blob: 9fde69be5d6b77d4482362187bbd144e44ae45ae [file] [log] [blame] [edit]
// 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 '../kernel/dart2js_target.dart';
import '../kernel/no_such_method_resolver.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 'element_map.dart';
import 'element_map_impl.dart';
import 'native_basic_data.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.pragmaAnnotations,
);
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 = processMemberAnnotations(
_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);
});
}
}