[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:
Martin Kustermann
2024-07-11 13:54:13 +00:00
parent 0313dbd87d
commit 0889fdd883
8 changed files with 216 additions and 104 deletions
+2 -2
View File
@@ -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(
+71 -51
View File
@@ -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);
+1
View File
@@ -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.
///
+1 -1
View File
@@ -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);
+58 -32
View File
@@ -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);
+28 -16
View File
@@ -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}) {
+2 -2
View File
@@ -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);
}