|  | // Copyright (c) 2022, 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 'package:front_end/src/api_unstable/vm.dart' as fe; | 
|  | import 'package:path/path.dart' as path; | 
|  |  | 
|  | import 'dynamic_modules.dart' show DynamicModuleType; | 
|  | import 'translator.dart'; | 
|  |  | 
|  | /// Represents a discrete phase of dart2wasm's compilation process. | 
|  | /// | 
|  | /// cfe: Runs the common frontend and applies any modular transforms as part of | 
|  | /// that process. | 
|  | /// | 
|  | /// tfa: Runs global transforms on kernel including, but not limited to, TFA. | 
|  | /// | 
|  | /// codegen: Runs the main dart2wasm translation process converting the kernel | 
|  | /// into WASM modules. | 
|  | enum CompilerPhase { | 
|  | cfe, | 
|  | tfa, | 
|  | codegen; | 
|  |  | 
|  | static CompilerPhase parse(String name) { | 
|  | for (final phase in values) { | 
|  | if (phase.name == name) return phase; | 
|  | } | 
|  | throw ArgumentError('Invalid compiler phase name: $name'); | 
|  | } | 
|  | } | 
|  |  | 
|  | class WasmCompilerOptions { | 
|  | final TranslatorOptions translatorOptions = TranslatorOptions(); | 
|  |  | 
|  | Uri? platformPath; | 
|  | Uri? librariesSpecPath; | 
|  | Uri? packagesPath; | 
|  | Uri mainUri; | 
|  | String outputFile; | 
|  | String? depFile; | 
|  | DynamicModuleType? dynamicModuleType; | 
|  | Uri? dynamicMainModuleUri; | 
|  | Uri? dynamicInterfaceUri; | 
|  | Uri? dynamicModuleMetadataFile; | 
|  | Uri? loadsIdsUri; | 
|  | bool validateDynamicModules = true; | 
|  | Map<String, String> environment = {}; | 
|  | Map<fe.ExperimentalFlag, bool> feExperimentalFlags = const {}; | 
|  | String? multiRootScheme; | 
|  | List<Uri> multiRoots = const []; | 
|  | List<String> deleteToStringPackageUri = const []; | 
|  | String? dumpKernelAfterCfe; | 
|  | String? dumpKernelBeforeTfa; | 
|  | String? dumpKernelAfterTfa; | 
|  | bool dryRun = false; | 
|  | List<CompilerPhase> phases = const [ | 
|  | CompilerPhase.cfe, | 
|  | CompilerPhase.tfa, | 
|  | CompilerPhase.codegen | 
|  | ]; | 
|  |  | 
|  | factory WasmCompilerOptions.defaultOptions() => | 
|  | WasmCompilerOptions(mainUri: Uri(), outputFile: ''); | 
|  |  | 
|  | WasmCompilerOptions({required this.mainUri, required this.outputFile}); | 
|  |  | 
|  | bool get enableDynamicModules => dynamicModuleType != null; | 
|  |  | 
|  | void validate() { | 
|  | if (translatorOptions.importSharedMemory && | 
|  | translatorOptions.sharedMemoryMaxPages == null) { | 
|  | throw ArgumentError("--shared-memory-max-pages must be specified if " | 
|  | "--import-shared-memory is used."); | 
|  | } | 
|  |  | 
|  | if (!translatorOptions.enableDeferredLoading) { | 
|  | if (loadsIdsUri != null) { | 
|  | throw ArgumentError("--load-ids can only be used with " | 
|  | "--enable-deferred-loading"); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (enableDynamicModules) { | 
|  | if (dynamicMainModuleUri == null) { | 
|  | throw ArgumentError("--dynamic-module-main must be specified if " | 
|  | "compiling dynamic modules."); | 
|  | } | 
|  |  | 
|  | if (dynamicInterfaceUri == null) { | 
|  | throw ArgumentError("--dynamic-module-interface must be specified if " | 
|  | "compiling dynamic modules."); | 
|  | } | 
|  | } | 
|  |  | 
|  | _validatePhases(); | 
|  | } | 
|  |  | 
|  | void _validatePhases() { | 
|  | if (phases.isEmpty) { | 
|  | throw ArgumentError('--phases must contain at least one phase.'); | 
|  | } | 
|  |  | 
|  | CompilerPhase? previousPhase; | 
|  | for (final phase in phases) { | 
|  | // Ensure phases are consecutive | 
|  | if (previousPhase != null && previousPhase.index != phase.index - 1) { | 
|  | throw ArgumentError('--phases must contain consecutive phases.'); | 
|  | } | 
|  | previousPhase = phase; | 
|  | } | 
|  |  | 
|  | // Ensure correct input file type | 
|  | final inputExtension = path.extension(mainUri.path); | 
|  | switch (phases.first) { | 
|  | case CompilerPhase.cfe: | 
|  | if (inputExtension != '.dart') { | 
|  | throw ArgumentError('Input to cfe phase must be a .dart file.'); | 
|  | } | 
|  | case CompilerPhase.tfa: | 
|  | if (inputExtension != '.dill') { | 
|  | throw ArgumentError('Input to tfa phase must be a .dill file.'); | 
|  | } | 
|  | case CompilerPhase.codegen: | 
|  | if (inputExtension != '.dill') { | 
|  | throw ArgumentError('Input to codegen phase must be a .dill file.'); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Ensure correct output file type | 
|  | final outputExtension = path.extension(outputFile); | 
|  | switch (phases.last) { | 
|  | case CompilerPhase.cfe: | 
|  | if (outputExtension != '.dill') { | 
|  | throw ArgumentError('Output from cfe phase must be a .dill file.'); | 
|  | } | 
|  | case CompilerPhase.tfa: | 
|  | if (outputExtension != '.dill') { | 
|  | throw ArgumentError('Output from tfa phase must be a .dill file.'); | 
|  | } | 
|  | case CompilerPhase.codegen: | 
|  | if (outputExtension != '.wasm') { | 
|  | throw ArgumentError( | 
|  | 'Output from codegen phase must be a .wasm file.'); | 
|  | } | 
|  | } | 
|  | } | 
|  | } |