Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(386)

Unified Diff: src/x64/builtins-x64.cc

Issue 147205: X64 Implementation: Implement Generate_Function(Call,Apply) (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects-inl.h ('k') | src/x64/codegen-x64.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/x64/builtins-x64.cc
===================================================================
--- src/x64/builtins-x64.cc (revision 2286)
+++ src/x64/builtins-x64.cc (working copy)
@@ -168,14 +168,292 @@
}
-void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xBEFA)); // Debugging aid.
+void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
+ // Stack Layout:
+ // rsp: return address
+ // +1: Argument n
+ // +2: Argument n-1
+ // ...
+ // +n: Argument 1 = receiver
+ // +n+1: Argument 0 = function to call
+ //
+ // rax contains the number of arguments, n, not counting the function.
+ //
+ // 1. Make sure we have at least one argument.
+ { Label done;
+ __ testq(rax, rax);
+ __ j(not_zero, &done);
+ __ pop(rbx);
+ __ Push(Factory::undefined_value());
+ __ push(rbx);
+ __ incq(rax);
+ __ bind(&done);
+ }
+
+ // 2. Get the function to call from the stack.
+ { Label done, non_function, function;
+ // The function to call is at position n+1 on the stack.
+ __ movq(rdi, Operand(rsp, rax, times_pointer_size, +1 * kPointerSize));
+ __ testl(rdi, Immediate(kSmiTagMask));
+ __ j(zero, &non_function);
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
+ __ j(equal, &function);
+
+ // Non-function called: Clear the function to force exception.
+ __ bind(&non_function);
+ __ xor_(rdi, rdi);
+ __ jmp(&done);
+
+ // Function called: Change context eagerly to get the right global object.
+ __ bind(&function);
+ __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+
+ __ bind(&done);
+ }
+
+ // 3. Make sure first argument is an object; convert if necessary.
+ { Label call_to_object, use_global_receiver, patch_receiver, done;
+ __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
+
+ __ testl(rbx, Immediate(kSmiTagMask));
+ __ j(zero, &call_to_object);
+
+ __ Cmp(rbx, Factory::null_value());
+ __ j(equal, &use_global_receiver);
+ __ Cmp(rbx, Factory::undefined_value());
+ __ j(equal, &use_global_receiver);
+
+ __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx);
+ __ j(below, &call_to_object);
+ __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE);
+ __ j(below_equal, &done);
+
+ __ bind(&call_to_object);
+ __ EnterInternalFrame(); // preserves rax, rbx, rdi
+
+ // Store the arguments count on the stack (smi tagged).
+ ASSERT(kSmiTag == 0);
+ __ shl(rax, Immediate(kSmiTagSize));
+ __ push(rax);
+
+ __ push(rdi); // save edi across the call
+ __ push(rbx);
+ __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+ __ movq(rbx, rax);
+ __ pop(rdi); // restore edi after the call
+
+ // Get the arguments count and untag it.
+ __ pop(rax);
+ __ shr(rax, Immediate(kSmiTagSize));
+
+ __ LeaveInternalFrame();
+ __ jmp(&patch_receiver);
+
+ // Use the global receiver object from the called function as the receiver.
+ __ bind(&use_global_receiver);
+ const int kGlobalIndex =
+ Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+ __ movq(rbx, FieldOperand(rsi, kGlobalIndex));
+ __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
+
+ __ bind(&patch_receiver);
+ __ movq(Operand(rsp, rax, times_pointer_size, 0), rbx);
+
+ __ bind(&done);
+ }
+
+ // 4. Shift stuff one slot down the stack.
+ { Label loop;
+ __ lea(rcx, Operand(rax, +1)); // +1 ~ copy receiver too
+ __ bind(&loop);
+ __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0));
+ __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx);
+ __ decq(rcx);
+ __ j(not_zero, &loop);
+ }
+
+ // 5. Remove TOS (copy of last arguments), but keep return address.
+ __ pop(rbx);
+ __ pop(rcx);
+ __ push(rbx);
+ __ decq(rax);
+
+ // 6. Check that function really was a function and get the code to
+ // call from the function and check that the number of expected
+ // arguments matches what we're providing.
+ { Label invoke, trampoline;
+ __ testq(rdi, rdi);
+ __ j(not_zero, &invoke);
+ __ xor_(rbx, rbx);
+ __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
+ __ bind(&trampoline);
+ __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+ RelocInfo::CODE_TARGET);
+
+ __ bind(&invoke);
+ __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+ __ movsxlq(rbx,
+ FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
+ __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
+ __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
+ __ cmpq(rax, rbx);
+ __ j(not_equal, &trampoline);
+ }
+
+ // 7. Jump (tail-call) to the code in register edx without checking arguments.
+ ParameterCount expected(0);
+ __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION);
}
-void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xBEFC)); // Debugging aid.
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+ // Stack at entry:
+ // rsp: return address
+ // rsp+8: arguments
+ // rsp+16: receiver ("this")
+ // rsp+24: function
+ __ EnterInternalFrame();
+ // Stack frame:
+ // rbp: Old base pointer
+ // rbp[1]: return address
+ // rbp[2]: function arguments
+ // rbp[3]: receiver
+ // rbp[4]: function
+ static const int kArgumentsOffset = 2 * kPointerSize;
+ static const int kReceiverOffset = 3 * kPointerSize;
+ static const int kFunctionOffset = 4 * kPointerSize;
+ __ push(Operand(rbp, kFunctionOffset));
+ __ push(Operand(rbp, kArgumentsOffset));
+ __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+
+ if (FLAG_check_stack) {
+ // We need to catch preemptions right here, otherwise an unlucky preemption
+ // could show up as a failed apply.
+ Label retry_preemption;
+ Label no_preemption;
+ __ bind(&retry_preemption);
+ ExternalReference stack_guard_limit =
+ ExternalReference::address_of_stack_guard_limit();
+ __ movq(kScratchRegister, stack_guard_limit);
+ __ movq(rcx, rsp);
+ __ subq(rcx, Operand(kScratchRegister, 0));
+ // rcx contains the difference between the stack limit and the stack top.
+ // We use it below to check that there is enough room for the arguments.
+ __ j(above, &no_preemption);
+
+ // Preemption!
+ // Because runtime functions always remove the receiver from the stack, we
+ // have to fake one to avoid underflowing the stack.
+ __ push(rax);
+ __ push(Immediate(Smi::FromInt(0)));
+
+ // Do call to runtime routine.
+ __ CallRuntime(Runtime::kStackGuard, 1);
+ __ pop(rax);
+ __ jmp(&retry_preemption);
+
+ __ bind(&no_preemption);
+
+ Label okay;
+ // Make rdx the space we need for the array when it is unrolled onto the
+ // stack.
+ __ movq(rdx, rax);
+ __ shl(rdx, Immediate(kPointerSizeLog2 - kSmiTagSize));
+ __ cmpq(rcx, rdx);
+ __ j(greater, &okay);
+
+ // Too bad: Out of stack space.
+ __ push(Operand(rbp, kFunctionOffset));
+ __ push(rax);
+ __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
+ __ bind(&okay);
+ }
+
+ // Push current index and limit.
+ const int kLimitOffset =
+ StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
+ const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
+ __ push(rax); // limit
+ __ push(Immediate(0)); // index
+
+ // Change context eagerly to get the right global object if
+ // necessary.
+ __ movq(rdi, Operand(rbp, kFunctionOffset));
+ __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+
+ // Compute the receiver.
+ Label call_to_object, use_global_receiver, push_receiver;
+ __ movq(rbx, Operand(rbp, kReceiverOffset));
+ __ testl(rbx, Immediate(kSmiTagMask));
+ __ j(zero, &call_to_object);
+ __ Cmp(rbx, Factory::null_value());
+ __ j(equal, &use_global_receiver);
+ __ Cmp(rbx, Factory::undefined_value());
+ __ j(equal, &use_global_receiver);
+
+ // If given receiver is already a JavaScript object then there's no
+ // reason for converting it.
+ __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx);
+ __ j(less, &call_to_object);
+ __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE);
+ __ j(less_equal, &push_receiver);
+
+ // Convert the receiver to an object.
+ __ bind(&call_to_object);
+ __ push(rbx);
+ __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+ __ movq(rbx, rax);
+ __ jmp(&push_receiver);
+
+ // Use the current global receiver object as the receiver.
+ __ bind(&use_global_receiver);
+ const int kGlobalOffset =
+ Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+ __ movq(rbx, FieldOperand(rsi, kGlobalOffset));
+ __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
+
+ // Push the receiver.
+ __ bind(&push_receiver);
+ __ push(rbx);
+
+ // Copy all arguments from the array to the stack.
+ Label entry, loop;
+ __ movq(rax, Operand(rbp, kIndexOffset));
+ __ jmp(&entry);
+ __ bind(&loop);
+ __ movq(rcx, Operand(rbp, kArgumentsOffset)); // load arguments
+ __ push(rcx);
+ __ push(rax);
+
+ // Use inline caching to speed up access to arguments.
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ __ Call(ic, RelocInfo::CODE_TARGET);
+ // It is important that we do not have a test instruction after the
+ // call. A test instruction after the call is used to indicate that
+ // we have generated an inline version of the keyed load. In this
+ // case, we know that we are not generating a test instruction next.
+
+ // Remove IC arguments from the stack and push the nth argument.
+ __ addq(rsp, Immediate(2 * kPointerSize));
+ __ push(rax);
+
+ // Update the index on the stack and in register rax.
+ __ movq(rax, Operand(rbp, kIndexOffset));
+ __ addq(rax, Immediate(Smi::FromInt(1)));
+ __ movq(Operand(rbp, kIndexOffset), rax);
+
+ __ bind(&entry);
+ __ cmpq(rax, Operand(rbp, kLimitOffset));
+ __ j(not_equal, &loop);
+
+ // Invoke the function.
+ ParameterCount actual(rax);
+ __ shr(rax, Immediate(kSmiTagSize));
+ __ movq(rdi, Operand(rbp, kFunctionOffset));
+ __ InvokeFunction(rdi, actual, CALL_FUNCTION);
+
+ __ LeaveInternalFrame();
+ __ ret(3 * kPointerSize); // remove function, receiver, and arguments
}
« no previous file with comments | « src/objects-inl.h ('k') | src/x64/codegen-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698