Emitting the common return sequence in the top-level compiler in one function for each platform.

I factored out the code for emitting the return sequence since we had this code duplicated in the top-level compiler.

Review URL: http://codereview.chromium.org/354024

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3213 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 34dee031
...@@ -102,26 +102,51 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { ...@@ -102,26 +102,51 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
// body. // body.
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex); __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
} }
{ Comment cmnt(masm_, "Return sequence"); EmitReturnSequence(function_->end_position());
if (return_label_.is_bound()) { }
__ b(&return_label_);
} else {
__ bind(&return_label_); void FastCodeGenerator::EmitReturnSequence(int position) {
SetReturnPosition(fun); Comment cmnt(masm_, "[ Return sequence");
if (FLAG_trace) { if (return_label_.is_bound()) {
// Push the return value on the stack as the parameter. __ b(&return_label_);
// Runtime::TraceExit returns its parameter in r0. } else {
__ push(r0); __ bind(&return_label_);
__ CallRuntime(Runtime::kTraceExit, 1); if (FLAG_trace) {
} // Push the return value on the stack as the parameter.
__ RecordJSReturn(); // Runtime::TraceExit returns its parameter in r0.
__ mov(sp, fp); __ push(r0);
__ ldm(ia_w, sp, fp.bit() | lr.bit()); __ CallRuntime(Runtime::kTraceExit, 1);
int num_parameters = function_->scope()->num_parameters();
__ add(sp, sp, Operand((num_parameters + 1) * kPointerSize));
__ Jump(lr);
} }
#ifdef DEBUG
// Add a label for checking the size of the code used for returning.
Label check_exit_codesize;
masm_->bind(&check_exit_codesize);
#endif
CodeGenerator::RecordPositions(masm_, position);
__ RecordJSReturn();
__ mov(sp, fp);
__ ldm(ia_w, sp, fp.bit() | lr.bit());
int num_parameters = function_->scope()->num_parameters();
__ add(sp, sp, Operand((num_parameters + 1) * kPointerSize));
__ Jump(lr);
}
#ifdef DEBUG
// Check that the size of the code used for returning matches what is
// expected by the debugger. The add instruction above is an addressing
// mode 1 instruction where there are restrictions on which immediate values
// can be encoded in the instruction and which immediate values requires
// use of an additional instruction for moving the immediate to a temporary
// register.
int expected_return_sequence_length = CodeGenerator::kJSReturnSequenceLength;
if (!masm_->ImmediateFitsAddrMode1Instruction((num_parameters + 1) *
kPointerSize)) {
// Additional mov instruction generated.
expected_return_sequence_length++;
} }
ASSERT_EQ(expected_return_sequence_length,
masm_->InstructionsGeneratedSince(&check_exit_codesize));
#endif
} }
...@@ -259,7 +284,6 @@ void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { ...@@ -259,7 +284,6 @@ void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Comment cmnt(masm_, "[ ReturnStatement"); Comment cmnt(masm_, "[ ReturnStatement");
SetStatementPosition(stmt);
Expression* expr = stmt->expression(); Expression* expr = stmt->expression();
// Complete the statement based on the type of the subexpression. // Complete the statement based on the type of the subexpression.
if (expr->AsLiteral() != NULL) { if (expr->AsLiteral() != NULL) {
...@@ -269,21 +293,7 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { ...@@ -269,21 +293,7 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Visit(expr); Visit(expr);
__ pop(r0); __ pop(r0);
} }
if (return_label_.is_bound()) { EmitReturnSequence(stmt->statement_pos());
__ b(&return_label_);
} else {
__ bind(&return_label_);
if (FLAG_trace) {
__ push(r0);
__ CallRuntime(Runtime::kTraceExit, 1);
}
__ RecordJSReturn();
__ mov(sp, fp);
__ ldm(ia_w, sp, fp.bit() | lr.bit());
int num_parameters = function_->scope()->num_parameters();
__ add(sp, sp, Operand((num_parameters + 1) * kPointerSize));
__ Jump(lr);
}
} }
......
...@@ -73,6 +73,10 @@ class FastCodeGenerator: public AstVisitor { ...@@ -73,6 +73,10 @@ class FastCodeGenerator: public AstVisitor {
Handle<JSFunction> BuildBoilerplate(FunctionLiteral* fun); Handle<JSFunction> BuildBoilerplate(FunctionLiteral* fun);
void DeclareGlobals(Handle<FixedArray> pairs); void DeclareGlobals(Handle<FixedArray> pairs);
// Platform-specific return sequence
void EmitReturnSequence(int position);
// Platform-specific code sequences for calls
void EmitCallWithStub(Call* expr); void EmitCallWithStub(Call* expr);
void EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info); void EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info);
......
...@@ -91,30 +91,42 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { ...@@ -91,30 +91,42 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
} }
{ Comment cmnt(masm_, "[ return <undefined>;"); { Comment cmnt(masm_, "[ return <undefined>;");
// Emit a 'return undefined' in case control fell off the end of the // Emit a 'return undefined' in case control fell off the end of the body.
// body.
__ mov(eax, Factory::undefined_value()); __ mov(eax, Factory::undefined_value());
EmitReturnSequence(function_->end_position());
} }
{ Comment cmnt(masm_, "[ Return sequence"); }
SetReturnPosition(fun);
if (return_label_.is_bound()) {
__ jmp(&return_label_);
} else {
// Common return label
__ bind(&return_label_);
if (FLAG_trace) { void FastCodeGenerator::EmitReturnSequence(int position) {
__ push(eax); Comment cmnt(masm_, "[ Return sequence");
__ CallRuntime(Runtime::kTraceExit, 1); if (return_label_.is_bound()) {
} __ jmp(&return_label_);
__ RecordJSReturn(); } else {
// Do not use the leave instruction here because it is too short to // Common return label
// patch with the code required by the debugger. __ bind(&return_label_);
__ mov(esp, ebp); if (FLAG_trace) {
__ pop(ebp); __ push(eax);
__ ret((fun->scope()->num_parameters() + 1) * kPointerSize); __ CallRuntime(Runtime::kTraceExit, 1);
} }
#ifdef DEBUG
// Add a label for checking the size of the code used for returning.
Label check_exit_codesize;
masm_->bind(&check_exit_codesize);
#endif
CodeGenerator::RecordPositions(masm_, position);
__ RecordJSReturn();
// Do not use the leave instruction here because it is too short to
// patch with the code required by the debugger.
__ mov(esp, ebp);
__ pop(ebp);
__ ret((function_->scope()->num_parameters() + 1) * kPointerSize);
#ifdef ENABLE_DEBUGGER_SUPPORT
// Check that the size of the code used for returning matches what is
// expected by the debugger.
ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#endif
} }
} }
...@@ -270,7 +282,6 @@ void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { ...@@ -270,7 +282,6 @@ void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Comment cmnt(masm_, "[ ReturnStatement"); Comment cmnt(masm_, "[ ReturnStatement");
SetStatementPosition(stmt);
Expression* expr = stmt->expression(); Expression* expr = stmt->expression();
if (expr->AsLiteral() != NULL) { if (expr->AsLiteral() != NULL) {
__ mov(eax, expr->AsLiteral()->handle()); __ mov(eax, expr->AsLiteral()->handle());
...@@ -279,25 +290,7 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { ...@@ -279,25 +290,7 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Visit(expr); Visit(expr);
__ pop(eax); __ pop(eax);
} }
EmitReturnSequence(stmt->statement_pos());
if (return_label_.is_bound()) {
__ jmp(&return_label_);
} else {
__ bind(&return_label_);
if (FLAG_trace) {
__ push(eax);
__ CallRuntime(Runtime::kTraceExit, 1);
}
__ RecordJSReturn();
// Do not use the leave instruction here because it is too short to
// patch with the code required by the debugger.
__ mov(esp, ebp);
__ pop(ebp);
__ ret((function_->scope()->num_parameters() + 1) * kPointerSize);
}
} }
......
...@@ -90,44 +90,52 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { ...@@ -90,44 +90,52 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
} }
{ Comment cmnt(masm_, "[ return <undefined>;"); { Comment cmnt(masm_, "[ return <undefined>;");
// Emit a 'return undefined' in case control fell off the end of the // Emit a 'return undefined' in case control fell off the end of the body.
// body.
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex); __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
EmitReturnSequence(function_->end_position());
} }
{ Comment cmnt(masm_, "Return sequence"); }
SetReturnPosition(fun);
if (return_label_.is_bound()) {
__ jmp(&return_label_);
} else {
__ bind(&return_label_);
if (FLAG_trace) {
__ push(rax);
__ CallRuntime(Runtime::kTraceExit, 1);
}
__ RecordJSReturn();
// Do not use the leave instruction here because it is too short to void FastCodeGenerator::EmitReturnSequence(int position) {
// patch with the code required by the debugger. Comment cmnt(masm_, "[ Return sequence");
__ movq(rsp, rbp); if (return_label_.is_bound()) {
__ pop(rbp); __ jmp(&return_label_);
__ ret((fun->scope()->num_parameters() + 1) * kPointerSize); } else {
#ifdef ENABLE_DEBUGGER_SUPPORT __ bind(&return_label_);
// Add padding that will be overwritten by a debugger breakpoint. We if (FLAG_trace) {
// have just generated "movq rsp, rbp; pop rbp; ret k" with length 7 __ push(rax);
// (3 + 1 + 3). __ CallRuntime(Runtime::kTraceExit, 1);
const int kPadding = Debug::kX64JSReturnSequenceLength - 7; }
for (int i = 0; i < kPadding; ++i) { #ifdef DEBUG
masm_->int3(); // Add a label for checking the size of the code used for returning.
} Label check_exit_codesize;
masm_->bind(&check_exit_codesize);
#endif #endif
CodeGenerator::RecordPositions(masm_, position);
__ RecordJSReturn();
// Do not use the leave instruction here because it is too short to
// patch with the code required by the debugger.
__ movq(rsp, rbp);
__ pop(rbp);
__ ret((function_->scope()->num_parameters() + 1) * kPointerSize);
#ifdef ENABLE_DEBUGGER_SUPPORT
// Add padding that will be overwritten by a debugger breakpoint. We
// have just generated "movq rsp, rbp; pop rbp; ret k" with length 7
// (3 + 1 + 3).
const int kPadding = Debug::kX64JSReturnSequenceLength - 7;
for (int i = 0; i < kPadding; ++i) {
masm_->int3();
} }
// Check that the size of the code used for returning matches what is
// expected by the debugger.
ASSERT_EQ(Debug::Debug::kX64JSReturnSequenceLength,
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
#endif
} }
} }
void FastCodeGenerator::Move(Expression::Context context, Register source) { void FastCodeGenerator::Move(Expression::Context context, Register source) {
switch (context) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
...@@ -282,7 +290,6 @@ void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { ...@@ -282,7 +290,6 @@ void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Comment cmnt(masm_, "[ ReturnStatement"); Comment cmnt(masm_, "[ ReturnStatement");
SetStatementPosition(stmt);
Expression* expr = stmt->expression(); Expression* expr = stmt->expression();
if (expr->AsLiteral() != NULL) { if (expr->AsLiteral() != NULL) {
__ Move(rax, expr->AsLiteral()->handle()); __ Move(rax, expr->AsLiteral()->handle());
...@@ -291,33 +298,7 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { ...@@ -291,33 +298,7 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
ASSERT_EQ(Expression::kValue, expr->context()); ASSERT_EQ(Expression::kValue, expr->context());
__ pop(rax); __ pop(rax);
} }
EmitReturnSequence(stmt->statement_pos());
if (return_label_.is_bound()) {
__ jmp(&return_label_);
} else {
__ bind(&return_label_);
if (FLAG_trace) {
__ push(rax);
__ CallRuntime(Runtime::kTraceExit, 1);
}
__ RecordJSReturn();
// Do not use the leave instruction here because it is too short to
// patch with the code required by the debugger.
__ movq(rsp, rbp);
__ pop(rbp);
__ ret((function_->scope()->num_parameters() + 1) * kPointerSize);
#ifdef ENABLE_DEBUGGER_SUPPORT
// Add padding that will be overwritten by a debugger breakpoint. We
// have just generated "movq rsp, rbp; pop rbp; ret k" with length 7
// (3 + 1 + 3).
const int kPadding = Debug::kX64JSReturnSequenceLength - 7;
for (int i = 0; i < kPadding; ++i) {
masm_->int3();
}
#endif
}
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment