diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d443f4fe88..7ecc7c30d2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ ### Dart2JS +* Removed `--no-defer-class-types` and `--no-new-deferred-split'. + ### Tools #### Dartanalyzer diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart index ace1d4cbf5a..1c52968d8a0 100644 --- a/pkg/compiler/lib/src/commandline_options.dart +++ b/pkg/compiler/lib/src/commandline_options.dart @@ -113,13 +113,6 @@ class Flags { static const String soundNullSafety = '--sound-null-safety'; static const String noSoundNullSafety = '--no-sound-null-safety'; - static const String newDeferredSplit = '--new-deferred-split'; - static const String noNewDeferredSplit = '--no-new-deferred-split'; - static const String reportInvalidInferredDeferredTypes = - '--report-invalid-deferred-types'; - static const String deferClassTypes = '--defer-class-types'; - static const String noDeferClassTypes = '--no-defer-class-types'; - /// Flag for a combination of flags for 'production' mode. static const String benchmarkingProduction = '--benchmarking-production'; diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart index 98f2f79871f..3bd43ed2b3f 100644 --- a/pkg/compiler/lib/src/dart2js.dart +++ b/pkg/compiler/lib/src/dart2js.dart @@ -468,10 +468,6 @@ Future compile(List argv, new OptionHandler(Flags.disableRtiOptimization, passThrough), new OptionHandler(Flags.terse, passThrough), new OptionHandler('--deferred-map=.+', passThrough), - new OptionHandler(Flags.newDeferredSplit, passThrough), - new OptionHandler(Flags.reportInvalidInferredDeferredTypes, passThrough), - new OptionHandler(Flags.deferClassTypes, passThrough), - new OptionHandler(Flags.noDeferClassTypes, passThrough), new OptionHandler('${Flags.dumpInfo}|${Flags.dumpInfo}=.+', setDumpInfo), new OptionHandler('--disallow-unsafe-eval', ignoreOption), new OptionHandler(Option.showPackageWarnings, passThrough), diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart index d47da8e6d25..364fe9a30ac 100644 --- a/pkg/compiler/lib/src/deferred_load.dart +++ b/pkg/compiler/lib/src/deferred_load.dart @@ -7,6 +7,8 @@ library deferred_load; import 'dart:collection' show Queue; import 'package:front_end/src/api_unstable/dart2js.dart' as fe; +import 'package:kernel/ast.dart' as ir; +import 'package:kernel/type_environment.dart' as ir; import 'common/metrics.dart' show Metric, Metrics, CountMetric, DurationMetric; import 'common/tasks.dart' show CompilerTask; @@ -18,12 +20,13 @@ import 'constants/values.dart' show ConstantValue, ConstructedConstantValue, - TypeConstantValue, DeferredGlobalConstantValue, InstantiationConstantValue; import 'elements/types.dart'; import 'elements/entities.dart'; +import 'ir/util.dart'; import 'kernel/kelements.dart' show KLocalFunction; +import 'kernel/element_map.dart'; import 'serialization/serialization.dart'; import 'options.dart'; import 'universe/use.dart'; @@ -102,7 +105,7 @@ class _DeferredLoadTaskMetrics implements Metrics { /// For each deferred import, find elements and constants to be loaded when that /// import is loaded. Elements that are used by several deferred imports are in /// shared OutputUnits. -abstract class DeferredLoadTask extends CompilerTask { +class DeferredLoadTask extends CompilerTask { @override String get name => 'Deferred Loading'; @@ -149,17 +152,15 @@ abstract class DeferredLoadTask extends CompilerTask { final Compiler compiler; + KernelToElementMap _elementMap; + @override final _DeferredLoadTaskMetrics metrics = _DeferredLoadTaskMetrics(); bool get disableProgramSplit => compiler.options.disableProgramSplit; - bool get newDeferredSplit => compiler.options.newDeferredSplit; - bool get reportInvalidInferredDeferredTypes => - compiler.options.reportInvalidInferredDeferredTypes; - bool get deferClassTypes => compiler.options.deferClassTypes; - DeferredLoadTask(this.compiler) : super(compiler.measurer) { - _mainOutputUnit = OutputUnit(true, 'main', {}); + DeferredLoadTask(this.compiler, this._elementMap) : super(compiler.measurer) { + _mainOutputUnit = OutputUnit(true, 'main', {}); importSets.mainSet.unit = _mainOutputUnit; _allOutputUnits.add(_mainOutputUnit); } @@ -172,27 +173,6 @@ abstract class DeferredLoadTask extends CompilerTask { DiagnosticReporter get reporter => compiler.reporter; - /// Given [imports] that refer to an element from a library, determine whether - /// the element is explicitly deferred. - static bool _isExplicitlyDeferred(Iterable imports) { - // If the element is not imported explicitly, it is implicitly imported - // not deferred. - if (imports.isEmpty) return false; - // An element could potentially be loaded by several imports. If all of them - // is explicitly deferred, we say the element is explicitly deferred. - // TODO(sigurdm): We might want to give a warning if the imports do not - // agree. - return imports.every((ImportEntity import) => import.isDeferred); - } - - /// Returns every [ImportEntity] that imports [element] into [library]. - Iterable classImportsTo( - ClassEntity element, LibraryEntity library); - - /// Returns every [ImportEntity] that imports [element] into [library]. - Iterable memberImportsTo( - MemberEntity element, LibraryEntity library); - /// Collects all direct dependencies of [element]. /// /// The collected dependent elements and constants are are added to @@ -275,30 +255,37 @@ abstract class DeferredLoadTask extends CompilerTask { // they are processed as part of the class. } - /// Extract the set of constants that are used in annotations of [element]. - /// - /// If the underlying system doesn't support mirrors, then no constants are - /// added. - void collectConstantsFromMetadata( - Entity element, Set constants); - /// Extract the set of constants that are used in the body of [element]. - void collectConstantsInBody(MemberEntity element, Dependencies dependencies); + void collectConstantsInBody(MemberEntity element, Dependencies dependencies) { + ir.Member node = _elementMap.getMemberNode(element); + + // Fetch the internal node in order to skip annotations on the member. + // TODO(sigmund): replace this pattern when the kernel-ast provides a better + // way to skip annotations (issue 31565). + var visitor = new ConstantCollector( + _elementMap, _elementMap.getStaticTypeContext(element), dependencies); + if (node is ir.Field) { + node.initializer?.accept(visitor); + return; + } + + if (node is ir.Constructor) { + node.initializers.forEach((i) => i.accept(visitor)); + } + node.function?.accept(visitor); + } /// Recursively collects all the dependencies of [type]. void _collectTypeDependencies(DartType type, Dependencies dependencies, [ImportEntity import]) { - TypeDependencyVisitor(dependencies, import, commonElements, - collectClassesAndTypes: !deferClassTypes) - .visit(type); + TypeDependencyVisitor(dependencies, import, commonElements).visit(type); } void _collectTypeArgumentDependencies( Iterable typeArguments, Dependencies dependencies, [ImportEntity import]) { if (typeArguments == null) return; - TypeDependencyVisitor(dependencies, import, commonElements, - collectClassesAndTypes: !deferClassTypes) + TypeDependencyVisitor(dependencies, import, commonElements) .visitList(typeArguments); } @@ -600,62 +587,6 @@ abstract class DeferredLoadTask extends CompilerTask { /// same nodes we have already seen. _shouldAddDeferredDependency(ImportSet newSet) => newSet.length <= 1; - void _fixDependencyInfo(DependencyInfo info, List imports, - String prefix, String name, Spannable context) { - var isDeferred = _isExplicitlyDeferred(imports); - if (isDeferred) { - if (!newDeferredSplit) { - info.isDeferred = true; - info.imports = imports; - } - if (reportInvalidInferredDeferredTypes) { - reporter.reportErrorMessage(context, MessageKind.GENERIC, { - 'text': "$prefix '$name' is deferred but appears to be inferred as" - " a return type or a type parameter (dartbug.com/35311)." - }); - } - } - } - - // The following 3 methods are used to check whether the new deferred split - // algorithm and the old one match. Because of a soundness bug in the old - // algorithm the new algorithm can pull in a lot of code to the main output - // unit. This logic detects it and will make it easier for us to migrate code - // off it incrementally. - // Note: we only expect discrepancies on class-dependency-info due to how - // inferred types expose deferred types in type-variables and return types - // (Issue #35311). We added the other two methods to test our transition, but - // we don't expect to detect any mismatches there. - // - // TODO(sigmund): delete once the new implementation is on by default. - void _fixClassDependencyInfo(DependencyInfo info, ClassEntity cls, - LibraryEntity library, Spannable context) { - if (info.isDeferred) return; - if (newDeferredSplit && !reportInvalidInferredDeferredTypes) return; - var imports = classImportsTo(cls, library); - _fixDependencyInfo(info, imports, "Class", cls.name, context); - } - - void _fixMemberDependencyInfo(DependencyInfo info, MemberEntity member, - LibraryEntity library, Spannable context) { - if (info.isDeferred || compiler.options.newDeferredSplit) return; - var imports = memberImportsTo(member, library); - _fixDependencyInfo(info, imports, "Member", member.name, context); - } - - void _fixConstantDependencyInfo(DependencyInfo info, ConstantValue constant, - LibraryEntity library, Spannable context) { - if (info.isDeferred || compiler.options.newDeferredSplit) return; - if (constant is TypeConstantValue) { - var type = constant.representedType.withoutNullability; - if (type is InterfaceType) { - var imports = classImportsTo(type.element, library); - _fixDependencyInfo( - info, imports, "Class (in constant) ", type.element.name, context); - } - } - } - void _processDependencies( KClosedWorld closedWorld, LibraryEntity library, @@ -665,7 +596,6 @@ abstract class DeferredLoadTask extends CompilerTask { WorkQueue queue, Spannable context) { dependencies.classes.forEach((ClassEntity cls, DependencyInfo info) { - _fixClassDependencyInfo(info, cls, library, context); if (info.isDeferred) { if (_shouldAddDeferredDependency(newSet)) { for (ImportEntity deferredImport in info.imports) { @@ -678,7 +608,6 @@ abstract class DeferredLoadTask extends CompilerTask { }); dependencies.classType.forEach((ClassEntity cls, DependencyInfo info) { - _fixClassDependencyInfo(info, cls, library, context); if (info.isDeferred) { if (_shouldAddDeferredDependency(newSet)) { for (ImportEntity deferredImport in info.imports) { @@ -691,7 +620,6 @@ abstract class DeferredLoadTask extends CompilerTask { }); dependencies.members.forEach((MemberEntity member, DependencyInfo info) { - _fixMemberDependencyInfo(info, member, library, context); if (info.isDeferred) { if (_shouldAddDeferredDependency(newSet)) { for (ImportEntity deferredImport in info.imports) { @@ -709,7 +637,6 @@ abstract class DeferredLoadTask extends CompilerTask { dependencies.constants .forEach((ConstantValue constant, DependencyInfo info) { - _fixConstantDependencyInfo(info, constant, library, context); if (info.isDeferred) { if (_shouldAddDeferredDependency(newSet)) { for (ImportEntity deferredImport in info.imports) { @@ -948,10 +875,8 @@ abstract class DeferredLoadTask extends CompilerTask { _localFunctionToSet = null; _constantToSet = null; importSets = null; - cleanup(); return OutputUnitData( this.isProgramSplit && !disableProgramSplit, - deferClassTypes, this._mainOutputUnit, classMap, classTypeMap, @@ -964,15 +889,11 @@ abstract class DeferredLoadTask extends CompilerTask { _deferredImportDescriptions); } - /// Frees up strategy-specific temporary data. - void cleanup() {} - void beforeResolution(Uri rootLibraryUri, Iterable libraries) { measureSubtask('prepare', () { for (Uri uri in libraries) { LibraryEntity library = elementEnvironment.lookupLibrary(uri); reporter.withCurrentElement(library, () { - checkForDeferredErrorCases(library); for (ImportEntity import in elementEnvironment.getImports(library)) { if (import.isDeferred) { _deferredImportDescriptions[import] = @@ -985,13 +906,6 @@ abstract class DeferredLoadTask extends CompilerTask { }); } - /// Detects errors like duplicate uses of a prefix or using the old deferred - /// loading syntax. - /// - /// These checks are already done by the shared front-end, so they can be - /// skipped by the new compiler pipeline. - void checkForDeferredErrorCases(LibraryEntity library); - bool ignoreEntityInDump(Entity element) => false; /// Creates a textual representation of the output unit content. @@ -1014,7 +928,7 @@ abstract class DeferredLoadTask extends CompilerTask { }); _memberToSet.forEach((MemberEntity element, ImportSet importSet) { if (ignoreEntityInDump(element)) return; - var elements = elementMap.putIfAbsent(importSet.unit, () => []); + var elements = elementMap.putIfAbsent(importSet.unit, () => []); var id = element.name ?? '$element'; var cls = element.enclosingClass?.name; if (cls != null) id = '$cls.$id'; @@ -1024,7 +938,7 @@ abstract class DeferredLoadTask extends CompilerTask { }); _localFunctionToSet.forEach((Local element, ImportSet importSet) { if (ignoreEntityInDump(element)) return; - var elements = elementMap.putIfAbsent(importSet.unit, () => []); + var elements = elementMap.putIfAbsent(importSet.unit, () => []); var id = element.name ?? '$element'; var context = (element as dynamic).memberContext.name; id = element.name == null || element.name == '' ? '' : id; @@ -1037,7 +951,7 @@ abstract class DeferredLoadTask extends CompilerTask { // if they are shared, they end up duplicated anyways across output units. if (value.isPrimitive) return; constantMap - .putIfAbsent(importSet.unit, () => []) + .putIfAbsent(importSet.unit, () => []) .add(value.toStructuredText(dartTypes)); }); @@ -1464,7 +1378,6 @@ class OutputUnitData { static const String tag = 'output-unit-data'; final bool isProgramSplit; - final bool deferClassTypes; final OutputUnit mainOutputUnit; final Map _classToUnit; final Map _classTypeToUnit; @@ -1489,7 +1402,6 @@ class OutputUnitData { OutputUnitData( this.isProgramSplit, - this.deferClassTypes, this.mainOutputUnit, this._classToUnit, this._classTypeToUnit, @@ -1532,13 +1444,12 @@ class OutputUnitData { return OutputUnitData( other.isProgramSplit, - other.deferClassTypes, other.mainOutputUnit, classToUnit, classTypeToUnit, memberToUnit, // Local functions only make sense in the K-world model. - const {}, + const {}, constantToUnit, other.outputUnits, other._importDeferName, @@ -1550,7 +1461,6 @@ class OutputUnitData { factory OutputUnitData.readFromDataSource(DataSource source) { source.begin(tag); bool isProgramSplit = source.readBool(); - bool deferClassTypes = source.readBool(); List outputUnits = source.readList(() { bool isMainOutput = source.readBool(); String name = source.readString(); @@ -1589,13 +1499,12 @@ class OutputUnitData { source.end(tag); return OutputUnitData( isProgramSplit, - deferClassTypes, mainOutputUnit, classToUnit, classTypeToUnit, memberToUnit, // Local functions only make sense in the K-world model. - const {}, + const {}, constantToUnit, outputUnits, importDeferName, @@ -1607,7 +1516,6 @@ class OutputUnitData { void writeToDataSink(DataSink sink) { sink.begin(tag); sink.writeBool(isProgramSplit); - sink.writeBool(deferClassTypes); Map outputUnitIndices = {}; sink.writeList(outputUnits, (OutputUnit outputUnit) { outputUnitIndices[outputUnit] = outputUnitIndices.length; @@ -1661,18 +1569,13 @@ class OutputUnitData { // TODO(joshualitt): see above TODO regarding allowNull. OutputUnit outputUnitForClassType(ClassEntity cls, {bool allowNull: false}) { if (!isProgramSplit) return mainOutputUnit; - OutputUnit unit; - if (deferClassTypes) { - unit = _classTypeToUnit[cls]; - } else { - unit = _classToUnit[cls]; - } + OutputUnit unit = _classTypeToUnit[cls]; assert(allowNull || unit != null, 'No output unit for type $cls'); return unit ?? mainOutputUnit; } OutputUnit outputUnitForClassTypeForTesting(ClassEntity cls) => - deferClassTypes ? _classTypeToUnit[cls] : _classToUnit[cls]; + _classTypeToUnit[cls]; /// Returns the [OutputUnit] where [member] belongs. OutputUnit outputUnitForMember(MemberEntity member) { @@ -1801,10 +1704,8 @@ class OutputUnitData { Map libraryMap = mapping.putIfAbsent( description.importingUri, - () => { - "name": getName(description._importingLibrary), - "imports": >{} - }); + () => + {"name": getName(description._importingLibrary), "imports": {}}); List partFileNames = outputUnits .where((outputUnit) => !omittedUnits.contains(outputUnit)) @@ -1874,16 +1775,11 @@ class DependencyInfo { } class TypeDependencyVisitor implements DartTypeVisitor { - // If true, collect classes and types, otherwise just collect types. - // Note: When collecting classes, types are added implicitly by the - // dependencies class. - final bool collectClassesAndTypes; final Dependencies _dependencies; final ImportEntity _import; final CommonElements _commonElements; - TypeDependencyVisitor(this._dependencies, this._import, this._commonElements, - {this.collectClassesAndTypes}); + TypeDependencyVisitor(this._dependencies, this._import, this._commonElements); @override void visit(DartType type, [_]) { @@ -1906,11 +1802,7 @@ class TypeDependencyVisitor implements DartTypeVisitor { @override void visitFutureOrType(FutureOrType type, Null argument) { - if (collectClassesAndTypes) { - _dependencies.addClass(_commonElements.futureClass); - } else { - _dependencies.addClassType(_commonElements.futureClass); - } + _dependencies.addClassType(_commonElements.futureClass); visit(type.typeArgument); } @@ -1937,11 +1829,7 @@ class TypeDependencyVisitor implements DartTypeVisitor { @override void visitInterfaceType(InterfaceType type, Null argument) { visitList(type.typeArguments); - if (collectClassesAndTypes) { - _dependencies.addClass(type.element, _import); - } else { - _dependencies.addClassType(type.element, _import); - } + _dependencies.addClassType(type.element, _import); } @override @@ -1970,3 +1858,108 @@ class TypeDependencyVisitor implements DartTypeVisitor { // Nothing to add. } } + +class ConstantCollector extends ir.RecursiveVisitor { + final KernelToElementMap elementMap; + final Dependencies dependencies; + final ir.StaticTypeContext staticTypeContext; + + ConstantCollector(this.elementMap, this.staticTypeContext, this.dependencies); + + CommonElements get commonElements => elementMap.commonElements; + + void add(ir.Expression node, {bool required: true}) { + ConstantValue constant = elementMap + .getConstantValue(staticTypeContext, node, requireConstant: required); + if (constant != null) { + dependencies.addConstant( + constant, elementMap.getImport(getDeferredImport(node))); + } + } + + @override + void visitIntLiteral(ir.IntLiteral literal) {} + + @override + void visitDoubleLiteral(ir.DoubleLiteral literal) {} + + @override + void visitBoolLiteral(ir.BoolLiteral literal) {} + + @override + void visitStringLiteral(ir.StringLiteral literal) {} + + @override + void visitSymbolLiteral(ir.SymbolLiteral literal) => add(literal); + + @override + void visitNullLiteral(ir.NullLiteral literal) {} + + @override + void visitListLiteral(ir.ListLiteral literal) { + if (literal.isConst) { + add(literal); + } else { + super.visitListLiteral(literal); + } + } + + @override + void visitSetLiteral(ir.SetLiteral literal) { + if (literal.isConst) { + add(literal); + } else { + super.visitSetLiteral(literal); + } + } + + @override + void visitMapLiteral(ir.MapLiteral literal) { + if (literal.isConst) { + add(literal); + } else { + super.visitMapLiteral(literal); + } + } + + @override + void visitConstructorInvocation(ir.ConstructorInvocation node) { + if (node.isConst) { + add(node); + } else { + super.visitConstructorInvocation(node); + } + } + + @override + void visitTypeParameter(ir.TypeParameter node) { + // We avoid visiting metadata on the type parameter declaration. The bound + // cannot hold constants so we skip that as well. + } + + @override + void visitVariableDeclaration(ir.VariableDeclaration node) { + // We avoid visiting metadata on the parameter declaration by only visiting + // the initializer. The type cannot hold constants so can kan skip that + // as well. + node.initializer?.accept(this); + } + + @override + void visitTypeLiteral(ir.TypeLiteral node) { + if (node.type is! ir.TypeParameterType) add(node); + } + + @override + void visitInstantiation(ir.Instantiation node) { + // TODO(johnniwinther): The CFE should mark constant instantiations as + // constant. + add(node, required: false); + super.visitInstantiation(node); + } + + @override + void visitConstantExpression(ir.ConstantExpression node) { + add(node); + } +} diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart index 1ab31fc6f68..bac69a0cba4 100644 --- a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart +++ b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart @@ -9,7 +9,6 @@ part of dart2js.js_emitter.program_builder; /// /// The code for the containing (used) methods must exist in the `universe`. class Collector { - final CompilerOptions _options; final JCommonElements _commonElements; final JElementEnvironment _elementEnvironment; final OutputUnitData _outputUnitData; @@ -43,7 +42,6 @@ class Collector { final List nativeClassesAndSubclasses = []; Collector( - this._options, this._commonElements, this._elementEnvironment, this._outputUnitData, @@ -105,7 +103,7 @@ class Collector { // Return the classes that are just helpers for the backend's type system. static Iterable getBackendTypeHelpers( JCommonElements commonElements) { - return [ + return [ commonElements.jsMutableArrayClass, commonElements.jsFixedArrayClass, commonElements.jsExtendableArrayClass, @@ -137,14 +135,6 @@ class Collector { } } - Map> get _outputListsForClassType { - if (_options.deferClassTypes) { - return outputClassTypeLists; - } else { - return outputClassLists; - } - } - /// Compute all the classes and typedefs that must be emitted. void computeNeededDeclarations() { Set backendTypeHelpers = @@ -157,7 +147,6 @@ class Collector { return !backendTypeHelpers.contains(cls) && _rtiNeededClasses.contains(cls) && !classesOnlyNeededForRti.contains(cls) && - _options.deferClassTypes && _outputUnitData.outputUnitForClass(cls) != _outputUnitData.outputUnitForClassType(cls); } @@ -240,7 +229,7 @@ class Collector { // 7. Sort classes needed for type checking and then add them to their // respective OutputUnits. for (ClassEntity cls in _sorter.sortClasses(neededClassTypes)) { - _outputListsForClassType + outputClassTypeLists .putIfAbsent(_outputUnitData.outputUnitForClassType(cls), () => []) .add(cls); } diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart index 53518854258..0d0b4382f00 100644 --- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart +++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart @@ -135,7 +135,6 @@ class ProgramBuilder { this._rtiNeededClasses, this._mainFunction) : this.collector = new Collector( - _options, _commonElements, _elementEnvironment, _outputUnitData, @@ -653,16 +652,11 @@ class ProgramBuilder { Class _buildClass(ClassEntity cls) { bool onlyForConstructor = collector.classesOnlyNeededForConstructor.contains(cls); - bool onlyForRti = _options.deferClassTypes - ? false - : collector.classesOnlyNeededForRti.contains(cls); + // TODO(joshualitt): Can we just emit JSInteropClasses as types? + // TODO(jacobr): check whether the class has any active static fields + // if it does not we can suppress it completely. + bool onlyForRti = _nativeData.isJsInteropClass(cls); bool hasRtiField = _rtiNeed.classNeedsTypeArguments(cls); - if (_nativeData.isJsInteropClass(cls)) { - // TODO(joshualitt): Can we just emit JSInteropClasses as types? - // TODO(jacobr): check whether the class has any active static fields - // if it does not we can suppress it completely. - onlyForRti = true; - } bool onlyForConstructorOrRti = onlyForConstructor || onlyForRti; bool isClosureBaseClass = cls == _commonElements.closureClass; diff --git a/pkg/compiler/lib/src/kernel/deferred_load.dart b/pkg/compiler/lib/src/kernel/deferred_load.dart deleted file mode 100644 index 37ca71d1fb5..00000000000 --- a/pkg/compiler/lib/src/kernel/deferred_load.dart +++ /dev/null @@ -1,217 +0,0 @@ -// 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. - -library kernel.deferred_load_data; - -import 'package:kernel/ast.dart' as ir; -import 'package:kernel/type_environment.dart' as ir; - -import '../common_elements.dart'; -import '../compiler.dart' show Compiler; -import '../constants/values.dart'; -import '../deferred_load.dart'; -import '../elements/entities.dart'; -import '../ir/util.dart'; -import 'element_map.dart'; - -class KernelDeferredLoadTask extends DeferredLoadTask { - KernelToElementMap _elementMap; - Map> _additionalExportsSets = - >{}; - - KernelDeferredLoadTask(Compiler compiler, this._elementMap) : super(compiler); - - Iterable _findImportsTo(ir.NamedNode node, String nodeName, - ir.Library enclosingLibrary, LibraryEntity library) { - return measureSubtask('find-imports', () { - List imports = []; - ir.Library source = _elementMap.getLibraryNode(library); - if (!source.dependencies.any((d) => d.isDeferred)) return const []; - for (ir.LibraryDependency dependency in source.dependencies) { - if (dependency.isExport) continue; - if (!_isVisible(dependency.combinators, nodeName)) continue; - if (enclosingLibrary == dependency.targetLibrary || - additionalExports(dependency.targetLibrary).contains(node)) { - imports.add(_elementMap.getImport(dependency)); - } - } - return imports; - }); - } - - @override - Iterable classImportsTo( - ClassEntity element, LibraryEntity library) { - ir.Class node = _elementMap.getClassNode(element); - return _findImportsTo(node, node.name, node.enclosingLibrary, library); - } - - @override - Iterable memberImportsTo( - Entity element, LibraryEntity library) { - ir.Member node = _elementMap.getMemberNode(element); - return _findImportsTo( - node is ir.Constructor ? node.enclosingClass : node, - node is ir.Constructor ? node.enclosingClass.name : node.name.text, - node.enclosingLibrary, - library); - } - - @override - void checkForDeferredErrorCases(LibraryEntity library) { - // Nothing to do. The FE checks for error cases upfront. - } - - @override - void collectConstantsFromMetadata( - Entity element, Set constants) { - // Nothing to do. Kernel-pipeline doesn't support mirrors, so we don't need - // to track any constants from meta-data. - } - - @override - void collectConstantsInBody(MemberEntity element, Dependencies dependencies) { - ir.Member node = _elementMap.getMemberNode(element); - - // Fetch the internal node in order to skip annotations on the member. - // TODO(sigmund): replace this pattern when the kernel-ast provides a better - // way to skip annotations (issue 31565). - var visitor = new ConstantCollector( - _elementMap, _elementMap.getStaticTypeContext(element), dependencies); - if (node is ir.Field) { - node.initializer?.accept(visitor); - return; - } - - if (node is ir.Constructor) { - node.initializers.forEach((i) => i.accept(visitor)); - } - node.function?.accept(visitor); - } - - Set additionalExports(ir.Library library) { - return _additionalExportsSets[library] ??= new Set.from( - library.additionalExports.map((ir.Reference ref) => ref.node)); - } - - @override - void cleanup() { - _additionalExportsSets = null; - } -} - -/// Returns whether [name] would be visible according to the given list of -/// show/hide [combinators]. -bool _isVisible(List combinators, String name) { - for (var c in combinators) { - if (c.isShow && !c.names.contains(name)) return false; - if (c.isHide && c.names.contains(name)) return false; - } - return true; -} - -class ConstantCollector extends ir.RecursiveVisitor { - final KernelToElementMap elementMap; - final Dependencies dependencies; - final ir.StaticTypeContext staticTypeContext; - - ConstantCollector(this.elementMap, this.staticTypeContext, this.dependencies); - - CommonElements get commonElements => elementMap.commonElements; - - void add(ir.Expression node, {bool required: true}) { - ConstantValue constant = elementMap - .getConstantValue(staticTypeContext, node, requireConstant: required); - if (constant != null) { - dependencies.addConstant( - constant, elementMap.getImport(getDeferredImport(node))); - } - } - - @override - void visitIntLiteral(ir.IntLiteral literal) {} - - @override - void visitDoubleLiteral(ir.DoubleLiteral literal) {} - - @override - void visitBoolLiteral(ir.BoolLiteral literal) {} - - @override - void visitStringLiteral(ir.StringLiteral literal) {} - - @override - void visitSymbolLiteral(ir.SymbolLiteral literal) => add(literal); - - @override - void visitNullLiteral(ir.NullLiteral literal) {} - - @override - void visitListLiteral(ir.ListLiteral literal) { - if (literal.isConst) { - add(literal); - } else { - super.visitListLiteral(literal); - } - } - - @override - void visitSetLiteral(ir.SetLiteral literal) { - if (literal.isConst) { - add(literal); - } else { - super.visitSetLiteral(literal); - } - } - - @override - void visitMapLiteral(ir.MapLiteral literal) { - if (literal.isConst) { - add(literal); - } else { - super.visitMapLiteral(literal); - } - } - - @override - void visitConstructorInvocation(ir.ConstructorInvocation node) { - if (node.isConst) { - add(node); - } else { - super.visitConstructorInvocation(node); - } - } - - @override - void visitTypeParameter(ir.TypeParameter node) { - // We avoid visiting metadata on the type parameter declaration. The bound - // cannot hold constants so we skip that as well. - } - - @override - void visitVariableDeclaration(ir.VariableDeclaration node) { - // We avoid visiting metadata on the parameter declaration by only visiting - // the initializer. The type cannot hold constants so can kan skip that - // as well. - node.initializer?.accept(this); - } - - @override - void visitTypeLiteral(ir.TypeLiteral node) { - if (node.type is! ir.TypeParameterType) add(node); - } - - @override - void visitInstantiation(ir.Instantiation node) { - // TODO(johnniwinther): The CFE should mark constant instantiations as - // constant. - add(node, required: false); - super.visitInstantiation(node); - } - - @override - void visitConstantExpression(ir.ConstantExpression node) { - add(node); - } -} diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart index 478c2bce1b2..b8959e97bac 100644 --- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart +++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart @@ -45,7 +45,6 @@ import '../universe/resolution_world_builder.dart'; import '../universe/world_builder.dart'; import '../universe/world_impact.dart'; import '../util/enumset.dart'; -import 'deferred_load.dart'; import 'element_map.dart'; import 'element_map_impl.dart'; import 'loader.dart'; @@ -54,7 +53,7 @@ import 'loader.dart'; /// model from kernel IR nodes. class KernelFrontendStrategy extends FrontendStrategy { final NativeBasicDataBuilderImpl nativeBasicDataBuilder = - new NativeBasicDataBuilderImpl(); + NativeBasicDataBuilderImpl(); NativeBasicData _nativeBasicData; CompilerOptions _options; CompilerTask _compilerTask; @@ -87,12 +86,11 @@ class KernelFrontendStrategy extends FrontendStrategy { KernelFrontendStrategy(this._compilerTask, this._options, DiagnosticReporter reporter, env.Environment environment) { assert(_compilerTask != null); - _elementMap = - new KernelToElementMapImpl(reporter, environment, this, _options); - _modularStrategy = new KernelModularStrategy(_compilerTask, _elementMap); - _backendUsageBuilder = new BackendUsageBuilderImpl(this); - noSuchMethodRegistry = new NoSuchMethodRegistryImpl( - commonElements, new KernelNoSuchMethodResolver(_elementMap)); + _elementMap = KernelToElementMapImpl(reporter, environment, this, _options); + _modularStrategy = KernelModularStrategy(_compilerTask, _elementMap); + _backendUsageBuilder = BackendUsageBuilderImpl(this); + noSuchMethodRegistry = NoSuchMethodRegistryImpl( + commonElements, KernelNoSuchMethodResolver(_elementMap)); } NativeResolutionEnqueuer get nativeResolutionEnqueuerForTesting => @@ -139,32 +137,30 @@ class KernelFrontendStrategy extends FrontendStrategy { ResolutionEnqueuer createResolutionEnqueuer( CompilerTask task, Compiler compiler) { RuntimeTypesNeedBuilder rtiNeedBuilder = _createRuntimeTypesNeedBuilder(); - BackendImpacts impacts = - new BackendImpacts(commonElements, compiler.options); - _nativeResolutionEnqueuer = new NativeResolutionEnqueuer( + BackendImpacts impacts = BackendImpacts(commonElements, compiler.options); + _nativeResolutionEnqueuer = NativeResolutionEnqueuer( compiler.options, elementEnvironment, commonElements, _elementMap.types, - new BaseNativeClassFinder(elementEnvironment, nativeBasicData)); - _nativeDataBuilder = new NativeDataBuilderImpl(nativeBasicData); - _customElementsResolutionAnalysis = new CustomElementsResolutionAnalysis( + BaseNativeClassFinder(elementEnvironment, nativeBasicData)); + _nativeDataBuilder = NativeDataBuilderImpl(nativeBasicData); + _customElementsResolutionAnalysis = CustomElementsResolutionAnalysis( elementEnvironment, commonElements, nativeBasicData, _backendUsageBuilder); - _fieldAnalysis = new KFieldAnalysis(this); - ClassQueries classQueries = new KernelClassQueries(elementMap); + _fieldAnalysis = KFieldAnalysis(this); + ClassQueries classQueries = KernelClassQueries(elementMap); ClassHierarchyBuilder classHierarchyBuilder = - new ClassHierarchyBuilder(commonElements, classQueries); - AnnotationsDataBuilder annotationsDataBuilder = - new AnnotationsDataBuilder(); + ClassHierarchyBuilder(commonElements, classQueries); + AnnotationsDataBuilder annotationsDataBuilder = AnnotationsDataBuilder(); // TODO(johnniwinther): This is a hack. The annotation data is built while // using it. With CFE constants the annotations data can be built fully // before creating the resolution enqueuer. - AnnotationsData annotationsData = new AnnotationsDataImpl( + AnnotationsData annotationsData = AnnotationsDataImpl( compiler.options, annotationsDataBuilder.pragmaAnnotations); - ImpactTransformer impactTransformer = new JavaScriptImpactTransformer( + ImpactTransformer impactTransformer = JavaScriptImpactTransformer( elementEnvironment, commonElements, impacts, @@ -175,13 +171,12 @@ class KernelFrontendStrategy extends FrontendStrategy { rtiNeedBuilder, classHierarchyBuilder, annotationsData); - InterceptorDataBuilder interceptorDataBuilder = - new InterceptorDataBuilderImpl( - nativeBasicData, elementEnvironment, commonElements); - return new ResolutionEnqueuer( + InterceptorDataBuilder interceptorDataBuilder = InterceptorDataBuilderImpl( + nativeBasicData, elementEnvironment, commonElements); + return ResolutionEnqueuer( task, compiler.reporter, - new ResolutionEnqueuerListener( + ResolutionEnqueuerListener( compiler.options, elementEnvironment, commonElements, @@ -194,7 +189,7 @@ class KernelFrontendStrategy extends FrontendStrategy { _nativeResolutionEnqueuer, _fieldAnalysis, compiler.deferredLoadTask), - new ResolutionWorldBuilderImpl( + ResolutionWorldBuilderImpl( _options, elementMap, elementEnvironment, @@ -212,7 +207,7 @@ class KernelFrontendStrategy extends FrontendStrategy { const StrongModeWorldStrategy(), classHierarchyBuilder, classQueries), - new KernelWorkItemBuilder( + KernelWorkItemBuilder( _compilerTask, elementMap, nativeBasicData, @@ -251,8 +246,8 @@ class KernelFrontendStrategy extends FrontendStrategy { void registerLoadedLibraries(KernelResult kernelResult) { _elementMap.addComponent(kernelResult.component); _irAnnotationData = processAnnotations( - new ModularCore(kernelResult.component, _elementMap.constantEvaluator)); - _annotationProcessor = new KernelAnnotationProcessor( + ModularCore(kernelResult.component, _elementMap.constantEvaluator)); + _annotationProcessor = KernelAnnotationProcessor( elementMap, nativeBasicDataBuilder, _irAnnotationData); for (Uri uri in kernelResult.libraries) { LibraryEntity library = elementEnvironment.lookupLibrary(uri); @@ -280,7 +275,7 @@ class KernelFrontendStrategy extends FrontendStrategy { @override DeferredLoadTask createDeferredLoadTask(Compiler compiler) => - new KernelDeferredLoadTask(compiler, _elementMap); + DeferredLoadTask(compiler, _elementMap); @override FunctionEntity computeMain(WorldImpactBuilder impactBuilder) { @@ -290,7 +285,7 @@ class KernelFrontendStrategy extends FrontendStrategy { RuntimeTypesNeedBuilder _createRuntimeTypesNeedBuilder() { return _runtimeTypesNeedBuilder ??= _options.disableRtiOptimization ? const TrivialRuntimeTypesNeedBuilder() - : new RuntimeTypesNeedBuilderImpl(elementEnvironment); + : RuntimeTypesNeedBuilderImpl(elementEnvironment); } RuntimeTypesNeedBuilder get runtimeTypesNeedBuilderForTesting => @@ -326,12 +321,12 @@ class KernelWorkItemBuilder implements WorkItemBuilder { this._fieldAnalysis, this._modularStrategy, this._irAnnotationData) - : _nativeMemberResolver = new KernelNativeMemberResolver( + : _nativeMemberResolver = KernelNativeMemberResolver( _elementMap, nativeBasicData, nativeDataBuilder); @override WorkItem createWorkItem(MemberEntity entity) { - return new KernelWorkItem( + return KernelWorkItem( _compilerTask, _elementMap, _impactTransformer, @@ -404,7 +399,7 @@ class KernelWorkItem implements WorkItem { ResolutionImpact impact = _elementMap.computeWorldImpact( element, scopeModel.variableScopeModel, - new Set.from( + Set.from( annotations.iterable(PragmaAnnotation.values)), impactBuilderData: impactBuilderData); WorldImpact worldImpact = @@ -440,8 +435,8 @@ class KernelModularStrategy extends ModularStrategy { @override ModularMemberData getModularMemberData( ir.Member node, EnumSet annotations) { - ScopeModel scopeModel = _compilerTask.measureSubtask('closures', - () => new ScopeModel.from(node, _elementMap.constantEvaluator)); + ScopeModel scopeModel = _compilerTask.measureSubtask( + 'closures', () => ScopeModel.from(node, _elementMap.constantEvaluator)); ImpactBuilderData impactBuilderData; if (useImpactDataForTesting) { // TODO(johnniwinther): Always create and use the [ImpactBuilderData]. @@ -449,8 +444,8 @@ class KernelModularStrategy extends ModularStrategy { // depend on metadata, so these parts of the impact data need to be // computed during conversion to [ResolutionImpact]. impactBuilderData = _compilerTask.measureSubtask('worldImpact', () { - ImpactBuilder builder = new ImpactBuilder( - new ir.StaticTypeContext(node, _elementMap.typeEnvironment), + ImpactBuilder builder = ImpactBuilder( + ir.StaticTypeContext(node, _elementMap.typeEnvironment), _elementMap.classHierarchy, scopeModel.variableScopeModel, useAsserts: _elementMap.options.enableUserAssertions, @@ -459,6 +454,6 @@ class KernelModularStrategy extends ModularStrategy { return builder.computeImpact(node); }); } - return new ModularMemberData(scopeModel, impactBuilderData); + return ModularMemberData(scopeModel, impactBuilderData); } } diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart index f8c790105ad..f11a3bb0910 100644 --- a/pkg/compiler/lib/src/options.dart +++ b/pkg/compiler/lib/src/options.dart @@ -142,32 +142,6 @@ class CompilerOptions implements DiagnosticOptions { /// libraries are subdivided. Uri deferredMapUri; - /// Whether to apply the new deferred split fixes. The fixes improve on - /// performance and fix a soundness issue with inferred types. The latter will - /// move more code to the main output unit, because of that we are not - /// enabling the feature by default right away. - /// - /// When [reportInvalidInferredDeferredTypes] shows no errors, we expect this - /// flag to produce the same or better results than the current unsound - /// implementation. - bool newDeferredSplit = true; // default value. - bool _newDeferredSplit = false; - bool _noNewDeferredSplit = false; - - /// Show errors when a deferred type is inferred as a return type of a closure - /// or in a type parameter. Those cases cause the compiler today to behave - /// unsoundly by putting the code in a deferred output unit. In the future - /// when [newDeferredSplit] is on by default, those cases will be treated - /// soundly and will cause more code to be moved to the main output unit. - /// - /// This flag is presented to help developers find and fix the affected code. - bool reportInvalidInferredDeferredTypes = false; - - /// Whether to defer load class types. - bool deferClassTypes = true; // default value. - bool _deferClassTypes = false; - bool _noDeferClassTypes = false; - /// Whether to disable inlining during the backend optimizations. // TODO(sigmund): negate, so all flags are positive bool disableInlining = false; @@ -443,12 +417,6 @@ class CompilerOptions implements DiagnosticOptions { _extractStringOption(options, '--build-id=', _UNDETERMINED_BUILD_ID) ..compileForServer = _hasOption(options, Flags.serverMode) ..deferredMapUri = _extractUriOption(options, '--deferred-map=') - .._newDeferredSplit = _hasOption(options, Flags.newDeferredSplit) - .._noNewDeferredSplit = _hasOption(options, Flags.noNewDeferredSplit) - ..reportInvalidInferredDeferredTypes = - _hasOption(options, Flags.reportInvalidInferredDeferredTypes) - .._deferClassTypes = _hasOption(options, Flags.deferClassTypes) - .._noDeferClassTypes = _hasOption(options, Flags.noDeferClassTypes) ..fatalWarnings = _hasOption(options, Flags.fatalWarnings) ..terseDiagnostics = _hasOption(options, Flags.terse) ..suppressWarnings = _hasOption(options, Flags.suppressWarnings) @@ -555,14 +523,6 @@ class CompilerOptions implements DiagnosticOptions { throw ArgumentError("'${Flags.soundNullSafety}' requires the " "'non-nullable' experiment to be enabled"); } - if (_deferClassTypes && _noDeferClassTypes) { - throw ArgumentError("'${Flags.deferClassTypes}' incompatible with " - "'${Flags.noDeferClassTypes}'"); - } - if (_newDeferredSplit && _noNewDeferredSplit) { - throw ArgumentError("'${Flags.newDeferredSplit}' incompatible with " - "'${Flags.noNewDeferredSplit}'"); - } } void deriveOptions() { @@ -620,12 +580,6 @@ class CompilerOptions implements DiagnosticOptions { if (_disableMinification) { enableMinification = false; } - - if (_deferClassTypes) deferClassTypes = true; - if (_noDeferClassTypes) deferClassTypes = false; - - if (_newDeferredSplit) newDeferredSplit = true; - if (_noNewDeferredSplit) newDeferredSplit = false; } /// Returns `true` if warnings and hints are shown for all packages.