From 0889fdd8839ab179c8c1943c6b28842be7d1bc62 Mon Sep 17 00:00:00 2001 From: Martin Kustermann Date: Thu, 11 Jul 2024 13:54:13 +0000 Subject: [PATCH] [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 Reviewed-by: Slava Egorov --- pkg/dart2wasm/lib/async.dart | 4 +- pkg/dart2wasm/lib/code_generator.dart | 122 ++++++++++-------- pkg/dart2wasm/lib/dispatch_table.dart | 1 + pkg/dart2wasm/lib/dynamic_forwarders.dart | 2 +- pkg/dart2wasm/lib/functions.dart | 90 ++++++++----- pkg/dart2wasm/lib/translator.dart | 42 +++--- pkg/dart2wasm/lib/types.dart | 4 +- .../flutter_regession_151473_test.dart | 53 ++++++++ 8 files changed, 215 insertions(+), 103 deletions(-) create mode 100644 tests/language/flutter_regession_151473_test.dart diff --git a/pkg/dart2wasm/lib/async.dart b/pkg/dart2wasm/lib/async.dart index 6a04f22b8b9a..ff526b10f3d4 100644 --- a/pkg/dart2wasm/lib/async.dart +++ b/pkg/dart2wasm/lib/async.dart @@ -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( diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart index 833b9083490f..29e11a7fbcff 100644 --- a/pkg/dart2wasm/lib/code_generator.dart +++ b/pkg/dart2wasm/lib/code_generator.dart @@ -499,7 +499,7 @@ class CodeGenerator extends ExpressionVisitor1 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 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 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 setupParameters(member.reference, isForwarder: true); w.FunctionType initializerMethodType = - translator.functions.getFunctionType(member.initializerReference); + translator.signatureForDirectCall(member.initializerReference); List constructorArgs = _getConstructorArgumentLocals(member.reference); @@ -1011,7 +1011,7 @@ class CodeGenerator extends ExpressionVisitor1 List call(Reference target) { if (translator.shouldInline(target)) { w.FunctionType targetFunctionType = - translator.functions.getFunctionType(target); + translator.signatureForDirectCall(target); List inlinedLocals = targetFunctionType.inputs.map((t) => addLocal(t)).toList(); for (w.Local local in inlinedLocals.reversed) { @@ -1066,18 +1066,18 @@ class CodeGenerator extends ExpressionVisitor1 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 // 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 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? 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 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 } 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 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 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 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 } } - void right([_]) { + void right([_, __]) { b.local_get(rightLocal); if (rightNullable) { b.ref_as_non_null(); @@ -2170,7 +2185,7 @@ class CodeGenerator extends ExpressionVisitor1 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 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.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 } } 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.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 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 // 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 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 } 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 } 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 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 } } - 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 } 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 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 // Argument types are as expected, call the member function final w.FunctionType memberWasmFunctionType = - translator.functions.getFunctionType(member.reference); + translator.signatureForDirectCall(member.reference); final List memberWasmInputs = memberWasmFunctionType.inputs; b.local_get(receiverLocal); diff --git a/pkg/dart2wasm/lib/dispatch_table.dart b/pkg/dart2wasm/lib/dispatch_table.dart index 2cfb1eaba2af..63ed86245736 100644 --- a/pkg/dart2wasm/lib/dispatch_table.dart +++ b/pkg/dart2wasm/lib/dispatch_table.dart @@ -45,6 +45,7 @@ class SelectorInfo { /// Maps class IDs to the selector's member in the class. The member can be /// abstract. final Map targets = {}; + late final Set targetSet = targets.values.toSet(); /// Wasm function type for the selector. /// diff --git a/pkg/dart2wasm/lib/dynamic_forwarders.dart b/pkg/dart2wasm/lib/dynamic_forwarders.dart index 4815671e7ad8..62f17e7bf053 100644 --- a/pkg/dart2wasm/lib/dynamic_forwarders.dart +++ b/pkg/dart2wasm/lib/dynamic_forwarders.dart @@ -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); diff --git a/pkg/dart2wasm/lib/functions.dart b/pkg/dart2wasm/lib/functions.dart index aa493386c664..40da880f6bed 100644 --- a/pkg/dart2wasm/lib/functions.dart +++ b/pkg/dart2wasm/lib/functions.dart @@ -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( - 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 { 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 { 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 { 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 { if (supersupertype != null) { w.FunctionType superOrRedirectedConstructorBodyType = translator - .functions - .getFunctionType(target.constructorBodyReference); + .signatureForDirectCall(target.constructorBodyReference); // drop receiver param inputs += superOrRedirectedConstructorBodyType.inputs.sublist(1); diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart index 75450bd10fc2..1927e766c0f0 100644 --- a/pkg/dart2wasm/lib/translator.dart +++ b/pkg/dart2wasm/lib/translator.dart @@ -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 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 paramInfoFor(Reference target) { - Member member = target.asMember; - if (member.isInstanceMember) { - return dispatchTable.selectorForTarget(target).paramInfo; - } else { - return staticParamInfo.putIfAbsent( - target, () => ParameterInfo.fromMember(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}) { diff --git a/pkg/dart2wasm/lib/types.dart b/pkg/dart2wasm/lib/types.dart index b2f0addbc299..18c8d36f5f29 100644 --- a/pkg/dart2wasm/lib/types.dart +++ b/pkg/dart2wasm/lib/types.dart @@ -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 { diff --git a/tests/language/flutter_regession_151473_test.dart b/tests/language/flutter_regession_151473_test.dart new file mode 100644 index 000000000000..5573e883fbea --- /dev/null +++ b/tests/language/flutter_regession_151473_test.dart @@ -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); +}