}
+void LCallFunction::PrintDataTo(StringStream* stream) {
+ context()->PrintTo(stream);
+ stream->Add(" ");
+ function()->PrintTo(stream);
+ if (hydrogen()->HasVectorAndSlot()) {
+ stream->Add(" (type-feedback-vector ");
+ temp_vector()->PrintTo(stream);
+ stream->Add(" ");
+ temp_slot()->PrintTo(stream);
+ stream->Add(")");
+ }
+}
+
+
void LCallJSFunction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
function()->PrintTo(stream);
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* function = UseFixed(instr->function(), r1);
- LCallFunction* call = new(zone()) LCallFunction(context, function);
+ LOperand* slot = NULL;
+ LOperand* vector = NULL;
+ if (instr->HasVectorAndSlot()) {
+ slot = FixedTemp(r3);
+ vector = FixedTemp(r2);
+ }
+
+ LCallFunction* call =
+ new (zone()) LCallFunction(context, function, slot, vector);
return MarkAsCall(DefineFixed(call, r0), instr);
}
};
-class LCallFunction FINAL : public LTemplateInstruction<1, 2, 0> {
+class LCallFunction FINAL : public LTemplateInstruction<1, 2, 2> {
public:
- LCallFunction(LOperand* context, LOperand* function) {
+ LCallFunction(LOperand* context, LOperand* function, LOperand* slot,
+ LOperand* vector) {
inputs_[0] = context;
inputs_[1] = function;
+ temps_[0] = slot;
+ temps_[1] = vector;
}
LOperand* context() { return inputs_[0]; }
LOperand* function() { return inputs_[1]; }
+ LOperand* temp_slot() { return temps_[0]; }
+ LOperand* temp_vector() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
DECLARE_HYDROGEN_ACCESSOR(CallFunction)
int arity() const { return hydrogen()->argument_count() - 1; }
+ void PrintDataTo(StringStream* stream) OVERRIDE;
};
DCHECK(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
- CallFunctionStub stub(isolate(), arity, instr->hydrogen()->function_flags());
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallFunctionFlags flags = instr->hydrogen()->function_flags();
+ if (instr->hydrogen()->HasVectorAndSlot()) {
+ Register slot_register = ToRegister(instr->temp_slot());
+ Register vector_register = ToRegister(instr->temp_vector());
+ DCHECK(slot_register.is(r3));
+ DCHECK(vector_register.is(r2));
+
+ Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+ int index = vector->GetIndex(instr->hydrogen()->slot());
+
+ __ Move(vector_register, vector);
+ __ mov(slot_register, Operand(Smi::FromInt(index)));
+
+ CallICState::CallType call_type =
+ (flags & CALL_AS_METHOD) ? CallICState::METHOD : CallICState::FUNCTION;
+
+ Handle<Code> ic =
+ CodeFactory::CallICInOptimizedCode(isolate(), arity, call_type).code();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ CallFunctionStub stub(isolate(), arity, flags);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ }
}
}
+void LCallFunction::PrintDataTo(StringStream* stream) {
+ context()->PrintTo(stream);
+ stream->Add(" ");
+ function()->PrintTo(stream);
+ if (hydrogen()->HasVectorAndSlot()) {
+ stream->Add(" (type-feedback-vector ");
+ temp_vector()->PrintTo(stream);
+ stream->Add(" ");
+ temp_slot()->PrintTo(stream);
+ stream->Add(")");
+ }
+}
+
+
void LInvokeFunction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
function()->PrintTo(stream);
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* function = UseFixed(instr->function(), x1);
- LCallFunction* call = new(zone()) LCallFunction(context, function);
+ LOperand* slot = NULL;
+ LOperand* vector = NULL;
+ if (instr->HasVectorAndSlot()) {
+ slot = FixedTemp(x3);
+ vector = FixedTemp(x2);
+ }
+
+ LCallFunction* call =
+ new (zone()) LCallFunction(context, function, slot, vector);
return MarkAsCall(DefineFixed(call, x0), instr);
}
};
-class LCallFunction FINAL : public LTemplateInstruction<1, 2, 0> {
+class LCallFunction FINAL : public LTemplateInstruction<1, 2, 2> {
public:
- LCallFunction(LOperand* context, LOperand* function) {
+ LCallFunction(LOperand* context, LOperand* function, LOperand* slot,
+ LOperand* vector) {
inputs_[0] = context;
inputs_[1] = function;
+ temps_[0] = slot;
+ temps_[1] = vector;
}
LOperand* context() { return inputs_[0]; }
LOperand* function() { return inputs_[1]; }
+ LOperand* temp_slot() { return temps_[0]; }
+ LOperand* temp_vector() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
DECLARE_HYDROGEN_ACCESSOR(CallFunction)
int arity() const { return hydrogen()->argument_count() - 1; }
+ void PrintDataTo(StringStream* stream) OVERRIDE;
};
DCHECK(ToRegister(instr->result()).Is(x0));
int arity = instr->arity();
- CallFunctionStub stub(isolate(), arity, instr->hydrogen()->function_flags());
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallFunctionFlags flags = instr->hydrogen()->function_flags();
+ if (instr->hydrogen()->HasVectorAndSlot()) {
+ Register slot_register = ToRegister(instr->temp_slot());
+ Register vector_register = ToRegister(instr->temp_vector());
+ DCHECK(slot_register.is(x3));
+ DCHECK(vector_register.is(x2));
+
+ Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+ int index = vector->GetIndex(instr->hydrogen()->slot());
+
+ __ Mov(vector_register, vector);
+ __ Mov(slot_register, Operand(Smi::FromInt(index)));
+
+ CallICState::CallType call_type =
+ (flags & CALL_AS_METHOD) ? CallICState::METHOD : CallICState::FUNCTION;
+
+ Handle<Code> ic =
+ CodeFactory::CallICInOptimizedCode(isolate(), arity, call_type).code();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ CallFunctionStub stub(isolate(), arity, flags);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ }
after_push_argument_ = false;
}
}
+std::ostream& HCallFunction::PrintDataTo(std::ostream& os) const { // NOLINT
+ os << NameOf(context()) << " " << NameOf(function());
+ if (HasVectorAndSlot()) {
+ os << " (type-feedback-vector icslot " << slot().ToInt() << ")";
+ }
+ return os;
+}
+
+
void HBoundsCheck::ApplyIndexChange() {
if (skip_check()) return;
DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(
HCallFunction, HValue*, int, CallFunctionFlags);
- HValue* context() { return first(); }
- HValue* function() { return second(); }
+ HValue* context() const { return first(); }
+ HValue* function() const { return second(); }
CallFunctionFlags function_flags() const { return function_flags_; }
+ FeedbackVectorICSlot slot() const { return slot_; }
+ Handle<TypeFeedbackVector> feedback_vector() const {
+ return feedback_vector_;
+ }
+ bool HasVectorAndSlot() const { return !feedback_vector_.is_null(); }
+ void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
+ FeedbackVectorICSlot slot) {
+ feedback_vector_ = vector;
+ slot_ = slot;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(CallFunction)
+ std::ostream& PrintDataTo(std::ostream& os) const OVERRIDE; // NOLINT
+
int argument_delta() const OVERRIDE { return -argument_count(); }
private:
- HCallFunction(HValue* context,
- HValue* function,
- int argument_count,
+ HCallFunction(HValue* context, HValue* function, int argument_count,
CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS)
- : HBinaryCall(context, function, argument_count), function_flags_(flags) {
- }
+ : HBinaryCall(context, function, argument_count),
+ function_flags_(flags),
+ slot_(FeedbackVectorICSlot::Invalid()) {}
CallFunctionFlags function_flags_;
+ Handle<TypeFeedbackVector> feedback_vector_;
+ FeedbackVectorICSlot slot_;
};
Push(graph()->GetConstantUndefined());
CHECK_ALIVE(VisitExpressions(expr->arguments()));
PushArgumentsFromEnvironment(argument_count);
- call = New<HCallFunction>(function, argument_count);
+ HCallFunction* call_function =
+ New<HCallFunction>(function, argument_count);
+ call = call_function;
+ if (expr->is_uninitialized() && expr->HasCallFeedbackSlot()) {
+ // We've never seen this call before, so let's have Crankshaft learn
+ // through the type vector.
+ Handle<SharedFunctionInfo> current_shared =
+ function_state()->compilation_info()->shared_info();
+ Handle<TypeFeedbackVector> vector =
+ handle(current_shared->feedback_vector(), isolate());
+ FeedbackVectorICSlot slot = expr->CallFeedbackSlot();
+ call_function->SetVectorAndSlot(vector, slot);
+ }
}
}
DCHECK(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- CallFunctionStub stub(isolate(), arity, instr->hydrogen()->function_flags());
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallFunctionFlags flags = instr->hydrogen()->function_flags();
+ if (instr->hydrogen()->HasVectorAndSlot()) {
+ Register slot_register = ToRegister(instr->temp_slot());
+ Register vector_register = ToRegister(instr->temp_vector());
+ DCHECK(slot_register.is(edx));
+ DCHECK(vector_register.is(ebx));
+
+ Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+ int index = vector->GetIndex(instr->hydrogen()->slot());
+
+ __ mov(vector_register, vector);
+ __ mov(slot_register, Immediate(Smi::FromInt(index)));
+
+ CallICState::CallType call_type =
+ (flags & CALL_AS_METHOD) ? CallICState::METHOD : CallICState::FUNCTION;
+
+ Handle<Code> ic =
+ CodeFactory::CallICInOptimizedCode(isolate(), arity, call_type).code();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ CallFunctionStub stub(isolate(), arity, flags);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ }
}
}
+void LCallFunction::PrintDataTo(StringStream* stream) {
+ context()->PrintTo(stream);
+ stream->Add(" ");
+ function()->PrintTo(stream);
+ if (hydrogen()->HasVectorAndSlot()) {
+ stream->Add(" (type-feedback-vector ");
+ temp_vector()->PrintTo(stream);
+ stream->Add(" ");
+ temp_slot()->PrintTo(stream);
+ stream->Add(")");
+ }
+}
+
+
void LCallJSFunction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
function()->PrintTo(stream);
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* function = UseFixed(instr->function(), edi);
- LCallFunction* call = new(zone()) LCallFunction(context, function);
+ LOperand* slot = NULL;
+ LOperand* vector = NULL;
+ if (instr->HasVectorAndSlot()) {
+ slot = FixedTemp(edx);
+ vector = FixedTemp(ebx);
+ }
+
+ LCallFunction* call =
+ new (zone()) LCallFunction(context, function, slot, vector);
return MarkAsCall(DefineFixed(call, eax), instr);
}
};
-class LCallFunction FINAL : public LTemplateInstruction<1, 2, 0> {
+class LCallFunction FINAL : public LTemplateInstruction<1, 2, 2> {
public:
- explicit LCallFunction(LOperand* context, LOperand* function) {
+ LCallFunction(LOperand* context, LOperand* function, LOperand* slot,
+ LOperand* vector) {
inputs_[0] = context;
inputs_[1] = function;
+ temps_[0] = slot;
+ temps_[1] = vector;
}
LOperand* context() { return inputs_[0]; }
LOperand* function() { return inputs_[1]; }
+ LOperand* temp_slot() { return temps_[0]; }
+ LOperand* temp_vector() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
DECLARE_HYDROGEN_ACCESSOR(CallFunction)
+ void PrintDataTo(StringStream* stream) OVERRIDE;
int arity() const { return hydrogen()->argument_count() - 1; }
};
}
+bool IC::AddressIsOptimizedCode() const {
+ Object* maybe_function =
+ Memory::Object_at(fp() + JavaScriptFrameConstants::kFunctionOffset);
+ if (maybe_function->IsJSFunction()) {
+ JSFunction* function = JSFunction::cast(maybe_function);
+ return function->IsOptimized();
+ }
+ return false;
+}
+
+
static void LookupForRead(LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
CallICNexus* nexus = casted_nexus<CallICNexus>();
nexus->ConfigureMonomorphicArray();
- CallIC_ArrayTrampolineStub stub(isolate(), callic_state);
- set_target(*stub.GetCode());
+ // Vector-based ICs have a different calling convention in optimized code
+ // than full code so the correct stub has to be chosen.
+ if (AddressIsOptimizedCode()) {
+ CallIC_ArrayStub stub(isolate(), callic_state);
+ set_target(*stub.GetCode());
+ } else {
+ CallIC_ArrayTrampolineStub stub(isolate(), callic_state);
+ set_target(*stub.GetCode());
+ }
+
Handle<String> name;
if (array_function->shared()->name()->IsString()) {
name = Handle<String>(String::cast(array_function->shared()->name()),
CallICNexus* nexus = casted_nexus<CallICNexus>();
nexus->ConfigureGeneric();
- CallICTrampolineStub stub(isolate(), callic_state);
- Handle<Code> code = stub.GetCode();
- set_target(*code);
+ // Vector-based ICs have a different calling convention in optimized code
+ // than full code so the correct stub has to be chosen.
+ if (AddressIsOptimizedCode()) {
+ CallICStub stub(isolate(), callic_state);
+ set_target(*stub.GetCode());
+ } else {
+ CallICTrampolineStub stub(isolate(), callic_state);
+ set_target(*stub.GetCode());
+ }
Handle<Object> name = isolate()->factory()->empty_string();
if (function->IsJSFunction()) {
// Get the original (non-breakpointed) code object of the caller.
Code* GetOriginalCode() const;
+ bool AddressIsOptimizedCode() const;
+
// Set the call-site target.
inline void set_target(Code* code);
bool is_target_set() { return target_set_; }
DCHECK(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
- CallFunctionStub stub(isolate(), arity, instr->hydrogen()->function_flags());
- CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ CallFunctionFlags flags = instr->hydrogen()->function_flags();
+ if (instr->hydrogen()->HasVectorAndSlot()) {
+ Register slot_register = ToRegister(instr->temp_slot());
+ Register vector_register = ToRegister(instr->temp_vector());
+ DCHECK(slot_register.is(rdx));
+ DCHECK(vector_register.is(rbx));
+
+ Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+ int index = vector->GetIndex(instr->hydrogen()->slot());
+
+ __ Move(vector_register, vector);
+ __ Move(slot_register, Smi::FromInt(index));
+
+ CallICState::CallType call_type =
+ (flags & CALL_AS_METHOD) ? CallICState::METHOD : CallICState::FUNCTION;
+
+ Handle<Code> ic =
+ CodeFactory::CallICInOptimizedCode(isolate(), arity, call_type).code();
+ CallCode(ic, RelocInfo::CODE_TARGET, instr);
+ } else {
+ CallFunctionStub stub(isolate(), arity, flags);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+ }
}
}
+void LCallFunction::PrintDataTo(StringStream* stream) {
+ context()->PrintTo(stream);
+ stream->Add(" ");
+ function()->PrintTo(stream);
+ if (hydrogen()->HasVectorAndSlot()) {
+ stream->Add(" (type-feedback-vector ");
+ temp_vector()->PrintTo(stream);
+ stream->Add(" ");
+ temp_slot()->PrintTo(stream);
+ stream->Add(")");
+ }
+}
+
+
void LCallJSFunction::PrintDataTo(StringStream* stream) {
stream->Add("= ");
function()->PrintTo(stream);
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
LOperand* context = UseFixed(instr->context(), rsi);
LOperand* function = UseFixed(instr->function(), rdi);
- LCallFunction* call = new(zone()) LCallFunction(context, function);
+ LOperand* slot = NULL;
+ LOperand* vector = NULL;
+ if (instr->HasVectorAndSlot()) {
+ slot = FixedTemp(rdx);
+ vector = FixedTemp(rbx);
+ }
+ LCallFunction* call =
+ new (zone()) LCallFunction(context, function, slot, vector);
return MarkAsCall(DefineFixed(call, rax), instr);
}
};
-class LCallFunction FINAL : public LTemplateInstruction<1, 2, 0> {
+class LCallFunction FINAL : public LTemplateInstruction<1, 2, 2> {
public:
- LCallFunction(LOperand* context, LOperand* function) {
+ LCallFunction(LOperand* context, LOperand* function, LOperand* slot,
+ LOperand* vector) {
inputs_[0] = context;
inputs_[1] = function;
+ temps_[0] = slot;
+ temps_[1] = vector;
}
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
LOperand* context() { return inputs_[0]; }
LOperand* function() { return inputs_[1]; }
+ LOperand* temp_slot() { return temps_[0]; }
+ LOperand* temp_vector() { return temps_[1]; }
int arity() const { return hydrogen()->argument_count() - 1; }
+
+ void PrintDataTo(StringStream* stream) OVERRIDE;
};