Skip to content

Commit dd4ea07

Browse files
Use dart2wasm support-detection scripts (#3845)
* Use dart2wasm support expression * Fix looking up support file * Review feedback --------- Co-authored-by: David Morgan <[email protected]>
1 parent 4b6ca48 commit dd4ea07

File tree

5 files changed

+66
-21
lines changed

5 files changed

+66
-21
lines changed

build_web_compilers/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 4.1.2-wip
2+
3+
- Use support-detection scripts emitted by `dart2wasm`.
4+
15
## 4.1.1
26

37
- Support 3.8.0 pre-release sdks.

build_web_compilers/lib/src/dart2wasm_bootstrap.dart

+36-4
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,42 @@ import 'web_entrypoint_builder.dart';
1717

1818
final _resourcePool = Pool(maxWorkersPerTask);
1919

20+
/// Result of invoking the `dart2wasm` compiler.
21+
final class Dart2WasmBootstrapResult {
22+
/// Whether `dart2wasm` did compile the Dart program.
23+
///
24+
/// This is typically false when the program transitively imports an
25+
/// unsupported library, or if the compiler fails for another reason.
26+
final bool didCompile;
27+
28+
/// An optional JavaScript expression that might be emitted by `dart2wasm`.
29+
/// The expression evaluates to `true` if the current JavaScript environment
30+
/// supports all the features expected by the generated WebAssembly module.
31+
final String? supportExpression;
32+
33+
const Dart2WasmBootstrapResult.didNotCompile()
34+
: didCompile = false,
35+
supportExpression = null;
36+
37+
Dart2WasmBootstrapResult({
38+
required this.supportExpression,
39+
}) : didCompile = true;
40+
}
41+
2042
/// Invokes `dart compile wasm` to compile the primary input of [buildStep].
2143
///
2244
/// This only emits the `.wasm` and `.mjs` files produced by `dart2wasm`. An
2345
/// entrypoint loader needs to be emitted separately.
24-
Future<void> bootstrapDart2Wasm(
46+
Future<Dart2WasmBootstrapResult> bootstrapDart2Wasm(
2547
BuildStep buildStep,
2648
List<String> additionalArguments,
2749
String javaScriptModuleExtension,
2850
) async {
29-
await _resourcePool.withResource(() => _bootstrapDart2Wasm(
51+
return await _resourcePool.withResource(() => _bootstrapDart2Wasm(
3052
buildStep, additionalArguments, javaScriptModuleExtension));
3153
}
3254

33-
Future<void> _bootstrapDart2Wasm(
55+
Future<Dart2WasmBootstrapResult> _bootstrapDart2Wasm(
3456
BuildStep buildStep,
3557
List<String> additionalArguments,
3658
String javaScriptModuleExtension,
@@ -61,7 +83,7 @@ $librariesString
6183
6284
https://github.com/dart-lang/build/blob/master/docs/faq.md#how-can-i-resolve-skipped-compiling-warnings
6385
''');
64-
return;
86+
return const Dart2WasmBootstrapResult.didNotCompile();
6587
}
6688

6789
var scratchSpace = await buildStep.fetchResource(scratchSpaceResource);
@@ -123,5 +145,15 @@ https://github.com/dart-lang/build/blob/master/docs/faq.md#how-can-i-resolve-ski
123145
} else {
124146
log.severe('ExitCode:${result.exitCode}\nStdOut:\n${result.stdout}\n'
125147
'StdErr:\n${result.stderr}');
148+
return const Dart2WasmBootstrapResult.didNotCompile();
126149
}
150+
151+
var supportFile =
152+
scratchSpace.fileFor(dartEntrypointId.changeExtension('.support.js'));
153+
String? supportExpression;
154+
if (await supportFile.exists()) {
155+
supportExpression = await supportFile.readAsString();
156+
}
157+
158+
return Dart2WasmBootstrapResult(supportExpression: supportExpression);
127159
}

build_web_compilers/lib/src/web_entrypoint_builder.dart

+15-14
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ class WebEntrypointBuilder implements Builder {
290290
if (!isAppEntrypoint) return;
291291

292292
final compilationSteps = <Future>[];
293+
Dart2WasmBootstrapResult? dart2WasmResult;
293294

294295
for (final compiler in options.compilers) {
295296
switch (compiler.compiler) {
@@ -311,17 +312,21 @@ class WebEntrypointBuilder implements Builder {
311312
entrypointExtension: compiler.extension,
312313
));
313314
case WebCompiler.Dart2Wasm:
314-
compilationSteps.add(bootstrapDart2Wasm(
315-
buildStep, compiler.compilerArguments, compiler.extension));
315+
compilationSteps.add(Future(() async {
316+
dart2WasmResult = await bootstrapDart2Wasm(
317+
buildStep, compiler.compilerArguments, compiler.extension);
318+
}));
316319
}
317320
}
318321
await Future.wait(compilationSteps);
319-
if (_generateLoader(buildStep.inputId) case (var id, var loader)?) {
322+
if (_generateLoader(buildStep.inputId, dart2WasmResult)
323+
case (var id, var loader)?) {
320324
await buildStep.writeAsString(id, loader);
321325
}
322326
}
323327

324-
(AssetId, String)? _generateLoader(AssetId input) {
328+
(AssetId, String)? _generateLoader(
329+
AssetId input, Dart2WasmBootstrapResult? dart2WasmResult) {
325330
var loaderExtension = options.loaderExtension;
326331
var wasmCompiler = options.optionsFor(WebCompiler.Dart2Wasm);
327332
if (loaderExtension == null || wasmCompiler == null) {
@@ -350,17 +355,13 @@ function relativeURL(ref) {
350355
// If we're compiling to JS, start a feature detection to prefer wasm but
351356
// fall back to JS if necessary.
352357
if (jsCompiler != null) {
353-
loaderResult.writeln('''
354-
function supportsWasmGC() {
355-
// This attempts to instantiate a wasm module that only will validate if the
356-
// final WasmGC spec is implemented in the browser.
357-
//
358-
// Copied from https://github.com/GoogleChromeLabs/wasm-feature-detect/blob/main/src/detectors/gc/index.js
359-
const bytes = [0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 95, 1, 120, 0];
360-
return 'WebAssembly' in self && WebAssembly.validate(new Uint8Array(bytes));
361-
}
358+
final supportCheck = dart2WasmResult?.supportExpression ??
359+
"'WebAssembly' in self && "
360+
'WebAssembly.validate(new Uint8Array('
361+
'[0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 95, 1, 120, 0]));';
362362

363-
if (supportsWasmGC()) {
363+
loaderResult.writeln('''
364+
if ($supportCheck) {
364365
''');
365366
}
366367

build_web_compilers/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: build_web_compilers
2-
version: 4.1.1
2+
version: 4.1.2-wip
33
description: Builder implementations wrapping the dart2js and DDC compilers.
44
repository: https://github.com/dart-lang/build/tree/master/build_web_compilers
55
resolution: workspace

build_web_compilers/test/dart2wasm_bootstrap_test.dart

+10-2
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,17 @@ void main() {
6969
'a|web/index.dart.js': decodedMatches(
7070
stringContainsInOrder(
7171
[
72-
'if (supportsWasmGC())',
72+
'if',
73+
// Depending on whether dart2wasm emitted a .support.js file,
74+
// this check either comes from dart2wasm or from our own script
75+
// doing its own feature detection as a fallback. Which one is
76+
// used depends on the SDK version, we can only assume that the
77+
// check is guaranteed to include WebAssembly.validate to check
78+
// for WASM features.
79+
'WebAssembly.validate',
80+
'{',
7381
'compileStreaming',
74-
'else',
82+
'} else {',
7583
'scriptTag.src = relativeURL("./index.dart2js.js");'
7684
],
7785
),

0 commit comments

Comments
 (0)