From 80adb589335b23a0ec2229b637386183f1a52ade Mon Sep 17 00:00:00 2001 From: "danno@chromium.org" Date: Thu, 18 Apr 2013 20:37:27 +0000 Subject: [PATCH] Add infrastructure to automatucally generate IC miss stubs Review URL: https://codereview.chromium.org/13886013 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14342 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/code-stubs-arm.cc | 24 ++++++++++ src/code-stubs-hydrogen.cc | 92 +++++++++++++++++++++++++++++++----- src/code-stubs.cc | 10 ++++ src/code-stubs.h | 113 +++++++++++++++++++++++++++++--------------- src/ia32/code-stubs-ia32.cc | 25 ++++++++++ src/ic.cc | 7 +++ src/ic.h | 1 + src/x64/code-stubs-x64.cc | 25 ++++++++++ 8 files changed, 248 insertions(+), 49 deletions(-) diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index ef2dbb3..8ad3089 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -161,6 +161,30 @@ static void EmitCheckForHeapNumber(MacroAssembler* masm, Register operand, } +void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { + // Update the static counter each time a new code stub is generated. + Isolate* isolate = masm->isolate(); + isolate->counters()->code_stubs()->Increment(); + + CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate); + int param_count = descriptor->register_param_count_; + { + // Call the runtime system in a fresh internal frame. + FrameScope scope(masm, StackFrame::INTERNAL); + ASSERT(descriptor->register_param_count_ == 0 || + r0.is(descriptor->register_params_[param_count - 1])); + // Push arguments + for (int i = 0; i < param_count; ++i) { + __ push(descriptor->register_params_[i]); + } + ExternalReference miss = descriptor->miss_handler_; + __ CallExternalReference(miss, descriptor->register_param_count_); + } + + __ Ret(); +} + + void ToNumberStub::Generate(MacroAssembler* masm) { // The ToNumber stub takes one argument in eax. Label check_heap_number, call_builtin; diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index 60ddf9b..f866156 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -61,11 +61,7 @@ class CodeStubGraphBuilderBase : public HGraphBuilder { arguments_length_(NULL), info_(stub, isolate), context_(NULL) { - int major_key = stub->MajorKey(); - descriptor_ = isolate->code_stub_interface_descriptor(major_key); - if (descriptor_->register_param_count_ < 0) { - stub->InitializeInterfaceDescriptor(isolate, descriptor_); - } + descriptor_ = stub->GetInterfaceDescriptor(isolate); parameters_.Reset(new HParameter*[descriptor_->register_param_count_]); } virtual bool BuildGraph(); @@ -96,6 +92,9 @@ class CodeStubGraphBuilderBase : public HGraphBuilder { bool CodeStubGraphBuilderBase::BuildGraph() { + // Update the static counter each time a new code stub is generated. + isolate()->counters()->code_stubs()->Increment(); + if (FLAG_trace_hydrogen) { const char* name = CodeStub::MajorName(stub()->MajorKey(), false); PrintF("-----------------------------------------------------------\n"); @@ -176,16 +175,87 @@ class CodeStubGraphBuilder: public CodeStubGraphBuilderBase { : CodeStubGraphBuilderBase(Isolate::Current(), stub) {} protected: - virtual HValue* BuildCodeStub(); + virtual HValue* BuildCodeStub() { + if (casted_stub()->IsMiss()) { + return BuildCodeInitializedStub(); + } else { + return BuildCodeUninitializedStub(); + } + } + + virtual HValue* BuildCodeInitializedStub() { + UNIMPLEMENTED(); + return NULL; + } + + virtual HValue* BuildCodeUninitializedStub() { + // Force a deopt that falls back to the runtime. + HValue* undefined = graph()->GetConstantUndefined(); + CheckBuilder builder(this); + builder.CheckNotUndefined(undefined); + builder.End(); + return undefined; + } + Stub* casted_stub() { return static_cast(stub()); } }; +Handle HydrogenCodeStub::GenerateLightweightMissCode(Isolate* isolate) { + Factory* factory = isolate->factory(); + + // Generate the new code. + MacroAssembler masm(isolate, NULL, 256); + + { + // Update the static counter each time a new code stub is generated. + isolate->counters()->code_stubs()->Increment(); + + // Nested stubs are not allowed for leaves. + AllowStubCallsScope allow_scope(&masm, false); + + // Generate the code for the stub. + masm.set_generating_stub(true); + NoCurrentFrameScope scope(&masm); + GenerateLightweightMiss(&masm); + } + + // Create the code object. + CodeDesc desc; + masm.GetCode(&desc); + + // Copy the generated code into a heap object. + Code::Flags flags = Code::ComputeFlags( + GetCodeKind(), + GetICState(), + GetExtraICState(), + GetStubType(), -1); + Handle new_object = factory->NewCode( + desc, flags, masm.CodeObject(), NeedsImmovableCode()); + return new_object; +} + + template static Handle DoGenerateCode(Stub* stub) { - CodeStubGraphBuilder builder(stub); - LChunk* chunk = OptimizeGraph(builder.CreateGraph()); - return chunk->Codegen(); + Isolate* isolate = Isolate::Current(); + CodeStub::Major major_key = + static_cast(stub)->MajorKey(); + CodeStubInterfaceDescriptor* descriptor = + isolate->code_stub_interface_descriptor(major_key); + if (descriptor->register_param_count_ < 0) { + stub->InitializeInterfaceDescriptor(isolate, descriptor); + } + // The miss case without stack parameters can use a light-weight stub to enter + // the runtime that is significantly faster than using the standard + // stub-failure deopt mechanism. + if (stub->IsMiss() && descriptor->stack_parameter_count_ == NULL) { + return stub->GenerateLightweightMissCode(isolate); + } else { + CodeStubGraphBuilder builder(stub); + LChunk* chunk = OptimizeGraph(builder.CreateGraph()); + return chunk->Codegen(); + } } @@ -248,9 +318,7 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { Handle FastCloneShallowArrayStub::GenerateCode() { - CodeStubGraphBuilder builder(this); - LChunk* chunk = OptimizeGraph(builder.CreateGraph()); - return chunk->Codegen(); + return DoGenerateCode(this); } diff --git a/src/code-stubs.cc b/src/code-stubs.cc index 497dde5..6bda25d 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -37,6 +37,16 @@ namespace v8 { namespace internal { + +CodeStubInterfaceDescriptor::CodeStubInterfaceDescriptor() + : register_param_count_(-1), + stack_parameter_count_(NULL), + function_mode_(NOT_JS_FUNCTION_STUB_MODE), + register_params_(NULL), + deoptimization_handler_(NULL), + miss_handler_(IC_Utility(IC::kUnreachable), Isolate::Current()) { } + + bool CodeStub::FindCodeInCache(Code** code_out, Isolate* isolate) { UnseededNumberDictionary* stubs = isolate->heap()->code_stubs(); int index = stubs->FindEntry(GetKey()); diff --git a/src/code-stubs.h b/src/code-stubs.h index 56b5955..55d7e5d 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -29,6 +29,7 @@ #define V8_CODE_STUBS_H_ #include "allocation.h" +#include "assembler.h" #include "globals.h" #include "codegen.h" @@ -260,17 +261,15 @@ class PlatformCodeStub : public CodeStub { enum StubFunctionMode { NOT_JS_FUNCTION_STUB_MODE, JS_FUNCTION_STUB_MODE }; + struct CodeStubInterfaceDescriptor { - CodeStubInterfaceDescriptor() - : register_param_count_(-1), - stack_parameter_count_(NULL), - function_mode_(NOT_JS_FUNCTION_STUB_MODE), - register_params_(NULL) { } + CodeStubInterfaceDescriptor(); int register_param_count_; const Register* stack_parameter_count_; StubFunctionMode function_mode_; Register* register_params_; Address deoptimization_handler_; + ExternalReference miss_handler_; int environment_length() const { if (stack_parameter_count_ != NULL) { @@ -283,8 +282,14 @@ struct CodeStubInterfaceDescriptor { class HydrogenCodeStub : public CodeStub { public: - // Retrieve the code for the stub. Generate the code if needed. - virtual Handle GenerateCode() = 0; + enum InitializationState { + CODE_STUB_IS_NOT_MISS, + CODE_STUB_IS_MISS + }; + + explicit HydrogenCodeStub(InitializationState state) { + is_miss_ = (state == CODE_STUB_IS_MISS); + } virtual Code::Kind GetCodeKind() const { return Code::STUB; } @@ -292,9 +297,36 @@ class HydrogenCodeStub : public CodeStub { return isolate->code_stub_interface_descriptor(MajorKey()); } + bool IsMiss() { return is_miss_; } + + template + static Handle GetUninitialized(Isolate* isolate) { + SubClass::GenerateAheadOfTime(isolate); + return SubClass().GetCode(isolate); + } + virtual void InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) = 0; + + // Retrieve the code for the stub. Generate the code if needed. + virtual Handle GenerateCode() = 0; + + virtual int NotMissMinorKey() = 0; + + Handle GenerateLightweightMissCode(Isolate* isolate); + + private: + class MinorKeyBits: public BitField {}; + class IsMissBits: public BitField {}; + + void GenerateLightweightMiss(MacroAssembler* masm); + virtual int MinorKey() { + return IsMissBits::encode(is_miss_) | + MinorKeyBits::encode(NotMissMinorKey()); + } + + bool is_miss_; }; @@ -467,7 +499,8 @@ class FastCloneShallowArrayStub : public HydrogenCodeStub { FastCloneShallowArrayStub(Mode mode, AllocationSiteMode allocation_site_mode, int length) - : mode_(mode), + : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS), + mode_(mode), allocation_site_mode_(allocation_site_mode), length_((mode == COPY_ON_WRITE_ELEMENTS) ? 0 : length) { ASSERT_GE(length_, 0); @@ -513,7 +546,7 @@ class FastCloneShallowArrayStub : public HydrogenCodeStub { STATIC_ASSERT(kFastCloneModeCount < 16); STATIC_ASSERT(kMaximumClonedLength < 16); Major MajorKey() { return FastCloneShallowArray; } - int MinorKey() { + int NotMissMinorKey() { return AllocationSiteModeBits::encode(allocation_site_mode_) | ModeBits::encode(mode_) | LengthBits::encode(length_); @@ -526,7 +559,9 @@ class FastCloneShallowObjectStub : public HydrogenCodeStub { // Maximum number of properties in copied object. static const int kMaximumClonedProperties = 6; - explicit FastCloneShallowObjectStub(int length) : length_(length) { + explicit FastCloneShallowObjectStub(int length) + : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS), + length_(length) { ASSERT_GE(length_, 0); ASSERT_LE(length_, kMaximumClonedProperties); } @@ -543,7 +578,7 @@ class FastCloneShallowObjectStub : public HydrogenCodeStub { int length_; Major MajorKey() { return FastCloneShallowObject; } - int MinorKey() { return length_; } + int NotMissMinorKey() { return length_; } DISALLOW_COPY_AND_ASSIGN(FastCloneShallowObjectStub); }; @@ -1291,19 +1326,20 @@ class KeyedLoadDictionaryElementStub : public PlatformCodeStub { public: KeyedLoadDictionaryElementStub() {} - Major MajorKey() { return KeyedLoadElement; } - int MinorKey() { return DICTIONARY_ELEMENTS; } - void Generate(MacroAssembler* masm); private: + Major MajorKey() { return KeyedLoadElement; } + int MinorKey() { return DICTIONARY_ELEMENTS; } + DISALLOW_COPY_AND_ASSIGN(KeyedLoadDictionaryElementStub); }; class KeyedLoadFastElementStub : public HydrogenCodeStub { public: - KeyedLoadFastElementStub(bool is_js_array, ElementsKind elements_kind) { + KeyedLoadFastElementStub(bool is_js_array, ElementsKind elements_kind) + : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) { bit_field_ = ElementsKindBits::encode(elements_kind) | IsJSArrayBits::encode(is_js_array); } @@ -1323,12 +1359,12 @@ class KeyedLoadFastElementStub : public HydrogenCodeStub { CodeStubInterfaceDescriptor* descriptor); private: - class IsJSArrayBits: public BitField {}; class ElementsKindBits: public BitField {}; + class IsJSArrayBits: public BitField {}; uint32_t bit_field_; Major MajorKey() { return KeyedLoadElement; } - int MinorKey() { return bit_field_; } + int NotMissMinorKey() { return bit_field_; } DISALLOW_COPY_AND_ASSIGN(KeyedLoadFastElementStub); }; @@ -1338,15 +1374,13 @@ class KeyedStoreFastElementStub : public HydrogenCodeStub { public: KeyedStoreFastElementStub(bool is_js_array, ElementsKind elements_kind, - KeyedAccessStoreMode mode) { + KeyedAccessStoreMode mode) + : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) { bit_field_ = ElementsKindBits::encode(elements_kind) | IsJSArrayBits::encode(is_js_array) | StoreModeBits::encode(mode); } - Major MajorKey() { return KeyedStoreElement; } - int MinorKey() { return bit_field_; } - bool is_js_array() const { return IsJSArrayBits::decode(bit_field_); } @@ -1371,6 +1405,9 @@ class KeyedStoreFastElementStub : public HydrogenCodeStub { class IsJSArrayBits: public BitField {}; uint32_t bit_field_; + Major MajorKey() { return KeyedStoreElement; } + int NotMissMinorKey() { return bit_field_; } + DISALLOW_COPY_AND_ASSIGN(KeyedStoreFastElementStub); }; @@ -1378,7 +1415,8 @@ class KeyedStoreFastElementStub : public HydrogenCodeStub { class TransitionElementsKindStub : public HydrogenCodeStub { public: TransitionElementsKindStub(ElementsKind from_kind, - ElementsKind to_kind) { + ElementsKind to_kind) + : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) { bit_field_ = FromKindBits::encode(from_kind) | ToKindBits::encode(to_kind); } @@ -1403,7 +1441,7 @@ class TransitionElementsKindStub : public HydrogenCodeStub { uint32_t bit_field_; Major MajorKey() { return TransitionElementsKind; } - int MinorKey() { return bit_field_; } + int NotMissMinorKey() { return bit_field_; } DISALLOW_COPY_AND_ASSIGN(TransitionElementsKindStub); }; @@ -1411,12 +1449,10 @@ class TransitionElementsKindStub : public HydrogenCodeStub { class ArrayNoArgumentConstructorStub : public HydrogenCodeStub { public: - ArrayNoArgumentConstructorStub() { + ArrayNoArgumentConstructorStub() + : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) { } - Major MajorKey() { return ArrayNoArgumentConstructor; } - int MinorKey() { return 0; } - virtual Handle GenerateCode(); virtual void InitializeInterfaceDescriptor( @@ -1424,17 +1460,17 @@ class ArrayNoArgumentConstructorStub : public HydrogenCodeStub { CodeStubInterfaceDescriptor* descriptor); private: + Major MajorKey() { return ArrayNoArgumentConstructor; } + int NotMissMinorKey() { return 0; } + DISALLOW_COPY_AND_ASSIGN(ArrayNoArgumentConstructorStub); }; class ArraySingleArgumentConstructorStub : public HydrogenCodeStub { public: - ArraySingleArgumentConstructorStub() { - } - - Major MajorKey() { return ArraySingleArgumentConstructor; } - int MinorKey() { return 0; } + ArraySingleArgumentConstructorStub() + : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) {} virtual Handle GenerateCode(); @@ -1443,17 +1479,17 @@ class ArraySingleArgumentConstructorStub : public HydrogenCodeStub { CodeStubInterfaceDescriptor* descriptor); private: + Major MajorKey() { return ArraySingleArgumentConstructor; } + int NotMissMinorKey() { return 0; } + DISALLOW_COPY_AND_ASSIGN(ArraySingleArgumentConstructorStub); }; class ArrayNArgumentsConstructorStub : public HydrogenCodeStub { public: - ArrayNArgumentsConstructorStub() { - } - - Major MajorKey() { return ArrayNArgumentsConstructor; } - int MinorKey() { return 0; } + ArrayNArgumentsConstructorStub() + : HydrogenCodeStub(CODE_STUB_IS_NOT_MISS) {} virtual Handle GenerateCode(); @@ -1462,6 +1498,9 @@ class ArrayNArgumentsConstructorStub : public HydrogenCodeStub { CodeStubInterfaceDescriptor* descriptor); private: + Major MajorKey() { return ArrayNArgumentsConstructor; } + int NotMissMinorKey() { return 0; } + DISALLOW_COPY_AND_ASSIGN(ArrayNArgumentsConstructorStub); }; diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 84fe688..e29d834 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -141,6 +141,31 @@ void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( #define __ ACCESS_MASM(masm) + +void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { + // Update the static counter each time a new code stub is generated. + Isolate* isolate = masm->isolate(); + isolate->counters()->code_stubs()->Increment(); + + CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate); + int param_count = descriptor->register_param_count_; + { + // Call the runtime system in a fresh internal frame. + FrameScope scope(masm, StackFrame::INTERNAL); + ASSERT(descriptor->register_param_count_ == 0 || + eax.is(descriptor->register_params_[param_count - 1])); + // Push arguments + for (int i = 0; i < param_count; ++i) { + __ push(descriptor->register_params_[i]); + } + ExternalReference miss = descriptor->miss_handler_; + __ CallExternalReference(miss, descriptor->register_param_count_); + } + + __ ret(0); +} + + void ToNumberStub::Generate(MacroAssembler* masm) { // The ToNumber stub takes one argument in eax. Label check_heap_number, call_builtin; diff --git a/src/ic.cc b/src/ic.cc index 78fb297..fbdffb0 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -2766,6 +2766,13 @@ RUNTIME_FUNCTION(Code*, CompareIC_Miss) { } +RUNTIME_FUNCTION(MaybeObject*, Unreachable) { + UNREACHABLE(); + CHECK(false); + return isolate->heap()->undefined_value(); +} + + RUNTIME_FUNCTION(MaybeObject*, ToBoolean_Patch) { ASSERT(args.length() == 3); diff --git a/src/ic.h b/src/ic.h index 55b5661..6c676e6 100644 --- a/src/ic.h +++ b/src/ic.h @@ -59,6 +59,7 @@ namespace internal { ICU(UnaryOp_Patch) \ ICU(BinaryOp_Patch) \ ICU(CompareIC_Miss) \ + ICU(Unreachable) \ ICU(ToBoolean_Patch) // // IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC, diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 3958cf0..2fecc1e 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -136,6 +136,31 @@ void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( #define __ ACCESS_MASM(masm) + +void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { + // Update the static counter each time a new code stub is generated. + Isolate* isolate = masm->isolate(); + isolate->counters()->code_stubs()->Increment(); + + CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate); + int param_count = descriptor->register_param_count_; + { + // Call the runtime system in a fresh internal frame. + FrameScope scope(masm, StackFrame::INTERNAL); + ASSERT(descriptor->register_param_count_ == 0 || + rax.is(descriptor->register_params_[param_count - 1])); + // Push arguments + for (int i = 0; i < param_count; ++i) { + __ push(descriptor->register_params_[i]); + } + ExternalReference miss = descriptor->miss_handler_; + __ CallExternalReference(miss, descriptor->register_param_count_); + } + + __ Ret(); +} + + void ToNumberStub::Generate(MacroAssembler* masm) { // The ToNumber stub takes one argument in eax. Label check_heap_number, call_builtin; -- 2.7.4