Skip to content

Commit dd57e91

Browse files
mkustermannCommit Queue
authored andcommitted
[dart2wasm] Reduce base overhead of hello world
Currently we perform a type check of the `main` method against several function types at runtime to determine which version to use when invoking the user-written `main` method. This CL moves those checks to compile-time as we have the function type of the user-written `main` method available at compile time. This reduces the most simple hello world main() => print('hello world'); from 12 KB to 4 KB in -O4 mode. Change-Id: Icf49a1396e808274ac452c528b407a8bd1ef4bf6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/415440 Commit-Queue: Martin Kustermann <[email protected]> Reviewed-by: Ömer Ağacan <[email protected]>
1 parent b5821f9 commit dd57e91

File tree

2 files changed

+55
-20
lines changed

2 files changed

+55
-20
lines changed

pkg/dart2wasm/lib/compile.dart

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import 'package:kernel/core_types.dart';
2222
import 'package:kernel/kernel.dart'
2323
show writeComponentToBinary, writeComponentToText;
2424
import 'package:kernel/library_index.dart';
25+
import 'package:kernel/type_environment.dart';
2526
import 'package:kernel/verifier.dart';
2627
import 'package:path/path.dart' as path show setExtension;
2728
import 'package:vm/kernel_front_end.dart' show writeDepfile;
@@ -273,14 +274,7 @@ Future<CompilationResult> compileToModule(
273274
includeSource: false);
274275
}
275276

276-
// Patch `dart:_internal`s `mainTearOff` getter.
277-
final internalLib = component.libraries
278-
.singleWhere((lib) => lib.importUri.toString() == 'dart:_internal');
279-
final mainTearOff = internalLib.procedures
280-
.singleWhere((procedure) => procedure.name.text == 'mainTearOff');
281-
mainTearOff.isExternal = false;
282-
mainTearOff.function.body = ReturnStatement(
283-
ConstantExpression(StaticTearOffConstant(component.mainMethod!)));
277+
_patchMainTearOffs(coreTypes, component);
284278

285279
// Keep the flags in-sync with
286280
// pkg/vm/test/transformations/type_flow/transformer_test.dart
@@ -353,6 +347,38 @@ Future<CompilationResult> compileToModule(
353347
return CompilationSuccess(wasmModules, jsRuntime, supportJs);
354348
}
355349

350+
// Patches `dart:_internal`s `mainTearOff{0,1,2}` getters.
351+
void _patchMainTearOffs(CoreTypes coreTypes, Component component) {
352+
final mainMethod = component.mainMethod!;
353+
final mainMethodType = mainMethod.computeSignatureOrFunctionType();
354+
void patchToReturnMainTearOff(Procedure p) {
355+
p.function.body =
356+
ReturnStatement(ConstantExpression(StaticTearOffConstant(mainMethod)))
357+
..parent = p.function;
358+
}
359+
360+
final typeEnv =
361+
TypeEnvironment(coreTypes, ClassHierarchy(component, coreTypes));
362+
bool mainHasType(DartType type) => typeEnv.isSubtypeOf(
363+
mainMethodType, type, SubtypeCheckMode.withNullabilities);
364+
365+
final internalLib = coreTypes.index.getLibrary('dart:_internal');
366+
(Procedure, DartType) lookupAndInitialize(String name) {
367+
final p = internalLib.procedures
368+
.singleWhere((procedure) => procedure.name.text == name);
369+
p.isExternal = false;
370+
p.function.body = ReturnStatement(NullLiteral())..parent = p.function;
371+
return (p, p.function.returnType.toNonNull());
372+
}
373+
374+
final (mainTearOff0, mainArg0Type) = lookupAndInitialize('mainTearOffArg0');
375+
final (mainTearOff1, mainArg1Type) = lookupAndInitialize('mainTearOffArg1');
376+
final (mainTearOff2, mainArg2Type) = lookupAndInitialize('mainTearOffArg2');
377+
if (mainHasType(mainArg2Type)) return patchToReturnMainTearOff(mainTearOff2);
378+
if (mainHasType(mainArg1Type)) return patchToReturnMainTearOff(mainTearOff1);
379+
if (mainHasType(mainArg0Type)) return patchToReturnMainTearOff(mainTearOff0);
380+
}
381+
356382
String _generateSupportJs(TranslatorOptions options) {
357383
// Copied from
358384
// https://github.com/GoogleChromeLabs/wasm-feature-detect/blob/main/src/detectors/gc/index.js

sdk/lib/_internal/wasm/lib/internal_patch.dart

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,25 +121,34 @@ external int doubleToIntBits(double value);
121121
external double intBitsToDouble(int value);
122122

123123
// Will be patched in `pkg/dart2wasm/lib/compile.dart` right before TFA.
124-
external Function get mainTearOff;
124+
external void Function()? get mainTearOffArg0;
125+
external void Function(List<String>)? get mainTearOffArg1;
126+
external void Function(List<String>, Null)? get mainTearOffArg2;
125127

126128
/// Used to invoke the `main` function from JS, printing any exceptions that
127129
/// escape.
128130
@pragma("wasm:export", "\$invokeMain")
129131
void _invokeMain(WasmExternRef jsArrayRef) {
130132
try {
131-
final jsArray = (JSValue(jsArrayRef) as JSArray<JSString>).toDart;
132-
final args = <String>[for (final jsValue in jsArray) jsValue.toDart];
133-
final main = mainTearOff;
134-
if (main is void Function(List<String>, Null)) {
135-
main(List.unmodifiable(args), null);
136-
} else if (main is void Function(List<String>)) {
137-
main(List.unmodifiable(args));
138-
} else if (main is void Function()) {
139-
main();
140-
} else {
141-
throw "Could not call main";
133+
// We will only compile one of these cases, the remaining cases will be
134+
// eliminated by the compiler.
135+
if (mainTearOffArg0 case final mainMethod?) {
136+
mainMethod();
137+
return;
138+
}
139+
if (mainTearOffArg1 case final mainMethod?) {
140+
final jsArray = (JSValue(jsArrayRef) as JSArray<JSString>).toDart;
141+
final args = <String>[for (final jsValue in jsArray) jsValue.toDart];
142+
mainMethod(List.unmodifiable(args));
143+
return;
144+
}
145+
if (mainTearOffArg2 case final mainMethod?) {
146+
final jsArray = (JSValue(jsArrayRef) as JSArray<JSString>).toDart;
147+
final args = <String>[for (final jsValue in jsArray) jsValue.toDart];
148+
mainMethod(List.unmodifiable(args), null);
149+
return;
142150
}
151+
throw "Could not call main";
143152
} catch (e, s) {
144153
print(e);
145154
print(s);

0 commit comments

Comments
 (0)