Index: runtime/vm/stub_code_x64.cc |
=================================================================== |
--- runtime/vm/stub_code_x64.cc (revision 3306) |
+++ runtime/vm/stub_code_x64.cc (working copy) |
@@ -1,4 +1,4 @@ |
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |
@@ -166,7 +166,6 @@ |
// RAX - 8*R10 + 8 : address of last argument in argument array. |
// RBX : address of the native function to call. |
// R10 : number of arguments to the call. |
-// Uses R8. |
void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { |
const intptr_t native_args_struct_offset = 0; |
const intptr_t isolate_offset = |
@@ -275,13 +274,49 @@ |
} |
+// Called when number of invocations exceeds |
+// --optimization_invocation_threshold. |
+// RAX: target function. |
+// R10: arguments descriptor array (num_args is first Smi element). |
void StubCode::GenerateOptimizeInvokedFunctionStub(Assembler* assembler) { |
- __ Unimplemented("OptimizeInvokedFunction stub"); |
+ __ Untested("OptimizeInvokedFunction stub"); |
+ __ EnterFrame(0); |
+ __ pushq(R10); // Preserve arguments descriptor array. |
+ __ pushq(RAX); // Preserve target function. |
+ __ pushq(RAX); // Target function. |
+ __ CallRuntimeFromStub(kOptimizeInvokedFunctionRuntimeEntry); |
+ __ popq(RAX); // discard argument. |
+ __ popq(RAX); // Restore function. |
+ __ popq(R10); // Restore arguments descriptor array. |
+ __ movq(RAX, FieldAddress(RAX, Function::code_offset())); |
+ __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); |
+ __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
+ __ LeaveFrame(); |
+ __ jmp(RAX); |
+ __ int3(); |
} |
+// Called from a static call only when an invalid code has been entered |
+// (invalid because its function was optimized or deoptimized). |
+// RBX: function object. |
+// R10: arguments descriptor array (num_args is first Smi element). |
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
- __ Unimplemented("FixCallersTarget stub"); |
+ __ Untested("FixCallersTarget stub"); |
+ __ EnterFrame(0); |
+ __ pushq(R10); // Preserve arguments descriptor array. |
+ __ pushq(RBX); // Preserve target function. |
+ __ pushq(RBX); // Target function. |
+ __ CallRuntimeFromStub(kFixCallersTargetRuntimeEntry); |
+ __ popq(RAX); // discard argument. |
+ __ popq(RAX); // Restore function. |
+ __ popq(R10); // Restore arguments descriptor array. |
+ __ movq(RAX, FieldAddress(RAX, Function::code_offset())); |
+ __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); |
+ __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
+ __ LeaveFrame(); |
+ __ jmp(RAX); |
+ __ int3(); |
} |
@@ -370,7 +405,6 @@ |
// Input parameters: |
// R13: argument count, may be zero. |
-// Uses RAX, RBX, R10, R12. |
static void PushArgumentsArray(Assembler* assembler, intptr_t arg_offset) { |
const Immediate raw_null = |
Immediate(reinterpret_cast<intptr_t>(Object::null())); |
@@ -405,7 +439,6 @@ |
// Note: The receiver object is the first argument to the function being |
// called, the stub accesses the receiver from this location directly |
// when trying to resolve the call. |
-// Uses R13. |
void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) { |
const Immediate raw_null = |
Immediate(reinterpret_cast<intptr_t>(Object::null())); |
@@ -593,7 +626,18 @@ |
void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
- __ Unimplemented("Deoptimize stub"); |
+ __ Untested("Deoptimize stub"); |
+ __ EnterFrame(0); |
+ // RAX: deoptimization reason id. |
+ // Stack at this point: |
+ // TOS + 0: Saved EBP of function frame that will be deoptimized. <== EBP |
+ // TOS + 1: Deoptimization point (return address), will be patched. |
+ // TOS + 2: top-of-stack at deoptimization point (all arguments on stack). |
+ __ pushq(RAX); |
+ __ CallRuntimeFromStub(kDeoptimizeRuntimeEntry); |
+ __ popq(RAX); |
+ __ LeaveFrame(); |
+ __ ret(); |
} |
@@ -676,7 +720,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)); |
@@ -693,9 +737,9 @@ |
// Initialize all array elements to raw_null. |
// RAX: new object start as a tagged pointer. |
// R12: new object end address. |
+ __ leaq(RBX, FieldAddress(RAX, Array::data_offset())); |
// RBX: iterator which initially points to the start of the variable |
// data area to be initialized. |
- __ leaq(RBX, FieldAddress(RAX, Array::data_offset())); |
Label done; |
Label init_loop; |
__ Bind(&init_loop); |
@@ -730,8 +774,101 @@ |
} |
+// 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. |
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); // Preserve read-only function object argument. |
+ __ 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,22 +990,121 @@ |
// 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())); |
- if (false) { |
- // TODO(regis): Implement fast inline allocation of contexts. |
- __ Unimplemented("AllocateContext stub - inline allocation"); |
+ if (FLAG_inline_alloc) { |
+ const Class& context_class = Class::ZoneHandle(Object::context_class()); |
+ Label slow_case; |
+ Heap* heap = Isolate::Current()->heap(); |
+ // First compute the rounded instance size. |
+ // R10: number of context variables. |
+ intptr_t fixed_size = (sizeof(RawContext) + kObjectAlignment - 1); |
+ __ leaq(R13, Address(R10, TIMES_8, fixed_size)); |
+ __ andq(R13, Immediate(-kObjectAlignment)); |
+ |
+ // Now allocate the object. |
+ // R10: number of context variables. |
+ __ movq(RAX, Immediate(heap->TopAddress())); |
+ __ movq(RAX, Address(RAX, 0)); |
+ __ addq(R13, RAX); |
+ // Check if the allocation fits into the remaining space. |
+ // RAX: potential new object. |
+ // R13: potential next object start. |
+ // R10: number of context variables. |
+ __ movq(RDI, Immediate(heap->EndAddress())); |
+ __ cmpq(R13, Address(RDI, 0)); |
+ if (FLAG_use_slow_path) { |
+ __ jmp(&slow_case); |
+ } else { |
+ __ j(ABOVE_EQUAL, &slow_case); |
+ } |
+ |
+ // Successfully allocated the object, now update top to point to |
+ // next object start and initialize the object. |
+ // RAX: new object. |
+ // R13: next object start. |
+ // R10: number of context variables. |
+ __ movq(RDI, Immediate(heap->TopAddress())); |
+ __ movq(Address(RDI, 0), R13); |
+ __ addq(RAX, Immediate(kHeapObjectTag)); |
+ |
+ // Initialize the class field in the context object. |
+ // RAX: new object. |
+ // R10: number of context variables. |
+ __ LoadObject(R13, context_class); // Load up class field of context. |
+ __ StoreIntoObject(RAX, |
+ FieldAddress(RAX, Context::class_offset()), |
+ R13); |
+ // Calculate the size tag. |
+ // RAX: new object. |
+ // R10: number of context variables. |
+ { |
+ Label size_tag_overflow, done; |
+ __ leaq(R13, Address(R10, TIMES_8, fixed_size)); |
+ __ andq(R13, Immediate(-kObjectAlignment)); |
+ __ cmpq(R13, Immediate(RawObject::SizeTag::kMaxSizeTag)); |
+ __ j(ABOVE, &size_tag_overflow, Assembler::kNearJump); |
+ __ shlq(R13, Immediate(RawObject::kSizeTagBit - kObjectAlignmentLog2)); |
+ __ movq(FieldAddress(RAX, Context::tags_offset()), R13); // Tags. |
+ __ jmp(&done); |
+ |
+ __ Bind(&size_tag_overflow); |
+ // Set overflow size tag value. |
+ __ movq(FieldAddress(RAX, Context::tags_offset()), Immediate(0)); |
+ __ Bind(&done); |
+ } |
+ |
+ // Setup up number of context variables field. |
+ // RAX: new object. |
+ // R10: number of context variables as integer value (not object). |
+ __ movq(FieldAddress(RAX, Context::num_variables_offset()), R10); |
+ |
+ // Setup isolate field. |
+ // Load Isolate pointer from Context structure into R13. |
+ // RAX: new object. |
+ // R10: number of context variables. |
+ __ movq(R13, FieldAddress(CTX, Context::isolate_offset())); |
+ // R13: Isolate, not an object. |
+ __ movq(FieldAddress(RAX, Context::isolate_offset()), R13); |
+ |
+ const Immediate raw_null = |
+ Immediate(reinterpret_cast<intptr_t>(Object::null())); |
+ // Setup the parent field. |
+ // RAX: new object. |
+ // R10: number of context variables. |
+ __ movq(FieldAddress(RAX, Context::parent_offset()), raw_null); |
+ |
+ // Initialize the context variables. |
+ // RAX: new object. |
+ // R10: number of context variables. |
+ { |
+ Label loop, entry; |
+ __ leaq(R13, FieldAddress(RAX, Context::variable_offset(0))); |
+ |
+ __ jmp(&entry, Assembler::kNearJump); |
+ __ Bind(&loop); |
+ __ decq(R10); |
+ __ movq(Address(R13, R10, TIMES_8, 0), raw_null); |
+ __ Bind(&entry); |
+ __ cmpq(R10, Immediate(0)); |
+ __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
+ } |
+ |
+ // Done allocating and initializing the context. |
+ // RAX: new object. |
+ __ ret(); |
+ |
+ __ Bind(&slow_case); |
} |
- // Create the stub frame. |
+ // Create a 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,14 +1115,11 @@ |
} |
- |
- |
// Called for inline allocation of objects. |
// Input parameters: |
// RSP + 16 : type arguments object (only if class is parameterized). |
// RSP + 8 : type arguments of instantiator (only if class is parameterized). |
// RSP : points to return address. |
-// Uses RAX, RBX, RCX, RDX, RDI as temporary registers. |
void StubCode::GenerateAllocationStubForClass(Assembler* assembler, |
const Class& cls) { |
const intptr_t kObjectTypeArgumentsOffset = 2 * kWordSize; |
@@ -1083,7 +1316,6 @@ |
// RSP + 16 (or RSP + 8): receiver (only if implicit instance closure). |
// RSP + 8 : type arguments object (only if signature class is parameterized). |
// RSP : points to return address. |
-// Uses RAX, RCX as temporary registers. |
void StubCode::GenerateAllocationStubForClosure(Assembler* assembler, |
const Function& func) { |
const Immediate raw_null = |
@@ -1097,9 +1329,110 @@ |
const bool has_type_arguments = cls.HasTypeArguments(); |
const intptr_t kTypeArgumentsOffset = 1 * kWordSize; |
const intptr_t kReceiverOffset = (has_type_arguments ? 2 : 1) * kWordSize; |
- if (false) { |
- // TODO(regis): Implement inline context allocation. |
- __ Unimplemented("AllocateClosure stub - inline allocation"); |
+ const intptr_t closure_size = Closure::InstanceSize(); |
+ const intptr_t context_size = Context::InstanceSize(1); // Captured receiver. |
+ if (FLAG_inline_alloc && |
+ PageSpace::IsPageAllocatableSize(closure_size + context_size)) { |
+ Label slow_case; |
+ Heap* heap = Isolate::Current()->heap(); |
+ __ movq(RAX, Immediate(heap->TopAddress())); |
+ __ movq(RAX, Address(RAX, 0)); |
+ __ leaq(R13, Address(RAX, closure_size)); |
+ if (is_implicit_instance_closure) { |
+ __ movq(RBX, R13); // RBX: new context address. |
+ __ addq(R13, Immediate(context_size)); |
+ } |
+ // Check if the allocation fits into the remaining space. |
+ // RAX: potential new closure object. |
+ // RBX: potential new context object (only if is_implicit_closure). |
+ // R13: potential next object start. |
+ __ movq(RDI, Immediate(heap->EndAddress())); |
+ __ cmpq(R13, Address(RDI, 0)); |
+ if (FLAG_use_slow_path) { |
+ __ jmp(&slow_case); |
+ } else { |
+ __ j(ABOVE_EQUAL, &slow_case); |
+ } |
+ |
+ // Successfully allocated the object, now update top to point to |
+ // next object start and initialize the object. |
+ __ movq(RDI, Immediate(heap->TopAddress())); |
+ __ movq(Address(RDI, 0), R13); |
+ |
+ // Initialize the class field in the object. |
+ // RAX: new closure object. |
+ // RBX: new context object (only if is_implicit_closure). |
+ __ LoadObject(R10, cls); // Load signature class of closure. |
+ __ movq(Address(RAX, Closure::class_offset()), R10); |
+ // Set the tags. |
+ __ movq(Address(RAX, Closure::tags_offset()), |
+ Immediate(RawObject::SizeTag::encode(closure_size))); |
+ |
+ // Initialize the function field in the object. |
+ // RAX: new closure object. |
+ // RBX: new context object (only if is_implicit_closure). |
+ // R13: next object start. |
+ __ LoadObject(R10, func); // Load function of closure to be allocated. |
+ __ movq(Address(RAX, Closure::function_offset()), R10); |
+ |
+ // Setup the context for this closure. |
+ if (is_implicit_static_closure) { |
+ ObjectStore* object_store = Isolate::Current()->object_store(); |
+ ASSERT(object_store != NULL); |
+ const Context& empty_context = |
+ Context::ZoneHandle(object_store->empty_context()); |
+ __ LoadObject(R10, empty_context); |
+ __ movq(Address(RAX, Closure::context_offset()), R10); |
+ } else if (is_implicit_instance_closure) { |
+ // Initialize the new context capturing the receiver. |
+ |
+ // Set the class field to the Context class. |
+ __ LoadObject(R13, Class::ZoneHandle(Object::context_class())); |
+ __ movq(Address(RBX, Context::class_offset()), R13); |
+ // Set the tags. |
+ __ movq(Address(RBX, Context::tags_offset()), |
+ Immediate(RawObject::SizeTag::encode(context_size))); |
+ |
+ // Set number of variables field to 1 (for captured receiver). |
+ __ movq(Address(RBX, Context::num_variables_offset()), Immediate(1)); |
+ |
+ // Set isolate field to isolate of current context. |
+ __ movq(R10, FieldAddress(CTX, Context::isolate_offset())); |
+ __ movq(Address(RBX, Context::isolate_offset()), R10); |
+ |
+ // Set the parent field to null. |
+ __ movq(Address(RBX, Context::parent_offset()), raw_null); |
+ |
+ // Initialize the context variable to the receiver. |
+ __ movq(R10, Address(RSP, kReceiverOffset)); |
+ __ movq(Address(RBX, Context::variable_offset(0)), R10); |
+ |
+ // Set the newly allocated context in the newly allocated closure. |
+ __ addq(RBX, Immediate(kHeapObjectTag)); |
+ __ movq(Address(RAX, Closure::context_offset()), RBX); |
+ } else { |
+ __ movq(Address(RAX, Closure::context_offset()), CTX); |
+ } |
+ |
+ // Set the type arguments field in the newly allocated closure. |
+ if (has_type_arguments) { |
+ ASSERT(!is_implicit_static_closure); |
+ // Use the passed-in type arguments. |
+ __ movq(R10, Address(RSP, kTypeArgumentsOffset)); |
+ __ movq(Address(RAX, Closure::type_arguments_offset()), R10); |
+ } else { |
+ // Set to null. |
+ __ movq(Address(RAX, Closure::type_arguments_offset()), raw_null); |
+ } |
+ |
+ __ movq(Address(RAX, Closure::smrck_offset()), raw_null); |
+ |
+ // Done allocating and initializing the instance. |
+ // RAX: new object. |
+ __ addq(RAX, Immediate(kHeapObjectTag)); |
+ __ ret(); |
+ |
+ __ Bind(&slow_case); |
} |
if (has_type_arguments) { |
__ movq(RCX, Address(RSP, kTypeArgumentsOffset)); |
@@ -1141,11 +1474,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())); |
+ __ SmiUntag(R13); |
+ __ movq(RAX, Address(RBP, R13, TIMES_8, 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. |
+ __ 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. |
@@ -1307,13 +1697,42 @@ |
} |
+// RBX: Function object. |
+// R10: Arguments array. |
+// TOS(0): return address (Dart code). |
void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { |
- __ Unimplemented("BreakpointStatic stub"); |
+ __ Untested("BreakpointStatic stub"); |
+ __ EnterFrame(0); |
+ __ pushq(R10); |
+ __ pushq(RBX); |
+ __ CallRuntimeFromStub(kBreakpointStaticHandlerRuntimeEntry); |
+ __ popq(RBX); |
+ __ popq(R10); |
+ __ LeaveFrame(); |
+ |
+ // Now call the static function. The breakpoint handler function |
+ // ensures that the call target is compiled. |
+ __ movq(RAX, FieldAddress(RBX, Function::code_offset())); |
+ __ movq(RBX, FieldAddress(RAX, Code::instructions_offset())); |
+ __ addq(RBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
+ __ jmp(RBX); |
} |
+// RBX: Inline cache data array. |
+// R10: Arguments array. |
+// TOS(0): return address (Dart code). |
void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) { |
- __ Unimplemented("BreakpointDynamic stub"); |
+ __ Untested("BreakpointDynamic stub"); |
+ __ EnterFrame(0); |
+ __ pushq(RBX); |
+ __ pushq(R10); |
+ __ CallRuntimeFromStub(kBreakpointDynamicHandlerRuntimeEntry); |
+ __ popq(R10); |
+ __ popq(RBX); |
+ __ LeaveFrame(); |
+ // Now call the dynamic function. |
+ __ jmp(&StubCode::OneArgCheckInlineCacheLabel()); |
} |
} // namespace dart |