Index: runtime/vm/flow_graph_compiler_mips.cc |
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc |
index 56e934f72fe27cccbf5a4e9bb2af453f77ece00c..96be50c3d173873e6dddf46f263c8de8a9a753d8 100644 |
--- a/runtime/vm/flow_graph_compiler_mips.cc |
+++ b/runtime/vm/flow_graph_compiler_mips.cc |
@@ -201,10 +201,13 @@ void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
// A0: instance (must be preserved). |
// A1: instantiator type arguments (if used). |
+// A2: function type arguments (if used). |
+// Clobbers A3. |
RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
TypeTestStubKind test_kind, |
Register instance_reg, |
- Register type_arguments_reg, |
+ Register instantiator_type_arguments_reg, |
+ Register function_type_arguments_reg, |
Register temp_reg, |
Label* is_instance_lbl, |
Label* is_not_instance_lbl) { |
@@ -213,18 +216,19 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
ASSERT(temp_reg == kNoRegister); // Unused on MIPS. |
const SubtypeTestCache& type_test_cache = |
SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
- __ LoadUniqueObject(A2, type_test_cache); |
+ __ LoadUniqueObject(A3, type_test_cache); |
if (test_kind == kTestTypeOneArg) { |
- ASSERT(type_arguments_reg == kNoRegister); |
- __ LoadObject(A1, Object::null_object()); |
+ ASSERT(instantiator_type_arguments_reg == kNoRegister); |
+ ASSERT(function_type_arguments_reg == kNoRegister); |
__ BranchLink(*StubCode::Subtype1TestCache_entry()); |
} else if (test_kind == kTestTypeTwoArgs) { |
- ASSERT(type_arguments_reg == kNoRegister); |
- __ LoadObject(A1, Object::null_object()); |
+ ASSERT(instantiator_type_arguments_reg == kNoRegister); |
+ ASSERT(function_type_arguments_reg == kNoRegister); |
__ BranchLink(*StubCode::Subtype2TestCache_entry()); |
- } else if (test_kind == kTestTypeThreeArgs) { |
- ASSERT(type_arguments_reg == A1); |
- __ BranchLink(*StubCode::Subtype3TestCache_entry()); |
+ } else if (test_kind == kTestTypeFourArgs) { |
+ ASSERT(instantiator_type_arguments_reg == A1); |
+ ASSERT(function_type_arguments_reg == A2); |
+ __ BranchLink(*StubCode::Subtype4TestCache_entry()); |
} else { |
UNREACHABLE(); |
} |
@@ -301,11 +305,13 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
} |
} |
// Regular subtype test cache involving instance's type arguments. |
- const Register kTypeArgumentsReg = kNoRegister; |
+ const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
+ const Register kFunctionTypeArgumentsReg = kNoRegister; |
const Register kTempReg = kNoRegister; |
// A0: instance (must be preserved). |
return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
- kTypeArgumentsReg, kTempReg, |
+ kInstantiatorTypeArgumentsReg, |
+ kFunctionTypeArgumentsReg, kTempReg, |
is_instance_lbl, is_not_instance_lbl); |
} |
@@ -389,7 +395,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
// Uses SubtypeTestCache to store instance class and result. |
// A0: instance to test. |
-// Clobbers A1, A2, T0-T3. |
+// Clobbers A1-A3, T0-T3. |
// Immediate class test already done. |
// TODO(srdjan): Implement a quicker subtype check, as type test |
// arrays can grow too high, but they may be useful when optimizing |
@@ -409,10 +415,12 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
__ BranchEqual(T0, Immediate(Smi::RawValue(type_class.id())), |
is_instance_lbl); |
- const Register kTypeArgumentsReg = kNoRegister; |
+ const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
+ const Register kFunctionTypeArgumentsReg = kNoRegister; |
const Register kTempReg = kNoRegister; |
return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
- kTypeArgumentsReg, kTempReg, |
+ kInstantiatorTypeArgumentsReg, |
+ kFunctionTypeArgumentsReg, kTempReg, |
is_instance_lbl, is_not_instance_lbl); |
} |
@@ -429,19 +437,23 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
// Skip check if destination is a dynamic type. |
if (type.IsTypeParameter()) { |
const TypeParameter& type_param = TypeParameter::Cast(type); |
- // Load instantiator type arguments on stack. |
- __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. |
+ __ lw(A1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
+ __ lw(A2, Address(SP, 0 * kWordSize)); // Get function type args. |
// A1: instantiator type arguments. |
+ // A2: function type arguments. |
+ const Register kTypeArgumentsReg = |
+ type_param.IsClassTypeParameter() ? A1 : A2; |
// Check if type arguments are null, i.e. equivalent to vector of dynamic. |
__ LoadObject(T7, Object::null_object()); |
- __ beq(A1, T7, is_instance_lbl); |
- __ lw(T2, |
- FieldAddress(A1, TypeArguments::type_at_offset(type_param.index()))); |
- // R2: concrete type of type. |
+ __ beq(kTypeArgumentsReg, T7, is_instance_lbl); |
+ __ lw(T2, FieldAddress(kTypeArgumentsReg, |
+ TypeArguments::type_at_offset(type_param.index()))); |
+ // T2: concrete type of type. |
// Check if type argument is dynamic. |
__ BranchEqual(T2, Object::dynamic_type(), is_instance_lbl); |
__ BranchEqual(T2, Type::ZoneHandle(zone(), Type::ObjectType()), |
is_instance_lbl); |
+ // TODO(regis): Optimize void type as well once allowed as type argument. |
// For Smi check quickly against int and num interfaces. |
Label not_smi; |
@@ -456,29 +468,35 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
__ b(&fall_through); |
__ Bind(¬_smi); |
- // T1: instantiator type arguments. |
// A0: instance. |
+ // A1: instantiator type arguments. |
+ // A2: function type arguments. |
const Register kInstanceReg = A0; |
- const Register kTypeArgumentsReg = A1; |
+ const Register kInstantiatorTypeArgumentsReg = A1; |
+ const Register kFunctionTypeArgumentsReg = A2; |
const Register kTempReg = kNoRegister; |
const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
zone(), GenerateCallSubtypeTestStub( |
- kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, |
+ kTestTypeFourArgs, kInstanceReg, |
+ kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, |
kTempReg, is_instance_lbl, is_not_instance_lbl)); |
__ Bind(&fall_through); |
return type_test_cache.raw(); |
} |
if (type.IsType()) { |
const Register kInstanceReg = A0; |
- const Register kTypeArgumentsReg = A1; |
+ const Register kInstantiatorTypeArgumentsReg = A1; |
+ const Register kFunctionTypeArgumentsReg = A2; |
__ andi(CMPRES1, kInstanceReg, Immediate(kSmiTagMask)); |
__ beq(CMPRES1, ZR, is_not_instance_lbl); // Is instance Smi? |
- __ lw(kTypeArgumentsReg, Address(SP, 0)); // Instantiator type args. |
+ __ lw(kInstantiatorTypeArgumentsReg, Address(SP, 1 * kWordSize)); |
+ __ lw(kFunctionTypeArgumentsReg, Address(SP, 0 * kWordSize)); |
// Uninstantiated type class is known at compile time, but the type |
// arguments are determined at runtime by the instantiator. |
const Register kTempReg = kNoRegister; |
- return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, |
- kTypeArgumentsReg, kTempReg, |
+ return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, |
+ kInstantiatorTypeArgumentsReg, |
+ kFunctionTypeArgumentsReg, kTempReg, |
is_instance_lbl, is_not_instance_lbl); |
} |
return SubtypeTestCache::null(); |
@@ -488,8 +506,10 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
// Inputs: |
// - A0: instance being type checked (preserved). |
// - A1: optional instantiator type arguments (preserved). |
+// - A2: optional function type arguments (preserved). |
// Returns: |
-// - preserved instance in A0 and optional instantiator type arguments in A1. |
+// - preserved instance in A0, optional instantiator type arguments in A1, and |
+// optional function type arguments in A2. |
// Clobbers: T0, T1, T2 |
// Note that this inlined code must be followed by the runtime_call code, as it |
// may fall through to it. Otherwise, this inline code will jump to the label |
@@ -539,6 +559,7 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
// Inputs: |
// - A0: object. |
// - A1: instantiator type arguments or raw_null. |
+// - A2: function type arguments or raw_null. |
// Returns: |
// - true or false in V0. |
void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
@@ -548,9 +569,10 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); |
ASSERT(!type.IsObjectType() && !type.IsDynamicType()); |
- // Preserve instantiator type arguments (A1). |
- __ addiu(SP, SP, Immediate(-1 * kWordSize)); |
- __ sw(A1, Address(SP, 0 * kWordSize)); |
+ // Preserve instantiator type arguments (A1) and function type arguments (A2). |
+ __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
+ __ sw(A1, Address(SP, 1 * kWordSize)); |
+ __ sw(A2, Address(SP, 0 * kWordSize)); |
Label is_instance, is_not_instance; |
// If type is instantiated and non-parameterized, we can inline code |
@@ -576,25 +598,24 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
Label done; |
if (!test_cache.IsNull()) { |
// Generate runtime call. |
- // Load instantiator type arguments (A1). |
- __ lw(A1, Address(SP, 0 * kWordSize)); |
- |
- __ addiu(SP, SP, Immediate(-5 * kWordSize)); |
+ __ lw(A1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
+ __ lw(A2, Address(SP, 0 * kWordSize)); // Get function type args. |
+ __ addiu(SP, SP, Immediate(-6 * kWordSize)); |
__ LoadObject(TMP, Object::null_object()); |
- __ sw(TMP, Address(SP, 4 * kWordSize)); // Make room for the result. |
- __ sw(A0, Address(SP, 3 * kWordSize)); // Push the instance. |
+ __ sw(TMP, Address(SP, 5 * kWordSize)); // Make room for the result. |
+ __ sw(A0, Address(SP, 4 * kWordSize)); // Push the instance. |
__ LoadObject(TMP, type); |
- __ sw(TMP, Address(SP, 2 * kWordSize)); // Push the type. |
- __ sw(A1, Address(SP, 1 * kWordSize)); // Push type arguments. |
+ __ sw(TMP, Address(SP, 3 * kWordSize)); // Push the type. |
+ __ sw(A1, Address(SP, 2 * kWordSize)); // Push instantiator type args. |
+ __ sw(A2, Address(SP, 1 * kWordSize)); // Push function type args. |
__ LoadUniqueObject(A0, test_cache); |
__ sw(A0, Address(SP, 0 * kWordSize)); |
- GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); |
+ GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); |
// Pop the parameters supplied to the runtime entry. The result of the |
// instanceof runtime call will be left as the result of the operation. |
- __ lw(T0, Address(SP, 4 * kWordSize)); |
- __ addiu(SP, SP, Immediate(5 * kWordSize)); |
- __ mov(V0, T0); |
+ __ lw(V0, Address(SP, 5 * kWordSize)); |
__ b(&done); |
+ __ delay_slot()->addiu(SP, SP, Immediate(6 * kWordSize)); |
} |
__ Bind(&is_not_instance); |
__ LoadObject(V0, Bool::Get(false)); |
@@ -603,8 +624,8 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
__ Bind(&is_instance); |
__ LoadObject(V0, Bool::Get(true)); |
__ Bind(&done); |
- // Remove instantiator type arguments (A1). |
- __ Drop(1); |
+ // Remove instantiator type arguments and function type arguments. |
+ __ Drop(2); |
} |
@@ -615,6 +636,7 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
// Inputs: |
// - A0: instance being type checked. |
// - A1: instantiator type arguments or raw_null. |
+// - A2: function type arguments or raw_null. |
// Returns: |
// - object in A0 for successful assignable check (or throws TypeError). |
// Clobbers: T0, T1, T2 |
@@ -632,15 +654,16 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
// Assignable check is skipped in FlowGraphBuilder, not here. |
ASSERT(dst_type.IsMalformedOrMalbounded() || |
(!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
- // Preserve instantiator type arguments. |
- __ addiu(SP, SP, Immediate(-1 * kWordSize)); |
- __ sw(A1, Address(SP, 0 * kWordSize)); |
+ |
+ // Preserve instantiator type arguments (A1) and function type arguments (A2). |
+ __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
+ __ sw(A1, Address(SP, 1 * kWordSize)); |
+ __ sw(A2, Address(SP, 0 * kWordSize)); |
// A null object is always assignable and is returned as result. |
Label is_assignable, runtime_call; |
__ BranchEqual(A0, Object::null_object(), &is_assignable); |
- __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize)); |
// Generate throw new TypeError() if the type is malformed or malbounded. |
if (dst_type.IsMalformedOrMalbounded()) { |
@@ -659,9 +682,9 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
__ break_(0); |
__ Bind(&is_assignable); // For a null object. |
- // Restore instantiator type arguments. |
- __ lw(A1, Address(SP, 0 * kWordSize)); |
- __ addiu(SP, SP, Immediate(1 * kWordSize)); |
+ __ lw(A1, Address(SP, 1 * kWordSize)); // Restore instantiator type args. |
+ __ lw(A2, Address(SP, 0 * kWordSize)); // Restore function type args. |
+ __ addiu(SP, SP, Immediate(2 * kWordSize)); |
return; |
} |
@@ -671,31 +694,32 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
&runtime_call); |
__ Bind(&runtime_call); |
- // Load instantiator type arguments (A1). |
- __ lw(A1, Address(SP, 0 * kWordSize)); |
+ __ lw(A1, Address(SP, 1 * kWordSize)); // Load instantiator type args. |
+ __ lw(A2, Address(SP, 0 * kWordSize)); // Load function type args. |
- __ addiu(SP, SP, Immediate(-6 * kWordSize)); |
+ __ addiu(SP, SP, Immediate(-7 * kWordSize)); |
__ LoadObject(TMP, Object::null_object()); |
- __ sw(TMP, Address(SP, 5 * kWordSize)); // Make room for the result. |
- __ sw(A0, Address(SP, 4 * kWordSize)); // Push the source object. |
+ __ sw(TMP, Address(SP, 6 * kWordSize)); // Make room for the result. |
+ __ sw(A0, Address(SP, 5 * kWordSize)); // Push the source object. |
__ LoadObject(TMP, dst_type); |
- __ sw(TMP, Address(SP, 3 * kWordSize)); // Push the type of the destination. |
- __ sw(A1, Address(SP, 2 * kWordSize)); // Push type arguments. |
+ __ sw(TMP, Address(SP, 4 * kWordSize)); // Push the type of the destination. |
+ __ sw(A1, Address(SP, 3 * kWordSize)); // Push instantiator type args. |
+ __ sw(A2, Address(SP, 2 * kWordSize)); // Push function type args. |
__ LoadObject(TMP, dst_name); |
__ sw(TMP, Address(SP, 1 * kWordSize)); // Push the name of the destination. |
__ LoadUniqueObject(T0, test_cache); |
__ sw(T0, Address(SP, 0 * kWordSize)); |
- GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); |
+ GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
// Pop the parameters supplied to the runtime entry. The result of the |
// type check runtime call is the checked value. |
- __ lw(A0, Address(SP, 5 * kWordSize)); |
- __ addiu(SP, SP, Immediate(6 * kWordSize)); |
+ __ lw(A0, Address(SP, 6 * kWordSize)); |
+ __ addiu(SP, SP, Immediate(7 * kWordSize)); |
__ Bind(&is_assignable); |
- // Restore instantiator type arguments. |
- __ lw(A1, Address(SP, 0 * kWordSize)); |
- __ addiu(SP, SP, Immediate(1 * kWordSize)); |
+ __ lw(A1, Address(SP, 1 * kWordSize)); // Restore instantiator type args. |
+ __ lw(A2, Address(SP, 0 * kWordSize)); // Restore function type args. |
+ __ addiu(SP, SP, Immediate(2 * kWordSize)); |
} |