[dart2wasm] Fix function instantiation in dynamic modules.

Closures are all invoked dynamically when dynamic modules are enabled so we can skip most of the closure representation logic. However, we still need to handle instantiation of type parameters.

Previously we had only one representation for all generic functions. However, the instantiation logic is dependent on the number of type parameters. So we update this to have one representation per type parameter count.

Fixes: https://github.com/dart-lang/sdk/issues/62592
Change-Id: I5ec1468e1f366ffe4db9b339f777e7de98efe12c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/479800
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
This commit is contained in:
Nate Biggs
2026-02-12 09:50:34 -08:00
committed by Commit Queue
parent c89aa814ee
commit c53054b9a8
5 changed files with 53 additions and 9 deletions
+5 -9
View File
@@ -203,10 +203,10 @@ class ClosureLayouter extends RecursiveVisitor {
representations;
// Dynamic submodules invoke closures dynamically so they use the base structs
// in all cases. Therefore, We only need one global copy of the
// ClosureRepresentation for generic and one for non-generic functions.
ClosureRepresentation? _dynamicSubmoduleRepresentation;
ClosureRepresentation? _dynamicSubmoduleGenericRepresentation;
// in all cases. Therefore, we only need one global copy of the
// ClosureRepresentation for each type parameter count.
final Map<int, ClosureRepresentation>
_dynamicSubmoduleGenericRepresentations = {};
Set<Constant> visitedConstants = Set.identity();
@@ -484,11 +484,7 @@ class ClosureLayouter extends RecursiveVisitor {
ClosureRepresentation? getClosureRepresentation(
int typeCount, int positionalCount, List<String> names) {
if (translator.dynamicModuleSupportEnabled) {
if (typeCount == 0) {
return _dynamicSubmoduleRepresentation ??=
_createRepresentation(typeCount, 0, const [], null, null, const []);
}
return _dynamicSubmoduleGenericRepresentation ??=
return _dynamicSubmoduleGenericRepresentations[typeCount] ??=
_createRepresentation(typeCount, 0, const [], null, null, const []);
}
final representations =
@@ -0,0 +1,7 @@
# Copyright (c) 2026, 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.
callable:
- library: 'dart:core'
- library: 'shared/shared.dart'
- library: 'package:expect/expect.dart'
@@ -0,0 +1,21 @@
// Copyright (c) 2026, 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 '../../common/testing.dart' as helper;
import 'package:expect/expect.dart';
import 'shared/shared.dart' as shared;
void main() async {
final wrap = shared.wrap<int, String>;
final wrapped = wrap(3, 'hello');
Expect.equals(3, wrapped.$1);
Expect.equals('hello', wrapped.$2);
final dynModWrap =
await helper.load('entry1.dart') as (bool, int) Function(bool k, int v);
final dynModWrapped = dynModWrap(true, 5);
Expect.equals(true, dynModWrapped.$1);
Expect.equals(5, dynModWrapped.$2);
helper.done();
}
@@ -0,0 +1,15 @@
// Copyright (c) 2026, 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 '../shared/shared.dart' as shared;
import 'package:expect/expect.dart';
@pragma('dyn-module:entry-point')
Object dynamicModuleEntrypoint() {
final wrap = shared.wrap<List<int>, String>;
final wrapped = wrap([20], 'foo');
Expect.equals(20, wrapped.$1[0]);
Expect.equals('foo', wrapped.$2);
return shared.wrap<bool, int>;
}
@@ -0,0 +1,5 @@
// Copyright (c) 2026, 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.
(K, V) wrap<K, V>(K k, V v) => (k, v);