Index: runtime/vm/flow_graph_compiler_arm.cc |
=================================================================== |
--- runtime/vm/flow_graph_compiler_arm.cc (revision 21708) |
+++ runtime/vm/flow_graph_compiler_arm.cc (working copy) |
@@ -111,14 +111,68 @@ |
} |
+// Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
+// type test is conclusive, otherwise fallthrough if a type test could not |
+// be completed. |
+// R0: instance being type checked (preserved). |
+// Clobbers R2. |
RawSubtypeTestCache* |
FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
intptr_t token_pos, |
const AbstractType& type, |
Label* is_instance_lbl, |
Label* is_not_instance_lbl) { |
- UNIMPLEMENTED(); |
- return NULL; |
+ __ Comment("InstantiatedTypeWithArgumentsTest"); |
+ ASSERT(type.IsInstantiated()); |
+ const Class& type_class = Class::ZoneHandle(type.type_class()); |
+ ASSERT(type_class.HasTypeArguments()); |
+ const Register kInstanceReg = R0; |
+ // A Smi object cannot be the instance of a parameterized class. |
+ __ tst(kInstanceReg, ShifterOperand(kSmiTagMask)); |
+ __ b(is_not_instance_lbl, EQ); |
+ const AbstractTypeArguments& type_arguments = |
+ AbstractTypeArguments::ZoneHandle(type.arguments()); |
+ const bool is_raw_type = type_arguments.IsNull() || |
+ type_arguments.IsRaw(type_arguments.Length()); |
+ if (is_raw_type) { |
+ const Register kClassIdReg = R2; |
+ // dynamic type argument, check only classes. |
+ __ LoadClassId(kClassIdReg, kInstanceReg); |
+ __ CompareImmediate(kClassIdReg, type_class.id()); |
+ __ b(is_instance_lbl, EQ); |
+ // List is a very common case. |
+ if (type_class.IsListClass()) { |
+ GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
+ } |
+ return GenerateSubtype1TestCacheLookup( |
+ token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
+ } |
+ // If one type argument only, check if type argument is Object or dynamic. |
+ if (type_arguments.Length() == 1) { |
+ const AbstractType& tp_argument = AbstractType::ZoneHandle( |
+ type_arguments.TypeAt(0)); |
+ ASSERT(!tp_argument.IsMalformed()); |
+ if (tp_argument.IsType()) { |
+ ASSERT(tp_argument.HasResolvedTypeClass()); |
+ // Check if type argument is dynamic or Object. |
+ const Type& object_type = Type::Handle(Type::ObjectType()); |
+ if (object_type.IsSubtypeOf(tp_argument, NULL)) { |
+ // Instance class test only necessary. |
+ return GenerateSubtype1TestCacheLookup( |
+ token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
+ } |
+ } |
+ } |
+ // Regular subtype test cache involving instance's type arguments. |
+ const Register kTypeArgumentsReg = kNoRegister; |
+ const Register kTempReg = kNoRegister; |
+ // R0: instance (must be preserved). |
+ return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, |
+ kInstanceReg, |
+ kTypeArgumentsReg, |
+ kTempReg, |
+ is_instance_lbl, |
+ is_not_instance_lbl); |
} |