From 07cd399b5cc408f9ae84cb623492e1671380d7bb Mon Sep 17 00:00:00 2001 From: "fschneider@chromium.org" Date: Fri, 30 Oct 2009 10:22:31 +0000 Subject: [PATCH] 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 " 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 --- src/arm/codegen-arm.cc | 21 ---- src/arm/codegen-arm.h | 21 ++++ src/arm/fast-codegen-arm.cc | 146 ++++++++++++++++++++------- src/compiler.cc | 17 +++- src/fast-codegen.h | 4 + src/ia32/codegen-ia32.cc | 21 ---- src/ia32/codegen-ia32.h | 21 ++++ src/ia32/fast-codegen-ia32.cc | 153 +++++++++++++++++++++------- src/x64/codegen-x64.cc | 21 ---- src/x64/codegen-x64.h | 19 ++++ src/x64/fast-codegen-x64.cc | 175 ++++++++++++++++++++++++--------- test/mjsunit/compiler/function-call.js | 48 +++++++++ 12 files changed, 486 insertions(+), 181 deletions(-) create mode 100644 test/mjsunit/compiler/function-call.js diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index dd88515..79f4017 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -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* args, int position) { diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h index e079950..46560b7 100644 --- a/src/arm/codegen-arm.h +++ b/src/arm/codegen-arm.h @@ -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, diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc index 747398d..3871d1b 100644 --- a/src/arm/fast-codegen-arm.cc +++ b/src/arm/fast-codegen-arm.cc @@ -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* 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 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* 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 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 diff --git a/src/compiler.cc b/src/compiler.cc index 991ad78..d8168ec 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -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++) { diff --git a/src/fast-codegen.h b/src/fast-codegen.h index f12783c..26f031e 100644 --- a/src/fast-codegen.h +++ b/src/fast-codegen.h @@ -63,6 +63,9 @@ class FastCodeGenerator: public AstVisitor { Handle BuildBoilerplate(FunctionLiteral* fun); void DeclareGlobals(Handle 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