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
This commit is contained in:
mvstanton@chromium.org 2014-07-21 11:19:56 +00:00
parent 81bc2f95e7
commit 6d3fc8a322
33 changed files with 730 additions and 127 deletions

View File

@ -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<Code> 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<Code> 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<Code> 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()));

View File

@ -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; }

View File

@ -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);
}

View File

@ -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)

View File

@ -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<Code> 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<Code> 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<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
}

View File

@ -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<Code> 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<String> 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<Code> 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<Code> 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;

View File

@ -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; }

View File

@ -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);
}

View File

@ -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);

View File

@ -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<Code> 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<Code> 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<Code> ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL);
CallCode(ic, RelocInfo::CODE_TARGET, instr);

View File

@ -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);

View File

@ -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<Expression*>* 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<Expression*>* 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_;
};

View File

@ -1910,6 +1910,12 @@ bool Genesis::InstallNatives() {
Handle<JSFunction> apply =
InstallFunction(proto, "apply", JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), 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<FixedArray> 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

View File

@ -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,

View File

@ -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);

View File

@ -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<String> name() const { return name_; }
bool for_typeof() const { return for_typeof_; }
int slot() const {
ASSERT(FLAG_vector_ics &&
slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
return slot_;
}
Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
void SetVectorAndSlot(Handle<FixedArray> 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<String> 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<String> name_;
bool for_typeof_;
Handle<FixedArray> feedback_vector_;
int slot_;
};
@ -6422,6 +6437,18 @@ class HLoadNamedGeneric V8_FINAL : public HTemplateInstruction<2> {
HValue* object() const { return OperandAt(1); }
Handle<Object> name() const { return name_; }
int slot() const {
ASSERT(FLAG_vector_ics &&
slot_ != FeedbackSlotInterface::kInvalidFeedbackSlot);
return slot_;
}
Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
void SetVectorAndSlot(Handle<FixedArray> 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<Object> 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<Object> name_;
Handle<FixedArray> 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<FixedArray> feedback_vector() const { return feedback_vector_; }
void SetVectorAndSlot(Handle<FixedArray> 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<FixedArray> feedback_vector_;
int slot_;
};

View File

@ -5371,6 +5371,13 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
New<HLoadGlobalGeneric>(global_object,
variable->name(),
ast_context()->is_for_typeof());
if (FLAG_vector_ics) {
Handle<SharedFunctionInfo> 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<String> name,
HValue* value,
@ -6782,7 +6792,15 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric(
Deoptimizer::SOFT);
}
if (access_type == LOAD) {
return New<HLoadNamedGeneric>(object, name);
HLoadNamedGeneric* result = New<HLoadNamedGeneric>(object, name);
if (FLAG_vector_ics) {
Handle<SharedFunctionInfo> current_shared =
function_state()->compilation_info()->shared_info();
result->SetVectorAndSlot(
handle(current_shared->feedback_vector(), isolate()),
expr->AsProperty()->PropertyFeedbackSlot());
}
return result;
} else {
return New<HStoreNamedGeneric>(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<HLoadKeyedGeneric>(object, key);
HLoadKeyedGeneric* result = New<HLoadKeyedGeneric>(object, key);
if (FLAG_vector_ics) {
Handle<SharedFunctionInfo> current_shared =
function_state()->compilation_info()->shared_info();
result->SetVectorAndSlot(
handle(current_shared->feedback_vector(), isolate()),
expr->AsProperty()->PropertyFeedbackSlot());
}
return result;
} else {
return New<HStoreKeyedGeneric>(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> 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);

View File

@ -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<String> name,
HValue* value,

View File

@ -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<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
__ call(ic, RelocInfo::CODE_TARGET);
// It is important that we do not have a test instruction after the

View File

@ -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<Code> 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<Code> 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<Code> 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);

View File

@ -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; }

View File

@ -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<Code> 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<Code> 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<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}

View File

@ -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);
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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<Code> ic =
masm->isolate()->builtins()->KeyedLoadIC_Initialize();
__ Call(ic, RelocInfo::CODE_TARGET);

View File

@ -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<Code> 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<Code> 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<Code> 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);

View File

@ -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; }

View File

@ -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<Code> 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<Code> 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<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}

View File

@ -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);
}

View File

@ -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<Object> 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<Object> name() const { return hydrogen()->name(); }
bool for_typeof() const { return hydrogen()->for_typeof(); }
};

View File

@ -309,8 +309,9 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) {
Handle<FixedArray> 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<v8::Function>::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());
}

View File

@ -3123,18 +3123,22 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) {
Handle<FixedArray> 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()));
}
}