From 6d3fc8a322338a55f970cb9cdf0023c671d51bfb Mon Sep 17 00:00:00 2001 From: "mvstanton@chromium.org" Date: Mon, 21 Jul 2014 11:19:56 +0000 Subject: [PATCH] Introduce FLAG_vector_ics. When FLAG_vector_ics is true, then AST nodes that use Load and KeyedLoad ICs will allocate a type vector slot to store feedback information. Full codegen will emit a load of the slot into a register if the flag is on. Support is incomplete, right now the IC doesn't know how to use the feedback slot. R=verwaest@chromium.org Review URL: https://codereview.chromium.org/398053002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22500 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/full-codegen-arm.cc | 66 +++++++++++++++++++++++------ src/arm/ic-arm.cc | 12 ++++++ src/arm/lithium-arm.cc | 20 +++++++-- src/arm/lithium-arm.h | 21 +++++++--- src/arm/lithium-codegen-arm.cc | 28 +++++++++++++ src/arm64/full-codegen-arm64.cc | 65 ++++++++++++++++++++++++----- src/arm64/ic-arm64.cc | 11 +++++ src/arm64/lithium-arm64.cc | 28 +++++++++++-- src/arm64/lithium-arm64.h | 23 +++++++--- src/arm64/lithium-codegen-arm64.cc | 27 ++++++++++++ src/ast.cc | 27 ++++++++---- src/ast.h | 67 +++++++++++++++++++++++++++--- src/bootstrapper.cc | 6 +++ src/flag-definitions.h | 1 + src/full-codegen.h | 4 +- src/hydrogen-instructions.h | 51 +++++++++++++++++++++-- src/hydrogen.cc | 60 +++++++++++++++++++------- src/hydrogen.h | 6 ++- src/ia32/builtins-ia32.cc | 3 ++ src/ia32/full-codegen-ia32.cc | 64 +++++++++++++++++++++++----- src/ia32/ic-ia32.cc | 12 ++++++ src/ia32/lithium-codegen-ia32.cc | 28 +++++++++++++ src/ia32/lithium-ia32.cc | 21 ++++++++-- src/ia32/lithium-ia32.h | 21 +++++++--- src/ic.h | 5 +++ src/x64/builtins-x64.cc | 3 ++ src/x64/full-codegen-x64.cc | 61 ++++++++++++++++++++++----- src/x64/ic-x64.cc | 12 ++++++ src/x64/lithium-codegen-x64.cc | 25 +++++++++++ src/x64/lithium-x64.cc | 20 +++++++-- src/x64/lithium-x64.h | 24 ++++++++--- test/cctest/test-compiler.cc | 15 +++---- test/cctest/test-heap.cc | 20 +++++---- 33 files changed, 730 insertions(+), 127 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 659687bcb..d8bd27fbd 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -1355,7 +1355,7 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { } -void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, +void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, TypeofState typeof_state, Label* slow) { Register current = cp; @@ -1404,7 +1404,12 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, } __ ldr(LoadIC::ReceiverRegister(), GlobalObjectOperand()); - __ mov(LoadIC::NameRegister(), Operand(var->name())); + __ mov(LoadIC::NameRegister(), Operand(proxy->var()->name())); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(proxy->VariableFeedbackSlot()))); + } + ContextualMode mode = (typeof_state == INSIDE_TYPEOF) ? NOT_CONTEXTUAL : CONTEXTUAL; @@ -1444,7 +1449,7 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, } -void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, +void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, TypeofState typeof_state, Label* slow, Label* done) { @@ -1453,8 +1458,9 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, // introducing variables. In those cases, we do not want to // perform a runtime call for all variables in the scope // containing the eval. + Variable* var = proxy->var(); if (var->mode() == DYNAMIC_GLOBAL) { - EmitLoadGlobalCheckExtensions(var, typeof_state, slow); + EmitLoadGlobalCheckExtensions(proxy, typeof_state, slow); __ jmp(done); } else if (var->mode() == DYNAMIC_LOCAL) { Variable* local = var->local_if_not_shadowed(); @@ -1488,6 +1494,10 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Comment cmnt(masm_, "[ Global variable"); __ ldr(LoadIC::ReceiverRegister(), GlobalObjectOperand()); __ mov(LoadIC::NameRegister(), Operand(var->name())); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(proxy->VariableFeedbackSlot()))); + } CallLoadIC(CONTEXTUAL); context()->Plug(r0); break; @@ -1564,7 +1574,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Label done, slow; // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done); __ bind(&slow); __ mov(r1, Operand(var->name())); __ Push(cp, r1); // Context and name. @@ -2078,6 +2088,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ bind(&l_call); __ ldr(load_receiver, MemOperand(sp, kPointerSize)); __ ldr(load_name, MemOperand(sp, 2 * kPointerSize)); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(expr->KeyedLoadFeedbackSlot()))); + } Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); CallIC(ic, TypeFeedbackId::None()); __ mov(r1, r0); @@ -2094,6 +2108,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ push(load_receiver); // save result __ LoadRoot(load_name, Heap::kdone_stringRootIndex); // "done" + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(expr->DoneFeedbackSlot()))); + } CallLoadIC(NOT_CONTEXTUAL); // r0=result.done Handle bool_ic = ToBooleanStub::GetUninitialized(isolate()); CallIC(bool_ic); @@ -2103,6 +2121,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { // result.value __ pop(load_receiver); // result __ LoadRoot(load_name, Heap::kvalue_stringRootIndex); // "value" + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(expr->ValueFeedbackSlot()))); + } CallLoadIC(NOT_CONTEXTUAL); // r0=result.value context()->DropAndPlug(2, r0); // drop iter and g break; @@ -2278,16 +2300,26 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Literal* key = prop->key()->AsLiteral(); __ mov(LoadIC::NameRegister(), Operand(key->value())); - // Call load IC. It has register arguments receiver and property. - CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(prop->PropertyFeedbackSlot()))); + CallLoadIC(NOT_CONTEXTUAL); + } else { + CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); + } } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); - // Call keyed load IC. It has register arguments receiver and key. Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); - CallIC(ic, prop->PropertyFeedbackId()); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(prop->PropertyFeedbackSlot()))); + CallIC(ic); + } else { + CallIC(ic, prop->PropertyFeedbackId()); + } } @@ -2761,7 +2793,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { { PreservePositionScope scope(masm()->positions_recorder()); // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done); } __ bind(&slow); @@ -4056,7 +4088,13 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { // Load the function from the receiver. __ mov(LoadIC::NameRegister(), Operand(expr->name())); - CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(expr->CallRuntimeFeedbackSlot()))); + CallLoadIC(NOT_CONTEXTUAL); + } else { + CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); + } // Push the target function under the receiver. __ ldr(ip, MemOperand(sp, 0)); @@ -4390,6 +4428,10 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { Comment cmnt(masm_, "[ Global variable"); __ ldr(LoadIC::ReceiverRegister(), GlobalObjectOperand()); __ mov(LoadIC::NameRegister(), Operand(proxy->name())); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(proxy->VariableFeedbackSlot()))); + } // Use a regular load, not a contextual load, to avoid a reference // error. CallLoadIC(NOT_CONTEXTUAL); @@ -4401,7 +4443,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, INSIDE_TYPEOF, &slow, &done); __ bind(&slow); __ mov(r0, Operand(proxy->name())); diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc index 17c815ee4..29150e428 100644 --- a/src/arm/ic-arm.cc +++ b/src/arm/ic-arm.cc @@ -497,6 +497,18 @@ const Register LoadIC::ReceiverRegister() { return r1; } const Register LoadIC::NameRegister() { return r2; } +const Register LoadIC::SlotRegister() { + ASSERT(FLAG_vector_ics); + return r0; +} + + +const Register LoadIC::VectorRegister() { + ASSERT(FLAG_vector_ics); + return r3; +} + + const Register StoreIC::ReceiverRegister() { return r1; } const Register StoreIC::NameRegister() { return r2; } const Register StoreIC::ValueRegister() { return r0; } diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 6071846c3..6ed8add0b 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -2087,8 +2087,12 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) { LOperand* context = UseFixed(instr->context(), cp); LOperand* global_object = UseFixed(instr->global_object(), LoadIC::ReceiverRegister()); + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } LLoadGlobalGeneric* result = - new(zone()) LLoadGlobalGeneric(context, global_object); + new(zone()) LLoadGlobalGeneric(context, global_object, vector); return MarkAsCall(DefineFixed(result, r0), instr); } @@ -2141,8 +2145,13 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { LOperand* context = UseFixed(instr->context(), cp); LOperand* object = UseFixed(instr->object(), LoadIC::ReceiverRegister()); + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } + LInstruction* result = - DefineFixed(new(zone()) LLoadNamedGeneric(context, object), r0); + DefineFixed(new(zone()) LLoadNamedGeneric(context, object, vector), r0); return MarkAsCall(result, instr); } @@ -2202,9 +2211,14 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { LOperand* context = UseFixed(instr->context(), cp); LOperand* object = UseFixed(instr->object(), LoadIC::ReceiverRegister()); LOperand* key = UseFixed(instr->key(), LoadIC::NameRegister()); + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } LInstruction* result = - DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key), r0); + DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key, vector), + r0); return MarkAsCall(result, instr); } diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 095640d86..7fa1eab2d 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -1585,15 +1585,17 @@ class LLoadNamedField V8_FINAL : public LTemplateInstruction<1, 1, 0> { }; -class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> { +class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: - LLoadNamedGeneric(LOperand* context, LOperand* object) { + LLoadNamedGeneric(LOperand* context, LOperand* object, LOperand* vector) { inputs_[0] = context; inputs_[1] = object; + temps_[0] = vector; } LOperand* context() { return inputs_[0]; } LOperand* object() { return inputs_[1]; } + LOperand* temp_vector() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic") DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric) @@ -1654,19 +1656,23 @@ class LLoadKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> { }; -class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 0> { +class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 1> { public: - LLoadKeyedGeneric(LOperand* context, LOperand* object, LOperand* key) { + LLoadKeyedGeneric(LOperand* context, LOperand* object, LOperand* key, + LOperand* vector) { inputs_[0] = context; inputs_[1] = object; inputs_[2] = key; + temps_[0] = vector; } LOperand* context() { return inputs_[0]; } LOperand* object() { return inputs_[1]; } LOperand* key() { return inputs_[2]; } + LOperand* temp_vector() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") + DECLARE_HYDROGEN_ACCESSOR(LoadKeyedGeneric) }; @@ -1677,15 +1683,18 @@ class LLoadGlobalCell V8_FINAL : public LTemplateInstruction<1, 0, 0> { }; -class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> { +class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: - LLoadGlobalGeneric(LOperand* context, LOperand* global_object) { + LLoadGlobalGeneric(LOperand* context, LOperand* global_object, + LOperand* vector) { inputs_[0] = context; inputs_[1] = global_object; + temps_[0] = vector; } LOperand* context() { return inputs_[0]; } LOperand* global_object() { return inputs_[1]; } + LOperand* temp_vector() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic") DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric) diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 879c57650..beb3c8f81 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -2995,6 +2995,15 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { ASSERT(ToRegister(instr->result()).is(r0)); __ mov(LoadIC::NameRegister(), Operand(instr->name())); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ Move(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(r0)); + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(instr->hydrogen()->slot()))); + } ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; Handle ic = LoadIC::initialize_stub(isolate(), mode); CallCode(ic, RelocInfo::CODE_TARGET, instr); @@ -3115,6 +3124,15 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { // Name is always in r2. __ mov(LoadIC::NameRegister(), Operand(instr->name())); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ Move(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(r0)); + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(instr->hydrogen()->slot()))); + } Handle ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL); CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } @@ -3419,6 +3437,16 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(LoadIC::ReceiverRegister())); ASSERT(ToRegister(instr->key()).is(LoadIC::NameRegister())); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ Move(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(r0)); + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(instr->hydrogen()->slot()))); + } + Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 81dfbfbb4..49ccd9580 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -1351,7 +1351,7 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { } -void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, +void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, TypeofState typeof_state, Label* slow) { Register current = cp; @@ -1395,7 +1395,12 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, } __ Ldr(LoadIC::ReceiverRegister(), GlobalObjectMemOperand()); - __ Mov(LoadIC::NameRegister(), Operand(var->name())); + __ Mov(LoadIC::NameRegister(), Operand(proxy->var()->name())); + if (FLAG_vector_ics) { + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(proxy->VariableFeedbackSlot())); + } + ContextualMode mode = (typeof_state == INSIDE_TYPEOF) ? NOT_CONTEXTUAL : CONTEXTUAL; CallLoadIC(mode); @@ -1432,7 +1437,7 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, } -void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, +void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, TypeofState typeof_state, Label* slow, Label* done) { @@ -1441,8 +1446,9 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, // introducing variables. In those cases, we do not want to // perform a runtime call for all variables in the scope // containing the eval. + Variable* var = proxy->var(); if (var->mode() == DYNAMIC_GLOBAL) { - EmitLoadGlobalCheckExtensions(var, typeof_state, slow); + EmitLoadGlobalCheckExtensions(proxy, typeof_state, slow); __ B(done); } else if (var->mode() == DYNAMIC_LOCAL) { Variable* local = var->local_if_not_shadowed(); @@ -1475,6 +1481,10 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Comment cmnt(masm_, "Global variable"); __ Ldr(LoadIC::ReceiverRegister(), GlobalObjectMemOperand()); __ Mov(LoadIC::NameRegister(), Operand(var->name())); + if (FLAG_vector_ics) { + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(proxy->VariableFeedbackSlot())); + } CallLoadIC(CONTEXTUAL); context()->Plug(x0); break; @@ -1551,7 +1561,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Label done, slow; // Generate code for loading from variables potentially shadowed by // eval-introduced variables. - EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done); __ Bind(&slow); Comment cmnt(masm_, "Lookup variable"); __ Mov(x1, Operand(var->name())); @@ -1950,8 +1960,13 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Literal* key = prop->key()->AsLiteral(); __ Mov(LoadIC::NameRegister(), Operand(key->value())); - // Call load IC. It has arguments receiver and property name x0 and x2. - CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); + if (FLAG_vector_ics) { + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(prop->PropertyFeedbackSlot())); + CallLoadIC(NOT_CONTEXTUAL); + } else { + CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); + } } @@ -1959,7 +1974,13 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); // Call keyed load IC. It has arguments key and receiver in r0 and r1. Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); - CallIC(ic, prop->PropertyFeedbackId()); + if (FLAG_vector_ics) { + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(prop->PropertyFeedbackSlot())); + CallIC(ic); + } else { + CallIC(ic, prop->PropertyFeedbackId()); + } } @@ -2452,7 +2473,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { { PreservePositionScope scope(masm()->positions_recorder()); // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done); } __ Bind(&slow); @@ -3745,7 +3766,13 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { // Load the function from the receiver. Handle name = expr->name(); __ Mov(LoadIC::NameRegister(), Operand(name)); - CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); + if (FLAG_vector_ics) { + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(expr->CallRuntimeFeedbackSlot())); + CallLoadIC(NOT_CONTEXTUAL); + } else { + CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); + } // Push the target function under the receiver. __ Pop(x10); @@ -4080,6 +4107,10 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { Comment cmnt(masm_, "Global variable"); __ Ldr(LoadIC::ReceiverRegister(), GlobalObjectMemOperand()); __ Mov(LoadIC::NameRegister(), Operand(proxy->name())); + if (FLAG_vector_ics) { + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(proxy->VariableFeedbackSlot())); + } // Use a regular load, not a contextual load, to avoid a reference // error. CallLoadIC(NOT_CONTEXTUAL); @@ -4090,7 +4121,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, INSIDE_TYPEOF, &slow, &done); __ Bind(&slow); __ Mov(x0, Operand(proxy->name())); @@ -4432,6 +4463,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ Bind(&l_call); __ Peek(load_receiver, 1 * kPointerSize); __ Peek(load_name, 2 * kPointerSize); + if (FLAG_vector_ics) { + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(expr->KeyedLoadFeedbackSlot())); + } Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); CallIC(ic, TypeFeedbackId::None()); __ Mov(x1, x0); @@ -4448,6 +4483,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ Push(load_receiver); // save result __ LoadRoot(load_name, Heap::kdone_stringRootIndex); // "done" + if (FLAG_vector_ics) { + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(expr->DoneFeedbackSlot())); + } CallLoadIC(NOT_CONTEXTUAL); // x0=result.done // The ToBooleanStub argument (result.done) is in x0. Handle bool_ic = ToBooleanStub::GetUninitialized(isolate()); @@ -4457,6 +4496,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { // result.value __ Pop(load_receiver); // result __ LoadRoot(load_name, Heap::kvalue_stringRootIndex); // "value" + if (FLAG_vector_ics) { + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(expr->ValueFeedbackSlot())); + } CallLoadIC(NOT_CONTEXTUAL); // x0=result.value context()->DropAndPlug(2, x0); // drop iter and g break; diff --git a/src/arm64/ic-arm64.cc b/src/arm64/ic-arm64.cc index 5be6438f7..c30662f3e 100644 --- a/src/arm64/ic-arm64.cc +++ b/src/arm64/ic-arm64.cc @@ -515,6 +515,17 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { const Register LoadIC::ReceiverRegister() { return x1; } const Register LoadIC::NameRegister() { return x2; } +const Register LoadIC::SlotRegister() { + ASSERT(FLAG_vector_ics); + return x0; +} + + +const Register LoadIC::VectorRegister() { + ASSERT(FLAG_vector_ics); + return x3; +} + const Register StoreIC::ReceiverRegister() { return x1; } const Register StoreIC::NameRegister() { return x2; } diff --git a/src/arm64/lithium-arm64.cc b/src/arm64/lithium-arm64.cc index 9ac108c32..f7ac46faa 100644 --- a/src/arm64/lithium-arm64.cc +++ b/src/arm64/lithium-arm64.cc @@ -551,6 +551,13 @@ LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) { } +LOperand* LChunkBuilder::FixedTemp(Register reg) { + LUnallocated* operand = ToUnallocated(reg); + ASSERT(operand->HasFixedPolicy()); + return operand; +} + + LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) { LUnallocated* operand = ToUnallocated(reg); ASSERT(operand->HasFixedPolicy()); @@ -1660,8 +1667,13 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) { LOperand* context = UseFixed(instr->context(), cp); LOperand* global_object = UseFixed(instr->global_object(), LoadIC::ReceiverRegister()); + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } + LLoadGlobalGeneric* result = - new(zone()) LLoadGlobalGeneric(context, global_object); + new(zone()) LLoadGlobalGeneric(context, global_object, vector); return MarkAsCall(DefineFixed(result, x0), instr); } @@ -1717,9 +1729,14 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { LOperand* context = UseFixed(instr->context(), cp); LOperand* object = UseFixed(instr->object(), LoadIC::ReceiverRegister()); LOperand* key = UseFixed(instr->key(), LoadIC::NameRegister()); + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } LInstruction* result = - DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key), x0); + DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key, vector), + x0); return MarkAsCall(result, instr); } @@ -1733,8 +1750,13 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { LOperand* context = UseFixed(instr->context(), cp); LOperand* object = UseFixed(instr->object(), LoadIC::ReceiverRegister()); + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } + LInstruction* result = - DefineFixed(new(zone()) LLoadNamedGeneric(context, object), x0); + DefineFixed(new(zone()) LLoadNamedGeneric(context, object, vector), x0); return MarkAsCall(result, instr); } diff --git a/src/arm64/lithium-arm64.h b/src/arm64/lithium-arm64.h index 771b625ec..04af5583c 100644 --- a/src/arm64/lithium-arm64.h +++ b/src/arm64/lithium-arm64.h @@ -1720,15 +1720,18 @@ class LLoadGlobalCell V8_FINAL : public LTemplateInstruction<1, 0, 0> { }; -class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> { +class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: - LLoadGlobalGeneric(LOperand* context, LOperand* global_object) { + LLoadGlobalGeneric(LOperand* context, LOperand* global_object, + LOperand* vector) { inputs_[0] = context; inputs_[1] = global_object; + temps_[0] = vector; } LOperand* context() { return inputs_[0]; } LOperand* global_object() { return inputs_[1]; } + LOperand* temp_vector() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic") DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric) @@ -1817,31 +1820,37 @@ class LLoadKeyedFixedDouble: public LLoadKeyed<1> { }; -class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 0> { +class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 1> { public: - LLoadKeyedGeneric(LOperand* context, LOperand* object, LOperand* key) { + LLoadKeyedGeneric(LOperand* context, LOperand* object, LOperand* key, + LOperand* vector) { inputs_[0] = context; inputs_[1] = object; inputs_[2] = key; + temps_[0] = vector; } LOperand* context() { return inputs_[0]; } LOperand* object() { return inputs_[1]; } LOperand* key() { return inputs_[2]; } + LOperand* temp_vector() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") + DECLARE_HYDROGEN_ACCESSOR(LoadKeyedGeneric) }; -class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> { +class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: - LLoadNamedGeneric(LOperand* context, LOperand* object) { + LLoadNamedGeneric(LOperand* context, LOperand* object, LOperand* vector) { inputs_[0] = context; inputs_[1] = object; + temps_[0] = vector; } LOperand* context() { return inputs_[0]; } LOperand* object() { return inputs_[1]; } + LOperand* temp_vector() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic") DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric) @@ -3156,6 +3165,8 @@ class LChunkBuilder V8_FINAL : public LChunkBuilderBase { // Temporary operand that must be in a double register. MUST_USE_RESULT LUnallocated* TempDoubleRegister(); + MUST_USE_RESULT LOperand* FixedTemp(Register reg); + // Temporary operand that must be in a fixed double register. MUST_USE_RESULT LOperand* FixedTemp(DoubleRegister reg); diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index 6ea4ae866..3f6be920a 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -3385,6 +3385,15 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { ASSERT(ToRegister(instr->global_object()).is(LoadIC::ReceiverRegister())); ASSERT(ToRegister(instr->result()).Is(x0)); __ Mov(LoadIC::NameRegister(), Operand(instr->name())); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ Mov(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(x0)); + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(instr->hydrogen()->slot())); + } ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; Handle ic = LoadIC::initialize_stub(isolate(), mode); CallCode(ic, RelocInfo::CODE_TARGET, instr); @@ -3637,6 +3646,15 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->context()).is(cp)); ASSERT(ToRegister(instr->object()).is(LoadIC::ReceiverRegister())); ASSERT(ToRegister(instr->key()).is(LoadIC::NameRegister())); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ Mov(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(x0)); + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(instr->hydrogen()->slot())); + } Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); CallCode(ic, RelocInfo::CODE_TARGET, instr); @@ -3690,6 +3708,15 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { // LoadIC expects name and receiver in registers. ASSERT(ToRegister(instr->object()).is(LoadIC::ReceiverRegister())); __ Mov(LoadIC::NameRegister(), Operand(instr->name())); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ Mov(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(x0)); + __ Mov(LoadIC::SlotRegister(), + Smi::FromInt(instr->hydrogen()->slot())); + } Handle ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL); CallCode(ic, RelocInfo::CODE_TARGET, instr); diff --git a/src/ast.cc b/src/ast.cc index df293dda0..822b9a5fa 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -65,7 +65,8 @@ VariableProxy::VariableProxy(Zone* zone, Variable* var, int position) var_(NULL), // Will be set by the call to BindTo. is_this_(var->is_this()), is_assigned_(false), - interface_(var->interface()) { + interface_(var->interface()), + variable_feedback_slot_(kInvalidFeedbackSlot) { BindTo(var); } @@ -80,7 +81,8 @@ VariableProxy::VariableProxy(Zone* zone, var_(NULL), is_this_(is_this), is_assigned_(false), - interface_(interface) { + interface_(interface), + variable_feedback_slot_(kInvalidFeedbackSlot) { } @@ -1021,7 +1023,14 @@ CaseClause::CaseClause(Zone* zone, set_dont_optimize_reason(k##NodeType); \ add_flag(kDontSelfOptimize); \ } -#define DONT_SELFOPTIMIZE_NODE(NodeType) \ +#define DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType) \ + void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ + increase_node_count(); \ + add_slot_node(node); \ + set_dont_optimize_reason(k##NodeType); \ + add_flag(kDontSelfOptimize); \ + } +#define DONT_SELFOPTIMIZE_NODE(NodeType) \ void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ increase_node_count(); \ add_flag(kDontSelfOptimize); \ @@ -1059,20 +1068,21 @@ REGULAR_NODE(RegExpLiteral) REGULAR_NODE(FunctionLiteral) REGULAR_NODE(Assignment) REGULAR_NODE(Throw) -REGULAR_NODE(Property) REGULAR_NODE(UnaryOperation) REGULAR_NODE(CountOperation) REGULAR_NODE(BinaryOperation) REGULAR_NODE(CompareOperation) REGULAR_NODE(ThisFunction) + REGULAR_NODE_WITH_FEEDBACK_SLOTS(Call) REGULAR_NODE_WITH_FEEDBACK_SLOTS(CallNew) +REGULAR_NODE_WITH_FEEDBACK_SLOTS(Property) // In theory, for VariableProxy we'd have to add: // if (node->var()->IsLookupSlot()) // set_dont_optimize_reason(kReferenceToAVariableWhichRequiresDynamicLookup); // But node->var() is usually not bound yet at VariableProxy creation time, and // LOOKUP variables only result from constructs that cannot be inlined anyway. -REGULAR_NODE(VariableProxy) +REGULAR_NODE_WITH_FEEDBACK_SLOTS(VariableProxy) // We currently do not optimize any modules. DONT_OPTIMIZE_NODE(ModuleDeclaration) @@ -1082,24 +1092,27 @@ DONT_OPTIMIZE_NODE(ModuleVariable) DONT_OPTIMIZE_NODE(ModulePath) DONT_OPTIMIZE_NODE(ModuleUrl) DONT_OPTIMIZE_NODE(ModuleStatement) -DONT_OPTIMIZE_NODE(Yield) DONT_OPTIMIZE_NODE(WithStatement) DONT_OPTIMIZE_NODE(TryCatchStatement) DONT_OPTIMIZE_NODE(TryFinallyStatement) DONT_OPTIMIZE_NODE(DebuggerStatement) DONT_OPTIMIZE_NODE(NativeFunctionLiteral) +DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(Yield) + DONT_SELFOPTIMIZE_NODE(DoWhileStatement) DONT_SELFOPTIMIZE_NODE(WhileStatement) DONT_SELFOPTIMIZE_NODE(ForStatement) -DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(ForInStatement) DONT_SELFOPTIMIZE_NODE(ForOfStatement) +DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(ForInStatement) + DONT_CACHE_NODE(ModuleLiteral) void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) { increase_node_count(); + add_slot_node(node); if (node->is_jsruntime()) { // Don't try to optimize JS runtime calls because we bailout on them. set_dont_optimize_reason(kCallToAJavaScriptRuntimeFunction); diff --git a/src/ast.h b/src/ast.h index b4aab4ec9..5a4a5ac66 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1625,7 +1625,7 @@ class ArrayLiteral V8_FINAL : public MaterializedLiteral { }; -class VariableProxy V8_FINAL : public Expression { +class VariableProxy V8_FINAL : public Expression, public FeedbackSlotInterface { public: DECLARE_NODE_TYPE(VariableProxy) @@ -1647,6 +1647,13 @@ class VariableProxy V8_FINAL : public Expression { // Bind this proxy to the variable var. Interfaces must match. void BindTo(Variable* var); + virtual int ComputeFeedbackSlotCount() { return FLAG_vector_ics ? 1 : 0; } + virtual void SetFirstFeedbackSlot(int slot) { + variable_feedback_slot_ = slot; + } + + int VariableFeedbackSlot() { return variable_feedback_slot_; } + protected: VariableProxy(Zone* zone, Variable* var, int position); @@ -1661,10 +1668,11 @@ class VariableProxy V8_FINAL : public Expression { bool is_this_; bool is_assigned_; Interface* interface_; + int variable_feedback_slot_; }; -class Property V8_FINAL : public Expression { +class Property V8_FINAL : public Expression, public FeedbackSlotInterface { public: DECLARE_NODE_TYPE(Property) @@ -1700,6 +1708,13 @@ class Property V8_FINAL : public Expression { TypeFeedbackId PropertyFeedbackId() { return reuse(id()); } + virtual int ComputeFeedbackSlotCount() { return FLAG_vector_ics ? 1 : 0; } + virtual void SetFirstFeedbackSlot(int slot) { + property_feedback_slot_ = slot; + } + + int PropertyFeedbackSlot() const { return property_feedback_slot_; } + protected: Property(Zone* zone, Expression* obj, @@ -1709,6 +1724,7 @@ class Property V8_FINAL : public Expression { obj_(obj), key_(key), load_id_(GetNextId(zone)), + property_feedback_slot_(kInvalidFeedbackSlot), is_for_call_(false), is_uninitialized_(false), is_string_access_(false), @@ -1718,6 +1734,7 @@ class Property V8_FINAL : public Expression { Expression* obj_; Expression* key_; const BailoutId load_id_; + int property_feedback_slot_; SmallMapList receiver_types_; bool is_for_call_ : 1; @@ -1895,7 +1912,7 @@ class CallNew V8_FINAL : public Expression, public FeedbackSlotInterface { // language construct. Instead it is used to call a C or JS function // with a set of arguments. This is used from the builtins that are // implemented in JavaScript (see "v8natives.js"). -class CallRuntime V8_FINAL : public Expression { +class CallRuntime V8_FINAL : public Expression, public FeedbackSlotInterface { public: DECLARE_NODE_TYPE(CallRuntime) @@ -1905,6 +1922,20 @@ class CallRuntime V8_FINAL : public Expression { ZoneList* arguments() const { return arguments_; } bool is_jsruntime() const { return function_ == NULL; } + // Type feedback information. + virtual int ComputeFeedbackSlotCount() { + return (FLAG_vector_ics && is_jsruntime()) ? 1 : 0; + } + virtual void SetFirstFeedbackSlot(int slot) { + callruntime_feedback_slot_ = slot; + } + + int CallRuntimeFeedbackSlot() { + ASSERT(!is_jsruntime() || + callruntime_feedback_slot_ != kInvalidFeedbackSlot); + return callruntime_feedback_slot_; + } + TypeFeedbackId CallRuntimeFeedbackId() const { return reuse(id()); } protected: @@ -1922,6 +1953,7 @@ class CallRuntime V8_FINAL : public Expression { const AstRawString* raw_name_; const Runtime::Function* function_; ZoneList* arguments_; + int callruntime_feedback_slot_; }; @@ -2215,7 +2247,7 @@ class Assignment V8_FINAL : public Expression { }; -class Yield V8_FINAL : public Expression { +class Yield V8_FINAL : public Expression, public FeedbackSlotInterface { public: DECLARE_NODE_TYPE(Yield) @@ -2242,6 +2274,29 @@ class Yield V8_FINAL : public Expression { index_ = index; } + // Type feedback information. + virtual int ComputeFeedbackSlotCount() { + return (FLAG_vector_ics && yield_kind() == DELEGATING) ? 3 : 0; + } + virtual void SetFirstFeedbackSlot(int slot) { + yield_first_feedback_slot_ = slot; + } + + int KeyedLoadFeedbackSlot() { + ASSERT(yield_first_feedback_slot_ != kInvalidFeedbackSlot); + return yield_first_feedback_slot_; + } + + int DoneFeedbackSlot() { + ASSERT(yield_first_feedback_slot_ != kInvalidFeedbackSlot); + return yield_first_feedback_slot_ + 1; + } + + int ValueFeedbackSlot() { + ASSERT(yield_first_feedback_slot_ != kInvalidFeedbackSlot); + return yield_first_feedback_slot_ + 2; + } + protected: Yield(Zone* zone, Expression* generator_object, @@ -2252,13 +2307,15 @@ class Yield V8_FINAL : public Expression { generator_object_(generator_object), expression_(expression), yield_kind_(yield_kind), - index_(-1) { } + index_(-1), + yield_first_feedback_slot_(kInvalidFeedbackSlot) { } private: Expression* generator_object_; Expression* expression_; Kind yield_kind_; int index_; + int yield_first_feedback_slot_; }; diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index aaa0f3f7e..0344ee1d9 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1910,6 +1910,12 @@ bool Genesis::InstallNatives() { Handle apply = InstallFunction(proto, "apply", JS_OBJECT_TYPE, JSObject::kHeaderSize, MaybeHandle(), Builtins::kFunctionApply); + if (FLAG_vector_ics) { + // Apply embeds an IC, so we need a type vector of size 1 in the shared + // function info. + Handle feedback_vector = factory()->NewTypeFeedbackVector(1); + apply->shared()->set_feedback_vector(*feedback_vector); + } // Make sure that Function.prototype.call appears to be compiled. // The code will never be called, but inline caching for call will diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 94d2d1c02..50b6accb7 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -212,6 +212,7 @@ DEFINE_BOOL(track_field_types, true, "track field types") DEFINE_IMPLICATION(track_field_types, track_fields) DEFINE_IMPLICATION(track_field_types, track_heap_object_fields) DEFINE_BOOL(smi_binop, true, "support smi representation in binary operations") +DEFINE_BOOL(vector_ics, false, "support vector-based ics") // Flags for optimization types. DEFINE_BOOL(optimize_for_size, false, diff --git a/src/full-codegen.h b/src/full-codegen.h index ab1d47bb7..73431d54a 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -495,11 +495,11 @@ class FullCodeGenerator: public AstVisitor { JSGeneratorObject::ResumeMode resume_mode); // Platform-specific code for loading variables. - void EmitLoadGlobalCheckExtensions(Variable* var, + void EmitLoadGlobalCheckExtensions(VariableProxy* proxy, TypeofState typeof_state, Label* slow); MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow); - void EmitDynamicLookupFastCase(Variable* var, + void EmitDynamicLookupFastCase(VariableProxy* proxy, TypeofState typeof_state, Label* slow, Label* done); diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 77874b068..8f9a44b50 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -12,6 +12,7 @@ #include "src/conversions.h" #include "src/data-flow.h" #include "src/deoptimizer.h" +#include "src/feedback-slots.h" #include "src/hydrogen-types.h" #include "src/ostreams.h" #include "src/small-pointer-list.h" @@ -5433,6 +5434,17 @@ class HLoadGlobalGeneric V8_FINAL : public HTemplateInstruction<2> { HValue* global_object() { return OperandAt(1); } Handle name() const { return name_; } bool for_typeof() const { return for_typeof_; } + int slot() const { + ASSERT(FLAG_vector_ics && + slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot); + return slot_; + } + Handle feedback_vector() const { return feedback_vector_; } + void SetVectorAndSlot(Handle vector, int slot) { + ASSERT(FLAG_vector_ics); + feedback_vector_ = vector; + slot_ = slot; + } virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT @@ -5445,7 +5457,8 @@ class HLoadGlobalGeneric V8_FINAL : public HTemplateInstruction<2> { private: HLoadGlobalGeneric(HValue* context, HValue* global_object, Handle name, bool for_typeof) - : name_(name), for_typeof_(for_typeof) { + : name_(name), for_typeof_(for_typeof), + slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) { SetOperandAt(0, context); SetOperandAt(1, global_object); set_representation(Representation::Tagged()); @@ -5454,6 +5467,8 @@ class HLoadGlobalGeneric V8_FINAL : public HTemplateInstruction<2> { Handle name_; bool for_typeof_; + Handle feedback_vector_; + int slot_; }; @@ -6422,6 +6437,18 @@ class HLoadNamedGeneric V8_FINAL : public HTemplateInstruction<2> { HValue* object() const { return OperandAt(1); } Handle name() const { return name_; } + int slot() const { + ASSERT(FLAG_vector_ics && + slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot); + return slot_; + } + Handle feedback_vector() const { return feedback_vector_; } + void SetVectorAndSlot(Handle vector, int slot) { + ASSERT(FLAG_vector_ics); + feedback_vector_ = vector; + slot_ = slot; + } + virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { return Representation::Tagged(); } @@ -6432,7 +6459,8 @@ class HLoadNamedGeneric V8_FINAL : public HTemplateInstruction<2> { private: HLoadNamedGeneric(HValue* context, HValue* object, Handle name) - : name_(name) { + : name_(name), + slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) { SetOperandAt(0, context); SetOperandAt(1, object); set_representation(Representation::Tagged()); @@ -6440,6 +6468,8 @@ class HLoadNamedGeneric V8_FINAL : public HTemplateInstruction<2> { } Handle name_; + Handle feedback_vector_; + int slot_; }; @@ -6685,6 +6715,17 @@ class HLoadKeyedGeneric V8_FINAL : public HTemplateInstruction<3> { HValue* object() const { return OperandAt(0); } HValue* key() const { return OperandAt(1); } HValue* context() const { return OperandAt(2); } + int slot() const { + ASSERT(FLAG_vector_ics && + slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot); + return slot_; + } + Handle feedback_vector() const { return feedback_vector_; } + void SetVectorAndSlot(Handle vector, int slot) { + ASSERT(FLAG_vector_ics); + feedback_vector_ = vector; + slot_ = slot; + } virtual OStream& PrintDataTo(OStream& os) const V8_OVERRIDE; // NOLINT @@ -6698,13 +6739,17 @@ class HLoadKeyedGeneric V8_FINAL : public HTemplateInstruction<3> { DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric) private: - HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key) { + HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key) + : slot_(FeedbackSlotInterface::kInvalidFeedbackSlot) { set_representation(Representation::Tagged()); SetOperandAt(0, obj); SetOperandAt(1, key); SetOperandAt(2, context); SetAllSideEffects(); } + + Handle feedback_vector_; + int slot_; }; diff --git a/src/hydrogen.cc b/src/hydrogen.cc index c48de4c43..0290d7c61 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -5371,6 +5371,13 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { New(global_object, variable->name(), ast_context()->is_for_typeof()); + if (FLAG_vector_ics) { + Handle current_shared = + function_state()->compilation_info()->shared_info(); + instr->SetVectorAndSlot( + handle(current_shared->feedback_vector(), isolate()), + expr->VariableFeedbackSlot()); + } return ast_context()->ReturnInstruction(instr, expr->id()); } } @@ -5589,7 +5596,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { if (map.is_null()) { // If we don't know the monomorphic type, do a generic store. CHECK_ALIVE(store = BuildNamedGeneric( - STORE, literal, name, value)); + STORE, NULL, literal, name, value)); } else { PropertyAccessInfo info(this, STORE, ToType(map), name); if (info.CanAccessMonomorphic()) { @@ -5600,7 +5607,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { BailoutId::None(), BailoutId::None()); } else { CHECK_ALIVE(store = BuildNamedGeneric( - STORE, literal, name, value)); + STORE, NULL, literal, name, value)); } } AddInstruction(store); @@ -6213,6 +6220,7 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess( void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( PropertyAccessType access_type, + Expression* expr, BailoutId ast_id, BailoutId return_id, HValue* object, @@ -6326,7 +6334,8 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( if (count == types->length() && FLAG_deoptimize_uncommon_cases) { FinishExitWithHardDeoptimization("Uknown map in polymorphic access"); } else { - HInstruction* instr = BuildNamedGeneric(access_type, object, name, value); + HInstruction* instr = BuildNamedGeneric(access_type, expr, object, name, + value); AddInstruction(instr); if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value); @@ -6773,6 +6782,7 @@ HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) { HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( PropertyAccessType access_type, + Expression* expr, HValue* object, Handle name, HValue* value, @@ -6782,7 +6792,15 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( Deoptimizer::SOFT); } if (access_type == LOAD) { - return New(object, name); + HLoadNamedGeneric* result = New(object, name); + if (FLAG_vector_ics) { + Handle current_shared = + function_state()->compilation_info()->shared_info(); + result->SetVectorAndSlot( + handle(current_shared->feedback_vector(), isolate()), + expr->AsProperty()->PropertyFeedbackSlot()); + } + return result; } else { return New(object, name, value, function_strict_mode()); } @@ -6792,11 +6810,20 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric( PropertyAccessType access_type, + Expression* expr, HValue* object, HValue* key, HValue* value) { if (access_type == LOAD) { - return New(object, key); + HLoadKeyedGeneric* result = New(object, key); + if (FLAG_vector_ics) { + Handle current_shared = + function_state()->compilation_info()->shared_info(); + result->SetVectorAndSlot( + handle(current_shared->feedback_vector(), isolate()), + expr->AsProperty()->PropertyFeedbackSlot()); + } + return result; } else { return New(object, key, value, function_strict_mode()); } @@ -6924,6 +6951,7 @@ HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( + Expression* expr, HValue* object, HValue* key, HValue* val, @@ -6955,7 +6983,8 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( possible_transitioned_maps.Add(map); } if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) { - HInstruction* result = BuildKeyedGeneric(access_type, object, key, val); + HInstruction* result = BuildKeyedGeneric(access_type, expr, object, key, + val); *has_side_effects = result->HasObservableSideEffects(); return AddInstruction(result); } @@ -6992,7 +7021,8 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( HInstruction* instr = NULL; if (untransitionable_map->has_slow_elements_kind() || !untransitionable_map->IsJSObjectMap()) { - instr = AddInstruction(BuildKeyedGeneric(access_type, object, key, val)); + instr = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key, + val)); } else { instr = BuildMonomorphicElementAccess( object, key, val, transition, untransitionable_map, access_type, @@ -7017,7 +7047,8 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( set_current_block(this_map); HInstruction* access = NULL; if (IsDictionaryElementsKind(elements_kind)) { - access = AddInstruction(BuildKeyedGeneric(access_type, object, key, val)); + access = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key, + val)); } else { ASSERT(IsFastElementsKind(elements_kind) || IsExternalArrayElementsKind(elements_kind) || @@ -7088,7 +7119,8 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( if (monomorphic) { Handle map = types->first(); if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) { - instr = AddInstruction(BuildKeyedGeneric(access_type, obj, key, val)); + instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key, + val)); } else { BuildCheckHeapObject(obj); instr = BuildMonomorphicElementAccess( @@ -7096,7 +7128,7 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( } } else if (!force_generic && (types != NULL && !types->is_empty())) { return HandlePolymorphicElementAccess( - obj, key, val, types, access_type, + expr, obj, key, val, types, access_type, expr->GetStoreMode(), has_side_effects); } else { if (access_type == STORE) { @@ -7111,7 +7143,7 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( Deoptimizer::SOFT); } } - instr = AddInstruction(BuildKeyedGeneric(access_type, obj, key, val)); + instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key, val)); } *has_side_effects = instr->HasObservableSideEffects(); return instr; @@ -7212,7 +7244,7 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedAccess( PropertyAccessInfo info(this, access, ToType(types->first()), name); if (!info.CanAccessAsMonomorphic(types)) { HandlePolymorphicNamedFieldAccess( - access, ast_id, return_id, object, value, types, name); + access, expr, ast_id, return_id, object, value, types, name); return NULL; } @@ -7230,7 +7262,7 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedAccess( &info, object, checked_object, value, ast_id, return_id); } - return BuildNamedGeneric(access, object, name, value, is_uninitialized); + return BuildNamedGeneric(access, expr, object, name, value, is_uninitialized); } @@ -7559,7 +7591,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( } else { Property* prop = expr->expression()->AsProperty(); HInstruction* function = BuildNamedGeneric( - LOAD, receiver, name, NULL, prop->IsUninitialized()); + LOAD, prop, receiver, name, NULL, prop->IsUninitialized()); AddInstruction(function); Push(function); AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); diff --git a/src/hydrogen.h b/src/hydrogen.h index bb9366739..d8d0da77f 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -2415,6 +2415,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { void HandlePropertyAssignment(Assignment* expr); void HandleCompoundAssignment(Assignment* expr); void HandlePolymorphicNamedFieldAccess(PropertyAccessType access_type, + Expression* expr, BailoutId ast_id, BailoutId return_id, HValue* object, @@ -2592,6 +2593,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { HInstruction* BuildIncrement(bool returns_original_input, CountOperation* expr); HInstruction* BuildKeyedGeneric(PropertyAccessType access_type, + Expression* expr, HValue* object, HValue* key, HValue* value); @@ -2611,7 +2613,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { PropertyAccessType access_type, KeyedAccessStoreMode store_mode); - HValue* HandlePolymorphicElementAccess(HValue* object, + HValue* HandlePolymorphicElementAccess(Expression* expr, + HValue* object, HValue* key, HValue* val, SmallMapList* maps, @@ -2627,6 +2630,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { bool* has_side_effects); HInstruction* BuildNamedGeneric(PropertyAccessType access, + Expression* expr, HValue* object, Handle name, HValue* value, diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index 6b93ddd68..f9515bc09 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -1003,6 +1003,9 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { __ mov(receiver, Operand(ebp, kArgumentsOffset)); // load arguments // Use inline caching to speed up access to arguments. + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), Immediate(Smi::FromInt(0))); + } Handle ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize(); __ call(ic, RelocInfo::CODE_TARGET); // It is important that we do not have a test instruction after the diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index beea0b658..a4b4c6dd6 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -1287,7 +1287,7 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { } -void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, +void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, TypeofState typeof_state, Label* slow) { Register context = esi; @@ -1338,7 +1338,12 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, // All extension objects were empty and it is safe to use a global // load IC call. __ mov(LoadIC::ReceiverRegister(), GlobalObjectOperand()); - __ mov(LoadIC::NameRegister(), var->name()); + __ mov(LoadIC::NameRegister(), proxy->var()->name()); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(proxy->VariableFeedbackSlot()))); + } + ContextualMode mode = (typeof_state == INSIDE_TYPEOF) ? NOT_CONTEXTUAL : CONTEXTUAL; @@ -1377,7 +1382,7 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, } -void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, +void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, TypeofState typeof_state, Label* slow, Label* done) { @@ -1386,8 +1391,9 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, // introducing variables. In those cases, we do not want to // perform a runtime call for all variables in the scope // containing the eval. + Variable* var = proxy->var(); if (var->mode() == DYNAMIC_GLOBAL) { - EmitLoadGlobalCheckExtensions(var, typeof_state, slow); + EmitLoadGlobalCheckExtensions(proxy, typeof_state, slow); __ jmp(done); } else if (var->mode() == DYNAMIC_LOCAL) { Variable* local = var->local_if_not_shadowed(); @@ -1420,6 +1426,10 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Comment cmnt(masm_, "[ Global variable"); __ mov(LoadIC::ReceiverRegister(), GlobalObjectOperand()); __ mov(LoadIC::NameRegister(), var->name()); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(proxy->VariableFeedbackSlot()))); + } CallLoadIC(CONTEXTUAL); context()->Plug(eax); break; @@ -1495,7 +1505,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Label done, slow; // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done); __ bind(&slow); __ push(esi); // Context. __ push(Immediate(var->name())); @@ -2022,6 +2032,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { // result = receiver[f](arg); __ bind(&l_call); __ mov(load_receiver, Operand(esp, kPointerSize)); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(expr->KeyedLoadFeedbackSlot()))); + } Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); CallIC(ic, TypeFeedbackId::None()); __ mov(edi, eax); @@ -2038,6 +2052,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ Move(load_receiver, eax); // result __ mov(load_name, isolate()->factory()->done_string()); // "done" + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(expr->DoneFeedbackSlot()))); + } CallLoadIC(NOT_CONTEXTUAL); // result.done in eax Handle bool_ic = ToBooleanStub::GetUninitialized(isolate()); CallIC(bool_ic); @@ -2048,6 +2066,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ pop(load_receiver); // result __ mov(load_name, isolate()->factory()->value_string()); // "value" + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(expr->ValueFeedbackSlot()))); + } CallLoadIC(NOT_CONTEXTUAL); // result.value in eax context()->DropAndPlug(2, eax); // drop iter and g break; @@ -2208,14 +2230,26 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { Literal* key = prop->key()->AsLiteral(); ASSERT(!key->value()->IsSmi()); __ mov(LoadIC::NameRegister(), Immediate(key->value())); - CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(prop->PropertyFeedbackSlot()))); + CallLoadIC(NOT_CONTEXTUAL); + } else { + CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); + } } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); - CallIC(ic, prop->PropertyFeedbackId()); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(prop->PropertyFeedbackSlot()))); + CallIC(ic); + } else { + CallIC(ic, prop->PropertyFeedbackId()); + } } @@ -2680,7 +2714,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { { PreservePositionScope scope(masm()->positions_recorder()); // Generate code for loading from variables potentially shadowed by // eval-introduced variables. - EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done); } __ bind(&slow); // Call the runtime to find the function to call (returned in eax) and @@ -4022,7 +4056,13 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { // Load the function from the receiver. __ mov(LoadIC::ReceiverRegister(), Operand(esp, 0)); __ mov(LoadIC::NameRegister(), Immediate(expr->name())); - CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(expr->CallRuntimeFeedbackSlot()))); + CallLoadIC(NOT_CONTEXTUAL); + } else { + CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); + } // Push the target function under the receiver. __ push(Operand(esp, 0)); @@ -4370,6 +4410,10 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { Comment cmnt(masm_, "[ Global variable"); __ mov(LoadIC::ReceiverRegister(), GlobalObjectOperand()); __ mov(LoadIC::NameRegister(), Immediate(proxy->name())); + if (FLAG_vector_ics) { + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(proxy->VariableFeedbackSlot()))); + } // Use a regular load, not a contextual load, to avoid a reference // error. CallLoadIC(NOT_CONTEXTUAL); @@ -4381,7 +4425,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, INSIDE_TYPEOF, &slow, &done); __ bind(&slow); __ push(esi); diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index 16b8ecfb6..aa5899ce6 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -974,6 +974,18 @@ const Register LoadIC::ReceiverRegister() { return edx; } const Register LoadIC::NameRegister() { return ecx; } +const Register LoadIC::SlotRegister() { + ASSERT(FLAG_vector_ics); + return eax; +} + + +const Register LoadIC::VectorRegister() { + ASSERT(FLAG_vector_ics); + return ebx; +} + + const Register StoreIC::ReceiverRegister() { return edx; } const Register StoreIC::NameRegister() { return ecx; } const Register StoreIC::ValueRegister() { return eax; } diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index ca3a6400b..6762a6c66 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -2836,6 +2836,15 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { ASSERT(ToRegister(instr->result()).is(eax)); __ mov(LoadIC::NameRegister(), instr->name()); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ mov(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(eax)); + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(instr->hydrogen()->slot()))); + } ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; Handle ic = LoadIC::initialize_stub(isolate(), mode); CallCode(ic, RelocInfo::CODE_TARGET, instr); @@ -2970,6 +2979,15 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { ASSERT(ToRegister(instr->result()).is(eax)); __ mov(LoadIC::NameRegister(), instr->name()); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ mov(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(eax)); + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(instr->hydrogen()->slot()))); + } Handle ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3210,6 +3228,16 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(LoadIC::ReceiverRegister())); ASSERT(ToRegister(instr->key()).is(LoadIC::NameRegister())); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ mov(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(eax)); + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(instr->hydrogen()->slot()))); + } + Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index feb714759..5aa08d9a6 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -2092,8 +2092,13 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) { LOperand* context = UseFixed(instr->context(), esi); LOperand* global_object = UseFixed(instr->global_object(), LoadIC::ReceiverRegister()); + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } + LLoadGlobalGeneric* result = - new(zone()) LLoadGlobalGeneric(context, global_object); + new(zone()) LLoadGlobalGeneric(context, global_object, vector); return MarkAsCall(DefineFixed(result, eax), instr); } @@ -2147,7 +2152,12 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { LOperand* context = UseFixed(instr->context(), esi); LOperand* object = UseFixed(instr->object(), LoadIC::ReceiverRegister()); - LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(context, object); + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } + LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric( + context, object, vector); return MarkAsCall(DefineFixed(result, eax), instr); } @@ -2206,9 +2216,12 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { LOperand* context = UseFixed(instr->context(), esi); LOperand* object = UseFixed(instr->object(), LoadIC::ReceiverRegister()); LOperand* key = UseFixed(instr->key(), LoadIC::NameRegister()); - + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } LLoadKeyedGeneric* result = - new(zone()) LLoadKeyedGeneric(context, object, key); + new(zone()) LLoadKeyedGeneric(context, object, key, vector); return MarkAsCall(DefineFixed(result, eax), instr); } diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 4a6ec75b1..ed06d986c 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -1578,15 +1578,17 @@ class LLoadNamedField V8_FINAL : public LTemplateInstruction<1, 1, 0> { }; -class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> { +class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: - LLoadNamedGeneric(LOperand* context, LOperand* object) { + LLoadNamedGeneric(LOperand* context, LOperand* object, LOperand* vector) { inputs_[0] = context; inputs_[1] = object; + temps_[0] = vector; } LOperand* context() { return inputs_[0]; } LOperand* object() { return inputs_[1]; } + LOperand* temp_vector() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic") DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric) @@ -1667,19 +1669,23 @@ inline static bool ExternalArrayOpRequiresTemp( } -class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 0> { +class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 1> { public: - LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) { + LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key, + LOperand* vector) { inputs_[0] = context; inputs_[1] = obj; inputs_[2] = key; + temps_[0] = vector; } LOperand* context() { return inputs_[0]; } LOperand* object() { return inputs_[1]; } LOperand* key() { return inputs_[2]; } + LOperand* temp_vector() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") + DECLARE_HYDROGEN_ACCESSOR(LoadKeyedGeneric) }; @@ -1690,15 +1696,18 @@ class LLoadGlobalCell V8_FINAL : public LTemplateInstruction<1, 0, 0> { }; -class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> { +class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: - LLoadGlobalGeneric(LOperand* context, LOperand* global_object) { + LLoadGlobalGeneric(LOperand* context, LOperand* global_object, + LOperand* vector) { inputs_[0] = context; inputs_[1] = global_object; + temps_[0] = vector; } LOperand* context() { return inputs_[0]; } LOperand* global_object() { return inputs_[1]; } + LOperand* temp_vector() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic") DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric) diff --git a/src/ic.h b/src/ic.h index 4e7542341..61845d1d6 100644 --- a/src/ic.h +++ b/src/ic.h @@ -392,6 +392,11 @@ class LoadIC: public IC { static const Register ReceiverRegister(); static const Register NameRegister(); + // With flag vector-ics, there is an additional argument. And for calls from + // crankshaft, yet another. + static const Register SlotRegister(); + static const Register VectorRegister(); + static ExtraICState ComputeExtraICState(ContextualMode contextual_mode) { return ContextualModeBits::encode(contextual_mode); } diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc index 272c977ea..7ec4f3b85 100644 --- a/src/x64/builtins-x64.cc +++ b/src/x64/builtins-x64.cc @@ -1074,6 +1074,9 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { __ movp(receiver, Operand(rbp, kArgumentsOffset)); // load arguments // Use inline caching to speed up access to arguments. + if (FLAG_vector_ics) { + __ Move(LoadIC::SlotRegister(), Smi::FromInt(0)); + } Handle ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize(); __ Call(ic, RelocInfo::CODE_TARGET); diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 9ea58d285..ae277b3fe 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -1321,7 +1321,7 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { } -void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, +void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, TypeofState typeof_state, Label* slow) { Register context = rsi; @@ -1373,7 +1373,12 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, // All extension objects were empty and it is safe to use a global // load IC call. __ movp(LoadIC::ReceiverRegister(), GlobalObjectOperand()); - __ Move(LoadIC::NameRegister(), var->name()); + __ Move(LoadIC::NameRegister(), proxy->var()->name()); + if (FLAG_vector_ics) { + __ Move(LoadIC::SlotRegister(), + Smi::FromInt(proxy->VariableFeedbackSlot())); + } + ContextualMode mode = (typeof_state == INSIDE_TYPEOF) ? NOT_CONTEXTUAL : CONTEXTUAL; @@ -1411,7 +1416,7 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, } -void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, +void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, TypeofState typeof_state, Label* slow, Label* done) { @@ -1420,8 +1425,9 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, // introducing variables. In those cases, we do not want to // perform a runtime call for all variables in the scope // containing the eval. + Variable* var = proxy->var(); if (var->mode() == DYNAMIC_GLOBAL) { - EmitLoadGlobalCheckExtensions(var, typeof_state, slow); + EmitLoadGlobalCheckExtensions(proxy, typeof_state, slow); __ jmp(done); } else if (var->mode() == DYNAMIC_LOCAL) { Variable* local = var->local_if_not_shadowed(); @@ -1454,6 +1460,10 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Comment cmnt(masm_, "[ Global variable"); __ Move(LoadIC::NameRegister(), var->name()); __ movp(LoadIC::ReceiverRegister(), GlobalObjectOperand()); + if (FLAG_vector_ics) { + __ Move(LoadIC::SlotRegister(), + Smi::FromInt(proxy->VariableFeedbackSlot())); + } CallLoadIC(CONTEXTUAL); context()->Plug(rax); break; @@ -1529,7 +1539,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Label done, slow; // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done); __ bind(&slow); __ Push(rsi); // Context. __ Push(var->name()); @@ -2055,6 +2065,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { // result = receiver[f](arg); __ bind(&l_call); __ movp(load_receiver, Operand(rsp, kPointerSize)); + if (FLAG_vector_ics) { + __ Move(LoadIC::SlotRegister(), + Smi::FromInt(expr->KeyedLoadFeedbackSlot())); + } Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); CallIC(ic, TypeFeedbackId::None()); __ movp(rdi, rax); @@ -2070,6 +2084,9 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ Move(load_receiver, rax); __ Push(load_receiver); // save result __ LoadRoot(load_name, Heap::kdone_stringRootIndex); // "done" + if (FLAG_vector_ics) { + __ Move(LoadIC::SlotRegister(), Smi::FromInt(expr->DoneFeedbackSlot())); + } CallLoadIC(NOT_CONTEXTUAL); // rax=result.done Handle bool_ic = ToBooleanStub::GetUninitialized(isolate()); CallIC(bool_ic); @@ -2079,6 +2096,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { // result.value __ Pop(load_receiver); // result __ LoadRoot(load_name, Heap::kvalue_stringRootIndex); // "value" + if (FLAG_vector_ics) { + __ Move(LoadIC::SlotRegister(), + Smi::FromInt(expr->ValueFeedbackSlot())); + } CallLoadIC(NOT_CONTEXTUAL); // result.value in rax context()->DropAndPlug(2, rax); // drop iter and g break; @@ -2240,14 +2261,24 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Literal* key = prop->key()->AsLiteral(); __ Move(LoadIC::NameRegister(), key->value()); - CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); + if (FLAG_vector_ics) { + __ Move(LoadIC::SlotRegister(), Smi::FromInt(prop->PropertyFeedbackSlot())); + CallLoadIC(NOT_CONTEXTUAL); + } else { + CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); + } } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); - CallIC(ic, prop->PropertyFeedbackId()); + if (FLAG_vector_ics) { + __ Move(LoadIC::SlotRegister(), Smi::FromInt(prop->PropertyFeedbackSlot())); + CallIC(ic); + } else { + CallIC(ic, prop->PropertyFeedbackId()); + } } @@ -2676,7 +2707,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { { PreservePositionScope scope(masm()->positions_recorder()); // Generate code for loading from variables potentially shadowed by // eval-introduced variables. - EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done); } __ bind(&slow); // Call the runtime to find the function to call (returned in rax) and @@ -4036,7 +4067,13 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { // Load the function from the receiver. __ movp(LoadIC::ReceiverRegister(), Operand(rsp, 0)); __ Move(LoadIC::NameRegister(), expr->name()); - CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); + if (FLAG_vector_ics) { + __ Move(LoadIC::SlotRegister(), + Smi::FromInt(expr->CallRuntimeFeedbackSlot())); + CallLoadIC(NOT_CONTEXTUAL); + } else { + CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); + } // Push the target function under the receiver. __ Push(Operand(rsp, 0)); @@ -4377,6 +4414,10 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { Comment cmnt(masm_, "[ Global variable"); __ Move(LoadIC::NameRegister(), proxy->name()); __ movp(LoadIC::ReceiverRegister(), GlobalObjectOperand()); + if (FLAG_vector_ics) { + __ Move(LoadIC::SlotRegister(), + Smi::FromInt(proxy->VariableFeedbackSlot())); + } // Use a regular load, not a contextual load, to avoid a reference // error. CallLoadIC(NOT_CONTEXTUAL); @@ -4388,7 +4429,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { // Generate code for loading from variables potentially shadowed // by eval-introduced variables. - EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); + EmitDynamicLookupFastCase(proxy, INSIDE_TYPEOF, &slow, &done); __ bind(&slow); __ Push(rsi); diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index 61696ce1a..2244f4a9a 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -1000,6 +1000,18 @@ const Register LoadIC::ReceiverRegister() { return rdx; } const Register LoadIC::NameRegister() { return rcx; } +const Register LoadIC::SlotRegister() { + ASSERT(FLAG_vector_ics); + return rax; +} + + +const Register LoadIC::VectorRegister() { + ASSERT(FLAG_vector_ics); + return rbx; +} + + const Register StoreIC::ReceiverRegister() { return rdx; } const Register StoreIC::NameRegister() { return rcx; } const Register StoreIC::ValueRegister() { return rax; } diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 407154c3d..18b230539 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -2853,6 +2853,14 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { ASSERT(ToRegister(instr->result()).is(rax)); __ Move(LoadIC::NameRegister(), instr->name()); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ Move(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(rax)); + __ Move(LoadIC::SlotRegister(), Smi::FromInt(instr->hydrogen()->slot())); + } ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; Handle ic = LoadIC::initialize_stub(isolate(), mode); CallCode(ic, RelocInfo::CODE_TARGET, instr); @@ -2993,6 +3001,14 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { ASSERT(ToRegister(instr->result()).is(rax)); __ Move(LoadIC::NameRegister(), instr->name()); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ Move(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(rax)); + __ Move(LoadIC::SlotRegister(), Smi::FromInt(instr->hydrogen()->slot())); + } Handle ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3289,6 +3305,15 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(LoadIC::ReceiverRegister())); ASSERT(ToRegister(instr->key()).is(LoadIC::NameRegister())); + if (FLAG_vector_ics) { + Register vector = ToRegister(instr->temp_vector()); + ASSERT(vector.is(LoadIC::VectorRegister())); + __ Move(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + ASSERT(LoadIC::SlotRegister().is(rax)); + __ Move(LoadIC::SlotRegister(), Smi::FromInt(instr->hydrogen()->slot())); + } + Handle ic = isolate()->builtins()->KeyedLoadIC_Initialize(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index f1821d355..005fbdba1 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -2043,8 +2043,13 @@ LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) { LOperand* context = UseFixed(instr->context(), rsi); LOperand* global_object = UseFixed(instr->global_object(), LoadIC::ReceiverRegister()); + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } + LLoadGlobalGeneric* result = - new(zone()) LLoadGlobalGeneric(context, global_object); + new(zone()) LLoadGlobalGeneric(context, global_object, vector); return MarkAsCall(DefineFixed(result, rax), instr); } @@ -2110,7 +2115,12 @@ LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { LOperand* context = UseFixed(instr->context(), rsi); LOperand* object = UseFixed(instr->object(), LoadIC::ReceiverRegister()); - LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(context, object); + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } + LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric( + context, object, vector); return MarkAsCall(DefineFixed(result, rax), instr); } @@ -2197,9 +2207,13 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { LOperand* context = UseFixed(instr->context(), rsi); LOperand* object = UseFixed(instr->object(), LoadIC::ReceiverRegister()); LOperand* key = UseFixed(instr->key(), LoadIC::NameRegister()); + LOperand* vector = NULL; + if (FLAG_vector_ics) { + vector = FixedTemp(LoadIC::VectorRegister()); + } LLoadKeyedGeneric* result = - new(zone()) LLoadKeyedGeneric(context, object, key); + new(zone()) LLoadKeyedGeneric(context, object, key, vector); return MarkAsCall(DefineFixed(result, rax), instr); } diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index a64f6a1d2..442e46f26 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -1570,11 +1570,13 @@ class LLoadNamedField V8_FINAL : public LTemplateInstruction<1, 1, 0> { }; -class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> { +class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: - explicit LLoadNamedGeneric(LOperand* context, LOperand* object) { + explicit LLoadNamedGeneric(LOperand* context, LOperand* object, + LOperand* vector) { inputs_[0] = context; inputs_[1] = object; + temps_[0] = vector; } DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic") @@ -1582,6 +1584,8 @@ class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> { LOperand* context() { return inputs_[0]; } LOperand* object() { return inputs_[1]; } + LOperand* temp_vector() { return temps_[0]; } + Handle name() const { return hydrogen()->name(); } }; @@ -1653,19 +1657,23 @@ class LLoadKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> { }; -class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 0> { +class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 1> { public: - LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key) { + LLoadKeyedGeneric(LOperand* context, LOperand* obj, LOperand* key, + LOperand* vector) { inputs_[0] = context; inputs_[1] = obj; inputs_[2] = key; + temps_[0] = vector; } DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") + DECLARE_HYDROGEN_ACCESSOR(LoadKeyedGeneric) LOperand* context() { return inputs_[0]; } LOperand* object() { return inputs_[1]; } LOperand* key() { return inputs_[2]; } + LOperand* temp_vector() { return temps_[0]; } }; @@ -1676,11 +1684,13 @@ class LLoadGlobalCell V8_FINAL : public LTemplateInstruction<1, 0, 0> { }; -class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> { +class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: - explicit LLoadGlobalGeneric(LOperand* context, LOperand* global_object) { + explicit LLoadGlobalGeneric(LOperand* context, LOperand* global_object, + LOperand* vector) { inputs_[0] = context; inputs_[1] = global_object; + temps_[0] = vector; } DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic") @@ -1688,6 +1698,8 @@ class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> { LOperand* context() { return inputs_[0]; } LOperand* global_object() { return inputs_[1]; } + LOperand* temp_vector() { return temps_[0]; } + Handle name() const { return hydrogen()->name(); } bool for_typeof() const { return hydrogen()->for_typeof(); } }; diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc index c7c8f3fc2..2d913715e 100644 --- a/test/cctest/test-compiler.cc +++ b/test/cctest/test-compiler.cc @@ -309,8 +309,9 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) { Handle feedback_vector(f->shared()->feedback_vector()); // Verify that we gathered feedback. - CHECK_EQ(1, feedback_vector->length()); - CHECK(feedback_vector->get(0)->IsJSFunction()); + int expected_count = FLAG_vector_ics ? 2 : 1; + CHECK_EQ(expected_count, feedback_vector->length()); + CHECK(feedback_vector->get(expected_count - 1)->IsJSFunction()); CompileRun("%OptimizeFunctionOnNextCall(f); f(fun1);"); @@ -318,7 +319,8 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) { // of the full code. CHECK(f->IsOptimized()); CHECK(f->shared()->has_deoptimization_support()); - CHECK(f->shared()->feedback_vector()->get(0)->IsJSFunction()); + CHECK(f->shared()->feedback_vector()-> + get(expected_count - 1)->IsJSFunction()); } @@ -344,16 +346,15 @@ TEST(FeedbackVectorUnaffectedByScopeChanges) { *v8::Handle::Cast( CcTest::global()->Get(v8_str("morphing_call")))); - // morphing_call should have one feedback vector slot for the call to - // call_target(). - CHECK_EQ(1, f->shared()->feedback_vector()->length()); + int expected_count = FLAG_vector_ics ? 2 : 1; + CHECK_EQ(expected_count, f->shared()->feedback_vector()->length()); // And yet it's not compiled. CHECK(!f->shared()->is_compiled()); CompileRun("morphing_call();"); // The vector should have the same size despite the new scoping. - CHECK_EQ(1, f->shared()->feedback_vector()->length()); + CHECK_EQ(expected_count, f->shared()->feedback_vector()->length()); CHECK(f->shared()->is_compiled()); } diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 46445e2a1..223350713 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -3123,18 +3123,22 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) { Handle feedback_vector(f->shared()->feedback_vector()); - CHECK_EQ(2, feedback_vector->length()); - CHECK(feedback_vector->get(0)->IsJSFunction()); - CHECK(feedback_vector->get(1)->IsJSFunction()); + int expected_length = FLAG_vector_ics ? 4 : 2; + CHECK_EQ(expected_length, feedback_vector->length()); + for (int i = 0; i < expected_length; i++) { + if ((i % 2) == 1) { + CHECK(feedback_vector->get(i)->IsJSFunction()); + } + } SimulateIncrementalMarking(); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); - CHECK_EQ(2, feedback_vector->length()); - CHECK_EQ(feedback_vector->get(0), - *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate())); - CHECK_EQ(feedback_vector->get(1), - *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate())); + CHECK_EQ(expected_length, feedback_vector->length()); + for (int i = 0; i < expected_length; i++) { + CHECK_EQ(feedback_vector->get(i), + *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate())); + } } -- 2.34.1