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

Unified Diff: runtime/vm/stub_code_mips.cc

Issue 14076005: Supports FrameLookup vm test on MIPS (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 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 | « runtime/vm/stub_code_arm.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/stub_code_mips.cc
===================================================================
--- runtime/vm/stub_code_mips.cc (revision 21219)
+++ runtime/vm/stub_code_mips.cc (working copy)
@@ -8,6 +8,7 @@
#include "vm/assembler.h"
#include "vm/code_generator.h"
#include "vm/dart_entry.h"
+#include "vm/flow_graph_compiler.h"
#include "vm/instructions.h"
#include "vm/stack_frame.h"
#include "vm/stub_code.h"
@@ -16,6 +17,13 @@
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.");
+DECLARE_FLAG(int, optimization_counter_threshold);
+DECLARE_FLAG(bool, trace_optimized_ic_calls);
+
+
// Input parameters:
// RA : return address.
// SP : address of last argument in argument array.
@@ -90,8 +98,8 @@
__ mov(SP, FP);
__ lw(RA, Address(SP, 1 * kWordSize));
__ lw(FP, Address(SP, 0 * kWordSize));
- __ addiu(SP, SP, Immediate(2 * kWordSize));
__ Ret();
+ __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize));
}
@@ -182,8 +190,8 @@
__ mov(SP, FP);
__ lw(RA, Address(SP, 1 * kWordSize));
__ lw(FP, Address(SP, 0 * kWordSize));
- __ addiu(SP, SP, Immediate(2 * kWordSize));
__ Ret();
+ __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize));
}
@@ -209,7 +217,7 @@
__ LeaveStubFrame();
__ lw(T0, FieldAddress(T0, Code::instructions_offset()));
- __ addiu(T0, T0, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
+ __ AddImmediate(T0, Instructions::HeaderSize() - kHeapObjectTag);
__ jr(T0);
}
@@ -311,25 +319,21 @@
__ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
__ SmiUntag(T1);
+ // Compute address of 'arguments array' data area into A2.
+ __ lw(A2, Address(A2, VMHandles::kOffsetOfRawPtrInHandle));
+ __ AddImmediate(A2, Array::data_offset() - kHeapObjectTag);
+
// Set up arguments for the Dart call.
Label push_arguments;
Label done_push_arguments;
-
- // Compute address of 'arguments array' data area into A2.
- // See also the addiu in the delay slot of the upcoming beq.
- __ lw(A2, Address(A2, VMHandles::kOffsetOfRawPtrInHandle));
-
__ beq(T1, ZR, &done_push_arguments); // check if there are arguments.
- __ delay_slot()->addiu(A2, A2,
- Immediate(Array::data_offset() - kHeapObjectTag));
-
__ mov(A1, ZR);
__ Bind(&push_arguments);
__ lw(A3, Address(A2));
__ Push(A3);
- __ addiu(A2, A2, Immediate(kWordSize));
__ addiu(A1, A1, Immediate(1));
__ BranchLess(A1, T1, &push_arguments);
+ __ delay_slot()->addiu(A2, A2, Immediate(kWordSize));
__ Bind(&done_push_arguments);
@@ -341,7 +345,7 @@
__ lw(CTX, Address(CTX, VMHandles::kOffsetOfRawPtrInHandle));
// Get rid of arguments pushed on the stack.
- __ addiu(SP, FP, Immediate(kSavedContextOffsetInEntryFrame));
+ __ AddImmediate(SP, FP, kSavedContextOffsetInEntryFrame);
// Load Isolate pointer from Context structure into CTX. Drop Context.
__ lw(CTX, FieldAddress(CTX, Context::isolate_offset()));
@@ -379,9 +383,174 @@
}
+// Called for inline allocation of objects.
+// Input parameters:
+// RA : return address.
+// SP + 4 : type arguments object (only if class is parameterized).
+// SP + 0 : type arguments of instantiator (only if class is parameterized).
void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
const Class& cls) {
- __ Unimplemented("AllocateObject stub");
+ // The generated code is different if the class is parameterized.
+ const bool is_cls_parameterized =
+ cls.type_arguments_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;
+ 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();
+ __ LoadImmediate(T5, heap->TopAddress());
+ __ lw(T2, Address(T5));
+ __ LoadImmediate(T4, instance_size);
+ __ addu(T3, T2, T4);
+ if (is_cls_parameterized) {
+ Label no_instantiator;
+ __ lw(T1, Address(SP, 1 * kWordSize));
+ __ lw(T0, Address(SP, 0 * kWordSize));
+ // A new InstantiatedTypeArguments object only needs to be allocated if
+ // the instantiator is provided (not kNoInstantiator, but may be null).
+ __ BranchEqual(T0, Smi::RawValue(StubCode::kNoInstantiator),
+ &no_instantiator);
+ __ delay_slot()->mov(T4, T3);
+ __ AddImmediate(T3, type_args_size);
+ __ Bind(&no_instantiator);
+ // T4: potential new object end and, if T4 != T3, potential new
+ // InstantiatedTypeArguments object start.
+ }
+ // Check if the allocation fits into the remaining space.
+ // T2: potential new object start.
+ // T3: potential next object start.
+ if (FLAG_use_slow_path) {
+ __ b(&slow_case);
+ } else {
+ __ BranchGreaterEqual(T3, heap->EndAddress(), &slow_case);
+ }
+
+ // Successfully allocated the object(s), now update top to point to
+ // next object start and initialize the object.
+ __ sw(T3, Address(T5));
+
+ if (is_cls_parameterized) {
+ // Initialize the type arguments field in the object.
+ // T2: new object start.
+ // T4: potential new object end and, if T4 != T3, potential new
+ // InstantiatedTypeArguments object start.
+ // T3: next object start.
+ Label type_arguments_ready;
+ __ beq(T4, T3, &type_arguments_ready);
+ // Initialize InstantiatedTypeArguments object at T4.
+ __ sw(T1, Address(T4,
+ InstantiatedTypeArguments::uninstantiated_type_arguments_offset()));
+ __ sw(T0, Address(T4,
+ InstantiatedTypeArguments::instantiator_type_arguments_offset()));
+ const Class& ita_cls =
+ Class::ZoneHandle(Object::instantiated_type_arguments_class());
+ // Set the tags.
+ uword tags = 0;
+ tags = RawObject::SizeTag::update(type_args_size, tags);
+ tags = RawObject::ClassIdTag::update(ita_cls.id(), tags);
+ __ LoadImmediate(T0, tags);
+ __ sw(T0, Address(T4, Instance::tags_offset()));
+ // Set the new InstantiatedTypeArguments object (T4) as the type
+ // arguments (T1) of the new object (T2).
+ __ addiu(T1, T4, Immediate(kHeapObjectTag));
+ // Set T3 to new object end.
+ __ mov(T3, T4);
+ __ Bind(&type_arguments_ready);
+ // T2: new object.
+ // T1: new object type arguments.
+ }
+
+ // T2: new object start.
+ // T3: next object start.
+ // T1: new object type arguments (if is_cls_parameterized).
+ // Set the tags.
+ uword tags = 0;
+ tags = RawObject::SizeTag::update(instance_size, tags);
+ ASSERT(cls.id() != kIllegalCid);
+ tags = RawObject::ClassIdTag::update(cls.id(), tags);
+ __ LoadImmediate(T0, tags);
+ __ sw(T0, Address(T2, Instance::tags_offset()));
+
+ // Initialize the remaining words of the object.
+ __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
+
+ // T0: raw null.
+ // T2: new object start.
+ // T3: next object start.
+ // T1: new object type arguments (if is_cls_parameterized).
+ // First try inlining the initialization without a loop.
+ if (instance_size < (kInlineInstanceSize * kWordSize)) {
+ // 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) {
+ __ sw(T0, Address(T2, current_offset));
+ }
+ } else {
+ __ addiu(T4, T2, Immediate(sizeof(RawObject)));
+ // Loop until the whole object is initialized.
+ // T0: raw null.
+ // T2: new object.
+ // T3: next object start.
+ // T4: next word to be initialized.
+ // T1: new object type arguments (if is_cls_parameterized).
+ Label init_loop;
+ Label done;
+ __ Bind(&init_loop);
+ __ BranchGreaterEqual(T4, T3, &done); // Done if T4 >= T3.
+ __ sw(T0, Address(T4));
+ __ AddImmediate(T4, kWordSize);
+ __ b(&init_loop);
+ __ Bind(&done);
+ }
+ if (is_cls_parameterized) {
+ // R1: new object type arguments.
+ // Set the type arguments in the new object.
+ __ sw(T1, Address(T2, cls.type_arguments_field_offset()));
+ }
+ // Done allocating and initializing the instance.
+ // R2: new object still missing its heap tag.
+ __ Ret();
+ __ delay_slot()->addiu(V0, T2, Immediate(kHeapObjectTag));
+
+ __ Bind(&slow_case);
+ }
+ if (is_cls_parameterized) {
+ __ lw(T1, Address(SP, 1 * kWordSize));
+ __ lw(T0, Address(SP, 0 * kWordSize));
+ }
+ // Create a stub frame as we are pushing some objects on the stack before
+ // calling into the runtime.
+ __ EnterStubFrame(true); // Uses pool pointer to pass cls to runtime.
+ __ LoadImmediate(T2, reinterpret_cast<intptr_t>(Object::null()));
+ __ Push(T2); // Setup space on stack for return value.
+ __ PushObject(cls); // Push class of object to be allocated.
+ if (is_cls_parameterized) {
+ // Push type arguments of object to be allocated and of instantiator.
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(T1, Address(SP, 1 * kWordSize));
+ __ sw(T0, Address(SP, 0 * kWordSize));
+ } else {
+ // Push null type arguments and kNoInstantiator.
+ __ LoadImmediate(T1, Smi::RawValue(StubCode::kNoInstantiator));
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(T2, Address(SP, 1 * kWordSize));
+ __ sw(T1, Address(SP, 0 * kWordSize));
+ }
+ __ CallRuntime(kAllocateObjectRuntimeEntry); // Allocate object.
+ __ Drop(3); // Pop arguments.
+ __ Pop(V0); // Pop result (newly allocated object).
+ // V0: new object
+ // Restore the frame pointer.
+ __ LeaveStubFrame(true);
+ __ Ret();
}
@@ -401,30 +570,242 @@
}
+// Loads function into 'temp_reg'.
void StubCode::GenerateUsageCounterIncrement(Assembler* assembler,
Register temp_reg) {
- __ Unimplemented("UsageCounterIncrement stub");
+ Register ic_reg = S5;
+ Register func_reg = temp_reg;
+ ASSERT(temp_reg == T0);
+ __ lw(func_reg, FieldAddress(ic_reg, ICData::function_offset()));
+ __ lw(T1, FieldAddress(func_reg, Function::usage_counter_offset()));
+ Label is_hot;
+ if (FlowGraphCompiler::CanOptimize()) {
+ ASSERT(FLAG_optimization_counter_threshold > 1);
+ // The usage_counter is always less than FLAG_optimization_counter_threshold
+ // except when the function gets optimized.
+ __ BranchEqual(T1, FLAG_optimization_counter_threshold, &is_hot);
+ // As long as VM has no OSR do not optimize in the middle of the function
+ // but only at exit so that we have collected all type feedback before
+ // optimizing.
+ }
+ __ addiu(T1, T1, Immediate(1));
+ __ sw(T1, FieldAddress(func_reg, Function::usage_counter_offset()));
+ __ Bind(&is_hot);
}
+// Generate inline cache check for 'num_args'.
+// AR: return address
+// S5: Inline cache data object.
+// S4: Arguments descriptor array.
+// 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) {
- __ Unimplemented("NArgsCheckInlineCache stub");
+ ASSERT(num_args > 0);
+#if defined(DEBUG)
+ { Label ok;
+ // Check that the IC data array has NumberOfArgumentsChecked() == num_args.
+ // 'num_args_tested' is stored as an untagged int.
+ __ lw(T0, FieldAddress(S5, ICData::num_args_tested_offset()));
+ __ BranchEqual(T0, num_args, &ok);
+ __ Stop("Incorrect stub for IC data");
+ __ Bind(&ok);
+ }
+#endif // DEBUG
+
+ // Preserve return address, since LR is needed for subroutine call.
+ __ mov(T2, RA);
+ // Loop that checks if there is an IC data match.
+ Label loop, update, test, found, get_class_id_as_smi;
+ // S5: IC data object (preserved).
+ __ lw(T0, FieldAddress(S5, ICData::ic_data_offset()));
+ // T0: ic_data_array with check entries: classes and target functions.
+ __ AddImmediate(T0, Array::data_offset() - kHeapObjectTag);
+ // T0: points directly to the first ic data array element.
+
+ // Get the receiver's class ID (first read number of arguments from
+ // arguments descriptor array and then access the receiver from the stack).
+ __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
+ __ AddImmediate(T1, -Smi::RawValue(1));
+ __ sll(T3, T1, 1); // T1 (argument_count - 1) is smi.
+ __ addu(T3, T3, SP);
+ __ bal(&get_class_id_as_smi);
+ __ delay_slot()->lw(T3, Address(T3));
+ // T1: argument_count - 1 (smi).
+ // T3: receiver's class ID (smi).
+ __ b(&test);
+ __ delay_slot()->lw(T4, Address(T0)); // First class id (smi) to check.
+
+ __ Bind(&loop);
+ for (int i = 0; i < num_args; i++) {
+ if (i > 0) {
+ // If not the first, load the next argument's class ID.
+ __ LoadImmediate(T3, Smi::RawValue(-i));
+ __ addu(T3, T1, T3);
+ __ sll(T3, T3, 1);
+ __ addu(T3, SP, T3);
+ __ bal(&get_class_id_as_smi);
+ __ delay_slot()->lw(T3, Address(T3));
+ // T3: next argument class ID (smi).
+ __ lw(T4, Address(T0, i * kWordSize));
+ // T4: next class ID to check (smi).
+ }
+ if (i < (num_args - 1)) {
+ __ bne(T3, T4, &update); // Continue.
+ } else {
+ // Last check, all checks before matched.
+ Label skip;
+ __ bne(T3, T4, &skip);
+ __ b(&found); // Break.
+ __ delay_slot()->mov(RA, T2); // Restore return address if found.
+ __ Bind(&skip);
+ }
+ }
+ __ Bind(&update);
+ // Reload receiver class ID. It has not been destroyed when num_args == 1.
+ if (num_args > 1) {
+ __ sll(T3, T1, 1);
+ __ addu(T3, SP, T3);
+ __ bal(&get_class_id_as_smi);
+ __ delay_slot()->lw(T3, Address(T3));
+ }
+
+ const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize;
+ __ AddImmediate(T0, entry_size); // Next entry.
+ __ lw(T4, Address(T0)); // Next class ID.
+
+ __ Bind(&test);
+ __ BranchNotEqual(T4, Smi::RawValue(kIllegalCid), &loop); // Done?
+
+ // IC miss.
+ // Restore return address.
+ __ mov(RA, T2);
+
+ // Compute address of arguments (first read number of arguments from
+ // arguments descriptor array and then compute address on the stack).
+ // T1: argument_count - 1 (smi).
+ __ sll(T1, T1, 1);
+ __ addu(T1, SP, T1); // T1 is Smi.
+ // T1: address of receiver.
+ // Create a stub frame as we are pushing some objects on the stack before
+ // calling into the runtime.
+ __ EnterStubFrame();
+ __ LoadImmediate(T3, reinterpret_cast<intptr_t>(Object::null()));
+ // Preserve IC data object and arguments descriptor array and
+ // setup space on stack for result (target code object).
+ __ addiu(SP, SP, Immediate(-3 * kWordSize));
+ __ sw(S5, Address(SP, 2 * kWordSize));
+ __ sw(S4, Address(SP, 1 * kWordSize));
+ __ sw(T3, Address(SP, 0 * kWordSize));
+ // Push call arguments.
+ for (intptr_t i = 0; i < num_args; i++) {
+ __ lw(TMP, Address(T1, -i * kWordSize));
+ __ Push(TMP);
+ }
+ // Pass IC data object and arguments descriptor array.
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(S5, Address(SP, 1 * kWordSize));
+ __ sw(S4, Address(SP, 0 * kWordSize));
+
+ if (num_args == 1) {
+ __ CallRuntime(kInlineCacheMissHandlerOneArgRuntimeEntry);
+ } else if (num_args == 2) {
+ __ CallRuntime(kInlineCacheMissHandlerTwoArgsRuntimeEntry);
+ } else if (num_args == 3) {
+ __ CallRuntime(kInlineCacheMissHandlerThreeArgsRuntimeEntry);
+ } else {
+ UNIMPLEMENTED();
+ }
+ // Remove the call arguments pushed earlier, including the IC data object
+ // and the arguments descriptor array.
+ __ Drop(num_args + 2);
+ // Pop returned code object into T3 (null if not found).
+ // Restore arguments descriptor array and IC data array.
+ __ lw(T3, Address(SP, 0 * kWordSize));
+ __ lw(S4, Address(SP, 1 * kWordSize));
+ __ lw(S5, Address(SP, 2 * kWordSize));
+ __ addiu(SP, SP, Immediate(3 * kWordSize));
+ __ LeaveStubFrame();
+ Label call_target_function;
+ __ BranchNotEqual(T3, reinterpret_cast<intptr_t>(Object::null()),
+ &call_target_function);
+ // NoSuchMethod or closure.
+ // Mark IC call that it may be a closure call that does not collect
+ // type feedback.
+ __ LoadImmediate(TMP2, 1);
+ __ Branch(&StubCode::InstanceFunctionLookupLabel());
+ __ delay_slot()->sb(TMP2, FieldAddress(S5, ICData::is_closure_call_offset()));
+
+ __ Bind(&found);
+ // T0: Pointer to an IC data check group.
+ const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
+ const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
+ __ lw(T3, Address(T0, target_offset));
+ __ lw(T4, Address(T0, count_offset));
+
+ __ AddImmediateDetectOverflow(T4, T4, Smi::RawValue(1), T5);
+
+ __ bgez(T5, &call_target_function); // No overflow.
+ __ delay_slot()->sw(T4, Address(T0, count_offset));
+
+ __ LoadImmediate(T1, Smi::RawValue(Smi::kMaxValue));
+ __ sw(T1, Address(T0, count_offset));
+
+ __ Bind(&call_target_function);
+ // T0: Target function.
+ __ lw(T3, FieldAddress(T3, Function::code_offset()));
+ __ lw(T3, FieldAddress(T3, Code::instructions_offset()));
+ __ AddImmediate(T3, Instructions::HeaderSize() - kHeapObjectTag);
+ __ jr(T3);
+
+ // Instance in T3, return its class-id in T3 as Smi.
+ __ Bind(&get_class_id_as_smi);
+ Label not_smi;
+ // Test if Smi -> load Smi class for comparison.
+ __ andi(TMP1, T3, Immediate(kSmiTagMask));
+ __ bne(TMP1, ZR, &not_smi);
+ __ LoadImmediate(T3, Smi::RawValue(kSmiCid));
+ __ jr(RA);
+
+ __ Bind(&not_smi);
+ __ LoadClassId(T3, T3);
+ __ SmiTag(T3);
+ __ jr(RA);
}
+// Use inline cache data array to invoke the target or continue in inline
+// cache miss handler. Stub for 1-argument check (receiver class).
+// RA: Return address.
+// S5: Inline cache data object.
+// S4: Arguments descriptor array.
+// Inline cache data object 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");
+ GenerateUsageCounterIncrement(assembler, T0);
+ GenerateNArgsCheckInlineCacheStub(assembler, 1);
}
void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) {
- __ Unimplemented("GenerateTwoArgsCheckInlineCacheStub stub");
+ GenerateUsageCounterIncrement(assembler, T0);
+ GenerateNArgsCheckInlineCacheStub(assembler, 2);
}
void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) {
- __ Unimplemented("GenerateThreeArgsCheckInlineCacheStub stub");
+ GenerateUsageCounterIncrement(assembler, T0);
+ GenerateNArgsCheckInlineCacheStub(assembler, 3);
}
@@ -474,18 +855,106 @@
}
+// Used to check class and type arguments. Arguments passed in registers:
+// RA: return address.
+// A0: instance (must be preserved).
+// A1: instantiator type arguments or NULL.
+// A2: cache array.
+// Result in V0: null -> not found, otherwise result (true or false).
+static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
+ ASSERT((1 <= n) && (n <= 3));
+ if (n > 1) {
+ // Get instance type arguments.
+ __ LoadClass(T0, A0);
+ // Compute instance type arguments into R4.
+ Label has_no_type_arguments;
+ __ LoadImmediate(T1, reinterpret_cast<intptr_t>(Object::null()));
+ __ lw(T2, FieldAddress(T0,
+ Class::type_arguments_field_offset_in_words_offset()));
+ __ BranchEqual(T2, Class::kNoTypeArguments, &has_no_type_arguments);
+ __ sll(T2, T2, 2);
+ __ addu(T2, A0, T2); // T2 <- A0 + T2 * 4
+ __ lw(T1, FieldAddress(T2, 0));
+ __ Bind(&has_no_type_arguments);
+ }
+ __ LoadClassId(T0, A0);
+ // A0: instance.
+ // A1: instantiator type arguments or NULL.
+ // A2: SubtypeTestCache.
+ // T0: instance class id.
+ // T1: instance type arguments (null if none), used only if n > 1.
+ __ lw(T2, FieldAddress(A2, SubtypeTestCache::cache_offset()));
+ __ AddImmediate(T2, Array::data_offset() - kHeapObjectTag);
+
+ Label loop, found, not_found, next_iteration;
+ // T0: instance class id.
+ // T1: instance type arguments.
+ // T2: Entry start.
+ __ SmiTag(T0);
+ __ Bind(&loop);
+ __ lw(T3, Address(T2, kWordSize * SubtypeTestCache::kInstanceClassId));
+ __ BranchEqual(T3, reinterpret_cast<intptr_t>(Object::null()), &not_found);
+
+ if (n == 1) {
+ __ BranchEqual(T3, T0, &found);
+ } else {
+ __ BranchNotEqual(T3, T0, &next_iteration);
+ __ lw(T3,
+ Address(T2, kWordSize * SubtypeTestCache::kInstanceTypeArguments));
+ if (n == 2) {
+ __ BranchEqual(T3, T1, &found);
+ } else {
+ __ BranchNotEqual(T3, T1, &next_iteration);
+ __ lw(T3, Address(T2, kWordSize *
+ SubtypeTestCache::kInstantiatorTypeArguments));
+ __ BranchEqual(T3, A1, &found);
+ }
+ }
+ __ Bind(&next_iteration);
+ __ AddImmediate(T2, kWordSize * SubtypeTestCache::kTestEntryLength);
+ __ b(&loop);
+ // Fall through to not found.
+ __ Bind(&not_found);
+ __ LoadImmediate(V0, reinterpret_cast<intptr_t>(Object::null()));
+ __ Ret();
+
+ __ Bind(&found);
+ __ Ret();
+ __ delay_slot()->lw(V0,
+ Address(T2, kWordSize * SubtypeTestCache::kTestResult));
+}
+
+
+// Used to check class and type arguments. Arguments passed in registers:
+// RA: return address.
+// A0: instance (must be preserved).
+// A1: instantiator type arguments or NULL.
+// A2: cache array.
+// Result in V0: null -> not found, otherwise result (true or false).
void StubCode::GenerateSubtype1TestCacheStub(Assembler* assembler) {
- __ Unimplemented("Subtype1TestCache Stub");
+ GenerateSubtypeNTestCacheStub(assembler, 1);
}
+// Used to check class and type arguments. Arguments passed in registers:
+// LR: return address.
+// A0: instance (must be preserved).
+// A1: instantiator type arguments or NULL.
+// A2: cache array.
+// Result in V0: null -> not found, otherwise result (true or false).
void StubCode::GenerateSubtype2TestCacheStub(Assembler* assembler) {
- __ Unimplemented("Subtype2TestCache Stub");
+ GenerateSubtypeNTestCacheStub(assembler, 2);
}
+// Used to check class and type arguments. Arguments passed in registers:
+// RA: return address.
+// A0: instance (must be preserved).
+// A1: instantiator type arguments or NULL.
+// A2: cache array.
+// Result in V0: null -> not found, otherwise result (true or false).
void StubCode::GenerateSubtype3TestCacheStub(Assembler* assembler) {
- __ Unimplemented("Subtype3TestCache Stub");
+ GenerateSubtypeNTestCacheStub(assembler, 3);
}
@@ -511,17 +980,113 @@
void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) {
- __ Unimplemented("EqualityWithNullArg stub");
+ __ Unimplemented("EqualityWithNullArg Stub");
}
void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
- __ Unimplemented("OptimizeFunction stub");
+ __ Unimplemented("OptimizeFunction Stub");
}
+DECLARE_LEAF_RUNTIME_ENTRY(intptr_t,
+ BigintCompare,
+ RawBigint* left,
+ RawBigint* right);
+
+
+// Does identical check (object references are equal or not equal) with special
+// checks for boxed numbers.
+// LR: return address.
+// SP + 4: left operand.
+// SP + 0: right operand.
+// Return: CMPRES is zero if equal, non-zero otherwise.
+// Note: A Mint cannot contain a value that would fit in Smi, a Bigint
+// cannot contain a value that fits in Mint or Smi.
void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) {
- __ Unimplemented("IdenticalWithNumberCheck stub");
+ const Register ret = CMPRES;
+ const Register temp1 = TMP1;
+ const Register temp2 = TMP2;
+ const Register left = T1;
+ const Register right = T0;
+ // Preserve left, right and temp.
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(T1, Address(SP, 1 * kWordSize));
+ __ sw(T0, Address(SP, 0 * kWordSize));
+ // TOS + 4: left argument.
+ // TOS + 3: right argument.
+ // TOS + 1: saved left
+ // TOS + 0: saved right
+ __ lw(left, Address(SP, 3 * kWordSize));
+ __ lw(right, Address(SP, 2 * kWordSize));
+ Label reference_compare, done, check_mint, check_bigint;
+ // If any of the arguments is Smi do reference compare.
+ __ andi(temp1, left, Immediate(kSmiTagMask));
+ __ beq(temp1, ZR, &reference_compare);
+ __ andi(temp1, right, Immediate(kSmiTagMask));
+ __ beq(temp1, ZR, &reference_compare);
+
+ // Value compare for two doubles.
+ __ LoadImmediate(temp1, kDoubleCid);
+ __ LoadClassId(temp2, left);
+ __ bne(temp1, temp2, &check_mint);
+ __ LoadClassId(temp2, right);
+ __ subu(ret, temp1, temp2);
+ __ bne(ret, ZR, &done);
+
+ // Double values bitwise compare.
+ __ lw(temp1, FieldAddress(left, Double::value_offset() + 0 * kWordSize));
+ __ lw(temp1, FieldAddress(right, Double::value_offset() + 0 * kWordSize));
+ __ subu(ret, temp1, temp2);
+ __ bne(ret, ZR, &done);
+ __ lw(temp1, FieldAddress(left, Double::value_offset() + 1 * kWordSize));
+ __ lw(temp2, FieldAddress(right, Double::value_offset() + 1 * kWordSize));
+ __ b(&done);
+ __ delay_slot()->subu(ret, temp1, temp2);
+
+ __ Bind(&check_mint);
+ __ LoadImmediate(temp1, kMintCid);
+ __ LoadClassId(temp2, left);
+ __ bne(temp1, temp2, &check_bigint);
+ __ LoadClassId(temp2, right);
+ __ subu(ret, temp1, temp2);
+ __ bne(ret, ZR, &done);
+
+ __ lw(temp1, FieldAddress(left, Mint::value_offset() + 0 * kWordSize));
+ __ lw(temp2, FieldAddress(right, Mint::value_offset() + 0 * kWordSize));
+ __ subu(ret, temp1, temp2);
+ __ bne(ret, ZR, &done);
+ __ lw(temp1, FieldAddress(left, Mint::value_offset() + 1 * kWordSize));
+ __ lw(temp2, FieldAddress(right, Mint::value_offset() + 1 * kWordSize));
+ __ b(&done);
+ __ delay_slot()->subu(ret, temp1, temp2);
+
+ __ Bind(&check_bigint);
+ __ LoadImmediate(temp1, kBigintCid);
+ __ LoadClassId(temp2, left);
+ __ bne(temp1, temp2, &reference_compare);
+ __ LoadClassId(temp2, right);
+ __ subu(ret, temp1, temp2);
+ __ bne(ret, ZR, &done);
+
+ __ EnterStubFrame(0);
+ __ ReserveAlignedFrameSpace(2 * kWordSize);
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(T1, Address(SP, 1 * kWordSize));
+ __ sw(T0, Address(SP, 0 * kWordSize));
+ __ CallRuntime(kBigintCompareRuntimeEntry);
+ // Result in V0, 0 means equal.
+ __ LeaveStubFrame();
+ __ b(&done);
+ __ delay_slot()->mov(CMPRES, V0);
+
+ __ Bind(&reference_compare);
+ __ subu(ret, left, right);
+ __ Bind(&done);
+ __ lw(T0, Address(SP, 0 * kWordSize));
+ __ lw(T1, Address(SP, 1 * kWordSize));
+ __ Ret();
+ __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize));
}
} // namespace dart
« no previous file with comments | « runtime/vm/stub_code_arm.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698