Support for calls on named and keyed properties in the fast compiler of the form:

o.x() and o[expr]()

other changes:
- Fix missing relocation info for StoreIC on global object.
- Generate only one common return sequence instead of always appending 
  "return <undefined>" at the end of each function: The first JS 
  return-statement will generate the common return sequence. All
  other return-statements will generate a unconditional branch to the common
  return sequence.


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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3183 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2181c96d
......@@ -1066,27 +1066,6 @@ void CodeGenerator::Comparison(Condition cc,
}
class CallFunctionStub: public CodeStub {
public:
CallFunctionStub(int argc, InLoopFlag in_loop)
: argc_(argc), in_loop_(in_loop) {}
void Generate(MacroAssembler* masm);
private:
int argc_;
InLoopFlag in_loop_;
#if defined(DEBUG)
void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); }
#endif // defined(DEBUG)
Major MajorKey() { return CallFunction; }
int MinorKey() { return argc_; }
InLoopFlag InLoop() { return in_loop_; }
};
// Call the function on the stack with the given arguments.
void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
int position) {
......
......@@ -433,6 +433,27 @@ class CodeGenerator: public AstVisitor {
};
class CallFunctionStub: public CodeStub {
public:
CallFunctionStub(int argc, InLoopFlag in_loop)
: argc_(argc), in_loop_(in_loop) {}
void Generate(MacroAssembler* masm);
private:
int argc_;
InLoopFlag in_loop_;
#if defined(DEBUG)
void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); }
#endif // defined(DEBUG)
Major MajorKey() { return CallFunction; }
int MinorKey() { return argc_; }
InLoopFlag InLoop() { return in_loop_; }
};
class GenericBinaryOpStub : public CodeStub {
public:
GenericBinaryOpStub(Token::Value op,
......
......@@ -99,20 +99,26 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
// Emit a 'return undefined' in case control fell off the end of the
// body.
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
SetReturnPosition(fun);
if (FLAG_trace) {
// Push the return value on the stack as the parameter.
// Runtime::TraceExit returns its parameter in r0.
__ push(r0);
__ CallRuntime(Runtime::kTraceExit, 1);
}
{ Comment cmnt(masm_, "Return sequence");
if (return_label_.is_bound()) {
__ b(&return_label_);
} else {
__ bind(&return_label_);
SetReturnPosition(fun);
if (FLAG_trace) {
// Push the return value on the stack as the parameter.
// Runtime::TraceExit returns its parameter in r0.
__ 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);
}
__ 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);
}
}
......@@ -183,18 +189,21 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Visit(expr);
__ pop(r0);
}
if (FLAG_trace) {
__ push(r0);
__ CallRuntime(Runtime::kTraceExit, 1);
if (return_label_.is_bound()) {
__ 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);
}
__ 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);
}
......@@ -565,36 +574,97 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
DropAndMove(expr->context(), r0);
}
void FastCodeGenerator::VisitCall(Call* expr) {
Comment cmnt(masm_, "[ Call");
Expression* fun = expr->expression();
void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) {
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
Variable* var = fun->AsVariableProxy()->AsVariable();
ASSERT(var != NULL && !var->is_this() && var->is_global());
ASSERT(!var->is_possibly_eval());
__ mov(r1, Operand(var->name()));
// Push global object as receiver.
__ ldr(r0, CodeGenerator::GlobalObject());
__ stm(db_w, sp, r1.bit() | r0.bit());
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
ASSERT_EQ(Expression::kValue, args->at(i)->context());
}
// Record source position for debugger
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
NOT_IN_LOOP);
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
__ Call(ic, reloc_info);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
DropAndMove(expr->context(), r0);
}
void FastCodeGenerator::EmitCallWithStub(Call* expr) {
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
}
// Record source position for debugger.
SetSourcePosition(expr->position());
CallFunctionStub stub(arg_count, NOT_IN_LOOP);
__ CallStub(&stub);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
DropAndMove(expr->context(), r0);
}
void FastCodeGenerator::VisitCall(Call* expr) {
Expression* fun = expr->expression();
if (fun->AsProperty() != NULL) {
// Call on a property.
Property* prop = fun->AsProperty();
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsSymbol()) {
// Call on a named property: foo.x(1,2,3)
__ mov(r0, Operand(key->handle()));
__ push(r0);
Visit(prop->obj());
// Use call IC.
EmitCallWithIC(expr, RelocInfo::CODE_TARGET);
} else {
// Call on a keyed property : foo[key](1,2,3)
// Use a keyed load IC followed by a call IC.
Visit(prop->obj());
Visit(prop->key());
// Record source position of property.
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Load receiver object into r1.
if (prop->is_synthetic()) {
__ ldr(r1, CodeGenerator::GlobalObject());
} else {
__ ldr(r1, MemOperand(sp, kPointerSize));
}
// Overwrite (object, key) with (function, receiver).
__ str(r0, MemOperand(sp, kPointerSize));
__ str(r1, MemOperand(sp));
EmitCallWithStub(expr);
}
} else if (fun->AsVariableProxy()->AsVariable() != NULL) {
// Call on a global variable
Variable* var = fun->AsVariableProxy()->AsVariable();
ASSERT(var != NULL && !var->is_this() && var->is_global());
ASSERT(!var->is_possibly_eval());
__ mov(r1, Operand(var->name()));
// Push global object as receiver.
__ ldr(r0, CodeGenerator::GlobalObject());
__ stm(db_w, sp, r1.bit() | r0.bit());
EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT);
} else {
// Calls we cannot handle right now.
// Should bailout in the CodeGenSelector.
UNREACHABLE();
}
}
void FastCodeGenerator::VisitCallNew(CallNew* expr) {
Comment cmnt(masm_, "[ CallNew");
// According to ECMA-262, section 11.2.2, page 44, the function
......
......@@ -770,8 +770,23 @@ void CodeGenSelector::VisitCall(Call* expr) {
// ----------------------------------
// JavaScript example: 'foo(1, 2, 3)' // foo is global
// ----------------------------------
} else if (fun->AsProperty() != NULL) {
// ------------------------------------------------------------------
// JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
// ------------------------------------------------------------------
Property* prop = fun->AsProperty();
Literal* literal_key = prop->key()->AsLiteral();
if (literal_key != NULL && literal_key->handle()->IsSymbol()) {
ProcessExpression(prop->obj(), Expression::kValue);
CHECK_BAILOUT;
} else {
ProcessExpression(prop->obj(), Expression::kValue);
CHECK_BAILOUT;
ProcessExpression(prop->key(), Expression::kValue);
CHECK_BAILOUT;
}
} else {
BAILOUT("Call to a non-global function");
BAILOUT("Unsupported call to a function");
}
// Check all arguments to the call. (Relies on TEMP meaning STACK.)
for (int i = 0; i < args->length(); i++) {
......
......@@ -63,6 +63,9 @@ class FastCodeGenerator: public AstVisitor {
Handle<JSFunction> BuildBoilerplate(FunctionLiteral* fun);
void DeclareGlobals(Handle<FixedArray> pairs);
void EmitCallWithStub(Call* expr);
void EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info);
void SetFunctionPosition(FunctionLiteral* fun);
void SetReturnPosition(FunctionLiteral* fun);
void SetStatementPosition(Statement* stmt);
......@@ -80,6 +83,7 @@ class FastCodeGenerator: public AstVisitor {
FunctionLiteral* function_;
Handle<Script> script_;
bool is_eval_;
Label return_label_;
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
};
......
......@@ -1970,27 +1970,6 @@ void CodeGenerator::Comparison(Condition cc,
}
class CallFunctionStub: public CodeStub {
public:
CallFunctionStub(int argc, InLoopFlag in_loop)
: argc_(argc), in_loop_(in_loop) { }
void Generate(MacroAssembler* masm);
private:
int argc_;
InLoopFlag in_loop_;
#ifdef DEBUG
void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); }
#endif
Major MajorKey() { return CallFunction; }
int MinorKey() { return argc_; }
InLoopFlag InLoop() { return in_loop_; }
};
// Call the function just below TOS on the stack with the given
// arguments. The receiver is the TOS.
void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
......
......@@ -626,6 +626,27 @@ class CodeGenerator: public AstVisitor {
};
class CallFunctionStub: public CodeStub {
public:
CallFunctionStub(int argc, InLoopFlag in_loop)
: argc_(argc), in_loop_(in_loop) { }
void Generate(MacroAssembler* masm);
private:
int argc_;
InLoopFlag in_loop_;
#ifdef DEBUG
void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); }
#endif
Major MajorKey() { return CallFunction; }
int MinorKey() { return argc_; }
InLoopFlag InLoop() { return in_loop_; }
};
class ToBooleanStub: public CodeStub {
public:
ToBooleanStub() { }
......
......@@ -65,6 +65,10 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
}
}
{ Comment cmnt(masm_, "[ Declarations");
VisitDeclarations(fun->scope()->declarations());
}
{ Comment cmnt(masm_, "[ Stack check");
Label ok;
ExternalReference stack_guard_limit =
......@@ -76,10 +80,6 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
__ bind(&ok);
}
{ Comment cmnt(masm_, "[ Declarations");
VisitDeclarations(fun->scope()->declarations());
}
if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceEnter, 0);
}
......@@ -92,18 +92,27 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
// Emit a 'return undefined' in case control fell off the end of the
// body.
__ mov(eax, Factory::undefined_value());
}
{ Comment cmnt(masm_, "[ Return sequence");
SetReturnPosition(fun);
if (FLAG_trace) {
__ push(eax);
__ CallRuntime(Runtime::kTraceExit, 1);
if (return_label_.is_bound()) {
__ jmp(&return_label_);
} else {
// Common return label
__ 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((fun->scope()->num_parameters() + 1) * kPointerSize);
}
__ 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((fun->scope()->num_parameters() + 1) * kPointerSize);
}
}
......@@ -171,17 +180,24 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
__ pop(eax);
}
if (FLAG_trace) {
__ push(eax);
__ CallRuntime(Runtime::kTraceExit, 1);
}
__ RecordJSReturn();
if (return_label_.is_bound()) {
__ jmp(&return_label_);
} else {
__ bind(&return_label_);
// 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);
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);
}
}
......@@ -484,6 +500,8 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Visit(rhs);
__ pop(eax);
}
// Record position for debugger.
SetSourcePosition(expr->position());
__ mov(ecx, var->name());
__ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
......@@ -533,6 +551,7 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
// Evaluate receiver.
Visit(expr->obj());
if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() &&
!String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) {
// Do a NAMED property load.
......@@ -558,27 +577,38 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
}
void FastCodeGenerator::VisitCall(Call* expr) {
Expression* fun = expr->expression();
void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) {
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
Variable* var = fun->AsVariableProxy()->AsVariable();
ASSERT(var != NULL && !var->is_this() && var->is_global());
ASSERT(!var->is_possibly_eval());
__ push(Immediate(var->name()));
// Push global object (receiver).
__ push(CodeGenerator::GlobalObject());
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
ASSERT_EQ(Expression::kValue, args->at(i)->context());
}
// Record source position for debugger
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
NOT_IN_LOOP);
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
__ call(ic, reloc_info);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
DropAndMove(expr->context(), eax);
}
void FastCodeGenerator::EmitCallWithStub(Call* expr) {
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
}
// Record source position for debugger.
SetSourcePosition(expr->position());
CallFunctionStub stub(arg_count, NOT_IN_LOOP);
__ CallStub(&stub);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
......@@ -586,6 +616,61 @@ void FastCodeGenerator::VisitCall(Call* expr) {
}
void FastCodeGenerator::VisitCall(Call* expr) {
Expression* fun = expr->expression();
if (fun->AsProperty() != NULL) {
// Call on a property.
Property* prop = fun->AsProperty();
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsSymbol()) {
// Call on a named property: foo.x(1,2,3)
__ push(Immediate(key->handle()));
Visit(prop->obj());
// Use call IC.
EmitCallWithIC(expr, RelocInfo::CODE_TARGET);
} else {
// Call on a keyed property: foo[key](1,2,3)
// Use a keyed load IC followed by a call IC.
Visit(prop->obj());
Visit(prop->key());
// Record source position of property.
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a "test eax,..."
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
// Drop key left on the stack by IC.
__ add(Operand(esp), Immediate(kPointerSize));
// Pop receiver.
__ pop(ebx);
// Push result (function).
__ push(eax);
// Push receiver object on stack.
if (prop->is_synthetic()) {
__ push(CodeGenerator::GlobalObject());
} else {
__ push(ebx);
}
EmitCallWithStub(expr);
}
} else if (fun->AsVariableProxy()->AsVariable() != NULL) {
// Call on a global variable
Variable* var = fun->AsVariableProxy()->AsVariable();
ASSERT(var != NULL && !var->is_this() && var->is_global());
ASSERT(!var->is_possibly_eval());
__ push(Immediate(var->name()));
// Push global object (receiver).
__ push(CodeGenerator::GlobalObject());
EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT);
} else {
// Calls we cannot handle right now.
// Should bailout in the CodeGenSelector.
UNREACHABLE();
}
}
void FastCodeGenerator::VisitCallNew(CallNew* expr) {
Comment cmnt(masm_, "[ CallNew");
// According to ECMA-262, section 11.2.2, page 44, the function
......
......@@ -643,27 +643,6 @@ void DeferredReferenceSetKeyedValue::Generate() {
}
class CallFunctionStub: public CodeStub {
public:
CallFunctionStub(int argc, InLoopFlag in_loop)
: argc_(argc), in_loop_(in_loop) { }
void Generate(MacroAssembler* masm);
private:
int argc_;
InLoopFlag in_loop_;
#ifdef DEBUG
void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); }
#endif
Major MajorKey() { return CallFunction; }
int MinorKey() { return argc_; }
InLoopFlag InLoop() { return in_loop_; }
};
void CodeGenerator::CallApplyLazy(Property* apply,
Expression* receiver,
VariableProxy* arguments,
......
......@@ -633,6 +633,25 @@ class CodeGenerator: public AstVisitor {
// times by generated code to perform common tasks, often the slow
// case of a JavaScript operation. They are all subclasses of CodeStub,
// which is declared in code-stubs.h.
class CallFunctionStub: public CodeStub {
public:
CallFunctionStub(int argc, InLoopFlag in_loop)
: argc_(argc), in_loop_(in_loop) { }
void Generate(MacroAssembler* masm);
private:
int argc_;
InLoopFlag in_loop_;
#ifdef DEBUG
void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); }
#endif
Major MajorKey() { return CallFunction; }
int MinorKey() { return argc_; }
InLoopFlag InLoop() { return in_loop_; }
};
class ToBooleanStub: public CodeStub {
......
......@@ -91,27 +91,36 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
// Emit a 'return undefined' in case control fell off the end of the
// body.
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
}
{ Comment cmnt(masm_, "Return sequence");
SetReturnPosition(fun);
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((fun->scope()->num_parameters() + 1) * kPointerSize);
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((fun->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();
}
// 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
}
}
}
......@@ -179,26 +188,32 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
__ pop(rax);
}
if (FLAG_trace) {
__ push(rax);
__ CallRuntime(Runtime::kTraceExit, 1);
}
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);
__ 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();
}
// 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
}
}
......@@ -495,6 +510,8 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Visit(rhs);
__ pop(rax);
}
// Record position for debugger.
SetSourcePosition(expr->position());
__ Move(rcx, var->name());
__ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
......@@ -544,6 +561,7 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
// Evaluate receiver.
Visit(expr->obj());
if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() &&
!String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) {
// Do a NAMED property load.
......@@ -569,27 +587,20 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
}
void FastCodeGenerator::VisitCall(Call* expr) {
Expression* fun = expr->expression();
void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) {
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
Variable* var = fun->AsVariableProxy()->AsVariable();
ASSERT(var != NULL && !var->is_this() && var->is_global());
ASSERT(!var->is_possibly_eval());
__ Push(var->name());
// Push global object (receiver).
__ push(CodeGenerator::GlobalObject());
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
ASSERT_EQ(Expression::kValue, args->at(i)->context());
}
// Record source position for debugger
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
NOT_IN_LOOP);
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
__ call(ic, reloc_info);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
......@@ -597,6 +608,80 @@ void FastCodeGenerator::VisitCall(Call* expr) {
}
void FastCodeGenerator::EmitCallWithStub(Call* expr) {
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
}
// Record source position for debugger.
SetSourcePosition(expr->position());
CallFunctionStub stub(arg_count, NOT_IN_LOOP);
__ CallStub(&stub);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
DropAndMove(expr->context(), rax);
}
void FastCodeGenerator::VisitCall(Call* expr) {
Expression* fun = expr->expression();
if (fun->AsProperty() != NULL) {
// Call on a property.
Property* prop = fun->AsProperty();
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsSymbol()) {
// Call on a named property: foo.x(1,2,3)
__ Push(key->handle());
Visit(prop->obj());
// Use call IC
EmitCallWithIC(expr, RelocInfo::CODE_TARGET);
} else {
// Call on a keyed property: foo[key](1,2,3)
// Use a keyed load IC followed by a call IC.
Visit(prop->obj());
Visit(prop->key());
// Record source position of property.
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a "test eax,..."
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
// Drop key left on the stack by IC.
__ addq(rsp, Immediate(kPointerSize));
// Pop receiver.
__ pop(rbx);
// Push result (function).
__ push(rax);
// Push receiver object on stack.
if (prop->is_synthetic()) {
__ push(CodeGenerator::GlobalObject());
} else {
__ push(rbx);
}
EmitCallWithStub(expr);
}
} else if (fun->AsVariableProxy()->AsVariable() != NULL) {
// Call on a global variable
Variable* var = fun->AsVariableProxy()->AsVariable();
ASSERT(var != NULL && !var->is_this() && var->is_global());
ASSERT(!var->is_possibly_eval());
__ Push(var->name());
// Push global object (receiver).
__ push(CodeGenerator::GlobalObject());
EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT);
} else {
// Calls we cannot handle right now.
// Should bailout in the CodeGenSelector.
UNREACHABLE();
}
}
void FastCodeGenerator::VisitCallNew(CallNew* expr) {
Comment cmnt(masm_, "[ CallNew");
// According to ECMA-262, section 11.2.2, page 44, the function
......
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test of function calls.
function f(x) { return x; }
var a;
// Call on global object.
a = f(8);
assertEquals(8, a);
// Call on a named property.
var b;
b = {x:f};
a = b.x(9);
assertEquals(9, a);
// Call on a keyed property.
c = "x";
a = b[c](10);
assertEquals(10, a);
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