[dart2wasm] Make dynamic call forwarders use normal CallTarget infrastructure
So far running the compiler with `--print-wasm` wouldn't print
the code for dynamic call forwarders as it doesn't use the same
compiler infrastructure as normal function compilations.
This CL makes the dynamic call forwarders be `CallTarget`s that
can be called and if so will enqueue a `CompilationTask` in the
compilation queue.
This will ensure we treat those forwarders as any other target
we may call, which will also make e.g. `--print-wasm` work.
Change-Id: Ieb5673befa1456e941276d538e2212ff8d4077fc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/428700
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 5d11477..158c669 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -1754,9 +1754,10 @@
final typeArguments = node.arguments.types;
final positionalArguments = node.arguments.positional;
final namedArguments = node.arguments.named;
+ final memberName = node.name.text;
final forwarder = translator
.getDynamicForwardersForModule(b.module)
- .getDynamicInvocationForwarder(node.name.text);
+ .getDynamicInvocationForwarder(memberName);
// Evaluate receiver
translateExpression(receiver, translator.topInfo.nullableType);
@@ -1816,7 +1817,7 @@
// invocation of `noSuchMethod` (done in [_callNoSuchMethod]), but we don't
// have a `Null` class in dart2wasm so we throw directly.
b.local_get(nullableReceiverLocal);
- createInvocationObject(translator, b, forwarder.memberName, typeArgsLocal,
+ createInvocationObject(translator, b, memberName, typeArgsLocal,
positionalArgsLocal, namedArgsLocal);
call(translator.noSuchMethodErrorThrowWithInvocation.reference);
@@ -2173,9 +2174,10 @@
@override
w.ValueType visitDynamicGet(DynamicGet node, w.ValueType expectedType) {
final receiver = node.receiver;
+ final memberName = node.name.text;
final forwarder = translator
.getDynamicForwardersForModule(b.module)
- .getDynamicGetForwarder(node.name.text);
+ .getDynamicGetForwarder(memberName);
// Evaluate receiver
translateExpression(receiver, translator.topInfo.nullableType);
@@ -2189,7 +2191,7 @@
// invocation of `noSuchMethod` (done in [_callNoSuchMethod]), but we don't
// have a `Null` class in dart2wasm so we throw directly.
b.local_get(nullableReceiverLocal);
- createGetterInvocationObject(translator, b, forwarder.memberName);
+ createGetterInvocationObject(translator, b, memberName);
call(translator.noSuchMethodErrorThrowWithInvocation.reference);
b.unreachable();
@@ -2205,9 +2207,10 @@
w.ValueType visitDynamicSet(DynamicSet node, w.ValueType expectedType) {
final receiver = node.receiver;
final value = node.value;
+ final memberName = node.name.text;
final forwarder = translator
.getDynamicForwardersForModule(b.module)
- .getDynamicSetForwarder(node.name.text);
+ .getDynamicSetForwarder(memberName);
// Evaluate receiver
translateExpression(receiver, translator.topInfo.nullableType);
@@ -2226,8 +2229,7 @@
// invocation of `noSuchMethod` (done in [_callNoSuchMethod]), but we don't
// have a `Null` class in dart2wasm so we throw directly.
b.local_get(nullableReceiverLocal);
- createSetterInvocationObject(
- translator, b, forwarder.memberName, positionalArgLocal);
+ createSetterInvocationObject(translator, b, memberName, positionalArgLocal);
call(translator.noSuchMethodErrorThrowWithInvocation.reference);
b.unreachable();
diff --git a/pkg/dart2wasm/lib/dynamic_forwarders.dart b/pkg/dart2wasm/lib/dynamic_forwarders.dart
index 03237d1..045ba19 100644
--- a/pkg/dart2wasm/lib/dynamic_forwarders.dart
+++ b/pkg/dart2wasm/lib/dynamic_forwarders.dart
@@ -6,7 +6,7 @@
import 'package:wasm_builder/wasm_builder.dart' as w;
import 'class_info.dart';
-import 'code_generator.dart' show MacroAssembler;
+import 'code_generator.dart' show CallTarget, CodeGenerator, MacroAssembler;
import 'dispatch_table.dart';
import 'reference_extensions.dart';
import 'translator.dart';
@@ -18,36 +18,61 @@
final Translator translator;
final w.ModuleBuilder callingModule;
- final Map<String, Forwarder> _getterForwarderOfName = {};
- final Map<String, Forwarder> _setterForwarderOfName = {};
- final Map<String, Forwarder> _methodForwarderOfName = {};
+ final Map<String, CallTarget> _getterForwarderOfName = {};
+ final Map<String, CallTarget> _setterForwarderOfName = {};
+ final Map<String, CallTarget> _methodForwarderOfName = {};
DynamicForwarders(this.translator, this.callingModule);
- Forwarder getDynamicGetForwarder(String memberName) =>
- _getterForwarderOfName[memberName] ??= Forwarder._(
- translator, _ForwarderKind.Getter, memberName, callingModule)
- .._generateCode(translator);
+ CallTarget getDynamicGetForwarder(String memberName) =>
+ _getterForwarderOfName[memberName] ??= _DynamicForwarderCallTarget(
+ translator, _ForwarderKind.Getter, memberName, callingModule);
- Forwarder getDynamicSetForwarder(String memberName) =>
- _setterForwarderOfName[memberName] ??= Forwarder._(
- translator, _ForwarderKind.Setter, memberName, callingModule)
- .._generateCode(translator);
+ CallTarget getDynamicSetForwarder(String memberName) =>
+ _setterForwarderOfName[memberName] ??= _DynamicForwarderCallTarget(
+ translator, _ForwarderKind.Setter, memberName, callingModule);
- Forwarder getDynamicInvocationForwarder(String memberName) {
+ CallTarget getDynamicInvocationForwarder(String memberName) {
// Add Wasm function to the map before generating the forwarder code, to
// allow recursive calls in the "call" forwarder.
var forwarder = _methodForwarderOfName[memberName];
if (forwarder == null) {
- forwarder = Forwarder._(
+ forwarder = _DynamicForwarderCallTarget(
translator, _ForwarderKind.Method, memberName, callingModule);
_methodForwarderOfName[memberName] = forwarder;
- forwarder._generateCode(translator);
}
return forwarder;
}
}
+class _DynamicForwarderCallTarget extends CallTarget {
+ final Translator translator;
+ final _ForwarderKind _kind;
+ final String memberName;
+ final w.ModuleBuilder callingModule;
+
+ _DynamicForwarderCallTarget(
+ this.translator, this._kind, this.memberName, this.callingModule)
+ : assert(!translator.isDynamicSubmodule ||
+ (memberName == 'call' && _kind == _ForwarderKind.Getter)),
+ super(_kind.functionType(translator));
+
+ @override
+ String get name => 'Dynamic $_kind forwarder for "$memberName"';
+
+ @override
+ bool get supportsInlining => false;
+
+ @override
+ late final w.BaseFunction function = (() {
+ final function = callingModule.functions.define(signature, name);
+ final forwarder =
+ _DynamicForwarderCodeGenerator(translator, _kind, memberName, function);
+ translator.compilationQueue.add(CompilationTask(function, forwarder));
+ return function;
+ })();
+}
+
/// A function that "forwards" a dynamic get, set, or invocation to the right
/// type checking member.
///
@@ -67,21 +92,19 @@
/// A forwarder calls `noSuchMethod` on the receiver when a matching member is
/// not found, or the passed arguments do not match the expected parameters of
/// the member.
-class Forwarder {
+class _DynamicForwarderCodeGenerator extends CodeGenerator {
+ final Translator translator;
final _ForwarderKind _kind;
-
final String memberName;
-
final w.FunctionBuilder function;
- Forwarder._(Translator translator, this._kind, this.memberName,
- w.ModuleBuilder module)
- : function = module.functions.define(_kind.functionType(translator),
- "$_kind forwarder for '$memberName'"),
- assert(!translator.isDynamicSubmodule ||
- (memberName == 'call' && _kind == _ForwarderKind.Getter));
+ _DynamicForwarderCodeGenerator(
+ this.translator, this._kind, this.memberName, this.function);
- void _generateCode(Translator translator) {
+ @override
+ void generate(w.InstructionsBuilder b, List<w.Local> paramLocals,
+ w.Label? returnLabel) {
+ assert(returnLabel == null); // no inlining support atm.
switch (_kind) {
case _ForwarderKind.Getter:
_generateGetterCode(translator);