Skip to content

Commit f6b74c3

Browse files
mkustermannCommit Queue
authored andcommitted
[dart2wasm] Retain CFE inserted deferred loading nodes for TFA
TFA has handling of the `LoadLibrary` & `CheckLibraryIsLoaded` nodes. It does logic based on them. For example it will ensure to that if one of these nodes is retained in the AST that we also retain the deferred library itself as well as the deferred library import. For now dart2wasm lowered those two nodes during modular transformations. This means TFA didn't see those nodes and weird things can happen (e.g. a `checkLibraryLoad()` call without that library existing anymore). Other interesting things that can happen: TFA sees only one call to `checklibraryLoad` and constant propagates the argument into the body & changes signature, ... We could keep the existing behavior and make TFA aware of the dart2wasm lowering (directly which is very hacky or via e.g. `Target` indirection). Though this seems too complex. So instead of making TFA aware of the lowerings, we move them to be after TFA. Though we want precise TFA results if we don't use deferred loading. So the approach is: If we actually need the runtime functions we'll inject `@pragma('wasm:entry-point')` annotations before running TFA and then lower those nodes after TFA. This also means we avoid the ugly CFE nodes lowering followed by lowering of the lowering (for load ids). Instead there's one place where we lower those two nodes and we choose either to lower to "load id" methods or the normal methods. This is part of moving constants to deferred modules. Issue #61727 Change-Id: Icebaf5a9495e00a8f85ecbf161b6ef891ea179ea Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/457700 Reviewed-by: Nate Biggs <[email protected]> Commit-Queue: Martin Kustermann <[email protected]>
1 parent 33fcfbf commit f6b74c3

File tree

14 files changed

+182
-114
lines changed

14 files changed

+182
-114
lines changed

