[dart2wasm] Align test outcomes of dart2wasm across configurations
Aligns exit codes of
* `dart compile wasm` and
* `pkg/dart2wasm/tool/compile_benchmark`
Also make them use exit codes recognized by the test runner to
distinguish CFE crashes, CFE compile-time-errors and other failures.
Also update status file entries to from D8 specific entries
to JS commandline shell entries
=> Step towards aligning D8 & JSC test results
Change-Id: I1acb8803f5db7c732ad546d5989b1c555583e7c5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/383660
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
diff --git a/pkg/dart2wasm/lib/compile.dart b/pkg/dart2wasm/lib/compile.dart
index 1418700..5bbf4fd 100644
--- a/pkg/dart2wasm/lib/compile.dart
+++ b/pkg/dart2wasm/lib/compile.dart
@@ -45,11 +45,38 @@
import 'target.dart' hide Mode;
import 'translator.dart';
-class CompilerOutput {
+sealed class CompilationResult {}
+
+class CompilationSuccess extends CompilationResult {
final Map<String, ({Uint8List moduleBytes, String? sourceMap})> wasmModules;
final String jsRuntime;
- CompilerOutput(this.wasmModules, this.jsRuntime);
+ CompilationSuccess(this.wasmModules, this.jsRuntime);
+}
+
+class CompilationError extends CompilationResult {}
+
+/// The CFE has crashed with an exception.
+///
+/// This is a CFE bug and should be reported by users.
+class CFECrashError extends CompilationError {
+ final Object error;
+ final StackTrace stackTrace;
+
+ CFECrashError(this.error, this.stackTrace);
+}
+
+/// Compiling the Dart program resulted in compile-time errors.
+///
+/// This is a bug in the dart program (e.g. syntax errors, static type errors,
+/// ...) that's being compiled. Users have to address those errors in their
+/// code for it to compile successfully.
+///
+/// The errors are already printed via the `handleDiagnosticMessage` callback.
+/// (We print them as soon as they are reported by CFE. i.e. we stream errors
+/// instead of accumulating/batching all of them and reporting at the end.)
+class CFECompileTimeErrors extends CompilationError {
+ CFECompileTimeErrors();
}
/// Compile a Dart file into a Wasm module.
@@ -63,14 +90,14 @@
/// This value will be added to the Wasm module in `sourceMappingURL` section.
/// When this argument is null the code generator does not generate source
/// mappings.
-Future<CompilerOutput?> compileToModule(
+Future<CompilationResult> compileToModule(
compiler.WasmCompilerOptions options,
Uri Function(String moduleName)? sourceMapUrlGenerator,
void Function(DiagnosticMessage) handleDiagnosticMessage) async {
- var succeeded = true;
+ var hadCompileTimeError = false;
void diagnosticMessageHandler(DiagnosticMessage message) {
if (message.severity == Severity.error) {
- succeeded = false;
+ hadCompileTimeError = true;
}
handleDiagnosticMessage(message);
}
@@ -118,12 +145,16 @@
compilerOptions.compileSdk = true;
}
- CompilerResult? compilerResult =
- await kernelForProgram(options.mainUri, compilerOptions);
- if (compilerResult == null || !succeeded) {
- return null;
+ CompilerResult? compilerResult;
+ try {
+ compilerResult = await kernelForProgram(options.mainUri, compilerOptions);
+ } catch (e, s) {
+ return CFECrashError(e, s);
}
- Component component = compilerResult.component!;
+ if (hadCompileTimeError) return CFECompileTimeErrors();
+ assert(compilerResult != null);
+
+ Component component = compilerResult!.component!;
CoreTypes coreTypes = compilerResult.coreTypes!;
ClassHierarchy classHierarchy = compilerResult.classHierarchy!;
LibraryIndex libraryIndex = LibraryIndex(component, [
@@ -231,5 +262,5 @@
translator.internalizedStringsForJSRuntime,
mode);
- return CompilerOutput(wasmModules, jsRuntime);
+ return CompilationSuccess(wasmModules, jsRuntime);
}
diff --git a/pkg/dart2wasm/lib/generate_wasm.dart b/pkg/dart2wasm/lib/generate_wasm.dart
index 05f4311..292988f 100644
--- a/pkg/dart2wasm/lib/generate_wasm.dart
+++ b/pkg/dart2wasm/lib/generate_wasm.dart
@@ -47,17 +47,31 @@
? moduleNameToRelativeSourceMapUri
: null;
- CompilerOutput? output = await compileToModule(
- options,
- relativeSourceMapUrlMapper,
- (message) => printDiagnosticMessage(message, errorPrinter));
+ CompilationResult result =
+ await compileToModule(options, relativeSourceMapUrlMapper, (message) {
+ printDiagnosticMessage(message, errorPrinter);
+ });
- if (output == null) {
- return 1;
+ // If the compilation to wasm failed we use appropriate exit codes recognized
+ // by our test infrastructure. We use the same exit codes as the VM does. See:
+ // runtime/bin/error_exit.h:kDartFrontendErrorExitCode
+ // runtime/bin/error_exit.h:kCompilationErrorExitCode
+ // runtime/bin/error_exit.h:kErrorExitCode
+ if (result is! CompilationSuccess) {
+ if (result is CFECrashError) {
+ print('The compiler crashed with: ${result.error}');
+ print(result.stackTrace);
+ return 252;
+ }
+ if (result is CFECompileTimeErrors) {
+ return 254;
+ }
+
+ return 255;
}
final writeFutures = <Future>[];
- output.wasmModules.forEach((moduleName, moduleInfo) {
+ result.wasmModules.forEach((moduleName, moduleInfo) {
final (:moduleBytes, :sourceMap) = moduleInfo;
final File outFile = File(moduleNameToWasmOutputFile(moduleName));
outFile.parent.createSync(recursive: true);
@@ -72,7 +86,7 @@
final jsFile = options.outputJSRuntimeFile ??
path.setExtension(options.outputFile, '.mjs');
- await File(jsFile).writeAsString(output.jsRuntime);
+ await File(jsFile).writeAsString(result.jsRuntime);
return 0;
}
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index 4862d36..c8cc3f2 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -20,7 +20,7 @@
import '../utils.dart';
const int genericErrorExitCode = 255;
-const int compileErrorExitCode = 64;
+const int compileErrorExitCode = 254;
class Option {
final String flag;
@@ -847,7 +847,7 @@
];
try {
final exitCode = await runProcess(dart2wasmCommand);
- if (exitCode != 0) return compileErrorExitCode;
+ if (exitCode != 0) return exitCode;
} catch (e, st) {
log.stderr('Error: Wasm compilation failed');
log.stderr(e.toString());
diff --git a/pkg/dartdev/test/commands/compile_test.dart b/pkg/dartdev/test/commands/compile_test.dart
index 4fc8148..6a4a33f 100644
--- a/pkg/dartdev/test/commands/compile_test.dart
+++ b/pkg/dartdev/test/commands/compile_test.dart
@@ -12,7 +12,7 @@
import '../utils.dart';
-const int compileErrorExitCode = 64;
+const int compileErrorExitCode = 254;
void main() {
ensureRunFromSdkBinDart();
@@ -179,7 +179,7 @@
],
);
expect(result.stderr, contains('Compile Dart'));
- expect(result.exitCode, compileErrorExitCode);
+ expect(result.exitCode, 64);
});
test('--help', () async {
@@ -1310,7 +1310,7 @@
expect(result.stderr, isNot(contains(soundNullSafetyMessage)));
expect(result.stderr, contains('must be assigned before it can be used'));
- expect(result.exitCode, 64);
+ expect(result.exitCode, compileErrorExitCode);
});
test('Compile JIT snapshot with default (sound null safety)', () async {
diff --git a/pkg/test_runner/lib/src/command_output.dart b/pkg/test_runner/lib/src/command_output.dart
index 86d618c..7a100aa 100644
--- a/pkg/test_runner/lib/src/command_output.dart
+++ b/pkg/test_runner/lib/src/command_output.dart
@@ -919,6 +919,28 @@
super.stdout, super.stderr, super.time, super.compilationSkipped);
@override
+ Expectation result(TestCase testCase) {
+ if (hasCrashed) return Expectation.crash;
+ if (hasTimedOut) return Expectation.timeout;
+ if (hasNonUtf8) return Expectation.nonUtf8Error;
+ if (truncatedOutput) return Expectation.truncatedOutput;
+
+ switch (exitCode) {
+ case VMCommandOutput._dfeErrorExitCode:
+ return Expectation.dartkCrash;
+ case VMCommandOutput._compileErrorExitCode:
+ if (testCase.testFile.isStaticErrorTest) {
+ return _validateExpectedErrors(testCase);
+ }
+ return Expectation.compileTimeError;
+ case VMCommandOutput._uncaughtExceptionExitCode:
+ return Expectation.crash;
+ default:
+ return exitCode != 0 ? Expectation.fail : Expectation.pass;
+ }
+ }
+
+ @override
void _parseErrors() {
var errors = <StaticError>[];
// We expect errors to be printed to `stderr` for dart2wasm.
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 06259c5..7b35f9f 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -29,13 +29,6 @@
[ $runtime != chrome ]
js/static_interop_test/import/import_trustedscripturl_test: SkipByDesign # Trusted Types are only supported in Chrome currently.
-[ $runtime == d8 ]
-js/export/static_interop_mock/proto_test: SkipByDesign # Uses dart:html.
-js/static_interop_test/constants_test: SkipByDesign # Uses dart:html.
-js/static_interop_test/futurevaluetype_test: SkipByDesign # Uses dart:html.
-js/static_interop_test/import/import_test: SkipByDesign # TODO(srujzs): This test uses the file system to load a module. Since the test runner doesn't start an HTTP server for d8, I don't think this is supported.
-js/static_interop_test/supertype_transform_test: SkipByDesign # Uses dart:html.
-
[ $runtime == dart_precompiled ]
isolate/package_config_getter_test: SkipByDesign # AOT mode doesn't preserve package structure.
@@ -100,6 +93,13 @@
js/trust_types_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
js/type_parameter_lowering_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
+[ $jscl ]
+js/export/static_interop_mock/proto_test: SkipByDesign # Uses dart:html.
+js/static_interop_test/constants_test: SkipByDesign # Uses dart:html.
+js/static_interop_test/futurevaluetype_test: SkipByDesign # Uses dart:html.
+js/static_interop_test/import/import_test: SkipByDesign # TODO(srujzs): This test uses the file system to load a module. Since the test runner doesn't start an HTTP server for commandline JS shells, I don't think this is supported.
+js/static_interop_test/supertype_transform_test: SkipByDesign # Uses dart:html.
+
[ $simulator ]
convert/utf85_test: Skip # Pass, Slow Issue 20111.