| // 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 kernel.target.targets; | |
| import '../ast.dart'; | |
| import '../class_hierarchy.dart'; | |
| import '../core_types.dart'; | |
| import '../reference_from_index.dart'; | |
| import '../verifier.dart'; | |
| import 'changed_structure_notifier.dart'; | |
| class TargetFlags { | |
| final bool trackCreationLocations; | |
| final bool supportMirrors; | |
| final bool supportFfi; | |
| /// Whether the backend expects closure contexts to be present in the AST. | |
| /// | |
| /// This flag is currently experimental. Generally, the backends rely on their | |
| /// own analysis of captured variables to create closure contexts. | |
| // TODO(cstefantsova): Update the comment when the feature is no longer | |
| // experimental. | |
| final bool isClosureContextLoweringEnabled; | |
| /// Indicator for the const backend setting "keep locals". | |
| /// Targets can overwrite based on other things. | |
| final bool? constKeepLocalsIndicator; | |
| /// Whether the backends should include stubs for core libraries not supported | |
| /// by their target platform. | |
| final bool includeUnsupportedPlatformLibraryStubs; | |
| const new({ | |
| this.trackCreationLocations = false, | |
| this.supportMirrors = true, | |
| this.supportFfi = true, | |
| this.isClosureContextLoweringEnabled = false, | |
| this.constKeepLocalsIndicator, | |
| this.includeUnsupportedPlatformLibraryStubs = false, | |
| }); | |
| @override | |
| bool operator ==(other) { | |
| if (identical(this, other)) return true; | |
| return other is TargetFlags && | |
| trackCreationLocations == other.trackCreationLocations && | |
| supportMirrors == other.supportMirrors && | |
| supportFfi == other.supportFfi && | |
| includeUnsupportedPlatformLibraryStubs == | |
| other.includeUnsupportedPlatformLibraryStubs && | |
| constKeepLocalsIndicator == other.constKeepLocalsIndicator; | |
| } | |
| @override | |
| int get hashCode { | |
| int hash = 485786; | |
| hash = 0x3fffffff & (hash * 31 + (hash ^ trackCreationLocations.hashCode)); | |
| hash = 0x3fffffff & (hash * 31 + (hash ^ supportMirrors.hashCode)); | |
| hash = 0x3fffffff & (hash * 31 + (hash ^ supportFfi.hashCode)); | |
| hash = | |
| 0x3fffffff & | |
| (hash * 31 + (hash ^ includeUnsupportedPlatformLibraryStubs.hashCode)); | |
| hash = | |
| 0x3fffffff & (hash * 31 + (hash ^ constKeepLocalsIndicator.hashCode)); | |
| return hash; | |
| } | |
| } | |
| typedef _TargetBuilder = Target Function(TargetFlags flags); | |
| final Map<String, _TargetBuilder> targets = <String, _TargetBuilder>{ | |
| 'none': (TargetFlags flags) => new NoneTarget(flags), | |
| }; | |
| Target? getTarget(String name, TargetFlags flags) { | |
| _TargetBuilder? builder = targets[name]; | |
| if (builder == null) return null; | |
| Target target = builder(flags); | |
| if (flags is TestTargetFlags) { | |
| target = new TestTargetWrapper(target, flags); | |
| } | |
| return target; | |
| } | |
| abstract class DiagnosticReporter<M, C> { | |
| void report( | |
| M message, | |
| int charOffset, | |
| int length, | |
| Uri? fileUri, { | |
| List<C> context, | |
| }); | |
| } | |
| /// The different kinds of number semantics supported by the constant evaluator. | |
| enum NumberSemantics { | |
| /// Dart VM number semantics. | |
| vm, | |
| /// JavaScript (Dart2js and DDC) number semantics. | |
| js, | |
| } | |
| // Backend specific constant evaluation behavior | |
| class ConstantsBackend { | |
| const new({this.keepLocals = true}); | |
| /// Lowering of a list constant to a backend-specific representation. | |
| Constant lowerListConstant(ListConstant constant) => constant; | |
| /// Returns `true` if [constant] is lowered list constant created by | |
| /// [lowerListConstant]. | |
| bool isLoweredListConstant(Constant constant) => false; | |
| /// Calls `f` for each element in the lowered list [constant]. | |
| /// | |
| /// This assumes that `isLoweredListConstant(constant)` is true. | |
| void forEachLoweredListConstantElement( | |
| Constant constant, | |
| void Function(Constant element) f, | |
| ) {} | |
| /// Lowering of a set constant to a backend-specific representation. | |
| Constant lowerSetConstant(SetConstant constant) => constant; | |
| /// Returns `true` if [constant] is lowered set constant created by | |
| /// [lowerSetConstant]. | |
| bool isLoweredSetConstant(Constant constant) => false; | |
| /// Calls `f` for each element in the lowered set [constant]. | |
| /// | |
| /// This assumes that `isLoweredSetConstant(constant)` is true. | |
| void forEachLoweredSetConstantElement( | |
| Constant constant, | |
| void Function(Constant element) f, | |
| ) {} | |
| /// Lowering of a map constant to a backend-specific representation. | |
| Constant lowerMapConstant(MapConstant constant) => constant; | |
| /// Returns `true` if [constant] is lowered map constant created by | |
| /// [lowerMapConstant]. | |
| bool isLoweredMapConstant(Constant constant) => false; | |
| /// Calls `f` for each key/value pair in the lowered map [constant]. | |
| /// | |
| /// This assumes that `lowerMapConstant(constant)` is true. | |
| void forEachLoweredMapConstantEntry( | |
| Constant constant, | |
| void Function(Constant key, Constant value) f, | |
| ) {} | |
| /// Number semantics to use for this backend. | |
| NumberSemantics get numberSemantics => NumberSemantics.vm; | |
| /// If true, all constants are inlined. Otherwise [shouldInlineConstant] is | |
| /// called to determine whether a constant expression should be inlined. | |
| bool get alwaysInlineConstants => true; | |
| /// Inline control of constant variables. The given constant expression | |
| /// is the initializer of a [Field] or [Variable] node. | |
| /// If this method returns `true`, the variable will be inlined at all | |
| /// points of reference and the variable itself removed (unless overridden | |
| /// by the `keepFields` or `keepLocals` properties). | |
| /// This method must be deterministic, i.e. it must always return the same | |
| /// value for the same constant value and place in the AST. | |
| /// | |
| /// This is only called if [alwaysInlineConstants] is `true`. | |
| bool shouldInlineConstant(ConstantExpression initializer) => | |
| throw new UnsupportedError( | |
| 'Per-value constant inlining is not supported', | |
| ); | |
| /// Whether this target supports unevaluated constants. | |
| /// | |
| /// If not, then trying to perform constant evaluation without an environment | |
| /// raises an exception. | |
| /// | |
| /// This defaults to `false` since it requires additional work for a backend | |
| /// to support unevaluated constants. | |
| bool get supportsUnevaluatedConstants => false; | |
| /// If `true` constant [Field] declarations are not removed from the AST even | |
| /// when use-sites are inlined. | |
| /// | |
| /// All use-sites will be rewritten based on [shouldInlineConstant]. | |
| bool get keepFields => true; | |
| /// If `true` constant [Variable]s are not removed from the AST | |
| /// even when use-sites are inlined. | |
| /// | |
| /// All use-sites will be rewritten based on [shouldInlineConstant]. | |
| final bool keepLocals; | |
| } | |
| /// Interface used for determining whether a `dart:*` is considered supported | |
| /// for the current target. | |
| abstract class DartLibrarySupport { | |
| /// Returns `true` if the 'dart:[libraryName]' library is supported. | |
| /// | |
| /// [isSupportedBySpec] is `true` if the dart library was supported by the | |
| /// libraries specification. | |
| /// | |
| /// This is used to allow AOT to consider `dart:mirrors` as unsupported | |
| /// despite it being supported in the platform dill, and for dart2js and DDC | |
| /// to consider `dart:_dart2js_only` and `dart:_ddc_only`, respectively, to be | |
| /// supported despite them being internal libraries. | |
| bool computeDartLibrarySupport( | |
| String libraryName, { | |
| required bool isSupportedBySpec, | |
| }); | |
| static const String dartLibraryPrefix = "dart.library."; | |
| static bool isDartLibraryQualifier(String dottedName) { | |
| return dottedName.startsWith(dartLibraryPrefix); | |
| } | |
| static String getDartLibraryName(String dottedName) { | |
| assert(isDartLibraryQualifier(dottedName)); | |
| return dottedName.substring(dartLibraryPrefix.length); | |
| } | |
| /// Whether the "dart:[libraryName]" is supported. | |
| /// | |
| /// This is used to determine conditional imports and `bool.fromEnvironment` | |
| /// constant values for "dart.library.[libraryName]" values. | |
| /// If the value is `false`, no environment entry exists for the library name, | |
| /// otherwise an entry with value `"true"` is created. | |
| static bool isDartLibrarySupported( | |
| String libraryName, { | |
| required bool libraryExists, | |
| required bool isSynthetic, | |
| required bool conditionalImportSupported, | |
| required DartLibrarySupport dartLibrarySupport, | |
| }) { | |
| // A `dart:` library can be unsupported for several reasons: | |
| // * If the library doesn't exist from source or from dill, it is not | |
| // supported. | |
| // * If the library has been synthesized, then it doesn't exist, but has | |
| // been synthetically created due to an explicit import or export of it, | |
| // in which case it is also not supported. | |
| // * If the library is marked as not supported in the libraries | |
| // specification, it does exist, but is not supported. | |
| // * If the library is marked as supported in the libraries specification, | |
| // it does exist and is potentially supported. Still the [Target] can | |
| // consider it unsupported. This is for instance used to consider | |
| // `dart:mirrors` as unsupported in AOT. The platform dill is shared with | |
| // JIT, so the library exists and is marked as supported, but for AOT | |
| // compilation it is still unsupported. | |
| bool isSupported = | |
| libraryExists && !isSynthetic && conditionalImportSupported; | |
| isSupported = dartLibrarySupport.computeDartLibrarySupport( | |
| libraryName, | |
| isSupportedBySpec: isSupported, | |
| ); | |
| return isSupported; | |
| } | |
| } | |
| /// [DartLibrarySupport] that only relies on the "supported" property of | |
| /// the libraries specification. | |
| class DefaultDartLibrarySupport implements DartLibrarySupport { | |
| const new(); | |
| @override | |
| bool computeDartLibrarySupport( | |
| String libraryName, { | |
| required bool isSupportedBySpec, | |
| }) => isSupportedBySpec; | |
| } | |
| /// [DartLibrarySupport] that supports overriding `dart:*` library support | |
| /// otherwise defined by the libraries specification. | |
| class CustomizedDartLibrarySupport implements DartLibrarySupport { | |
| final Set<String> supported; | |
| final Set<String> unsupported; | |
| const new({this.supported = const {}, this.unsupported = const {}}); | |
| @override | |
| bool computeDartLibrarySupport( | |
| String libraryName, { | |
| required bool isSupportedBySpec, | |
| }) { | |
| if (supported.contains(libraryName)) { | |
| return true; | |
| } else if (unsupported.contains(libraryName)) { | |
| return false; | |
| } | |
| return isSupportedBySpec; | |
| } | |
| } | |
| /// A target provides backend-specific options for generating kernel IR. | |
| abstract class Target { | |
| TargetFlags get flags; | |
| String get name; | |
| /// A list of URIs of required libraries, not including dart:core. | |
| /// | |
| /// Libraries will be loaded in order. | |
| List<String> get extraRequiredLibraries => const <String>[]; | |
| /// A list of URIs of extra required libraries when compiling the platform. | |
| /// | |
| /// Libraries will be loaded in order after the [extraRequiredLibraries] | |
| /// above. | |
| /// | |
| /// Normally not needed, but can be useful if removing libraries from the | |
| /// [extraRequiredLibraries] list so libraries will still be available in the | |
| /// platform if having a weird mix of current and not-quite-current as can | |
| /// sometimes be the case. | |
| List<String> get extraRequiredLibrariesPlatform => const <String>[]; | |
| /// A list of URIs of libraries to be indexed in the CoreTypes index, not | |
| /// including dart:_internal, dart:async, dart:core and dart:mirrors. | |
| List<String> get extraIndexedLibraries => const <String>[]; | |
| /// Classes from the SDK whose interface is required for the modular | |
| /// transformations. | |
| Map<String, List<String>> get requiredSdkClasses => CoreTypes.requiredClasses; | |
| /// A derived class may change this to `true` to enable forwarders to | |
| /// user-defined `noSuchMethod` that are generated for each abstract member | |
| /// if such `noSuchMethod` is present. | |
| /// | |
| /// The forwarders are abstract [Procedure]s with [isNoSuchMethodForwarder] | |
| /// bit set. The implementation of the behavior of such forwarders is up | |
| /// for the target backend. | |
| bool get enableNoSuchMethodForwarders => false; | |
| /// Perform target-specific transformations on the outlines stored in | |
| /// [Component] when generating summaries. | |
| /// | |
| /// This is used to transform the libraries, but not for instance | |
| /// filtering the output libraries or adding metadata. Do this in | |
| /// [performOutlineComponentOperations] instead. | |
| /// This transformation is not applied when compiling full kernel programs to | |
| /// prevent affecting the internal invariants of the compiler and accidentally | |
| /// slowing down compilation. | |
| void performOutlineTransformations( | |
| Component component, { | |
| List<Library>? libraries, | |
| ChangedStructureNotifier? changedStructureNotifier, | |
| }) {} | |
| /// Perform target-specific operations on the [Component] storing the outlines | |
| /// when generating summaries. | |
| /// | |
| /// This is not for transforming the libraries, but can be used to add | |
| /// metadata and filter libraries. | |
| /// This is not applied when compiling full kernel programs to prevent | |
| /// affecting the internal invariants of the compiler and accidentally | |
| /// slowing down compilation. | |
| void performOutlineComponentOperations(Component component) {} | |
| /// Perform target-specific transformations on the given libraries that must | |
| /// run before constant evaluation. | |
| void performPreConstantEvaluationTransformations( | |
| Component component, | |
| CoreTypes coreTypes, | |
| List<Library> libraries, | |
| DiagnosticReporter diagnosticReporter, { | |
| void Function(String msg)? logger, | |
| ChangedStructureNotifier? changedStructureNotifier, | |
| }) {} | |
| /// Perform target-specific modular transformations on the given libraries. | |
| void performModularTransformationsOnLibraries( | |
| Component component, | |
| CoreTypes coreTypes, | |
| ClassHierarchy hierarchy, | |
| List<Library> libraries, | |
| // TODO(askesc): Consider how to generally pass compiler options to | |
| // transformations. | |
| Map<String, String>? environmentDefines, | |
| DiagnosticReporter diagnosticReporter, | |
| ReferenceFromIndex? referenceFromIndex, { | |
| void Function(String msg)? logger, | |
| ChangedStructureNotifier? changedStructureNotifier, | |
| }); | |
| /// Perform target-specific modular transformations on the given program. | |
| /// | |
| /// This is used when an individual expression is compiled, e.g. for debugging | |
| /// purposes. It is illegal to modify any of the enclosing nodes of the | |
| /// procedure. | |
| void performTransformationsOnProcedure( | |
| CoreTypes coreTypes, | |
| ClassHierarchy hierarchy, | |
| Procedure procedure, | |
| // TODO(askesc): Consider how to generally pass compiler options to | |
| // transformations. | |
| Map<String, String>? environmentDefines, { | |
| void Function(String msg)? logger, | |
| required DiagnosticReporter diagnosticReporter, | |
| }) {} | |
| /// Whether a platform library may define a restricted type, such as `bool`, | |
| /// `int`, `double`, `num`, and `String`. | |
| /// | |
| /// By default only `dart:core` and `dart:typed_data` may define restricted | |
| /// types, but some target implementations override this. | |
| bool mayDefineRestrictedType(Uri uri) => | |
| uri.isScheme('dart') && (uri.path == 'core' || uri.path == 'typed_data'); | |
| /// Whether a library is allowed to import the platform private library | |
| /// [imported] from library [importer]. | |
| /// | |
| /// By default only `dart:*` libraries are allowed. May be overridden for | |
| /// testing purposes. | |
| bool allowPlatformPrivateLibraryAccess(Uri importer, Uri imported) => | |
| importer.isScheme("dart") || | |
| (importer.isScheme("package") && | |
| (importer.path.startsWith("dart_internal/") || | |
| importer.path.startsWith("dynamic_modules/"))); | |
| /// Whether the `native` language extension is supported within the library | |
| /// with the given import [uri]. | |
| /// | |
| /// The `native` language extension is not part of the language specification, | |
| /// it is an extension that is used by dart2js/ddc. | |
| bool enableNative(Uri uri) => false; | |
| /// Whether integer literals that cannot be represented exactly on the web | |
| /// (i.e. in JavaScript) should cause an error to be issued. | |
| /// An example of such a number is `2^53 + 1` where in JavaScript - because | |
| /// integers are represented as doubles | |
| /// `Math.pow(2, 53) = Math.pow(2, 53) + 1`. | |
| bool get errorOnUnexactWebIntLiterals => false; | |
| /// Whether set literals are natively supported by this target. If set | |
| /// literals are not supported by the target, they will be desugared into | |
| /// explicit `Set` creation (for non-const set literals) or wrapped map | |
| /// literals (for const set literals). | |
| bool get supportsSetLiterals => true; | |
| /// Whether [FileUriExpression] nodes are supported by this target after | |
| /// constant evaluation. | |
| /// | |
| /// [FileUriExpression] are used internally in the CFE to handle annotations | |
| /// on patches, and are replaced with [FileUriConstantExpression] nodes during | |
| /// constant evaluation. | |
| /// | |
| /// Targets can opt in to using this node for general inlining. | |
| bool get supportsFileUriExpression => false; | |
| /// Whether this target supports capturing `Let` variables. | |
| /// | |
| /// If the target does not support capturing `Let` variables then a `Let` | |
| /// expression whose variable may be captured in a nested function literal | |
| /// will be lowered to a block expression with a variable declaration. | |
| bool get supportsLetVariableCapture => true; | |
| /// Bit mask of [LateLowering] values for the late lowerings that should | |
| /// be performed by the CFE. | |
| /// | |
| /// For the selected lowerings, late fields and variables are encoded using | |
| /// fields, getter, setters etc. in a way that provide equivalent semantics. | |
| /// See `pkg/kernel/nnbd_api.md` for details. | |
| int get enabledLateLowerings; | |
| /// Returns `true` if the CFE should lower a late field given it | |
| /// [hasInitializer], [isFinal], and [isStatic]. | |
| /// | |
| /// This is determined by the [enabledLateLowerings] mask. | |
| bool isLateFieldLoweringEnabled({ | |
| required bool hasInitializer, | |
| required bool isFinal, | |
| required bool isStatic, | |
| }) { | |
| int mask = LateLowering.getFieldLowering( | |
| hasInitializer: hasInitializer, | |
| isFinal: isFinal, | |
| isStatic: isStatic, | |
| ); | |
| return enabledLateLowerings & mask != 0; | |
| } | |
| /// Bit mask of [ConstructorTearOffLowering] values for the constructor tear | |
| /// off lowerings that should be performed by the CFE. | |
| /// | |
| /// For the selected lowerings, constructor tear offs are encoded using | |
| /// synthesized top level functions. | |
| int get enabledConstructorTearOffLowerings; | |
| /// Returns `true` if lowering of generative constructor tear offs is enabled. | |
| /// | |
| /// This is determined by the [enabledConstructorTearOffLowerings] mask. | |
| bool get isConstructorTearOffLoweringEnabled => | |
| (enabledConstructorTearOffLowerings & | |
| ConstructorTearOffLowering.constructors) != | |
| 0; | |
| /// Returns `true` if lowering of non-redirecting factory tear offs is | |
| /// enabled. | |
| /// | |
| /// This is determined by the [enabledConstructorTearOffLowerings] mask. | |
| bool get isFactoryTearOffLoweringEnabled => | |
| (enabledConstructorTearOffLowerings & | |
| ConstructorTearOffLowering.factories) != | |
| 0; | |
| /// Returns `true` if lowering of redirecting factory tear offs is enabled. | |
| /// | |
| /// This is determined by the [enabledConstructorTearOffLowerings] mask. | |
| bool get isRedirectingFactoryTearOffLoweringEnabled => | |
| (enabledConstructorTearOffLowerings & | |
| ConstructorTearOffLowering.redirectingFactories) != | |
| 0; | |
| /// Returns `true` if lowering of typedef tear offs is enabled. | |
| /// | |
| /// This is determined by the [enabledConstructorTearOffLowerings] mask. | |
| bool get isTypedefTearOffLoweringEnabled => | |
| (enabledConstructorTearOffLowerings & | |
| ConstructorTearOffLowering.typedefs) != | |
| 0; | |
| /// Returns `true` if the CFE should lower a late local variable given it | |
| /// [hasInitializer], [isFinal], and its type [isPotentiallyNullable]. | |
| /// | |
| /// This is determined by the [enabledLateLowerings] mask. | |
| bool isLateLocalLoweringEnabled({ | |
| required bool hasInitializer, | |
| required bool isFinal, | |
| required bool isPotentiallyNullable, | |
| }) { | |
| int mask = LateLowering.getLocalLowering( | |
| hasInitializer: hasInitializer, | |
| isFinal: isFinal, | |
| isPotentiallyNullable: isPotentiallyNullable, | |
| ); | |
| return enabledLateLowerings & mask != 0; | |
| } | |
| /// If `true`, the backend supports creation and checking of a sentinel value | |
| /// for uninitialized late fields and variables through the `createSentinel` | |
| /// and `isSentinel` methods in `dart:_internal`. | |
| /// | |
| /// If `true` this is used when late fields and locals are lowered, | |
| /// as determined by [isLateLocalLoweringEnabled] and | |
| /// [isLateFieldLoweringEnabled]. | |
| bool get supportsLateLoweringSentinel; | |
| /// Whether static fields with initializers in nnbd libraries should be | |
| /// encoded using the late field lowering. | |
| bool get useStaticFieldLowering; | |
| /// Whether calls to getters and fields should be encoded as a .call | |
| /// invocation on a property get. | |
| /// | |
| /// If `false`, calls to getters and fields are encoded as method invocations | |
| /// with the accessed getter or field as the interface target. | |
| bool get supportsExplicitGetterCalls; | |
| /// Builds an expression that instantiates an [Invocation] that can be passed | |
| /// to [noSuchMethod]. | |
| Expression instantiateInvocation( | |
| CoreTypes coreTypes, | |
| Expression receiver, | |
| String name, | |
| Arguments arguments, | |
| int offset, | |
| bool isSuper, | |
| ); | |
| /// Configure the given [Component] in a target specific way. | |
| /// Returns the configured component. | |
| Component configureComponent(Component component) => component; | |
| /// Configure environment defines in a target-specific way. | |
| Map<String, String> updateEnvironmentDefines(Map<String, String> map) => map; | |
| @override | |
| String toString() => 'Target($name)'; | |
| Class? concreteListLiteralClass(CoreTypes coreTypes) => null; | |
| Class? concreteConstListLiteralClass(CoreTypes coreTypes) => null; | |
| Class? concreteMapLiteralClass(CoreTypes coreTypes) => null; | |
| Class? concreteConstMapLiteralClass(CoreTypes coreTypes) => null; | |
| Class? concreteSetLiteralClass(CoreTypes coreTypes) => null; | |
| Class? concreteConstSetLiteralClass(CoreTypes coreTypes) => null; | |
| Class? concreteConstSymbolLiteralClass(CoreTypes coreTypes) => null; | |
| Class? concreteClosureClass(CoreTypes coreTypes) => null; | |
| Class getRecordImplementationClass( | |
| CoreTypes coreTypes, | |
| int numPositionalFields, | |
| List<String> namedFields, | |
| ) => throw UnsupportedError('Target.getRecordImplementationClass'); | |
| Class? concreteIntLiteralClass(CoreTypes coreTypes, int value) => null; | |
| Class? concreteDoubleLiteralClass(CoreTypes coreTypes, double value) => null; | |
| Class? concreteStringLiteralClass(CoreTypes coreTypes, String value) => null; | |
| Class? concreteAsyncResultClass(CoreTypes coreTypes) => null; | |
| Class? concreteSyncStarResultClass(CoreTypes coreTypes) => null; | |
| ConstantsBackend get constantsBackend; | |
| /// Object that defines how AST nodes are verified for this [Target]. | |
| Verification get verification => const Verification(); | |
| /// Returns an [DartLibrarySupport] the defines which, if any, of the | |
| /// `dart:` libraries supported in the platform, that should not be | |
| /// considered supported when queried in conditional imports and | |
| /// `bool.fromEnvironment` constants. | |
| /// | |
| /// This is used treat `dart:mirrors` as unsupported in AOT but supported | |
| /// in JIT. | |
| DartLibrarySupport get dartLibrarySupport => | |
| const DefaultDartLibrarySupport(); | |
| /// Should this target-specific pragma be recognized by annotation parsers? | |
| bool isSupportedPragma(String pragmaName) => false; | |
| /// When `true` the incremental compiler will always include libraries that | |
| /// apply invalidated mixins in the output of a recompile. | |
| /// | |
| /// They will be included even when only the mixin was edited, and even if the | |
| /// invalidation was only within the body of the mixin member. | |
| bool get incrementalCompilerIncludeMixinApplicationInvalidatedLibraries => | |
| false; | |
| /// If this target is - or can be made - to be compatible with [other]. | |
| /// | |
| /// Used for the modular incremental compilation pipeline. | |
| bool isModularlyCompatibleWith(Target other) => true; | |
| /// Update this target to be compatible with [other]. Assumes | |
| /// [isModularlyCompatibleWith] returns true. | |
| /// | |
| /// Used for the modular incremental compilation pipeline. | |
| void updateModularCompatibilityAs(Target other) {} | |
| } | |
| class NoneConstantsBackend extends ConstantsBackend { | |
| @override | |
| final bool supportsUnevaluatedConstants; | |
| const new({required this.supportsUnevaluatedConstants, super.keepLocals}); | |
| } | |
| class NoneTarget extends Target { | |
| @override | |
| final TargetFlags flags; | |
| new(this.flags); | |
| @override | |
| int get enabledLateLowerings => LateLowering.none; | |
| @override | |
| bool get supportsLateLoweringSentinel => false; | |
| @override | |
| bool get useStaticFieldLowering => false; | |
| @override | |
| bool get supportsExplicitGetterCalls => true; | |
| @override | |
| int get enabledConstructorTearOffLowerings => ConstructorTearOffLowering.none; | |
| @override | |
| String get name => 'none'; | |
| @override | |
| List<String> get extraRequiredLibraries => <String>[]; | |
| @override | |
| void performModularTransformationsOnLibraries( | |
| Component component, | |
| CoreTypes coreTypes, | |
| ClassHierarchy hierarchy, | |
| List<Library> libraries, | |
| Map<String, String>? environmentDefines, | |
| DiagnosticReporter diagnosticReporter, | |
| ReferenceFromIndex? referenceFromIndex, { | |
| void Function(String msg)? logger, | |
| ChangedStructureNotifier? changedStructureNotifier, | |
| }) {} | |
| @override | |
| Expression instantiateInvocation( | |
| CoreTypes coreTypes, | |
| Expression receiver, | |
| String name, | |
| Arguments arguments, | |
| int offset, | |
| bool isSuper, | |
| ) { | |
| return new InvalidExpression( | |
| 'Unsupported: NoneTarget.instantiateInvocation', | |
| ); | |
| } | |
| @override | |
| ConstantsBackend get constantsBackend => | |
| // TODO(johnniwinther): Should this vary with the use case? | |
| const NoneConstantsBackend(supportsUnevaluatedConstants: true); | |
| } | |
| class LateLowering { | |
| static const int nullableUninitializedNonFinalLocal = 1 << 0; | |
| static const int nonNullableUninitializedNonFinalLocal = 1 << 1; | |
| static const int nullableUninitializedFinalLocal = 1 << 2; | |
| static const int nonNullableUninitializedFinalLocal = 1 << 3; | |
| static const int nullableInitializedNonFinalLocal = 1 << 4; | |
| static const int nonNullableInitializedNonFinalLocal = 1 << 5; | |
| static const int nullableInitializedFinalLocal = 1 << 6; | |
| static const int nonNullableInitializedFinalLocal = 1 << 7; | |
| static const int uninitializedNonFinalStaticField = 1 << 8; | |
| static const int uninitializedFinalStaticField = 1 << 9; | |
| static const int initializedNonFinalStaticField = 1 << 10; | |
| static const int initializedFinalStaticField = 1 << 11; | |
| static const int uninitializedNonFinalInstanceField = 1 << 12; | |
| static const int uninitializedFinalInstanceField = 1 << 13; | |
| static const int initializedNonFinalInstanceField = 1 << 14; | |
| static const int initializedFinalInstanceField = 1 << 15; | |
| static const int none = 0; | |
| static const int all = (1 << 16) - 1; | |
| static int getLocalLowering({ | |
| required bool hasInitializer, | |
| required bool isFinal, | |
| required bool isPotentiallyNullable, | |
| }) { | |
| if (hasInitializer) { | |
| if (isFinal) { | |
| if (isPotentiallyNullable) { | |
| return nullableInitializedFinalLocal; | |
| } else { | |
| return nonNullableInitializedFinalLocal; | |
| } | |
| } else { | |
| if (isPotentiallyNullable) { | |
| return nullableInitializedNonFinalLocal; | |
| } else { | |
| return nonNullableInitializedNonFinalLocal; | |
| } | |
| } | |
| } else { | |
| if (isFinal) { | |
| if (isPotentiallyNullable) { | |
| return nullableUninitializedFinalLocal; | |
| } else { | |
| return nonNullableUninitializedFinalLocal; | |
| } | |
| } else { | |
| if (isPotentiallyNullable) { | |
| return nullableUninitializedNonFinalLocal; | |
| } else { | |
| return nonNullableUninitializedNonFinalLocal; | |
| } | |
| } | |
| } | |
| } | |
| static int getFieldLowering({ | |
| required bool hasInitializer, | |
| required bool isFinal, | |
| required bool isStatic, | |
| }) { | |
| if (hasInitializer) { | |
| if (isFinal) { | |
| if (isStatic) { | |
| return initializedFinalStaticField; | |
| } else { | |
| return initializedFinalInstanceField; | |
| } | |
| } else { | |
| if (isStatic) { | |
| return initializedNonFinalStaticField; | |
| } else { | |
| return initializedNonFinalInstanceField; | |
| } | |
| } | |
| } else { | |
| if (isFinal) { | |
| if (isStatic) { | |
| return uninitializedFinalStaticField; | |
| } else { | |
| return uninitializedFinalInstanceField; | |
| } | |
| } else { | |
| if (isStatic) { | |
| return uninitializedNonFinalStaticField; | |
| } else { | |
| return uninitializedNonFinalInstanceField; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| class ConstructorTearOffLowering { | |
| /// Create static functions to use as tear offs of generative constructors. | |
| static const int constructors = 1 << 0; | |
| /// Create static functions to use as tear offs of non-redirecting factories. | |
| static const int factories = 1 << 1; | |
| /// Create static functions to use as tear offs of redirecting factories. | |
| static const int redirectingFactories = 1 << 2; | |
| /// Create top level functions to use as tear offs of typedefs that are not | |
| /// proper renames. | |
| static const int typedefs = 1 << 3; | |
| static const int none = 0; | |
| static const int all = (1 << 4) - 1; | |
| } | |
| class TestTargetFlags extends TargetFlags { | |
| final int? forceLateLoweringsForTesting; | |
| final bool? forceLateLoweringSentinelForTesting; | |
| final bool? forceStaticFieldLoweringForTesting; | |
| final bool? forceNoExplicitGetterCallsForTesting; | |
| final int? forceConstructorTearOffLoweringForTesting; | |
| final Set<String> supportedDartLibraries; | |
| final Set<String> unsupportedDartLibraries; | |
| const new({ | |
| bool trackCreationLocations = false, | |
| this.forceLateLoweringsForTesting, | |
| this.forceLateLoweringSentinelForTesting, | |
| this.forceStaticFieldLoweringForTesting, | |
| this.forceNoExplicitGetterCallsForTesting, | |
| this.forceConstructorTearOffLoweringForTesting, | |
| this.supportedDartLibraries = const {}, | |
| this.unsupportedDartLibraries = const {}, | |
| bool isClosureContextLoweringEnabled = false, | |
| }) : super( | |
| trackCreationLocations: trackCreationLocations, | |
| isClosureContextLoweringEnabled: isClosureContextLoweringEnabled, | |
| ); | |
| } | |
| mixin TestTargetMixin on Target { | |
| @override | |
| TestTargetFlags get flags; | |
| @override | |
| int get enabledLateLowerings => | |
| flags.forceLateLoweringsForTesting ?? super.enabledLateLowerings; | |
| @override | |
| bool get supportsLateLoweringSentinel => | |
| flags.forceLateLoweringSentinelForTesting ?? | |
| super.supportsLateLoweringSentinel; | |
| @override | |
| bool get useStaticFieldLowering => | |
| flags.forceStaticFieldLoweringForTesting ?? super.useStaticFieldLowering; | |
| @override | |
| bool get supportsExplicitGetterCalls => | |
| flags.forceNoExplicitGetterCallsForTesting != null | |
| ? !flags.forceNoExplicitGetterCallsForTesting! | |
| : super.supportsExplicitGetterCalls; | |
| @override | |
| int get enabledConstructorTearOffLowerings => | |
| flags.forceConstructorTearOffLoweringForTesting ?? | |
| super.enabledConstructorTearOffLowerings; | |
| @override | |
| late final DartLibrarySupport dartLibrarySupport = new TestDartLibrarySupport( | |
| super.dartLibrarySupport, | |
| flags, | |
| ); | |
| } | |
| class TestDartLibrarySupport implements DartLibrarySupport { | |
| final DartLibrarySupport delegate; | |
| final TestTargetFlags flags; | |
| new(this.delegate, this.flags); | |
| @override | |
| bool computeDartLibrarySupport( | |
| String libraryName, { | |
| required bool isSupportedBySpec, | |
| }) { | |
| if (flags.supportedDartLibraries.contains(libraryName)) { | |
| return true; | |
| } else if (flags.unsupportedDartLibraries.contains(libraryName)) { | |
| return false; | |
| } | |
| return delegate.computeDartLibrarySupport( | |
| libraryName, | |
| isSupportedBySpec: isSupportedBySpec, | |
| ); | |
| } | |
| } | |
| class TargetWrapper extends Target { | |
| final Target _target; | |
| new(this._target); | |
| @override | |
| TargetFlags get flags => _target.flags; | |
| @override | |
| int get enabledLateLowerings => _target.enabledLateLowerings; | |
| @override | |
| bool get supportsLateLoweringSentinel => _target.supportsLateLoweringSentinel; | |
| @override | |
| bool get useStaticFieldLowering => _target.useStaticFieldLowering; | |
| @override | |
| bool get supportsExplicitGetterCalls => _target.supportsExplicitGetterCalls; | |
| @override | |
| int get enabledConstructorTearOffLowerings => | |
| _target.enabledConstructorTearOffLowerings; | |
| @override | |
| bool allowPlatformPrivateLibraryAccess(Uri importer, Uri imported) { | |
| return _target.allowPlatformPrivateLibraryAccess(importer, imported); | |
| } | |
| @override | |
| Class? concreteConstListLiteralClass(CoreTypes coreTypes) { | |
| return _target.concreteConstListLiteralClass(coreTypes); | |
| } | |
| @override | |
| Class? concreteConstMapLiteralClass(CoreTypes coreTypes) { | |
| return _target.concreteConstMapLiteralClass(coreTypes); | |
| } | |
| @override | |
| Class? concreteSetLiteralClass(CoreTypes coreTypes) { | |
| return _target.concreteSetLiteralClass(coreTypes); | |
| } | |
| @override | |
| Class? concreteConstSetLiteralClass(CoreTypes coreTypes) { | |
| return _target.concreteConstSetLiteralClass(coreTypes); | |
| } | |
| @override | |
| Class? concreteConstSymbolLiteralClass(CoreTypes coreTypes) { | |
| return _target.concreteConstSymbolLiteralClass(coreTypes); | |
| } | |
| @override | |
| Class? concreteDoubleLiteralClass(CoreTypes coreTypes, double value) { | |
| return _target.concreteDoubleLiteralClass(coreTypes, value); | |
| } | |
| @override | |
| Class? concreteIntLiteralClass(CoreTypes coreTypes, int value) { | |
| return _target.concreteIntLiteralClass(coreTypes, value); | |
| } | |
| @override | |
| Class? concreteListLiteralClass(CoreTypes coreTypes) { | |
| return _target.concreteListLiteralClass(coreTypes); | |
| } | |
| @override | |
| Class? concreteMapLiteralClass(CoreTypes coreTypes) { | |
| return _target.concreteMapLiteralClass(coreTypes); | |
| } | |
| @override | |
| Class? concreteStringLiteralClass(CoreTypes coreTypes, String value) { | |
| return _target.concreteStringLiteralClass(coreTypes, value); | |
| } | |
| @override | |
| Component configureComponent(Component component) { | |
| return _target.configureComponent(component); | |
| } | |
| @override | |
| ConstantsBackend get constantsBackend => _target.constantsBackend; | |
| @override | |
| bool enableNative(Uri uri) { | |
| return _target.enableNative(uri); | |
| } | |
| @override | |
| bool get enableNoSuchMethodForwarders => _target.enableNoSuchMethodForwarders; | |
| @override | |
| bool get errorOnUnexactWebIntLiterals => _target.errorOnUnexactWebIntLiterals; | |
| @override | |
| List<String> get extraIndexedLibraries => _target.extraIndexedLibraries; | |
| @override | |
| List<String> get extraRequiredLibraries => _target.extraRequiredLibraries; | |
| @override | |
| List<String> get extraRequiredLibrariesPlatform => | |
| _target.extraRequiredLibrariesPlatform; | |
| @override | |
| Expression instantiateInvocation( | |
| CoreTypes coreTypes, | |
| Expression receiver, | |
| String name, | |
| Arguments arguments, | |
| int offset, | |
| bool isSuper, | |
| ) { | |
| return _target.instantiateInvocation( | |
| coreTypes, | |
| receiver, | |
| name, | |
| arguments, | |
| offset, | |
| isSuper, | |
| ); | |
| } | |
| @override | |
| bool mayDefineRestrictedType(Uri uri) { | |
| return _target.mayDefineRestrictedType(uri); | |
| } | |
| @override | |
| String get name => _target.name; | |
| @override | |
| void performModularTransformationsOnLibraries( | |
| Component component, | |
| CoreTypes coreTypes, | |
| ClassHierarchy hierarchy, | |
| List<Library> libraries, | |
| Map<String, String>? environmentDefines, | |
| DiagnosticReporter diagnosticReporter, | |
| ReferenceFromIndex? referenceFromIndex, { | |
| void Function(String msg)? logger, | |
| ChangedStructureNotifier? changedStructureNotifier, | |
| }) { | |
| _target.performModularTransformationsOnLibraries( | |
| component, | |
| coreTypes, | |
| hierarchy, | |
| libraries, | |
| environmentDefines, | |
| diagnosticReporter, | |
| referenceFromIndex, | |
| logger: logger, | |
| changedStructureNotifier: changedStructureNotifier, | |
| ); | |
| } | |
| @override | |
| void performOutlineTransformations( | |
| Component component, { | |
| List<Library>? libraries, | |
| ChangedStructureNotifier? changedStructureNotifier, | |
| }) { | |
| _target.performOutlineTransformations( | |
| component, | |
| libraries: libraries, | |
| changedStructureNotifier: changedStructureNotifier, | |
| ); | |
| } | |
| @override | |
| void performOutlineComponentOperations(Component component) { | |
| _target.performOutlineComponentOperations(component); | |
| } | |
| @override | |
| void performPreConstantEvaluationTransformations( | |
| Component component, | |
| CoreTypes coreTypes, | |
| List<Library> libraries, | |
| DiagnosticReporter diagnosticReporter, { | |
| void Function(String msg)? logger, | |
| ChangedStructureNotifier? changedStructureNotifier, | |
| }) { | |
| _target.performPreConstantEvaluationTransformations( | |
| component, | |
| coreTypes, | |
| libraries, | |
| diagnosticReporter, | |
| logger: logger, | |
| changedStructureNotifier: changedStructureNotifier, | |
| ); | |
| } | |
| @override | |
| void performTransformationsOnProcedure( | |
| CoreTypes coreTypes, | |
| ClassHierarchy hierarchy, | |
| Procedure procedure, | |
| Map<String, String>? environmentDefines, { | |
| void Function(String msg)? logger, | |
| required DiagnosticReporter diagnosticReporter, | |
| }) { | |
| _target.performTransformationsOnProcedure( | |
| coreTypes, | |
| hierarchy, | |
| procedure, | |
| environmentDefines, | |
| logger: logger, | |
| diagnosticReporter: diagnosticReporter, | |
| ); | |
| } | |
| @override | |
| Map<String, List<String>> get requiredSdkClasses => | |
| _target.requiredSdkClasses; | |
| @override | |
| bool get supportsSetLiterals => _target.supportsSetLiterals; | |
| @override | |
| Map<String, String> updateEnvironmentDefines(Map<String, String> map) { | |
| return _target.updateEnvironmentDefines(map); | |
| } | |
| @override | |
| Verification get verification => _target.verification; | |
| } | |
| class TestTargetWrapper extends TargetWrapper with TestTargetMixin { | |
| @override | |
| final TestTargetFlags flags; | |
| new(Target target, this.flags) : super(target); | |
| } | |
| /// Extends a Target to transform outlines to meet the requirements | |
| /// of summaries in bazel and package-build. | |
| /// | |
| /// Build systems like package-build may provide the same input file twice to | |
| /// the summary worker, but only intends to have it in one output summary. The | |
| /// convention is that if it is listed as a source, it is intended to be part of | |
| /// the output, if the source file was loaded as a dependency, then it was | |
| /// already included in a different summary. The transformation below ensures | |
| /// that the output summary doesn't include those implicit inputs. | |
| /// | |
| /// Note: this transformation is destructive and is only intended to be used | |
| /// when generating summaries. | |
| mixin SummaryMixin on Target { | |
| List<Uri> get sources; | |
| bool get excludeNonSources; | |
| @override | |
| void performOutlineComponentOperations(Component component) { | |
| super.performOutlineComponentOperations(component); | |
| if (!excludeNonSources) return; | |
| List<Library> componentLibraries = new List.of(component.libraries); | |
| component.libraries.clear(); | |
| Set<Uri> include = sources.toSet(); | |
| for (Library library in componentLibraries) { | |
| if (include.contains(library.importUri)) { | |
| component.libraries.add(library); | |
| } else { | |
| // Excluding the library also means that their canonical names will not | |
| // be computed as part of serialization, so we need to do that | |
| // preemptively here to avoid errors when serializing references to | |
| // elements of these libraries. | |
| library.bindCanonicalNames(component.root); | |
| } | |
| } | |
| } | |
| } |