Simplify invocation sequence at monomorphic function invocation sites.

Provide known target as a hint to HInvokeFunction instruction so that it can statically determine if arguments adaptation is required.

R=fschneider@chromium.org
BUG=v8:2079

Review URL: https://chromiumcodereview.appspot.com/10116021

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11364 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
vegorov@chromium.org 2012-04-18 09:38:45 +00:00
parent 5713859c99
commit fd9bd722bc
14 changed files with 162 additions and 47 deletions

View File

@ -1473,6 +1473,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> {
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
Handle<JSFunction> known_function() { return hydrogen()->known_function(); }
};

View File

@ -2962,7 +2962,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
CallKind call_kind) {
CallKind call_kind,
R1State r1_state) {
bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
function->shared()->formal_parameter_count() == arity;
@ -2970,7 +2971,10 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
RecordPosition(pointers->position());
if (can_invoke_directly) {
__ LoadHeapObject(r1, function);
if (r1_state == R1_UNINITIALIZED) {
__ LoadHeapObject(r1, function);
}
// Change context if needed.
bool change_context =
(info()->closure()->context() != function->context()) ||
@ -3009,7 +3013,8 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
CallKnownFunction(instr->function(),
instr->arity(),
instr,
CALL_AS_METHOD);
CALL_AS_METHOD,
R1_UNINITIALIZED);
}
@ -3434,12 +3439,21 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->function()).is(r1));
ASSERT(instr->HasPointerMap());
ASSERT(instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(instr->arity());
__ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
if (instr->known_function().is_null()) {
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(instr->arity());
__ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
} else {
CallKnownFunction(instr->known_function(),
instr->arity(),
instr,
CALL_AS_METHOD,
R1_CONTAINS_TARGET);
}
}
@ -3494,7 +3508,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
CallKnownFunction(instr->target(),
instr->arity(),
instr,
CALL_AS_FUNCTION,
R1_UNINITIALIZED);
}

View File

@ -215,12 +215,18 @@ class LCodeGen BASE_EMBEDDED {
int argc,
LInstruction* instr);
enum R1State {
R1_UNINITIALIZED,
R1_CONTAINS_TARGET
};
// Generate a direct call to a known function. Expects the function
// to be in r1.
void CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
CallKind call_kind);
CallKind call_kind,
R1State r1_state);
void LoadHeapObject(Register result, Handle<HeapObject> object);

View File

@ -1644,14 +1644,26 @@ class HInvokeFunction: public HBinaryCall {
: HBinaryCall(context, function, argument_count) {
}
HInvokeFunction(HValue* context,
HValue* function,
Handle<JSFunction> known_function,
int argument_count)
: HBinaryCall(context, function, argument_count),
known_function_(known_function) {
}
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
HValue* context() { return first(); }
HValue* function() { return second(); }
Handle<JSFunction> known_function() { return known_function_; }
DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
private:
Handle<JSFunction> known_function_;
};

View File

@ -6165,9 +6165,11 @@ void HGraphBuilder::VisitCall(Call* expr) {
if (TryInlineCall(expr, true)) { // Drop function from environment.
return;
} else {
call = PreProcessCall(new(zone()) HInvokeFunction(context,
function,
argument_count));
call = PreProcessCall(
new(zone()) HInvokeFunction(context,
function,
expr->target(),
argument_count));
Drop(1); // The function.
}

View File

@ -2738,7 +2738,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
CallKind call_kind) {
CallKind call_kind,
EDIState edi_state) {
bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
function->shared()->formal_parameter_count() == arity;
@ -2746,7 +2747,9 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
RecordPosition(pointers->position());
if (can_invoke_directly) {
__ LoadHeapObject(edi, function);
if (edi_state == EDI_UNINITIALIZED) {
__ LoadHeapObject(edi, function);
}
// Change context if needed.
bool change_context =
@ -2789,7 +2792,8 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
CallKnownFunction(instr->function(),
instr->arity(),
instr,
CALL_AS_METHOD);
CALL_AS_METHOD,
EDI_UNINITIALIZED);
}
@ -3236,12 +3240,21 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->function()).is(edi));
ASSERT(instr->HasPointerMap());
ASSERT(instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator generator(
this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(instr->arity());
__ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
if (instr->known_function().is_null()) {
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator generator(
this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(instr->arity());
__ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
} else {
CallKnownFunction(instr->known_function(),
instr->arity(),
instr,
CALL_AS_METHOD,
EDI_CONTAINS_TARGET);
}
}
@ -3296,7 +3309,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(eax));
CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
CallKnownFunction(instr->target(),
instr->arity(),
instr,
CALL_AS_FUNCTION,
EDI_UNINITIALIZED);
}

View File

