| // Copyright (c) 2017, 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; | |
| import 'package:kernel/ast.dart' as ir; | |
| import '../common.dart'; | |
| import '../common/elements.dart'; | |
| import '../common/tasks.dart'; | |
| import '../common/work.dart'; | |
| import '../compiler.dart'; | |
| import '../deferred_load/deferred_load.dart' show DeferredLoadTask; | |
| import '../elements/entities.dart'; | |
| import '../enqueue.dart'; | |
| import '../ir/annotations.dart'; | |
| import '../ir/closure.dart' show ClosureScopeModel; | |
| import '../ir/impact.dart'; | |
| import '../ir/modular.dart'; | |
| import '../ir/scope.dart' show ScopeModel; | |
| import '../js_backend/annotations.dart'; | |
| import '../js_backend/backend_impact.dart'; | |
| import '../js_backend/backend_usage.dart'; | |
| import '../js_backend/custom_elements_analysis.dart'; | |
| import '../js_backend/field_analysis.dart' show KFieldAnalysis; | |
| import '../js_backend/interceptor_data.dart'; | |
| import '../js_backend/native_data.dart'; | |
| import '../js_backend/no_such_method_registry.dart'; | |
| import '../js_backend/resolution_listener.dart'; | |
| import '../js_backend/runtime_types_resolution.dart'; | |
| import '../js_model/elements.dart'; | |
| import '../native/enqueue.dart' show NativeResolutionEnqueuer; | |
| import '../native/resolver.dart'; | |
| import '../options.dart'; | |
| import '../resolution/enqueuer.dart'; | |
| import '../universe/class_hierarchy.dart'; | |
| import '../universe/resolution_world_builder.dart'; | |
| import '../universe/world_builder.dart'; | |
| import '../universe/world_impact.dart'; | |
| import '../util/enumset.dart'; | |
| import 'dart2js_target.dart'; | |
| import 'element_map.dart'; | |
| import 'element_map_impl.dart'; | |
| import 'native_basic_data.dart'; | |
| import 'no_such_method_resolver.dart'; | |
| /// Front end strategy that loads '.dill' files and builds a resolved element | |
| /// model from kernel IR nodes. | |
| class KernelFrontendStrategy { | |
| final CompilerOptions _options; | |
| final CompilerTask _compilerTask; | |
| late final KernelToElementMap _elementMap; | |
| late final RuntimeTypesNeedBuilder _runtimeTypesNeedBuilder = | |
| _options.disableRtiOptimization | |
| ? const TrivialRuntimeTypesNeedBuilder() | |
| : RuntimeTypesNeedBuilderImpl(elementEnvironment); | |
| RuntimeTypesNeedBuilder get runtimeTypesNeedBuilderForTesting => | |
| _runtimeTypesNeedBuilder; | |
| late KernelAnnotationProcessor _annotationProcessor; | |
| final Map<MemberEntity, ClosureScopeModel> closureModels = {}; | |
| late ModularStrategy _modularStrategy; | |
| late IrAnnotationData _irAnnotationData; | |
| late NativeDataBuilder _nativeDataBuilder; | |
| NativeDataBuilder get nativeDataBuilder => _nativeDataBuilder; | |
| late final BackendUsageBuilder _backendUsageBuilder = BackendUsageBuilder( | |
| this, | |
| ); | |
| late NativeResolutionEnqueuer _nativeResolutionEnqueuer; | |
| /// Resolution support for generating table of interceptors and | |
| /// constructors for custom elements. | |
| late CustomElementsResolutionAnalysis _customElementsResolutionAnalysis; | |
| late KFieldAnalysis _fieldAnalysis; | |
| /// Support for classifying `noSuchMethod` implementations. | |
| late NoSuchMethodRegistry noSuchMethodRegistry; | |
| KernelFrontendStrategy( | |
| this._compilerTask, | |
| this._options, | |
| DiagnosticReporter reporter, | |
| ) : _elementMap = KernelToElementMap(reporter, _options) { | |
| _modularStrategy = KernelModularStrategy(_compilerTask, _elementMap); | |
| noSuchMethodRegistry = NoSuchMethodRegistry( | |
| commonElements, | |
| NoSuchMethodResolver(_elementMap), | |
| ); | |
| } | |
| NativeResolutionEnqueuer get nativeResolutionEnqueuerForTesting => | |
| _nativeResolutionEnqueuer; | |
| KFieldAnalysis get fieldAnalysisForTesting => _fieldAnalysis; | |
| /// Called before processing of the resolution queue is started. | |
| void onResolutionStart() { | |
| // TODO(johnniwinther): Avoid the compiler.elementEnvironment.getThisType | |
| // calls. Currently needed to ensure resolution of the classes for various | |
| // queries in native behavior computation, inference and codegen. | |
| elementEnvironment.getThisType(commonElements.jsArrayClass); | |
| elementEnvironment.getThisType(commonElements.jsExtendableArrayClass); | |
| _validateInterceptorImplementsAllObjectMethods( | |
| commonElements.jsInterceptorClass, | |
| ); | |
| // The null-interceptor must also implement *all* methods. | |
| _validateInterceptorImplementsAllObjectMethods(commonElements.jsNullClass); | |
| } | |
| void _validateInterceptorImplementsAllObjectMethods( | |
| ClassEntity interceptorClass, | |
| ) { | |
| ClassEntity objectClass = commonElements.objectClass; | |
| elementEnvironment.forEachClassMember(objectClass, ( | |
| _, | |
| MemberEntity member, | |
| ) { | |
| if (!member.isInstanceMember) return; | |
| MemberEntity interceptorMember = elementEnvironment | |
| .lookupLocalClassMember(interceptorClass, member.memberName)!; | |
| // Interceptors must override all Object methods due to calling convention | |
| // differences. | |
| assert( | |
| interceptorMember.enclosingClass == interceptorClass, | |
| failedAt( | |
| interceptorMember, | |
| "Member ${member.name} not overridden in $interceptorClass. " | |
| "Found $interceptorMember from " | |
| "${interceptorMember.enclosingClass}.", | |
| ), | |
| ); | |
| }); | |
| } | |
| ResolutionEnqueuer createResolutionEnqueuer( | |
| CompilerTask task, | |
| Compiler compiler, | |
| ) { | |
| RuntimeTypesNeedBuilder rtiNeedBuilder = _runtimeTypesNeedBuilder; | |
| BackendImpacts impacts = BackendImpacts(commonElements, compiler.options); | |
| final nativeBasicData = _elementMap.nativeBasicData; | |
| _nativeResolutionEnqueuer = NativeResolutionEnqueuer( | |
| compiler.options, | |
| elementEnvironment, | |
| commonElements, | |
| _elementMap.types, | |
| NativeClassFinder(elementEnvironment, nativeBasicData), | |
| ); | |
| _nativeDataBuilder = NativeDataBuilder(nativeBasicData); | |
| _customElementsResolutionAnalysis = CustomElementsResolutionAnalysis( | |
| elementEnvironment, | |
| commonElements, | |
| nativeBasicData, | |
| _backendUsageBuilder, | |
| ); | |
| _fieldAnalysis = KFieldAnalysis(elementMap); | |
| ClassHierarchyBuilder classHierarchyBuilder = ClassHierarchyBuilder( | |
| commonElements, | |
| elementMap, | |
| ); | |
| 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 = AnnotationsDataImpl( | |
| compiler.options, | |
| compiler.reporter, | |
| annotationsDataBuilder.classPragmaAnnotations, | |
| annotationsDataBuilder.memberPragmaAnnotations, | |
| ); | |
| InterceptorDataBuilder interceptorDataBuilder = InterceptorDataBuilderImpl( | |
| nativeBasicData, | |
| elementEnvironment, | |
| commonElements, | |
| ); | |
| return ResolutionEnqueuer( | |
| task, | |
| compiler.reporter, | |
| ResolutionEnqueuerListener( | |
| compiler.options, | |
| elementEnvironment, | |
| commonElements, | |
| impacts, | |
| nativeBasicData, | |
| interceptorDataBuilder, | |
| _backendUsageBuilder, | |
| noSuchMethodRegistry, | |
| _customElementsResolutionAnalysis, | |
| _nativeResolutionEnqueuer, | |
| _fieldAnalysis, | |
| compiler.deferredLoadTask, | |
| ), | |
| ResolutionWorldBuilder( | |
| _options, | |
| elementMap, | |
| elementEnvironment, | |
| _elementMap.types, | |
| commonElements, | |
| nativeBasicData, | |
| nativeDataBuilder, | |
| interceptorDataBuilder, | |
| _backendUsageBuilder, | |
| rtiNeedBuilder, | |
| _fieldAnalysis, | |
| _nativeResolutionEnqueuer, | |
| noSuchMethodRegistry, | |
| annotationsDataBuilder, | |
| const StrongModeWorldStrategy(), | |
| classHierarchyBuilder, | |
| ), | |
| KernelWorkItemBuilder( | |
| _compilerTask, | |
| elementMap, | |
| nativeBasicData, | |
| nativeDataBuilder, | |
| annotationsDataBuilder, | |
| closureModels, | |
| compiler.impactCache, | |
| _fieldAnalysis, | |
| _modularStrategy, | |
| _irAnnotationData, | |
| impacts, | |
| _nativeResolutionEnqueuer, | |
| _backendUsageBuilder, | |
| _customElementsResolutionAnalysis, | |
| rtiNeedBuilder, | |
| annotationsData, | |
| ), | |
| annotationsData, | |
| ); | |
| } | |
| /// Registers a component with this strategy. | |
| void registerComponent(ir.Component component) { | |
| _elementMap.addComponent(component); | |
| } | |
| /// Registers a set of loaded libraries with this strategy. | |
| void registerLoadedLibraries(ir.Component component, List<Uri> libraries) { | |
| registerComponent(component); | |
| _irAnnotationData = processAnnotations( | |
| ModularCore(component, _elementMap.typeEnvironment), | |
| ); | |
| _annotationProcessor = KernelAnnotationProcessor( | |
| elementMap, | |
| elementMap.nativeBasicDataBuilder, | |
| _irAnnotationData, | |
| ); | |
| for (Uri uri in libraries) { | |
| LibraryEntity library = elementEnvironment.lookupLibrary(uri)!; | |
| if (maybeEnableNative(library.canonicalUri)) { | |
| _annotationProcessor.extractNativeAnnotations(library); | |
| } | |
| _annotationProcessor.extractJsInteropAnnotations(library); | |
| } | |
| } | |
| IrAnnotationData get irAnnotationDataForTesting => _irAnnotationData; | |
| ModularStrategy get modularStrategyForTesting => _modularStrategy; | |
| /// Returns the [ElementEnvironment] for the element model used in this | |
| /// strategy. | |
| KernelElementEnvironment get elementEnvironment => | |
| _elementMap.elementEnvironment; | |
| /// Returns the [CommonElements] for the element model used in this | |
| /// strategy. | |
| KCommonElements get commonElements => _elementMap.commonElements; | |
| KernelToElementMap get elementMap => _elementMap; | |
| /// Creates a [DeferredLoadTask] for the element model used in this strategy. | |
| DeferredLoadTask createDeferredLoadTask(Compiler compiler) => | |
| DeferredLoadTask(compiler, _elementMap); | |
| /// Computes the main function from [mainLibrary] adding additional world | |
| /// impact to [impactBuilder]. | |
| FunctionEntity? computeMain(WorldImpactBuilder impactBuilder) { | |
| return elementEnvironment.mainFunction; | |
| } | |
| /// Creates a [SourceSpan] from [spannable] in context of [currentElement]. | |
| SourceSpan spanFromSpannable(Spannable spannable, Entity? currentElement) { | |
| return _elementMap.getSourceSpan(spannable, currentElement); | |
| } | |
| } | |
| class KernelWorkItemBuilder implements WorkItemBuilder { | |
| final CompilerTask _compilerTask; | |
| final KernelToElementMap _elementMap; | |
| final KernelNativeMemberResolver _nativeMemberResolver; | |
| final AnnotationsDataBuilder _annotationsDataBuilder; | |
| final Map<MemberEntity, ClosureScopeModel> _closureModels; | |
| final Map<Entity, WorldImpact> _impactCache; | |
| final KFieldAnalysis _fieldAnalysis; | |
| final ModularStrategy _modularStrategy; | |
| final IrAnnotationData _irAnnotationData; | |
| final BackendImpacts _impacts; | |
| final NativeResolutionEnqueuer _nativeResolutionEnqueuer; | |
| final BackendUsageBuilder _backendUsageBuilder; | |
| final CustomElementsResolutionAnalysis _customElementsResolutionAnalysis; | |
| final RuntimeTypesNeedBuilder _rtiNeedBuilder; | |
| final AnnotationsData _annotationsData; | |
| KernelWorkItemBuilder( | |
| this._compilerTask, | |
| this._elementMap, | |
| NativeBasicData nativeBasicData, | |
| NativeDataBuilder nativeDataBuilder, | |
| this._annotationsDataBuilder, | |
| this._closureModels, | |
| this._impactCache, | |
| this._fieldAnalysis, | |
| this._modularStrategy, | |
| this._irAnnotationData, | |
| this._impacts, | |
| this._nativeResolutionEnqueuer, | |
| this._backendUsageBuilder, | |
| this._customElementsResolutionAnalysis, | |
| this._rtiNeedBuilder, | |
| this._annotationsData, | |
| ) : _nativeMemberResolver = KernelNativeMemberResolver( | |
| _elementMap, | |
| nativeBasicData, | |
| nativeDataBuilder, | |
| ); | |
| @override | |
| WorkItem createWorkItem(MemberEntity entity) { | |
| return KernelWorkItem( | |
| _compilerTask, | |
| _elementMap, | |
| _nativeMemberResolver, | |
| _annotationsDataBuilder, | |
| entity, | |
| _closureModels, | |
| _impactCache, | |
| _fieldAnalysis, | |
| _modularStrategy, | |
| _irAnnotationData, | |
| _impacts, | |
| _nativeResolutionEnqueuer, | |
| _backendUsageBuilder, | |
| _customElementsResolutionAnalysis, | |
| _rtiNeedBuilder, | |
| _annotationsData, | |
| ); | |
| } | |
| } | |
| class KernelWorkItem implements WorkItem { | |
| final CompilerTask _compilerTask; | |
| final KernelToElementMap _elementMap; | |
| final KernelNativeMemberResolver _nativeMemberResolver; | |
| final AnnotationsDataBuilder _annotationsDataBuilder; | |
| @override | |
| final MemberEntity element; | |
| final Map<MemberEntity, ClosureScopeModel> _closureModels; | |
| final Map<Entity, WorldImpact> _impactCache; | |
| final KFieldAnalysis _fieldAnalysis; | |
| final ModularStrategy _modularStrategy; | |
| final IrAnnotationData _irAnnotationData; | |
| final BackendImpacts _impacts; | |
| final NativeResolutionEnqueuer _nativeResolutionEnqueuer; | |
| final BackendUsageBuilder _backendUsageBuilder; | |
| final CustomElementsResolutionAnalysis _customElementsResolutionAnalysis; | |
| final RuntimeTypesNeedBuilder _rtiNeedBuilder; | |
| final AnnotationsData _annotationsData; | |
| KernelWorkItem( | |
| this._compilerTask, | |
| this._elementMap, | |
| this._nativeMemberResolver, | |
| this._annotationsDataBuilder, | |
| this.element, | |
| this._closureModels, | |
| this._impactCache, | |
| this._fieldAnalysis, | |
| this._modularStrategy, | |
| this._irAnnotationData, | |
| this._impacts, | |
| this._nativeResolutionEnqueuer, | |
| this._backendUsageBuilder, | |
| this._customElementsResolutionAnalysis, | |
| this._rtiNeedBuilder, | |
| this._annotationsData, | |
| ); | |
| @override | |
| WorldImpact run() { | |
| return _compilerTask.measure(() { | |
| ir.Member node = _elementMap.getMemberNode(element); | |
| _nativeMemberResolver.resolveNativeMember(node, _irAnnotationData); | |
| List<PragmaAnnotationData> pragmaAnnotationData = _modularStrategy | |
| .getPragmaAnnotationData(node); | |
| EnumSet<PragmaAnnotation> annotations = processPragmaAnnotations( | |
| _elementMap.options, | |
| _elementMap.reporter, | |
| node, | |
| pragmaAnnotationData, | |
| ); | |
| _annotationsDataBuilder.registerPragmaAnnotations(element, annotations); | |
| // TODO(sra): Replace the above three statements with a single call to a | |
| // new API on AnnotationsData that causes the annotations to be parsed and | |
| // checked. | |
| ModularMemberData modularMemberData = _modularStrategy | |
| .getModularMemberData(node); | |
| ScopeModel scopeModel = modularMemberData.scopeModel; | |
| if (scopeModel.closureScopeModel != null) { | |
| _closureModels[element] = scopeModel.closureScopeModel!; | |
| } | |
| if (element is FieldEntity && !element.isInstanceMember) { | |
| _fieldAnalysis.registerStaticField( | |
| element as JField, | |
| scopeModel.initializerComplexity, | |
| ); | |
| } | |
| ImpactBuilderData impactBuilderData = modularMemberData.impactBuilderData; | |
| return _compilerTask.measureSubtask('worldImpact', () { | |
| WorldImpact worldImpact = _elementMap.computeWorldImpact( | |
| element as JMember, | |
| _impacts, | |
| _nativeResolutionEnqueuer, | |
| _backendUsageBuilder, | |
| _customElementsResolutionAnalysis, | |
| _rtiNeedBuilder, | |
| _annotationsData, | |
| impactBuilderData, | |
| ); | |
| _impactCache[element] = worldImpact; | |
| return worldImpact; | |
| }); | |
| }); | |
| } | |
| @override | |
| String toString() => 'KernelWorkItem($element)'; | |
| } | |
| class KernelModularStrategy extends ModularStrategy { | |
| final CompilerTask _compilerTask; | |
| final KernelToElementMap _elementMap; | |
| KernelModularStrategy(this._compilerTask, this._elementMap); | |
| @override | |
| List<PragmaAnnotationData> getPragmaAnnotationData(ir.Member node) { | |
| return computePragmaAnnotationDataFromIr(node); | |
| } | |
| @override | |
| ModularMemberData getModularMemberData(ir.Member node) { | |
| ScopeModel scopeModel = _compilerTask.measureSubtask( | |
| 'closures', | |
| () => ScopeModel.from(node, _elementMap.typeEnvironment), | |
| ); | |
| return _compilerTask.measureSubtask('worldImpact', () { | |
| return computeModularMemberData(_elementMap, node, scopeModel); | |
| }); | |
| } | |
| } |