Revision: 3183 Author: [email protected] Date: Fri Oct 30 03:22:31 2009 Log: 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 http://code.google.com/p/v8/source/detail?r=3183 Added: /branches/bleeding_edge/test/mjsunit/compiler/function-call.js Modified: /branches/bleeding_edge/src/arm/codegen-arm.cc /branches/bleeding_edge/src/arm/codegen-arm.h /branches/bleeding_edge/src/arm/fast-codegen-arm.cc /branches/bleeding_edge/src/compiler.cc /branches/bleeding_edge/src/fast-codegen.h /branches/bleeding_edge/src/ia32/codegen-ia32.cc /branches/bleeding_edge/src/ia32/codegen-ia32.h /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc /branches/bleeding_edge/src/x64/codegen-x64.cc /branches/bleeding_edge/src/x64/codegen-x64.h /branches/bleeding_edge/src/x64/fast-codegen-x64.cc ======================================= --- /dev/null +++ /branches/bleeding_edge/test/mjsunit/compiler/function-call.js Fri Oct 30 03:22:31 2009 @@ -0,0 +1,48 @@ +// 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); + ======================================= --- /branches/bleeding_edge/src/arm/codegen-arm.cc Thu Oct 29 06:17:11 2009 +++ /branches/bleeding_edge/src/arm/codegen-arm.cc Fri Oct 30 03:22:31 2009 @@ -1066,27 +1066,6 @@ } -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) { ======================================= --- /branches/bleeding_edge/src/arm/codegen-arm.h Wed Oct 21 02:17:39 2009 +++ /branches/bleeding_edge/src/arm/codegen-arm.h Fri Oct 30 03:22:31 2009 @@ -433,6 +433,27 @@ }; +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, ======================================= --- /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Fri Oct 30 01:36:46 2009 +++ /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Fri Oct 30 03:22:31 2009 @@ -99,20 +99,26 @@ // 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); - } - - __ 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); + } + { 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); + } } } @@ -183,18 +189,21 @@ Visit(expr); __ pop(r0); } - - 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); + 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); + } } @@ -565,34 +574,95 @@ 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) { ======================================= --- /branches/bleeding_edge/src/compiler.cc Fri Oct 30 01:36:46 2009 +++ /branches/bleeding_edge/src/compiler.cc Fri Oct 30 03:22:31 2009 @@ -770,8 +770,23 @@ // ---------------------------------- // 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++) { ======================================= --- /branches/bleeding_edge/src/fast-codegen.h Fri Oct 30 01:36:46 2009 +++ /branches/bleeding_edge/src/fast-codegen.h Fri Oct 30 03:22:31 2009 @@ -63,6 +63,9 @@ 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 @@ FunctionLiteral* function_; Handle<Script> script_; bool is_eval_; + Label return_label_; DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator); }; ======================================= --- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Oct 29 06:17:11 2009 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Oct 30 03:22:31 2009 @@ -1970,27 +1970,6 @@ } -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, ======================================= --- /branches/bleeding_edge/src/ia32/codegen-ia32.h Tue Oct 27 01:20:21 2009 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.h Fri Oct 30 03:22:31 2009 @@ -626,6 +626,27 @@ }; +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() { } ======================================= --- /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Fri Oct 30 02:57:08 2009 +++ /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Fri Oct 30 03:22:31 2009 @@ -64,6 +64,10 @@ __ push(Immediate(Factory::undefined_value())); } } + + { Comment cmnt(masm_, "[ Declarations"); + VisitDeclarations(fun->scope()->declarations()); + } { Comment cmnt(masm_, "[ Stack check"); Label ok; @@ -75,10 +79,6 @@ __ CallStub(&stub); __ bind(&ok); } - - { Comment cmnt(masm_, "[ Declarations"); - VisitDeclarations(fun->scope()->declarations()); - } if (FLAG_trace) { __ CallRuntime(Runtime::kTraceEnter, 0); @@ -92,18 +92,27 @@ // 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); - } - __ 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); + 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); + } } } @@ -171,17 +180,24 @@ __ pop(eax); } - 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); + 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); + } } @@ -484,6 +500,8 @@ 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 @@ // 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,20 @@ } -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. @@ -586,6 +598,79 @@ } +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. + DropAndMove(expr->context(), eax); +} + + +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 ======================================= --- /branches/bleeding_edge/src/x64/codegen-x64.cc Thu Oct 29 06:17:11 2009 +++ /branches/bleeding_edge/src/x64/codegen-x64.cc Fri Oct 30 03:22:31 2009 @@ -643,27 +643,6 @@ } -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, ======================================= --- /branches/bleeding_edge/src/x64/codegen-x64.h Tue Oct 27 01:20:21 2009 +++ /branches/bleeding_edge/src/x64/codegen-x64.h Fri Oct 30 03:22:31 2009 @@ -633,6 +633,25 @@ // 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 { ======================================= --- /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Fri Oct 30 01:36:46 2009 +++ /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Fri Oct 30 03:22:31 2009 @@ -91,27 +91,36 @@ // 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 @@ __ pop(rax); } - 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); + 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(); - } + // 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 @@ 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 @@ // 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,32 +587,99 @@ } -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. DropAndMove(expr->context(), rax); } + + +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) { --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---
