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

Unified Diff: runtime/vm/stub_code_x64.cc

Issue 8984003: Port code generator to x64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years 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 | « runtime/vm/stub_code_ia32.cc ('k') | runtime/vm/vm_sources.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/stub_code_x64.cc
===================================================================
--- runtime/vm/stub_code_x64.cc (revision 2556)
+++ runtime/vm/stub_code_x64.cc (working copy)
@@ -5,13 +5,24 @@
#include "vm/globals.h"
#if defined(TARGET_ARCH_X64)
-#include "vm/native_entry.h"
+#include "vm/code_generator.h"
+#include "vm/compiler.h"
+#include "vm/ic_data.h"
+#include "vm/object_store.h"
+#include "vm/pages.h"
+#include "vm/resolver.h"
+#include "vm/scavenger.h"
#include "vm/stub_code.h"
+
#define __ assembler->
namespace dart {
+DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects.");
+DEFINE_FLAG(bool, use_slow_path, false,
+ "Set to true for debugging & verifying the slow paths.");
+
// Input parameters:
// RSP : points to return address.
// RSP + 8 : address of last argument in argument array.
@@ -19,7 +30,9 @@
// RSP + 8*R10 + 8 : address of return value.
// RBX : address of the runtime function to call.
// R10 : number of arguments to the call.
+// Must preserve callee saved registers R12 and R13.
static void GenerateCallRuntimeStub(Assembler* assembler) {
+ ASSERT((R12 != CTX) && (R13 != CTX));
const intptr_t isolate_offset = NativeArguments::isolate_offset();
const intptr_t argc_offset = NativeArguments::argc_offset();
const intptr_t argv_offset = NativeArguments::argv_offset();
@@ -81,6 +94,7 @@
// RSP + 8*R10 + 8 : address of return value.
// RBX : address of the runtime function to call.
// R10 : number of arguments to the call.
+// Must preserve callee saved registers R12 and R13.
void StubCode::GenerateDartCallToRuntimeStub(Assembler* assembler) {
GenerateCallRuntimeStub(assembler);
}
@@ -93,6 +107,7 @@
// RSP + 8*R10 + 8 : address of return value.
// RBX : address of the runtime function to call.
// R10 : number of arguments to the call.
+// Must preserve callee saved registers R12 and R13.
void StubCode::GenerateStubCallToRuntimeStub(Assembler* assembler) {
GenerateCallRuntimeStub(assembler);
}
@@ -105,6 +120,7 @@
// 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 =
@@ -167,8 +183,49 @@
}
+// Input parameters:
+// RBX: function object.
+// R10: arguments descriptor array (num_args is first Smi element).
void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
- __ Unimplemented("CallStaticFunction stub");
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+
+ __ 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 dart function.
+ __ LeaveFrame();
+
+ __ Bind(&function_compiled);
+ // Patch caller.
+ __ EnterFrame(0);
+
+ __ pushq(R10); // Preserve arguments descriptor array.
+ __ pushq(RBX); // Preserve function object.
+ __ CallRuntimeFromStub(kPatchStaticCallRuntimeEntry);
+ __ popq(RBX); // Restore function object argument in RBX.
+ __ popq(R10); // Restore arguments descriptor array.
+ // Remove the stub frame as we are about to jump to the dart function.
+ __ LeaveFrame();
+ __ movq(RAX, FieldAddress(RBX, Function::code_offset()));
+
+ __ movq(RBX, FieldAddress(RAX, Code::instructions_offset()));
+ __ addq(RBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
+ __ jmp(RBX);
}
@@ -182,8 +239,312 @@
}
+// Lookup for [function-name, arg count] in 'functions_map_'.
+// Input parameters (to be treated as read only, unless calling to target!):
+// RBX: ic-data array.
+// R10: arguments descriptor array (num_args is first Smi element).
+// Stack: return address, arguments.
+// If the lookup succeeds we jump to the target method from here, otherwise
+// we continue in code generated by the caller of 'MegamorphicLookup'.
+static void MegamorphicLookup(Assembler* assembler) {
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ Label class_in_rax, smi_receiver, null_receiver, not_found;
+ // Total number of args is the first Smi in args descriptor array (R10).
+ __ movq(RAX, FieldAddress(R10, Array::data_offset()));
+ __ movq(RAX, Address(RSP, RAX, TIMES_4, 0)); // Get receiver. RAX is a Smi.
+ // TODO(srdjan): Remove the special casing below for null receiver, once
+ // NullClass is implemented.
+ __ cmpq(RAX, raw_null);
+ // Use Object class if receiver is null.
+ __ j(EQUAL, &null_receiver, Assembler::kNearJump);
+ __ testq(RAX, Immediate(kSmiTagMask));
+ __ j(ZERO, &smi_receiver, Assembler::kNearJump);
+ __ movq(RAX, FieldAddress(RAX, Object::class_offset()));
+ __ jmp(&class_in_rax, Assembler::kNearJump);
+ __ Bind(&smi_receiver);
+ // For Smis we need to get the class from the isolate.
+ // Load current Isolate pointer from Context structure into RAX.
+ __ movq(RAX, FieldAddress(CTX, Context::isolate_offset()));
+ __ movq(RAX, Address(RAX, Isolate::object_store_offset()));
+ __ movq(RAX, Address(RAX, ObjectStore::smi_class_offset()));
+ __ jmp(&class_in_rax, Assembler::kNearJump);
+ __ Bind(&null_receiver);
+ __ movq(RAX, FieldAddress(CTX, Context::isolate_offset()));
+ __ movq(RAX, Address(RAX, Isolate::object_store_offset()));
+ __ movq(RAX, Address(RAX, ObjectStore::object_class_offset()));
+
+ __ Bind(&class_in_rax);
+ // Class is in RAX.
+
+ Label loop, next_iteration;
+ // Get functions_cache, since it is allocated lazily it maybe null.
+ __ movq(RAX, FieldAddress(RAX, Class::functions_cache_offset()));
+ // Iterate and search for identical name.
+ __ leaq(R12, FieldAddress(RAX, Array::data_offset()));
+
+ // R12 is pointing into content of functions_map_ array.
+ __ Bind(&loop);
+ __ movq(R13, Address(R12, FunctionsCache::kFunctionName * kWordSize));
+
+ __ cmpq(R13, raw_null);
+ __ j(EQUAL, &not_found, Assembler::kNearJump);
+
+ ASSERT(ICData::kNameIndex == 0);
+ __ cmpq(R13, FieldAddress(RBX, Array::data_offset()));
+ __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
+
+ // Name found, check total argument count and named argument count.
+ __ movq(RAX, FieldAddress(R10, Array::data_offset()));
+ // RAX is total argument count as Smi.
+ __ movq(R13, Address(R12, FunctionsCache::kArgCount * kWordSize));
+ __ cmpq(RAX, R13); // Compare total argument counts.
+ __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
+ __ subq(RAX, FieldAddress(R10, Array::data_offset() + kWordSize));
+ // RAX is named argument count as Smi.
+ __ movq(R13, Address(R12, FunctionsCache::kNamedArgCount * kWordSize));
+ __ cmpq(RAX, R13); // Compare named argument counts.
+ __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
+
+ // Argument count matches, jump to target.
+ // R10: arguments descriptor array.
+ __ movq(RBX, Address(R12, FunctionsCache::kFunction * kWordSize));
+ __ movq(RBX, FieldAddress(RBX, Function::code_offset()));
+ __ movq(RBX, FieldAddress(RBX, Code::instructions_offset()));
+ __ addq(RBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
+ __ jmp(RBX);
+
+ __ Bind(&next_iteration);
+ __ AddImmediate(R12, Immediate(FunctionsCache::kNumEntries * kWordSize));
+ __ jmp(&loop, Assembler::kNearJump);
+
+ __ Bind(&not_found);
+}
+
+
+// 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()));
+
+ // Allocate array to store arguments of caller.
+ __ movq(R10, R13); // Arguments array length.
+ __ SmiTag(R10); // Convert to Smi.
+ __ movq(RBX, raw_null); // Null element type for raw Array.
+ __ call(&StubCode::AllocateArrayLabel());
+ __ SmiUntag(R10);
+ // RAX: newly allocated array.
+ // R10: length of the array (was preserved by the stub).
+ __ pushq(RAX); // Array is in RAX and on top of stack.
+ __ leaq(R12, Address(RSP, R10, TIMES_8, arg_offset)); // Addr of first arg.
+ __ leaq(RBX, FieldAddress(RAX, Array::data_offset()));
+ Label loop, loop_condition;
+ __ jmp(&loop_condition, Assembler::kNearJump);
+ __ Bind(&loop);
+ __ movq(RAX, Address(R12, 0));
+ __ movq(Address(RBX, 0), RAX);
+ __ AddImmediate(RBX, Immediate(kWordSize));
+ __ AddImmediate(R12, Immediate(-kWordSize));
+ __ Bind(&loop_condition);
+ __ decq(R10);
+ __ j(POSITIVE, &loop, Assembler::kNearJump);
+}
+
+
+// Input parameters:
+// RBX: ic-data array.
+// R10: arguments descriptor array (num_args is first Smi element).
+// 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) {
- __ Unimplemented("MegamorphicLookup stub");
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+
+ MegamorphicLookup(assembler);
+ // Lookup in function_table_ failed, resolve, compile and enter function
+ // into function_table_.
+
+ // Create a stub frame as we are pushing some objects on the stack before
+ // calling into the runtime.
+ __ EnterFrame(0);
+
+ // Preserve values across call to resolving.
+ // Stack at this point:
+ // TOS + 0: Saved RBP of previous frame. <== RBP
+ // TOS + 1: Dart code return address
+ // TOS + 2: Last argument of caller.
+ // ....
+ // Total number of args is the first Smi in args descriptor array (R10).
+ __ movq(RAX, FieldAddress(R10, Array::data_offset()));
+ __ movq(RAX, Address(RSP, RAX, TIMES_4, kWordSize)); // Get receiver.
+ __ pushq(R10); // Preserve arguments descriptor array.
+ __ pushq(RAX); // Preserve receiver.
+ __ pushq(RBX); // Preserve ic-data array.
+ // First resolve the function to get the function object.
+
+ // Setup space for return value on stack by pushing smi 0.
+ __ pushq(Immediate(0));
+ __ pushq(RAX); // Push receiver.
+ __ CallRuntimeFromStub(kResolveCompileInstanceFunctionRuntimeEntry);
+ __ popq(RAX); // Remove receiver pushed earlier.
+ __ popq(RBX); // Pop returned code object into RBX.
+ // Pop preserved values
+ __ popq(R10); // Restore ic-data array.
+ __ popq(RAX); // Restore receiver.
+ __ popq(R13); // Restore arguments descriptor array.
+
+ __ cmpq(RBX, raw_null);
+ Label check_implicit_closure;
+ __ j(EQUAL, &check_implicit_closure, Assembler::kNearJump);
+
+ // Remove the stub frame as we are about to jump to the dart function.
+ __ LeaveFrame();
+
+ __ movq(R10, R13);
+ __ movq(RBX, FieldAddress(RBX, Code::instructions_offset()));
+ __ addq(RBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
+ __ jmp(RBX);
+
+ __ Bind(&check_implicit_closure);
+ // RAX: receiver.
+ // R10: ic-data array.
+ // RBX: raw_null.
+ // R13: arguments descriptor array.
+ // The target function was not found.
+ // First check to see if this is a getter function and we are
+ // trying to create a closure of an instance function.
+ // Push values that need to be preserved across runtime call.
+ __ pushq(RAX); // Preserve receiver.
+ __ pushq(R10); // Preserve ic-data array.
+ __ pushq(R13); // Preserve arguments descriptor array.
+
+ __ pushq(Immediate(0));
+ __ pushq(RAX); // Push receiver.
+ __ pushq(R10); // Ic-data array.
+ __ CallRuntimeFromStub(kResolveImplicitClosureFunctionRuntimeEntry);
+ __ popq(RAX);
+ __ popq(RAX);
+ __ popq(RBX); // Get return value into RBX, might be Closure object.
+
+ // Pop preserved values.
+ __ popq(R13); // Restore arguments descriptor array.
+ __ popq(R10); // Restore ic-data array.
+ __ popq(RAX); // Restore receiver.
+
+ __ cmpq(RBX, raw_null);
+ Label check_implicit_closure_through_getter;
+ __ j(EQUAL, &check_implicit_closure_through_getter, Assembler::kNearJump);
+
+ __ movq(RAX, RBX); // Return value is the closure object.
+ // Remove the stub frame as we are about return.
+ __ LeaveFrame();
+ __ ret();
+
+ __ Bind(&check_implicit_closure_through_getter);
+ // RAX: receiver.
+ // R10: ic-data array.
+ // RBX: raw_null.
+ // R13: arguments descriptor array.
+ // This is not the case of an instance so invoke the getter of the
+ // same name and see if we get a closure back which we are then
+ // supposed to invoke.
+ // Push values that need to be preserved across runtime call.
+ __ pushq(RAX); // Preserve receiver.
+ __ pushq(R10); // Preserve ic-data array.
+ __ pushq(R13); // Preserve arguments descriptor array.
+
+ __ pushq(Immediate(0));
+ __ pushq(RAX); // Push receiver.
+ __ pushq(R10); // Ic-data array.
+ __ CallRuntimeFromStub(kResolveImplicitClosureThroughGetterRuntimeEntry);
+ __ popq(R10); // Pop argument.
+ __ popq(RAX); // Pop argument.
+ __ popq(RBX); // get return value into RBX, might be Closure object.
+
+ // Pop preserved values.
+ __ popq(R13); // Restore arguments descriptor array.
+ __ popq(R10); // Restore ic-data array.
+ __ popq(RAX); // Restore receiver.
+
+ __ cmpq(RBX, raw_null);
+ Label function_not_found;
+ __ j(EQUAL, &function_not_found, Assembler::kNearJump);
+
+ // RBX: Closure object.
+ // R13: Arguments descriptor array.
+ __ pushq(Immediate(0)); // Result from invoking Closure.
+ __ pushq(RBX); // Closure object.
+ __ pushq(R13); // Arguments descriptor.
+ __ movq(R13, FieldAddress(R13, Array::data_offset()));
+ __ SmiUntag(R13);
+ __ subq(R13, Immediate(1)); // Arguments array length, minus the receiver.
+ PushArgumentsArray(assembler, (kWordSize * 5));
+ // Stack layout explaining "(kWordSize * 5)" offset.
+ // TOS + 0: Argument array.
+ // TOS + 1: Arguments descriptor array.
+ // TOS + 2: Closure object.
+ // TOS + 3: Place for result from closure function.
+ // TOS + 4: Saved RBP of previous frame. <== RBP
+ // TOS + 5: Dart code return address
+ // TOS + 6: Last argument of caller.
+ // ....
+
+ __ CallRuntimeFromStub(kInvokeImplicitClosureFunctionRuntimeEntry);
+ // Remove arguments.
+ __ popq(RAX);
+ __ popq(RAX);
+ __ popq(RAX);
+ __ popq(RAX); // Get result into RAX.
+
+ // Remove the stub frame as we are about to return.
+ __ LeaveFrame();
+ __ ret();
+
+ __ Bind(&function_not_found);
+ // The target function was not found, so invoke method
+ // "void noSuchMethod(function_name, args_array)".
+ // RAX: receiver.
+ // R10: ic-data array.
+ // RBX: raw_null.
+ // R13: argument descriptor array.
+
+ // Setup space for return value on stack by pushing smi 0.
+ __ pushq(Immediate(0)); // Result from noSuchMethod.
+ __ pushq(RAX); // Receiver.
+ __ pushq(R10); // IC-data array.
+ __ pushq(R13); // Argument descriptor array.
+ __ movq(R13, FieldAddress(R13, Array::data_offset()));
+ __ SmiUntag(R13);
+ __ subq(R13, Immediate(1)); // Arguments array length, minus the receiver.
+ // See stack layout below explaining "wordSize * 6" offset.
+ PushArgumentsArray(assembler, (kWordSize * 6));
+
+ // Stack:
+ // TOS + 0: Argument array.
+ // TOS + 1: Argument 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 code return address
+ // TOS + 7: 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();
}
@@ -192,8 +553,115 @@
}
+// Called for inline allocation of arrays.
+// Input parameters:
+// R10 : Array length as Smi.
+// RBX : array element type (either NULL or an instantiated type).
+// NOTE: R10 cannot be clobbered here as the caller relies on it being saved.
+// The newly allocated object is returned in RAX.
void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
- __ Unimplemented("AllocateArray stub");
+ Label slow_case;
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+
+ if (FLAG_inline_alloc) {
+ // Compute the size to be allocated, it is based on the array length
+ // and it computed as:
+ // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
+ // Assert that length is a Smi.
+ __ testq(R10, Immediate(kSmiTagSize));
+ if (FLAG_use_slow_path) {
+ __ jmp(&slow_case);
+ } else {
+ __ j(NOT_ZERO, &slow_case, Assembler::kNearJump);
+ }
+ __ movq(R13, FieldAddress(CTX, Context::isolate_offset()));
+ __ movq(R13, Address(R13, Isolate::heap_offset()));
+ __ movq(R13, Address(R13, Heap::new_space_offset()));
+
+ // Calculate and align allocation size.
+ // Load new object start and calculate next object start.
+ // RBX: array element type.
+ // R10: Array length as Smi.
+ // R13: Points to new space object.
+ __ movq(RAX, Address(R13, Scavenger::top_offset()));
+ intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
+ __ leaq(R12, Address(R10, TIMES_4, fixed_size)); // R10 is Smi.
+ ASSERT(kSmiTagShift == 1);
+ __ andq(R12, Immediate(-kObjectAlignment));
+ __ leaq(R12, Address(RAX, R12, TIMES_1, 0));
+
+ // Check if the allocation fits into the remaining space.
+ // RAX: potential new object start.
+ // R12: potential next object start.
+ // RBX: array element type.
+ // R10: Array length as Smi.
+ // R13: Points to new space object.
+ __ cmpq(R12, Address(R13, Scavenger::end_offset()));
+ __ j(ABOVE_EQUAL, &slow_case, Assembler::kNearJump);
+
+ // Successfully allocated the object(s), now update top to point to
+ // next object start and initialize the object.
+ // RAX: potential new object start.
+ // R12: potential next object start.
+ // R13: Points to new space object.
+ __ movq(Address(R13, Scavenger::top_offset()), R12);
+ __ addq(RAX, Immediate(kHeapObjectTag));
+
+ // RAX: new object start as a tagged pointer.
+ // R12: new object end address.
+ // RBX: array element type.
+ // R10: Array length as Smi.
+
+ // Store the type argument field.
+ __ movq(FieldAddress(RAX, Array::type_arguments_offset()), RBX);
+
+ // Set the length field.
+ __ movq(FieldAddress(RAX, Array::length_offset()), R10);
+
+ // Store class value for array.
+ __ movq(RBX, FieldAddress(CTX, Context::isolate_offset()));
+ __ movq(RBX, Address(RBX, Isolate::object_store_offset()));
+ __ movq(RBX, Address(RBX, ObjectStore::array_class_offset()));
+ __ movq(FieldAddress(RAX, Array::class_offset()), RBX);
+ __ movq(FieldAddress(RAX, Array::tags_offset()), Immediate(0)); // Tags.
+
+ // Initialize all array elements to raw_null.
+ // RAX: new object start as a tagged pointer.
+ // R12: new object end address.
+ // 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);
+ __ cmpq(RBX, R12);
+ __ j(ABOVE_EQUAL, &done, Assembler::kNearJump);
+ __ movq(Address(RBX, 0), raw_null);
+ __ addq(RBX, Immediate(kWordSize));
+ __ jmp(&init_loop, Assembler::kNearJump);
+ __ Bind(&done);
+
+ // Done allocating and initializing the array.
+ // RAX: new object.
+ __ ret();
+ }
+
+ // Unable to allocate the array using the fast inline code, just call
+ // into the runtime.
+ __ Bind(&slow_case);
+ __ EnterFrame(0);
+ __ pushq(raw_null); // Push Null object for return value.
+ __ pushq(R10); // Array length as Smi.
+ __ pushq(RBX); // Element type.
+ __ pushq(raw_null); // Null instantiator.
+ __ CallRuntimeFromStub(kAllocateArrayRuntimeEntry);
+ __ popq(RAX); // Pop instantiator.
+ __ popq(RAX); // Pop element type argument.
+ __ popq(R10); // Pop array length argument.
+ __ popq(RAX); // Pop return value from return slot.
+ __ LeaveFrame();
+ __ ret();
}
@@ -323,9 +791,197 @@
}
+
+
+// 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) {
- __ Unimplemented("AllocateObject stub");
+ const intptr_t kObjectTypeArgumentsOffset = 2 * kWordSize;
+ const intptr_t kInstantiatorTypeArgumentsOffset = 1 * kWordSize;
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ // The generated code is different if the class is parameterized.
+ const bool is_cls_parameterized =
+ cls.type_arguments_instance_field_offset() != Class::kNoTypeArguments;
+ // kInlineInstanceSize is a constant used as a threshold for determining
+ // when the object initialization should be done as a loop or as
+ // straight line code.
+ const int kInlineInstanceSize = 12; // In words.
+ const intptr_t instance_size = cls.instance_size();
+ ASSERT(instance_size > 0);
+ const intptr_t type_args_size = InstantiatedTypeArguments::InstanceSize();
+ if (FLAG_inline_alloc &&
+ PageSpace::IsPageAllocatableSize(instance_size + type_args_size)) {
+ Label slow_case;
+ Heap* heap = Isolate::Current()->heap();
+ __ movq(RAX, Immediate(heap->TopAddress()));
+ __ movq(RAX, Address(RAX, 0));
+ __ leaq(RBX, Address(RAX, instance_size));
+ if (is_cls_parameterized) {
+ __ movq(RCX, RBX);
+ // A new InstantiatedTypeArguments object only needs to be allocated if
+ // the instantiator is non-null.
+ Label null_instantiator;
+ __ cmpq(Address(RSP, kInstantiatorTypeArgumentsOffset), raw_null);
+ __ j(EQUAL, &null_instantiator, Assembler::kNearJump);
+ __ addq(RBX, Immediate(type_args_size));
+ __ Bind(&null_instantiator);
+ // RCX: potential new object end and, if RCX != RBX, potential new
+ // InstantiatedTypeArguments object start.
+ }
+ // Check if the allocation fits into the remaining space.
+ // RAX: potential new object start.
+ // RBX: potential next object start.
+ __ movq(RDI, Immediate(heap->EndAddress()));
+ __ cmpq(RBX, Address(RDI, 0));
+ if (FLAG_use_slow_path) {
+ __ jmp(&slow_case);
+ } else {
+ __ j(ABOVE_EQUAL, &slow_case, Assembler::kNearJump);
+ }
+
+ // Successfully allocated the object(s), now update top to point to
+ // next object start and initialize the object.
+ __ movq(RDI, Immediate(heap->TopAddress()));
+ __ movq(Address(RDI, 0), RBX);
+
+ if (is_cls_parameterized) {
+ // Initialize the type arguments field in the object.
+ // RAX: new object start.
+ // RCX: potential new object end and, if RCX != RBX, potential new
+ // InstantiatedTypeArguments object start.
+ // RBX: next object start.
+ Label type_arguments_ready;
+ __ movq(RDI, Address(RSP, kObjectTypeArgumentsOffset));
+ __ cmpq(RCX, RBX);
+ __ j(EQUAL, &type_arguments_ready, Assembler::kNearJump);
+ // Initialize InstantiatedTypeArguments object at RCX.
+ __ movq(Address(RCX,
+ InstantiatedTypeArguments::uninstantiated_type_arguments_offset()),
+ RDI);
+ __ movq(RDX, Address(RSP, kInstantiatorTypeArgumentsOffset));
+ __ movq(Address(RCX,
+ InstantiatedTypeArguments::instantiator_type_arguments_offset()),
+ RDX);
+ __ LoadObject(RDX,
+ Class::ZoneHandle(Object::instantiated_type_arguments_class()));
+ __ movq(Address(RCX, Instance::class_offset()), RDX); // Set its class.
+ __ movq(Address(RCX, Instance::tags_offset()), Immediate(0)); // Tags.
+ // Set the new InstantiatedTypeArguments object (RCX) as the type
+ // arguments (RDI) of the new object (RAX).
+ __ movq(RDI, RCX);
+ __ addq(RDI, Immediate(kHeapObjectTag));
+ // Set RBX to new object end.
+ __ movq(RBX, RCX);
+ __ Bind(&type_arguments_ready);
+ // RAX: new object.
+ // RDI: new object type arguments.
+ }
+
+ // Initialize the class field in the object.
+ // RAX: new object start.
+ // RBX: next object start.
+ // RDI: new object type arguments (if is_cls_parameterized).
+ __ LoadObject(RDX, cls); // Load class of object to be allocated.
+ __ movq(Address(RAX, Instance::class_offset()), RDX);
+ __ movq(Address(RAX, Instance::tags_offset()), Immediate(0)); // Tags.
+
+ // Initialize the remaining words of the object.
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+
+ // RAX: new object start.
+ // RBX: next object start.
+ // RDX: class of the object to be allocated.
+ // First try inlining the initialization without a loop.
+ if (instance_size < (kInlineInstanceSize * kWordSize) &&
+ cls.num_native_fields() == 0) {
+ // Check if the object contains any non-header fields.
+ // Small objects are initialized using a consecutive set of writes.
+ for (intptr_t current_offset = sizeof(RawObject);
+ current_offset < instance_size;
+ current_offset += kWordSize) {
+ __ movq(Address(RAX, current_offset), raw_null);
+ }
+ } else {
+ __ leaq(RCX, Address(RAX, sizeof(RawObject)));
+ // Loop until the whole object is initialized.
+ Label init_loop;
+ if (cls.num_native_fields() > 0) {
+ // Initialize native fields.
+ // RAX: new object.
+ // RBX: next object start.
+ // RDX: class of the object to be allocated.
+ // RCX: next word to be initialized.
+ intptr_t offset = Class::num_native_fields_offset() - kHeapObjectTag;
+ __ movq(RDX, Address(RDX, offset));
+ __ leaq(RDX, Address(RAX, RDX, TIMES_8, sizeof(RawObject)));
+
+ // RDX: start of dart fields.
+ // RCX: next word to be initialized.
+ Label init_native_loop;
+ __ Bind(&init_native_loop);
+ __ cmpq(RCX, RDX);
+ __ j(ABOVE_EQUAL, &init_loop, Assembler::kNearJump);
+ __ movq(Address(RCX, 0), Immediate(0));
+ __ addq(RCX, Immediate(kWordSize));
+ __ jmp(&init_native_loop, Assembler::kNearJump);
+ }
+ // Now initialize the dart fields.
+ // RAX: new object.
+ // RBX: next object start.
+ // RCX: next word to be initialized.
+ Label done;
+ __ Bind(&init_loop);
+ __ cmpq(RCX, RBX);
+ __ j(ABOVE_EQUAL, &done, Assembler::kNearJump);
+ __ movq(Address(RCX, 0), raw_null);
+ __ addq(RCX, Immediate(kWordSize));
+ __ jmp(&init_loop, Assembler::kNearJump);
+ __ Bind(&done);
+ }
+ if (is_cls_parameterized) {
+ // RDI: new object type arguments.
+ // Set the type arguments in the new object.
+ __ movq(Address(RAX, cls.type_arguments_instance_field_offset()), RDI);
+ }
+ // Done allocating and initializing the instance.
+ // RAX: new object.
+ __ addq(RAX, Immediate(kHeapObjectTag));
+ __ ret();
+
+ __ Bind(&slow_case);
+ }
+ if (is_cls_parameterized) {
+ __ movq(RAX, Address(RSP, kObjectTypeArgumentsOffset));
+ __ movq(RDX, Address(RSP, kInstantiatorTypeArgumentsOffset));
+ }
+ // Create a stub frame.
+ __ EnterFrame(0);
+ const Object& new_object = Object::ZoneHandle();
+ __ PushObject(new_object); // Push Null object for return value.
+ __ PushObject(cls); // Push class of object to be allocated.
+ if (is_cls_parameterized) {
+ __ pushq(RAX); // Push type arguments of object to be allocated.
+ __ pushq(RDX); // Push type arguments of instantiator.
+ } else {
+ __ pushq(raw_null); // Push null type arguments.
+ __ pushq(raw_null); // Push null instantiator.
+ }
+ __ CallRuntimeFromStub(kAllocateObjectRuntimeEntry); // Allocate object.
+ __ popq(RAX); // Pop argument (instantiator).
+ __ popq(RAX); // Pop argument (type arguments of object).
+ __ popq(RAX); // Pop argument (class of object).
+ __ popq(RAX); // Pop result (newly allocated object).
+ // RAX: new object
+ // Restore the frame pointer.
+ __ LeaveFrame();
+ __ ret();
}
@@ -340,13 +996,165 @@
}
+// Generate inline cache check for 'num_args'.
+// RBX: Inline cache data array.
+// R10: Arguments array.
+// TOS(0): return address
+// Control flow:
+// - If receiver is null -> jump to IC miss.
+// - If receiver is Smi -> load Smi class.
+// - If receiver is not-Smi -> load receiver's class.
+// - Check if 'num_args' (including receiver) match any IC data group.
+// - Match found -> jump to target.
+// - Match not found -> jump to IC miss.
+void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler,
+ intptr_t num_args) {
+ ASSERT(num_args > 0);
+ // Get receiver.
+ __ movq(RAX, FieldAddress(R10, Array::data_offset()));
+ __ movq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi.
+
+ Label get_class, ic_miss;
+ __ call(&get_class);
+ // RAX: receiver's class
+ // RBX: IC data array.
+
+#if defined(DEBUG)
+ { Label ok;
+ // Check that the IC data array has NumberOfArgumentsChecked() == num_args.
+ __ movq(RCX, FieldAddress(RBX,
+ Array::data_offset() + ICData::kNumArgsCheckedIndex * kWordSize));
+ const Immediate value =
+ Immediate(reinterpret_cast<int64_t>(Smi::New(num_args)));
+ __ cmpq(RCX, value);
+ __ j(EQUAL, &ok, Assembler::kNearJump);
+ __ Stop("Incorrect stub for IC data");
+ __ Bind(&ok);
+ }
+#endif // DEBUG
+
+ // Loop that checks if there is an IC data match.
+ // RAX: receiver's class.
+ // RBX: IC data array (preserved).
+ __ leaq(R12, FieldAddress(RBX,
+ Array::data_offset() + ICData::kChecksStartIndex * kWordSize));
+ // R12: pointing to a class to check against (into IC data array).
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ Label loop, found;
+ if (num_args == 1) {
+ __ Bind(&loop);
+ __ movq(R13, Address(R12, 0)); // Get class to check.
+ __ cmpq(RAX, R13); // Match?
+ __ j(EQUAL, &found, Assembler::kNearJump);
+ __ addq(R12, Immediate(kWordSize * 2)); // Next element (class + target).
+ __ cmpq(R13, raw_null); // Done?
+ __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
+ } else if (num_args == 2) {
+ Label no_match;
+ __ Bind(&loop);
+ __ movq(R13, Address(R12, 0)); // Get class from IC data to check.
+ // Get receiver.
+ __ movq(RAX, FieldAddress(R10, Array::data_offset()));
+ __ movq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi.
+ __ call(&get_class);
+ __ cmpq(RAX, R13); // Match?
+ __ j(NOT_EQUAL, &no_match, Assembler::kNearJump);
+ // Check second.
+ __ movq(R13, Address(R12, kWordSize)); // Get class from IC data to check.
+ // Get next argument.
+ __ movq(RAX, FieldAddress(R10, Array::data_offset()));
+ __ movq(RAX, Address(RSP, RAX, TIMES_4, -kWordSize)); // RAX is Smi.
+ __ call(&get_class);
+ __ cmpq(RAX, R13); // Match?
+ __ j(EQUAL, &found, Assembler::kNearJump);
+ __ Bind(&no_match);
+ __ addq(R12, Immediate(kWordSize * (1 + num_args))); // Next element.
+ __ cmpq(R13, raw_null); // Done?
+ __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
+ }
+
+ __ Bind(&ic_miss);
+ // Get receiver, again.
+ __ movq(RAX, FieldAddress(R10, Array::data_offset()));
+ __ leaq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi.
+ __ EnterFrame(0);
+ // Setup space for return value on stack by pushing smi 0.
+ __ pushq(R10); // Preserve arguments array.
+ __ pushq(RBX); // Preserve IC data array
+ __ pushq(Immediate(0)); // Space for result (target code object).
+ __ movq(R10, FieldAddress(R10, Array::data_offset()));
+ // Push call arguments.
+ for (intptr_t i = 0; i < num_args; i++) {
+ __ movq(R10, Address(RAX, -kWordSize * i));
+ __ pushq(R10);
+ }
+ if (num_args == 1) {
+ __ CallRuntimeFromStub(kInlineCacheMissHandlerOneArgRuntimeEntry);
+ } else if (num_args == 2) {
+ __ CallRuntimeFromStub(kInlineCacheMissHandlerTwoArgsRuntimeEntry);
+ } else {
+ UNIMPLEMENTED();
+ }
+ // Remove call arguments pushed earlier.
+ for (intptr_t i = 0; i < num_args; i++) {
+ __ popq(RAX);
+ }
+ __ popq(RAX); // Pop returned code object into RAX (null if not found).
+ __ popq(RBX); // Restore IC data array.
+ __ popq(R10); // Restore arguments array.
+ __ LeaveFrame();
+ Label call_target_function;
+ __ cmpq(RAX, raw_null);
+ __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump);
+ // NoSuchMethod or closure.
+ __ jmp(&StubCode::MegamorphicLookupLabel());
+
+ __ Bind(&found);
+ // R12: Pointer to an IC data check group (classes + target)
+ __ movq(RAX, Address(R12, kWordSize * num_args)); // Target function.
+
+ __ Bind(&call_target_function);
+ // RAX: Target function.
+ __ movq(RAX, FieldAddress(RAX, Function::code_offset()));
+ __ movq(RAX, FieldAddress(RAX, Code::instructions_offset()));
+ __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
+ __ jmp(RAX);
+
+ __ Bind(&get_class);
+ Label not_smi;
+ // Test if Smi -> load Smi class for comparison.
+ __ testq(RAX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &not_smi, Assembler::kNearJump);
+ const Class& smi_class =
+ Class::ZoneHandle(Isolate::Current()->object_store()->smi_class());
+ __ LoadObject(RAX, smi_class);
+ __ ret();
+
+ __ Bind(&not_smi);
+ __ movq(RAX, FieldAddress(RAX, Object::class_offset()));
+ __ ret();
+}
+
+
+// Use inline cache data array to invoke the target or continue in inline
+// cache miss handler. Stub for 1-argument check (receiver class).
+// RCX: Inline cache data array
+// RDX: Arguments array
+// TOS(0): return address
+// Inline cache data array structure:
+// 0: function-name
+// 1: N, number of arguments checked.
+// 2 .. (length - 1): group of checks, each check containing:
+// - N classes.
+// - 1 target function.
void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) {
- __ Unimplemented("GenerateOneArgCheckInlineCacheStub stub");
+ return GenerateNArgsCheckInlineCacheStub(assembler, 1);
}
void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) {
- __ Unimplemented("GenerateTwoArgsCheckInlineCacheStub stub");
+ return GenerateNArgsCheckInlineCacheStub(assembler, 2);
}
« no previous file with comments | « runtime/vm/stub_code_ia32.cc ('k') | runtime/vm/vm_sources.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698