| // Copyright (c) 2014, 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 'dart:io'; |
| |
| import 'command.dart'; |
| import 'configuration.dart'; |
| import 'path.dart'; |
| import 'repository.dart'; |
| import 'runtime_configuration.dart'; |
| import 'test_file.dart'; |
| import 'utils.dart'; |
| |
| List<String> _replaceDartFiles(List<String> list, String replacement) { |
| return list |
| .map((file) => file.endsWith(".dart") ? replacement : file) |
| .toList(); |
| } |
| |
| /// Generates a list with a single `--enable-experiment=` option that includes |
| /// all experiments enabled by [configuration] and [testFile]. |
| /// |
| /// Returns an empty list if there are no experiments to enable. Returning a |
| /// list allows the result of calling this to be spread into another list. |
| List<String> _experimentsArgument( |
| TestConfiguration configuration, TestFile testFile) { |
| var experiments = { |
| ...configuration.experiments, |
| ...testFile.experiments, |
| }; |
| if (experiments.isEmpty) { |
| return const []; |
| } |
| |
| return ['--enable-experiment=${experiments.join(',')}']; |
| } |
| |
| List<String> _nnbdModeArgument(TestConfiguration configuration) { |
| switch (configuration.nnbdMode) { |
| case NnbdMode.legacy: |
| return []; |
| case NnbdMode.strong: |
| return ['--sound-null-safety']; |
| case NnbdMode.weak: |
| return ['--no-sound-null-safety']; |
| } |
| |
| throw 'unreachable'; |
| } |
| |
| /// Grouping of a command with its expected result. |
| class CommandArtifact { |
| final List<Command> commands; |
| |
| /// Expected result of running [commands]. |
| final String filename; |
| |
| /// MIME type of [filename]. |
| final String mimeType; |
| |
| CommandArtifact(this.commands, this.filename, this.mimeType); |
| } |
| |
| abstract class CompilerConfiguration { |
| final TestConfiguration _configuration; |
| |
| bool get _isDebug => _configuration.mode.isDebug; |
| |
| bool get _isHostChecked => _configuration.isHostChecked; |
| |
| bool get _useSdk => _configuration.useSdk; |
| |
| bool get _enableAsserts => _configuration.enableAsserts; |
| |
| /// Whether to run the runtime on the compilation result of a test which |
| /// expects a compile-time error and the compiler did not emit one. |
| bool get runRuntimeDespiteMissingCompileTimeError => false; |
| |
| factory CompilerConfiguration(TestConfiguration configuration) { |
| switch (configuration.compiler) { |
| case Compiler.dart2analyzer: |
| return AnalyzerCompilerConfiguration(configuration); |
| |
| case Compiler.compareAnalyzerCfe: |
| return CompareAnalyzerCfeCompilerConfiguration(configuration); |
| |
| case Compiler.dart2js: |
| return Dart2jsCompilerConfiguration(configuration); |
| |
| case Compiler.dartdevc: |
| return DevCompilerConfiguration(configuration); |
| |
| case Compiler.dartdevk: |
| return DevCompilerConfiguration(configuration); |
| |
| case Compiler.appJitk: |
| return AppJitCompilerConfiguration(configuration); |
| |
| case Compiler.dartk: |
| if (configuration.architecture == Architecture.simarm || |
| configuration.architecture == Architecture.simarm64 || |
| configuration.architecture == Architecture.simarm64c || |
| configuration.system == System.android) { |
| return VMKernelCompilerConfiguration(configuration); |
| } |
| return NoneCompilerConfiguration(configuration); |
| |
| case Compiler.dartkp: |
| return PrecompilerCompilerConfiguration(configuration); |
| |
| case Compiler.specParser: |
| return SpecParserCompilerConfiguration(configuration); |
| |
| case Compiler.fasta: |
| return FastaCompilerConfiguration(configuration); |
| |
| case Compiler.none: |
| return NoneCompilerConfiguration(configuration); |
| } |
| |
| throw "unreachable"; |
| } |
| |
| CompilerConfiguration._subclass(this._configuration); |
| |
| /// A multiplier used to give tests longer time to run. |
| int get timeoutMultiplier { |
| if (_configuration.configuration.vmOptions |
| .any((s) => s.contains("optimization-counter-threshold"))) { |
| return 2; |
| } else { |
| return 1; |
| } |
| } |
| |
| String computeCompilerPath() { |
| throw "Unknown compiler for: $runtimeType"; |
| } |
| |
| bool get hasCompiler => true; |
| |
| List<Uri> bootstrapDependencies() => const <Uri>[]; |
| |
| CommandArtifact computeCompilationArtifact( |
| |
| /// Each test has its own temporary directory to avoid name collisions. |
| String tempDir, |
| List<String> arguments, |
| Map<String, String> environmentOverrides) { |
| return CommandArtifact([], null, null); |
| } |
| |
| List<String> computeCompilerArguments( |
| TestFile testFile, List<String> vmOptions, List<String> args) { |
| return [ |
| ...testFile.sharedOptions, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| ...args |
| ]; |
| } |
| |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| return [artifact.filename]; |
| } |
| } |
| |
| /// The "none" compiler. |
| class NoneCompilerConfiguration extends CompilerConfiguration { |
| NoneCompilerConfiguration(TestConfiguration configuration) |
| : super._subclass(configuration); |
| |
| bool get hasCompiler => false; |
| |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| return [ |
| if (_enableAsserts) '--enable_asserts', |
| if (_configuration.hotReload) |
| '--hot-reload-test-mode' |
| else if (_configuration.hotReloadRollback) |
| '--hot-reload-rollback-test-mode', |
| ...vmOptions, |
| ..._nnbdModeArgument(_configuration), |
| ...testFile.sharedOptions, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| ...originalArguments, |
| ...testFile.dartOptions |
| ]; |
| } |
| } |
| |
| class VMKernelCompilerConfiguration extends CompilerConfiguration |
| with VMKernelCompilerMixin { |
| VMKernelCompilerConfiguration(TestConfiguration configuration) |
| : super._subclass(configuration); |
| |
| bool get _isAot => false; |
| |
| // Issue(http://dartbug.com/29840): Currently fasta sometimes does not emit a |
| // compile-time error (even though it should). The VM will emit some of these |
| // compile-time errors (e.g. in constant evaluator, class finalizer, ...). |
| // |
| // => Since this distinction between fasta and vm reported compile-time |
| // errors do not exist when running dart with the kernel-service, we will |
| // also not make this distinction when compiling to .dill and then run. |
| // |
| // The corresponding http://dartbug.com/29840 tracks to get the frontend to |
| // emit all necessary compile-time errors (and *additionally* encode them |
| // in the AST in certain cases). |
| bool get runRuntimeDespiteMissingCompileTimeError => true; |
| |
| CommandArtifact computeCompilationArtifact(String tempDir, |
| List<String> arguments, Map<String, String> environmentOverrides) { |
| final commands = <Command>[ |
| computeCompileToKernelCommand(tempDir, arguments, environmentOverrides), |
| ]; |
| return CommandArtifact(commands, tempKernelFile(tempDir), |
| 'application/kernel-ir-fully-linked'); |
| } |
| |
| @override |
| List<String> computeCompilerArguments( |
| TestFile testFile, List<String> vmOptions, List<String> args) { |
| return [ |
| ...testFile.sharedOptions, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| ...vmOptions, |
| ..._nnbdModeArgument(_configuration), |
| ...args |
| ]; |
| } |
| |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| var filename = artifact.filename; |
| if (runtimeConfiguration is DartkAdbRuntimeConfiguration) { |
| // On Android the Dill file will be pushed to a different directory on the |
| // device. Use that one instead. |
| filename = "${DartkAdbRuntimeConfiguration.deviceTestDir}/out.dill"; |
| } |
| |
| return [ |
| if (_enableAsserts) '--enable_asserts', |
| if (_configuration.hotReload) |
| '--hot-reload-test-mode' |
| else if (_configuration.hotReloadRollback) |
| '--hot-reload-rollback-test-mode', |
| ...vmOptions, |
| ..._nnbdModeArgument(_configuration), |
| ...testFile.sharedOptions, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| ..._replaceDartFiles(originalArguments, filename), |
| ...testFile.dartOptions |
| ]; |
| } |
| } |
| |
| typedef CompilerArgumentsFunction = List<String> Function( |
| List<String> globalArguments, String previousCompilerOutput); |
| |
| class PipelineCommand { |
| final CompilerConfiguration compilerConfiguration; |
| final CompilerArgumentsFunction _argumentsFunction; |
| |
| PipelineCommand._(this.compilerConfiguration, this._argumentsFunction); |
| |
| factory PipelineCommand.runWithGlobalArguments( |
| CompilerConfiguration configuration) { |
| return PipelineCommand._(configuration, |
| (List<String> globalArguments, String previousOutput) { |
| assert(previousOutput == null); |
| return globalArguments; |
| }); |
| } |
| |
| factory PipelineCommand.runWithDartOrKernelFile( |
| CompilerConfiguration configuration) { |
| return PipelineCommand._(configuration, |
| (List<String> globalArguments, String previousOutput) { |
| var filtered = globalArguments |
| .where((name) => name.endsWith('.dart') || name.endsWith('.dill')) |
| .toList(); |
| assert(filtered.length == 1); |
| return filtered; |
| }); |
| } |
| |
| factory PipelineCommand.runWithPreviousKernelOutput( |
| CompilerConfiguration configuration) { |
| return PipelineCommand._(configuration, |
| (List<String> globalArguments, String previousOutput) { |
| assert(previousOutput.endsWith('.dill')); |
| return _replaceDartFiles(globalArguments, previousOutput); |
| }); |
| } |
| |
| List<String> extractArguments( |
| List<String> globalArguments, String previousOutput) { |
| return _argumentsFunction(globalArguments, previousOutput); |
| } |
| } |
| |
| class ComposedCompilerConfiguration extends CompilerConfiguration { |
| final List<PipelineCommand> pipelineCommands; |
| |
| ComposedCompilerConfiguration( |
| TestConfiguration configuration, this.pipelineCommands) |
| : super._subclass(configuration); |
| |
| CommandArtifact computeCompilationArtifact(String tempDir, |
| List<String> arguments, Map<String, String> environmentOverrides) { |
| var allCommands = <Command>[]; |
| |
| // The first compilation command is as usual. |
| var compileArguments = |
| pipelineCommands[0].extractArguments(arguments, null); |
| var artifact = pipelineCommands[0] |
| .compilerConfiguration |
| .computeCompilationArtifact( |
| tempDir, compileArguments, environmentOverrides); |
| allCommands.addAll(artifact.commands); |
| |
| // The following compilation commands are based on the output of the |
| // previous one. |
| for (var i = 1; i < pipelineCommands.length; i++) { |
| var command = pipelineCommands[i]; |
| |
| compileArguments = command.extractArguments(arguments, artifact.filename); |
| artifact = command.compilerConfiguration.computeCompilationArtifact( |
| tempDir, compileArguments, environmentOverrides); |
| |
| allCommands.addAll(artifact.commands); |
| } |
| |
| return CommandArtifact(allCommands, artifact.filename, artifact.mimeType); |
| } |
| |
| List<String> computeCompilerArguments( |
| TestFile testFile, List<String> vmOptions, List<String> args) { |
| // The result will be passed as an input to [extractArguments] |
| // (i.e. the arguments to the [PipelineCommand]). |
| return [ |
| ...vmOptions, |
| ...testFile.sharedOptions, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| ...args |
| ]; |
| } |
| |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| var lastCompilerConfiguration = pipelineCommands.last.compilerConfiguration; |
| return lastCompilerConfiguration.computeRuntimeArguments( |
| runtimeConfiguration, testFile, vmOptions, originalArguments, artifact); |
| } |
| } |
| |
| /// Common configuration for dart2js-based tools, such as dart2js. |
| class Dart2xCompilerConfiguration extends CompilerConfiguration { |
| static final Map<String, List<Uri>> _bootstrapDependenciesCache = {}; |
| |
| final String moniker; |
| |
| Dart2xCompilerConfiguration(this.moniker, TestConfiguration configuration) |
| : super._subclass(configuration); |
| |
| String computeCompilerPath() { |
| var prefix = 'sdk/bin'; |
| var suffix = shellScriptExtension; |
| |
| if (_isHostChecked) { |
| if (_useSdk) { |
| // Note: when [_useSdk] is true, dart2js is run from a snapshot that was |
| // built without checked mode. The VM cannot make such snapshot run in |
| // checked mode later. These two flags could be used together if we also |
| // build an sdk with checked snapshots. |
| throw "--host-checked and --use-sdk cannot be used together"; |
| } |
| // The script dart2js_developer is not included in the |
| // shipped SDK, that is the script is not installed in |
| // "$buildDir/dart-sdk/bin/" |
| return '$prefix/dart2js_developer$suffix'; |
| } |
| |
| if (_useSdk) { |
| prefix = '${_configuration.buildDirectory}/dart-sdk/bin'; |
| } |
| return '$prefix/dart2js$suffix'; |
| } |
| |
| Command computeCompilationCommand(String outputFileName, |
| List<String> arguments, Map<String, String> environmentOverrides) { |
| arguments = arguments.toList(); |
| arguments.add('--out=$outputFileName'); |
| |
| return CompilationCommand(moniker, outputFileName, bootstrapDependencies(), |
| computeCompilerPath(), arguments, environmentOverrides, |
| alwaysCompile: !_useSdk); |
| } |
| |
| List<Uri> bootstrapDependencies() { |
| if (!_useSdk) return const <Uri>[]; |
| return _bootstrapDependenciesCache.putIfAbsent( |
| _configuration.buildDirectory, |
| () => [ |
| Uri.base |
| .resolveUri(Uri.directory(_configuration.buildDirectory)) |
| .resolve('dart-sdk/bin/snapshots/dart2js.dart.snapshot') |
| ]); |
| } |
| } |
| |
| /// Configuration for dart2js. |
| class Dart2jsCompilerConfiguration extends Dart2xCompilerConfiguration { |
| Dart2jsCompilerConfiguration(TestConfiguration configuration) |
| : super('dart2js', configuration); |
| |
| List<String> computeCompilerArguments( |
| TestFile testFile, List<String> vmOptions, List<String> args) { |
| return [ |
| ...testFile.sharedOptions, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| ...testFile.dart2jsOptions, |
| ..._nnbdModeArgument(_configuration), |
| ...args |
| ]; |
| } |
| |
| CommandArtifact computeCompilationArtifact(String tempDir, |
| List<String> arguments, Map<String, String> environmentOverrides) { |
| var compilerArguments = [ |
| ...arguments, |
| ..._configuration.dart2jsOptions, |
| ..._nnbdModeArgument(_configuration), |
| ]; |
| |
| // TODO(athom): input filename extraction is copied from DDC. Maybe this |
| // should be passed to computeCompilationArtifact, instead? |
| var inputFile = arguments.last; |
| var inputFilename = Uri.file(inputFile).pathSegments.last; |
| var out = "$tempDir/${inputFilename.replaceAll('.dart', '.js')}"; |
| var babel = _configuration.babel; |
| var babelOut = out; |
| if (babel != null && babel.isNotEmpty) { |
| out = out.replaceAll('.js', '.raw.js'); |
| } |
| var commands = [ |
| computeCompilationCommand(out, compilerArguments, environmentOverrides), |
| if (babel != null && babel.isNotEmpty) |
| computeBabelCommand(out, babelOut, babel) |
| ]; |
| |
| return CommandArtifact(commands, babelOut, 'application/javascript'); |
| } |
| |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| var sdk = _useSdk |
| ? Uri.directory(_configuration.buildDirectory).resolve('dart-sdk/') |
| : Uri.directory(Repository.dir.toNativePath()).resolve('sdk/'); |
| var preambleDir = sdk.resolve('lib/_internal/js_runtime/lib/preambles/'); |
| return runtimeConfiguration.dart2jsPreambles(preambleDir) |
| ..add(artifact.filename); |
| } |
| |
| Command computeBabelCommand(String input, String output, String options) { |
| var uri = Repository.uri; |
| var babelTransform = |
| uri.resolve('pkg/test_runner/lib/src/babel_transform.js').toFilePath(); |
| var babelStandalone = |
| uri.resolve('third_party/babel/babel.min.js').toFilePath(); |
| return CompilationCommand( |
| 'babel', |
| output, |
| [], |
| _configuration.runtimeConfiguration.d8FileName, |
| [babelTransform, "--", babelStandalone, options, input], |
| {}, |
| alwaysCompile: true); // TODO(athom): ensure dependency tracking works. |
| } |
| } |
| |
| /// Configuration for `dartdevc` and `dartdevk` (DDC with Kernel) |
| class DevCompilerConfiguration extends CompilerConfiguration { |
| DevCompilerConfiguration(TestConfiguration configuration) |
| : super._subclass(configuration); |
| |
| bool get useKernel => _configuration.compiler == Compiler.dartdevk; |
| |
| String computeCompilerPath() { |
| var dir = _useSdk ? "${_configuration.buildDirectory}/dart-sdk" : "sdk"; |
| return "$dir/bin/dartdevc$shellScriptExtension"; |
| } |
| |
| List<String> computeCompilerArguments( |
| TestFile testFile, List<String> vmOptions, List<String> args) { |
| return [ |
| ...testFile.sharedOptions, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| ...testFile.ddcOptions, |
| if (_configuration.nnbdMode == NnbdMode.strong) '--sound-null-safety', |
| // The file being compiled is the last argument. |
| args.last |
| ]; |
| } |
| |
| Command _createCommand(String inputFile, String outputFile, |
| List<String> sharedOptions, Map<String, String> environment) { |
| var args = <String>[]; |
| // Remove option for generating non-null assertions for non-nullable |
| // method parameters in weak mode. DDC treats this as a runtime flag for |
| // the bootstrapping code, instead of a compiler option. |
| var options = sharedOptions.toList(); |
| options.remove('--null-assertions'); |
| if (!_useSdk) { |
| // If we're testing a built SDK, DDC will find its own summary. |
| // |
| // For local development we don't have a built SDK yet, so point directly |
| // at the built summary file location. |
| var sdkSummaryFile = _configuration.nnbdMode == NnbdMode.strong |
| ? 'ddc_outline_sound.dill' |
| : 'ddc_outline.dill'; |
| var sdkSummary = Path(_configuration.buildDirectory) |
| .append(sdkSummaryFile) |
| .absolute |
| .toNativePath(); |
| args.addAll(["--dart-sdk-summary", sdkSummary]); |
| } |
| args.addAll(options); |
| args.addAll(_configuration.sharedOptions); |
| |
| var d8Runtime = _configuration.runtime == Runtime.d8; |
| |
| args.addAll([ |
| "--ignore-unrecognized-flags", |
| "--no-summarize", |
| if (d8Runtime) "--modules=legacy", |
| "-o", |
| outputFile, |
| inputFile, |
| ]); |
| |
| if (!d8Runtime) { |
| // TODO(sigmund): allow caching of shared packages in legacy mode too. |
| // Link to the summaries for the available packages, so that they don't |
| // get recompiled into the test's own module. |
| var packageSummaryDir = _configuration.nnbdMode == NnbdMode.strong |
| ? 'pkg_sound' |
| : 'pkg_kernel'; |
| for (var package in testPackages) { |
| args.add("-s"); |
| |
| // Since the summaries for the packages are not near the tests, we give |
| // dartdevc explicit module paths for each one. When the test is run, we |
| // will tell require.js where to find each package's compiled JS. |
| var summary = Path(_configuration.buildDirectory) |
| .append("/gen/utils/dartdevc/$packageSummaryDir/$package.dill") |
| .absolute |
| .toNativePath(); |
| args.add("$summary=$package"); |
| } |
| } |
| |
| var inputDir = Path(inputFile).append("..").canonicalize().toNativePath(); |
| var displayName = useKernel ? 'dartdevk' : 'dartdevc'; |
| return CompilationCommand(displayName, outputFile, bootstrapDependencies(), |
| computeCompilerPath(), args, environment, |
| workingDirectory: inputDir); |
| } |
| |
| CommandArtifact computeCompilationArtifact(String tempDir, |
| List<String> arguments, Map<String, String> environmentOverrides) { |
| // The list of arguments comes from a call to our own |
| // computeCompilerArguments(). It contains the shared options followed by |
| // the input file path. |
| // TODO(rnystrom): Jamming these into a list in order to pipe them from |
| // computeCompilerArguments() to here seems hacky. Is there a cleaner way? |
| var sharedOptions = arguments.sublist(0, arguments.length - 1); |
| var inputFile = arguments.last; |
| var inputUri = Uri.file(inputFile); |
| var inputFilename = inputUri.pathSegments.last; |
| var moduleName = |
| inputFilename.substring(0, inputFilename.length - ".dart".length); |
| var outputFile = "$tempDir/$moduleName.js"; |
| var runFile = outputFile; |
| |
| if (_configuration.runtime == Runtime.d8) { |
| // TODO(sigmund): ddc should have a flag to emit an entrypoint file like |
| // the one below, otherwise it is succeptible to break, for example, if |
| // library naming conventions were to change in the future. |
| runFile = "$tempDir/$moduleName.d8.js"; |
| var nonNullAsserts = arguments.contains('--null-assertions'); |
| var nativeNonNullAsserts = arguments.contains('--native-null-assertions'); |
| var weakNullSafetyErrors = |
| arguments.contains('--weak-null-safety-errors'); |
| var soundNullSafety = _configuration.nnbdMode == NnbdMode.strong; |
| var weakNullSafetyWarnings = !(weakNullSafetyErrors || soundNullSafety); |
| var repositoryUri = Uri.directory(Repository.dir.toNativePath()); |
| var dartLibraryPath = repositoryUri |
| .resolve('pkg/dev_compiler/lib/js/legacy/dart_library.js') |
| .path; |
| var sdkJsDir = Uri.directory(_configuration.buildDirectory) |
| .resolve('gen/utils/dartdevc/'); |
| var sdkJsPath = soundNullSafety |
| ? 'sound/legacy/dart_sdk.js' |
| : 'kernel/legacy/dart_sdk.js'; |
| var libraryName = inputUri.path |
| .substring(repositoryUri.path.length) |
| .replaceAll("/", "__") |
| .replaceAll("-", "_") |
| .replaceAll(".dart", ""); |
| |
| // Note: this assumes that d8 is invoked with the dart2js d8.js preamble. |
| // TODO(sigmund): to support other runtimes like js-shell, we may want to |
| // remove the `load` statements here and instead provide those files |
| // through the runtime command-line arguments. |
| File(runFile).writeAsStringSync(''' |
| load("$dartLibraryPath"); |
| load("$sdkJsDir/$sdkJsPath"); |
| load("$outputFile"); |
| |
| let sdk = dart_library.import("dart_sdk"); |
| sdk.dart.weakNullSafetyWarnings($weakNullSafetyWarnings); |
| sdk.dart.weakNullSafetyErrors($weakNullSafetyErrors); |
| sdk.dart.nonNullAsserts($nonNullAsserts); |
| sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts); |
| |
| // Invoke main through the d8 preamble to ensure the code is running |
| // within the fake event loop. |
| self.dartMainRunner(function () { |
| dart_library.start("$moduleName", "$libraryName"); |
| }); |
| ''' |
| .replaceAll("\n ", "\n")); |
| } |
| |
| return CommandArtifact([ |
| _createCommand(inputFile, outputFile, sharedOptions, environmentOverrides) |
| ], runFile, "application/javascript"); |
| } |
| |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| var sdkDir = _useSdk |
| ? Uri.directory(_configuration.buildDirectory).resolve('dart-sdk/') |
| : Uri.directory(Repository.dir.toNativePath()).resolve('sdk/'); |
| var preambleDir = sdkDir.resolve('lib/_internal/js_runtime/lib/preambles/'); |
| return runtimeConfiguration.dart2jsPreambles(preambleDir) |
| ..add(artifact.filename); |
| } |
| } |
| |
| class PrecompilerCompilerConfiguration extends CompilerConfiguration |
| with VMKernelCompilerMixin { |
| bool get _isAndroid => _configuration.system == System.android; |
| |
| bool get _isArm => _configuration.architecture == Architecture.arm; |
| |
| bool get _isSimArm => _configuration.architecture == Architecture.simarm; |
| |
| bool get _isSimArm64 => |
| _configuration.architecture == Architecture.simarm64 || |
| _configuration.architecture == Architecture.simarm64c; |
| |
| bool get _isArmX64 => _configuration.architecture == Architecture.arm_x64; |
| |
| bool get _isArm64 => |
| _configuration.architecture == Architecture.arm64 || |
| _configuration.architecture == Architecture.arm64c; |
| |
| bool get _isX64 => |
| _configuration.architecture == Architecture.x64 || |
| _configuration.architecture == Architecture.x64c; |
| |
| bool get _isIA32 => _configuration.architecture == Architecture.ia32; |
| |
| bool get _isAot => true; |
| |
| PrecompilerCompilerConfiguration(TestConfiguration configuration) |
| : super._subclass(configuration); |
| |
| int get timeoutMultiplier { |
| var multiplier = 2; |
| if (_isDebug) multiplier *= 4; |
| if (_enableAsserts) multiplier *= 2; |
| return multiplier; |
| } |
| |
| CommandArtifact computeCompilationArtifact(String tempDir, |
| List<String> arguments, Map<String, String> environmentOverrides) { |
| var commands = <Command>[]; |
| |
| commands.add(computeCompileToKernelCommand( |
| tempDir, arguments, environmentOverrides)); |
| |
| commands.add( |
| computeDartBootstrapCommand(tempDir, arguments, environmentOverrides)); |
| |
| if (!_configuration.keepGeneratedFiles) { |
| commands.add(computeRemoveKernelFileCommand( |
| tempDir, arguments, environmentOverrides)); |
| } |
| |
| if (!_configuration.useElf) { |
| commands.add( |
| computeAssembleCommand(tempDir, arguments, environmentOverrides)); |
| if (!_configuration.keepGeneratedFiles) { |
| commands.add(computeRemoveAssemblyCommand( |
| tempDir, arguments, environmentOverrides)); |
| } |
| } |
| |
| if (_configuration.useElf && _isAndroid) { |
| // On Android, run the NDK's "strip" tool with "--strip-unneeded" to copy |
| // Flutter's workflow. Skip this step on tests for DWARF (which may get |
| // stripped). |
| if (!arguments.last.contains("dwarf")) { |
| commands.add(computeStripCommand(tempDir, environmentOverrides)); |
| } |
| } |
| |
| return CommandArtifact( |
| commands, '$tempDir', 'application/dart-precompiled'); |
| } |
| |
| /// Creates a command to clean up large temporary kernel files. |
| /// |
| /// Warning: this command removes temporary file and violates tracking of |
| /// dependencies between commands, which may cause problems if multiple |
| /// almost identical configurations are tested simultaneously. |
| Command computeRemoveKernelFileCommand(String tempDir, List arguments, |
| Map<String, String> environmentOverrides) { |
| String exec; |
| List<String> args; |
| |
| if (Platform.isWindows) { |
| exec = 'cmd.exe'; |
| args = ['/c', 'del', tempKernelFile(tempDir)]; |
| } else { |
| exec = 'rm'; |
| args = [tempKernelFile(tempDir)]; |
| } |
| |
| return CompilationCommand('remove_kernel_file', tempDir, |
| bootstrapDependencies(), exec, args, environmentOverrides, |
| alwaysCompile: !_useSdk); |
| } |
| |
| Command computeDartBootstrapCommand(String tempDir, List<String> arguments, |
| Map<String, String> environmentOverrides) { |
| var buildDir = _configuration.buildDirectory; |
| var exec = _configuration.genSnapshotPath; |
| if (exec == null) { |
| if (_isAndroid) { |
| if (_isArm || _isIA32) { |
| exec = "$buildDir/clang_x86/gen_snapshot"; |
| } else if (_isArm64 || _isX64 || _isArmX64) { |
| exec = "$buildDir/clang_x64/gen_snapshot"; |
| } else { |
| // Guaranteed by package:test_runner/src/configuration.dart's |
| // TestConfiguration.validate(). |
| assert(false); |
| } |
| } else if (_configuration.builderTag == "crossword") { |
| exec = "${buildDir}_X64/gen_snapshot"; |
| } else if (_isArm && _configuration.useQemu) { |
| // DebugXARM --> DebugSIMARM_X64 |
| final simBuildDir = buildDir.replaceAll("XARM", "SIMARM_X64"); |
| exec = "$simBuildDir/gen_snapshot"; |
| } else if (_isArm64 && _configuration.useQemu) { |
| exec = "$buildDir/clang_x64/gen_snapshot"; |
| } else { |
| exec = "$buildDir/gen_snapshot"; |
| } |
| } |
| |
| var args = [ |
| if (_configuration.useElf) ...[ |
| "--snapshot-kind=app-aot-elf", |
| "--elf=$tempDir/out.aotsnapshot", |
| // Only splitting with a ELF to avoid having to setup compilation of |
| // multiple assembly files in the test harness. |
| "--loading-unit-manifest=$tempDir/ignored.json", |
| ] else ...[ |
| "--snapshot-kind=app-aot-assembly", |
| "--assembly=$tempDir/out.S", |
| ], |
| if (_isAndroid && _isArm) '--no-sim-use-hardfp', |
| if (_configuration.isMinified) '--obfuscate', |
| // The SIMARM precompiler assumes support for integer division, but the |
| // Qemu arm cpus do not support integer division. |
| if (_configuration.useQemu) '--no-use-integer-division', |
| ..._replaceDartFiles(arguments, tempKernelFile(tempDir)), |
| ]; |
| |
| return CompilationCommand('precompiler', tempDir, bootstrapDependencies(), |
| exec, args, environmentOverrides, |
| alwaysCompile: !_useSdk); |
| } |
| |
| static const String ndkPath = "third_party/android_tools/ndk"; |
| String get abiTriple => _isArm || _isArmX64 |
| ? "arm-linux-androideabi" |
| : _isArm64 |
| ? "aarch64-linux-android" |
| : null; |
| String get host => Platform.isLinux |
| ? "linux" |
| : Platform.isMacOS |
| ? "darwin" |
| : null; |
| |
| Command computeAssembleCommand(String tempDir, List arguments, |
| Map<String, String> environmentOverrides) { |
| String cc, shared, ldFlags; |
| if (_isAndroid) { |
| cc = "$ndkPath/toolchains/$abiTriple-4.9/prebuilt/" |
| "$host-x86_64/bin/$abiTriple-gcc"; |
| shared = '-shared'; |
| } else if (Platform.isLinux) { |
| if (_isSimArm || (_isArm && _configuration.useQemu)) { |
| cc = 'arm-linux-gnueabihf-gcc'; |
| } else if (_isSimArm64 || (_isArm64 && _configuration.useQemu)) { |
| cc = 'aarch64-linux-gnu-gcc'; |
| } else { |
| cc = 'gcc'; |
| } |
| shared = '-shared'; |
| } else if (Platform.isMacOS) { |
| cc = 'clang'; |
| shared = '-dynamiclib'; |
| // Tell Mac linker to give up generating eh_frame from dwarf. |
| ldFlags = '-Wl,-no_compact_unwind'; |
| } else { |
| throw "Platform not supported: ${Platform.operatingSystem}"; |
| } |
| |
| String ccFlags; |
| switch (_configuration.architecture) { |
| case Architecture.x64: |
| case Architecture.x64c: |
| ccFlags = "-m64"; |
| break; |
| case Architecture.simarm64: |
| case Architecture.simarm64c: |
| case Architecture.ia32: |
| case Architecture.simarm: |
| case Architecture.arm: |
| case Architecture.arm_x64: |
| case Architecture.arm64: |
| case Architecture.arm64c: |
| ccFlags = null; |
| break; |
| default: |
| throw "Architecture not supported: ${_configuration.architecture.name}"; |
| } |
| |
| var args = [ |
| if (ccFlags != null) ccFlags, |
| if (ldFlags != null) ldFlags, |
| shared, |
| '-nostdlib', |
| '-o', |
| '$tempDir/out.aotsnapshot', |
| '$tempDir/out.S' |
| ]; |
| |
| return CompilationCommand('assemble', tempDir, bootstrapDependencies(), cc, |
| args, environmentOverrides, |
| alwaysCompile: !_useSdk); |
| } |
| |
| Command computeStripCommand( |
| String tempDir, Map<String, String> environmentOverrides) { |
| var stripTool = "$ndkPath/toolchains/$abiTriple-4.9/prebuilt/" |
| "$host-x86_64/bin/$abiTriple-strip"; |
| var args = ['--strip-unneeded', "$tempDir/out.aotsnapshot"]; |
| return CompilationCommand('strip', tempDir, bootstrapDependencies(), |
| stripTool, args, environmentOverrides, |
| alwaysCompile: !_useSdk); |
| } |
| |
| /// Creates a command to clean up large temporary assembly files. |
| /// |
| /// This step reduces the amount of space needed to run the precompilation |
| /// tests by 60%. |
| /// Warning: this command removes temporary file and violates tracking of |
| /// dependencies between commands, which may cause problems if multiple |
| /// almost identical configurations are tested simultaneously. |
| Command computeRemoveAssemblyCommand(String tempDir, List arguments, |
| Map<String, String> environmentOverrides) { |
| return CompilationCommand('remove_assembly', tempDir, |
| bootstrapDependencies(), 'rm', ['$tempDir/out.S'], environmentOverrides, |
| alwaysCompile: !_useSdk); |
| } |
| |
| List<String> filterVmOptions(List<String> vmOptions) { |
| var filtered = vmOptions.toList(); |
| filtered.removeWhere( |
| (option) => option.startsWith("--optimization-counter-threshold")); |
| filtered.removeWhere( |
| (option) => option.startsWith("--optimization_counter_threshold")); |
| return filtered; |
| } |
| |
| List<String> computeCompilerArguments( |
| TestFile testFile, List<String> vmOptions, List<String> args) { |
| return [ |
| if (_enableAsserts) '--enable_asserts', |
| ...filterVmOptions(vmOptions), |
| ...testFile.sharedOptions, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| ...args |
| ]; |
| } |
| |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| var dir = artifact.filename; |
| if (runtimeConfiguration is DartPrecompiledAdbRuntimeConfiguration) { |
| // On android the precompiled snapshot will be pushed to a different |
| // directory on the device, use that one instead. |
| dir = DartPrecompiledAdbRuntimeConfiguration.deviceTestDir; |
| } |
| originalArguments = |
| _replaceDartFiles(originalArguments, "$dir/out.aotsnapshot"); |
| |
| return [ |
| if (_enableAsserts) '--enable_asserts', |
| ...vmOptions, |
| ..._nnbdModeArgument(_configuration), |
| ...testFile.sharedOptions, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| ...originalArguments, |
| ...testFile.dartOptions |
| ]; |
| } |
| } |
| |
| class AppJitCompilerConfiguration extends CompilerConfiguration { |
| AppJitCompilerConfiguration(TestConfiguration configuration) |
| : super._subclass(configuration); |
| |
| int get timeoutMultiplier { |
| var multiplier = 1; |
| if (_isDebug) multiplier *= 2; |
| if (_enableAsserts) multiplier *= 2; |
| return multiplier; |
| } |
| |
| CommandArtifact computeCompilationArtifact(String tempDir, |
| List<String> arguments, Map<String, String> environmentOverrides) { |
| var snapshot = "$tempDir/out.jitsnapshot"; |
| return CommandArtifact( |
| [computeCompilationCommand(tempDir, arguments, environmentOverrides)], |
| snapshot, |
| 'application/dart-snapshot'); |
| } |
| |
| Command computeCompilationCommand(String tempDir, List<String> arguments, |
| Map<String, String> environmentOverrides) { |
| var snapshot = "$tempDir/out.jitsnapshot"; |
| return CompilationCommand( |
| 'app_jit', |
| tempDir, |
| bootstrapDependencies(), |
| "${_configuration.buildDirectory}/dart", |
| ["--snapshot=$snapshot", "--snapshot-kind=app-jit", ...arguments], |
| environmentOverrides, |
| alwaysCompile: !_useSdk); |
| } |
| |
| List<String> computeCompilerArguments( |
| TestFile testFile, List<String> vmOptions, List<String> args) { |
| return [ |
| if (_enableAsserts) '--enable_asserts', |
| ...vmOptions, |
| ..._nnbdModeArgument(_configuration), |
| ...testFile.sharedOptions, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| ...args, |
| ...testFile.dartOptions |
| ]; |
| } |
| |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| return [ |
| if (_enableAsserts) '--enable_asserts', |
| ...vmOptions, |
| ..._nnbdModeArgument(_configuration), |
| ...testFile.sharedOptions, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| ..._replaceDartFiles(originalArguments, artifact.filename), |
| ...testFile.dartOptions |
| ]; |
| } |
| } |
| |
| /// Configuration for dartanalyzer. |
| class AnalyzerCompilerConfiguration extends CompilerConfiguration { |
| AnalyzerCompilerConfiguration(TestConfiguration configuration) |
| : super._subclass(configuration); |
| |
| int get timeoutMultiplier => 4; |
| |
| String computeCompilerPath() { |
| var prefix = 'sdk/bin'; |
| if (_isHostChecked) { |
| if (_useSdk) { |
| throw "--host-checked and --use-sdk cannot be used together"; |
| } |
| // The script dartanalyzer_developer is not included in the |
| // shipped SDK, that is the script is not installed in |
| // "$buildDir/dart-sdk/bin/" |
| return '$prefix/dartanalyzer_developer$shellScriptExtension'; |
| } |
| if (_useSdk) { |
| prefix = '${_configuration.buildDirectory}/dart-sdk/bin'; |
| } |
| return '$prefix/dartanalyzer$shellScriptExtension'; |
| } |
| |
| CommandArtifact computeCompilationArtifact(String tempDir, |
| List<String> arguments, Map<String, String> environmentOverrides) { |
| const legacyTestDirectories = { |
| "co19_2", |
| "corelib_2", |
| "ffi_2", |
| "language_2", |
| "lib_2", |
| "service_2", |
| "standalone_2" |
| }; |
| |
| // If we are running a legacy test with NNBD enabled, tell analyzer to use |
| // a pre-NNBD language version for the test. |
| var testPath = arguments.last; |
| var segments = Path(testPath).relativeTo(Repository.dir).segments(); |
| var setLegacyVersion = segments.any(legacyTestDirectories.contains); |
| |
| var args = [ |
| ...arguments, |
| if (_configuration.useAnalyzerCfe) '--use-cfe', |
| if (_configuration.useAnalyzerFastaParser) '--use-fasta-parser', |
| if (setLegacyVersion) '--default-language-version=2.7', |
| ]; |
| |
| // Since this is not a real compilation, no artifacts are produced. |
| return CommandArtifact( |
| [AnalysisCommand(computeCompilerPath(), args, environmentOverrides)], |
| null, |
| null); |
| } |
| |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| return []; |
| } |
| } |
| |
| /// Configuration for compareAnalyzerCfe. |
| class CompareAnalyzerCfeCompilerConfiguration extends CompilerConfiguration { |
| CompareAnalyzerCfeCompilerConfiguration(TestConfiguration configuration) |
| : super._subclass(configuration); |
| |
| int get timeoutMultiplier => 4; |
| |
| String computeCompilerPath() { |
| if (_useSdk) { |
| throw "--use-sdk cannot be used with compiler compare_analyzer_cfe"; |
| } |
| return 'pkg/analyzer_fe_comparison/bin/' |
| 'compare_sdk_tests$shellScriptExtension'; |
| } |
| |
| CommandArtifact computeCompilationArtifact(String tempDir, |
| List<String> arguments, Map<String, String> environmentOverrides) { |
| // Since this is not a real compilation, no artifacts are produced. |
| return CommandArtifact([ |
| CompareAnalyzerCfeCommand( |
| computeCompilerPath(), arguments.toList(), environmentOverrides) |
| ], null, null); |
| } |
| |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| return []; |
| } |
| } |
| |
| /// Configuration for spec_parser. |
| class SpecParserCompilerConfiguration extends CompilerConfiguration { |
| SpecParserCompilerConfiguration(TestConfiguration configuration) |
| : super._subclass(configuration); |
| |
| String computeCompilerPath() => 'tools/spec_parse.py'; |
| |
| CommandArtifact computeCompilationArtifact(String tempDir, |
| List<String> arguments, Map<String, String> environmentOverrides) { |
| arguments = arguments.toList(); |
| |
| // Since this is not a real compilation, no artifacts are produced. |
| return CommandArtifact([ |
| SpecParseCommand(computeCompilerPath(), arguments, environmentOverrides) |
| ], null, null); |
| } |
| |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| return []; |
| } |
| } |
| |
| abstract class VMKernelCompilerMixin { |
| TestConfiguration get _configuration; |
| |
| bool get _useSdk; |
| |
| bool get _isAot; |
| |
| bool get _enableAsserts; |
| |
| List<Uri> bootstrapDependencies(); |
| |
| String tempKernelFile(String tempDir) => |
| Path('$tempDir/out.dill').toNativePath(); |
| |
| Command computeCompileToKernelCommand(String tempDir, List<String> arguments, |
| Map<String, String> environmentOverrides) { |
| var pkgVmDir = Platform.script.resolve('../../../pkg/vm').toFilePath(); |
| var genKernel = '$pkgVmDir/tool/gen_kernel$shellScriptExtension'; |
| |
| var kernelBinariesFolder = '${_configuration.buildDirectory}'; |
| if (_useSdk) { |
| kernelBinariesFolder += '/dart-sdk/lib/_internal'; |
| } |
| |
| var vmPlatform = '$kernelBinariesFolder/vm_platform_strong.dill'; |
| |
| var dillFile = tempKernelFile(tempDir); |
| |
| var isProductMode = _configuration.configuration.mode == Mode.product; |
| |
| var args = [ |
| _isAot ? '--aot' : '--no-aot', |
| '--platform=$vmPlatform', |
| '-o', |
| dillFile, |
| arguments.where((name) => name.endsWith('.dart')).single, |
| ...arguments.where((name) => |
| name.startsWith('-D') || |
| name.startsWith('--define') || |
| name.startsWith('--packages=') || |
| name.startsWith('--enable-experiment=')), |
| '-Ddart.vm.product=$isProductMode', |
| if (_enableAsserts || |
| arguments.contains('--enable-asserts') || |
| arguments.contains('--enable_asserts')) |
| '--enable-asserts', |
| ..._nnbdModeArgument(_configuration), |
| ..._configuration.genKernelOptions, |
| ]; |
| |
| return VMKernelCompilationCommand(dillFile, bootstrapDependencies(), |
| genKernel, args, environmentOverrides, |
| alwaysCompile: true); |
| } |
| } |
| |
| class FastaCompilerConfiguration extends CompilerConfiguration { |
| static final _compilerLocation = |
| Repository.uri.resolve("pkg/front_end/tool/_fasta/compile.dart"); |
| |
| final Uri _platformDill; |
| |
| final Uri _vmExecutable; |
| |
| factory FastaCompilerConfiguration(TestConfiguration configuration) { |
| var buildDirectory = |
| Uri.base.resolveUri(Uri.directory(configuration.buildDirectory)); |
| |
| var dillDir = buildDirectory; |
| if (configuration.useSdk) { |
| dillDir = buildDirectory.resolve("dart-sdk/lib/_internal/"); |
| } |
| |
| var platformDill = dillDir.resolve("vm_platform_strong.dill"); |
| |
| var vmExecutable = buildDirectory |
| .resolve(configuration.useSdk ? "dart-sdk/bin/dart" : "dart"); |
| return FastaCompilerConfiguration._( |
| platformDill, vmExecutable, configuration); |
| } |
| |
| FastaCompilerConfiguration._( |
| this._platformDill, this._vmExecutable, TestConfiguration configuration) |
| : super._subclass(configuration); |
| |
| @override |
| bool get runRuntimeDespiteMissingCompileTimeError => true; |
| |
| @override |
| List<Uri> bootstrapDependencies() => [_platformDill]; |
| |
| @override |
| CommandArtifact computeCompilationArtifact(String tempDir, |
| List<String> arguments, Map<String, String> environmentOverrides) { |
| var output = |
| Uri.base.resolveUri(Uri.directory(tempDir)).resolve("out.dill"); |
| var outputFileName = output.toFilePath(); |
| |
| var compilerArguments = [ |
| '--verify', |
| '--skip-platform-verification', |
| "-o", |
| outputFileName, |
| "--platform", |
| _platformDill.toFilePath(), |
| ...arguments |
| ]; |
| |
| return CommandArtifact([ |
| FastaCompilationCommand( |
| _compilerLocation, |
| output.toFilePath(), |
| bootstrapDependencies(), |
| _vmExecutable.toFilePath(), |
| compilerArguments, |
| environmentOverrides, |
| Repository.uri.toFilePath()) |
| ], outputFileName, "application/x.dill"); |
| } |
| |
| @override |
| List<String> computeCompilerArguments( |
| TestFile testFile, List<String> vmOptions, List<String> args) { |
| // Remove shared option for generating non-null assertions for non-nullable |
| // method parameters in weak mode. It's currently unused by the front end. |
| var options = testFile.sharedOptions.toList(); |
| options.remove('--null-assertions'); |
| var arguments = [ |
| ...options, |
| ..._configuration.sharedOptions, |
| ..._experimentsArgument(_configuration, testFile), |
| if (_configuration.configuration.nnbdMode == NnbdMode.strong) ...[ |
| "--nnbd-strong" |
| ] |
| ]; |
| for (var argument in args) { |
| if (argument == "--ignore-unrecognized-flags") continue; |
| arguments.add(argument); |
| if (!argument.startsWith("-")) { |
| // Some tests pass arguments to the Dart program; that is, arguments |
| // after the name of the test file. Such arguments have nothing to do |
| // with the compiler and should be ignored. |
| break; |
| } |
| } |
| return arguments; |
| } |
| |
| @override |
| List<String> computeRuntimeArguments( |
| RuntimeConfiguration runtimeConfiguration, |
| TestFile testFile, |
| List<String> vmOptions, |
| List<String> originalArguments, |
| CommandArtifact artifact) { |
| if (runtimeConfiguration is! NoneRuntimeConfiguration) { |
| throw "--compiler=fasta only supports --runtime=none"; |
| } |
| |
| return []; |
| } |
| } |