1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_CODE_STUBS_H_ 6 #define V8_CODE_STUBS_H_ 7 8 #include "src/allocation.h" 9 #include "src/assembler.h" 10 #include "src/codegen.h" 11 #include "src/globals.h" 12 #include "src/ic/ic-state.h" 13 #include "src/interface-descriptors.h" 14 #include "src/macro-assembler.h" 15 #include "src/ostreams.h" 16 17 namespace v8 { 18 namespace internal { 19 20 // List of code stubs used on all platforms. 21 #define CODE_STUB_LIST_ALL_PLATFORMS(V) \ 22 /* PlatformCodeStubs */ \ 23 V(ArgumentsAccess) \ 24 V(ArrayConstructor) \ 25 V(BinaryOpICWithAllocationSite) \ 26 V(CallApiFunction) \ 27 V(CallApiGetter) \ 28 V(CallConstruct) \ 29 V(CallFunction) \ 30 V(CallIC) \ 31 V(CallIC_Array) \ 32 V(CEntry) \ 33 V(CompareIC) \ 34 V(DoubleToI) \ 35 V(FunctionPrototype) \ 36 V(Instanceof) \ 37 V(InternalArrayConstructor) \ 38 V(JSEntry) \ 39 V(KeyedLoadICTrampoline) \ 40 V(LoadICTrampoline) \ 41 V(LoadIndexedInterceptor) \ 42 V(MathPow) \ 43 V(ProfileEntryHook) \ 44 V(RecordWrite) \ 45 V(RegExpExec) \ 46 V(StoreArrayLiteralElement) \ 47 V(StoreBufferOverflow) \ 48 V(StoreElement) \ 49 V(StringCompare) \ 50 V(StubFailureTrampoline) \ 51 V(SubString) \ 52 /* HydrogenCodeStubs */ \ 53 V(ArrayNArgumentsConstructor) \ 54 V(ArrayNoArgumentConstructor) \ 55 V(ArraySingleArgumentConstructor) \ 56 V(BinaryOpIC) \ 57 V(BinaryOpWithAllocationSite) \ 58 V(CompareNilIC) \ 59 V(CreateAllocationSite) \ 60 V(ElementsTransitionAndStore) \ 61 V(FastCloneShallowArray) \ 62 V(FastCloneShallowObject) \ 63 V(FastNewClosure) \ 64 V(FastNewContext) \ 65 V(InternalArrayNArgumentsConstructor) \ 66 V(InternalArrayNoArgumentConstructor) \ 67 V(InternalArraySingleArgumentConstructor) \ 68 V(KeyedLoadGeneric) \ 69 V(LoadDictionaryElement) \ 70 V(LoadFastElement) \ 71 V(MegamorphicLoad) \ 72 V(NameDictionaryLookup) \ 73 V(NumberToString) \ 74 V(RegExpConstructResult) \ 75 V(StoreFastElement) \ 76 V(StringAdd) \ 77 V(ToBoolean) \ 78 V(ToNumber) \ 79 V(TransitionElementsKind) \ 80 V(VectorKeyedLoad) \ 81 V(VectorLoad) \ 82 /* IC Handler stubs */ \ 83 V(LoadConstant) \ 84 V(LoadField) \ 85 V(KeyedLoadSloppyArguments) \ 86 V(StoreField) \ 87 V(StoreGlobal) \ 88 V(StringLength) 89 90 // List of code stubs only used on ARM 32 bits platforms. 91 #if V8_TARGET_ARCH_ARM 92 #define CODE_STUB_LIST_ARM(V) \ 93 V(DirectCEntry) \ 94 V(WriteInt32ToHeapNumber) 95 96 #else 97 #define CODE_STUB_LIST_ARM(V) 98 #endif 99 100 // List of code stubs only used on ARM 64 bits platforms. 101 #if V8_TARGET_ARCH_ARM64 102 #define CODE_STUB_LIST_ARM64(V) \ 103 V(DirectCEntry) \ 104 V(RestoreRegistersState) \ 105 V(StoreRegistersState) 106 107 #else 108 #define CODE_STUB_LIST_ARM64(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(DirectCEntry) \ 115 V(RestoreRegistersState) \ 116 V(StoreRegistersState) \ 117 V(WriteInt32ToHeapNumber) 118 #elif V8_TARGET_ARCH_MIPS64 119 #define CODE_STUB_LIST_MIPS(V) \ 120 V(DirectCEntry) \ 121 V(RestoreRegistersState) \ 122 V(StoreRegistersState) \ 123 V(WriteInt32ToHeapNumber) 124 #else 125 #define CODE_STUB_LIST_MIPS(V) 126 #endif 127 128 // Combined list of code stubs. 129 #define CODE_STUB_LIST(V) \ 130 CODE_STUB_LIST_ALL_PLATFORMS(V) \ 131 CODE_STUB_LIST_ARM(V) \ 132 CODE_STUB_LIST_ARM64(V) \ 133 CODE_STUB_LIST_MIPS(V) 134 135 // Stub is base classes of all stubs. 136 class CodeStub BASE_EMBEDDED { 137 public: 138 enum Major { 139 #define DEF_ENUM(name) name, 140 CODE_STUB_LIST(DEF_ENUM) 141 #undef DEF_ENUM 142 NoCache, // marker for stubs that do custom caching 143 NUMBER_OF_IDS 144 }; 145 146 // Retrieve the code for the stub. Generate the code if needed. 147 Handle<Code> GetCode(); 148 149 // Retrieve the code for the stub, make and return a copy of the code. 150 Handle<Code> GetCodeCopy(const Code::FindAndReplacePattern& pattern); 151 MajorKeyFromKey(uint32_t key)152 static Major MajorKeyFromKey(uint32_t key) { 153 return static_cast<Major>(MajorKeyBits::decode(key)); 154 } MinorKeyFromKey(uint32_t key)155 static uint32_t MinorKeyFromKey(uint32_t key) { 156 return MinorKeyBits::decode(key); 157 } 158 159 // Gets the major key from a code object that is a code stub or binary op IC. GetMajorKey(Code * code_stub)160 static Major GetMajorKey(Code* code_stub) { 161 return MajorKeyFromKey(code_stub->stub_key()); 162 } 163 NoCacheKey()164 static uint32_t NoCacheKey() { return MajorKeyBits::encode(NoCache); } 165 166 static const char* MajorName(Major major_key, bool allow_unknown_keys); 167 CodeStub(Isolate * isolate)168 explicit CodeStub(Isolate* isolate) : minor_key_(0), isolate_(isolate) {} ~CodeStub()169 virtual ~CodeStub() {} 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. SometimesSetsUpAFrame()180 virtual bool SometimesSetsUpAFrame() { return true; } 181 182 // Lookup the code in the (possibly custom) cache. 183 bool FindCodeInCache(Code** code_out); 184 185 virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() = 0; 186 InitializeDescriptor(CodeStubDescriptor * descriptor)187 virtual void InitializeDescriptor(CodeStubDescriptor* descriptor) {} 188 189 static void InitializeDescriptor(Isolate* isolate, uint32_t key, 190 CodeStubDescriptor* desc); 191 192 static MaybeHandle<Code> GetCode(Isolate* isolate, uint32_t key); 193 194 // Returns information for computing the number key. 195 virtual Major MajorKey() const = 0; MinorKey()196 uint32_t MinorKey() const { return minor_key_; } 197 GetICState()198 virtual InlineCacheState GetICState() const { return UNINITIALIZED; } GetExtraICState()199 virtual ExtraICState GetExtraICState() const { return kNoExtraICState; } GetStubType()200 virtual Code::StubType GetStubType() { 201 return Code::NORMAL; 202 } 203 204 friend OStream& operator<<(OStream& os, const CodeStub& s) { 205 s.PrintName(os); 206 return os; 207 } 208 isolate()209 Isolate* isolate() const { return isolate_; } 210 211 protected: CodeStub(uint32_t key,Isolate * isolate)212 CodeStub(uint32_t key, Isolate* isolate) 213 : minor_key_(MinorKeyFromKey(key)), isolate_(isolate) {} 214 215 // Generates the assembler code for the stub. 216 virtual Handle<Code> GenerateCode() = 0; 217 218 // Returns whether the code generated for this stub needs to be allocated as 219 // a fixed (non-moveable) code object. NeedsImmovableCode()220 virtual bool NeedsImmovableCode() { return false; } 221 222 virtual void PrintName(OStream& os) const; // NOLINT 223 virtual void PrintBaseName(OStream& os) const; // NOLINT PrintState(OStream & os)224 virtual void PrintState(OStream& os) const { ; } // NOLINT 225 226 // Computes the key based on major and minor. GetKey()227 uint32_t GetKey() { 228 DCHECK(static_cast<int>(MajorKey()) < NUMBER_OF_IDS); 229 return MinorKeyBits::encode(MinorKey()) | MajorKeyBits::encode(MajorKey()); 230 } 231 232 uint32_t minor_key_; 233 234 private: 235 // Perform bookkeeping required after code generation when stub code is 236 // initially generated. 237 void RecordCodeGeneration(Handle<Code> code); 238 239 // Finish the code object after it has been generated. FinishCode(Handle<Code> code)240 virtual void FinishCode(Handle<Code> code) { } 241 242 // Activate newly generated stub. Is called after 243 // registering stub in the stub cache. Activate(Code * code)244 virtual void Activate(Code* code) { } 245 246 // BinaryOpStub needs to override this. 247 virtual Code::Kind GetCodeKind() const; 248 249 // Add the code to a specialized cache, specific to an individual 250 // stub type. Please note, this method must add the code object to a 251 // roots object, otherwise we will remove the code during GC. AddToSpecialCache(Handle<Code> new_object)252 virtual void AddToSpecialCache(Handle<Code> new_object) { } 253 254 // Find code in a specialized cache, work is delegated to the specific stub. FindCodeInSpecialCache(Code ** code_out)255 virtual bool FindCodeInSpecialCache(Code** code_out) { 256 return false; 257 } 258 259 // If a stub uses a special cache override this. UseSpecialCache()260 virtual bool UseSpecialCache() { return false; } 261 262 // We use this dispatch to statically instantiate the correct code stub for 263 // the given stub key and call the passed function with that code stub. 264 typedef void (*DispatchedCall)(CodeStub* stub, void** value_out); 265 static void Dispatch(Isolate* isolate, uint32_t key, void** value_out, 266 DispatchedCall call); 267 268 static void GetCodeDispatchCall(CodeStub* stub, void** value_out); 269 270 STATIC_ASSERT(NUMBER_OF_IDS < (1 << kStubMajorKeyBits)); 271 class MajorKeyBits: public BitField<uint32_t, 0, kStubMajorKeyBits> {}; 272 class MinorKeyBits: public BitField<uint32_t, 273 kStubMajorKeyBits, kStubMinorKeyBits> {}; // NOLINT 274 275 friend class BreakPointIterator; 276 277 Isolate* isolate_; 278 }; 279 280 281 #define DEFINE_CODE_STUB_BASE(NAME, SUPER) \ 282 public: \ 283 NAME(uint32_t key, Isolate* isolate) : SUPER(key, isolate) {} \ 284 \ 285 private: \ 286 DISALLOW_COPY_AND_ASSIGN(NAME) 287 288 289 #define DEFINE_CODE_STUB(NAME, SUPER) \ 290 protected: \ 291 virtual inline Major MajorKey() const OVERRIDE { \ 292 return NAME; \ 293 }; \ 294 DEFINE_CODE_STUB_BASE(NAME##Stub, SUPER) 295 296 297 #define DEFINE_PLATFORM_CODE_STUB(NAME, SUPER) \ 298 private: \ 299 virtual void Generate(MacroAssembler* masm) OVERRIDE; \ 300 DEFINE_CODE_STUB(NAME, SUPER) 301 302 303 #define DEFINE_HYDROGEN_CODE_STUB(NAME, SUPER) \ 304 public: \ 305 virtual void InitializeDescriptor(CodeStubDescriptor* descriptor) OVERRIDE; \ 306 virtual Handle<Code> GenerateCode() OVERRIDE; \ 307 DEFINE_CODE_STUB(NAME, SUPER) 308 309 #define DEFINE_HANDLER_CODE_STUB(NAME, SUPER) \ 310 public: \ 311 virtual Handle<Code> GenerateCode() OVERRIDE; \ 312 DEFINE_CODE_STUB(NAME, SUPER) 313 314 #define DEFINE_CALL_INTERFACE_DESCRIPTOR(NAME) \ 315 public: \ 316 virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE { \ 317 return NAME##Descriptor(isolate()); \ 318 } 319 320 // There are some code stubs we just can't describe right now with a 321 // CallInterfaceDescriptor. Isolate behavior for those cases with this macro. 322 // An attempt to retrieve a descriptor will fail. 323 #define DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR() \ 324 public: \ 325 virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE { \ 326 UNREACHABLE(); \ 327 return CallInterfaceDescriptor(); \ 328 } 329 330 331 class PlatformCodeStub : public CodeStub { 332 public: 333 // Retrieve the code for the stub. Generate the code if needed. 334 virtual Handle<Code> GenerateCode() OVERRIDE; 335 GetCodeKind()336 virtual Code::Kind GetCodeKind() const { return Code::STUB; } 337 338 protected: PlatformCodeStub(Isolate * isolate)339 explicit PlatformCodeStub(Isolate* isolate) : CodeStub(isolate) {} 340 341 // Generates the assembler code for the stub. 342 virtual void Generate(MacroAssembler* masm) = 0; 343 344 DEFINE_CODE_STUB_BASE(PlatformCodeStub, CodeStub); 345 }; 346 347 348 enum StubFunctionMode { NOT_JS_FUNCTION_STUB_MODE, JS_FUNCTION_STUB_MODE }; 349 enum HandlerArgumentsMode { DONT_PASS_ARGUMENTS, PASS_ARGUMENTS }; 350 351 352 class CodeStubDescriptor { 353 public: 354 explicit CodeStubDescriptor(CodeStub* stub); 355 356 CodeStubDescriptor(Isolate* isolate, uint32_t stub_key); 357 358 void Initialize(Address deoptimization_handler = NULL, 359 int hint_stack_parameter_count = -1, 360 StubFunctionMode function_mode = NOT_JS_FUNCTION_STUB_MODE); 361 void Initialize(Register stack_parameter_count, 362 Address deoptimization_handler = NULL, 363 int hint_stack_parameter_count = -1, 364 StubFunctionMode function_mode = NOT_JS_FUNCTION_STUB_MODE, 365 HandlerArgumentsMode handler_mode = DONT_PASS_ARGUMENTS); 366 SetMissHandler(ExternalReference handler)367 void SetMissHandler(ExternalReference handler) { 368 miss_handler_ = handler; 369 has_miss_handler_ = true; 370 // Our miss handler infrastructure doesn't currently support 371 // variable stack parameter counts. 372 DCHECK(!stack_parameter_count_.is_valid()); 373 } 374 set_call_descriptor(CallInterfaceDescriptor d)375 void set_call_descriptor(CallInterfaceDescriptor d) { call_descriptor_ = d; } call_descriptor()376 CallInterfaceDescriptor call_descriptor() const { return call_descriptor_; } 377 GetEnvironmentParameterCount()378 int GetEnvironmentParameterCount() const { 379 return call_descriptor().GetEnvironmentParameterCount(); 380 } 381 GetEnvironmentParameterRepresentation(int index)382 Representation GetEnvironmentParameterRepresentation(int index) const { 383 return call_descriptor().GetEnvironmentParameterRepresentation(index); 384 } 385 miss_handler()386 ExternalReference miss_handler() const { 387 DCHECK(has_miss_handler_); 388 return miss_handler_; 389 } 390 has_miss_handler()391 bool has_miss_handler() const { 392 return has_miss_handler_; 393 } 394 IsEnvironmentParameterCountRegister(int index)395 bool IsEnvironmentParameterCountRegister(int index) const { 396 return call_descriptor().GetEnvironmentParameterRegister(index).is( 397 stack_parameter_count_); 398 } 399 GetHandlerParameterCount()400 int GetHandlerParameterCount() const { 401 int params = call_descriptor().GetEnvironmentParameterCount(); 402 if (handler_arguments_mode_ == PASS_ARGUMENTS) { 403 params += 1; 404 } 405 return params; 406 } 407 hint_stack_parameter_count()408 int hint_stack_parameter_count() const { return hint_stack_parameter_count_; } stack_parameter_count()409 Register stack_parameter_count() const { return stack_parameter_count_; } function_mode()410 StubFunctionMode function_mode() const { return function_mode_; } deoptimization_handler()411 Address deoptimization_handler() const { return deoptimization_handler_; } 412 413 private: 414 CallInterfaceDescriptor call_descriptor_; 415 Register stack_parameter_count_; 416 // If hint_stack_parameter_count_ > 0, the code stub can optimize the 417 // return sequence. Default value is -1, which means it is ignored. 418 int hint_stack_parameter_count_; 419 StubFunctionMode function_mode_; 420 421 Address deoptimization_handler_; 422 HandlerArgumentsMode handler_arguments_mode_; 423 424 ExternalReference miss_handler_; 425 bool has_miss_handler_; 426 }; 427 428 429 class HydrogenCodeStub : public CodeStub { 430 public: 431 enum InitializationState { 432 UNINITIALIZED, 433 INITIALIZED 434 }; 435 GetCodeKind()436 virtual Code::Kind GetCodeKind() const { return Code::STUB; } 437 438 template<class SubClass> GetUninitialized(Isolate * isolate)439 static Handle<Code> GetUninitialized(Isolate* isolate) { 440 SubClass::GenerateAheadOfTime(isolate); 441 return SubClass().GetCode(isolate); 442 } 443 444 // Retrieve the code for the stub. Generate the code if needed. 445 virtual Handle<Code> GenerateCode() = 0; 446 IsUninitialized()447 bool IsUninitialized() const { return IsMissBits::decode(minor_key_); } 448 449 Handle<Code> GenerateLightweightMissCode(ExternalReference miss); 450 451 template<class StateType> 452 void TraceTransition(StateType from, StateType to); 453 454 protected: 455 explicit HydrogenCodeStub(Isolate* isolate, 456 InitializationState state = INITIALIZED) CodeStub(isolate)457 : CodeStub(isolate) { 458 minor_key_ = IsMissBits::encode(state == UNINITIALIZED); 459 } 460 set_sub_minor_key(uint32_t key)461 void set_sub_minor_key(uint32_t key) { 462 minor_key_ = SubMinorKeyBits::update(minor_key_, key); 463 } 464 sub_minor_key()465 uint32_t sub_minor_key() const { return SubMinorKeyBits::decode(minor_key_); } 466 467 static const int kSubMinorKeyBits = kStubMinorKeyBits - 1; 468 469 private: 470 class IsMissBits : public BitField<bool, kSubMinorKeyBits, 1> {}; 471 class SubMinorKeyBits : public BitField<int, 0, kSubMinorKeyBits> {}; 472 473 void GenerateLightweightMiss(MacroAssembler* masm, ExternalReference miss); 474 475 DEFINE_CODE_STUB_BASE(HydrogenCodeStub, CodeStub); 476 }; 477 478 479 // Helper interface to prepare to/restore after making runtime calls. 480 class RuntimeCallHelper { 481 public: ~RuntimeCallHelper()482 virtual ~RuntimeCallHelper() {} 483 484 virtual void BeforeCall(MacroAssembler* masm) const = 0; 485 486 virtual void AfterCall(MacroAssembler* masm) const = 0; 487 488 protected: RuntimeCallHelper()489 RuntimeCallHelper() {} 490 491 private: 492 DISALLOW_COPY_AND_ASSIGN(RuntimeCallHelper); 493 }; 494 495 496 } } // namespace v8::internal 497 498 #if V8_TARGET_ARCH_IA32 499 #include "src/ia32/code-stubs-ia32.h" 500 #elif V8_TARGET_ARCH_X64 501 #include "src/x64/code-stubs-x64.h" 502 #elif V8_TARGET_ARCH_ARM64 503 #include "src/arm64/code-stubs-arm64.h" 504 #elif V8_TARGET_ARCH_ARM 505 #include "src/arm/code-stubs-arm.h" 506 #elif V8_TARGET_ARCH_MIPS 507 #include "src/mips/code-stubs-mips.h" 508 #elif V8_TARGET_ARCH_MIPS64 509 #include "src/mips64/code-stubs-mips64.h" 510 #elif V8_TARGET_ARCH_X87 511 #include "src/x87/code-stubs-x87.h" 512 #else 513 #error Unsupported target architecture. 514 #endif 515 516 namespace v8 { 517 namespace internal { 518 519 520 // RuntimeCallHelper implementation used in stubs: enters/leaves a 521 // newly created internal frame before/after the runtime call. 522 class StubRuntimeCallHelper : public RuntimeCallHelper { 523 public: StubRuntimeCallHelper()524 StubRuntimeCallHelper() {} 525 526 virtual void BeforeCall(MacroAssembler* masm) const; 527 528 virtual void AfterCall(MacroAssembler* masm) const; 529 }; 530 531 532 // Trivial RuntimeCallHelper implementation. 533 class NopRuntimeCallHelper : public RuntimeCallHelper { 534 public: NopRuntimeCallHelper()535 NopRuntimeCallHelper() {} 536 BeforeCall(MacroAssembler * masm)537 virtual void BeforeCall(MacroAssembler* masm) const {} 538 AfterCall(MacroAssembler * masm)539 virtual void AfterCall(MacroAssembler* masm) const {} 540 }; 541 542 543 class ToNumberStub: public HydrogenCodeStub { 544 public: ToNumberStub(Isolate * isolate)545 explicit ToNumberStub(Isolate* isolate) : HydrogenCodeStub(isolate) { } 546 547 DEFINE_CALL_INTERFACE_DESCRIPTOR(ToNumber); 548 DEFINE_HYDROGEN_CODE_STUB(ToNumber, HydrogenCodeStub); 549 }; 550 551 552 class NumberToStringStub FINAL : public HydrogenCodeStub { 553 public: NumberToStringStub(Isolate * isolate)554 explicit NumberToStringStub(Isolate* isolate) : HydrogenCodeStub(isolate) {} 555 556 // Parameters accessed via CodeStubGraphBuilder::GetParameter() 557 static const int kNumber = 0; 558 559 DEFINE_CALL_INTERFACE_DESCRIPTOR(NumberToString); 560 DEFINE_HYDROGEN_CODE_STUB(NumberToString, HydrogenCodeStub); 561 }; 562 563 564 class FastNewClosureStub : public HydrogenCodeStub { 565 public: FastNewClosureStub(Isolate * isolate,StrictMode strict_mode,FunctionKind kind)566 FastNewClosureStub(Isolate* isolate, StrictMode strict_mode, 567 FunctionKind kind) 568 : HydrogenCodeStub(isolate) { 569 DCHECK(IsValidFunctionKind(kind)); 570 set_sub_minor_key(StrictModeBits::encode(strict_mode) | 571 FunctionKindBits::encode(kind)); 572 } 573 strict_mode()574 StrictMode strict_mode() const { 575 return StrictModeBits::decode(sub_minor_key()); 576 } 577 kind()578 FunctionKind kind() const { 579 return FunctionKindBits::decode(sub_minor_key()); 580 } is_arrow()581 bool is_arrow() const { return IsArrowFunction(kind()); } is_generator()582 bool is_generator() const { return IsGeneratorFunction(kind()); } is_concise_method()583 bool is_concise_method() const { return IsConciseMethod(kind()); } 584 585 private: 586 class StrictModeBits : public BitField<StrictMode, 0, 1> {}; 587 class FunctionKindBits : public BitField<FunctionKind, 1, 3> {}; 588 589 DEFINE_CALL_INTERFACE_DESCRIPTOR(FastNewClosure); 590 DEFINE_HYDROGEN_CODE_STUB(FastNewClosure, HydrogenCodeStub); 591 }; 592 593 594 class FastNewContextStub FINAL : public HydrogenCodeStub { 595 public: 596 static const int kMaximumSlots = 64; 597 FastNewContextStub(Isolate * isolate,int slots)598 FastNewContextStub(Isolate* isolate, int slots) : HydrogenCodeStub(isolate) { 599 DCHECK(slots > 0 && slots <= kMaximumSlots); 600 set_sub_minor_key(SlotsBits::encode(slots)); 601 } 602 slots()603 int slots() const { return SlotsBits::decode(sub_minor_key()); } 604 605 // Parameters accessed via CodeStubGraphBuilder::GetParameter() 606 static const int kFunction = 0; 607 608 private: 609 class SlotsBits : public BitField<int, 0, 8> {}; 610 611 DEFINE_CALL_INTERFACE_DESCRIPTOR(FastNewContext); 612 DEFINE_HYDROGEN_CODE_STUB(FastNewContext, HydrogenCodeStub); 613 }; 614 615 616 class FastCloneShallowArrayStub : public HydrogenCodeStub { 617 public: FastCloneShallowArrayStub(Isolate * isolate,AllocationSiteMode allocation_site_mode)618 FastCloneShallowArrayStub(Isolate* isolate, 619 AllocationSiteMode allocation_site_mode) 620 : HydrogenCodeStub(isolate) { 621 set_sub_minor_key(AllocationSiteModeBits::encode(allocation_site_mode)); 622 } 623 allocation_site_mode()624 AllocationSiteMode allocation_site_mode() const { 625 return AllocationSiteModeBits::decode(sub_minor_key()); 626 } 627 628 private: 629 class AllocationSiteModeBits: public BitField<AllocationSiteMode, 0, 1> {}; 630 631 DEFINE_CALL_INTERFACE_DESCRIPTOR(FastCloneShallowArray); 632 DEFINE_HYDROGEN_CODE_STUB(FastCloneShallowArray, HydrogenCodeStub); 633 }; 634 635 636 class FastCloneShallowObjectStub : public HydrogenCodeStub { 637 public: 638 // Maximum number of properties in copied object. 639 static const int kMaximumClonedProperties = 6; 640 FastCloneShallowObjectStub(Isolate * isolate,int length)641 FastCloneShallowObjectStub(Isolate* isolate, int length) 642 : HydrogenCodeStub(isolate) { 643 DCHECK_GE(length, 0); 644 DCHECK_LE(length, kMaximumClonedProperties); 645 set_sub_minor_key(LengthBits::encode(length)); 646 } 647 length()648 int length() const { return LengthBits::decode(sub_minor_key()); } 649 650 private: 651 class LengthBits : public BitField<int, 0, 4> {}; 652 653 DEFINE_CALL_INTERFACE_DESCRIPTOR(FastCloneShallowObject); 654 DEFINE_HYDROGEN_CODE_STUB(FastCloneShallowObject, HydrogenCodeStub); 655 }; 656 657 658 class CreateAllocationSiteStub : public HydrogenCodeStub { 659 public: CreateAllocationSiteStub(Isolate * isolate)660 explicit CreateAllocationSiteStub(Isolate* isolate) 661 : HydrogenCodeStub(isolate) { } 662 663 static void GenerateAheadOfTime(Isolate* isolate); 664 665 DEFINE_CALL_INTERFACE_DESCRIPTOR(CreateAllocationSite); 666 DEFINE_HYDROGEN_CODE_STUB(CreateAllocationSite, HydrogenCodeStub); 667 }; 668 669 670 class InstanceofStub: public PlatformCodeStub { 671 public: 672 enum Flags { 673 kNoFlags = 0, 674 kArgsInRegisters = 1 << 0, 675 kCallSiteInlineCheck = 1 << 1, 676 kReturnTrueFalseObject = 1 << 2 677 }; 678 InstanceofStub(Isolate * isolate,Flags flags)679 InstanceofStub(Isolate* isolate, Flags flags) : PlatformCodeStub(isolate) { 680 minor_key_ = FlagBits::encode(flags); 681 } 682 left()683 static Register left() { return InstanceofDescriptor::left(); } right()684 static Register right() { return InstanceofDescriptor::right(); } 685 GetCallInterfaceDescriptor()686 virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE { 687 if (HasArgsInRegisters()) { 688 return InstanceofDescriptor(isolate()); 689 } 690 return ContextOnlyDescriptor(isolate()); 691 } 692 693 private: flags()694 Flags flags() const { return FlagBits::decode(minor_key_); } 695 HasArgsInRegisters()696 bool HasArgsInRegisters() const { return (flags() & kArgsInRegisters) != 0; } 697 HasCallSiteInlineCheck()698 bool HasCallSiteInlineCheck() const { 699 return (flags() & kCallSiteInlineCheck) != 0; 700 } 701 ReturnTrueFalseObject()702 bool ReturnTrueFalseObject() const { 703 return (flags() & kReturnTrueFalseObject) != 0; 704 } 705 706 virtual void PrintName(OStream& os) const OVERRIDE; // NOLINT 707 708 class FlagBits : public BitField<Flags, 0, 3> {}; 709 710 DEFINE_PLATFORM_CODE_STUB(Instanceof, PlatformCodeStub); 711 }; 712 713 714 enum AllocationSiteOverrideMode { 715 DONT_OVERRIDE, 716 DISABLE_ALLOCATION_SITES, 717 LAST_ALLOCATION_SITE_OVERRIDE_MODE = DISABLE_ALLOCATION_SITES 718 }; 719 720 721 class ArrayConstructorStub: public PlatformCodeStub { 722 public: 723 enum ArgumentCountKey { ANY, NONE, ONE, MORE_THAN_ONE }; 724 725 ArrayConstructorStub(Isolate* isolate, int argument_count); 726 727 explicit ArrayConstructorStub(Isolate* isolate); 728 729 private: argument_count()730 ArgumentCountKey argument_count() const { 731 return ArgumentCountBits::decode(minor_key_); 732 } 733 734 void GenerateDispatchToArrayStub(MacroAssembler* masm, 735 AllocationSiteOverrideMode mode); 736 737 virtual void PrintName(OStream& os) const OVERRIDE; // NOLINT 738 739 class ArgumentCountBits : public BitField<ArgumentCountKey, 0, 2> {}; 740 741 DEFINE_CALL_INTERFACE_DESCRIPTOR(ArrayConstructor); 742 DEFINE_PLATFORM_CODE_STUB(ArrayConstructor, PlatformCodeStub); 743 }; 744 745 746 class InternalArrayConstructorStub: public PlatformCodeStub { 747 public: 748 explicit InternalArrayConstructorStub(Isolate* isolate); 749 750 private: 751 void GenerateCase(MacroAssembler* masm, ElementsKind kind); 752 753 DEFINE_CALL_INTERFACE_DESCRIPTOR(InternalArrayConstructor); 754 DEFINE_PLATFORM_CODE_STUB(InternalArrayConstructor, PlatformCodeStub); 755 }; 756 757 758 class MathPowStub: public PlatformCodeStub { 759 public: 760 enum ExponentType { INTEGER, DOUBLE, TAGGED, ON_STACK }; 761 MathPowStub(Isolate * isolate,ExponentType exponent_type)762 MathPowStub(Isolate* isolate, ExponentType exponent_type) 763 : PlatformCodeStub(isolate) { 764 minor_key_ = ExponentTypeBits::encode(exponent_type); 765 } 766 GetCallInterfaceDescriptor()767 virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE { 768 if (exponent_type() == TAGGED) { 769 return MathPowTaggedDescriptor(isolate()); 770 } else if (exponent_type() == INTEGER) { 771 return MathPowIntegerDescriptor(isolate()); 772 } 773 // A CallInterfaceDescriptor doesn't specify double registers (yet). 774 return ContextOnlyDescriptor(isolate()); 775 } 776 777 private: exponent_type()778 ExponentType exponent_type() const { 779 return ExponentTypeBits::decode(minor_key_); 780 } 781 782 class ExponentTypeBits : public BitField<ExponentType, 0, 2> {}; 783 784 DEFINE_PLATFORM_CODE_STUB(MathPow, PlatformCodeStub); 785 }; 786 787 788 class CallICStub: public PlatformCodeStub { 789 public: CallICStub(Isolate * isolate,const CallICState & state)790 CallICStub(Isolate* isolate, const CallICState& state) 791 : PlatformCodeStub(isolate) { 792 minor_key_ = state.GetExtraICState(); 793 } 794 ExtractArgcFromMinorKey(int minor_key)795 static int ExtractArgcFromMinorKey(int minor_key) { 796 CallICState state(static_cast<ExtraICState>(minor_key)); 797 return state.arg_count(); 798 } 799 GetCodeKind()800 virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::CALL_IC; } 801 GetICState()802 virtual InlineCacheState GetICState() const OVERRIDE { return DEFAULT; } 803 GetExtraICState()804 virtual ExtraICState GetExtraICState() const FINAL OVERRIDE { 805 return static_cast<ExtraICState>(minor_key_); 806 } 807 808 protected: CallAsMethod()809 bool CallAsMethod() const { 810 return state().call_type() == CallICState::METHOD; 811 } 812 arg_count()813 int arg_count() const { return state().arg_count(); } 814 state()815 CallICState state() const { 816 return CallICState(static_cast<ExtraICState>(minor_key_)); 817 } 818 819 // Code generation helpers. 820 void GenerateMiss(MacroAssembler* masm); 821 822 private: 823 virtual void PrintState(OStream& os) const OVERRIDE; // NOLINT 824 825 DEFINE_CALL_INTERFACE_DESCRIPTOR(CallFunctionWithFeedback); 826 DEFINE_PLATFORM_CODE_STUB(CallIC, PlatformCodeStub); 827 }; 828 829 830 class CallIC_ArrayStub: public CallICStub { 831 public: CallIC_ArrayStub(Isolate * isolate,const CallICState & state_in)832 CallIC_ArrayStub(Isolate* isolate, const CallICState& state_in) 833 : CallICStub(isolate, state_in) {} 834 GetICState()835 virtual InlineCacheState GetICState() const FINAL OVERRIDE { 836 return MONOMORPHIC; 837 } 838 839 private: 840 virtual void PrintState(OStream& os) const OVERRIDE; // NOLINT 841 842 DEFINE_PLATFORM_CODE_STUB(CallIC_Array, CallICStub); 843 }; 844 845 846 // TODO(verwaest): Translate to hydrogen code stub. 847 class FunctionPrototypeStub : public PlatformCodeStub { 848 public: FunctionPrototypeStub(Isolate * isolate)849 explicit FunctionPrototypeStub(Isolate* isolate) 850 : PlatformCodeStub(isolate) {} 851 GetCodeKind()852 virtual Code::Kind GetCodeKind() const { return Code::HANDLER; } 853 854 // TODO(mvstanton): only the receiver register is accessed. When this is 855 // translated to a hydrogen code stub, a new CallInterfaceDescriptor 856 // should be created that just uses that register for more efficient code. 857 DEFINE_CALL_INTERFACE_DESCRIPTOR(Load); 858 DEFINE_PLATFORM_CODE_STUB(FunctionPrototype, PlatformCodeStub); 859 }; 860 861 862 // TODO(mvstanton): Translate to hydrogen code stub. 863 class LoadIndexedInterceptorStub : public PlatformCodeStub { 864 public: LoadIndexedInterceptorStub(Isolate * isolate)865 explicit LoadIndexedInterceptorStub(Isolate* isolate) 866 : PlatformCodeStub(isolate) {} 867 GetCodeKind()868 virtual Code::Kind GetCodeKind() const { return Code::HANDLER; } GetStubType()869 virtual Code::StubType GetStubType() { return Code::FAST; } 870 871 DEFINE_CALL_INTERFACE_DESCRIPTOR(Load); 872 DEFINE_PLATFORM_CODE_STUB(LoadIndexedInterceptor, PlatformCodeStub); 873 }; 874 875 876 class HandlerStub : public HydrogenCodeStub { 877 public: GetCodeKind()878 virtual Code::Kind GetCodeKind() const { return Code::HANDLER; } GetExtraICState()879 virtual ExtraICState GetExtraICState() const { return kind(); } GetICState()880 virtual InlineCacheState GetICState() const { return MONOMORPHIC; } 881 882 virtual void InitializeDescriptor(CodeStubDescriptor* descriptor) OVERRIDE; 883 884 virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE; 885 886 protected: HandlerStub(Isolate * isolate)887 explicit HandlerStub(Isolate* isolate) : HydrogenCodeStub(isolate) {} 888 889 virtual Code::Kind kind() const = 0; 890 891 DEFINE_CODE_STUB_BASE(HandlerStub, HydrogenCodeStub); 892 }; 893 894 895 class LoadFieldStub: public HandlerStub { 896 public: LoadFieldStub(Isolate * isolate,FieldIndex index)897 LoadFieldStub(Isolate* isolate, FieldIndex index) : HandlerStub(isolate) { 898 int property_index_key = index.GetFieldAccessStubKey(); 899 set_sub_minor_key(LoadFieldByIndexBits::encode(property_index_key)); 900 } 901 index()902 FieldIndex index() const { 903 int property_index_key = LoadFieldByIndexBits::decode(sub_minor_key()); 904 return FieldIndex::FromFieldAccessStubKey(property_index_key); 905 } 906 907 protected: kind()908 virtual Code::Kind kind() const { return Code::LOAD_IC; } GetStubType()909 virtual Code::StubType GetStubType() { return Code::FAST; } 910 911 private: 912 class LoadFieldByIndexBits : public BitField<int, 0, 13> {}; 913 914 DEFINE_HANDLER_CODE_STUB(LoadField, HandlerStub); 915 }; 916 917 918 class KeyedLoadSloppyArgumentsStub : public HandlerStub { 919 public: KeyedLoadSloppyArgumentsStub(Isolate * isolate)920 explicit KeyedLoadSloppyArgumentsStub(Isolate* isolate) 921 : HandlerStub(isolate) {} 922 923 protected: kind()924 virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; } GetStubType()925 virtual Code::StubType GetStubType() { return Code::FAST; } 926 927 private: 928 DEFINE_HANDLER_CODE_STUB(KeyedLoadSloppyArguments, HandlerStub); 929 }; 930 931 932 class LoadConstantStub : public HandlerStub { 933 public: LoadConstantStub(Isolate * isolate,int constant_index)934 LoadConstantStub(Isolate* isolate, int constant_index) 935 : HandlerStub(isolate) { 936 set_sub_minor_key(ConstantIndexBits::encode(constant_index)); 937 } 938 constant_index()939 int constant_index() const { 940 return ConstantIndexBits::decode(sub_minor_key()); 941 } 942 943 protected: kind()944 virtual Code::Kind kind() const { return Code::LOAD_IC; } GetStubType()945 virtual Code::StubType GetStubType() { return Code::FAST; } 946 947 private: 948 class ConstantIndexBits : public BitField<int, 0, kSubMinorKeyBits> {}; 949 950 DEFINE_HANDLER_CODE_STUB(LoadConstant, HandlerStub); 951 }; 952 953 954 class StringLengthStub: public HandlerStub { 955 public: StringLengthStub(Isolate * isolate)956 explicit StringLengthStub(Isolate* isolate) : HandlerStub(isolate) {} 957 958 protected: kind()959 virtual Code::Kind kind() const { return Code::LOAD_IC; } GetStubType()960 virtual Code::StubType GetStubType() { return Code::FAST; } 961 962 DEFINE_HANDLER_CODE_STUB(StringLength, HandlerStub); 963 }; 964 965 966 class StoreFieldStub : public HandlerStub { 967 public: StoreFieldStub(Isolate * isolate,FieldIndex index,Representation representation)968 StoreFieldStub(Isolate* isolate, FieldIndex index, 969 Representation representation) 970 : HandlerStub(isolate) { 971 int property_index_key = index.GetFieldAccessStubKey(); 972 uint8_t repr = PropertyDetails::EncodeRepresentation(representation); 973 set_sub_minor_key(StoreFieldByIndexBits::encode(property_index_key) | 974 RepresentationBits::encode(repr)); 975 } 976 index()977 FieldIndex index() const { 978 int property_index_key = StoreFieldByIndexBits::decode(sub_minor_key()); 979 return FieldIndex::FromFieldAccessStubKey(property_index_key); 980 } 981 representation()982 Representation representation() { 983 uint8_t repr = RepresentationBits::decode(sub_minor_key()); 984 return PropertyDetails::DecodeRepresentation(repr); 985 } 986 987 protected: kind()988 virtual Code::Kind kind() const { return Code::STORE_IC; } GetStubType()989 virtual Code::StubType GetStubType() { return Code::FAST; } 990 991 private: 992 class StoreFieldByIndexBits : public BitField<int, 0, 13> {}; 993 class RepresentationBits : public BitField<uint8_t, 13, 4> {}; 994 995 DEFINE_HANDLER_CODE_STUB(StoreField, HandlerStub); 996 }; 997 998 999 class StoreGlobalStub : public HandlerStub { 1000 public: StoreGlobalStub(Isolate * isolate,bool is_constant,bool check_global)1001 StoreGlobalStub(Isolate* isolate, bool is_constant, bool check_global) 1002 : HandlerStub(isolate) { 1003 set_sub_minor_key(IsConstantBits::encode(is_constant) | 1004 CheckGlobalBits::encode(check_global)); 1005 } 1006 global_placeholder(Isolate * isolate)1007 static Handle<HeapObject> global_placeholder(Isolate* isolate) { 1008 return isolate->factory()->uninitialized_value(); 1009 } 1010 GetCodeCopyFromTemplate(Handle<GlobalObject> global,Handle<PropertyCell> cell)1011 Handle<Code> GetCodeCopyFromTemplate(Handle<GlobalObject> global, 1012 Handle<PropertyCell> cell) { 1013 if (check_global()) { 1014 Code::FindAndReplacePattern pattern; 1015 pattern.Add(Handle<Map>(global_placeholder(isolate())->map()), global); 1016 pattern.Add(isolate()->factory()->meta_map(), Handle<Map>(global->map())); 1017 pattern.Add(isolate()->factory()->global_property_cell_map(), cell); 1018 return CodeStub::GetCodeCopy(pattern); 1019 } else { 1020 Code::FindAndReplacePattern pattern; 1021 pattern.Add(isolate()->factory()->global_property_cell_map(), cell); 1022 return CodeStub::GetCodeCopy(pattern); 1023 } 1024 } 1025 kind()1026 virtual Code::Kind kind() const { return Code::STORE_IC; } 1027 is_constant()1028 bool is_constant() const { return IsConstantBits::decode(sub_minor_key()); } 1029 check_global()1030 bool check_global() const { return CheckGlobalBits::decode(sub_minor_key()); } 1031 set_is_constant(bool value)1032 void set_is_constant(bool value) { 1033 set_sub_minor_key(IsConstantBits::update(sub_minor_key(), value)); 1034 } 1035 representation()1036 Representation representation() { 1037 return Representation::FromKind( 1038 RepresentationBits::decode(sub_minor_key())); 1039 } 1040 set_representation(Representation r)1041 void set_representation(Representation r) { 1042 set_sub_minor_key(RepresentationBits::update(sub_minor_key(), r.kind())); 1043 } 1044 1045 private: 1046 class IsConstantBits: public BitField<bool, 0, 1> {}; 1047 class RepresentationBits: public BitField<Representation::Kind, 1, 8> {}; 1048 class CheckGlobalBits: public BitField<bool, 9, 1> {}; 1049 1050 DEFINE_HANDLER_CODE_STUB(StoreGlobal, HandlerStub); 1051 }; 1052 1053 1054 class CallApiFunctionStub : public PlatformCodeStub { 1055 public: CallApiFunctionStub(Isolate * isolate,bool is_store,bool call_data_undefined,int argc)1056 CallApiFunctionStub(Isolate* isolate, 1057 bool is_store, 1058 bool call_data_undefined, 1059 int argc) : PlatformCodeStub(isolate) { 1060 minor_key_ = IsStoreBits::encode(is_store) | 1061 CallDataUndefinedBits::encode(call_data_undefined) | 1062 ArgumentBits::encode(argc); 1063 DCHECK(!is_store || argc == 1); 1064 } 1065 1066 private: is_store()1067 bool is_store() const { return IsStoreBits::decode(minor_key_); } call_data_undefined()1068 bool call_data_undefined() const { 1069 return CallDataUndefinedBits::decode(minor_key_); 1070 } argc()1071 int argc() const { return ArgumentBits::decode(minor_key_); } 1072 1073 class IsStoreBits: public BitField<bool, 0, 1> {}; 1074 class CallDataUndefinedBits: public BitField<bool, 1, 1> {}; 1075 class ArgumentBits: public BitField<int, 2, Code::kArgumentsBits> {}; 1076 STATIC_ASSERT(Code::kArgumentsBits + 2 <= kStubMinorKeyBits); 1077 1078 DEFINE_CALL_INTERFACE_DESCRIPTOR(ApiFunction); 1079 DEFINE_PLATFORM_CODE_STUB(CallApiFunction, PlatformCodeStub); 1080 }; 1081 1082 1083 class CallApiGetterStub : public PlatformCodeStub { 1084 public: CallApiGetterStub(Isolate * isolate)1085 explicit CallApiGetterStub(Isolate* isolate) : PlatformCodeStub(isolate) {} 1086 1087 DEFINE_CALL_INTERFACE_DESCRIPTOR(ApiGetter); 1088 DEFINE_PLATFORM_CODE_STUB(CallApiGetter, PlatformCodeStub); 1089 }; 1090 1091 1092 class BinaryOpICStub : public HydrogenCodeStub { 1093 public: 1094 BinaryOpICStub(Isolate* isolate, Token::Value op, 1095 OverwriteMode mode = NO_OVERWRITE) HydrogenCodeStub(isolate,UNINITIALIZED)1096 : HydrogenCodeStub(isolate, UNINITIALIZED) { 1097 BinaryOpICState state(isolate, op, mode); 1098 set_sub_minor_key(state.GetExtraICState()); 1099 } 1100 BinaryOpICStub(Isolate * isolate,const BinaryOpICState & state)1101 BinaryOpICStub(Isolate* isolate, const BinaryOpICState& state) 1102 : HydrogenCodeStub(isolate) { 1103 set_sub_minor_key(state.GetExtraICState()); 1104 } 1105 1106 static void GenerateAheadOfTime(Isolate* isolate); 1107 GetCodeKind()1108 virtual Code::Kind GetCodeKind() const OVERRIDE { 1109 return Code::BINARY_OP_IC; 1110 } 1111 GetICState()1112 virtual InlineCacheState GetICState() const FINAL OVERRIDE { 1113 return state().GetICState(); 1114 } 1115 GetExtraICState()1116 virtual ExtraICState GetExtraICState() const FINAL OVERRIDE { 1117 return static_cast<ExtraICState>(sub_minor_key()); 1118 } 1119 state()1120 BinaryOpICState state() const { 1121 return BinaryOpICState(isolate(), GetExtraICState()); 1122 } 1123 1124 virtual void PrintState(OStream& os) const FINAL OVERRIDE; // NOLINT 1125 1126 // Parameters accessed via CodeStubGraphBuilder::GetParameter() 1127 static const int kLeft = 0; 1128 static const int kRight = 1; 1129 1130 private: 1131 static void GenerateAheadOfTime(Isolate* isolate, 1132 const BinaryOpICState& state); 1133 1134 DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOp); 1135 DEFINE_HYDROGEN_CODE_STUB(BinaryOpIC, HydrogenCodeStub); 1136 }; 1137 1138 1139 // TODO(bmeurer): Merge this into the BinaryOpICStub once we have proper tail 1140 // call support for stubs in Hydrogen. 1141 class BinaryOpICWithAllocationSiteStub FINAL : public PlatformCodeStub { 1142 public: BinaryOpICWithAllocationSiteStub(Isolate * isolate,const BinaryOpICState & state)1143 BinaryOpICWithAllocationSiteStub(Isolate* isolate, 1144 const BinaryOpICState& state) 1145 : PlatformCodeStub(isolate) { 1146 minor_key_ = state.GetExtraICState(); 1147 } 1148 1149 static void GenerateAheadOfTime(Isolate* isolate); 1150 GetCodeCopyFromTemplate(Handle<AllocationSite> allocation_site)1151 Handle<Code> GetCodeCopyFromTemplate(Handle<AllocationSite> allocation_site) { 1152 Code::FindAndReplacePattern pattern; 1153 pattern.Add(isolate()->factory()->undefined_map(), allocation_site); 1154 return CodeStub::GetCodeCopy(pattern); 1155 } 1156 GetCodeKind()1157 virtual Code::Kind GetCodeKind() const OVERRIDE { 1158 return Code::BINARY_OP_IC; 1159 } 1160 GetICState()1161 virtual InlineCacheState GetICState() const OVERRIDE { 1162 return state().GetICState(); 1163 } 1164 GetExtraICState()1165 virtual ExtraICState GetExtraICState() const OVERRIDE { 1166 return static_cast<ExtraICState>(minor_key_); 1167 } 1168 1169 virtual void PrintState(OStream& os) const OVERRIDE; // NOLINT 1170 1171 private: state()1172 BinaryOpICState state() const { 1173 return BinaryOpICState(isolate(), static_cast<ExtraICState>(minor_key_)); 1174 } 1175 1176 static void GenerateAheadOfTime(Isolate* isolate, 1177 const BinaryOpICState& state); 1178 1179 DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOpWithAllocationSite); 1180 DEFINE_PLATFORM_CODE_STUB(BinaryOpICWithAllocationSite, PlatformCodeStub); 1181 }; 1182 1183 1184 class BinaryOpWithAllocationSiteStub FINAL : public BinaryOpICStub { 1185 public: BinaryOpWithAllocationSiteStub(Isolate * isolate,Token::Value op,OverwriteMode mode)1186 BinaryOpWithAllocationSiteStub(Isolate* isolate, 1187 Token::Value op, 1188 OverwriteMode mode) 1189 : BinaryOpICStub(isolate, op, mode) {} 1190 BinaryOpWithAllocationSiteStub(Isolate * isolate,const BinaryOpICState & state)1191 BinaryOpWithAllocationSiteStub(Isolate* isolate, const BinaryOpICState& state) 1192 : BinaryOpICStub(isolate, state) {} 1193 GetCodeKind()1194 virtual Code::Kind GetCodeKind() const FINAL OVERRIDE { 1195 return Code::STUB; 1196 } 1197 1198 // Parameters accessed via CodeStubGraphBuilder::GetParameter() 1199 static const int kAllocationSite = 0; 1200 static const int kLeft = 1; 1201 static const int kRight = 2; 1202 1203 DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOpWithAllocationSite); 1204 DEFINE_HYDROGEN_CODE_STUB(BinaryOpWithAllocationSite, BinaryOpICStub); 1205 }; 1206 1207 1208 enum StringAddFlags { 1209 // Omit both parameter checks. 1210 STRING_ADD_CHECK_NONE = 0, 1211 // Check left parameter. 1212 STRING_ADD_CHECK_LEFT = 1 << 0, 1213 // Check right parameter. 1214 STRING_ADD_CHECK_RIGHT = 1 << 1, 1215 // Check both parameters. 1216 STRING_ADD_CHECK_BOTH = STRING_ADD_CHECK_LEFT | STRING_ADD_CHECK_RIGHT 1217 }; 1218 1219 1220 class StringAddStub FINAL : public HydrogenCodeStub { 1221 public: StringAddStub(Isolate * isolate,StringAddFlags flags,PretenureFlag pretenure_flag)1222 StringAddStub(Isolate* isolate, StringAddFlags flags, 1223 PretenureFlag pretenure_flag) 1224 : HydrogenCodeStub(isolate) { 1225 set_sub_minor_key(StringAddFlagsBits::encode(flags) | 1226 PretenureFlagBits::encode(pretenure_flag)); 1227 } 1228 flags()1229 StringAddFlags flags() const { 1230 return StringAddFlagsBits::decode(sub_minor_key()); 1231 } 1232 pretenure_flag()1233 PretenureFlag pretenure_flag() const { 1234 return PretenureFlagBits::decode(sub_minor_key()); 1235 } 1236 1237 // Parameters accessed via CodeStubGraphBuilder::GetParameter() 1238 static const int kLeft = 0; 1239 static const int kRight = 1; 1240 1241 private: 1242 class StringAddFlagsBits: public BitField<StringAddFlags, 0, 2> {}; 1243 class PretenureFlagBits: public BitField<PretenureFlag, 2, 1> {}; 1244 1245 virtual void PrintBaseName(OStream& os) const OVERRIDE; // NOLINT 1246 1247 DEFINE_CALL_INTERFACE_DESCRIPTOR(StringAdd); 1248 DEFINE_HYDROGEN_CODE_STUB(StringAdd, HydrogenCodeStub); 1249 }; 1250 1251 1252 class CompareICStub : public PlatformCodeStub { 1253 public: CompareICStub(Isolate * isolate,Token::Value op,CompareICState::State left,CompareICState::State right,CompareICState::State state)1254 CompareICStub(Isolate* isolate, Token::Value op, CompareICState::State left, 1255 CompareICState::State right, CompareICState::State state) 1256 : PlatformCodeStub(isolate) { 1257 DCHECK(Token::IsCompareOp(op)); 1258 minor_key_ = OpBits::encode(op - Token::EQ) | LeftStateBits::encode(left) | 1259 RightStateBits::encode(right) | StateBits::encode(state); 1260 } 1261 set_known_map(Handle<Map> map)1262 void set_known_map(Handle<Map> map) { known_map_ = map; } 1263 1264 virtual InlineCacheState GetICState() const; 1265 op()1266 Token::Value op() const { 1267 return static_cast<Token::Value>(Token::EQ + OpBits::decode(minor_key_)); 1268 } 1269 left()1270 CompareICState::State left() const { 1271 return LeftStateBits::decode(minor_key_); 1272 } right()1273 CompareICState::State right() const { 1274 return RightStateBits::decode(minor_key_); 1275 } state()1276 CompareICState::State state() const { return StateBits::decode(minor_key_); } 1277 1278 private: GetCodeKind()1279 virtual Code::Kind GetCodeKind() const { return Code::COMPARE_IC; } 1280 1281 void GenerateSmis(MacroAssembler* masm); 1282 void GenerateNumbers(MacroAssembler* masm); 1283 void GenerateInternalizedStrings(MacroAssembler* masm); 1284 void GenerateStrings(MacroAssembler* masm); 1285 void GenerateUniqueNames(MacroAssembler* masm); 1286 void GenerateObjects(MacroAssembler* masm); 1287 void GenerateMiss(MacroAssembler* masm); 1288 void GenerateKnownObjects(MacroAssembler* masm); 1289 void GenerateGeneric(MacroAssembler* masm); 1290 strict()1291 bool strict() const { return op() == Token::EQ_STRICT; } 1292 Condition GetCondition() const; 1293 1294 virtual void AddToSpecialCache(Handle<Code> new_object); 1295 virtual bool FindCodeInSpecialCache(Code** code_out); UseSpecialCache()1296 virtual bool UseSpecialCache() { 1297 return state() == CompareICState::KNOWN_OBJECT; 1298 } 1299 1300 class OpBits : public BitField<int, 0, 3> {}; 1301 class LeftStateBits : public BitField<CompareICState::State, 3, 4> {}; 1302 class RightStateBits : public BitField<CompareICState::State, 7, 4> {}; 1303 class StateBits : public BitField<CompareICState::State, 11, 4> {}; 1304 1305 Handle<Map> known_map_; 1306 1307 DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOp); 1308 DEFINE_PLATFORM_CODE_STUB(CompareIC, PlatformCodeStub); 1309 }; 1310 1311 1312 class CompareNilICStub : public HydrogenCodeStub { 1313 public: 1314 Type* GetType(Zone* zone, Handle<Map> map = Handle<Map>()); 1315 Type* GetInputType(Zone* zone, Handle<Map> map); 1316 CompareNilICStub(Isolate * isolate,NilValue nil)1317 CompareNilICStub(Isolate* isolate, NilValue nil) : HydrogenCodeStub(isolate) { 1318 set_sub_minor_key(NilValueBits::encode(nil)); 1319 } 1320 1321 CompareNilICStub(Isolate* isolate, ExtraICState ic_state, 1322 InitializationState init_state = INITIALIZED) HydrogenCodeStub(isolate,init_state)1323 : HydrogenCodeStub(isolate, init_state) { 1324 set_sub_minor_key(ic_state); 1325 } 1326 GetUninitialized(Isolate * isolate,NilValue nil)1327 static Handle<Code> GetUninitialized(Isolate* isolate, 1328 NilValue nil) { 1329 return CompareNilICStub(isolate, nil, UNINITIALIZED).GetCode(); 1330 } 1331 GetICState()1332 virtual InlineCacheState GetICState() const { 1333 State state = this->state(); 1334 if (state.Contains(GENERIC)) { 1335 return MEGAMORPHIC; 1336 } else if (state.Contains(MONOMORPHIC_MAP)) { 1337 return MONOMORPHIC; 1338 } else { 1339 return PREMONOMORPHIC; 1340 } 1341 } 1342 GetCodeKind()1343 virtual Code::Kind GetCodeKind() const { return Code::COMPARE_NIL_IC; } 1344 GetExtraICState()1345 virtual ExtraICState GetExtraICState() const { return sub_minor_key(); } 1346 1347 void UpdateStatus(Handle<Object> object); 1348 IsMonomorphic()1349 bool IsMonomorphic() const { return state().Contains(MONOMORPHIC_MAP); } 1350 nil_value()1351 NilValue nil_value() const { return NilValueBits::decode(sub_minor_key()); } 1352 ClearState()1353 void ClearState() { 1354 set_sub_minor_key(TypesBits::update(sub_minor_key(), 0)); 1355 } 1356 1357 virtual void PrintState(OStream& os) const OVERRIDE; // NOLINT 1358 virtual void PrintBaseName(OStream& os) const OVERRIDE; // NOLINT 1359 1360 private: CompareNilICStub(Isolate * isolate,NilValue nil,InitializationState init_state)1361 CompareNilICStub(Isolate* isolate, NilValue nil, 1362 InitializationState init_state) 1363 : HydrogenCodeStub(isolate, init_state) { 1364 set_sub_minor_key(NilValueBits::encode(nil)); 1365 } 1366 1367 enum CompareNilType { 1368 UNDEFINED, 1369 NULL_TYPE, 1370 MONOMORPHIC_MAP, 1371 GENERIC, 1372 NUMBER_OF_TYPES 1373 }; 1374 1375 // At most 6 different types can be distinguished, because the Code object 1376 // only has room for a single byte to hold a set and there are two more 1377 // boolean flags we need to store. :-P 1378 STATIC_ASSERT(NUMBER_OF_TYPES <= 6); 1379 1380 class State : public EnumSet<CompareNilType, byte> { 1381 public: State()1382 State() : EnumSet<CompareNilType, byte>(0) { } State(byte bits)1383 explicit State(byte bits) : EnumSet<CompareNilType, byte>(bits) { } 1384 }; 1385 friend OStream& operator<<(OStream& os, const State& s); 1386 state()1387 State state() const { return State(TypesBits::decode(sub_minor_key())); } 1388 1389 class NilValueBits : public BitField<NilValue, 0, 1> {}; 1390 class TypesBits : public BitField<byte, 1, NUMBER_OF_TYPES> {}; 1391 1392 friend class CompareNilIC; 1393 1394 DEFINE_CALL_INTERFACE_DESCRIPTOR(CompareNil); 1395 DEFINE_HYDROGEN_CODE_STUB(CompareNilIC, HydrogenCodeStub); 1396 }; 1397 1398 1399 OStream& operator<<(OStream& os, const CompareNilICStub::State& s); 1400 1401 1402 class CEntryStub : public PlatformCodeStub { 1403 public: 1404 CEntryStub(Isolate* isolate, int result_size, 1405 SaveFPRegsMode save_doubles = kDontSaveFPRegs) PlatformCodeStub(isolate)1406 : PlatformCodeStub(isolate) { 1407 minor_key_ = SaveDoublesBits::encode(save_doubles == kSaveFPRegs); 1408 DCHECK(result_size == 1 || result_size == 2); 1409 #ifdef _WIN64 1410 minor_key_ = ResultSizeBits::update(minor_key_, result_size); 1411 #endif // _WIN64 1412 } 1413 1414 // The version of this stub that doesn't save doubles is generated ahead of 1415 // time, so it's OK to call it from other stubs that can't cope with GC during 1416 // their code generation. On machines that always have gp registers (x64) we 1417 // can generate both variants ahead of time. 1418 static void GenerateAheadOfTime(Isolate* isolate); 1419 1420 private: save_doubles()1421 bool save_doubles() const { return SaveDoublesBits::decode(minor_key_); } 1422 #ifdef _WIN64 result_size()1423 int result_size() const { return ResultSizeBits::decode(minor_key_); } 1424 #endif // _WIN64 1425 1426 bool NeedsImmovableCode(); 1427 1428 class SaveDoublesBits : public BitField<bool, 0, 1> {}; 1429 class ResultSizeBits : public BitField<int, 1, 3> {}; 1430 1431 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 1432 DEFINE_PLATFORM_CODE_STUB(CEntry, PlatformCodeStub); 1433 }; 1434 1435 1436 class JSEntryStub : public PlatformCodeStub { 1437 public: JSEntryStub(Isolate * isolate,StackFrame::Type type)1438 JSEntryStub(Isolate* isolate, StackFrame::Type type) 1439 : PlatformCodeStub(isolate) { 1440 DCHECK(type == StackFrame::ENTRY || type == StackFrame::ENTRY_CONSTRUCT); 1441 minor_key_ = StackFrameTypeBits::encode(type); 1442 } 1443 1444 private: 1445 virtual void FinishCode(Handle<Code> code); 1446 PrintName(OStream & os)1447 virtual void PrintName(OStream& os) const OVERRIDE { // NOLINT 1448 os << (type() == StackFrame::ENTRY ? "JSEntryStub" 1449 : "JSConstructEntryStub"); 1450 } 1451 type()1452 StackFrame::Type type() const { 1453 return StackFrameTypeBits::decode(minor_key_); 1454 } 1455 1456 class StackFrameTypeBits : public BitField<StackFrame::Type, 0, 5> {}; 1457 1458 int handler_offset_; 1459 1460 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 1461 DEFINE_PLATFORM_CODE_STUB(JSEntry, PlatformCodeStub); 1462 }; 1463 1464 1465 class ArgumentsAccessStub: public PlatformCodeStub { 1466 public: 1467 enum Type { 1468 READ_ELEMENT, 1469 NEW_SLOPPY_FAST, 1470 NEW_SLOPPY_SLOW, 1471 NEW_STRICT 1472 }; 1473 ArgumentsAccessStub(Isolate * isolate,Type type)1474 ArgumentsAccessStub(Isolate* isolate, Type type) : PlatformCodeStub(isolate) { 1475 minor_key_ = TypeBits::encode(type); 1476 } 1477 GetCallInterfaceDescriptor()1478 virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE { 1479 if (type() == READ_ELEMENT) { 1480 return ArgumentsAccessReadDescriptor(isolate()); 1481 } 1482 return ContextOnlyDescriptor(isolate()); 1483 } 1484 1485 private: type()1486 Type type() const { return TypeBits::decode(minor_key_); } 1487 1488 void GenerateReadElement(MacroAssembler* masm); 1489 void GenerateNewStrict(MacroAssembler* masm); 1490 void GenerateNewSloppyFast(MacroAssembler* masm); 1491 void GenerateNewSloppySlow(MacroAssembler* masm); 1492 1493 virtual void PrintName(OStream& os) const OVERRIDE; // NOLINT 1494 1495 class TypeBits : public BitField<Type, 0, 2> {}; 1496 1497 DEFINE_PLATFORM_CODE_STUB(ArgumentsAccess, PlatformCodeStub); 1498 }; 1499 1500 1501 class RegExpExecStub: public PlatformCodeStub { 1502 public: RegExpExecStub(Isolate * isolate)1503 explicit RegExpExecStub(Isolate* isolate) : PlatformCodeStub(isolate) { } 1504 1505 DEFINE_CALL_INTERFACE_DESCRIPTOR(ContextOnly); 1506 DEFINE_PLATFORM_CODE_STUB(RegExpExec, PlatformCodeStub); 1507 }; 1508 1509 1510 class RegExpConstructResultStub FINAL : public HydrogenCodeStub { 1511 public: RegExpConstructResultStub(Isolate * isolate)1512 explicit RegExpConstructResultStub(Isolate* isolate) 1513 : HydrogenCodeStub(isolate) { } 1514 1515 // Parameters accessed via CodeStubGraphBuilder::GetParameter() 1516 static const int kLength = 0; 1517 static const int kIndex = 1; 1518 static const int kInput = 2; 1519 1520 DEFINE_CALL_INTERFACE_DESCRIPTOR(RegExpConstructResult); 1521 DEFINE_HYDROGEN_CODE_STUB(RegExpConstructResult, HydrogenCodeStub); 1522 }; 1523 1524 1525 class CallFunctionStub: public PlatformCodeStub { 1526 public: CallFunctionStub(Isolate * isolate,int argc,CallFunctionFlags flags)1527 CallFunctionStub(Isolate* isolate, int argc, CallFunctionFlags flags) 1528 : PlatformCodeStub(isolate) { 1529 DCHECK(argc >= 0 && argc <= Code::kMaxArguments); 1530 minor_key_ = ArgcBits::encode(argc) | FlagBits::encode(flags); 1531 } 1532 ExtractArgcFromMinorKey(int minor_key)1533 static int ExtractArgcFromMinorKey(int minor_key) { 1534 return ArgcBits::decode(minor_key); 1535 } 1536 1537 private: argc()1538 int argc() const { return ArgcBits::decode(minor_key_); } flags()1539 int flags() const { return FlagBits::decode(minor_key_); } 1540 CallAsMethod()1541 bool CallAsMethod() const { 1542 return flags() == CALL_AS_METHOD || flags() == WRAP_AND_CALL; 1543 } 1544 NeedsChecks()1545 bool NeedsChecks() const { return flags() != WRAP_AND_CALL; } 1546 1547 virtual void PrintName(OStream& os) const OVERRIDE; // NOLINT 1548 1549 // Minor key encoding in 32 bits with Bitfield <Type, shift, size>. 1550 class FlagBits : public BitField<CallFunctionFlags, 0, 2> {}; 1551 class ArgcBits : public BitField<unsigned, 2, Code::kArgumentsBits> {}; 1552 STATIC_ASSERT(Code::kArgumentsBits + 2 <= kStubMinorKeyBits); 1553 1554 DEFINE_CALL_INTERFACE_DESCRIPTOR(CallFunction); 1555 DEFINE_PLATFORM_CODE_STUB(CallFunction, PlatformCodeStub); 1556 }; 1557 1558 1559 class CallConstructStub: public PlatformCodeStub { 1560 public: CallConstructStub(Isolate * isolate,CallConstructorFlags flags)1561 CallConstructStub(Isolate* isolate, CallConstructorFlags flags) 1562 : PlatformCodeStub(isolate) { 1563 minor_key_ = FlagBits::encode(flags); 1564 } 1565 FinishCode(Handle<Code> code)1566 virtual void FinishCode(Handle<Code> code) { 1567 code->set_has_function_cache(RecordCallTarget()); 1568 } 1569 1570 private: flags()1571 CallConstructorFlags flags() const { return FlagBits::decode(minor_key_); } 1572 RecordCallTarget()1573 bool RecordCallTarget() const { 1574 return (flags() & RECORD_CONSTRUCTOR_TARGET) != 0; 1575 } 1576 1577 virtual void PrintName(OStream& os) const OVERRIDE; // NOLINT 1578 1579 class FlagBits : public BitField<CallConstructorFlags, 0, 1> {}; 1580 1581 DEFINE_CALL_INTERFACE_DESCRIPTOR(CallConstruct); 1582 DEFINE_PLATFORM_CODE_STUB(CallConstruct, PlatformCodeStub); 1583 }; 1584 1585 1586 enum StringIndexFlags { 1587 // Accepts smis or heap numbers. 1588 STRING_INDEX_IS_NUMBER, 1589 1590 // Accepts smis or heap numbers that are valid array indices 1591 // (ECMA-262 15.4). Invalid indices are reported as being out of 1592 // range. 1593 STRING_INDEX_IS_ARRAY_INDEX 1594 }; 1595 1596 1597 // Generates code implementing String.prototype.charCodeAt. 1598 // 1599 // Only supports the case when the receiver is a string and the index 1600 // is a number (smi or heap number) that is a valid index into the 1601 // string. Additional index constraints are specified by the 1602 // flags. Otherwise, bails out to the provided labels. 1603 // 1604 // Register usage: |object| may be changed to another string in a way 1605 // that doesn't affect charCodeAt/charAt semantics, |index| is 1606 // preserved, |scratch| and |result| are clobbered. 1607 class StringCharCodeAtGenerator { 1608 public: StringCharCodeAtGenerator(Register object,Register index,Register result,Label * receiver_not_string,Label * index_not_number,Label * index_out_of_range,StringIndexFlags index_flags)1609 StringCharCodeAtGenerator(Register object, 1610 Register index, 1611 Register result, 1612 Label* receiver_not_string, 1613 Label* index_not_number, 1614 Label* index_out_of_range, 1615 StringIndexFlags index_flags) 1616 : object_(object), 1617 index_(index), 1618 result_(result), 1619 receiver_not_string_(receiver_not_string), 1620 index_not_number_(index_not_number), 1621 index_out_of_range_(index_out_of_range), 1622 index_flags_(index_flags) { 1623 DCHECK(!result_.is(object_)); 1624 DCHECK(!result_.is(index_)); 1625 } 1626 1627 // Generates the fast case code. On the fallthrough path |result| 1628 // register contains the result. 1629 void GenerateFast(MacroAssembler* masm); 1630 1631 // Generates the slow case code. Must not be naturally 1632 // reachable. Expected to be put after a ret instruction (e.g., in 1633 // deferred code). Always jumps back to the fast case. 1634 void GenerateSlow(MacroAssembler* masm, 1635 const RuntimeCallHelper& call_helper); 1636 1637 // Skip handling slow case and directly jump to bailout. SkipSlow(MacroAssembler * masm,Label * bailout)1638 void SkipSlow(MacroAssembler* masm, Label* bailout) { 1639 masm->bind(&index_not_smi_); 1640 masm->bind(&call_runtime_); 1641 masm->jmp(bailout); 1642 } 1643 1644 private: 1645 Register object_; 1646 Register index_; 1647 Register result_; 1648 1649 Label* receiver_not_string_; 1650 Label* index_not_number_; 1651 Label* index_out_of_range_; 1652 1653 StringIndexFlags index_flags_; 1654 1655 Label call_runtime_; 1656 Label index_not_smi_; 1657 Label got_smi_index_; 1658 Label exit_; 1659 1660 DISALLOW_COPY_AND_ASSIGN(StringCharCodeAtGenerator); 1661 }; 1662 1663 1664 // Generates code for creating a one-char string from a char code. 1665 class StringCharFromCodeGenerator { 1666 public: StringCharFromCodeGenerator(Register code,Register result)1667 StringCharFromCodeGenerator(Register code, 1668 Register result) 1669 : code_(code), 1670 result_(result) { 1671 DCHECK(!code_.is(result_)); 1672 } 1673 1674 // Generates the fast case code. On the fallthrough path |result| 1675 // register contains the result. 1676 void GenerateFast(MacroAssembler* masm); 1677 1678 // Generates the slow case code. Must not be naturally 1679 // reachable. Expected to be put after a ret instruction (e.g., in 1680 // deferred code). Always jumps back to the fast case. 1681 void GenerateSlow(MacroAssembler* masm, 1682 const RuntimeCallHelper& call_helper); 1683 1684 // Skip handling slow case and directly jump to bailout. SkipSlow(MacroAssembler * masm,Label * bailout)1685 void SkipSlow(MacroAssembler* masm, Label* bailout) { 1686 masm->bind(&slow_case_); 1687 masm->jmp(bailout); 1688 } 1689 1690 private: 1691 Register code_; 1692 Register result_; 1693 1694 Label slow_case_; 1695 Label exit_; 1696 1697 DISALLOW_COPY_AND_ASSIGN(StringCharFromCodeGenerator); 1698 }; 1699 1700 1701 // Generates code implementing String.prototype.charAt. 1702 // 1703 // Only supports the case when the receiver is a string and the index 1704 // is a number (smi or heap number) that is a valid index into the 1705 // string. Additional index constraints are specified by the 1706 // flags. Otherwise, bails out to the provided labels. 1707 // 1708 // Register usage: |object| may be changed to another string in a way 1709 // that doesn't affect charCodeAt/charAt semantics, |index| is 1710 // preserved, |scratch1|, |scratch2|, and |result| are clobbered. 1711 class StringCharAtGenerator { 1712 public: StringCharAtGenerator(Register object,Register index,Register scratch,Register result,Label * receiver_not_string,Label * index_not_number,Label * index_out_of_range,StringIndexFlags index_flags)1713 StringCharAtGenerator(Register object, 1714 Register index, 1715 Register scratch, 1716 Register result, 1717 Label* receiver_not_string, 1718 Label* index_not_number, 1719 Label* index_out_of_range, 1720 StringIndexFlags index_flags) 1721 : char_code_at_generator_(object, 1722 index, 1723 scratch, 1724 receiver_not_string, 1725 index_not_number, 1726 index_out_of_range, 1727 index_flags), 1728 char_from_code_generator_(scratch, result) {} 1729 1730 // Generates the fast case code. On the fallthrough path |result| 1731 // register contains the result. GenerateFast(MacroAssembler * masm)1732 void GenerateFast(MacroAssembler* masm) { 1733 char_code_at_generator_.GenerateFast(masm); 1734 char_from_code_generator_.GenerateFast(masm); 1735 } 1736 1737 // Generates the slow case code. Must not be naturally 1738 // reachable. Expected to be put after a ret instruction (e.g., in 1739 // deferred code). Always jumps back to the fast case. GenerateSlow(MacroAssembler * masm,const RuntimeCallHelper & call_helper)1740 void GenerateSlow(MacroAssembler* masm, 1741 const RuntimeCallHelper& call_helper) { 1742 char_code_at_generator_.GenerateSlow(masm, call_helper); 1743 char_from_code_generator_.GenerateSlow(masm, call_helper); 1744 } 1745 1746 // Skip handling slow case and directly jump to bailout. SkipSlow(MacroAssembler * masm,Label * bailout)1747 void SkipSlow(MacroAssembler* masm, Label* bailout) { 1748 char_code_at_generator_.SkipSlow(masm, bailout); 1749 char_from_code_generator_.SkipSlow(masm, bailout); 1750 } 1751 1752 private: 1753 StringCharCodeAtGenerator char_code_at_generator_; 1754 StringCharFromCodeGenerator char_from_code_generator_; 1755 1756 DISALLOW_COPY_AND_ASSIGN(StringCharAtGenerator); 1757 }; 1758 1759 1760 class LoadDictionaryElementStub : public HydrogenCodeStub { 1761 public: LoadDictionaryElementStub(Isolate * isolate)1762 explicit LoadDictionaryElementStub(Isolate* isolate) 1763 : HydrogenCodeStub(isolate) {} 1764 1765 DEFINE_CALL_INTERFACE_DESCRIPTOR(Load); 1766 DEFINE_HYDROGEN_CODE_STUB(LoadDictionaryElement, HydrogenCodeStub); 1767 }; 1768 1769 1770 class KeyedLoadGenericStub : public HydrogenCodeStub { 1771 public: KeyedLoadGenericStub(Isolate * isolate)1772 explicit KeyedLoadGenericStub(Isolate* isolate) : HydrogenCodeStub(isolate) {} 1773 GetCodeKind()1774 virtual Code::Kind GetCodeKind() const { return Code::KEYED_LOAD_IC; } GetICState()1775 virtual InlineCacheState GetICState() const { return GENERIC; } 1776 1777 DEFINE_CALL_INTERFACE_DESCRIPTOR(Load); 1778 DEFINE_HYDROGEN_CODE_STUB(KeyedLoadGeneric, HydrogenCodeStub); 1779 }; 1780 1781 1782 class LoadICTrampolineStub : public PlatformCodeStub { 1783 public: LoadICTrampolineStub(Isolate * isolate,const LoadICState & state)1784 LoadICTrampolineStub(Isolate* isolate, const LoadICState& state) 1785 : PlatformCodeStub(isolate) { 1786 minor_key_ = state.GetExtraICState(); 1787 } 1788 GetCodeKind()1789 virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; } 1790 GetICState()1791 virtual InlineCacheState GetICState() const FINAL OVERRIDE { 1792 return GENERIC; 1793 } 1794 GetExtraICState()1795 virtual ExtraICState GetExtraICState() const FINAL OVERRIDE { 1796 return static_cast<ExtraICState>(minor_key_); 1797 } 1798 1799 private: state()1800 LoadICState state() const { 1801 return LoadICState(static_cast<ExtraICState>(minor_key_)); 1802 } 1803 1804 DEFINE_CALL_INTERFACE_DESCRIPTOR(VectorLoadICTrampoline); 1805 DEFINE_PLATFORM_CODE_STUB(LoadICTrampoline, PlatformCodeStub); 1806 }; 1807 1808 1809 class KeyedLoadICTrampolineStub : public LoadICTrampolineStub { 1810 public: KeyedLoadICTrampolineStub(Isolate * isolate)1811 explicit KeyedLoadICTrampolineStub(Isolate* isolate) 1812 : LoadICTrampolineStub(isolate, LoadICState(0)) {} 1813 GetCodeKind()1814 virtual Code::Kind GetCodeKind() const OVERRIDE { 1815 return Code::KEYED_LOAD_IC; 1816 } 1817 1818 DEFINE_PLATFORM_CODE_STUB(KeyedLoadICTrampoline, LoadICTrampolineStub); 1819 }; 1820 1821 1822 class MegamorphicLoadStub : public HydrogenCodeStub { 1823 public: MegamorphicLoadStub(Isolate * isolate,const LoadICState & state)1824 MegamorphicLoadStub(Isolate* isolate, const LoadICState& state) 1825 : HydrogenCodeStub(isolate) { 1826 set_sub_minor_key(state.GetExtraICState()); 1827 } 1828 GetCodeKind()1829 virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; } 1830 GetICState()1831 virtual InlineCacheState GetICState() const FINAL OVERRIDE { 1832 return MEGAMORPHIC; 1833 } 1834 GetExtraICState()1835 virtual ExtraICState GetExtraICState() const FINAL OVERRIDE { 1836 return static_cast<ExtraICState>(sub_minor_key()); 1837 } 1838 1839 DEFINE_CALL_INTERFACE_DESCRIPTOR(Load); 1840 DEFINE_HYDROGEN_CODE_STUB(MegamorphicLoad, HydrogenCodeStub); 1841 }; 1842 1843 1844 class VectorLoadStub : public HydrogenCodeStub { 1845 public: VectorLoadStub(Isolate * isolate,const LoadICState & state)1846 explicit VectorLoadStub(Isolate* isolate, const LoadICState& state) 1847 : HydrogenCodeStub(isolate) { 1848 set_sub_minor_key(state.GetExtraICState()); 1849 } 1850 GetCodeKind()1851 virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; } 1852 GetICState()1853 virtual InlineCacheState GetICState() const FINAL OVERRIDE { 1854 return GENERIC; 1855 } 1856 GetExtraICState()1857 virtual ExtraICState GetExtraICState() const FINAL OVERRIDE { 1858 return static_cast<ExtraICState>(sub_minor_key()); 1859 } 1860 1861 private: state()1862 LoadICState state() const { return LoadICState(GetExtraICState()); } 1863 1864 DEFINE_CALL_INTERFACE_DESCRIPTOR(VectorLoadIC); 1865 DEFINE_HYDROGEN_CODE_STUB(VectorLoad, HydrogenCodeStub); 1866 }; 1867 1868 1869 class VectorKeyedLoadStub : public VectorLoadStub { 1870 public: VectorKeyedLoadStub(Isolate * isolate)1871 explicit VectorKeyedLoadStub(Isolate* isolate) 1872 : VectorLoadStub(isolate, LoadICState(0)) {} 1873 GetCodeKind()1874 virtual Code::Kind GetCodeKind() const OVERRIDE { 1875 return Code::KEYED_LOAD_IC; 1876 } 1877 1878 DEFINE_CALL_INTERFACE_DESCRIPTOR(VectorLoadIC); 1879 DEFINE_HYDROGEN_CODE_STUB(VectorKeyedLoad, VectorLoadStub); 1880 }; 1881 1882 1883 class DoubleToIStub : public PlatformCodeStub { 1884 public: 1885 DoubleToIStub(Isolate* isolate, Register source, Register destination, 1886 int offset, bool is_truncating, bool skip_fastpath = false) PlatformCodeStub(isolate)1887 : PlatformCodeStub(isolate) { 1888 minor_key_ = SourceRegisterBits::encode(source.code()) | 1889 DestinationRegisterBits::encode(destination.code()) | 1890 OffsetBits::encode(offset) | 1891 IsTruncatingBits::encode(is_truncating) | 1892 SkipFastPathBits::encode(skip_fastpath) | 1893 SSE3Bits::encode(CpuFeatures::IsSupported(SSE3) ? 1 : 0); 1894 } 1895 SometimesSetsUpAFrame()1896 virtual bool SometimesSetsUpAFrame() { return false; } 1897 1898 private: source()1899 Register source() const { 1900 return Register::from_code(SourceRegisterBits::decode(minor_key_)); 1901 } destination()1902 Register destination() const { 1903 return Register::from_code(DestinationRegisterBits::decode(minor_key_)); 1904 } is_truncating()1905 bool is_truncating() const { return IsTruncatingBits::decode(minor_key_); } skip_fastpath()1906 bool skip_fastpath() const { return SkipFastPathBits::decode(minor_key_); } offset()1907 int offset() const { return OffsetBits::decode(minor_key_); } 1908 1909 static const int kBitsPerRegisterNumber = 6; 1910 STATIC_ASSERT((1L << kBitsPerRegisterNumber) >= Register::kNumRegisters); 1911 class SourceRegisterBits: 1912 public BitField<int, 0, kBitsPerRegisterNumber> {}; // NOLINT 1913 class DestinationRegisterBits: 1914 public BitField<int, kBitsPerRegisterNumber, 1915 kBitsPerRegisterNumber> {}; // NOLINT 1916 class IsTruncatingBits: 1917 public BitField<bool, 2 * kBitsPerRegisterNumber, 1> {}; // NOLINT 1918 class OffsetBits: 1919 public BitField<int, 2 * kBitsPerRegisterNumber + 1, 3> {}; // NOLINT 1920 class SkipFastPathBits: 1921 public BitField<int, 2 * kBitsPerRegisterNumber + 4, 1> {}; // NOLINT 1922 class SSE3Bits: 1923 public BitField<int, 2 * kBitsPerRegisterNumber + 5, 1> {}; // NOLINT 1924 1925 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 1926 DEFINE_PLATFORM_CODE_STUB(DoubleToI, PlatformCodeStub); 1927 }; 1928 1929 1930 class LoadFastElementStub : public HydrogenCodeStub { 1931 public: LoadFastElementStub(Isolate * isolate,bool is_js_array,ElementsKind elements_kind)1932 LoadFastElementStub(Isolate* isolate, bool is_js_array, 1933 ElementsKind elements_kind) 1934 : HydrogenCodeStub(isolate) { 1935 set_sub_minor_key(ElementsKindBits::encode(elements_kind) | 1936 IsJSArrayBits::encode(is_js_array)); 1937 } 1938 is_js_array()1939 bool is_js_array() const { return IsJSArrayBits::decode(sub_minor_key()); } 1940 elements_kind()1941 ElementsKind elements_kind() const { 1942 return ElementsKindBits::decode(sub_minor_key()); 1943 } 1944 1945 private: 1946 class ElementsKindBits: public BitField<ElementsKind, 0, 8> {}; 1947 class IsJSArrayBits: public BitField<bool, 8, 1> {}; 1948 1949 DEFINE_CALL_INTERFACE_DESCRIPTOR(Load); 1950 DEFINE_HYDROGEN_CODE_STUB(LoadFastElement, HydrogenCodeStub); 1951 }; 1952 1953 1954 class StoreFastElementStub : public HydrogenCodeStub { 1955 public: StoreFastElementStub(Isolate * isolate,bool is_js_array,ElementsKind elements_kind,KeyedAccessStoreMode mode)1956 StoreFastElementStub(Isolate* isolate, bool is_js_array, 1957 ElementsKind elements_kind, KeyedAccessStoreMode mode) 1958 : HydrogenCodeStub(isolate) { 1959 set_sub_minor_key(ElementsKindBits::encode(elements_kind) | 1960 IsJSArrayBits::encode(is_js_array) | 1961 StoreModeBits::encode(mode)); 1962 } 1963 is_js_array()1964 bool is_js_array() const { return IsJSArrayBits::decode(sub_minor_key()); } 1965 elements_kind()1966 ElementsKind elements_kind() const { 1967 return ElementsKindBits::decode(sub_minor_key()); 1968 } 1969 store_mode()1970 KeyedAccessStoreMode store_mode() const { 1971 return StoreModeBits::decode(sub_minor_key()); 1972 } 1973 1974 private: 1975 class ElementsKindBits: public BitField<ElementsKind, 0, 8> {}; 1976 class StoreModeBits: public BitField<KeyedAccessStoreMode, 8, 4> {}; 1977 class IsJSArrayBits: public BitField<bool, 12, 1> {}; 1978 1979 DEFINE_CALL_INTERFACE_DESCRIPTOR(Store); 1980 DEFINE_HYDROGEN_CODE_STUB(StoreFastElement, HydrogenCodeStub); 1981 }; 1982 1983 1984 class TransitionElementsKindStub : public HydrogenCodeStub { 1985 public: TransitionElementsKindStub(Isolate * isolate,ElementsKind from_kind,ElementsKind to_kind,bool is_js_array)1986 TransitionElementsKindStub(Isolate* isolate, 1987 ElementsKind from_kind, 1988 ElementsKind to_kind, 1989 bool is_js_array) : HydrogenCodeStub(isolate) { 1990 set_sub_minor_key(FromKindBits::encode(from_kind) | 1991 ToKindBits::encode(to_kind) | 1992 IsJSArrayBits::encode(is_js_array)); 1993 } 1994 from_kind()1995 ElementsKind from_kind() const { 1996 return FromKindBits::decode(sub_minor_key()); 1997 } 1998 to_kind()1999 ElementsKind to_kind() const { return ToKindBits::decode(sub_minor_key()); } 2000 is_js_array()2001 bool is_js_array() const { return IsJSArrayBits::decode(sub_minor_key()); } 2002 2003 private: 2004 class FromKindBits: public BitField<ElementsKind, 8, 8> {}; 2005 class ToKindBits: public BitField<ElementsKind, 0, 8> {}; 2006 class IsJSArrayBits: public BitField<bool, 16, 1> {}; 2007 2008 DEFINE_CALL_INTERFACE_DESCRIPTOR(TransitionElementsKind); 2009 DEFINE_HYDROGEN_CODE_STUB(TransitionElementsKind, HydrogenCodeStub); 2010 }; 2011 2012 2013 class ArrayConstructorStubBase : public HydrogenCodeStub { 2014 public: ArrayConstructorStubBase(Isolate * isolate,ElementsKind kind,AllocationSiteOverrideMode override_mode)2015 ArrayConstructorStubBase(Isolate* isolate, 2016 ElementsKind kind, 2017 AllocationSiteOverrideMode override_mode) 2018 : HydrogenCodeStub(isolate) { 2019 // It only makes sense to override local allocation site behavior 2020 // if there is a difference between the global allocation site policy 2021 // for an ElementsKind and the desired usage of the stub. 2022 DCHECK(override_mode != DISABLE_ALLOCATION_SITES || 2023 AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE); 2024 set_sub_minor_key(ElementsKindBits::encode(kind) | 2025 AllocationSiteOverrideModeBits::encode(override_mode)); 2026 } 2027 elements_kind()2028 ElementsKind elements_kind() const { 2029 return ElementsKindBits::decode(sub_minor_key()); 2030 } 2031 override_mode()2032 AllocationSiteOverrideMode override_mode() const { 2033 return AllocationSiteOverrideModeBits::decode(sub_minor_key()); 2034 } 2035 2036 static void GenerateStubsAheadOfTime(Isolate* isolate); 2037 2038 // Parameters accessed via CodeStubGraphBuilder::GetParameter() 2039 static const int kConstructor = 0; 2040 static const int kAllocationSite = 1; 2041 2042 protected: 2043 OStream& BasePrintName(OStream& os, const char* name) const; // NOLINT 2044 2045 private: 2046 // Ensure data fits within available bits. 2047 STATIC_ASSERT(LAST_ALLOCATION_SITE_OVERRIDE_MODE == 1); 2048 2049 class ElementsKindBits: public BitField<ElementsKind, 0, 8> {}; 2050 class AllocationSiteOverrideModeBits: public 2051 BitField<AllocationSiteOverrideMode, 8, 1> {}; // NOLINT 2052 2053 DEFINE_CODE_STUB_BASE(ArrayConstructorStubBase, HydrogenCodeStub); 2054 }; 2055 2056 2057 class ArrayNoArgumentConstructorStub : public ArrayConstructorStubBase { 2058 public: 2059 ArrayNoArgumentConstructorStub( 2060 Isolate* isolate, 2061 ElementsKind kind, 2062 AllocationSiteOverrideMode override_mode = DONT_OVERRIDE) ArrayConstructorStubBase(isolate,kind,override_mode)2063 : ArrayConstructorStubBase(isolate, kind, override_mode) { 2064 } 2065 2066 private: PrintName(OStream & os)2067 virtual void PrintName(OStream& os) const OVERRIDE { // NOLINT 2068 BasePrintName(os, "ArrayNoArgumentConstructorStub"); 2069 } 2070 2071 DEFINE_CALL_INTERFACE_DESCRIPTOR(ArrayConstructorConstantArgCount); 2072 DEFINE_HYDROGEN_CODE_STUB(ArrayNoArgumentConstructor, 2073 ArrayConstructorStubBase); 2074 }; 2075 2076 2077 class ArraySingleArgumentConstructorStub : public ArrayConstructorStubBase { 2078 public: 2079 ArraySingleArgumentConstructorStub( 2080 Isolate* isolate, 2081 ElementsKind kind, 2082 AllocationSiteOverrideMode override_mode = DONT_OVERRIDE) ArrayConstructorStubBase(isolate,kind,override_mode)2083 : ArrayConstructorStubBase(isolate, kind, override_mode) { 2084 } 2085 2086 private: PrintName(OStream & os)2087 virtual void PrintName(OStream& os) const { // NOLINT 2088 BasePrintName(os, "ArraySingleArgumentConstructorStub"); 2089 } 2090 2091 DEFINE_CALL_INTERFACE_DESCRIPTOR(ArrayConstructor); 2092 DEFINE_HYDROGEN_CODE_STUB(ArraySingleArgumentConstructor, 2093 ArrayConstructorStubBase); 2094 }; 2095 2096 2097 class ArrayNArgumentsConstructorStub : public ArrayConstructorStubBase { 2098 public: 2099 ArrayNArgumentsConstructorStub( 2100 Isolate* isolate, 2101 ElementsKind kind, 2102 AllocationSiteOverrideMode override_mode = DONT_OVERRIDE) ArrayConstructorStubBase(isolate,kind,override_mode)2103 : ArrayConstructorStubBase(isolate, kind, override_mode) { 2104 } 2105 2106 private: PrintName(OStream & os)2107 virtual void PrintName(OStream& os) const { // NOLINT 2108 BasePrintName(os, "ArrayNArgumentsConstructorStub"); 2109 } 2110 2111 DEFINE_CALL_INTERFACE_DESCRIPTOR(ArrayConstructor); 2112 DEFINE_HYDROGEN_CODE_STUB(ArrayNArgumentsConstructor, 2113 ArrayConstructorStubBase); 2114 }; 2115 2116 2117 class InternalArrayConstructorStubBase : public HydrogenCodeStub { 2118 public: InternalArrayConstructorStubBase(Isolate * isolate,ElementsKind kind)2119 InternalArrayConstructorStubBase(Isolate* isolate, ElementsKind kind) 2120 : HydrogenCodeStub(isolate) { 2121 set_sub_minor_key(ElementsKindBits::encode(kind)); 2122 } 2123 2124 static void GenerateStubsAheadOfTime(Isolate* isolate); 2125 2126 // Parameters accessed via CodeStubGraphBuilder::GetParameter() 2127 static const int kConstructor = 0; 2128 elements_kind()2129 ElementsKind elements_kind() const { 2130 return ElementsKindBits::decode(sub_minor_key()); 2131 } 2132 2133 private: 2134 class ElementsKindBits : public BitField<ElementsKind, 0, 8> {}; 2135 2136 DEFINE_CODE_STUB_BASE(InternalArrayConstructorStubBase, HydrogenCodeStub); 2137 }; 2138 2139 2140 class InternalArrayNoArgumentConstructorStub : public 2141 InternalArrayConstructorStubBase { 2142 public: InternalArrayNoArgumentConstructorStub(Isolate * isolate,ElementsKind kind)2143 InternalArrayNoArgumentConstructorStub(Isolate* isolate, 2144 ElementsKind kind) 2145 : InternalArrayConstructorStubBase(isolate, kind) { } 2146 2147 DEFINE_CALL_INTERFACE_DESCRIPTOR(InternalArrayConstructorConstantArgCount); 2148 DEFINE_HYDROGEN_CODE_STUB(InternalArrayNoArgumentConstructor, 2149 InternalArrayConstructorStubBase); 2150 }; 2151 2152 2153 class InternalArraySingleArgumentConstructorStub : public 2154 InternalArrayConstructorStubBase { 2155 public: InternalArraySingleArgumentConstructorStub(Isolate * isolate,ElementsKind kind)2156 InternalArraySingleArgumentConstructorStub(Isolate* isolate, 2157 ElementsKind kind) 2158 : InternalArrayConstructorStubBase(isolate, kind) { } 2159 2160 DEFINE_CALL_INTERFACE_DESCRIPTOR(InternalArrayConstructor); 2161 DEFINE_HYDROGEN_CODE_STUB(InternalArraySingleArgumentConstructor, 2162 InternalArrayConstructorStubBase); 2163 }; 2164 2165 2166 class InternalArrayNArgumentsConstructorStub : public 2167 InternalArrayConstructorStubBase { 2168 public: InternalArrayNArgumentsConstructorStub(Isolate * isolate,ElementsKind kind)2169 InternalArrayNArgumentsConstructorStub(Isolate* isolate, ElementsKind kind) 2170 : InternalArrayConstructorStubBase(isolate, kind) { } 2171 2172 DEFINE_CALL_INTERFACE_DESCRIPTOR(InternalArrayConstructor); 2173 DEFINE_HYDROGEN_CODE_STUB(InternalArrayNArgumentsConstructor, 2174 InternalArrayConstructorStubBase); 2175 }; 2176 2177 2178 class StoreElementStub : public PlatformCodeStub { 2179 public: StoreElementStub(Isolate * isolate,ElementsKind elements_kind)2180 StoreElementStub(Isolate* isolate, ElementsKind elements_kind) 2181 : PlatformCodeStub(isolate) { 2182 minor_key_ = ElementsKindBits::encode(elements_kind); 2183 } 2184 2185 private: elements_kind()2186 ElementsKind elements_kind() const { 2187 return ElementsKindBits::decode(minor_key_); 2188 } 2189 2190 class ElementsKindBits : public BitField<ElementsKind, 0, 8> {}; 2191 2192 DEFINE_CALL_INTERFACE_DESCRIPTOR(Store); 2193 DEFINE_PLATFORM_CODE_STUB(StoreElement, PlatformCodeStub); 2194 }; 2195 2196 2197 class ToBooleanStub: public HydrogenCodeStub { 2198 public: 2199 enum Type { 2200 UNDEFINED, 2201 BOOLEAN, 2202 NULL_TYPE, 2203 SMI, 2204 SPEC_OBJECT, 2205 STRING, 2206 SYMBOL, 2207 HEAP_NUMBER, 2208 NUMBER_OF_TYPES 2209 }; 2210 2211 enum ResultMode { 2212 RESULT_AS_SMI, // For Smi(1) on truthy value, Smi(0) otherwise. 2213 RESULT_AS_ODDBALL, // For {true} on truthy value, {false} otherwise. 2214 RESULT_AS_INVERSE_ODDBALL // For {false} on truthy value, {true} otherwise. 2215 }; 2216 2217 // At most 8 different types can be distinguished, because the Code object 2218 // only has room for a single byte to hold a set of these types. :-P 2219 STATIC_ASSERT(NUMBER_OF_TYPES <= 8); 2220 2221 class Types : public EnumSet<Type, byte> { 2222 public: Types()2223 Types() : EnumSet<Type, byte>(0) {} Types(byte bits)2224 explicit Types(byte bits) : EnumSet<Type, byte>(bits) {} 2225 ToByte()2226 byte ToByte() const { return ToIntegral(); } 2227 bool UpdateStatus(Handle<Object> object); 2228 bool NeedsMap() const; 2229 bool CanBeUndetectable() const; IsGeneric()2230 bool IsGeneric() const { return ToIntegral() == Generic().ToIntegral(); } 2231 Generic()2232 static Types Generic() { return Types((1 << NUMBER_OF_TYPES) - 1); } 2233 }; 2234 2235 ToBooleanStub(Isolate* isolate, ResultMode mode, Types types = Types()) HydrogenCodeStub(isolate)2236 : HydrogenCodeStub(isolate) { 2237 set_sub_minor_key(TypesBits::encode(types.ToByte()) | 2238 ResultModeBits::encode(mode)); 2239 } 2240 ToBooleanStub(Isolate * isolate,ExtraICState state)2241 ToBooleanStub(Isolate* isolate, ExtraICState state) 2242 : HydrogenCodeStub(isolate) { 2243 set_sub_minor_key(TypesBits::encode(static_cast<byte>(state)) | 2244 ResultModeBits::encode(RESULT_AS_SMI)); 2245 } 2246 2247 bool UpdateStatus(Handle<Object> object); types()2248 Types types() const { return Types(TypesBits::decode(sub_minor_key())); } mode()2249 ResultMode mode() const { return ResultModeBits::decode(sub_minor_key()); } 2250 GetCodeKind()2251 virtual Code::Kind GetCodeKind() const { return Code::TO_BOOLEAN_IC; } 2252 virtual void PrintState(OStream& os) const OVERRIDE; // NOLINT 2253 SometimesSetsUpAFrame()2254 virtual bool SometimesSetsUpAFrame() { return false; } 2255 GetUninitialized(Isolate * isolate)2256 static Handle<Code> GetUninitialized(Isolate* isolate) { 2257 return ToBooleanStub(isolate, UNINITIALIZED).GetCode(); 2258 } 2259 GetExtraICState()2260 virtual ExtraICState GetExtraICState() const { return types().ToIntegral(); } 2261 GetICState()2262 virtual InlineCacheState GetICState() const { 2263 if (types().IsEmpty()) { 2264 return ::v8::internal::UNINITIALIZED; 2265 } else { 2266 return MONOMORPHIC; 2267 } 2268 } 2269 2270 private: ToBooleanStub(Isolate * isolate,InitializationState init_state)2271 ToBooleanStub(Isolate* isolate, InitializationState init_state) 2272 : HydrogenCodeStub(isolate, init_state) { 2273 set_sub_minor_key(ResultModeBits::encode(RESULT_AS_SMI)); 2274 } 2275 2276 class TypesBits : public BitField<byte, 0, NUMBER_OF_TYPES> {}; 2277 class ResultModeBits : public BitField<ResultMode, NUMBER_OF_TYPES, 2> {}; 2278 2279 DEFINE_CALL_INTERFACE_DESCRIPTOR(ToBoolean); 2280 DEFINE_HYDROGEN_CODE_STUB(ToBoolean, HydrogenCodeStub); 2281 }; 2282 2283 2284 OStream& operator<<(OStream& os, const ToBooleanStub::Types& t); 2285 2286 2287 class ElementsTransitionAndStoreStub : public HydrogenCodeStub { 2288 public: ElementsTransitionAndStoreStub(Isolate * isolate,ElementsKind from_kind,ElementsKind to_kind,bool is_jsarray,KeyedAccessStoreMode store_mode)2289 ElementsTransitionAndStoreStub(Isolate* isolate, ElementsKind from_kind, 2290 ElementsKind to_kind, bool is_jsarray, 2291 KeyedAccessStoreMode store_mode) 2292 : HydrogenCodeStub(isolate) { 2293 set_sub_minor_key(FromBits::encode(from_kind) | ToBits::encode(to_kind) | 2294 IsJSArrayBits::encode(is_jsarray) | 2295 StoreModeBits::encode(store_mode)); 2296 } 2297 from_kind()2298 ElementsKind from_kind() const { return FromBits::decode(sub_minor_key()); } to_kind()2299 ElementsKind to_kind() const { return ToBits::decode(sub_minor_key()); } is_jsarray()2300 bool is_jsarray() const { return IsJSArrayBits::decode(sub_minor_key()); } store_mode()2301 KeyedAccessStoreMode store_mode() const { 2302 return StoreModeBits::decode(sub_minor_key()); 2303 } 2304 2305 // Parameters accessed via CodeStubGraphBuilder::GetParameter() 2306 enum ParameterIndices { 2307 kValueIndex, 2308 kMapIndex, 2309 kKeyIndex, 2310 kObjectIndex, 2311 kParameterCount 2312 }; 2313 ValueRegister()2314 static const Register ValueRegister() { 2315 return ElementTransitionAndStoreDescriptor::ValueRegister(); 2316 } MapRegister()2317 static const Register MapRegister() { 2318 return ElementTransitionAndStoreDescriptor::MapRegister(); 2319 } KeyRegister()2320 static const Register KeyRegister() { 2321 return ElementTransitionAndStoreDescriptor::NameRegister(); 2322 } ObjectRegister()2323 static const Register ObjectRegister() { 2324 return ElementTransitionAndStoreDescriptor::ReceiverRegister(); 2325 } 2326 2327 private: 2328 class FromBits : public BitField<ElementsKind, 0, 8> {}; 2329 class ToBits : public BitField<ElementsKind, 8, 8> {}; 2330 class IsJSArrayBits : public BitField<bool, 16, 1> {}; 2331 class StoreModeBits : public BitField<KeyedAccessStoreMode, 17, 4> {}; 2332 2333 DEFINE_CALL_INTERFACE_DESCRIPTOR(ElementTransitionAndStore); 2334 DEFINE_HYDROGEN_CODE_STUB(ElementsTransitionAndStore, HydrogenCodeStub); 2335 }; 2336 2337 2338 class StoreArrayLiteralElementStub : public PlatformCodeStub { 2339 public: StoreArrayLiteralElementStub(Isolate * isolate)2340 explicit StoreArrayLiteralElementStub(Isolate* isolate) 2341 : PlatformCodeStub(isolate) { } 2342 2343 DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreArrayLiteralElement); 2344 DEFINE_PLATFORM_CODE_STUB(StoreArrayLiteralElement, PlatformCodeStub); 2345 }; 2346 2347 2348 class StubFailureTrampolineStub : public PlatformCodeStub { 2349 public: StubFailureTrampolineStub(Isolate * isolate,StubFunctionMode function_mode)2350 StubFailureTrampolineStub(Isolate* isolate, StubFunctionMode function_mode) 2351 : PlatformCodeStub(isolate) { 2352 minor_key_ = FunctionModeField::encode(function_mode); 2353 } 2354 2355 static void GenerateAheadOfTime(Isolate* isolate); 2356 2357 private: function_mode()2358 StubFunctionMode function_mode() const { 2359 return FunctionModeField::decode(minor_key_); 2360 } 2361 2362 class FunctionModeField : public BitField<StubFunctionMode, 0, 1> {}; 2363 2364 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 2365 DEFINE_PLATFORM_CODE_STUB(StubFailureTrampoline, PlatformCodeStub); 2366 }; 2367 2368 2369 class ProfileEntryHookStub : public PlatformCodeStub { 2370 public: ProfileEntryHookStub(Isolate * isolate)2371 explicit ProfileEntryHookStub(Isolate* isolate) : PlatformCodeStub(isolate) {} 2372 2373 // The profile entry hook function is not allowed to cause a GC. SometimesSetsUpAFrame()2374 virtual bool SometimesSetsUpAFrame() { return false; } 2375 2376 // Generates a call to the entry hook if it's enabled. 2377 static void MaybeCallEntryHook(MacroAssembler* masm); 2378 2379 private: 2380 static void EntryHookTrampoline(intptr_t function, 2381 intptr_t stack_pointer, 2382 Isolate* isolate); 2383 2384 // ProfileEntryHookStub is called at the start of a function, so it has the 2385 // same register set. 2386 DEFINE_CALL_INTERFACE_DESCRIPTOR(CallFunction) 2387 DEFINE_PLATFORM_CODE_STUB(ProfileEntryHook, PlatformCodeStub); 2388 }; 2389 2390 2391 class StoreBufferOverflowStub : public PlatformCodeStub { 2392 public: StoreBufferOverflowStub(Isolate * isolate,SaveFPRegsMode save_fp)2393 StoreBufferOverflowStub(Isolate* isolate, SaveFPRegsMode save_fp) 2394 : PlatformCodeStub(isolate) { 2395 minor_key_ = SaveDoublesBits::encode(save_fp == kSaveFPRegs); 2396 } 2397 2398 static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate); SometimesSetsUpAFrame()2399 virtual bool SometimesSetsUpAFrame() { return false; } 2400 2401 private: save_doubles()2402 bool save_doubles() const { return SaveDoublesBits::decode(minor_key_); } 2403 2404 class SaveDoublesBits : public BitField<bool, 0, 1> {}; 2405 2406 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 2407 DEFINE_PLATFORM_CODE_STUB(StoreBufferOverflow, PlatformCodeStub); 2408 }; 2409 2410 2411 class SubStringStub : public PlatformCodeStub { 2412 public: SubStringStub(Isolate * isolate)2413 explicit SubStringStub(Isolate* isolate) : PlatformCodeStub(isolate) {} 2414 2415 DEFINE_CALL_INTERFACE_DESCRIPTOR(ContextOnly); 2416 DEFINE_PLATFORM_CODE_STUB(SubString, PlatformCodeStub); 2417 }; 2418 2419 2420 class StringCompareStub : public PlatformCodeStub { 2421 public: StringCompareStub(Isolate * isolate)2422 explicit StringCompareStub(Isolate* isolate) : PlatformCodeStub(isolate) {} 2423 2424 DEFINE_CALL_INTERFACE_DESCRIPTOR(ContextOnly); 2425 DEFINE_PLATFORM_CODE_STUB(StringCompare, PlatformCodeStub); 2426 }; 2427 2428 2429 #undef DEFINE_CALL_INTERFACE_DESCRIPTOR 2430 #undef DEFINE_PLATFORM_CODE_STUB 2431 #undef DEFINE_HANDLER_CODE_STUB 2432 #undef DEFINE_HYDROGEN_CODE_STUB 2433 #undef DEFINE_CODE_STUB 2434 #undef DEFINE_CODE_STUB_BASE 2435 } } // namespace v8::internal 2436 2437 #endif // V8_CODE_STUBS_H_ 2438