| // Copyright (c) 2016, 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. | |
| library dart2js.src.options; | |
| import 'package:front_end/src/api_unstable/dart2js.dart' as fe; | |
| import '../compiler.dart' show PackagesDiscoveryProvider; | |
| import 'commandline_options.dart' show Flags; | |
| /// Options used for controlling diagnostic messages. | |
| abstract class DiagnosticOptions { | |
| const DiagnosticOptions(); | |
| /// If `true`, warnings cause the compilation to fail. | |
| bool get fatalWarnings; | |
| /// Emit terse diagnostics without howToFix. | |
| bool get terseDiagnostics; | |
| /// If `true`, warnings are not reported. | |
| bool get suppressWarnings; | |
| /// If `true`, hints are not reported. | |
| bool get suppressHints; | |
| /// Returns `true` if warnings and hints are shown for all packages. | |
| bool get showAllPackageWarnings; | |
| /// Returns `true` if warnings and hints are hidden for all packages. | |
| bool get hidePackageWarnings; | |
| /// Returns `true` if warnings should be should for [uri]. | |
| bool showPackageWarningsFor(Uri uri); | |
| } | |
| /// Object for passing options to the compiler. Superclasses are used to select | |
| /// subsets of these options, enabling each part of the compiler to depend on | |
| /// as few as possible. | |
| class CompilerOptions implements DiagnosticOptions { | |
| /// The entry point of the application that is being compiled. | |
| Uri entryPoint; | |
| /// Root location where SDK libraries are found. | |
| Uri libraryRoot; | |
| /// Package root location. | |
| /// | |
| /// If not null then [packageConfig] should be null. | |
| Uri packageRoot; | |
| /// Location of the package configuration file. | |
| /// | |
| /// If not null then [packageRoot] should be null. | |
| Uri packageConfig; | |
| // TODO(sigmund): Move out of here, maybe to CompilerInput. Options should not | |
| // hold code, just configuration options. | |
| PackagesDiscoveryProvider packagesDiscoveryProvider; | |
| /// Resolved constant "environment" values passed to the compiler via the `-D` | |
| /// flags. | |
| Map<String, String> environment = const <String, String>{}; | |
| /// A possibly null state object for kernel compilation. | |
| fe.InitializedCompilerState kernelInitializedCompilerState; | |
| /// Whether we allow mocking compilation of libraries such as dart:io and | |
| /// dart:html for unit testing purposes. | |
| bool allowMockCompilation = false; | |
| /// Sets a combination of flags for benchmarking 'production' mode. | |
| bool benchmarkingProduction = false; | |
| /// ID associated with this sdk build. | |
| String buildId = _UNDETERMINED_BUILD_ID; | |
| /// Whether there is a build-id available so we can use it on error messages | |
| /// and in the emitted output of the compiler. | |
| bool get hasBuildId => buildId != _UNDETERMINED_BUILD_ID; | |
| /// Whether to compile for the server category. This is used to compile to JS | |
| /// that is intended to be run on server-side VMs like nodejs. | |
| bool compileForServer = false; | |
| /// Location where to generate a map containing details of how deferred | |
| /// libraries are subdivided. | |
| Uri deferredMapUri; | |
| /// Whether to disable inlining during the backend optimizations. | |
| // TODO(sigmund): negate, so all flags are positive | |
| bool disableInlining = false; | |
| /// Disable deferred loading, instead generate everything in one output unit. | |
| /// Note: the resulting program still correctly checks that loadLibrary & | |
| /// checkLibrary calls are correct. | |
| bool disableProgramSplit = false; | |
| /// Diagnostic option: If `true`, warnings cause the compilation to fail. | |
| bool fatalWarnings = false; | |
| /// Diagnostic option: Emit terse diagnostics without howToFix. | |
| bool terseDiagnostics = false; | |
| /// Diagnostic option: If `true`, warnings are not reported. | |
| bool suppressWarnings = false; | |
| /// Diagnostic option: If `true`, hints are not reported. | |
| bool suppressHints = false; | |
| /// Diagnostic option: List of packages for which warnings and hints are | |
| /// reported. If `null`, no package warnings or hints are reported. If | |
| /// empty, all warnings and hints are reported. | |
| List<String> shownPackageWarnings; // &&&&& | |
| /// Whether to disable global type inference. | |
| bool disableTypeInference = false; | |
| /// Whether to disable optimization for need runtime type information. | |
| bool disableRtiOptimization = false; | |
| /// Whether to emit a .json file with a summary of the information used by the | |
| /// compiler during optimization. This includes resolution details, | |
| /// dependencies between elements, results of type inference, and the output | |
| /// code for each function. | |
| bool dumpInfo = false; | |
| /// Whether we allow passing an extra argument to `assert`, containing a | |
| /// reason for why an assertion fails. (experimental) | |
| /// | |
| /// This is only included so that tests can pass the --assert-message flag | |
| /// without causing dart2js to crash. The flag has no effect. | |
| bool enableAssertMessage = true; | |
| /// Whether the user specified a flag to allow the use of dart:mirrors. This | |
| /// silences a warning produced by the compiler. | |
| bool enableExperimentalMirrors = false; | |
| /// Whether to enable minification | |
| // TODO(sigmund): rename to minify | |
| bool enableMinification = false; | |
| /// Whether to model which native classes are live based on annotations on the | |
| /// core libraries. If false, all native classes will be included by default. | |
| bool enableNativeLiveTypeAnalysis = true; | |
| /// Whether to generate code containing user's `assert` statements. | |
| bool enableUserAssertions = false; | |
| /// Whether to generate output even when there are compile-time errors. | |
| bool generateCodeWithCompileTimeErrors = false; | |
| /// Whether to generate a source-map file together with the output program. | |
| bool generateSourceMap = true; | |
| /// URI of the main output if the compiler is generating source maps. | |
| Uri outputUri; | |
| /// Location of the platform configuration file. | |
| // TODO(sigmund): deprecate and remove, use only [librariesSpecificationUri] | |
| Uri platformConfigUri; | |
| /// Location of the libraries specification file. | |
| Uri librariesSpecificationUri; | |
| /// Location of the kernel platform `.dill` files. | |
| Uri platformBinaries; | |
| /// URI where the compiler should generate the output source map file. | |
| Uri sourceMapUri; | |
| /// The compiler is run from the build bot. | |
| bool testMode = false; | |
| /// Whether to trust JS-interop annotations. (experimental) | |
| bool trustJSInteropTypeAnnotations = false; | |
| /// Whether to trust primitive types during inference and optimizations. | |
| bool trustPrimitives = false; | |
| /// Whether to omit implicit strong mode checks. | |
| bool omitImplicitChecks = false; | |
| /// Whether to omit as casts. | |
| bool omitAsCasts = false; | |
| /// Whether to omit class type arguments only needed for `toString` on | |
| /// `Object.runtimeType`. | |
| bool laxRuntimeTypeToString = false; | |
| /// What should the compiler do with type assertions of assignments. | |
| /// | |
| /// This is an internal configuration option derived from other flags. | |
| CheckPolicy assignmentCheckPolicy; | |
| /// What should the compiler do with parameter type assertions. | |
| /// | |
| /// This is an internal configuration option derived from other flags. | |
| CheckPolicy parameterCheckPolicy; | |
| /// What should the compiler do with implicit downcasts. | |
| /// | |
| /// This is an internal configuration option derived from other flags. | |
| CheckPolicy implicitDowncastCheckPolicy; | |
| /// Whether to generate code compliant with content security policy (CSP). | |
| bool useContentSecurityPolicy = false; | |
| /// When obfuscating for minification, whether to use the frequency of a name | |
| /// as an heuristic to pick shorter names. | |
| bool useFrequencyNamer = true; | |
| /// Whether to generate source-information from both the old and the new | |
| /// source-information engines. (experimental) | |
| bool useMultiSourceInfo = false; | |
| /// Whether to use the new source-information implementation for source-maps. | |
| /// (experimental) | |
| bool useNewSourceInfo = false; | |
| /// Whether the user requested to use the fast startup emitter. The full | |
| /// emitter might still be used if the program uses dart:mirrors. | |
| bool useStartupEmitter = false; | |
| /// Enable verbose printing during compilation. Includes progress messages | |
| /// during each phase and a time-breakdown between phases at the end. | |
| bool verbose = false; | |
| /// Track allocations in the JS output. | |
| /// | |
| /// This is an experimental feature. | |
| bool experimentalTrackAllocations = false; | |
| /// The path to the file that contains the profiled allocations. | |
| /// | |
| /// The file must contain the Map that was produced by using | |
| /// [experimentalTrackAllocations] encoded as a JSON map. | |
| /// | |
| /// This is an experimental feature. | |
| String experimentalAllocationsPath; | |
| // ------------------------------------------------- | |
| // Options for deprecated features | |
| // ------------------------------------------------- | |
| // TODO(sigmund): delete these as we delete the underlying features | |
| /// Whether to start `async` functions synchronously. | |
| bool startAsyncSynchronously = false; | |
| /// If specified, a bundle of optimizations to enable (or disable). | |
| int optimizationLevel = null; | |
| /// Create an options object by parsing flags from [options]. | |
| static CompilerOptions parse(List<String> options, | |
| {Uri libraryRoot, Uri platformBinaries}) { | |
| return new CompilerOptions() | |
| ..libraryRoot = libraryRoot | |
| ..allowMockCompilation = _hasOption(options, Flags.allowMockCompilation) | |
| ..benchmarkingProduction = | |
| _hasOption(options, Flags.benchmarkingProduction) | |
| ..buildId = | |
| _extractStringOption(options, '--build-id=', _UNDETERMINED_BUILD_ID) | |
| ..compileForServer = _resolveCompileForServerFromOptions(options) | |
| ..deferredMapUri = _extractUriOption(options, '--deferred-map=') | |
| ..fatalWarnings = _hasOption(options, Flags.fatalWarnings) | |
| ..terseDiagnostics = _hasOption(options, Flags.terse) | |
| ..suppressWarnings = _hasOption(options, Flags.suppressWarnings) | |
| ..suppressHints = _hasOption(options, Flags.suppressHints) | |
| ..shownPackageWarnings = | |
| _extractOptionalCsvOption(options, Flags.showPackageWarnings) | |
| ..disableInlining = _hasOption(options, Flags.disableInlining) | |
| ..disableProgramSplit = _hasOption(options, Flags.disableProgramSplit) | |
| ..disableTypeInference = _hasOption(options, Flags.disableTypeInference) | |
| ..disableRtiOptimization = | |
| _hasOption(options, Flags.disableRtiOptimization) | |
| ..dumpInfo = _hasOption(options, Flags.dumpInfo) | |
| ..enableExperimentalMirrors = | |
| _hasOption(options, Flags.enableExperimentalMirrors) | |
| ..enableMinification = _hasOption(options, Flags.minify) | |
| ..enableNativeLiveTypeAnalysis = | |
| !_hasOption(options, Flags.disableNativeLiveTypeAnalysis) | |
| ..enableUserAssertions = _hasOption(options, Flags.enableCheckedMode) || | |
| _hasOption(options, Flags.enableAsserts) | |
| ..experimentalTrackAllocations = | |
| _hasOption(options, Flags.experimentalTrackAllocations) | |
| ..experimentalAllocationsPath = _extractStringOption( | |
| options, "${Flags.experimentalAllocationsPath}=", null) | |
| ..generateCodeWithCompileTimeErrors = | |
| _hasOption(options, Flags.generateCodeWithCompileTimeErrors) | |
| ..generateSourceMap = !_hasOption(options, Flags.noSourceMaps) | |
| ..outputUri = _extractUriOption(options, '--out=') | |
| ..platformConfigUri = | |
| _resolvePlatformConfigFromOptions(libraryRoot, options) | |
| ..librariesSpecificationUri = _resolveLibrariesSpecification(libraryRoot) | |
| ..platformBinaries = | |
| platformBinaries ?? _extractUriOption(options, '--platform-binaries=') | |
| ..sourceMapUri = _extractUriOption(options, '--source-map=') | |
| ..omitImplicitChecks = _hasOption(options, Flags.omitImplicitChecks) | |
| ..omitAsCasts = _hasOption(options, Flags.omitAsCasts) | |
| ..laxRuntimeTypeToString = | |
| _hasOption(options, Flags.laxRuntimeTypeToString) | |
| ..testMode = _hasOption(options, Flags.testMode) | |
| ..trustJSInteropTypeAnnotations = | |
| _hasOption(options, Flags.trustJSInteropTypeAnnotations) | |
| ..trustPrimitives = _hasOption(options, Flags.trustPrimitives) | |
| ..useContentSecurityPolicy = | |
| _hasOption(options, Flags.useContentSecurityPolicy) | |
| ..useFrequencyNamer = | |
| !_hasOption(options, Flags.noFrequencyBasedMinification) | |
| ..useMultiSourceInfo = _hasOption(options, Flags.useMultiSourceInfo) | |
| ..useNewSourceInfo = _hasOption(options, Flags.useNewSourceInfo) | |
| ..useStartupEmitter = _hasOption(options, Flags.fastStartup) | |
| ..startAsyncSynchronously = !_hasOption(options, Flags.noSyncAsync) | |
| ..verbose = _hasOption(options, Flags.verbose); | |
| } | |
| void validate() { | |
| // TODO(sigmund): should entrypoint be here? should we validate it is not | |
| // null? In unittests we use the same compiler to analyze or build multiple | |
| // entrypoints. | |
| if (libraryRoot == null) { | |
| throw new ArgumentError("[libraryRoot] is null."); | |
| } | |
| if (!libraryRoot.path.endsWith("/")) { | |
| throw new ArgumentError("[libraryRoot] must end with a /"); | |
| } | |
| if (packageRoot != null && packageConfig != null) { | |
| throw new ArgumentError("Only one of [packageRoot] or [packageConfig] " | |
| "may be given."); | |
| } | |
| if (packageRoot != null && !packageRoot.path.endsWith("/")) { | |
| throw new ArgumentError("[packageRoot] must end with a /"); | |
| } | |
| if (platformBinaries == null) { | |
| throw new ArgumentError("Missing required ${Flags.platformBinaries}"); | |
| } | |
| } | |
| void deriveOptions() { | |
| if (benchmarkingProduction) { | |
| useStartupEmitter = true; | |
| trustPrimitives = true; | |
| omitImplicitChecks = true; | |
| } | |
| if (optimizationLevel != null) { | |
| if (optimizationLevel == 0) { | |
| disableInlining = true; | |
| disableTypeInference = true; | |
| disableRtiOptimization = true; | |
| } | |
| if (optimizationLevel >= 2) { | |
| enableMinification = true; | |
| laxRuntimeTypeToString = true; | |
| } | |
| if (optimizationLevel >= 3) { | |
| omitImplicitChecks = true; | |
| } | |
| if (optimizationLevel == 4) { | |
| trustPrimitives = true; | |
| } | |
| } | |
| // TODO(johnniwinther): Should we support this in the future? | |
| generateCodeWithCompileTimeErrors = false; | |
| if (platformConfigUri == null) { | |
| platformConfigUri = _resolvePlatformConfig(libraryRoot, null, const []); | |
| } | |
| librariesSpecificationUri = _resolveLibrariesSpecification(libraryRoot); | |
| // Strong mode always trusts type annotations (inferred or explicit), so | |
| // assignments checks should be trusted. | |
| assignmentCheckPolicy = CheckPolicy.trusted; | |
| if (omitImplicitChecks) { | |
| parameterCheckPolicy = CheckPolicy.trusted; | |
| implicitDowncastCheckPolicy = CheckPolicy.trusted; | |
| } else { | |
| parameterCheckPolicy = CheckPolicy.checked; | |
| implicitDowncastCheckPolicy = CheckPolicy.checked; | |
| } | |
| } | |
| /// Returns `true` if warnings and hints are shown for all packages. | |
| bool get showAllPackageWarnings { | |
| return shownPackageWarnings != null && shownPackageWarnings.isEmpty; | |
| } | |
| /// Returns `true` if warnings and hints are hidden for all packages. | |
| bool get hidePackageWarnings => shownPackageWarnings == null; | |
| /// Returns `true` if warnings should be should for [uri]. | |
| bool showPackageWarningsFor(Uri uri) { | |
| if (showAllPackageWarnings) { | |
| return true; | |
| } | |
| if (shownPackageWarnings != null) { | |
| return uri.scheme == 'package' && | |
| shownPackageWarnings.contains(uri.pathSegments.first); | |
| } | |
| return false; | |
| } | |
| } | |
| /// Policy for what to do with a type assertion check. | |
| /// | |
| /// This enum-like class is used to configure how the compiler treats type | |
| /// assertions during global type inference and codegen. | |
| class CheckPolicy { | |
| /// Whether the type assertion should be trusted. | |
| final bool isTrusted; | |
| /// Whether the type assertion should be emitted and checked. | |
| final bool isEmitted; | |
| /// Whether the type assertion should be ignored. | |
| final bool isIgnored; | |
| const CheckPolicy( | |
| {this.isTrusted: false, this.isEmitted: false, this.isIgnored: false}); | |
| static const trusted = const CheckPolicy(isTrusted: true); | |
| static const checked = const CheckPolicy(isEmitted: true); | |
| static const ignored = const CheckPolicy(isIgnored: true); | |
| String toString() => 'CheckPolicy(isTrusted=$isTrusted,' | |
| 'isEmitted=$isEmitted,isIgnored=$isIgnored)'; | |
| } | |
| String _extractStringOption( | |
| List<String> options, String prefix, String defaultValue) { | |
| for (String option in options) { | |
| if (option.startsWith(prefix)) { | |
| return option.substring(prefix.length); | |
| } | |
| } | |
| return defaultValue; | |
| } | |
| Uri _extractUriOption(List<String> options, String prefix) { | |
| var option = _extractStringOption(options, prefix, null); | |
| return (option == null) ? null : Uri.parse(option); | |
| } | |
| // CSV: Comma separated values. | |
| List<String> _extractCsvOption(List<String> options, String prefix) { | |
| for (String option in options) { | |
| if (option.startsWith(prefix)) { | |
| return option.substring(prefix.length).split(','); | |
| } | |
| } | |
| return const <String>[]; | |
| } | |
| bool _hasOption(List<String> options, String option) { | |
| return options.indexOf(option) >= 0; | |
| } | |
| /// Extract list of comma separated values provided for [flag]. Returns an | |
| /// empty list if [option] contain [flag] without arguments. Returns `null` if | |
| /// [option] doesn't contain [flag] with or without arguments. | |
| List<String> _extractOptionalCsvOption(List<String> options, String flag) { | |
| String prefix = '$flag='; | |
| for (String option in options) { | |
| if (option == flag) { | |
| return const <String>[]; | |
| } | |
| if (option.startsWith(flag)) { | |
| return option.substring(prefix.length).split(','); | |
| } | |
| } | |
| return null; | |
| } | |
| Uri _resolvePlatformConfig( | |
| Uri libraryRoot, String platformConfigPath, Iterable<String> categories) { | |
| if (platformConfigPath != null) { | |
| return libraryRoot.resolve(platformConfigPath); | |
| } else { | |
| if (categories.length == 0) { | |
| return libraryRoot.resolve(_clientPlatform); | |
| } | |
| assert(categories.length <= 2); | |
| if (categories.contains("Client")) { | |
| if (categories.contains("Server")) { | |
| return libraryRoot.resolve(_sharedPlatform); | |
| } | |
| return libraryRoot.resolve(_clientPlatform); | |
| } | |
| assert(categories.contains("Server")); | |
| return libraryRoot.resolve(_serverPlatform); | |
| } | |
| } | |
| bool _resolveCompileForServerFromOptions(List<String> options) { | |
| var categories = _extractCsvOption(options, '--categories='); | |
| return categories.length == 1 && categories.single == 'Server'; | |
| } | |
| Uri _resolvePlatformConfigFromOptions(Uri libraryRoot, List<String> options) { | |
| return _resolvePlatformConfig( | |
| libraryRoot, | |
| _extractStringOption(options, "--platform-config=", null), | |
| _extractCsvOption(options, '--categories=')); | |
| } | |
| Uri _resolveLibrariesSpecification(Uri libraryRoot) => | |
| libraryRoot.resolve('lib/libraries.json'); | |
| /// Locations of the platform descriptor files relative to the library root. | |
| const String _clientPlatform = "lib/dart_client.platform"; | |
| const String _serverPlatform = "lib/dart_server.platform"; | |
| const String _sharedPlatform = "lib/dart_shared.platform"; | |
| const String _UNDETERMINED_BUILD_ID = "build number could not be determined"; |