| Index: runtime/vm/flow_graph_compiler_arm64.cc
|
| diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
|
| index 6f02236c483f9568f99b6bb6f4168a35dad99857..3a8310a89778ba27fdb203f1192c3f534445cbed 100644
|
| --- a/runtime/vm/flow_graph_compiler_arm64.cc
|
| +++ b/runtime/vm/flow_graph_compiler_arm64.cc
|
| @@ -202,29 +202,32 @@ void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
|
|
|
| // R0: instance (must be preserved).
|
| // R1: instantiator type arguments (if used).
|
| +// R2: function type arguments (if used).
|
| 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) {
|
| ASSERT(instance_reg == R0);
|
| - ASSERT(temp_reg == kNoRegister); // Unused on ARM.
|
| + ASSERT(temp_reg == kNoRegister); // Unused on ARM64.
|
| const SubtypeTestCache& type_test_cache =
|
| SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
|
| - __ LoadUniqueObject(R2, type_test_cache);
|
| + __ LoadUniqueObject(R3, type_test_cache);
|
| if (test_kind == kTestTypeOneArg) {
|
| - ASSERT(type_arguments_reg == kNoRegister);
|
| - __ LoadObject(R1, 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(R1, 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 == R1);
|
| - __ BranchLink(*StubCode::Subtype3TestCache_entry());
|
| + } else if (test_kind == kTestTypeFourArgs) {
|
| + ASSERT(instantiator_type_arguments_reg == R1);
|
| + ASSERT(function_type_arguments_reg == R2);
|
| + __ BranchLink(*StubCode::Subtype4TestCache_entry());
|
| } else {
|
| UNREACHABLE();
|
| }
|
| @@ -238,7 +241,7 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
|
| // type test is conclusive, otherwise fallthrough if a type test could not
|
| // be completed.
|
| // R0: instance being type checked (preserved).
|
| -// Clobbers R2.
|
| +// Clobbers R1, R2.
|
| RawSubtypeTestCache*
|
| FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
|
| TokenPosition token_pos,
|
| @@ -302,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;
|
| // R0: instance (must be preserved).
|
| return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg,
|
| - kTypeArgumentsReg, kTempReg,
|
| + kInstantiatorTypeArgumentsReg,
|
| + kFunctionTypeArgumentsReg, kTempReg,
|
| is_instance_lbl, is_not_instance_lbl);
|
| }
|
|
|
| @@ -413,10 +418,12 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
|
| __ CompareImmediate(R2, Smi::RawValue(type_class.id()));
|
| __ b(is_instance_lbl, EQ);
|
|
|
| - 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);
|
| }
|
|
|
| @@ -433,28 +440,32 @@ 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.
|
| - __ ldr(R1, Address(SP)); // Get instantiator type arguments.
|
| + // Get instantiator type args (high, R1) and function type args (low, R2).
|
| + __ ldp(R2, R1, Address(SP, 0 * kWordSize, Address::PairOffset));
|
| // R1: instantiator type arguments.
|
| + // R2: function type arguments.
|
| + const Register kTypeArgumentsReg =
|
| + type_param.IsClassTypeParameter() ? R1 : R2;
|
| // Check if type arguments are null, i.e. equivalent to vector of dynamic.
|
| - __ CompareObject(R1, Object::null_object());
|
| + __ CompareObject(kTypeArgumentsReg, Object::null_object());
|
| __ b(is_instance_lbl, EQ);
|
| - __ LoadFieldFromOffset(R2, R1,
|
| + __ LoadFieldFromOffset(R3, kTypeArgumentsReg,
|
| TypeArguments::type_at_offset(type_param.index()));
|
| - // R2: concrete type of type.
|
| + // R3: concrete type of type.
|
| // Check if type argument is dynamic.
|
| - __ CompareObject(R2, Object::dynamic_type());
|
| + __ CompareObject(R3, Object::dynamic_type());
|
| __ b(is_instance_lbl, EQ);
|
| - __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType()));
|
| + __ CompareObject(R3, Type::ZoneHandle(zone(), Type::ObjectType()));
|
| __ b(is_instance_lbl, EQ);
|
| + // TODO(regis): Optimize void type as well once allowed as type argument.
|
|
|
| // For Smi check quickly against int and num interfaces.
|
| Label not_smi;
|
| __ tsti(R0, Immediate(kSmiTagMask)); // Value is Smi?
|
| __ b(¬_smi, NE);
|
| - __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType()));
|
| + __ CompareObject(R3, Type::ZoneHandle(zone(), Type::IntType()));
|
| __ b(is_instance_lbl, EQ);
|
| - __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number()));
|
| + __ CompareObject(R3, Type::ZoneHandle(zone(), Type::Number()));
|
| __ b(is_instance_lbl, EQ);
|
| // Smi must be handled in runtime.
|
| Label fall_through;
|
| @@ -462,28 +473,34 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
|
|
|
| __ Bind(¬_smi);
|
| // R1: instantiator type arguments.
|
| + // R2: function type arguments.
|
| // R0: instance.
|
| const Register kInstanceReg = R0;
|
| - const Register kTypeArgumentsReg = R1;
|
| + const Register kInstantiatorTypeArgumentsReg = R1;
|
| + const Register kFunctionTypeArgumentsReg = R2;
|
| 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 = R0;
|
| - const Register kTypeArgumentsReg = R1;
|
| + const Register kInstantiatorTypeArgumentsReg = R1;
|
| + const Register kFunctionTypeArgumentsReg = R2;
|
| __ tsti(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi?
|
| __ b(is_not_instance_lbl, EQ);
|
| - __ ldr(kTypeArgumentsReg, Address(SP)); // Instantiator type args.
|
| + __ ldp(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg,
|
| + Address(SP, 0 * kWordSize, Address::PairOffset));
|
| // 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();
|
| @@ -493,9 +510,11 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
|
| // Inputs:
|
| // - R0: instance being type checked (preserved).
|
| // - R1: optional instantiator type arguments (preserved).
|
| -// Clobbers R2, R3.
|
| +// - R2: optional function type arguments (preserved).
|
| +// Clobbers R3, R4, R8, R9.
|
| // Returns:
|
| -// - preserved instance in R0 and optional instantiator type arguments in R1.
|
| +// - preserved instance in R0, optional instantiator type arguments in R1, and
|
| +// optional function type arguments in R2.
|
| // 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
|
| // is_instance or to the label is_not_instance.
|
| @@ -544,6 +563,7 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
|
| // Inputs:
|
| // - R0: object.
|
| // - R1: instantiator type arguments or raw_null.
|
| +// - R2: function type arguments or raw_null.
|
| // Returns:
|
| // - true or false in R0.
|
| void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
|
| @@ -552,10 +572,9 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
|
| LocationSummary* locs) {
|
| ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded());
|
| ASSERT(!type.IsObjectType() && !type.IsDynamicType());
|
| -
|
| - // Preserve instantiator type arguments (R1).
|
| - __ Push(R1);
|
| -
|
| + const Register kInstantiatorTypeArgumentsReg = R1;
|
| + const Register kFunctionTypeArgumentsReg = R2;
|
| + __ PushPair(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
|
| Label is_instance, is_not_instance;
|
| // If type is instantiated and non-parameterized, we can inline code
|
| // checking whether the tested instance is a Smi.
|
| @@ -580,18 +599,20 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
|
| Label done;
|
| if (!test_cache.IsNull()) {
|
| // Generate runtime call.
|
| - // Load instantiator (R2) and its type arguments (R1).
|
| - __ ldr(R1, Address(SP, 0 * kWordSize));
|
| + const Register kInstantiatorTypeArgumentsReg = R1;
|
| + const Register kFunctionTypeArgumentsReg = R2;
|
| + __ ldp(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg,
|
| + Address(SP, 0 * kWordSize, Address::PairOffset));
|
| __ PushObject(Object::null_object()); // Make room for the result.
|
| __ Push(R0); // Push the instance.
|
| __ PushObject(type); // Push the type.
|
| - __ Push(R1); // Push instantiator type arguments (R1).
|
| + __ PushPair(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
|
| __ LoadUniqueObject(R0, test_cache);
|
| __ Push(R0);
|
| - 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.
|
| - __ Drop(4);
|
| + __ Drop(5);
|
| __ Pop(R0);
|
| __ b(&done);
|
| }
|
| @@ -602,8 +623,8 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
|
| __ Bind(&is_instance);
|
| __ LoadObject(R0, Bool::Get(true));
|
| __ Bind(&done);
|
| - // Remove instantiator type arguments (R1).
|
| - __ Drop(1);
|
| + // Remove instantiator type arguments and function type arguments.
|
| + __ Drop(2);
|
| }
|
|
|
|
|
| @@ -614,6 +635,7 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
|
| // Inputs:
|
| // - R0: instance being type checked.
|
| // - R1: instantiator type arguments or raw_null.
|
| +// - R2: function type arguments or raw_null.
|
| // Returns:
|
| // - object in R0 for successful assignable check (or throws TypeError).
|
| // Performance notes: positive checks must be quick, negative checks can be slow
|
| @@ -629,8 +651,9 @@ 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 (R1).
|
| - __ Push(R1);
|
| + const Register kInstantiatorTypeArgumentsReg = R1;
|
| + const Register kFunctionTypeArgumentsReg = R2;
|
| + __ PushPair(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
|
| // A null object is always assignable and is returned as result.
|
| Label is_assignable, runtime_call;
|
| __ CompareObject(R0, Object::null_object());
|
| @@ -648,8 +671,7 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
|
| __ brk(0);
|
|
|
| __ Bind(&is_assignable); // For a null object.
|
| - // Restore instantiator type arguments (R1).
|
| - __ Pop(R1);
|
| + __ PopPair(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
|
| return;
|
| }
|
|
|
| @@ -659,23 +681,23 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
|
| &runtime_call);
|
|
|
| __ Bind(&runtime_call);
|
| - __ ldr(R1, Address(SP)); // Load instantiator type arguments (R1).
|
| + __ ldp(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg,
|
| + Address(SP, 0 * kWordSize, Address::PairOffset));
|
| __ PushObject(Object::null_object()); // Make room for the result.
|
| __ Push(R0); // Push the source object.
|
| __ PushObject(dst_type); // Push the type of the destination.
|
| - __ Push(R1); // Push instantiator type arguments (R1).
|
| + __ PushPair(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
|
| __ PushObject(dst_name); // Push the name of the destination.
|
| __ LoadUniqueObject(R0, test_cache);
|
| __ Push(R0);
|
| - 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.
|
| - __ Drop(5);
|
| + __ Drop(6);
|
| __ Pop(R0);
|
|
|
| __ Bind(&is_assignable);
|
| - // Restore instantiator type arguments (R1).
|
| - __ Pop(R1);
|
| + __ PopPair(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
|
| }
|
|
|
|
|
|
|