Index: src/x64/builtins-x64.cc |
=================================================================== |
--- src/x64/builtins-x64.cc (revision 2254) |
+++ src/x64/builtins-x64.cc (working copy) |
@@ -53,7 +53,7 @@ |
// eax and ebx because these registers are used when copying the |
// arguments and the receiver. |
ASSERT(kSmiTagSize == 1); |
- __ lea(rcx, Operand(rax, rax, kTimes1, kSmiTag)); |
+ __ lea(rcx, Operand(rax, rax, times_1, kSmiTag)); |
__ push(rcx); |
} |
@@ -71,7 +71,7 @@ |
ASSERT_EQ(kSmiTagSize, 1 && kSmiTag == 0); |
ASSERT_EQ(kPointerSize, (1 << kSmiTagSize) * 4); |
__ pop(rcx); |
- __ lea(rsp, Operand(rsp, rbx, kTimes4, 1 * kPointerSize)); // 1 ~ receiver |
+ __ lea(rsp, Operand(rsp, rbx, times_4, 1 * kPointerSize)); // 1 ~ receiver |
__ push(rcx); |
} |
@@ -98,7 +98,7 @@ |
// Copy receiver and all expected arguments. |
const int offset = StandardFrameConstants::kCallerSPOffset; |
- __ lea(rax, Operand(rbp, rax, kTimesPointerSize, offset)); |
+ __ lea(rax, Operand(rbp, rax, times_pointer_size, offset)); |
__ movq(rcx, Immediate(-1)); // account for receiver |
Label copy; |
@@ -117,7 +117,7 @@ |
// Copy receiver and all actual arguments. |
const int offset = StandardFrameConstants::kCallerSPOffset; |
- __ lea(rdi, Operand(rbp, rax, kTimesPointerSize, offset)); |
+ __ lea(rdi, Operand(rbp, rax, times_pointer_size, offset)); |
__ movq(rcx, Immediate(-1)); // account for receiver |
Label copy; |
@@ -167,14 +167,134 @@ |
masm->int3(); // UNIMPLEMENTED. |
} |
+ |
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { |
- masm->int3(); // UNIMPLEMENTED. |
+ // ----------- S t a t e ------------- |
+ // -- rax: number of arguments |
+ // -- rdi: constructor function |
+ // ----------------------------------- |
+ |
+ Label non_function_call; |
+ // Check that function is not a smi. |
+ __ testl(rdi, Immediate(kSmiTagMask)); |
+ __ j(zero, &non_function_call); |
+ // Check that function is a JSFunction. |
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
+ __ j(not_equal, &non_function_call); |
+ |
+ // Jump to the function-specific construct stub. |
+ __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
+ __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset)); |
+ __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize)); |
+ __ jmp(rbx); |
+ |
+ // edi: called object |
+ // eax: number of arguments |
+ __ bind(&non_function_call); |
+ |
+ // Set expected number of arguments to zero (not changing eax). |
+ __ movq(rbx, Immediate(0)); |
+ __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); |
+ __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), |
+ RelocInfo::CODE_TARGET); |
} |
+ |
void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { |
- masm->int3(); // UNIMPLEMENTED. |
+ // Enter a construct frame. |
+ __ EnterConstructFrame(); |
William Hesse
2009/06/24 07:55:57
What is the calling convention of this function on
Mads Ager (chromium)
2009/06/24 08:18:50
rax: number of arguments
rdi: constructor function
|
+ |
+ // Store a smi-tagged arguments count on the stack. |
+ __ shl(rax, Immediate(kSmiTagSize)); |
+ __ push(rax); |
+ |
+ // Push the function to invoke on the stack. |
+ __ push(rdi); |
+ |
+ // Try to allocate the object without transitioning into C code. If any of the |
+ // preconditions is not met, the code bails out to the runtime call. |
+ Label rt_call, allocated; |
+ |
+ // TODO(x64): Implement inlined allocation. |
+ |
+ // Allocate the new receiver object using the runtime call. |
+ // rdi: function (constructor) |
+ __ bind(&rt_call); |
+ // Must restore edi (constructor) before calling runtime. |
+ __ movq(rdi, Operand(rsp, 0)); |
+ __ push(rdi); |
+ __ CallRuntime(Runtime::kNewObject, 1); |
+ __ movq(rbx, rax); // store result in ebx |
William Hesse
2009/06/24 07:55:57
rbx, not ebx
Mads Ager (chromium)
2009/06/24 08:18:50
Done.
|
+ |
+ // New object allocated. |
+ // ebx: newly allocated object |
William Hesse
2009/06/24 07:55:57
rbx
Mads Ager (chromium)
2009/06/24 08:18:50
Done.
|
+ __ bind(&allocated); |
+ // Retrieve the function from the stack. |
+ __ pop(rdi); |
+ |
+ // Retrieve smi-tagged arguments count from the stack. |
+ __ movq(rax, Operand(rsp, 0)); |
+ __ shr(rax, Immediate(kSmiTagSize)); |
+ |
+ // Push the allocated receiver to the stack. We need two copies |
+ // because we may have to return the original one and the calling |
+ // conventions dictate that the called function pops the receiver. |
+ __ push(rbx); |
+ __ push(rbx); |
+ |
+ // Setup pointer to last argument. |
+ __ lea(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset)); |
+ |
+ // Copy arguments and receiver to the expression stack. |
+ Label loop, entry; |
+ __ movq(rcx, rax); |
+ __ jmp(&entry); |
+ __ bind(&loop); |
+ __ push(Operand(rbx, rcx, times_pointer_size, 0)); |
William Hesse
2009/06/24 07:55:57
Isn't there a three-argument version of Operand(Re
Mads Ager (chromium)
2009/06/24 08:18:50
There isn't no, and I'm not sure it adds much to h
|
+ __ bind(&entry); |
+ __ decq(rcx); |
+ __ j(greater_equal, &loop); |
+ |
+ // Call the function. |
+ ParameterCount actual(rax); |
+ __ InvokeFunction(rdi, actual, CALL_FUNCTION); |
+ |
+ // Restore context from the frame. |
+ __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
+ |
+ // If the result is an object (in the ECMA sense), we should get rid |
+ // of the receiver and use the result; see ECMA-262 section 13.2.2-7 |
+ // on page 74. |
+ Label use_receiver, exit; |
+ // If the result is a smi, it is *not* an object in the ECMA sense. |
+ __ testl(rax, Immediate(kSmiTagMask)); |
+ __ j(zero, &use_receiver); |
+ |
+ // If the type of the result (stored in its map) is less than |
+ // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense. |
+ __ movq(rcx, FieldOperand(rax, HeapObject::kMapOffset)); |
+ __ CmpInstanceType(rcx, FIRST_JS_OBJECT_TYPE); |
William Hesse
2009/06/24 07:55:57
CmpInstanceType can now be written inline as a sin
Mads Ager (chromium)
2009/06/24 08:18:50
CmpInstanceType does the one instruction compare.
|
+ __ j(greater_equal, &exit); |
+ |
+ // Throw away the result of the constructor invocation and use the |
+ // on-stack receiver as the result. |
+ __ bind(&use_receiver); |
+ __ movq(rax, Operand(rsp, 0)); |
+ |
+ // Restore the arguments count and leave the construct frame. |
+ __ bind(&exit); |
+ __ movq(rbx, Operand(rsp, kPointerSize)); // get arguments count |
+ __ LeaveConstructFrame(); |
+ |
+ // Remove caller arguments from the stack and return. |
+ ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
+ __ pop(rcx); |
+ __ lea(rsp, Operand(rsp, rbx, times_4, 1 * kPointerSize)); // 1 ~ receiver |
+ __ push(rcx); |
+ __ ret(0); |
} |
+ |
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
bool is_construct) { |
// Expects five C++ function parameters. |
@@ -258,7 +378,7 @@ |
__ xor_(rcx, rcx); // Set loop variable to 0. |
__ jmp(&entry); |
__ bind(&loop); |
- __ movq(kScratchRegister, Operand(rbx, rcx, kTimesPointerSize, 0)); |
+ __ movq(kScratchRegister, Operand(rbx, rcx, times_pointer_size, 0)); |
__ push(Operand(kScratchRegister, 0)); // dereference handle |
__ addq(rcx, Immediate(1)); |
__ bind(&entry); |