[VM/compiler] Cleanup ABIs for instantiation and type testing code and stubs.
Change-Id: Ifc211c98804fcaff5b7788f6823ea631d2867974 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/140441 Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Régis Crelier <regis@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
6ce852bd89
commit
0bc8474383
@@ -359,8 +359,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
|
||||
const Class& type_class = Class::Handle(zone(), type.type_class());
|
||||
ASSERT(type_class.NumTypeArguments() == 0);
|
||||
|
||||
const Register kInstanceReg = R0;
|
||||
__ tst(kInstanceReg, compiler::Operand(kSmiTagMask));
|
||||
__ tst(TypeTestABI::kInstanceReg, compiler::Operand(kSmiTagMask));
|
||||
// If instance is Smi, check directly.
|
||||
const Class& smi_class = Class::Handle(zone(), Smi::Class());
|
||||
if (Class::IsSubtypeOf(smi_class, Object::null_type_arguments(), type,
|
||||
@@ -371,7 +370,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
|
||||
__ b(is_not_instance_lbl, EQ);
|
||||
}
|
||||
const Register kClassIdReg = R2;
|
||||
__ LoadClassId(kClassIdReg, kInstanceReg);
|
||||
__ LoadClassId(kClassIdReg, TypeTestABI::kInstanceReg);
|
||||
// Bool interface can be implemented only by core class Bool.
|
||||
if (type.IsBoolType()) {
|
||||
__ CompareImmediate(kClassIdReg, kBoolCid);
|
||||
@@ -460,7 +459,8 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
|
||||
// Skip check if destination is a dynamic type.
|
||||
if (type.IsTypeParameter()) {
|
||||
const TypeParameter& type_param = TypeParameter::Cast(type);
|
||||
static_assert(kFunctionTypeArgumentsReg < kInstantiatorTypeArgumentsReg,
|
||||
static_assert(TypeTestABI::kFunctionTypeArgumentsReg <
|
||||
TypeTestABI::kInstantiatorTypeArgumentsReg,
|
||||
"Should be ordered to load arguments with one instruction");
|
||||
__ ldm(IA, SP,
|
||||
(1 << TypeTestABI::kFunctionTypeArgumentsReg) |
|
||||
|
||||
@@ -346,18 +346,17 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
|
||||
const Class& type_class = Class::Handle(zone(), type.type_class());
|
||||
ASSERT(type_class.NumTypeArguments() == 0);
|
||||
|
||||
const Register kInstanceReg = R0;
|
||||
// If instance is Smi, check directly.
|
||||
const Class& smi_class = Class::Handle(zone(), Smi::Class());
|
||||
if (Class::IsSubtypeOf(smi_class, Object::null_type_arguments(), type,
|
||||
Heap::kOld)) {
|
||||
// Fast case for type = int/num/top-type.
|
||||
__ BranchIfSmi(kInstanceReg, is_instance_lbl);
|
||||
__ BranchIfSmi(TypeTestABI::kInstanceReg, is_instance_lbl);
|
||||
} else {
|
||||
__ BranchIfSmi(kInstanceReg, is_not_instance_lbl);
|
||||
__ BranchIfSmi(TypeTestABI::kInstanceReg, is_not_instance_lbl);
|
||||
}
|
||||
const Register kClassIdReg = R2;
|
||||
__ LoadClassId(kClassIdReg, kInstanceReg);
|
||||
__ LoadClassId(kClassIdReg, TypeTestABI::kInstanceReg);
|
||||
// Bool interface can be implemented only by core class Bool.
|
||||
if (type.IsBoolType()) {
|
||||
__ CompareImmediate(kClassIdReg, kBoolCid);
|
||||
|
||||
@@ -256,10 +256,9 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
|
||||
ASSERT(!type.IsFunctionType());
|
||||
const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
|
||||
ASSERT(type_class.NumTypeArguments() > 0);
|
||||
const Register kInstanceReg = EAX;
|
||||
const Type& smi_type = Type::Handle(zone(), Type::SmiType());
|
||||
const bool smi_is_ok = smi_type.IsSubtypeOf(type, Heap::kOld);
|
||||
__ testl(kInstanceReg, compiler::Immediate(kSmiTagMask));
|
||||
__ testl(TypeTestABI::kInstanceReg, compiler::Immediate(kSmiTagMask));
|
||||
if (smi_is_ok) {
|
||||
// Fast case for type = FutureOr<int/num/top-type>.
|
||||
__ j(ZERO, is_instance_lbl);
|
||||
@@ -276,7 +275,7 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
|
||||
if (is_raw_type) {
|
||||
const Register kClassIdReg = ECX;
|
||||
// dynamic type argument, check only classes.
|
||||
__ LoadClassId(kClassIdReg, kInstanceReg);
|
||||
__ LoadClassId(kClassIdReg, TypeTestABI::kInstanceReg);
|
||||
__ cmpl(kClassIdReg, compiler::Immediate(type_class.id()));
|
||||
__ j(EQUAL, is_instance_lbl);
|
||||
// List is a very common case.
|
||||
@@ -300,10 +299,10 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
|
||||
const Register kInstantiatorTypeArgumentsReg = kNoRegister;
|
||||
const Register kFunctionTypeArgumentsReg = kNoRegister;
|
||||
const Register kTempReg = EDI;
|
||||
return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg,
|
||||
kInstantiatorTypeArgumentsReg,
|
||||
kFunctionTypeArgumentsReg, kTempReg,
|
||||
is_instance_lbl, is_not_instance_lbl);
|
||||
return GenerateCallSubtypeTestStub(
|
||||
kTestTypeTwoArgs, TypeTestABI::kInstanceReg,
|
||||
kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, kTempReg,
|
||||
is_instance_lbl, is_not_instance_lbl);
|
||||
}
|
||||
|
||||
void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
|
||||
@@ -333,8 +332,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
|
||||
const Class& type_class = Class::Handle(zone(), type.type_class());
|
||||
ASSERT(type_class.NumTypeArguments() == 0);
|
||||
|
||||
const Register kInstanceReg = EAX;
|
||||
__ testl(kInstanceReg, compiler::Immediate(kSmiTagMask));
|
||||
__ testl(TypeTestABI::kInstanceReg, compiler::Immediate(kSmiTagMask));
|
||||
// If instance is Smi, check directly.
|
||||
const Class& smi_class = Class::Handle(zone(), Smi::Class());
|
||||
if (Class::IsSubtypeOf(smi_class, Object::null_type_arguments(), type,
|
||||
@@ -345,7 +343,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
|
||||
__ j(ZERO, is_not_instance_lbl);
|
||||
}
|
||||
const Register kClassIdReg = ECX;
|
||||
__ LoadClassId(kClassIdReg, kInstanceReg);
|
||||
__ LoadClassId(kClassIdReg, TypeTestABI::kInstanceReg);
|
||||
// Bool interface can be implemented only by core class Bool.
|
||||
if (type.IsBoolType()) {
|
||||
__ cmpl(kClassIdReg, compiler::Immediate(kBoolCid));
|
||||
@@ -394,14 +392,13 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
|
||||
compiler::Label* is_instance_lbl,
|
||||
compiler::Label* is_not_instance_lbl) {
|
||||
__ Comment("Subtype1TestCacheLookup");
|
||||
const Register kInstanceReg = EAX;
|
||||
#if defined(DEBUG)
|
||||
compiler::Label ok;
|
||||
__ BranchIfNotSmi(kInstanceReg, &ok);
|
||||
__ BranchIfNotSmi(TypeTestABI::kInstanceReg, &ok);
|
||||
__ Breakpoint();
|
||||
__ Bind(&ok);
|
||||
#endif
|
||||
__ LoadClassId(EDI, kInstanceReg);
|
||||
__ LoadClassId(EDI, TypeTestABI::kInstanceReg);
|
||||
__ LoadClassById(ECX, EDI);
|
||||
// ECX: instance class.
|
||||
// Check immediate superclass equality.
|
||||
@@ -413,7 +410,7 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
|
||||
const Register kInstantiatorTypeArgumentsReg = kNoRegister;
|
||||
const Register kFunctionTypeArgumentsReg = kNoRegister;
|
||||
const Register kTempReg = EDI;
|
||||
return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg,
|
||||
return GenerateCallSubtypeTestStub(kTestTypeOneArg, TypeTestABI::kInstanceReg,
|
||||
kInstantiatorTypeArgumentsReg,
|
||||
kFunctionTypeArgumentsReg, kTempReg,
|
||||
is_instance_lbl, is_not_instance_lbl);
|
||||
@@ -428,7 +425,6 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
|
||||
compiler::Label* is_instance_lbl,
|
||||
compiler::Label* is_not_instance_lbl) {
|
||||
__ Comment("UninstantiatedTypeTest");
|
||||
const Register kInstanceReg = EAX;
|
||||
const Register kTempReg = EDI;
|
||||
ASSERT(!type.IsInstantiated());
|
||||
ASSERT(!type.IsFunctionType());
|
||||
@@ -444,9 +440,10 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
|
||||
compiler::Address(ESP, 0 * kWordSize)); // Get function type args.
|
||||
// EDX: instantiator type arguments.
|
||||
// ECX: function type arguments.
|
||||
const Register kTypeArgumentsReg = type_param.IsClassTypeParameter()
|
||||
? kInstantiatorTypeArgumentsReg
|
||||
: kFunctionTypeArgumentsReg;
|
||||
const Register kTypeArgumentsReg =
|
||||
type_param.IsClassTypeParameter()
|
||||
? TypeTestABI::kInstantiatorTypeArgumentsReg
|
||||
: TypeTestABI::kFunctionTypeArgumentsReg;
|
||||
// Check if type arguments are null, i.e. equivalent to vector of dynamic.
|
||||
__ cmpl(kTypeArgumentsReg, raw_null);
|
||||
__ j(EQUAL, is_instance_lbl);
|
||||
@@ -478,27 +475,30 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
|
||||
const auto test_kind = GetTypeTestStubKindForTypeParameter(type_param);
|
||||
const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
|
||||
zone(), GenerateCallSubtypeTestStub(
|
||||
test_kind, kInstanceReg, kInstantiatorTypeArgumentsReg,
|
||||
kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
|
||||
is_not_instance_lbl));
|
||||
test_kind, TypeTestABI::kInstanceReg,
|
||||
TypeTestABI::kInstantiatorTypeArgumentsReg,
|
||||
TypeTestABI::kFunctionTypeArgumentsReg, kTempReg,
|
||||
is_instance_lbl, is_not_instance_lbl));
|
||||
return type_test_cache.raw();
|
||||
}
|
||||
if (type.IsType()) {
|
||||
// Smi is FutureOr<T>, when T is a top type or int or num.
|
||||
if (!type.IsFutureOrType()) {
|
||||
__ testl(kInstanceReg,
|
||||
__ testl(TypeTestABI::kInstanceReg,
|
||||
compiler::Immediate(kSmiTagMask)); // Is instance Smi?
|
||||
__ j(ZERO, is_not_instance_lbl);
|
||||
}
|
||||
__ movl(kInstantiatorTypeArgumentsReg,
|
||||
__ movl(TypeTestABI::kInstantiatorTypeArgumentsReg,
|
||||
compiler::Address(ESP, 1 * kWordSize));
|
||||
__ movl(kFunctionTypeArgumentsReg, compiler::Address(ESP, 0 * kWordSize));
|
||||
__ movl(TypeTestABI::kFunctionTypeArgumentsReg,
|
||||
compiler::Address(ESP, 0 * kWordSize));
|
||||
// Uninstantiated type class is known at compile time, but the type
|
||||
// arguments are determined at runtime by the instantiator(s).
|
||||
return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg,
|
||||
kInstantiatorTypeArgumentsReg,
|
||||
kFunctionTypeArgumentsReg, kTempReg,
|
||||
is_instance_lbl, is_not_instance_lbl);
|
||||
return GenerateCallSubtypeTestStub(
|
||||
kTestTypeFourArgs, TypeTestABI::kInstanceReg,
|
||||
TypeTestABI::kInstantiatorTypeArgumentsReg,
|
||||
TypeTestABI::kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
|
||||
is_not_instance_lbl);
|
||||
}
|
||||
return SubtypeTestCache::null();
|
||||
}
|
||||
@@ -511,18 +511,18 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateFunctionTypeTest(
|
||||
const AbstractType& type,
|
||||
compiler::Label* is_instance_lbl,
|
||||
compiler::Label* is_not_instance_lbl) {
|
||||
const Register kInstanceReg = EAX;
|
||||
__ Comment("FunctionTypeTest");
|
||||
|
||||
__ testl(kInstanceReg, compiler::Immediate(kSmiTagMask));
|
||||
__ testl(TypeTestABI::kInstanceReg, compiler::Immediate(kSmiTagMask));
|
||||
__ j(ZERO, is_not_instance_lbl);
|
||||
// Uninstantiated type class is known at compile time, but the type
|
||||
// arguments are determined at runtime by the instantiator(s).
|
||||
const Register kTempReg = EDI;
|
||||
return GenerateCallSubtypeTestStub(kTestTypeSixArgs, kInstanceReg,
|
||||
kInstantiatorTypeArgumentsReg,
|
||||
kFunctionTypeArgumentsReg, kTempReg,
|
||||
is_instance_lbl, is_not_instance_lbl);
|
||||
return GenerateCallSubtypeTestStub(
|
||||
kTestTypeSixArgs, TypeTestABI::kInstanceReg,
|
||||
TypeTestABI::kInstantiatorTypeArgumentsReg,
|
||||
TypeTestABI::kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
|
||||
is_not_instance_lbl);
|
||||
}
|
||||
|
||||
// Inputs:
|
||||
@@ -628,8 +628,8 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
|
||||
__ PushObject(Object::null_object()); // Make room for the result.
|
||||
__ pushl(EAX); // Push the instance.
|
||||
__ PushObject(type); // Push the type.
|
||||
__ pushl(kInstantiatorTypeArgumentsReg);
|
||||
__ pushl(kFunctionTypeArgumentsReg);
|
||||
__ pushl(TypeTestABI::kInstantiatorTypeArgumentsReg);
|
||||
__ pushl(TypeTestABI::kFunctionTypeArgumentsReg);
|
||||
__ LoadObject(EAX, test_cache);
|
||||
__ pushl(EAX);
|
||||
GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs);
|
||||
@@ -673,8 +673,8 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
|
||||
// Assignable check is skipped in FlowGraphBuilder, not here.
|
||||
ASSERT(!dst_type.IsTopTypeForAssignability());
|
||||
|
||||
__ pushl(kInstantiatorTypeArgumentsReg);
|
||||
__ pushl(kFunctionTypeArgumentsReg);
|
||||
__ pushl(TypeTestABI::kInstantiatorTypeArgumentsReg);
|
||||
__ pushl(TypeTestABI::kFunctionTypeArgumentsReg);
|
||||
|
||||
compiler::Label is_assignable, runtime_call;
|
||||
if (Instance::NullIsAssignableTo(dst_type)) {
|
||||
@@ -691,15 +691,15 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
|
||||
|
||||
__ Bind(&runtime_call);
|
||||
__ movl(
|
||||
kInstantiatorTypeArgumentsReg,
|
||||
TypeTestABI::kInstantiatorTypeArgumentsReg,
|
||||
compiler::Address(ESP, 1 * kWordSize)); // Get instantiator type args.
|
||||
__ movl(kFunctionTypeArgumentsReg,
|
||||
__ movl(TypeTestABI::kFunctionTypeArgumentsReg,
|
||||
compiler::Address(ESP, 0 * kWordSize)); // Get function type args.
|
||||
__ PushObject(Object::null_object()); // Make room for the result.
|
||||
__ pushl(EAX); // Push the source object.
|
||||
__ PushObject(dst_type); // Push the type of the destination.
|
||||
__ pushl(kInstantiatorTypeArgumentsReg);
|
||||
__ pushl(kFunctionTypeArgumentsReg);
|
||||
__ pushl(TypeTestABI::kInstantiatorTypeArgumentsReg);
|
||||
__ pushl(TypeTestABI::kFunctionTypeArgumentsReg);
|
||||
__ PushObject(dst_name); // Push the name of the destination.
|
||||
__ LoadObject(EAX, test_cache);
|
||||
__ pushl(EAX);
|
||||
@@ -711,8 +711,8 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
|
||||
__ popl(EAX);
|
||||
|
||||
__ Bind(&is_assignable);
|
||||
__ popl(kFunctionTypeArgumentsReg);
|
||||
__ popl(kInstantiatorTypeArgumentsReg);
|
||||
__ popl(TypeTestABI::kFunctionTypeArgumentsReg);
|
||||
__ popl(TypeTestABI::kInstantiatorTypeArgumentsReg);
|
||||
}
|
||||
|
||||
void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) {
|
||||
|
||||
@@ -360,8 +360,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
|
||||
const Class& type_class = Class::Handle(zone(), type.type_class());
|
||||
ASSERT(type_class.NumTypeArguments() == 0);
|
||||
|
||||
const Register kInstanceReg = RAX;
|
||||
__ testq(kInstanceReg, compiler::Immediate(kSmiTagMask));
|
||||
__ testq(TypeTestABI::kInstanceReg, compiler::Immediate(kSmiTagMask));
|
||||
// If instance is Smi, check directly.
|
||||
const Class& smi_class = Class::Handle(zone(), Smi::Class());
|
||||
if (Class::IsSubtypeOf(smi_class, Object::null_type_arguments(), type,
|
||||
@@ -372,7 +371,7 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
|
||||
__ j(ZERO, is_not_instance_lbl);
|
||||
}
|
||||
const Register kClassIdReg = R10;
|
||||
__ LoadClassId(kClassIdReg, kInstanceReg);
|
||||
__ LoadClassId(kClassIdReg, TypeTestABI::kInstanceReg);
|
||||
// Bool interface can be implemented only by core class Bool.
|
||||
if (type.IsBoolType()) {
|
||||
__ cmpl(kClassIdReg, compiler::Immediate(kBoolCid));
|
||||
|
||||
@@ -736,8 +736,8 @@ LocationSummary* AssertSubtypeInstr::MakeLocationSummary(Zone* zone,
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
summary->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
summary->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
summary->set_in(0, Location::RegisterLocation(R2)); // Instant. type args.
|
||||
summary->set_in(1, Location::RegisterLocation(R1)); // Function type args.
|
||||
return summary;
|
||||
}
|
||||
|
||||
@@ -3318,9 +3318,12 @@ LocationSummary* InstantiateTypeInstr::MakeLocationSummary(Zone* zone,
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0, Location::RegisterLocation(R0));
|
||||
locs->set_in(0, Location::RegisterLocation(
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(
|
||||
InstantiationABI::kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0,
|
||||
Location::RegisterLocation(InstantiationABI::kResultTypeReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
@@ -3334,7 +3337,8 @@ void InstantiateTypeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
// A runtime call to instantiate the type is required.
|
||||
__ PushObject(Object::null_object()); // Make room for the result.
|
||||
__ PushObject(type());
|
||||
static_assert(kFunctionTypeArgumentsReg < kInstantiatorTypeArgumentsReg,
|
||||
static_assert(InstantiationABI::kFunctionTypeArgumentsReg <
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg,
|
||||
"Should be ordered to push arguments with one instruction");
|
||||
__ PushList((1 << instantiator_type_args_reg) |
|
||||
(1 << function_type_args_reg));
|
||||
@@ -3351,9 +3355,12 @@ LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary(
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0, Location::RegisterLocation(kResultTypeArgumentsReg));
|
||||
locs->set_in(0, Location::RegisterLocation(
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(
|
||||
InstantiationABI::kFunctionTypeArgumentsReg));
|
||||
locs->set_out(
|
||||
0, Location::RegisterLocation(InstantiationABI::kResultTypeArgumentsReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
@@ -3380,7 +3387,8 @@ void InstantiateTypeArgumentsInstr::EmitNativeCode(
|
||||
__ b(&type_arguments_instantiated, EQ);
|
||||
}
|
||||
// Lookup cache in stub before calling runtime.
|
||||
__ LoadObject(kUninstantiatedTypeArgumentsReg, type_arguments());
|
||||
__ LoadObject(InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
type_arguments());
|
||||
compiler->GenerateCall(token_pos(), GetStub(), RawPcDescriptors::kOther,
|
||||
locs());
|
||||
__ Bind(&type_arguments_instantiated);
|
||||
|
||||
@@ -627,8 +627,8 @@ LocationSummary* AssertSubtypeInstr::MakeLocationSummary(Zone* zone,
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
summary->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
summary->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
summary->set_in(0, Location::RegisterLocation(R2)); // Instant. type args.
|
||||
summary->set_in(1, Location::RegisterLocation(R1)); // Function type args.
|
||||
return summary;
|
||||
}
|
||||
|
||||
@@ -2809,9 +2809,12 @@ LocationSummary* InstantiateTypeInstr::MakeLocationSummary(Zone* zone,
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0, Location::RegisterLocation(R0));
|
||||
locs->set_in(0, Location::RegisterLocation(
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(
|
||||
InstantiationABI::kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0,
|
||||
Location::RegisterLocation(InstantiationABI::kResultTypeReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
@@ -2839,9 +2842,12 @@ LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary(
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0, Location::RegisterLocation(kResultTypeArgumentsReg));
|
||||
locs->set_in(0, Location::RegisterLocation(
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(
|
||||
InstantiationABI::kFunctionTypeArgumentsReg));
|
||||
locs->set_out(
|
||||
0, Location::RegisterLocation(InstantiationABI::kResultTypeArgumentsReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
@@ -2871,7 +2877,8 @@ void InstantiateTypeArgumentsInstr::EmitNativeCode(
|
||||
__ Bind(&non_null_type_args);
|
||||
}
|
||||
// Lookup cache in stub before calling runtime.
|
||||
__ LoadObject(kUninstantiatedTypeArgumentsReg, type_arguments());
|
||||
__ LoadObject(InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
type_arguments());
|
||||
compiler->GenerateCall(token_pos(), GetStub(), RawPcDescriptors::kOther,
|
||||
locs());
|
||||
__ Bind(&type_arguments_instantiated);
|
||||
|
||||
@@ -368,8 +368,10 @@ LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone,
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
summary->set_in(0, Location::RegisterLocation(EAX)); // Value.
|
||||
summary->set_in(1, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
summary->set_in(2, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
summary->set_in(1, Location::RegisterLocation(
|
||||
TypeTestABI::kInstantiatorTypeArgumentsReg));
|
||||
summary->set_in(
|
||||
2, Location::RegisterLocation(TypeTestABI::kFunctionTypeArgumentsReg));
|
||||
summary->set_out(0, Location::RegisterLocation(EAX));
|
||||
return summary;
|
||||
}
|
||||
@@ -380,8 +382,8 @@ LocationSummary* AssertSubtypeInstr::MakeLocationSummary(Zone* zone,
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
summary->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
summary->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
summary->set_in(0, Location::RegisterLocation(EDX)); // Instant. type args.
|
||||
summary->set_in(1, Location::RegisterLocation(ECX)); // Function type args.
|
||||
return summary;
|
||||
}
|
||||
|
||||
@@ -2229,17 +2231,20 @@ LocationSummary* InstanceOfInstr::MakeLocationSummary(Zone* zone,
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
summary->set_in(0, Location::RegisterLocation(EAX)); // Instance.
|
||||
summary->set_in(1, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
summary->set_in(2, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
|
||||
summary->set_in(0, Location::RegisterLocation(TypeTestABI::kInstanceReg));
|
||||
summary->set_in(1, Location::RegisterLocation(
|
||||
TypeTestABI::kInstantiatorTypeArgumentsReg));
|
||||
summary->set_in(
|
||||
2, Location::RegisterLocation(TypeTestABI::kFunctionTypeArgumentsReg));
|
||||
summary->set_out(0, Location::RegisterLocation(EAX));
|
||||
return summary;
|
||||
}
|
||||
|
||||
void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(locs()->in(0).reg() == EAX); // Value.
|
||||
ASSERT(locs()->in(1).reg() == kInstantiatorTypeArgumentsReg);
|
||||
ASSERT(locs()->in(2).reg() == kFunctionTypeArgumentsReg);
|
||||
ASSERT(locs()->in(0).reg() == TypeTestABI::kInstanceReg);
|
||||
ASSERT(locs()->in(1).reg() == TypeTestABI::kInstantiatorTypeArgumentsReg);
|
||||
ASSERT(locs()->in(2).reg() == TypeTestABI::kFunctionTypeArgumentsReg);
|
||||
|
||||
compiler->GenerateInstanceOf(token_pos(), deopt_id(), type(), locs());
|
||||
ASSERT(locs()->out(0).reg() == EAX);
|
||||
@@ -2488,9 +2493,12 @@ LocationSummary* InstantiateTypeInstr::MakeLocationSummary(Zone* zone,
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0, Location::RegisterLocation(EAX));
|
||||
locs->set_in(0, Location::RegisterLocation(
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(
|
||||
InstantiationABI::kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0,
|
||||
Location::RegisterLocation(InstantiationABI::kResultTypeReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
@@ -2519,9 +2527,12 @@ LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary(
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0, Location::RegisterLocation(kResultTypeArgumentsReg));
|
||||
locs->set_in(0, Location::RegisterLocation(
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(
|
||||
InstantiationABI::kFunctionTypeArgumentsReg));
|
||||
locs->set_out(
|
||||
0, Location::RegisterLocation(InstantiationABI::kResultTypeArgumentsReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
@@ -2551,7 +2562,8 @@ void InstantiateTypeArgumentsInstr::EmitNativeCode(
|
||||
__ Bind(&non_null_type_args);
|
||||
}
|
||||
// Lookup cache in stub before calling runtime.
|
||||
__ LoadObject(kUninstantiatedTypeArgumentsReg, type_arguments());
|
||||
__ LoadObject(InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
type_arguments());
|
||||
compiler->GenerateCall(token_pos(), GetStub(), RawPcDescriptors::kOther,
|
||||
locs());
|
||||
__ Bind(&type_arguments_instantiated);
|
||||
|
||||
@@ -582,8 +582,8 @@ LocationSummary* AssertSubtypeInstr::MakeLocationSummary(Zone* zone,
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* summary = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
summary->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
summary->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
summary->set_in(0, Location::RegisterLocation(RDX)); // Instant. type args.
|
||||
summary->set_in(1, Location::RegisterLocation(RCX)); // Function type args.
|
||||
return summary;
|
||||
}
|
||||
|
||||
@@ -2505,8 +2505,8 @@ LocationSummary* InstanceOfInstr::MakeLocationSummary(Zone* zone,
|
||||
|
||||
void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(locs()->in(0).reg() == TypeTestABI::kInstanceReg);
|
||||
ASSERT(locs()->in(1).reg() == kInstantiatorTypeArgumentsReg);
|
||||
ASSERT(locs()->in(2).reg() == kFunctionTypeArgumentsReg);
|
||||
ASSERT(locs()->in(1).reg() == TypeTestABI::kInstantiatorTypeArgumentsReg);
|
||||
ASSERT(locs()->in(2).reg() == TypeTestABI::kFunctionTypeArgumentsReg);
|
||||
|
||||
compiler->GenerateInstanceOf(token_pos(), deopt_id(), type(), locs());
|
||||
ASSERT(locs()->out(0).reg() == RAX);
|
||||
@@ -2801,9 +2801,12 @@ LocationSummary* InstantiateTypeInstr::MakeLocationSummary(Zone* zone,
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0, Location::RegisterLocation(RAX));
|
||||
locs->set_in(0, Location::RegisterLocation(
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(
|
||||
InstantiationABI::kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0,
|
||||
Location::RegisterLocation(InstantiationABI::kResultTypeReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
@@ -2832,9 +2835,12 @@ LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary(
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs = new (zone)
|
||||
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(kFunctionTypeArgumentsReg));
|
||||
locs->set_out(0, Location::RegisterLocation(kResultTypeArgumentsReg));
|
||||
locs->set_in(0, Location::RegisterLocation(
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg));
|
||||
locs->set_in(1, Location::RegisterLocation(
|
||||
InstantiationABI::kFunctionTypeArgumentsReg));
|
||||
locs->set_out(
|
||||
0, Location::RegisterLocation(InstantiationABI::kResultTypeArgumentsReg));
|
||||
return locs;
|
||||
}
|
||||
|
||||
@@ -2863,7 +2869,8 @@ void InstantiateTypeArgumentsInstr::EmitNativeCode(
|
||||
__ j(EQUAL, &type_arguments_instantiated, compiler::Assembler::kNearJump);
|
||||
__ Bind(&non_null_type_args);
|
||||
}
|
||||
__ LoadObject(kUninstantiatedTypeArgumentsReg, type_arguments());
|
||||
__ LoadObject(InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
type_arguments());
|
||||
compiler->GenerateCall(token_pos(), GetStub(), RawPcDescriptors::kOther,
|
||||
locs());
|
||||
__ Bind(&type_arguments_instantiated);
|
||||
|
||||
@@ -2960,9 +2960,8 @@ void StubCodeCompiler::GenerateDefaultNullableTypeTestStub(
|
||||
Assembler* assembler) {
|
||||
Label done;
|
||||
|
||||
const Register kInstanceReg = R0;
|
||||
// Fast case for 'null'.
|
||||
__ CompareObject(kInstanceReg, NullObject());
|
||||
__ CompareObject(TypeTestABI::kInstanceReg, NullObject());
|
||||
__ BranchIf(EQUAL, &done);
|
||||
|
||||
__ ldr(CODE_REG, Address(THR, target::Thread::slow_type_test_stub_offset()));
|
||||
@@ -3014,10 +3013,9 @@ void StubCodeCompiler::GenerateLazySpecializeTypeTestStub(
|
||||
// Used instead of LazySpecializeTypeTestStub when null is assignable.
|
||||
void StubCodeCompiler::GenerateLazySpecializeNullableTypeTestStub(
|
||||
Assembler* assembler) {
|
||||
const Register kInstanceReg = R0;
|
||||
Label done;
|
||||
|
||||
__ CompareObject(kInstanceReg, NullObject());
|
||||
__ CompareObject(TypeTestABI::kInstanceReg, NullObject());
|
||||
__ BranchIf(EQUAL, &done);
|
||||
|
||||
__ ldr(CODE_REG,
|
||||
@@ -3033,43 +3031,41 @@ void StubCodeCompiler::GenerateLazySpecializeNullableTypeTestStub(
|
||||
void StubCodeCompiler::GenerateSlowTypeTestStub(Assembler* assembler) {
|
||||
Label done, call_runtime;
|
||||
|
||||
const Register kInstanceReg = R0;
|
||||
const Register kDstTypeReg = R8;
|
||||
const Register kSubtypeTestCacheReg = R3;
|
||||
|
||||
__ EnterStubFrame();
|
||||
|
||||
// If the subtype-cache is null, it needs to be lazily-created by the runtime.
|
||||
__ CompareObject(kSubtypeTestCacheReg, NullObject());
|
||||
__ CompareObject(TypeTestABI::kSubtypeTestCacheReg, NullObject());
|
||||
__ BranchIf(EQUAL, &call_runtime);
|
||||
|
||||
const Register kTmp = R9;
|
||||
|
||||
// If this is not a [Type] object, we'll go to the runtime.
|
||||
Label is_simple_case, is_complex_case;
|
||||
__ LoadClassId(kTmp, kDstTypeReg);
|
||||
__ LoadClassId(kTmp, TypeTestABI::kDstTypeReg);
|
||||
__ cmp(kTmp, Operand(kTypeCid));
|
||||
__ BranchIf(NOT_EQUAL, &is_complex_case);
|
||||
|
||||
// Check whether this [Type] is instantiated/uninstantiated.
|
||||
__ ldrb(kTmp, FieldAddress(kDstTypeReg, target::Type::type_state_offset()));
|
||||
__ ldrb(kTmp, FieldAddress(TypeTestABI::kDstTypeReg,
|
||||
target::Type::type_state_offset()));
|
||||
__ cmp(kTmp,
|
||||
Operand(target::RawAbstractType::kTypeStateFinalizedInstantiated));
|
||||
__ BranchIf(NOT_EQUAL, &is_complex_case);
|
||||
|
||||
// Check whether this [Type] is a function type.
|
||||
__ ldr(kTmp, FieldAddress(kDstTypeReg, target::Type::signature_offset()));
|
||||
__ ldr(kTmp, FieldAddress(TypeTestABI::kDstTypeReg,
|
||||
target::Type::signature_offset()));
|
||||
__ CompareObject(kTmp, NullObject());
|
||||
__ BranchIf(NOT_EQUAL, &is_complex_case);
|
||||
|
||||
// This [Type] could be a FutureOr. Subtype2TestCache does not support Smi.
|
||||
__ BranchIfSmi(kInstanceReg, &is_complex_case);
|
||||
__ BranchIfSmi(TypeTestABI::kInstanceReg, &is_complex_case);
|
||||
|
||||
// Fall through to &is_simple_case
|
||||
|
||||
const intptr_t kRegsToSave = (1 << kSubtypeTestCacheReg) |
|
||||
(1 << kDstTypeReg) |
|
||||
(1 << kFunctionTypeArgumentsReg);
|
||||
const intptr_t kRegsToSave = (1 << TypeTestABI::kSubtypeTestCacheReg) |
|
||||
(1 << TypeTestABI::kDstTypeReg) |
|
||||
(1 << TypeTestABI::kFunctionTypeArgumentsReg);
|
||||
|
||||
__ Bind(&is_simple_case);
|
||||
{
|
||||
@@ -3565,7 +3561,7 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
Assembler* assembler) {
|
||||
// Lookup cache before calling runtime.
|
||||
__ ldr(R0, compiler::FieldAddress(
|
||||
kUninstantiatedTypeArgumentsReg,
|
||||
InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::instantiations_offset()));
|
||||
__ AddImmediate(R0, compiler::target::Array::data_offset() - kHeapObjectTag);
|
||||
// The instantiations cache is initialized with Object::zero_array() and is
|
||||
@@ -3575,13 +3571,14 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
__ ldr(R4, compiler::Address(
|
||||
R0, TypeArguments::Instantiation::kInstantiatorTypeArgsIndex *
|
||||
target::kWordSize));
|
||||
__ cmp(R4, compiler::Operand(kInstantiatorTypeArgumentsReg));
|
||||
__ cmp(R4,
|
||||
compiler::Operand(InstantiationABI::kInstantiatorTypeArgumentsReg));
|
||||
__ b(&next, NE);
|
||||
// Using IP as destination register and reading it immediately is safe.
|
||||
__ ldr(IP, compiler::Address(
|
||||
R0, TypeArguments::Instantiation::kFunctionTypeArgsIndex *
|
||||
target::kWordSize));
|
||||
__ cmp(IP, compiler::Operand(kFunctionTypeArgumentsReg));
|
||||
__ cmp(IP, compiler::Operand(InstantiationABI::kFunctionTypeArgumentsReg));
|
||||
__ b(&found, EQ);
|
||||
__ Bind(&next);
|
||||
__ AddImmediate(
|
||||
@@ -3593,21 +3590,22 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
// A runtime call to instantiate the type arguments is required.
|
||||
__ EnterStubFrame();
|
||||
__ PushObject(Object::null_object()); // Make room for the result.
|
||||
static_assert(
|
||||
(kUninstantiatedTypeArgumentsReg > kInstantiatorTypeArgumentsReg) &&
|
||||
(kInstantiatorTypeArgumentsReg > kFunctionTypeArgumentsReg),
|
||||
"Should be ordered to push arguments with one instruction");
|
||||
__ PushList((1 << kUninstantiatedTypeArgumentsReg) |
|
||||
(1 << kInstantiatorTypeArgumentsReg) |
|
||||
(1 << kFunctionTypeArgumentsReg));
|
||||
static_assert((InstantiationABI::kUninstantiatedTypeArgumentsReg >
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg) &&
|
||||
(InstantiationABI::kInstantiatorTypeArgumentsReg >
|
||||
InstantiationABI::kFunctionTypeArgumentsReg),
|
||||
"Should be ordered to push arguments with one instruction");
|
||||
__ PushList((1 << InstantiationABI::kUninstantiatedTypeArgumentsReg) |
|
||||
(1 << InstantiationABI::kInstantiatorTypeArgumentsReg) |
|
||||
(1 << InstantiationABI::kFunctionTypeArgumentsReg));
|
||||
__ CallRuntime(kInstantiateTypeArgumentsRuntimeEntry, 3);
|
||||
__ Drop(3); // Drop 2 type vectors, and uninstantiated type.
|
||||
__ Pop(kResultTypeArgumentsReg); // Pop instantiated type arguments.
|
||||
__ Pop(InstantiationABI::kResultTypeArgumentsReg);
|
||||
__ LeaveStubFrame();
|
||||
__ Ret();
|
||||
|
||||
__ Bind(&found);
|
||||
__ ldr(kResultTypeArgumentsReg,
|
||||
__ ldr(InstantiationABI::kResultTypeArgumentsReg,
|
||||
compiler::Address(
|
||||
R0, TypeArguments::Instantiation::kInstantiatedTypeArgsIndex *
|
||||
target::kWordSize));
|
||||
@@ -3620,16 +3618,17 @@ void StubCodeCompiler::
|
||||
// Return the instantiator type arguments if its nullability is compatible for
|
||||
// sharing, otherwise proceed to instantiation cache lookup.
|
||||
compiler::Label cache_lookup;
|
||||
__ ldr(R0,
|
||||
compiler::FieldAddress(kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ ldr(R0, compiler::FieldAddress(
|
||||
InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ ldr(R4,
|
||||
compiler::FieldAddress(kInstantiatorTypeArgumentsReg,
|
||||
compiler::FieldAddress(InstantiationABI::kInstantiatorTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ and_(R4, R4, Operand(R0));
|
||||
__ cmp(R4, Operand(R0));
|
||||
__ b(&cache_lookup, NE);
|
||||
__ mov(kResultTypeArgumentsReg, Operand(kInstantiatorTypeArgumentsReg));
|
||||
__ mov(InstantiationABI::kResultTypeArgumentsReg,
|
||||
Operand(InstantiationABI::kInstantiatorTypeArgumentsReg));
|
||||
__ Ret();
|
||||
|
||||
__ Bind(&cache_lookup);
|
||||
@@ -3641,16 +3640,17 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsMayShareFunctionTAStub(
|
||||
// Return the function type arguments if its nullability is compatible for
|
||||
// sharing, otherwise proceed to instantiation cache lookup.
|
||||
compiler::Label cache_lookup;
|
||||
__ ldr(R0,
|
||||
compiler::FieldAddress(kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ ldr(R0, compiler::FieldAddress(
|
||||
InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ ldr(R4,
|
||||
compiler::FieldAddress(kFunctionTypeArgumentsReg,
|
||||
compiler::FieldAddress(InstantiationABI::kFunctionTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ and_(R4, R4, Operand(R0));
|
||||
__ cmp(R4, Operand(R0));
|
||||
__ b(&cache_lookup, NE);
|
||||
__ mov(kResultTypeArgumentsReg, Operand(kFunctionTypeArgumentsReg));
|
||||
__ mov(InstantiationABI::kResultTypeArgumentsReg,
|
||||
Operand(InstantiationABI::kFunctionTypeArgumentsReg));
|
||||
__ Ret();
|
||||
|
||||
__ Bind(&cache_lookup);
|
||||
|
||||
@@ -3081,10 +3081,8 @@ void StubCodeCompiler::GenerateDefaultNullableTypeTestStub(
|
||||
Assembler* assembler) {
|
||||
Label done;
|
||||
|
||||
const Register kInstanceReg = R0;
|
||||
|
||||
// Fast case for 'null'.
|
||||
__ CompareObject(kInstanceReg, NullObject());
|
||||
__ CompareObject(TypeTestABI::kInstanceReg, NullObject());
|
||||
__ BranchIf(EQUAL, &done);
|
||||
|
||||
// Tail call the [SubtypeTestCache]-based implementation.
|
||||
@@ -3138,10 +3136,9 @@ void StubCodeCompiler::GenerateLazySpecializeTypeTestStub(
|
||||
// Used instead of LazySpecializeTypeTestStub when null is assignable.
|
||||
void StubCodeCompiler::GenerateLazySpecializeNullableTypeTestStub(
|
||||
Assembler* assembler) {
|
||||
const Register kInstanceReg = R0;
|
||||
Label done;
|
||||
|
||||
__ CompareObject(kInstanceReg, NullObject());
|
||||
__ CompareObject(TypeTestABI::kInstanceReg, NullObject());
|
||||
__ BranchIf(EQUAL, &done);
|
||||
|
||||
__ ldr(CODE_REG,
|
||||
@@ -3157,57 +3154,60 @@ void StubCodeCompiler::GenerateLazySpecializeNullableTypeTestStub(
|
||||
void StubCodeCompiler::GenerateSlowTypeTestStub(Assembler* assembler) {
|
||||
Label done, call_runtime;
|
||||
|
||||
const Register kInstanceReg = R0;
|
||||
const Register kSubtypeTestCacheReg = R3;
|
||||
const Register kDstTypeReg = R8;
|
||||
|
||||
__ EnterStubFrame();
|
||||
|
||||
// If the subtype-cache is null, it needs to be lazily-created by the runtime.
|
||||
__ CompareObject(kSubtypeTestCacheReg, NullObject());
|
||||
__ CompareObject(TypeTestABI::kSubtypeTestCacheReg, NullObject());
|
||||
__ BranchIf(EQUAL, &call_runtime);
|
||||
|
||||
const Register kTmp = R9;
|
||||
|
||||
// If this is not a [Type] object, we'll go to the runtime.
|
||||
Label is_simple_case, is_complex_case;
|
||||
__ LoadClassId(kTmp, kDstTypeReg);
|
||||
__ LoadClassId(kTmp, TypeTestABI::kDstTypeReg);
|
||||
__ cmp(kTmp, Operand(kTypeCid));
|
||||
__ BranchIf(NOT_EQUAL, &is_complex_case);
|
||||
|
||||
// Check whether this [Type] is instantiated/uninstantiated.
|
||||
__ ldr(kTmp, FieldAddress(kDstTypeReg, target::Type::type_state_offset()),
|
||||
kByte);
|
||||
__ ldr(
|
||||
kTmp,
|
||||
FieldAddress(TypeTestABI::kDstTypeReg, target::Type::type_state_offset()),
|
||||
kByte);
|
||||
__ cmp(kTmp,
|
||||
Operand(target::RawAbstractType::kTypeStateFinalizedInstantiated));
|
||||
__ BranchIf(NOT_EQUAL, &is_complex_case);
|
||||
|
||||
// Check whether this [Type] is a function type.
|
||||
__ ldr(kTmp, FieldAddress(kDstTypeReg, target::Type::signature_offset()));
|
||||
__ ldr(kTmp, FieldAddress(TypeTestABI::kDstTypeReg,
|
||||
target::Type::signature_offset()));
|
||||
__ CompareObject(kTmp, NullObject());
|
||||
__ BranchIf(NOT_EQUAL, &is_complex_case);
|
||||
|
||||
// This [Type] could be a FutureOr. Subtype2TestCache does not support Smi.
|
||||
__ BranchIfSmi(kInstanceReg, &is_complex_case);
|
||||
__ BranchIfSmi(TypeTestABI::kInstanceReg, &is_complex_case);
|
||||
|
||||
// Fall through to &is_simple_case
|
||||
|
||||
__ Bind(&is_simple_case);
|
||||
{
|
||||
__ PushPair(kFunctionTypeArgumentsReg, kSubtypeTestCacheReg);
|
||||
__ PushPair(TypeTestABI::kFunctionTypeArgumentsReg,
|
||||
TypeTestABI::kSubtypeTestCacheReg);
|
||||
__ BranchLink(StubCodeSubtype2TestCache());
|
||||
__ CompareObject(R1, CastHandle<Object>(TrueObject()));
|
||||
__ PopPair(kFunctionTypeArgumentsReg, kSubtypeTestCacheReg);
|
||||
__ PopPair(TypeTestABI::kFunctionTypeArgumentsReg,
|
||||
TypeTestABI::kSubtypeTestCacheReg);
|
||||
__ BranchIf(EQUAL, &done); // Cache said: yes.
|
||||
__ Jump(&call_runtime);
|
||||
}
|
||||
|
||||
__ Bind(&is_complex_case);
|
||||
{
|
||||
__ PushPair(kFunctionTypeArgumentsReg, kSubtypeTestCacheReg);
|
||||
__ PushPair(TypeTestABI::kFunctionTypeArgumentsReg,
|
||||
TypeTestABI::kSubtypeTestCacheReg);
|
||||
__ BranchLink(StubCodeSubtype6TestCache());
|
||||
__ CompareObject(R1, CastHandle<Object>(TrueObject()));
|
||||
__ PopPair(kFunctionTypeArgumentsReg, kSubtypeTestCacheReg);
|
||||
__ PopPair(TypeTestABI::kFunctionTypeArgumentsReg,
|
||||
TypeTestABI::kSubtypeTestCacheReg);
|
||||
__ BranchIf(EQUAL, &done); // Cache said: yes.
|
||||
// Fall through to runtime_call
|
||||
}
|
||||
@@ -3685,7 +3685,7 @@ void StubCodeCompiler::GenerateAsynchronousGapMarkerStub(Assembler* assembler) {
|
||||
void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
Assembler* assembler) {
|
||||
// Lookup cache before calling runtime.
|
||||
__ LoadFieldFromOffset(R0, kUninstantiatedTypeArgumentsReg,
|
||||
__ LoadFieldFromOffset(R0, InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::instantiations_offset());
|
||||
__ AddImmediate(R0, Array::data_offset() - kHeapObjectTag);
|
||||
// The instantiations cache is initialized with Object::zero_array() and is
|
||||
@@ -3695,12 +3695,12 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
__ LoadFromOffset(R5, R0,
|
||||
TypeArguments::Instantiation::kInstantiatorTypeArgsIndex *
|
||||
target::kWordSize);
|
||||
__ CompareRegisters(R5, kInstantiatorTypeArgumentsReg);
|
||||
__ CompareRegisters(R5, InstantiationABI::kInstantiatorTypeArgumentsReg);
|
||||
__ b(&next, NE);
|
||||
__ LoadFromOffset(
|
||||
R4, R0,
|
||||
TypeArguments::Instantiation::kFunctionTypeArgsIndex * target::kWordSize);
|
||||
__ CompareRegisters(R4, kFunctionTypeArgumentsReg);
|
||||
__ CompareRegisters(R4, InstantiationABI::kFunctionTypeArgumentsReg);
|
||||
__ b(&found, EQ);
|
||||
__ Bind(&next);
|
||||
__ AddImmediate(
|
||||
@@ -3711,16 +3711,17 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
// Instantiate non-null type arguments.
|
||||
// A runtime call to instantiate the type arguments is required.
|
||||
__ EnterStubFrame();
|
||||
__ PushPair(kUninstantiatedTypeArgumentsReg, NULL_REG);
|
||||
__ PushPair(kFunctionTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
|
||||
__ PushPair(InstantiationABI::kUninstantiatedTypeArgumentsReg, NULL_REG);
|
||||
__ PushPair(InstantiationABI::kFunctionTypeArgumentsReg,
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg);
|
||||
__ CallRuntime(kInstantiateTypeArgumentsRuntimeEntry, 3);
|
||||
__ Drop(3); // Drop 2 type vectors, and uninstantiated type.
|
||||
__ Pop(kResultTypeArgumentsReg); // Pop instantiated type arguments.
|
||||
__ Pop(InstantiationABI::kResultTypeArgumentsReg);
|
||||
__ LeaveStubFrame();
|
||||
__ Ret();
|
||||
|
||||
__ Bind(&found);
|
||||
__ LoadFromOffset(kResultTypeArgumentsReg, R0,
|
||||
__ LoadFromOffset(InstantiationABI::kResultTypeArgumentsReg, R0,
|
||||
TypeArguments::Instantiation::kInstantiatedTypeArgsIndex *
|
||||
target::kWordSize);
|
||||
__ Ret();
|
||||
@@ -3732,14 +3733,15 @@ void StubCodeCompiler::
|
||||
// Return the instantiator type arguments if its nullability is compatible for
|
||||
// sharing, otherwise proceed to instantiation cache lookup.
|
||||
compiler::Label cache_lookup;
|
||||
__ LoadFieldFromOffset(R0, kUninstantiatedTypeArgumentsReg,
|
||||
__ LoadFieldFromOffset(R0, InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset());
|
||||
__ LoadFieldFromOffset(R4, kInstantiatorTypeArgumentsReg,
|
||||
__ LoadFieldFromOffset(R4, InstantiationABI::kInstantiatorTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset());
|
||||
__ and_(R4, R4, Operand(R0));
|
||||
__ cmp(R4, Operand(R0));
|
||||
__ b(&cache_lookup, NE);
|
||||
__ mov(kResultTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
|
||||
__ mov(InstantiationABI::kResultTypeArgumentsReg,
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg);
|
||||
__ Ret();
|
||||
|
||||
__ Bind(&cache_lookup);
|
||||
@@ -3751,14 +3753,15 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsMayShareFunctionTAStub(
|
||||
// Return the function type arguments if its nullability is compatible for
|
||||
// sharing, otherwise proceed to instantiation cache lookup.
|
||||
compiler::Label cache_lookup;
|
||||
__ LoadFieldFromOffset(R0, kUninstantiatedTypeArgumentsReg,
|
||||
__ LoadFieldFromOffset(R0, InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset());
|
||||
__ LoadFieldFromOffset(R4, kFunctionTypeArgumentsReg,
|
||||
__ LoadFieldFromOffset(R4, InstantiationABI::kFunctionTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset());
|
||||
__ and_(R4, R4, Operand(R0));
|
||||
__ cmp(R4, Operand(R0));
|
||||
__ b(&cache_lookup, NE);
|
||||
__ mov(kResultTypeArgumentsReg, kFunctionTypeArgumentsReg);
|
||||
__ mov(InstantiationABI::kResultTypeArgumentsReg,
|
||||
InstantiationABI::kFunctionTypeArgumentsReg);
|
||||
__ Ret();
|
||||
|
||||
__ Bind(&cache_lookup);
|
||||
|
||||
@@ -2385,14 +2385,12 @@ static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
|
||||
static intptr_t kInstanceOffsetInBytes = 3 * target::kWordSize;
|
||||
static intptr_t kCacheOffsetInBytes = 4 * target::kWordSize;
|
||||
|
||||
const Register kInstanceReg = EAX;
|
||||
|
||||
const Register kInstanceCidOrFunction = ECX;
|
||||
const Register kInstanceInstantiatorTypeArgumentsReg = EBX;
|
||||
|
||||
const auto& raw_null = Immediate(target::ToRawPointer(NullObject()));
|
||||
|
||||
__ movl(kInstanceReg, Address(ESP, kInstanceOffsetInBytes));
|
||||
__ movl(TypeTestABI::kInstanceReg, Address(ESP, kInstanceOffsetInBytes));
|
||||
|
||||
// Loop initialization (moved up here to avoid having all dependent loads
|
||||
// after each other)
|
||||
@@ -2402,9 +2400,9 @@ static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
|
||||
|
||||
Label loop, not_closure;
|
||||
if (n >= 4) {
|
||||
__ LoadClassIdMayBeSmi(kInstanceCidOrFunction, kInstanceReg);
|
||||
__ LoadClassIdMayBeSmi(kInstanceCidOrFunction, TypeTestABI::kInstanceReg);
|
||||
} else {
|
||||
__ LoadClassId(kInstanceCidOrFunction, kInstanceReg);
|
||||
__ LoadClassId(kInstanceCidOrFunction, TypeTestABI::kInstanceReg);
|
||||
}
|
||||
__ cmpl(kInstanceCidOrFunction, Immediate(kClosureCid));
|
||||
__ j(NOT_EQUAL, ¬_closure, Assembler::kNearJump);
|
||||
@@ -2412,17 +2410,20 @@ static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
|
||||
// Closure handling.
|
||||
{
|
||||
__ movl(kInstanceCidOrFunction,
|
||||
FieldAddress(kInstanceReg, target::Closure::function_offset()));
|
||||
FieldAddress(TypeTestABI::kInstanceReg,
|
||||
target::Closure::function_offset()));
|
||||
if (n >= 2) {
|
||||
__ movl(
|
||||
kInstanceInstantiatorTypeArgumentsReg,
|
||||
FieldAddress(kInstanceReg,
|
||||
FieldAddress(TypeTestABI::kInstanceReg,
|
||||
target::Closure::instantiator_type_arguments_offset()));
|
||||
if (n >= 6) {
|
||||
__ pushl(FieldAddress(
|
||||
kInstanceReg, target::Closure::delayed_type_arguments_offset()));
|
||||
__ pushl(FieldAddress(
|
||||
kInstanceReg, target::Closure::function_type_arguments_offset()));
|
||||
__ pushl(
|
||||
FieldAddress(TypeTestABI::kInstanceReg,
|
||||
target::Closure::delayed_type_arguments_offset()));
|
||||
__ pushl(
|
||||
FieldAddress(TypeTestABI::kInstanceReg,
|
||||
target::Closure::function_type_arguments_offset()));
|
||||
}
|
||||
}
|
||||
__ jmp(&loop, Assembler::kNearJump);
|
||||
@@ -2442,7 +2443,7 @@ static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
|
||||
__ cmpl(EDI, Immediate(target::Class::kNoTypeArguments));
|
||||
__ j(EQUAL, &has_no_type_arguments, Assembler::kNearJump);
|
||||
__ movl(kInstanceInstantiatorTypeArgumentsReg,
|
||||
FieldAddress(kInstanceReg, EDI, TIMES_4, 0));
|
||||
FieldAddress(TypeTestABI::kInstanceReg, EDI, TIMES_4, 0));
|
||||
__ Bind(&has_no_type_arguments);
|
||||
|
||||
if (n >= 6) {
|
||||
@@ -2915,9 +2916,9 @@ void StubCodeCompiler::GenerateAsynchronousGapMarkerStub(Assembler* assembler) {
|
||||
void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
Assembler* assembler) {
|
||||
// Lookup cache before calling runtime.
|
||||
__ pushl(kUninstantiatedTypeArgumentsReg); // Preserve reg.
|
||||
__ pushl(InstantiationABI::kUninstantiatedTypeArgumentsReg); // Preserve reg.
|
||||
__ movl(EAX, compiler::FieldAddress(
|
||||
kUninstantiatedTypeArgumentsReg,
|
||||
InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::instantiations_offset()));
|
||||
__ leal(EAX, compiler::FieldAddress(EAX, Array::data_offset()));
|
||||
// The instantiations cache is initialized with Object::zero_array() and is
|
||||
@@ -2928,12 +2929,12 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
compiler::Address(
|
||||
EAX, TypeArguments::Instantiation::kInstantiatorTypeArgsIndex *
|
||||
target::kWordSize));
|
||||
__ cmpl(EDI, kInstantiatorTypeArgumentsReg);
|
||||
__ cmpl(EDI, InstantiationABI::kInstantiatorTypeArgumentsReg);
|
||||
__ j(NOT_EQUAL, &next, compiler::Assembler::kNearJump);
|
||||
__ movl(EBX, compiler::Address(
|
||||
EAX, TypeArguments::Instantiation::kFunctionTypeArgsIndex *
|
||||
target::kWordSize));
|
||||
__ cmpl(EBX, kFunctionTypeArgumentsReg);
|
||||
__ cmpl(EBX, InstantiationABI::kFunctionTypeArgumentsReg);
|
||||
__ j(EQUAL, &found, compiler::Assembler::kNearJump);
|
||||
__ Bind(&next);
|
||||
__ addl(EAX, compiler::Immediate(TypeArguments::Instantiation::kSizeInWords *
|
||||
@@ -2944,21 +2945,21 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
|
||||
// Instantiate non-null type arguments.
|
||||
// A runtime call to instantiate the type arguments is required.
|
||||
__ popl(kUninstantiatedTypeArgumentsReg); // Restore reg.
|
||||
__ popl(InstantiationABI::kUninstantiatedTypeArgumentsReg); // Restore reg.
|
||||
__ EnterStubFrame();
|
||||
__ PushObject(Object::null_object()); // Make room for the result.
|
||||
__ pushl(kUninstantiatedTypeArgumentsReg);
|
||||
__ pushl(kInstantiatorTypeArgumentsReg); // Push instantiator type arguments.
|
||||
__ pushl(kFunctionTypeArgumentsReg); // Push function type arguments.
|
||||
__ pushl(InstantiationABI::kUninstantiatedTypeArgumentsReg);
|
||||
__ pushl(InstantiationABI::kInstantiatorTypeArgumentsReg);
|
||||
__ pushl(InstantiationABI::kFunctionTypeArgumentsReg);
|
||||
__ CallRuntime(kInstantiateTypeArgumentsRuntimeEntry, 3);
|
||||
__ Drop(3); // Drop 2 type vectors, and uninstantiated args.
|
||||
__ popl(kResultTypeArgumentsReg); // Pop instantiated type arguments.
|
||||
__ popl(InstantiationABI::kResultTypeArgumentsReg);
|
||||
__ LeaveFrame();
|
||||
__ ret();
|
||||
|
||||
__ Bind(&found);
|
||||
__ popl(kUninstantiatedTypeArgumentsReg); // Drop reg.
|
||||
__ movl(kResultTypeArgumentsReg,
|
||||
__ popl(InstantiationABI::kUninstantiatedTypeArgumentsReg); // Drop reg.
|
||||
__ movl(InstantiationABI::kResultTypeArgumentsReg,
|
||||
compiler::Address(
|
||||
EAX, TypeArguments::Instantiation::kInstantiatedTypeArgsIndex *
|
||||
target::kWordSize));
|
||||
@@ -2971,16 +2972,17 @@ void StubCodeCompiler::
|
||||
// Return the instantiator type arguments if its nullability is compatible for
|
||||
// sharing, otherwise proceed to instantiation cache lookup.
|
||||
compiler::Label cache_lookup;
|
||||
__ movl(EAX,
|
||||
compiler::FieldAddress(kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ movl(EDI,
|
||||
compiler::FieldAddress(kInstantiatorTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ movl(EAX, compiler::FieldAddress(
|
||||
InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ movl(EDI, compiler::FieldAddress(
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ andl(EDI, EAX);
|
||||
__ cmpl(EDI, EAX);
|
||||
__ j(NOT_EQUAL, &cache_lookup, compiler::Assembler::kNearJump);
|
||||
__ movl(kResultTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
|
||||
__ movl(InstantiationABI::kResultTypeArgumentsReg,
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg);
|
||||
__ ret();
|
||||
|
||||
__ Bind(&cache_lookup);
|
||||
@@ -2992,16 +2994,17 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsMayShareFunctionTAStub(
|
||||
// Return the function type arguments if its nullability is compatible for
|
||||
// sharing, otherwise proceed to instantiation cache lookup.
|
||||
compiler::Label cache_lookup;
|
||||
__ movl(EAX,
|
||||
compiler::FieldAddress(kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ movl(EAX, compiler::FieldAddress(
|
||||
InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ movl(EDI,
|
||||
compiler::FieldAddress(kFunctionTypeArgumentsReg,
|
||||
compiler::FieldAddress(InstantiationABI::kFunctionTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ andl(EDI, EAX);
|
||||
__ cmpl(EDI, EAX);
|
||||
__ j(NOT_EQUAL, &cache_lookup, compiler::Assembler::kNearJump);
|
||||
__ movl(kResultTypeArgumentsReg, kFunctionTypeArgumentsReg);
|
||||
__ movl(InstantiationABI::kResultTypeArgumentsReg,
|
||||
InstantiationABI::kFunctionTypeArgumentsReg);
|
||||
__ ret();
|
||||
|
||||
__ Bind(&cache_lookup);
|
||||
|
||||
@@ -3030,10 +3030,8 @@ void StubCodeCompiler::GenerateDefaultNullableTypeTestStub(
|
||||
Assembler* assembler) {
|
||||
Label done;
|
||||
|
||||
const Register kInstanceReg = RAX;
|
||||
|
||||
// Fast case for 'null'.
|
||||
__ CompareObject(kInstanceReg, NullObject());
|
||||
__ CompareObject(TypeTestABI::kInstanceReg, NullObject());
|
||||
__ BranchIf(EQUAL, &done);
|
||||
|
||||
__ movq(CODE_REG, Address(THR, target::Thread::slow_type_test_stub_offset()));
|
||||
@@ -3086,12 +3084,10 @@ void StubCodeCompiler::GenerateLazySpecializeTypeTestStub(
|
||||
// Used instead of LazySpecializeTypeTestStub when null is assignable.
|
||||
void StubCodeCompiler::GenerateLazySpecializeNullableTypeTestStub(
|
||||
Assembler* assembler) {
|
||||
const Register kInstanceReg = RAX;
|
||||
|
||||
Label done;
|
||||
|
||||
// Fast case for 'null'.
|
||||
__ CompareObject(kInstanceReg, NullObject());
|
||||
__ CompareObject(TypeTestABI::kInstanceReg, NullObject());
|
||||
__ BranchIf(EQUAL, &done);
|
||||
|
||||
__ movq(
|
||||
@@ -3108,36 +3104,34 @@ void StubCodeCompiler::GenerateLazySpecializeNullableTypeTestStub(
|
||||
void StubCodeCompiler::GenerateSlowTypeTestStub(Assembler* assembler) {
|
||||
Label done, call_runtime;
|
||||
|
||||
const Register kInstanceReg = RAX;
|
||||
const Register kDstTypeReg = RBX;
|
||||
const Register kSubtypeTestCacheReg = R9;
|
||||
|
||||
__ EnterStubFrame();
|
||||
|
||||
// If the subtype-cache is null, it needs to be lazily-created by the runtime.
|
||||
__ CompareObject(kSubtypeTestCacheReg, NullObject());
|
||||
__ CompareObject(TypeTestABI::kSubtypeTestCacheReg, NullObject());
|
||||
__ BranchIf(EQUAL, &call_runtime);
|
||||
|
||||
const Register kTmp = RDI;
|
||||
|
||||
// If this is not a [Type] object, we'll go to the runtime.
|
||||
Label is_simple_case, is_complex_case;
|
||||
__ LoadClassId(kTmp, kDstTypeReg);
|
||||
__ LoadClassId(kTmp, TypeTestABI::kDstTypeReg);
|
||||
__ cmpq(kTmp, Immediate(kTypeCid));
|
||||
__ BranchIf(NOT_EQUAL, &is_complex_case);
|
||||
|
||||
// Check whether this [Type] is instantiated/uninstantiated.
|
||||
__ cmpb(FieldAddress(kDstTypeReg, target::Type::type_state_offset()),
|
||||
Immediate(target::RawAbstractType::kTypeStateFinalizedInstantiated));
|
||||
__ cmpb(
|
||||
FieldAddress(TypeTestABI::kDstTypeReg, target::Type::type_state_offset()),
|
||||
Immediate(target::RawAbstractType::kTypeStateFinalizedInstantiated));
|
||||
__ BranchIf(NOT_EQUAL, &is_complex_case);
|
||||
|
||||
// Check whether this [Type] is a function type.
|
||||
__ movq(kTmp, FieldAddress(kDstTypeReg, target::Type::signature_offset()));
|
||||
__ movq(kTmp, FieldAddress(TypeTestABI::kDstTypeReg,
|
||||
target::Type::signature_offset()));
|
||||
__ CompareObject(kTmp, NullObject());
|
||||
__ BranchIf(NOT_EQUAL, &is_complex_case);
|
||||
|
||||
// This [Type] could be a FutureOr. Subtype2TestCache does not support Smi.
|
||||
__ BranchIfSmi(kInstanceReg, &is_complex_case);
|
||||
__ BranchIfSmi(TypeTestABI::kInstanceReg, &is_complex_case);
|
||||
|
||||
// Fall through to &is_simple_case
|
||||
|
||||
@@ -3622,7 +3616,7 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
Assembler* assembler) {
|
||||
// Lookup cache before calling runtime.
|
||||
__ movq(RAX, compiler::FieldAddress(
|
||||
kUninstantiatedTypeArgumentsReg,
|
||||
InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::instantiations_offset()));
|
||||
__ leaq(RAX, compiler::FieldAddress(RAX, Array::data_offset()));
|
||||
// The instantiations cache is initialized with Object::zero_array() and is
|
||||
@@ -3633,12 +3627,12 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
compiler::Address(
|
||||
RAX, TypeArguments::Instantiation::kInstantiatorTypeArgsIndex *
|
||||
target::kWordSize));
|
||||
__ cmpq(RDI, kInstantiatorTypeArgumentsReg);
|
||||
__ cmpq(RDI, InstantiationABI::kInstantiatorTypeArgumentsReg);
|
||||
__ j(NOT_EQUAL, &next, compiler::Assembler::kNearJump);
|
||||
__ movq(R10, compiler::Address(
|
||||
RAX, TypeArguments::Instantiation::kFunctionTypeArgsIndex *
|
||||
target::kWordSize));
|
||||
__ cmpq(R10, kFunctionTypeArgumentsReg);
|
||||
__ cmpq(R10, InstantiationABI::kFunctionTypeArgumentsReg);
|
||||
__ j(EQUAL, &found, compiler::Assembler::kNearJump);
|
||||
__ Bind(&next);
|
||||
__ addq(RAX, compiler::Immediate(TypeArguments::Instantiation::kSizeInWords *
|
||||
@@ -3651,17 +3645,17 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsStub(
|
||||
// A runtime call to instantiate the type arguments is required.
|
||||
__ EnterStubFrame();
|
||||
__ PushObject(Object::null_object()); // Make room for the result.
|
||||
__ pushq(kUninstantiatedTypeArgumentsReg);
|
||||
__ pushq(kInstantiatorTypeArgumentsReg); // Push instantiator type arguments.
|
||||
__ pushq(kFunctionTypeArgumentsReg); // Push function type arguments.
|
||||
__ pushq(InstantiationABI::kUninstantiatedTypeArgumentsReg);
|
||||
__ pushq(InstantiationABI::kInstantiatorTypeArgumentsReg);
|
||||
__ pushq(InstantiationABI::kFunctionTypeArgumentsReg);
|
||||
__ CallRuntime(kInstantiateTypeArgumentsRuntimeEntry, 3);
|
||||
__ Drop(3); // Drop 2 type vectors, and uninstantiated type.
|
||||
__ popq(kResultTypeArgumentsReg); // Pop instantiated type arguments.
|
||||
__ popq(InstantiationABI::kResultTypeArgumentsReg);
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
|
||||
__ Bind(&found);
|
||||
__ movq(kResultTypeArgumentsReg,
|
||||
__ movq(InstantiationABI::kResultTypeArgumentsReg,
|
||||
compiler::Address(
|
||||
RAX, TypeArguments::Instantiation::kInstantiatedTypeArgsIndex *
|
||||
target::kWordSize));
|
||||
@@ -3674,16 +3668,17 @@ void StubCodeCompiler::
|
||||
// Return the instantiator type arguments if its nullability is compatible for
|
||||
// sharing, otherwise proceed to instantiation cache lookup.
|
||||
compiler::Label cache_lookup;
|
||||
__ movq(RAX,
|
||||
compiler::FieldAddress(kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ movq(RDI,
|
||||
compiler::FieldAddress(kInstantiatorTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ movq(RAX, compiler::FieldAddress(
|
||||
InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ movq(RDI, compiler::FieldAddress(
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ andq(RDI, RAX);
|
||||
__ cmpq(RDI, RAX);
|
||||
__ j(NOT_EQUAL, &cache_lookup, compiler::Assembler::kNearJump);
|
||||
__ movq(kResultTypeArgumentsReg, kInstantiatorTypeArgumentsReg);
|
||||
__ movq(InstantiationABI::kResultTypeArgumentsReg,
|
||||
InstantiationABI::kInstantiatorTypeArgumentsReg);
|
||||
__ ret();
|
||||
|
||||
__ Bind(&cache_lookup);
|
||||
@@ -3695,16 +3690,17 @@ void StubCodeCompiler::GenerateInstantiateTypeArgumentsMayShareFunctionTAStub(
|
||||
// Return the function type arguments if its nullability is compatible for
|
||||
// sharing, otherwise proceed to instantiation cache lookup.
|
||||
compiler::Label cache_lookup;
|
||||
__ movq(RAX,
|
||||
compiler::FieldAddress(kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ movq(RAX, compiler::FieldAddress(
|
||||
InstantiationABI::kUninstantiatedTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ movq(RDI,
|
||||
compiler::FieldAddress(kFunctionTypeArgumentsReg,
|
||||
compiler::FieldAddress(InstantiationABI::kFunctionTypeArgumentsReg,
|
||||
target::TypeArguments::nullability_offset()));
|
||||
__ andq(RDI, RAX);
|
||||
__ cmpq(RDI, RAX);
|
||||
__ j(NOT_EQUAL, &cache_lookup, compiler::Assembler::kNearJump);
|
||||
__ movq(kResultTypeArgumentsReg, kFunctionTypeArgumentsReg);
|
||||
__ movq(InstantiationABI::kResultTypeArgumentsReg,
|
||||
InstantiationABI::kFunctionTypeArgumentsReg);
|
||||
__ ret();
|
||||
|
||||
__ Bind(&cache_lookup);
|
||||
|
||||
@@ -311,10 +311,13 @@ const Register kWriteBarrierSlotReg = R9;
|
||||
const Register kAllocationStubTypeArgumentsReg = R3;
|
||||
|
||||
// ABI for instantiation stubs.
|
||||
const Register kUninstantiatedTypeArgumentsReg = R3;
|
||||
const Register kInstantiatorTypeArgumentsReg = R2;
|
||||
const Register kFunctionTypeArgumentsReg = R1;
|
||||
const Register kResultTypeArgumentsReg = R0;
|
||||
struct InstantiationABI {
|
||||
static const Register kUninstantiatedTypeArgumentsReg = R3;
|
||||
static const Register kInstantiatorTypeArgumentsReg = R2;
|
||||
static const Register kFunctionTypeArgumentsReg = R1;
|
||||
static const Register kResultTypeArgumentsReg = R0;
|
||||
static const Register kResultTypeReg = R0;
|
||||
};
|
||||
|
||||
// Calling convention when calling TypeTestingStub and SubtypeTestCacheStub.
|
||||
struct TypeTestABI {
|
||||
|
||||
@@ -143,10 +143,13 @@ const Register kWriteBarrierSlotReg = R25;
|
||||
const Register kAllocationStubTypeArgumentsReg = R1;
|
||||
|
||||
// ABI for instantiation stubs.
|
||||
const Register kUninstantiatedTypeArgumentsReg = R3;
|
||||
const Register kInstantiatorTypeArgumentsReg = R2;
|
||||
const Register kFunctionTypeArgumentsReg = R1;
|
||||
const Register kResultTypeArgumentsReg = R0;
|
||||
struct InstantiationABI {
|
||||
static const Register kUninstantiatedTypeArgumentsReg = R3;
|
||||
static const Register kInstantiatorTypeArgumentsReg = R2;
|
||||
static const Register kFunctionTypeArgumentsReg = R1;
|
||||
static const Register kResultTypeArgumentsReg = R0;
|
||||
static const Register kResultTypeReg = R0;
|
||||
};
|
||||
|
||||
// Calling convention when calling TypeTestingStub and SubtypeTestCacheStub.
|
||||
struct TypeTestABI {
|
||||
|
||||
@@ -92,13 +92,24 @@ const Register kWriteBarrierSlotReg = EDI;
|
||||
const Register kAllocationStubTypeArgumentsReg = EDX;
|
||||
|
||||
// ABI for instantiation stubs.
|
||||
const Register kUninstantiatedTypeArgumentsReg = EBX;
|
||||
const Register kInstantiatorTypeArgumentsReg = EDX;
|
||||
const Register kFunctionTypeArgumentsReg = ECX;
|
||||
const Register kResultTypeArgumentsReg = EAX;
|
||||
struct InstantiationABI {
|
||||
static const Register kUninstantiatedTypeArgumentsReg = EBX;
|
||||
static const Register kInstantiatorTypeArgumentsReg = EDX;
|
||||
static const Register kFunctionTypeArgumentsReg = ECX;
|
||||
static const Register kResultTypeArgumentsReg = EAX;
|
||||
static const Register kResultTypeReg = EAX;
|
||||
};
|
||||
|
||||
// TODO(regis): Add ABIs for type testing stubs and is-type test stubs instead
|
||||
// of reusing the constants of the instantiation stubs ABI.
|
||||
// Calling convention when calling SubtypeTestCacheStub.
|
||||
// Although ia32 uses a stack-based calling convention, we keep the same
|
||||
// 'TypeTestABI' name for symmetry with other architectures with a proper ABI.
|
||||
// Note that ia32 has no support for type testing stubs.
|
||||
struct TypeTestABI {
|
||||
static const Register kInstanceReg = EAX;
|
||||
static const Register kDstTypeReg = EBX;
|
||||
static const Register kInstantiatorTypeArgumentsReg = EDX;
|
||||
static const Register kFunctionTypeArgumentsReg = ECX;
|
||||
};
|
||||
|
||||
typedef uint32_t RegList;
|
||||
const RegList kAllCpuRegistersList = 0xFF;
|
||||
|
||||
@@ -133,10 +133,13 @@ const Register kWriteBarrierSlotReg = R13;
|
||||
const Register kAllocationStubTypeArgumentsReg = RDX;
|
||||
|
||||
// ABI for instantiation stubs.
|
||||
const Register kUninstantiatedTypeArgumentsReg = RBX;
|
||||
const Register kInstantiatorTypeArgumentsReg = RDX;
|
||||
const Register kFunctionTypeArgumentsReg = RCX;
|
||||
const Register kResultTypeArgumentsReg = RAX;
|
||||
struct InstantiationABI {
|
||||
static const Register kUninstantiatedTypeArgumentsReg = RBX;
|
||||
static const Register kInstantiatorTypeArgumentsReg = RDX;
|
||||
static const Register kFunctionTypeArgumentsReg = RCX;
|
||||
static const Register kResultTypeArgumentsReg = RAX;
|
||||
static const Register kResultTypeReg = RAX;
|
||||
};
|
||||
|
||||
// Calling convention when calling TypeTestingStub and SubtypeTestCacheStub.
|
||||
struct TypeTestABI {
|
||||
|
||||
Reference in New Issue
Block a user