[dart2wasm] Disentagle dispatch table calls from static calls in dart2wasm
Not all instance members are necessarily called via dispatch table
calls.
If we know an instance member isn't a target of any dispatch table call
we can choose the representation for that member on its own (instead of
using the selector representation - which is a upper-bounding of all
implementations of that selector).
This CL requires all call sites to obtain target signature & parameter
information via one of
* `Translator.{signature,paramInfo}ForDirectCall`
* `Translator.{signature,paramInfo}ForDispatchTableCall`
=> Those methods handle the case of calling a method
a) via dispatch table call
b) via direct call where
b.1) target can also be called via dispatch table
b.2) target cannot be called via dispatch table
In a follow up CL we're going to reland [0] which will shrink the set of
instance methods that are callable via dispatch table calls (e.g.
members that are only called via `super.*()` can use their own
representation selection instead of clustering it with methods of same
name that can be called via dispatch table).
The regression test added in this CL is a test that will fail with [0]
without this CL.
[0] https://dart-review.googlesource.com/c/sdk/+/374320
Change-Id: I5184cf6e712f33a894fd1463a5903128f87be92f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/375280
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
@@ -152,8 +152,8 @@ class AsyncCodeGenerator extends StateMachineCodeGenerator {
|
||||
// (3) Return the completer's future.
|
||||
|
||||
b.local_get(asyncStateLocal);
|
||||
final completerFutureGetterType = translator.functions
|
||||
.getFunctionType(translator.completerFuture.getterReference);
|
||||
final completerFutureGetterType = translator
|
||||
.signatureForDirectCall(translator.completerFuture.getterReference);
|
||||
b.struct_get(
|
||||
asyncSuspendStateInfo.struct, FieldIndex.asyncSuspendStateCompleter);
|
||||
translator.convertType(
|
||||
|
||||
@@ -499,7 +499,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
|
||||
void setupParameters(Reference reference, {bool isForwarder = false}) {
|
||||
Member member = reference.asMember;
|
||||
ParameterInfo paramInfo = translator.paramInfoFor(reference);
|
||||
ParameterInfo paramInfo = translator.paramInfoForDirectCall(reference);
|
||||
|
||||
int parameterOffset = _initializeThis(reference);
|
||||
int implicitParams = parameterOffset + paramInfo.typeParamCount;
|
||||
@@ -527,7 +527,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
|
||||
void setupConstructorBodyParametersAndContexts(Reference reference) {
|
||||
Constructor member = reference.asConstructor;
|
||||
ParameterInfo paramInfo = translator.paramInfoFor(reference);
|
||||
ParameterInfo paramInfo = translator.paramInfoForDirectCall(reference);
|
||||
|
||||
// For constructor body functions, the first parameter is always the
|
||||
// receiver parameter, and the second parameter is a reference to the
|
||||
@@ -649,7 +649,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
namedArgs[param.name!] = locals[param]!;
|
||||
}
|
||||
|
||||
final ParameterInfo paramInfo = translator.paramInfoFor(target);
|
||||
final ParameterInfo paramInfo = translator.paramInfoForDirectCall(target);
|
||||
|
||||
for (String name in paramInfo.names) {
|
||||
w.Local namedLocal = namedArgs[name]!;
|
||||
@@ -683,7 +683,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
setupParameters(member.reference, isForwarder: true);
|
||||
|
||||
w.FunctionType initializerMethodType =
|
||||
translator.functions.getFunctionType(member.initializerReference);
|
||||
translator.signatureForDirectCall(member.initializerReference);
|
||||
|
||||
List<w.Local> constructorArgs =
|
||||
_getConstructorArgumentLocals(member.reference);
|
||||
@@ -1011,7 +1011,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
List<w.ValueType> call(Reference target) {
|
||||
if (translator.shouldInline(target)) {
|
||||
w.FunctionType targetFunctionType =
|
||||
translator.functions.getFunctionType(target);
|
||||
translator.signatureForDirectCall(target);
|
||||
List<w.Local> inlinedLocals =
|
||||
targetFunctionType.inputs.map((t) => addLocal(t)).toList();
|
||||
for (w.Local local in inlinedLocals.reversed) {
|
||||
@@ -1066,18 +1066,18 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
void visitRedirectingInitializer(RedirectingInitializer node) {
|
||||
Class cls = (node.parent as Constructor).enclosingClass;
|
||||
|
||||
final Member targetMember = node.targetReference.asMember;
|
||||
|
||||
for (TypeParameter typeParam in cls.typeParameters) {
|
||||
types.makeType(
|
||||
this, TypeParameterType(typeParam, Nullability.nonNullable));
|
||||
}
|
||||
|
||||
_visitArguments(node.arguments, targetMember.initializerReference,
|
||||
cls.typeParameters.length);
|
||||
final targetMember = node.targetReference.asMember;
|
||||
final target = targetMember.initializerReference;
|
||||
_visitArguments(node.arguments, translator.signatureForDirectCall(target),
|
||||
translator.paramInfoForDirectCall(target), cls.typeParameters.length);
|
||||
|
||||
b.comment("Direct call of '$targetMember Redirected Initializer'");
|
||||
call(targetMember.initializerReference);
|
||||
call(target);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1088,17 +1088,20 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
|
||||
// Skip calls to the constructor for Object, as this is empty
|
||||
if (supersupertype != null) {
|
||||
final Member targetMember = node.targetReference.asMember;
|
||||
|
||||
for (DartType typeArg in supertype!.typeArguments) {
|
||||
types.makeType(this, typeArg);
|
||||
}
|
||||
|
||||
_visitArguments(node.arguments, targetMember.initializerReference,
|
||||
final targetMember = node.targetReference.asMember;
|
||||
final target = targetMember.initializerReference;
|
||||
_visitArguments(
|
||||
node.arguments,
|
||||
translator.signatureForDirectCall(target),
|
||||
translator.paramInfoForDirectCall(target),
|
||||
supertype.typeArguments.length);
|
||||
|
||||
b.comment("Direct call of '$targetMember Initializer'");
|
||||
call(targetMember.initializerReference);
|
||||
call(target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1862,9 +1865,11 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
ClassInfo info = translator.classInfo[node.target.enclosingClass]!;
|
||||
translator.functions.recordClassAllocation(info.classId);
|
||||
|
||||
_visitArguments(node.arguments, node.targetReference, 0);
|
||||
final target = node.targetReference;
|
||||
_visitArguments(node.arguments, translator.signatureForDirectCall(target),
|
||||
translator.paramInfoForDirectCall(target), 0);
|
||||
|
||||
return call(node.targetReference).single;
|
||||
return call(target).single;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1873,8 +1878,10 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
w.ValueType? intrinsicResult = intrinsifier.generateStaticIntrinsic(node);
|
||||
if (intrinsicResult != null) return intrinsicResult;
|
||||
|
||||
_visitArguments(node.arguments, node.targetReference, 0);
|
||||
return translator.outputOrVoid(call(node.targetReference));
|
||||
final target = node.targetReference;
|
||||
_visitArguments(node.arguments, translator.signatureForDirectCall(target),
|
||||
translator.paramInfoForDirectCall(target), 0);
|
||||
return translator.outputOrVoid(call(target));
|
||||
}
|
||||
|
||||
Member _lookupSuperTarget(Member interfaceTarget, {required bool setter}) {
|
||||
@@ -1889,7 +1896,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
Reference target =
|
||||
_lookupSuperTarget(node.interfaceTarget, setter: false).reference;
|
||||
w.FunctionType targetFunctionType =
|
||||
translator.functions.getFunctionType(target);
|
||||
translator.signatureForDirectCall(target);
|
||||
final w.ValueType receiverType = translator.preciseThisFor(target.asMember);
|
||||
|
||||
// When calling `==` and the argument is potentially nullable, check if the
|
||||
@@ -1927,7 +1934,8 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
}
|
||||
|
||||
visitThis(receiverType);
|
||||
_visitArguments(node.arguments, target, 1);
|
||||
_visitArguments(node.arguments, translator.signatureForDirectCall(target),
|
||||
translator.paramInfoForDirectCall(target), 1);
|
||||
return translator.outputOrVoid(call(target));
|
||||
}
|
||||
|
||||
@@ -1946,8 +1954,8 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
final w.Label nullReceiver = b.block();
|
||||
wrap(node.receiver, translator.topInfo.nullableType);
|
||||
b.br_on_null(nullReceiver);
|
||||
}, (_) {
|
||||
_visitArguments(node.arguments, node.interfaceTargetReference, 1);
|
||||
}, (w.FunctionType signature, ParameterInfo paramInfo) {
|
||||
_visitArguments(node.arguments, signature, paramInfo, 1);
|
||||
});
|
||||
b.br(done);
|
||||
b.end(); // end nullReceiver
|
||||
@@ -1964,10 +1972,14 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
target, (resultType) => wrap(StringLiteral("null"), resultType));
|
||||
case "noSuchMethod":
|
||||
return callWithNullCheck(target, (resultType) {
|
||||
final target = node.interfaceTargetReference;
|
||||
final signature = translator.signatureForDirectCall(target);
|
||||
final paramInfo = translator.paramInfoForDirectCall(target);
|
||||
|
||||
// Object? receiver
|
||||
b.ref_null(translator.topInfo.struct);
|
||||
// Invocation invocation
|
||||
_visitArguments(node.arguments, node.interfaceTargetReference, 1);
|
||||
_visitArguments(node.arguments, signature, paramInfo, 1);
|
||||
call(translator.noSuchMethodErrorThrowWithInvocation.reference);
|
||||
});
|
||||
default:
|
||||
@@ -1979,15 +1991,18 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
|
||||
Member? singleTarget = translator.singleTarget(node);
|
||||
if (singleTarget != null) {
|
||||
w.FunctionType targetFunctionType =
|
||||
translator.functions.getFunctionType(singleTarget.reference);
|
||||
wrap(node.receiver, targetFunctionType.inputs.first);
|
||||
_visitArguments(node.arguments, node.interfaceTargetReference, 1);
|
||||
return translator.outputOrVoid(call(singleTarget.reference));
|
||||
final target = singleTarget.reference;
|
||||
final signature = translator.signatureForDirectCall(target);
|
||||
final paramInfo = translator.paramInfoForDirectCall(target);
|
||||
wrap(node.receiver, signature.inputs.first);
|
||||
_visitArguments(node.arguments, signature, paramInfo, 1);
|
||||
|
||||
return translator.outputOrVoid(call(target));
|
||||
}
|
||||
return _virtualCall(node, target, _VirtualCallKind.Call,
|
||||
(signature) => wrap(node.receiver, signature.inputs.first), (_) {
|
||||
_visitArguments(node.arguments, node.interfaceTargetReference, 1);
|
||||
(signature) => wrap(node.receiver, signature.inputs.first),
|
||||
(w.FunctionType signature, ParameterInfo paramInfo) {
|
||||
_visitArguments(node.arguments, signature, paramInfo, 1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2120,7 +2135,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
}
|
||||
}
|
||||
|
||||
void right([_]) {
|
||||
void right([_, __]) {
|
||||
b.local_get(rightLocal);
|
||||
if (rightNullable) {
|
||||
b.ref_as_non_null();
|
||||
@@ -2170,7 +2185,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
Member interfaceTarget,
|
||||
_VirtualCallKind kind,
|
||||
void Function(w.FunctionType signature) pushReceiver,
|
||||
void Function(w.FunctionType signature) pushArguments) {
|
||||
void Function(w.FunctionType signature, ParameterInfo) pushArguments) {
|
||||
SelectorInfo selector = translator.dispatchTable.selectorForTarget(
|
||||
interfaceTarget.referenceAs(
|
||||
getter: kind.isGetter, setter: kind.isSetter));
|
||||
@@ -2179,8 +2194,11 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
pushReceiver(selector.signature);
|
||||
|
||||
if (selector.targetCount == 1) {
|
||||
pushArguments(selector.signature);
|
||||
return translator.outputOrVoid(call(selector.singularTarget!));
|
||||
final target = selector.singularTarget!;
|
||||
final signature = translator.signatureForDirectCall(target);
|
||||
final paramInfo = translator.paramInfoForDirectCall(target);
|
||||
pushArguments(signature, paramInfo);
|
||||
return translator.outputOrVoid(call(target));
|
||||
}
|
||||
|
||||
int? offset = selector.offset;
|
||||
@@ -2200,8 +2218,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
w.Local receiverVar = addLocal(selector.signature.inputs.first);
|
||||
assert(!receiverVar.type.nullable);
|
||||
b.local_tee(receiverVar);
|
||||
pushArguments(selector.signature);
|
||||
|
||||
pushArguments(selector.signature, selector.paramInfo);
|
||||
if (options.polymorphicSpecialization) {
|
||||
_polymorphicSpecialization(selector, receiverVar);
|
||||
} else {
|
||||
@@ -2374,7 +2391,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
}
|
||||
} else {
|
||||
w.FunctionType targetFunctionType =
|
||||
translator.functions.getFunctionType(target.reference);
|
||||
translator.signatureForDirectCall(target.reference);
|
||||
w.ValueType paramType = targetFunctionType.inputs.single;
|
||||
wrap(node.value, paramType);
|
||||
w.Local? temp;
|
||||
@@ -2426,7 +2443,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
w.Label nullLabel = b.block();
|
||||
wrap(node.receiver, translator.topInfo.nullableType);
|
||||
b.br_on_null(nullLabel);
|
||||
}, (_) {});
|
||||
}, (_, __) {});
|
||||
b.br(doneLabel);
|
||||
b.end(); // nullLabel
|
||||
switch (target.name.text) {
|
||||
@@ -2449,8 +2466,12 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
return _directGet(singleTarget, node.receiver,
|
||||
() => intrinsifier.generateInstanceGetterIntrinsic(node));
|
||||
} else {
|
||||
return _virtualCall(node, target, _VirtualCallKind.Get,
|
||||
(signature) => wrap(node.receiver, signature.inputs.first), (_) {});
|
||||
return _virtualCall(
|
||||
node,
|
||||
target,
|
||||
_VirtualCallKind.Get,
|
||||
(signature) => wrap(node.receiver, signature.inputs.first),
|
||||
(_, __) {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2542,7 +2563,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
// Instance call of getter
|
||||
assert(target is Procedure && target.isGetter);
|
||||
w.FunctionType targetFunctionType =
|
||||
translator.functions.getFunctionType(target.reference);
|
||||
translator.signatureForDirectCall(target.reference);
|
||||
wrap(receiver, targetFunctionType.inputs.single);
|
||||
return translator.outputOrVoid(call(target.reference));
|
||||
}
|
||||
@@ -2563,7 +2584,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
b.br_on_null(nullLabel);
|
||||
translator.convertType(
|
||||
function, translator.topInfo.nullableType, signature.inputs[0]);
|
||||
}, (_) {});
|
||||
}, (_, __) {});
|
||||
b.br(doneLabel);
|
||||
b.end(); // nullLabel
|
||||
switch (target.name.text) {
|
||||
@@ -2589,7 +2610,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
}
|
||||
|
||||
return _virtualCall(node, target, _VirtualCallKind.Get,
|
||||
(signature) => wrap(node.receiver, signature.inputs.first), (_) {});
|
||||
(signature) => wrap(node.receiver, signature.inputs.first), (_, __) {});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -2603,7 +2624,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
} else {
|
||||
_virtualCall(node, node.interfaceTarget, _VirtualCallKind.Set,
|
||||
(signature) => wrap(node.receiver, signature.inputs.first),
|
||||
(signature) {
|
||||
(signature, _) {
|
||||
w.ValueType paramType = signature.inputs.last;
|
||||
wrap(node.value, paramType);
|
||||
if (preserved) {
|
||||
@@ -2637,7 +2658,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
b.struct_set(info.struct, fieldIndex);
|
||||
} else {
|
||||
w.FunctionType targetFunctionType =
|
||||
translator.functions.getFunctionType(target.reference);
|
||||
translator.signatureForDirectCall(target.reference);
|
||||
w.ValueType paramType = targetFunctionType.inputs.last;
|
||||
wrap(receiver, targetFunctionType.inputs.first);
|
||||
wrap(value, paramType);
|
||||
@@ -2941,9 +2962,8 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
}
|
||||
}
|
||||
|
||||
void _visitArguments(Arguments node, Reference target, int signatureOffset) {
|
||||
final w.FunctionType signature = translator.signatureFor(target);
|
||||
final ParameterInfo paramInfo = translator.paramInfoFor(target);
|
||||
void _visitArguments(Arguments node, w.FunctionType signature,
|
||||
ParameterInfo paramInfo, int signatureOffset) {
|
||||
visitArgumentsLists(node.positional, signature, paramInfo, signatureOffset,
|
||||
typeArguments: node.types, named: node.named);
|
||||
}
|
||||
@@ -3492,7 +3512,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
} else {
|
||||
final setterProcedure = member_ as Procedure;
|
||||
final setterProcedureWasmType =
|
||||
translator.functions.getFunctionType(setterProcedure.reference);
|
||||
translator.signatureForDirectCall(setterProcedure.reference);
|
||||
final setterWasmInputs = setterProcedureWasmType.inputs;
|
||||
assert(setterWasmInputs.length == 2);
|
||||
b.local_get(receiverLocal);
|
||||
@@ -3521,7 +3541,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
final typeType =
|
||||
translator.classInfo[translator.typeClass]!.nonNullableType;
|
||||
|
||||
final targetParamInfo = translator.paramInfoFor(member.reference);
|
||||
final targetParamInfo = translator.paramInfoForDirectCall(member.reference);
|
||||
|
||||
final procedure = member as Procedure;
|
||||
|
||||
@@ -3630,7 +3650,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
||||
|
||||
// Argument types are as expected, call the member function
|
||||
final w.FunctionType memberWasmFunctionType =
|
||||
translator.functions.getFunctionType(member.reference);
|
||||
translator.signatureForDirectCall(member.reference);
|
||||
final List<w.ValueType> memberWasmInputs = memberWasmFunctionType.inputs;
|
||||
|
||||
b.local_get(receiverLocal);
|
||||
|
||||
@@ -45,6 +45,7 @@ class SelectorInfo {
|
||||
/// Maps class IDs to the selector's member in the class. The member can be
|
||||
/// abstract.
|
||||
final Map<int, Reference> targets = {};
|
||||
late final Set<Reference> targetSet = targets.values.toSet();
|
||||
|
||||
/// Wasm function type for the selector.
|
||||
///
|
||||
|
||||
@@ -224,7 +224,7 @@ class Forwarder {
|
||||
continue;
|
||||
}
|
||||
|
||||
final targetMemberParamInfo = translator.paramInfoFor(target);
|
||||
final targetMemberParamInfo = translator.paramInfoForDirectCall(target);
|
||||
|
||||
b.local_get(receiverLocal);
|
||||
b.struct_get(translator.topInfo.struct, FieldIndex.classId);
|
||||
|
||||
@@ -134,53 +134,62 @@ class FunctionCollector {
|
||||
w.BaseFunction getFunction(Reference target) {
|
||||
return _functions.putIfAbsent(target, () {
|
||||
_worklist.add(target);
|
||||
return _getFunctionTypeAndName(target, m.functions.define);
|
||||
return m.functions.define(
|
||||
translator.signatureForDirectCall(target), _getFunctionName(target));
|
||||
});
|
||||
}
|
||||
|
||||
w.FunctionType getFunctionType(Reference target) {
|
||||
return _getFunctionTypeAndName(target, (ftype, name) => ftype);
|
||||
return _getFunctionType(target);
|
||||
}
|
||||
|
||||
/// Pass the Wasm type and name of the function for [target] to [action].
|
||||
///
|
||||
/// Name should be used for the Wasm names section entry for the function so
|
||||
/// that the error stack traces will have names expected by the Dart spec.
|
||||
T _getFunctionTypeAndName<T>(
|
||||
Reference target, T Function(w.FunctionType, String) action) {
|
||||
w.FunctionType _getFunctionType(Reference target) {
|
||||
final Member member = target.asMember;
|
||||
if (target.isTypeCheckerReference) {
|
||||
Member member = target.asMember;
|
||||
if (member is Field || (member is Procedure && member.isSetter)) {
|
||||
return action(translator.dynamicSetForwarderFunctionType,
|
||||
'${target.asMember} setter type checker');
|
||||
return translator.dynamicSetForwarderFunctionType;
|
||||
} else {
|
||||
return action(translator.dynamicInvocationForwarderFunctionType,
|
||||
'${target.asMember} invocation type checker');
|
||||
return translator.dynamicInvocationForwarderFunctionType;
|
||||
}
|
||||
}
|
||||
|
||||
if (target.isTearOffReference) {
|
||||
return action(
|
||||
translator.dispatchTable.selectorForTarget(target).signature,
|
||||
"${target.asMember} tear-off");
|
||||
assert(!translator.dispatchTable
|
||||
.selectorForTarget(target)
|
||||
.targetSet
|
||||
.contains(target));
|
||||
return translator.signatureForDirectCall(target);
|
||||
}
|
||||
|
||||
Member member = target.asMember;
|
||||
final ftype = member.accept1(_FunctionTypeGenerator(translator), target);
|
||||
return member.accept1(_FunctionTypeGenerator(translator), target);
|
||||
}
|
||||
|
||||
String _getFunctionName(Reference target) {
|
||||
if (target.isTearOffReference) {
|
||||
return "${target.asMember} tear-off";
|
||||
}
|
||||
|
||||
final Member member = target.asMember;
|
||||
String memberName = member.toString();
|
||||
if (memberName.endsWith('.')) {
|
||||
memberName = memberName.substring(0, memberName.length - 1);
|
||||
}
|
||||
if (target.isTypeCheckerReference) {
|
||||
if (member is Field || (member is Procedure && member.isSetter)) {
|
||||
return '$memberName setter type checker';
|
||||
} else {
|
||||
return '$memberName invocation type checker';
|
||||
}
|
||||
}
|
||||
|
||||
if (target.isInitializerReference) {
|
||||
return action(ftype, 'new $memberName (initializer)');
|
||||
return 'new $memberName (initializer)';
|
||||
} else if (target.isConstructorBodyReference) {
|
||||
return action(ftype, 'new $memberName (constructor body)');
|
||||
return 'new $memberName (constructor body)';
|
||||
} else if (member is Procedure && member.isFactory) {
|
||||
return action(ftype, 'new $memberName');
|
||||
return 'new $memberName';
|
||||
} else {
|
||||
return action(ftype, memberName);
|
||||
return memberName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,15 +238,33 @@ class _FunctionTypeGenerator extends MemberVisitor1<w.FunctionType, Reference> {
|
||||
String kind = target == node.setterReference ? "setter" : "getter";
|
||||
throw "No implicit $kind function for static field: $node";
|
||||
}
|
||||
return translator.dispatchTable.selectorForTarget(target).signature;
|
||||
assert(!translator.dispatchTable
|
||||
.selectorForTarget(target)
|
||||
.targetSet
|
||||
.contains(target));
|
||||
|
||||
final receiverType = target.asMember.enclosingClass!
|
||||
.getThisType(translator.coreTypes, Nullability.nonNullable);
|
||||
return _makeFunctionType(
|
||||
translator, target, translator.translateType(receiverType));
|
||||
}
|
||||
|
||||
@override
|
||||
w.FunctionType visitProcedure(Procedure node, Reference target) {
|
||||
assert(!node.isAbstract);
|
||||
return node.isInstanceMember
|
||||
? translator.dispatchTable.selectorForTarget(node.reference).signature
|
||||
: _makeFunctionType(translator, target, null);
|
||||
if (!node.isInstanceMember) {
|
||||
return _makeFunctionType(translator, target, null);
|
||||
}
|
||||
|
||||
assert(!translator.dispatchTable
|
||||
.selectorForTarget(target)
|
||||
.targetSet
|
||||
.contains(target));
|
||||
|
||||
final receiverType = target.asMember.enclosingClass!
|
||||
.getThisType(translator.coreTypes, Nullability.nonNullable);
|
||||
return _makeFunctionType(
|
||||
translator, target, translator.translateType(receiverType));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -291,8 +318,8 @@ class _FunctionTypeGenerator extends MemberVisitor1<w.FunctionType, Reference> {
|
||||
|
||||
if (supersupertype != null) {
|
||||
ClassInfo superInfo = info.superInfo!;
|
||||
w.FunctionType superInitializer = translator.functions
|
||||
.getFunctionType(initializer.target.initializerReference);
|
||||
w.FunctionType superInitializer = translator
|
||||
.signatureForDirectCall(initializer.target.initializerReference);
|
||||
|
||||
final int numSuperclassFields = superInfo.getClassFieldTypes().length;
|
||||
final int numSuperContextAndConstructorArgs =
|
||||
@@ -307,8 +334,8 @@ class _FunctionTypeGenerator extends MemberVisitor1<w.FunctionType, Reference> {
|
||||
Supertype? supersupertype = initializer.target.enclosingClass.supertype;
|
||||
|
||||
if (supersupertype != null) {
|
||||
w.FunctionType redirectedInitializer = translator.functions
|
||||
.getFunctionType(initializer.target.initializerReference);
|
||||
w.FunctionType redirectedInitializer = translator
|
||||
.signatureForDirectCall(initializer.target.initializerReference);
|
||||
|
||||
final int numClassFields = info.getClassFieldTypes().length;
|
||||
final int numRedirectedContextAndConstructorArgs =
|
||||
@@ -374,8 +401,7 @@ class _FunctionTypeGenerator extends MemberVisitor1<w.FunctionType, Reference> {
|
||||
|
||||
if (supersupertype != null) {
|
||||
w.FunctionType superOrRedirectedConstructorBodyType = translator
|
||||
.functions
|
||||
.getFunctionType(target.constructorBodyReference);
|
||||
.signatureForDirectCall(target.constructorBodyReference);
|
||||
|
||||
// drop receiver param
|
||||
inputs += superOrRedirectedConstructorBodyType.inputs.sublist(1);
|
||||
|
||||
@@ -674,8 +674,8 @@ class Translator with KernelNodes {
|
||||
return tearOffFunctionCache.putIfAbsent(member, () {
|
||||
assert(member.kind == ProcedureKind.Method);
|
||||
w.BaseFunction target = functions.getFunction(member.reference);
|
||||
return getClosure(member.function, target, paramInfoFor(member.reference),
|
||||
"$member tear-off");
|
||||
return getClosure(member.function, target,
|
||||
paramInfoForDirectCall(member.reference), "$member tear-off");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -875,23 +875,35 @@ class Translator with KernelNodes {
|
||||
}
|
||||
}
|
||||
|
||||
w.FunctionType signatureFor(Reference target) {
|
||||
Member member = target.asMember;
|
||||
if (member.isInstanceMember) {
|
||||
return dispatchTable.selectorForTarget(target).signature;
|
||||
} else {
|
||||
return functions.getFunctionType(target);
|
||||
}
|
||||
w.FunctionType signatureForDispatchTableCall(Reference target) {
|
||||
assert(target.asMember.isInstanceMember);
|
||||
return dispatchTable.selectorForTarget(target).signature;
|
||||
}
|
||||
|
||||
ParameterInfo paramInfoFor(Reference target) {
|
||||
Member member = target.asMember;
|
||||
if (member.isInstanceMember) {
|
||||
return dispatchTable.selectorForTarget(target).paramInfo;
|
||||
} else {
|
||||
return staticParamInfo.putIfAbsent(
|
||||
target, () => ParameterInfo.fromMember(target));
|
||||
ParameterInfo paramInfoForDispatchTableCall(Reference target) {
|
||||
assert(target.asMember.isInstanceMember);
|
||||
return dispatchTable.selectorForTarget(target).paramInfo;
|
||||
}
|
||||
|
||||
w.FunctionType signatureForDirectCall(Reference target) {
|
||||
if (target.asMember.isInstanceMember) {
|
||||
final selector = dispatchTable.selectorForTarget(target);
|
||||
if (selector.targetSet.contains(target)) {
|
||||
return selector.signature;
|
||||
}
|
||||
}
|
||||
return functions.getFunctionType(target);
|
||||
}
|
||||
|
||||
ParameterInfo paramInfoForDirectCall(Reference target) {
|
||||
if (target.asMember.isInstanceMember) {
|
||||
final selector = dispatchTable.selectorForTarget(target);
|
||||
if (selector.targetSet.contains(target)) {
|
||||
return selector.paramInfo;
|
||||
}
|
||||
}
|
||||
return staticParamInfo.putIfAbsent(
|
||||
target, () => ParameterInfo.fromMember(target));
|
||||
}
|
||||
|
||||
w.ValueType preciseThisFor(Member member, {bool nullable = false}) {
|
||||
|
||||
@@ -428,8 +428,8 @@ class Types {
|
||||
b.local_get(operandTemp!);
|
||||
makeType(codeGen, testedAgainstType);
|
||||
if (location != null) {
|
||||
w.FunctionType verifyFunctionType = translator.functions
|
||||
.getFunctionType(translator.verifyOptimizedTypeCheck.reference);
|
||||
w.FunctionType verifyFunctionType = translator.signatureForDirectCall(
|
||||
translator.verifyOptimizedTypeCheck.reference);
|
||||
translator.constants.instantiateConstant(codeGen.function, b,
|
||||
StringConstant('$location'), verifyFunctionType.inputs.last);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
abstract class I {
|
||||
Base foo();
|
||||
Base get bar;
|
||||
}
|
||||
|
||||
abstract class A extends I {
|
||||
Base foo() => Sub1();
|
||||
Base get bar => Sub1();
|
||||
}
|
||||
|
||||
class B1 extends A {
|
||||
Base foo() {
|
||||
print(super.foo());
|
||||
return Sub2();
|
||||
}
|
||||
|
||||
Base get bar {
|
||||
print(super.bar);
|
||||
return Sub2();
|
||||
}
|
||||
}
|
||||
|
||||
class B2 extends A {
|
||||
Base foo() {
|
||||
print(super.foo());
|
||||
return Sub3();
|
||||
}
|
||||
|
||||
Base get bar {
|
||||
print(super.bar);
|
||||
return Sub3();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Base {}
|
||||
|
||||
class Sub1 extends Base {}
|
||||
|
||||
class Sub2 extends Base {}
|
||||
|
||||
class Sub3 extends Base {}
|
||||
|
||||
main() {
|
||||
final l = [B1(), B2()];
|
||||
Expect.isTrue(l[0].foo() is Sub2);
|
||||
Expect.isTrue(l[0].bar is Sub2);
|
||||
}
|
||||
Reference in New Issue
Block a user