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:
parent
81bc2f95e7
commit
6d3fc8a322
@ -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()));
|
||||
|
@ -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; }
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
27
src/ast.cc
27
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);
|
||||
|
67
src/ast.h
67
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<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_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
5
src/ic.h
5
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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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(); }
|
||||
};
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user