Index: src/x64/codegen-x64.cc |
=================================================================== |
--- src/x64/codegen-x64.cc (revision 2281) |
+++ src/x64/codegen-x64.cc (working copy) |
@@ -504,6 +504,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_; } |
+}; |
+ |
+ |
void CodeGenerator::VisitAndSpill(Statement* statement) { |
// TODO(X64): No architecture specific code. Move to shared location. |
ASSERT(in_spilled_code()); |
@@ -2485,8 +2506,64 @@ |
} |
-void CodeGenerator::VisitCallEval(CallEval* a) { |
- UNIMPLEMENTED(); |
+void CodeGenerator::VisitCallEval(CallEval* node) { |
+ Comment cmnt(masm_, "[ CallEval"); |
+ |
+ // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve |
+ // the function we need to call and the receiver of the call. |
+ // Then we call the resolved function using the given arguments. |
+ |
+ ZoneList<Expression*>* args = node->arguments(); |
+ Expression* function = node->expression(); |
+ |
+ CodeForStatementPosition(node); |
+ |
+ // Prepare the stack for the call to the resolved function. |
+ Load(function); |
+ |
+ // Allocate a frame slot for the receiver. |
+ frame_->Push(Factory::undefined_value()); |
+ int arg_count = args->length(); |
+ for (int i = 0; i < arg_count; i++) { |
+ Load(args->at(i)); |
+ } |
+ |
+ // Prepare the stack for the call to ResolvePossiblyDirectEval. |
+ frame_->PushElementAt(arg_count + 1); |
+ if (arg_count > 0) { |
+ frame_->PushElementAt(arg_count); |
+ } else { |
+ frame_->Push(Factory::undefined_value()); |
+ } |
+ |
+ // Resolve the call. |
+ Result result = |
+ frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 2); |
+ |
+ // Touch up the stack with the right values for the function and the |
+ // receiver. Use a scratch register to avoid destroying the result. |
+ Result scratch = allocator_->Allocate(); |
+ ASSERT(scratch.is_valid()); |
+ __ movl(scratch.reg(), |
+ FieldOperand(result.reg(), FixedArray::OffsetOfElementAt(0))); |
+ frame_->SetElementAt(arg_count + 1, &scratch); |
+ |
+ // We can reuse the result register now. |
+ frame_->Spill(result.reg()); |
+ __ movl(result.reg(), |
+ FieldOperand(result.reg(), FixedArray::OffsetOfElementAt(1))); |
+ frame_->SetElementAt(arg_count, &result); |
+ |
+ // Call the function. |
+ CodeForSourcePosition(node->position()); |
+ InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; |
+ CallFunctionStub call_function(arg_count, in_loop); |
+ result = frame_->CallStub(&call_function, arg_count + 1); |
+ |
+ // Restore the context and overwrite the function on the stack with |
+ // the result. |
+ frame_->RestoreContextRegister(); |
+ frame_->SetElementAt(0, &result); |
} |
@@ -3742,10 +3819,10 @@ |
__ movq(kScratchRegister, slot->var()->name(), RelocInfo::EMBEDDED_OBJECT); |
frame_->EmitPush(kScratchRegister); |
if (typeof_state == INSIDE_TYPEOF) { |
- // value = |
- // frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
+ value = |
+ frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
} else { |
- // value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
+ value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
} |
done.Bind(&value); |
@@ -5589,55 +5666,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 CallFunctionStub::Generate(MacroAssembler* masm) { |
- Label slow; |
- |
- // Get the function to call from the stack. |
- // +2 ~ receiver, return address |
- __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize)); |
- |
- // Check that the function really is a JavaScript function. |
- __ testl(rdi, Immediate(kSmiTagMask)); |
- __ j(zero, &slow); |
- // Goto slow case if we do not have a function. |
- __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
- __ j(not_equal, &slow); |
- |
- // Fast-case: Just invoke the function. |
- ParameterCount actual(argc_); |
- __ InvokeFunction(rdi, actual, JUMP_FUNCTION); |
- |
- // Slow-case: Non-function called. |
- __ bind(&slow); |
- __ Set(rax, argc_); |
- __ Set(rbx, 0); |
- __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); |
- Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); |
- __ Jump(adaptor, RelocInfo::CODE_TARGET); |
-} |
- |
- |
// Call the function just below TOS on the stack with the given |
// arguments. The receiver is the TOS. |
void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
@@ -5691,6 +5719,7 @@ |
__ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3); |
} |
+ |
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { |
// The key is in rdx and the parameter count is in rax. |
@@ -5805,7 +5834,6 @@ |
} |
- |
void CEntryStub::GenerateCore(MacroAssembler* masm, |
Label* throw_normal_exception, |
Label* throw_out_of_memory_exception, |
@@ -5954,6 +5982,34 @@ |
} |
+void CallFunctionStub::Generate(MacroAssembler* masm) { |
+ Label slow; |
+ |
+ // Get the function to call from the stack. |
+ // +2 ~ receiver, return address |
+ __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize)); |
+ |
+ // Check that the function really is a JavaScript function. |
+ __ testl(rdi, Immediate(kSmiTagMask)); |
+ __ j(zero, &slow); |
+ // Goto slow case if we do not have a function. |
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
+ __ j(not_equal, &slow); |
+ |
+ // Fast-case: Just invoke the function. |
+ ParameterCount actual(argc_); |
+ __ InvokeFunction(rdi, actual, JUMP_FUNCTION); |
+ |
+ // Slow-case: Non-function called. |
+ __ bind(&slow); |
+ __ Set(rax, argc_); |
+ __ Set(rbx, 0); |
+ __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); |
+ Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); |
+ __ Jump(adaptor, RelocInfo::CODE_TARGET); |
+} |
+ |
+ |
void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { |
// rax: number of arguments including receiver |
// rbx: pointer to C function (C callee-saved) |
@@ -6248,7 +6304,7 @@ |
__ bind(&load_smi_lhs); |
ASSERT(kSmiTagSize == 1); |
ASSERT(kSmiTag == 0); |
- __ lea(kScratchRegister, Operand(lhs, lhs, times_1, 0); |
+ __ lea(kScratchRegister, Operand(lhs, lhs, times_1, 0)); |
__ push(kScratchRegister); |
__ fild_s(Operand(rsp, 0)); |
__ pop(kScratchRegister); |