Index: runtime/vm/intrinsifier_mips.cc |
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc |
index ff354af7f4455fce5ca87bb738162f61e4f2b3ac..aa512ad211b3fe290025346da25961f43a1970e9 100644 |
--- a/runtime/vm/intrinsifier_mips.cc |
+++ b/runtime/vm/intrinsifier_mips.cc |
@@ -1689,15 +1689,109 @@ void Intrinsifier::ObjectEquals(Assembler* assembler) { |
} |
+enum RangeCheckCondition { |
+ kIfNotInRange, kIfInRange |
+}; |
+ |
+ |
+static void RangeCheck(Assembler* assembler, |
+ Register val, |
+ Register tmp, |
+ intptr_t low, |
+ intptr_t high, |
+ RangeCheckCondition cc, |
+ Label* target) { |
+ __ AddImmediate(tmp, val, -low); |
+ if (cc == kIfInRange) { |
+ __ BranchUnsignedLessEqual(tmp, Immediate(high - low), target); |
+ } else { |
+ ASSERT(cc == kIfNotInRange); |
+ __ BranchUnsignedGreater(tmp, Immediate(high - low), target); |
+ } |
+} |
+ |
+ |
+static void JumpIfInteger(Assembler* assembler, |
+ Register cid, |
+ Register tmp, |
+ Label* target) { |
+ RangeCheck(assembler, cid, tmp, kSmiCid, kBigintCid, kIfInRange, target); |
+} |
+ |
+ |
+static void JumpIfNotInteger(Assembler* assembler, |
+ Register cid, |
+ Register tmp, |
+ Label* target) { |
+ RangeCheck(assembler, cid, tmp, kSmiCid, kBigintCid, kIfNotInRange, target); |
+} |
+ |
+ |
+static void JumpIfString(Assembler* assembler, |
+ Register cid, |
+ Register tmp, |
+ Label* target) { |
+ RangeCheck(assembler, |
+ cid, |
+ tmp, |
+ kOneByteStringCid, |
+ kExternalTwoByteStringCid, |
+ kIfInRange, |
+ target); |
+} |
+ |
+ |
+static void JumpIfNotString(Assembler* assembler, |
+ Register cid, |
+ Register tmp, |
+ Label* target) { |
+ RangeCheck(assembler, |
+ cid, |
+ tmp, |
+ kOneByteStringCid, |
+ kExternalTwoByteStringCid, |
+ kIfNotInRange, |
+ target); |
+} |
+ |
+ |
// Return type quickly for simple types (not parameterized and not signature). |
void Intrinsifier::ObjectRuntimeType(Assembler* assembler) { |
- Label fall_through; |
+ Label fall_through, use_canonical_type, not_integer, not_double; |
__ lw(T0, Address(SP, 0 * kWordSize)); |
__ LoadClassIdMayBeSmi(T1, T0); |
+ |
+ // Closures are handled in the runtime. |
__ BranchEqual(T1, Immediate(kClosureCid), &fall_through); |
- __ LoadClassById(T2, T1); |
- // T2: class of instance (T0). |
+ __ BranchUnsignedGreaterEqual( |
+ T1, Immediate(kNumPredefinedCids), &use_canonical_type); |
+ |
+ __ BranchNotEqual(T1, Immediate(kDoubleCid), ¬_double); |
+ // Object is a double. |
+ __ LoadIsolate(T1); |
+ __ LoadFromOffset(T1, T1, Isolate::object_store_offset()); |
+ __ LoadFromOffset(V0, T1, ObjectStore::double_type_offset()); |
+ __ Ret(); |
+ |
+ __ Bind(¬_double); |
+ JumpIfNotInteger(assembler, T1, T2, ¬_integer); |
+ // Object is an integer. |
+ __ LoadIsolate(T1); |
+ __ LoadFromOffset(T1, T1, Isolate::object_store_offset()); |
+ __ LoadFromOffset(V0, T1, ObjectStore::int_type_offset()); |
+ __ Ret(); |
+ |
+ __ Bind(¬_integer); |
+ JumpIfNotString(assembler, T1, T2, &use_canonical_type); |
+ // Object is a string. |
+ __ LoadIsolate(T1); |
+ __ LoadFromOffset(T1, T1, Isolate::object_store_offset()); |
+ __ LoadFromOffset(V0, T1, ObjectStore::string_type_offset()); |
+ __ Ret(); |
+ |
+ __ Bind(&use_canonical_type); |
+ __ LoadClassById(T2, T1); |
__ lhu(T1, FieldAddress(T2, Class::num_type_arguments_offset())); |
__ BranchNotEqual(T1, Immediate(0), &fall_through); |
@@ -1709,6 +1803,59 @@ void Intrinsifier::ObjectRuntimeType(Assembler* assembler) { |
} |
+void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) { |
+ Label fall_through, different_cids, equal, not_equal, not_integer; |
+ |
+ __ lw(T0, Address(SP, 0 * kWordSize)); |
+ __ LoadClassIdMayBeSmi(T1, T0); |
+ |
+ // Closures are handled in the runtime. |
+ __ BranchEqual(T1, Immediate(kClosureCid), &fall_through); |
+ |
+ __ lw(T0, Address(SP, 1 * kWordSize)); |
+ __ LoadClassIdMayBeSmi(T2, T0); |
+ |
+ // Check whether class ids match. If class ids don't match objects can still |
+ // have the same runtime type (e.g. multiple string implementation classes |
+ // map to a single String type). |
+ __ BranchNotEqual(T1, T2, &different_cids); |
+ |
+ // Objects have the same class and neither is a closure. |
+ // Check if there are no type arguments. In this case we can return true. |
+ // Otherwise fall through into the runtime to handle comparison. |
+ __ LoadClassById(T2, T1); |
+ __ lhu(T1, FieldAddress(T2, Class::num_type_arguments_offset())); |
+ __ BranchNotEqual(T1, Immediate(0), &fall_through); |
+ |
+ __ Bind(&equal); |
+ __ LoadObject(V0, Bool::True()); |
+ __ Ret(); |
+ |
+ // Class ids are different. Check if we are comparing runtime types of |
+ // two strings (with different representations) or two integers. |
+ __ Bind(&different_cids); |
+ __ BranchUnsignedGreaterEqual( |
+ T1, Immediate(kNumPredefinedCids), ¬_equal); |
+ |
+ // Check if both are integers. |
+ JumpIfNotInteger(assembler, T1, T0, ¬_integer); |
+ JumpIfInteger(assembler, T2, T0, &equal); |
+ __ b(¬_equal); |
+ |
+ __ Bind(¬_integer); |
+ // Check if both are strings. |
+ JumpIfNotString(assembler, T1, T0, ¬_equal); |
+ JumpIfString(assembler, T2, T0, &equal); |
+ |
+ // Neither strings nor integers and have different class ids. |
+ __ Bind(¬_equal); |
+ __ LoadObject(V0, Bool::False()); |
+ __ Ret(); |
+ |
+ __ Bind(&fall_through); |
+} |
+ |
+ |
void Intrinsifier::String_getHashCode(Assembler* assembler) { |
Label fall_through; |
__ lw(T0, Address(SP, 0 * kWordSize)); |