Index: runtime/vm/stub_code_x64.cc |
=================================================================== |
--- runtime/vm/stub_code_x64.cc (revision 3170) |
+++ runtime/vm/stub_code_x64.cc (working copy) |
@@ -676,7 +676,7 @@ |
// R10: Array length as Smi. |
{ |
Label size_tag_overflow, done; |
- __ leaq(RBX, Address(R10, TIMES_2, fixed_size)); // R10 is Smi. |
+ __ leaq(RBX, Address(R10, TIMES_4, fixed_size)); // R10 is Smi. |
ASSERT(kSmiTagShift == 1); |
__ andq(RBX, Immediate(-kObjectAlignment)); |
__ cmpq(RBX, Immediate(RawObject::SizeTag::kMaxSizeTag)); |
@@ -730,8 +730,102 @@ |
} |
+// Input parameters: |
+// R10: Arguments descriptor array (num_args is first Smi element, closure |
+// object is not included in num_args). |
+// Note: The closure object is pushed before the first argument to the function |
+// being called, the stub accesses the closure from this location directly |
+// when setting up the context and resolving the entry point. |
+// Uses R13. |
void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) { |
- __ Unimplemented("CallClosureFunction stub"); |
+ const Immediate raw_null = |
+ Immediate(reinterpret_cast<intptr_t>(Object::null())); |
+ |
+ // Total number of args is the first Smi in args descriptor array (R10). |
+ __ movq(RAX, FieldAddress(R10, Array::data_offset())); // Load num_args. |
+ // Load closure object in R13. |
+ __ movq(R13, Address(RSP, RAX, TIMES_4, kWordSize)); // RAX is a Smi. |
+ |
+ // Verify that R13 is a closure by checking its class. |
+ Label not_closure; |
+ __ cmpq(R13, raw_null); |
+ // Not a closure, but null object. |
+ __ j(EQUAL, ¬_closure, Assembler::kNearJump); |
+ __ testq(R13, Immediate(kSmiTagMask)); |
+ __ j(ZERO, ¬_closure, Assembler::kNearJump); // Not a closure, but a smi. |
+ // Verify that the class of the object is a closure class by checking that |
+ // class.signature_function() is not null. |
+ __ movq(RAX, FieldAddress(R13, Object::class_offset())); |
+ __ movq(RAX, FieldAddress(RAX, Class::signature_function_offset())); |
+ __ cmpq(RAX, raw_null); |
+ // Actual class is not a closure class. |
+ __ j(EQUAL, ¬_closure, Assembler::kNearJump); |
+ |
+ // RAX is just the signature function. Load the actual closure function. |
+ __ movq(RBX, FieldAddress(R13, Closure::function_offset())); |
+ |
+ // Load closure context in CTX; note that CTX has already been preserved. |
+ __ movq(CTX, FieldAddress(R13, Closure::context_offset())); |
+ |
+ // Load closure function code in RAX. |
+ __ movq(RAX, FieldAddress(RBX, Function::code_offset())); |
+ __ cmpq(RAX, raw_null); |
+ Label function_compiled; |
+ __ j(NOT_EQUAL, &function_compiled, Assembler::kNearJump); |
+ |
+ // Create a stub frame as we are pushing some objects on the stack before |
+ // calling into the runtime. |
+ __ EnterFrame(0); |
+ |
+ __ pushq(R10); // Preserve arguments descriptor array. |
+ __ pushq(RBX); |
+ __ CallRuntimeFromStub(kCompileFunctionRuntimeEntry); |
+ __ popq(RBX); // Restore read-only function object argument in RBX. |
+ __ popq(R10); // Restore arguments descriptor array. |
+ // Restore RAX. |
+ __ movq(RAX, FieldAddress(RBX, Function::code_offset())); |
+ |
+ // Remove the stub frame as we are about to jump to the closure function. |
+ __ LeaveFrame(); |
+ |
+ __ Bind(&function_compiled); |
+ // RAX: Code. |
+ // RBX: Function. |
+ // R10: Arguments descriptor array (num_args is first Smi element). |
+ |
+ __ movq(RBX, FieldAddress(RAX, Code::instructions_offset())); |
+ __ addq(RBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
+ __ jmp(RBX); |
+ |
+ __ Bind(¬_closure); |
+ // Call runtime to report that a closure call was attempted on a non-closure |
+ // object, passing the non-closure object and its arguments array. |
+ // R13: non-closure object. |
+ // R10: arguments descriptor array (num_args is first Smi element, closure |
+ // object is not included in num_args). |
+ |
+ // Create a stub frame as we are pushing some objects on the stack before |
+ // calling into the runtime. |
+ __ EnterFrame(0); |
+ |
+ __ pushq(raw_null); // Setup space on stack for result from error reporting. |
+ __ pushq(R13); // Non-closure object. |
+ // Total number of args is the first Smi in args descriptor array (R10). |
+ __ movq(R13, FieldAddress(R10, Array::data_offset())); // Load num_args. |
+ __ SmiUntag(R13); |
+ // See stack layout below explaining "wordSize * 4" offset. |
+ PushArgumentsArray(assembler, (kWordSize * 4)); |
+ |
+ // Stack: |
+ // TOS + 0: Argument array. |
+ // TOS + 1: Non-closure object. |
+ // TOS + 2: Place for result from reporting the error. |
+ // TOS + 3: Saved RBP of previous frame. <== RBP |
+ // TOS + 4: Dart code return address |
+ // TOS + 5: Last argument of caller. |
+ // .... |
+ __ CallRuntimeFromStub(kReportObjectNotClosureRuntimeEntry); |
+ __ Stop("runtime call throws an exception"); |
} |
@@ -853,10 +947,9 @@ |
// Called for inline allocation of contexts. |
// Input: |
-// RDX: number of context variables. |
+// R10: number of context variables. |
// Output: |
// RAX: new allocated RawContext object. |
-// RBX and RDX are destroyed. |
void StubCode::GenerateAllocateContextStub(Assembler* assembler) { |
const Immediate raw_null = |
Immediate(reinterpret_cast<intptr_t>(Object::null())); |
@@ -867,8 +960,8 @@ |
// Create the stub frame. |
__ EnterFrame(0); |
__ pushq(raw_null); // Setup space on stack for the return value. |
- __ SmiTag(RDX); |
- __ pushq(RDX); // Push number of context variables. |
+ __ SmiTag(R10); |
+ __ pushq(R10); // Push number of context variables. |
__ CallRuntimeFromStub(kAllocateContextRuntimeEntry); // Allocate context. |
__ popq(RAX); // Pop number of context variables argument. |
__ popq(RAX); // Pop the new context object. |
@@ -879,8 +972,6 @@ |
} |
- |
- |
// Called for inline allocation of objects. |
// Input parameters: |
// RSP + 16 : type arguments object (only if class is parameterized). |
@@ -1141,11 +1232,68 @@ |
} |
+// Called for invoking noSuchMethod function from the entry code of a dart |
+// function after an error in passed named arguments is detected. |
+// Input parameters: |
+// RBP : points to previous frame pointer. |
+// RBP + 8 : points to return address. |
+// RBP + 16 : address of last argument (arg n-1). |
+// RBP + 16 + 8*(n-1) : address of first argument (arg 0). |
+// RBX : ic-data array. |
+// R10 : arguments descriptor array. |
void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { |
- __ Unimplemented("CallNoSuchMethodFunction stub"); |
+ // The target function was not found, so invoke method |
+ // "void noSuchMethod(function_name, Array arguments)". |
+ // TODO(regis): For now, we simply pass the actual arguments, both positional |
+ // and named, as the argument array. This is not correct if out-of-order |
+ // named arguments were passed. |
+ // The signature of the "noSuchMethod" method has to change from |
+ // noSuchMethod(String name, Array arguments) to something like |
+ // noSuchMethod(InvocationMirror call). |
+ // Also, the class NoSuchMethodException has to be modified accordingly. |
+ // Total number of args is the first Smi in args descriptor array (R10). |
+ const Immediate raw_null = |
+ Immediate(reinterpret_cast<intptr_t>(Object::null())); |
+ __ movq(R13, FieldAddress(R10, Array::data_offset())); // R13 is Smi. |
+ __ movq(RAX, Address(RBP, R13, TIMES_4, kWordSize)); // Get receiver. |
+ |
+ __ EnterFrame(0); |
+ __ pushq(raw_null); // Setup space on stack for result from noSuchMethod. |
+ __ pushq(RAX); // Receiver. |
+ __ pushq(RBX); // IC data array. |
+ __ pushq(R10); // Arguments descriptor array. |
+ __ SmiUntag(R13); |
+ __ subq(R13, Immediate(1)); // Arguments array length, minus the receiver. |
+ // See stack layout below explaining "wordSize * 8" offset. |
+ PushArgumentsArray(assembler, (kWordSize * 8)); |
+ |
+ // Stack: |
+ // TOS + 0: Argument array. |
+ // TOS + 1: Arguments descriptor array. |
+ // TOS + 2: Ic-data array. |
+ // TOS + 3: Receiver. |
+ // TOS + 4: Place for result from noSuchMethod. |
+ // TOS + 5: Saved RBP of previous frame. <== RBP |
+ // TOS + 6: Dart callee (or stub) code return address |
+ // TOS + 7: Saved RBP of dart caller frame. |
+ // TOS + 8: Dart caller code return address |
+ // TOS + 9: Last argument of caller. |
+ // .... |
+ __ CallRuntimeFromStub(kInvokeNoSuchMethodFunctionRuntimeEntry); |
+ // Remove arguments. |
+ __ popq(RAX); |
+ __ popq(RAX); |
+ __ popq(RAX); |
+ __ popq(RAX); |
+ __ popq(RAX); // Get result into RAX. |
+ |
+ // Remove the stub frame as we are about to return. |
+ __ LeaveFrame(); |
+ __ ret(); |
} |
+ |
// Generate inline cache check for 'num_args'. |
// RBX: Inline cache data array. |
// R10: Arguments array. |