pkg/dart2wasm/lib/code_generator.dart

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,9 @@ abstract class AstCodeGenerator
5454
extends ExpressionVisitor1<w.ValueType, w.ValueType>
5555
with
5656
ExpressionVisitor1DefaultMixin<w.ValueType, w.ValueType>,
57-
ExpressionVisitor1ExperimentExclusionMixin<w.ValueType,
58-
w.ValueType>,
57+
ExpressionVisitor1ExperimentExclusionMixin<w.ValueType, w.ValueType>,
5958
StatementVisitorExperimentExclusionMixin<void>
60-
implements
61-
InitializerVisitor<void>,
62-
StatementVisitor<void>,
63-
CodeGenerator {
59+
implements InitializerVisitor<void>, StatementVisitor<void>, CodeGenerator {
6460
final Translator translator;
6561
final w.FunctionType functionType;
6662
final Member enclosingMember;

pkg/dart2wasm/lib/compile.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ ModuleStrategy _createModuleStrategy(
584584
return DynamicSubmoduleStrategy(
585585
component, options, target, coreTypes, dynamicMainModuleUri!);
586586
}
587-
return DefaultModuleStrategy(component, options);
587+
return DefaultModuleStrategy(coreTypes, component, options);
588588
}
589589

590590
// Patches `dart:_internal`s `mainTearOff{0,1,2}` getters.

pkg/dart2wasm/lib/deferred_loading.dart

Lines changed: 103 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import 'compiler_options.dart';
1818
import 'generate_wasm.dart';
1919
import 'modules.dart';
2020
import 'target.dart';
21+
import 'util.dart' show addPragma;
2122

2223
/// The root of a deferred import subgraph.
2324
///
@@ -91,15 +92,21 @@ class DeferredLoadingModuleStrategy extends ModuleStrategy {
9192
DeferredLoadingModuleStrategy(
9293
this.component, this.options, this.kernelTarget, this.coreTypes);
9394

95+
late final deferredLoweringTransformer = options.loadsIdsUri != null
96+
? _DeferredLoadingLoweringLoadIds(component, coreTypes)
97+
: DeferredLoadingLoweringUris(coreTypes);
98+
9499
@override
95100
void prepareComponent() {
96-
if (options.loadsIdsUri != null) {
97-
component.accept(_DeferredLoadingLoadIdTransformer(component, coreTypes));
98-
}
101+
// Since we've deferred module loading enabled, we mark the necessary
102+
// runtime methods as entrypoints for TFA.
103+
deferredLoweringTransformer.markRuntimeFunctionsAsEntrypoints();
99104
}
100105

101106
@override
102107
Future<void> processComponentAfterTfa() async {
108+
component.accept(deferredLoweringTransformer);
109+
103110
final (libraryToRootSet, importTargetMap) = _buildLibraryToImports();
104111

105112
final builder = ModuleMetadataBuilder(options);
@@ -229,6 +236,10 @@ class StressTestModuleStrategy extends ModuleStrategy {
229236
final WasmCompilerOptions options;
230237
late final ModuleOutputData moduleOutputData;
231238

239+
late final deferredLoweringTransformer = options.loadsIdsUri != null
240+
? _DeferredLoadingLoweringLoadIds(component, coreTypes)
241+
: DeferredLoadingLoweringUris(coreTypes);
242+
232243
/// We load all 'dart:*' libraries since just doing the deferred load of modules
233244
/// requires a significant portion of the SDK libraries.
234245
late final Set<Library> _testModeMainLibraries = {
@@ -283,13 +294,15 @@ class StressTestModuleStrategy extends ModuleStrategy {
283294
await_transformer.transformLibraries(
284295
[invokeMain.enclosingLibrary], classHierarchy, coreTypes);
285296

286-
if (options.loadsIdsUri != null) {
287-
component.accept(_DeferredLoadingLoadIdTransformer(component, coreTypes));
288-
}
297+
// Since we've deferred module loading enabled, we mark the necessary
298+
// runtime methods as entrypoints for TFA.
299+
deferredLoweringTransformer.markRuntimeFunctionsAsEntrypoints();
289300
}
290301

291302
@override
292303
Future<void> processComponentAfterTfa() async {
304+
component.accept(deferredLoweringTransformer);
305+
293306
final moduleBuilder = ModuleMetadataBuilder(options);
294307
final mainModule = moduleBuilder.buildModuleMetadata();
295308
final initLibraries = _testModeMainLibraries;
@@ -409,27 +422,90 @@ String _generateDeferredMapJson(Component component, Uri rootLibraryUri,
409422
return const JsonEncoder.withIndent(' ').convert(output);
410423
}
411424

412-
class _DeferredLoadingLoadIdTransformer extends Transformer {
413-
final Procedure? _loadLibrary;
414-
final Procedure? _checkLibraryIsLoaded;
425+
abstract class DeferredLoadingLoweringBase extends Transformer {
426+
final CoreTypes coreTypes;
427+
428+
DeferredLoadingLoweringBase(this.coreTypes);
429+
430+
void markRuntimeFunctionsAsEntrypoints();
431+
432+
void addEntryPointPragma(Procedure node) {
433+
addPragma(node, 'wasm:entry-point', coreTypes, value: BoolConstant(true));
434+
}
435+
}
436+
437+
class DeferredLoadingLoweringUris extends DeferredLoadingLoweringBase {
438+
final Procedure _loadLibrary;
439+
final Procedure _checkLibraryIsLoaded;
440+
441+
DeferredLoadingLoweringUris(super.coreTypes)
442+
: _loadLibrary = coreTypes.index
443+
.getTopLevelProcedure('dart:_internal', 'loadLibrary'),
444+
_checkLibraryIsLoaded = coreTypes.index
445+
.getTopLevelProcedure('dart:_internal', 'checkLibraryIsLoaded');
446+
447+
@override
448+
void markRuntimeFunctionsAsEntrypoints() {
449+
addEntryPointPragma(_loadLibrary);
450+
addEntryPointPragma(_checkLibraryIsLoaded);
451+
}
452+
453+
@override
454+
TreeNode visitLibrary(Library node) {
455+
for (final dep in node.dependencies) {
456+
if (dep.isDeferred) {
457+
return super.visitLibrary(node);
458+
}
459+
}
460+
// No need to transform libraries without deferred imports.
461+
return node;
462+
}
463+
464+
@override
465+
TreeNode visitLoadLibrary(LoadLibrary node) {
466+
final import = node.import;
467+
return StaticInvocation(
468+
_loadLibrary,
469+
Arguments([
470+
StringLiteral('${import.enclosingLibrary.importUri}'),
471+
StringLiteral(import.name!)
472+
]));
473+
}
474+
475+
@override
476+
TreeNode visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
477+
final import = node.import;
478+
return StaticInvocation(
479+
_checkLibraryIsLoaded,
480+
Arguments([
481+
StringLiteral('${import.enclosingLibrary.importUri}'),
482+
StringLiteral(import.name!)
483+
]));
484+
}
485+
}
486+
487+
class _DeferredLoadingLoweringLoadIds extends DeferredLoadingLoweringBase {
415488
final Procedure _loadLibraryFromLoadId;
416489
final Procedure _checkLibraryIsLoadedFromLoadId;
490+
417491
final LoadIdRepository _loadIdRepository = LoadIdRepository();
418492
Map<String, int> _libraryLoadIds = {};
419493
int _loadIdCounter = 1;
420494

421-
_DeferredLoadingLoadIdTransformer(Component component, CoreTypes coreTypes)
422-
: _loadLibrary = coreTypes.index.tryGetProcedure(
423-
'dart:_internal', LibraryIndex.topLevel, 'loadLibrary'),
424-
_checkLibraryIsLoaded = coreTypes.index.tryGetProcedure(
425-
'dart:_internal', LibraryIndex.topLevel, 'checkLibraryIsLoaded'),
426-
_loadLibraryFromLoadId = coreTypes.index
495+
_DeferredLoadingLoweringLoadIds(Component component, super.coreTypes)
496+
: _loadLibraryFromLoadId = coreTypes.index
427497
.getTopLevelProcedure('dart:_internal', 'loadLibraryFromLoadId'),
428498
_checkLibraryIsLoadedFromLoadId = coreTypes.index.getTopLevelProcedure(
429499
'dart:_internal', 'checkLibraryIsLoadedFromLoadId') {
430500
component.addMetadataRepository(_loadIdRepository);
431501
}
432502

503+
@override
504+
void markRuntimeFunctionsAsEntrypoints() {
505+
addEntryPointPragma(_loadLibraryFromLoadId);
506+
addEntryPointPragma(_checkLibraryIsLoadedFromLoadId);
507+
}
508+
433509
@override
434510
TreeNode visitLibrary(Library node) {
435511
// Assign a load ID to each deferred import.
@@ -446,17 +522,19 @@ class _DeferredLoadingLoadIdTransformer extends Transformer {
446522
}
447523

448524
@override
449-
TreeNode visitStaticInvocation(StaticInvocation node) {
450-
if (node.target != _loadLibrary && node.target != _checkLibraryIsLoaded) {
451-
return super.visitStaticInvocation(node);
452-
}
453-
final [_, importPrefix as StringLiteral] = node.arguments.positional;
454-
final loadId = '${_libraryLoadIds[importPrefix.value]!}';
525+
TreeNode visitLoadLibrary(LoadLibrary node) {
526+
final import = node.import;
527+
final loadId = '${_libraryLoadIds[import.name!]!}';
528+
return StaticInvocation(
529+
_loadLibraryFromLoadId, Arguments([StringLiteral(loadId)]));
530+
}
531+
532+
@override
533+
TreeNode visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
534+
final import = node.import;
535+
final loadId = '${_libraryLoadIds[import.name!]!}';
455536
return StaticInvocation(
456-
node.target == _loadLibrary
457-
? _loadLibraryFromLoadId
458-
: _checkLibraryIsLoadedFromLoadId,
459-
Arguments([StringLiteral(loadId)]));
537+
_checkLibraryIsLoadedFromLoadId, Arguments([StringLiteral(loadId)]));
460538
}
461539
}
462540

pkg/dart2wasm/lib/dynamic_modules.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import 'class_info.dart';
2020
import 'code_generator.dart';
2121
import 'compiler_options.dart';
2222
import 'constants.dart' show maxArrayNewFixedLength;
23+
import 'deferred_loading.dart' show DeferredLoadingLoweringUris;
2324
import 'dispatch_table.dart';
2425
import 'dynamic_module_kernel_metadata.dart';
2526
import 'intrinsics.dart' show MemberIntrinsic;
@@ -117,6 +118,9 @@ class DynamicMainModuleStrategy extends ModuleStrategy with KernelNodes {
117118
this.dynamicInterfaceSpecificationBaseUri)
118119
: index = coreTypes.index;
119120

121+
late final deferredLoweringTransformer =
122+
DeferredLoadingLoweringUris(coreTypes);
123+
120124
@override
121125
void prepareComponent() {
122126
// Annotate the kernel with info from dynamic interface.
@@ -131,6 +135,8 @@ class DynamicMainModuleStrategy extends ModuleStrategy with KernelNodes {
131135

132136
component.addMetadataRepository(DynamicModuleConstantRepository());
133137
component.addMetadataRepository(DynamicModuleGlobalIdRepository());
138+
139+
deferredLoweringTransformer.markRuntimeFunctionsAsEntrypoints();
134140
}
135141

136142
@override
@@ -202,7 +208,9 @@ class DynamicMainModuleStrategy extends ModuleStrategy with KernelNodes {
202208
}
203209

204210
@override
205-
Future<void> processComponentAfterTfa() async {}
211+
Future<void> processComponentAfterTfa() async {
212+
component.accept(deferredLoweringTransformer);
213+
}
206214
}
207215

208216
class DynamicSubmoduleStrategy extends ModuleStrategy {

pkg/dart2wasm/lib/modules.dart

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:kernel/core_types.dart';
77
import 'package:path/path.dart' as path;
88

99
import 'compiler_options.dart';
10+
import 'deferred_loading.dart' show DeferredLoadingLoweringUris;
1011
import 'target.dart';
1112
import 'util.dart';
1213

@@ -101,10 +102,14 @@ class ModuleOutputData {
101102

102103
/// Module strategy that puts all libraries into a single module.
103104
class DefaultModuleStrategy extends ModuleStrategy {
105+
final CoreTypes coreTypes;
104106
final Component component;
105107
final WasmCompilerOptions options;
106108

107-
DefaultModuleStrategy(this.component, this.options);
109+
DefaultModuleStrategy(this.coreTypes, this.component, this.options);
110+
111+
late final deferredLoweringTransformer =
112+
DeferredLoadingLoweringUris(coreTypes);
108113

109114
@override
110115
ModuleOutputData buildModuleOutputData() {
@@ -117,10 +122,14 @@ class DefaultModuleStrategy extends ModuleStrategy {
117122
}
118123

119124
@override
120-
void prepareComponent() {}
125+
void prepareComponent() {
126+
deferredLoweringTransformer.markRuntimeFunctionsAsEntrypoints();
127+
}
121128

122129
@override
123-
Future<void> processComponentAfterTfa() async {}
130+
Future<void> processComponentAfterTfa() async {
131+
component.accept(deferredLoweringTransformer);
132+
}
124133
}
125134

126135
bool _hasWasmExportPragma(CoreTypes coreTypes, Member m) =>

pkg/dart2wasm/lib/transformers.dart

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,6 @@ class _WasmTransformer extends Transformer {
5757
final Procedure _trySetStackTraceForwarder;
5858
final Procedure _trySetStackTrace;
5959

60-
final Procedure _loadLibrary;
61-
final Procedure _checkLibraryIsLoaded;
62-
6360
final List<_AsyncStarFrame> _asyncStarFrames = [];
6461
bool _enclosingIsAsyncStar = false;
6562

@@ -164,10 +161,6 @@ class _WasmTransformer extends Transformer {
164161
.getTopLevelProcedure('dart:async', '_trySetStackTrace'),
165162
_trySetStackTrace = coreTypes.index
166163
.getProcedure('dart:core', 'Error', '_trySetStackTrace'),
167-
_loadLibrary = coreTypes.index
168-
.getTopLevelProcedure("dart:_internal", "loadLibrary"),
169-
_checkLibraryIsLoaded = coreTypes.index
170-
.getTopLevelProcedure("dart:_internal", "checkLibraryIsLoaded"),
171164
_factorySpecializer = FactorySpecializer(coreTypes),
172165
_pushPopWasmArrayTransformer = PushPopWasmArrayTransformer(coreTypes);
173166

@@ -838,30 +831,6 @@ class _WasmTransformer extends Transformer {
838831
return node.receiver;
839832
}
840833

841-
@override
842-
TreeNode visitLoadLibrary(LoadLibrary node) {
843-
node.transformChildren(this);
844-
final import = node.import;
845-
return StaticInvocation(
846-
_loadLibrary,
847-
Arguments([
848-
StringLiteral('${import.enclosingLibrary.importUri}'),
849-
StringLiteral(import.name!)
850-
]));
851-
}
852-
853-
@override
854-
TreeNode visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
855-
node.transformChildren(this);
856-
final import = node.import;
857-
return StaticInvocation(
858-
_checkLibraryIsLoaded,
859-
Arguments([
860-
StringLiteral('${import.enclosingLibrary.importUri}'),
861-
StringLiteral(import.name!)
862-
]));
863-
}
864-
865834
@override
866835
TreeNode visitThrow(Throw node) {
867836
node.transformChildren(this);

0 commit comments

Comments
 (0)