@ -206,12 +206,18 @@ class LCodeGen BASE_EMBEDDED {
LInstruction* instr,
LOperand* context);
enum EDIState {
EDI_UNINITIALIZED,
EDI_CONTAINS_TARGET
};
// Generate a direct call to a known function. Expects the function
// to be in edi.
void CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
CallKind call_kind);
CallKind call_kind,
EDIState edi_state);
void RecordSafepointWithLazyDeopt(LInstruction* instr,
SafepointMode safepoint_mode);

View File

@ -1502,6 +1502,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 2, 0> {
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
Handle<JSFunction> known_function() { return hydrogen()->known_function(); }
};

View File

@ -2848,7 +2848,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
CallKind call_kind) {
CallKind call_kind,
A1State a1_state) {
bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
function->shared()->formal_parameter_count() == arity;
@ -2856,7 +2857,10 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
RecordPosition(pointers->position());
if (can_invoke_directly) {
__ LoadHeapObject(a1, function);
if (a1_state == A1_UNINITIALIZED) {
__ LoadHeapObject(a1, function);
}
// Change context if needed.
bool change_context =
(info()->closure()->context() != function->context()) ||
@ -2893,7 +2897,11 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
ASSERT(ToRegister(instr->result()).is(v0));
__ mov(a0, v0);
CallKnownFunction(instr->function(), instr->arity(), instr, CALL_AS_METHOD);
CallKnownFunction(instr->function(),
instr->arity(),
instr,
CALL_AS_METHOD,
A1_UNINITIALIZED);
}
@ -3330,12 +3338,21 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->function()).is(a1));
ASSERT(instr->HasPointerMap());
ASSERT(instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(instr->arity());
__ InvokeFunction(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
if (instr->known_function().is_null()) {
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(instr->arity());
__ InvokeFunction(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
} else {
CallKnownFunction(instr->known_function(),
instr->arity(),
instr,
CALL_AS_METHOD,
A1_CONTAINS_TARGET);
}
}
@ -3390,7 +3407,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(v0));
CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
CallKnownFunction(instr->target(),
instr->arity(),
instr,
CALL_AS_FUNCTION,
A1_UNINITIALIZED);
}

View File

@ -212,12 +212,18 @@ class LCodeGen BASE_EMBEDDED {
int argc,
LInstruction* instr);
enum A1State {
A1_UNINITIALIZED,
A1_CONTAINS_TARGET
};
// Generate a direct call to a known function. Expects the function
// to be in a1.
void CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
CallKind call_kind);
CallKind call_kind,
A1State a1_state);
void LoadHeapObject(Register result, Handle<HeapObject> object);

View File

@ -1453,6 +1453,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> {
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
Handle<JSFunction> known_function() { return hydrogen()->known_function(); }
};

View File

@ -2693,7 +2693,8 @@ void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
CallKind call_kind) {
CallKind call_kind,
RDIState rdi_state) {
bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
function->shared()->formal_parameter_count() == arity;
@ -2701,7 +2702,9 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
RecordPosition(pointers->position());
if (can_invoke_directly) {
__ LoadHeapObject(rdi, function);
if (rdi_state == RDI_UNINITIALIZED) {
__ LoadHeapObject(rdi, function);
}
// Change context if needed.
bool change_context =
@ -2746,7 +2749,8 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
CallKnownFunction(instr->function(),
instr->arity(),
instr,
CALL_AS_METHOD);
CALL_AS_METHOD,
RDI_UNINITIALIZED);
}
@ -3184,12 +3188,21 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(ToRegister(instr->function()).is(rdi));
ASSERT(instr->HasPointerMap());
ASSERT(instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(instr->arity());
__ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
if (instr->known_function().is_null()) {
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(instr->arity());
__ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
} else {
CallKnownFunction(instr->known_function(),
instr->arity(),
instr,
CALL_AS_METHOD,
RDI_CONTAINS_TARGET);
}
}
@ -3243,7 +3256,11 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(rax));
CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
CallKnownFunction(instr->target(),
instr->arity(),
instr,
CALL_AS_FUNCTION,
RDI_UNINITIALIZED);
}

View File

@ -196,12 +196,18 @@ class LCodeGen BASE_EMBEDDED {
int argc,
LInstruction* instr);
enum RDIState {
RDI_UNINITIALIZED,
RDI_CONTAINS_TARGET
};
// Generate a direct call to a known function. Expects the function
// to be in rdi.
void CallKnownFunction(Handle<JSFunction> function,
int arity,
LInstruction* instr,
CallKind call_kind);
CallKind call_kind,
RDIState rdi_state);
void RecordSafepointWithLazyDeopt(LInstruction* instr,

View File

@ -1447,6 +1447,7 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> {
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
Handle<JSFunction> known_function() { return hydrogen()->known_function(); }
};