blob: c233ee8eaf64b659684d0e13f3103d4abdbd9d06 [file] [log] [blame]
// 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 dart2js.js_backend.element_strategy;
import '../backend_strategy.dart';
import '../closure.dart' show ClosureConversionTask, ClosureTask;
import '../common.dart';
import '../common/codegen.dart';
import '../common/tasks.dart';
import '../common/work.dart';
import '../compiler.dart';
import '../deferred_load.dart' show OutputUnitData;
import '../elements/elements.dart';
import '../enqueue.dart';
import '../inferrer/type_graph_inferrer.dart' show AstTypeGraphInferrer;
import '../io/multi_information.dart' show MultiSourceInformationStrategy;
import '../io/position_information.dart' show PositionSourceInformationStrategy;
import '../io/source_information.dart';
import '../io/start_end_information.dart'
show StartEndSourceInformationStrategy;
import '../js/js_source_mapping.dart' show JavaScriptSourceInformationStrategy;
import '../js_backend/backend.dart';
import '../js_backend/native_data.dart';
import '../js_emitter/sorter.dart';
import '../resolution/resolution_strategy.dart';
import '../ssa/builder.dart';
import '../ssa/ssa.dart';
import '../types/types.dart';
import '../options.dart';
import '../universe/world_builder.dart';
import '../universe/world_impact.dart';
import '../world.dart';
/// Strategy for using the [Element] model from the resolver as the backend
/// model.
class ElementBackendStrategy extends ComputeSpannableMixin
implements BackendStrategy {
final Compiler _compiler;
final ClosureConversionTask closureDataLookup;
SourceInformationStrategy _sourceInformationStrategy;
ElementBackendStrategy(this._compiler)
: closureDataLookup = new ClosureTask(_compiler);
ClosedWorldRefiner createClosedWorldRefiner(
covariant ClosedWorldImpl closedWorld) =>
closedWorld;
Sorter get sorter => const ElementSorter();
@override
CodegenWorldBuilder createCodegenWorldBuilder(
NativeBasicData nativeBasicData,
ClosedWorld closedWorld,
SelectorConstraintsStrategy selectorConstraintsStrategy) {
return new ElementCodegenWorldBuilderImpl(
_compiler.backend.constants,
closedWorld.elementEnvironment,
nativeBasicData,
closedWorld,
selectorConstraintsStrategy);
}
@override
OutputUnitData convertOutputUnitData(OutputUnitData data) => data;
@override
WorkItemBuilder createCodegenWorkItemBuilder(ClosedWorld closedWorld) {
return new ElementCodegenWorkItemBuilder(
_compiler.backend, closedWorld, _compiler.options);
}
@override
SsaBuilder createSsaBuilder(CompilerTask task, JavaScriptBackend backend,
SourceInformationStrategy sourceInformationStrategy) {
return new SsaAstBuilder(task, backend, sourceInformationStrategy);
}
SourceInformationStrategy get sourceInformationStrategy {
return _sourceInformationStrategy ??= createSourceInformationStrategy(
generateSourceMap: _compiler.options.generateSourceMap,
useMultiSourceInfo: _compiler.options.useMultiSourceInfo,
useNewSourceInfo: _compiler.options.useNewSourceInfo);
}
static SourceInformationStrategy createSourceInformationStrategy(
{bool generateSourceMap: false,
bool useMultiSourceInfo: false,
bool useNewSourceInfo: false}) {
if (!generateSourceMap) return const JavaScriptSourceInformationStrategy();
if (useMultiSourceInfo) {
if (useNewSourceInfo) {
return const MultiSourceInformationStrategy(const [
const PositionSourceInformationStrategy(),
const StartEndSourceInformationStrategy()
]);
} else {
return const MultiSourceInformationStrategy(const [
const StartEndSourceInformationStrategy(),
const PositionSourceInformationStrategy()
]);
}
} else if (useNewSourceInfo) {
return const PositionSourceInformationStrategy();
} else {
return const StartEndSourceInformationStrategy();
}
}
@override
TypesInferrer createTypesInferrer(ClosedWorldRefiner closedWorldRefiner,
{bool disableTypeInference: false}) {
return new AstTypeGraphInferrer(
_compiler, closedWorldRefiner.closedWorld, closedWorldRefiner,
disableTypeInference: disableTypeInference);
}
}
/// Builder that creates the work item necessary for the code generation of a
/// [MemberElement].
class ElementCodegenWorkItemBuilder extends WorkItemBuilder {
final JavaScriptBackend _backend;
final ClosedWorld _closedWorld;
final CompilerOptions _options;
ElementCodegenWorkItemBuilder(
this._backend, this._closedWorld, this._options);
@override
WorkItem createWorkItem(MemberElement element) {
assert(element.isDeclaration, failedAt(element));
// Don't generate code for foreign elements.
if (_backend.isForeign(_closedWorld.commonElements, element)) return null;
if (element.isAbstract) return null;
// Codegen inlines field initializers. It only needs to generate
// code for checked setters.
if (element.isField && element.isInstanceMember) {
if (!_options.enableTypeAssertions ||
element.enclosingElement.isClosure) {
return null;
}
}
return new ElementCodegenWorkItem(_backend, _closedWorld, element);
}
}
class ElementCodegenWorkItem extends CodegenWorkItem {
CodegenRegistry registry;
final ResolvedAst resolvedAst;
final JavaScriptBackend _backend;
final ClosedWorld _closedWorld;
factory ElementCodegenWorkItem(JavaScriptBackend backend,
ClosedWorld closedWorld, MemberElement element) {
// If this assertion fails, the resolution callbacks of the backend may be
// missing call of form registry.registerXXX. Alternatively, the code
// generation could spuriously be adding dependencies on things we know we
// don't need.
assert(element.hasResolvedAst,
failedAt(element, "$element has no resolved ast."));
ResolvedAst resolvedAst = element.resolvedAst;
return new ElementCodegenWorkItem.internal(
resolvedAst, backend, closedWorld);
}
ElementCodegenWorkItem.internal(
this.resolvedAst, this._backend, this._closedWorld);
MemberElement get element => resolvedAst.element;
WorldImpact run() {
registry = new CodegenRegistry(_closedWorld.elementEnvironment, element);
return _backend.codegen(this, _closedWorld);
}
String toString() => 'CodegenWorkItem(${resolvedAst.element})';
}