[stubs] Port store IC dispatcher to TurboFan.

This CL introduces StoreICTFStub and StoreICTrampolineTFStub and a switch
to enable them instead of respective platform stubs.

This should ease the split of StoreIC to StoreGlobalIC and StoreIC.

StubCache tests now exercise both load and store ICs.

BUG=chromium:576312

Review-Url: https://codereview.chromium.org/2163253002
Cr-Commit-Position: refs/heads/master@{#39751}
This commit is contained in:
ishell 2016-09-27 00:20:39 -07:00 committed by Commit bot
parent 2c9661a62a
commit 2390243564
9 changed files with 199 additions and 32 deletions

View File

@ -108,6 +108,10 @@ Callable CodeFactory::CallICInOptimizedCode(Isolate* isolate, int argc,
// static
Callable CodeFactory::StoreIC(Isolate* isolate, LanguageMode language_mode) {
if (FLAG_tf_store_ic_stub) {
StoreICTrampolineTFStub stub(isolate, StoreICState(language_mode));
return make_callable(stub);
}
StoreICTrampolineStub stub(isolate, StoreICState(language_mode));
return make_callable(stub);
}
@ -115,6 +119,10 @@ Callable CodeFactory::StoreIC(Isolate* isolate, LanguageMode language_mode) {
// static
Callable CodeFactory::StoreICInOptimizedCode(Isolate* isolate,
LanguageMode language_mode) {
if (FLAG_tf_store_ic_stub) {
StoreICTFStub stub(isolate, StoreICState(language_mode));
return make_callable(stub);
}
StoreICStub stub(isolate, StoreICState(language_mode));
return make_callable(stub);
}

View File

@ -3752,23 +3752,23 @@ compiler::Node* CodeStubAssembler::LoadReceiverMap(compiler::Node* receiver) {
}
compiler::Node* CodeStubAssembler::TryMonomorphicCase(
const LoadICParameters* p, compiler::Node* receiver_map, Label* if_handler,
Variable* var_handler, Label* if_miss) {
compiler::Node* slot, compiler::Node* vector, compiler::Node* receiver_map,
Label* if_handler, Variable* var_handler, Label* if_miss) {
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
// TODO(ishell): add helper class that hides offset computations for a series
// of loads.
int32_t header_size = FixedArray::kHeaderSize - kHeapObjectTag;
Node* offset = ElementOffsetFromIndex(p->slot, FAST_HOLEY_ELEMENTS,
Node* offset = ElementOffsetFromIndex(slot, FAST_HOLEY_ELEMENTS,
SMI_PARAMETERS, header_size);
Node* feedback = Load(MachineType::AnyTagged(), p->vector, offset);
Node* feedback = Load(MachineType::AnyTagged(), vector, offset);
// Try to quickly handle the monomorphic case without knowing for sure
// if we have a weak cell in feedback. We do know it's safe to look
// at WeakCell::kValueOffset.
GotoUnless(WordEqual(receiver_map, LoadWeakCellValue(feedback)), if_miss);
Node* handler = Load(MachineType::AnyTagged(), p->vector,
Node* handler = Load(MachineType::AnyTagged(), vector,
IntPtrAdd(offset, IntPtrConstant(kPointerSize)));
var_handler->Bind(handler);
@ -3777,9 +3777,8 @@ compiler::Node* CodeStubAssembler::TryMonomorphicCase(
}
void CodeStubAssembler::HandlePolymorphicCase(
const LoadICParameters* p, compiler::Node* receiver_map,
compiler::Node* feedback, Label* if_handler, Variable* var_handler,
Label* if_miss, int unroll_count) {
compiler::Node* receiver_map, compiler::Node* feedback, Label* if_handler,
Variable* var_handler, Label* if_miss, int unroll_count) {
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
// Iterate {feedback} array.
@ -4312,8 +4311,9 @@ void CodeStubAssembler::LoadIC(const LoadICParameters* p) {
Node* receiver_map = LoadReceiverMap(p->receiver);
// Check monomorphic case.
Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler,
&var_handler, &try_polymorphic);
Node* feedback =
TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
&var_handler, &try_polymorphic);
Bind(&if_handler);
{
HandleLoadICHandlerCase(p, var_handler.value(), &miss);
@ -4325,7 +4325,7 @@ void CodeStubAssembler::LoadIC(const LoadICParameters* p) {
Comment("LoadIC_try_polymorphic");
GotoUnless(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
&try_megamorphic);
HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler,
HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
&miss, 2);
}
@ -4357,8 +4357,9 @@ void CodeStubAssembler::KeyedLoadIC(const LoadICParameters* p) {
Node* receiver_map = LoadReceiverMap(p->receiver);
// Check monomorphic case.
Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler,
&var_handler, &try_polymorphic);
Node* feedback =
TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
&var_handler, &try_polymorphic);
Bind(&if_handler);
{
HandleLoadICHandlerCase(p, var_handler.value(), &miss, kSupportElements);
@ -4370,7 +4371,7 @@ void CodeStubAssembler::KeyedLoadIC(const LoadICParameters* p) {
Comment("KeyedLoadIC_try_polymorphic");
GotoUnless(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
&try_megamorphic);
HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler,
HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
&miss, 2);
}
@ -4396,8 +4397,8 @@ void CodeStubAssembler::KeyedLoadIC(const LoadICParameters* p) {
p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
HandlePolymorphicCase(p, receiver_map, array, &if_handler, &var_handler,
&miss, 1);
HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss,
1);
}
Bind(&miss);
{
@ -4563,6 +4564,55 @@ void CodeStubAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
}
}
void CodeStubAssembler::StoreIC(const StoreICParameters* p) {
Variable var_handler(this, MachineRepresentation::kTagged);
// TODO(ishell): defer blocks when it works.
Label if_handler(this, &var_handler), try_polymorphic(this),
try_megamorphic(this /*, Label::kDeferred*/),
miss(this /*, Label::kDeferred*/);
Node* receiver_map = LoadReceiverMap(p->receiver);
// Check monomorphic case.
Node* feedback =
TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
&var_handler, &try_polymorphic);
Bind(&if_handler);
{
Comment("StoreIC_if_handler");
StoreWithVectorDescriptor descriptor(isolate());
TailCallStub(descriptor, var_handler.value(), p->context, p->receiver,
p->name, p->value, p->slot, p->vector);
}
Bind(&try_polymorphic);
{
// Check polymorphic case.
Comment("StoreIC_try_polymorphic");
GotoUnless(
WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
&try_megamorphic);
HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
&miss, 2);
}
Bind(&try_megamorphic);
{
// Check megamorphic case.
GotoUnless(
WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
&miss);
TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name,
&if_handler, &var_handler, &miss);
}
Bind(&miss);
{
TailCallRuntime(Runtime::kStoreIC_Miss, p->context, p->value, p->slot,
p->vector, p->receiver, p->name);
}
}
void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) {
Label try_handler(this), miss(this);
Node* weak_cell =

View File

@ -607,7 +607,7 @@ class CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* callable,
compiler::Node* object);
// LoadIC helpers.
// Load/StoreIC helpers.
struct LoadICParameters {
LoadICParameters(compiler::Node* context, compiler::Node* receiver,
compiler::Node* name, compiler::Node* slot,
@ -625,6 +625,15 @@ class CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* vector;
};
struct StoreICParameters : public LoadICParameters {
StoreICParameters(compiler::Node* context, compiler::Node* receiver,
compiler::Node* name, compiler::Node* value,
compiler::Node* slot, compiler::Node* vector)
: LoadICParameters(context, receiver, name, slot, vector),
value(value) {}
compiler::Node* value;
};
// Load type feedback vector from the stub caller's frame.
compiler::Node* LoadTypeFeedbackVectorForStub();
@ -636,12 +645,12 @@ class CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* LoadReceiverMap(compiler::Node* receiver);
// Checks monomorphic case. Returns {feedback} entry of the vector.
compiler::Node* TryMonomorphicCase(const LoadICParameters* p,
compiler::Node* TryMonomorphicCase(compiler::Node* slot,
compiler::Node* vector,
compiler::Node* receiver_map,
Label* if_handler, Variable* var_handler,
Label* if_miss);
void HandlePolymorphicCase(const LoadICParameters* p,
compiler::Node* receiver_map,
void HandlePolymorphicCase(compiler::Node* receiver_map,
compiler::Node* feedback, Label* if_handler,
Variable* var_handler, Label* if_miss,
int unroll_count);
@ -722,6 +731,7 @@ class CodeStubAssembler : public compiler::CodeAssembler {
void LoadGlobalIC(const LoadICParameters* p);
void KeyedLoadIC(const LoadICParameters* p);
void KeyedLoadICGeneric(const LoadICParameters* p);
void StoreIC(const StoreICParameters* p);
void TransitionElementsKind(compiler::Node* object, compiler::Node* map,
ElementsKind from_kind, ElementsKind to_kind,

View File

@ -498,6 +498,37 @@ void KeyedLoadICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const {
assembler->KeyedLoadIC(&p);
}
void StoreICTrampolineTFStub::GenerateAssembly(
CodeStubAssembler* assembler) const {
typedef compiler::Node Node;
Node* receiver = assembler->Parameter(Descriptor::kReceiver);
Node* name = assembler->Parameter(Descriptor::kName);
Node* value = assembler->Parameter(Descriptor::kValue);
Node* slot = assembler->Parameter(Descriptor::kSlot);
Node* context = assembler->Parameter(Descriptor::kContext);
Node* vector = assembler->LoadTypeFeedbackVectorForStub();
CodeStubAssembler::StoreICParameters p(context, receiver, name, value, slot,
vector);
assembler->StoreIC(&p);
}
void StoreICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const {
typedef compiler::Node Node;
Node* receiver = assembler->Parameter(Descriptor::kReceiver);
Node* name = assembler->Parameter(Descriptor::kName);
Node* value = assembler->Parameter(Descriptor::kValue);
Node* slot = assembler->Parameter(Descriptor::kSlot);
Node* vector = assembler->Parameter(Descriptor::kVector);
Node* context = assembler->Parameter(Descriptor::kContext);
CodeStubAssembler::StoreICParameters p(context, receiver, name, value, slot,
vector);
assembler->StoreIC(&p);
}
void StoreTransitionStub::GenerateAssembly(CodeStubAssembler* assembler) const {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;

View File

@ -164,6 +164,7 @@ class ObjectLiteral;
V(StoreFastElement) \
V(StoreField) \
V(StoreGlobal) \
V(StoreICTF) \
V(StoreInterceptor) \
V(StoreTransition) \
V(LoadApiGetter) \
@ -176,7 +177,8 @@ class ObjectLiteral;
/* only */ \
V(LoadICTrampolineTF) \
V(LoadGlobalICTrampoline) \
V(KeyedLoadICTrampolineTF)
V(KeyedLoadICTrampolineTF) \
V(StoreICTrampolineTF)
// List of code stubs only used on ARM 32 bits platforms.
#if V8_TARGET_ARCH_ARM
@ -2414,15 +2416,34 @@ class StoreICTrampolineStub : public PlatformCodeStub {
}
protected:
StoreICState state() const {
return StoreICState(static_cast<ExtraICState>(minor_key_));
}
StoreICState state() const { return StoreICState(GetExtraICState()); }
private:
DEFINE_CALL_INTERFACE_DESCRIPTOR(Store);
DEFINE_PLATFORM_CODE_STUB(StoreICTrampoline, PlatformCodeStub);
};
class StoreICTrampolineTFStub : public TurboFanCodeStub {
public:
StoreICTrampolineTFStub(Isolate* isolate, const StoreICState& state)
: TurboFanCodeStub(isolate) {
minor_key_ = state.GetExtraICState();
}
void GenerateAssembly(CodeStubAssembler* assembler) const override;
Code::Kind GetCodeKind() const override { return Code::STORE_IC; }
ExtraICState GetExtraICState() const final {
return static_cast<ExtraICState>(minor_key_);
}
protected:
StoreICState state() const { return StoreICState(GetExtraICState()); }
DEFINE_CALL_INTERFACE_DESCRIPTOR(Store);
DEFINE_CODE_STUB(StoreICTrampolineTF, TurboFanCodeStub);
};
class KeyedStoreICTrampolineStub : public StoreICTrampolineStub {
public:
KeyedStoreICTrampolineStub(Isolate* isolate, const StoreICState& state)
@ -2551,6 +2572,24 @@ class StoreICStub : public PlatformCodeStub {
void GenerateImpl(MacroAssembler* masm, bool in_frame);
};
class StoreICTFStub : public TurboFanCodeStub {
public:
StoreICTFStub(Isolate* isolate, const StoreICState& state)
: TurboFanCodeStub(isolate) {
minor_key_ = state.GetExtraICState();
}
void GenerateAssembly(CodeStubAssembler* assembler) const override;
Code::Kind GetCodeKind() const override { return Code::STORE_IC; }
ExtraICState GetExtraICState() const final {
return static_cast<ExtraICState>(minor_key_);
}
DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreWithVector);
DEFINE_CODE_STUB(StoreICTF, TurboFanCodeStub);
};
class KeyedStoreICStub : public PlatformCodeStub {
public:
KeyedStoreICStub(Isolate* isolate, const StoreICState& state)

View File

@ -765,6 +765,26 @@ Node* CodeAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor,
return raw_assembler_->TailCallN(call_descriptor, target, args);
}
Node* CodeAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor,
Node* target, Node* context, Node* arg1,
Node* arg2, Node* arg3, Node* arg4,
Node* arg5, size_t result_size) {
CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
CallDescriptor::kSupportsTailCalls, Operator::kNoProperties,
MachineType::AnyTagged(), result_size);
Node** args = zone()->NewArray<Node*>(6);
args[0] = arg1;
args[1] = arg2;
args[2] = arg3;
args[3] = arg4;
args[4] = arg5;
args[5] = context;
return raw_assembler_->TailCallN(call_descriptor, target, args);
}
Node* CodeAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor,
Node* target, Node* context, const Arg& arg1,
const Arg& arg2, const Arg& arg3,

View File

@ -407,6 +407,9 @@ class CodeAssembler {
Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
Node* context, Node* arg1, Node* arg2, Node* arg3,
Node* arg4, size_t result_size = 1);
Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
Node* context, Node* arg1, Node* arg2, Node* arg3,
Node* arg4, Node* arg5, size_t result_size = 1);
Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
Node* context, const Arg& arg1, const Arg& arg2,

View File

@ -802,6 +802,7 @@ DEFINE_BOOL(use_idle_notification, true,
DEFINE_BOOL(use_ic, true, "use inline caching")
DEFINE_BOOL(trace_ic, false, "trace inline cache state transitions")
DEFINE_BOOL(tf_load_ic_stub, true, "use TF LoadIC stub")
DEFINE_BOOL(tf_store_ic_stub, false, "use TF StoreIC stub")
// macro-assembler-ia32.cc
DEFINE_BOOL(native_code_counters, false,

View File

@ -21782,12 +21782,15 @@ int* LookupCounter(const char* name) {
const char* kMegamorphicTestProgram =
"function CreateClass(name) {\n"
" var src = \n"
" ` function ${name}() {};` +\n"
" ` function ${name}() { this.a = 0; };` +\n"
" ` ${name}.prototype.foo = function() {};` +\n"
" ` ${name};\\n`;\n"
" return (0, eval)(src);\n"
"}\n"
"function fooify(obj) { obj.foo(); };\n"
"function trigger_ics(obj, v) {\n"
" obj.foo();\n"
" obj.a = v;\n"
"};\n"
"var objs = [];\n"
"for (var i = 0; i < 50; i++) {\n"
" var Class = CreateClass('Class' + i);\n"
@ -21796,7 +21799,7 @@ const char* kMegamorphicTestProgram =
"}\n"
"for (var i = 0; i < 1000; i++) {\n"
" for (var obj of objs) {\n"
" fooify(obj);\n"
" trigger_ics(obj, i);\n"
" }\n"
"}\n";
@ -21832,6 +21835,7 @@ void TestStubCache(bool primary) {
i::CodeStub::LoadICTF, i::CodeStub::LoadICTrampolineTF,
i::CodeStub::KeyedLoadIC, i::CodeStub::KeyedLoadICTrampoline,
i::CodeStub::StoreIC, i::CodeStub::StoreICTrampoline,
i::CodeStub::StoreICTF, i::CodeStub::StoreICTrampolineTF,
i::CodeStub::KeyedStoreIC, i::CodeStub::KeyedStoreICTrampoline,
};
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
@ -21852,17 +21856,18 @@ void TestStubCache(bool primary) {
int updates = updates_counter - initial_updates;
const int kClassesCount = 50;
const int kIterationsCount = 1000;
CHECK_LE(kClassesCount, updates);
const int kICKinds = 2; // LoadIC and StoreIC
CHECK_LE(kClassesCount * kICKinds, updates);
// Check that updates and misses counts are bounded.
// If there are too many updates then most likely the stub cache does not
// work properly.
CHECK_LE(updates, kClassesCount * 2);
CHECK_LE(1, misses);
CHECK_LE(misses, kClassesCount * 2);
CHECK_LE(updates, kClassesCount * 2 * kICKinds);
CHECK_LE(kICKinds, misses);
CHECK_LE(misses, kClassesCount * 2 * kICKinds);
// 2 is for PREMONOMORPHIC and MONOMORPHIC states,
// 4 is for POLYMORPHIC states,
// and all the others probes are for MEGAMORPHIC state.
CHECK_EQ(kIterationsCount * kClassesCount - 2 - 4, probes);
CHECK_EQ((kIterationsCount * kClassesCount - 2 - 4) * kICKinds, probes);
}
isolate->Dispose();
}