Add ElementCodegenWorldBuilder

Reusable parts are left in CodegenWorldBuilderImpl and a stub KernelCodegenWorldBuilder is added.

R=sigmund@google.com

Review-Url: https://codereview.chromium.org/2894893002 .
This commit is contained in:
Johnni Winther 2017-05-22 10:05:53 +02:00
parent aa60a2ea90
commit 789fce309f
20 changed files with 338 additions and 188 deletions

View file

@ -4,8 +4,10 @@
library dart2js.backend_strategy; library dart2js.backend_strategy;
import 'compiler.dart'; import 'enqueue.dart';
import 'js_backend/native_data.dart';
import 'js_emitter/sorter.dart'; import 'js_emitter/sorter.dart';
import 'universe/world_builder.dart';
import 'world.dart'; import 'world.dart';
/// Strategy pattern that defines the element model used in type inference /// Strategy pattern that defines the element model used in type inference
@ -19,21 +21,13 @@ abstract class BackendStrategy {
/// The [Sorter] used for sorting elements in the generated code. /// The [Sorter] used for sorting elements in the generated code.
Sorter get sorter; Sorter get sorter;
}
/// Creates the [CodegenWorldBuilder] used by the codegen enqueuer.
/// Strategy for using the [Element] model from the resolver as the backend CodegenWorldBuilder createCodegenWorldBuilder(
/// model. NativeBasicData nativeBasicData,
class ElementBackendStrategy implements BackendStrategy { ClosedWorld closedWorld,
final Compiler _compiler; SelectorConstraintsStrategy selectorConstraintsStrategy);
ElementBackendStrategy(this._compiler); /// Creates the [WorkItemBuilder] used by the codegen enqueuer.
WorkItemBuilder createCodegenWorkItemBuilder(ClosedWorld closedWorld);
ClosedWorldRefiner createClosedWorldRefiner(ClosedWorldImpl closedWorld) =>
closedWorld;
Sorter get sorter => const ElementSorter();
void convertClosures(ClosedWorldRefiner closedWorldRefiner) {
_compiler.closureToClassMapper.createClosureClasses(closedWorldRefiner);
}
} }

View file

@ -4,23 +4,15 @@
library dart2js.common.codegen; library dart2js.common.codegen;
import '../common.dart';
import '../elements/elements.dart' import '../elements/elements.dart'
show show AsyncMarker, ClassElement, LocalFunctionElement, MemberElement;
AsyncMarker,
ClassElement,
LocalFunctionElement,
MemberElement,
ResolvedAst;
import '../elements/entities.dart'; import '../elements/entities.dart';
import '../elements/types.dart' show DartType, InterfaceType; import '../elements/types.dart' show DartType, InterfaceType;
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../universe/use.dart' show ConstantUse, DynamicUse, StaticUse, TypeUse; import '../universe/use.dart' show ConstantUse, DynamicUse, StaticUse, TypeUse;
import '../universe/world_impact.dart' import '../universe/world_impact.dart'
show WorldImpact, WorldImpactBuilderImpl, WorldImpactVisitor; show WorldImpact, WorldImpactBuilderImpl, WorldImpactVisitor;
import '../util/enumset.dart'; import '../util/enumset.dart';
import '../util/util.dart' show Pair, Setlet; import '../util/util.dart' show Pair, Setlet;
import '../world.dart' show ClosedWorld;
import 'work.dart' show WorkItem; import 'work.dart' show WorkItem;
class CodegenImpact extends WorldImpact { class CodegenImpact extends WorldImpact {
@ -181,32 +173,6 @@ class CodegenRegistry {
} }
/// [WorkItem] used exclusively by the [CodegenEnqueuer]. /// [WorkItem] used exclusively by the [CodegenEnqueuer].
class CodegenWorkItem extends WorkItem { abstract class CodegenWorkItem extends WorkItem {
CodegenRegistry registry; CodegenRegistry get registry;
final ResolvedAst resolvedAst;
final JavaScriptBackend _backend;
final ClosedWorld _closedWorld;
factory CodegenWorkItem(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(invariant(element, element.hasResolvedAst,
message: "$element has no resolved ast."));
ResolvedAst resolvedAst = element.resolvedAst;
return new CodegenWorkItem.internal(resolvedAst, backend, closedWorld);
}
CodegenWorkItem.internal(this.resolvedAst, this._backend, this._closedWorld);
MemberElement get element => resolvedAst.element;
WorldImpact run() {
registry = new CodegenRegistry(element);
return _backend.codegen(this, _closedWorld);
}
String toString() => 'CodegenWorkItem(${resolvedAst.element})';
} }

View file

@ -40,6 +40,7 @@ import 'frontend_strategy.dart';
import 'id_generator.dart'; import 'id_generator.dart';
import 'io/source_information.dart' show SourceInformation; import 'io/source_information.dart' show SourceInformation;
import 'js_backend/backend.dart' show JavaScriptBackend; import 'js_backend/backend.dart' show JavaScriptBackend;
import 'js_backend/element_strategy.dart' show ElementBackendStrategy;
import 'kernel/kernel_strategy.dart'; import 'kernel/kernel_strategy.dart';
import 'library_loader.dart' import 'library_loader.dart'
show show

View file

@ -5,6 +5,7 @@
library entities; library entities;
import '../common.dart'; import '../common.dart';
import '../universe/call_structure.dart' show CallStructure;
/// Abstract interface for entities. /// Abstract interface for entities.
/// ///
@ -183,4 +184,11 @@ class ParameterStructure {
/// The number of optional parameters (positional or named). /// The number of optional parameters (positional or named).
int get optionalParameters => int get optionalParameters =>
positionalParameters - requiredParameters + namedParameters.length; positionalParameters - requiredParameters + namedParameters.length;
/// Returns the [CallStructure] corresponding to a call site passing all
/// parameters both required and optional.
CallStructure get callStructure {
return new CallStructure(
positionalParameters + namedParameters.length, namedParameters);
}
} }

View file

@ -893,9 +893,9 @@ class JavaScriptBackend {
task, task,
compiler.options, compiler.options,
const TreeShakingEnqueuerStrategy(), const TreeShakingEnqueuerStrategy(),
new CodegenWorldBuilderImpl( compiler.backendStrategy.createCodegenWorldBuilder(
nativeBasicData, closedWorld, constants, const TypeMaskStrategy()), nativeBasicData, closedWorld, const TypeMaskStrategy()),
new CodegenWorkItemBuilder(this, closedWorld, compiler.options), compiler.backendStrategy.createCodegenWorkItemBuilder(closedWorld),
new CodegenEnqueuerListener( new CodegenEnqueuerListener(
compiler.elementEnvironment, compiler.elementEnvironment,
commonElements, commonElements,

View file

@ -105,13 +105,14 @@ class CodegenEnqueuerListener extends EnqueuerListener {
} }
/// Computes the [WorldImpact] of calling [mainMethod] as the entry point. /// Computes the [WorldImpact] of calling [mainMethod] as the entry point.
WorldImpact _computeMainImpact(MethodElement mainMethod) { WorldImpact _computeMainImpact(FunctionEntity mainMethod) {
WorldImpactBuilderImpl mainImpact = new WorldImpactBuilderImpl(); WorldImpactBuilderImpl mainImpact = new WorldImpactBuilderImpl();
if (mainMethod.parameters.isNotEmpty) { CallStructure callStructure = mainMethod.parameterStructure.callStructure;
if (callStructure.argumentCount > 0) {
_impacts.mainWithArguments _impacts.mainWithArguments
.registerImpact(mainImpact, _elementEnvironment); .registerImpact(mainImpact, _elementEnvironment);
mainImpact.registerStaticUse( mainImpact.registerStaticUse(
new StaticUse.staticInvoke(mainMethod, CallStructure.TWO_ARGS)); new StaticUse.staticInvoke(mainMethod, callStructure));
// If the main method takes arguments, this compilation could be the // If the main method takes arguments, this compilation could be the
// target of Isolate.spawnUri. Strictly speaking, that can happen also if // target of Isolate.spawnUri. Strictly speaking, that can happen also if
// main takes no arguments, but in this case the spawned isolate can't // main takes no arguments, but in this case the spawned isolate can't

View file

@ -0,0 +1,117 @@
// 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 '../common.dart';
import '../common/codegen.dart';
import '../common/work.dart';
import '../compiler.dart';
import '../elements/elements.dart';
import '../enqueue.dart';
import '../js_backend/backend.dart';
import '../js_backend/native_data.dart';
import '../js_emitter/sorter.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 implements BackendStrategy {
final Compiler _compiler;
ElementBackendStrategy(this._compiler);
ClosedWorldRefiner createClosedWorldRefiner(ClosedWorldImpl closedWorld) =>
closedWorld;
Sorter get sorter => const ElementSorter();
void convertClosures(ClosedWorldRefiner closedWorldRefiner) {
_compiler.closureToClassMapper.createClosureClasses(closedWorldRefiner);
}
@override
CodegenWorldBuilder createCodegenWorldBuilder(
NativeBasicData nativeBasicData,
ClosedWorld closedWorld,
SelectorConstraintsStrategy selectorConstraintsStrategy) {
return new ElementCodegenWorldBuilderImpl(
_compiler.elementEnvironment,
nativeBasicData,
closedWorld,
_compiler.backend.constants,
selectorConstraintsStrategy);
}
@override
WorkItemBuilder createCodegenWorkItemBuilder(ClosedWorld closedWorld) {
return new ElementCodegenWorkItemBuilder(
_compiler.backend, closedWorld, _compiler.options);
}
}
/// 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(invariant(element, element.isDeclaration));
// Don't generate code for foreign elements.
if (_backend.isForeign(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(invariant(element, element.hasResolvedAst,
message: "$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(element);
return _backend.codegen(this, _closedWorld);
}
String toString() => 'CodegenWorkItem(${resolvedAst.element})';
}

View file

@ -6,17 +6,14 @@ library dart2js.js.enqueue;
import 'dart:collection' show Queue; import 'dart:collection' show Queue;
import '../common/codegen.dart' show CodegenWorkItem;
import '../common/tasks.dart' show CompilerTask; import '../common/tasks.dart' show CompilerTask;
import '../common/work.dart' show WorkItem; import '../common/work.dart' show WorkItem;
import '../common.dart'; import '../common.dart';
import '../common_elements.dart' show ElementEnvironment; import '../common_elements.dart' show ElementEnvironment;
import '../elements/resolution_types.dart' import '../elements/resolution_types.dart'
show ResolutionDartType, ResolutionInterfaceType; show ResolutionDartType, ResolutionInterfaceType;
import '../elements/elements.dart' show MemberElement;
import '../elements/entities.dart'; import '../elements/entities.dart';
import '../enqueue.dart'; import '../enqueue.dart';
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../options.dart'; import '../options.dart';
import '../universe/world_builder.dart'; import '../universe/world_builder.dart';
import '../universe/use.dart' import '../universe/use.dart'
@ -31,7 +28,6 @@ import '../universe/world_impact.dart'
show ImpactUseCase, WorldImpact, WorldImpactVisitor; show ImpactUseCase, WorldImpact, WorldImpactVisitor;
import '../util/enumset.dart'; import '../util/enumset.dart';
import '../util/util.dart' show Setlet; import '../util/util.dart' show Setlet;
import '../world.dart' show ClosedWorld;
/// [Enqueuer] which is specific to code generation. /// [Enqueuer] which is specific to code generation.
class CodegenEnqueuer extends EnqueuerImpl { class CodegenEnqueuer extends EnqueuerImpl {
@ -268,31 +264,3 @@ class CodegenEnqueuer extends EnqueuerImpl {
@override @override
Iterable<ClassEntity> get processedClasses => _worldBuilder.processedClasses; Iterable<ClassEntity> get processedClasses => _worldBuilder.processedClasses;
} }
/// Builder that creates the work item necessary for the code generation of a
/// [MemberElement].
class CodegenWorkItemBuilder extends WorkItemBuilder {
final JavaScriptBackend _backend;
final ClosedWorld _closedWorld;
final CompilerOptions _options;
CodegenWorkItemBuilder(this._backend, this._closedWorld, this._options);
@override
WorkItem createWorkItem(MemberElement element) {
assert(invariant(element, element.isDeclaration));
// Don't generate code for foreign elements.
if (_backend.isForeign(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 CodegenWorkItem(_backend, _closedWorld, element);
}
}

View file

@ -153,11 +153,7 @@ class ResolutionEnqueuerListener extends EnqueuerListener {
/// Computes the [WorldImpact] of calling [mainMethod] as the entry point. /// Computes the [WorldImpact] of calling [mainMethod] as the entry point.
WorldImpact _computeMainImpact(FunctionEntity mainMethod) { WorldImpact _computeMainImpact(FunctionEntity mainMethod) {
WorldImpactBuilderImpl mainImpact = new WorldImpactBuilderImpl(); WorldImpactBuilderImpl mainImpact = new WorldImpactBuilderImpl();
ParameterStructure parameterStructure = mainMethod.parameterStructure; CallStructure callStructure = mainMethod.parameterStructure.callStructure;
CallStructure callStructure = new CallStructure(
parameterStructure.positionalParameters +
parameterStructure.namedParameters.length,
parameterStructure.namedParameters);
if (callStructure.argumentCount > 0) { if (callStructure.argumentCount > 0) {
_impacts.mainWithArguments _impacts.mainWithArguments
.registerImpact(mainImpact, _elementEnvironment); .registerImpact(mainImpact, _elementEnvironment);

View file

@ -203,7 +203,7 @@ class Collector {
.toList()); .toList());
// Compute needed classes. // Compute needed classes.
Set<ClassElement> instantiatedClasses = Set<ClassEntity> instantiatedClasses =
// TODO(johnniwinther): This should be accessed from a codegen closed // TODO(johnniwinther): This should be accessed from a codegen closed
// world. // world.
_worldBuilder.directlyInstantiatedClasses _worldBuilder.directlyInstantiatedClasses
@ -219,7 +219,7 @@ class Collector {
} }
} }
void addClassesWithSuperclasses(Iterable<ClassElement> classes) { void addClassesWithSuperclasses(Iterable<ClassEntity> classes) {
for (ClassElement cls in classes) { for (ClassElement cls in classes) {
addClassWithSuperclasses(cls); addClassWithSuperclasses(cls);
} }

View file

@ -7,7 +7,7 @@ library dart2js.js_emitter.type_test_registry;
import '../common.dart'; import '../common.dart';
import '../common_elements.dart'; import '../common_elements.dart';
import '../elements/elements.dart' import '../elements/elements.dart'
show ClassElement, Element, ElementKind, MemberElement, MethodElement; show ClassElement, ElementKind, MemberElement, MethodElement;
import '../elements/entities.dart'; import '../elements/entities.dart';
import '../elements/resolution_types.dart' import '../elements/resolution_types.dart'
show show
@ -138,7 +138,7 @@ class TypeTestRegistry {
} }
} }
bool canTearOff(Element function) { bool canTearOff(MemberElement function) {
if (!function.isFunction || if (!function.isFunction ||
function.isConstructor || function.isConstructor ||
function.isAccessor) { function.isAccessor) {

View file

@ -9,6 +9,7 @@ import '../backend_strategy.dart';
import '../common.dart'; import '../common.dart';
import '../common_elements.dart'; import '../common_elements.dart';
import '../common/backend_api.dart'; import '../common/backend_api.dart';
import '../common/codegen.dart' show CodegenWorkItem;
import '../common/resolution.dart'; import '../common/resolution.dart';
import '../common/tasks.dart'; import '../common/tasks.dart';
import '../common/work.dart'; import '../common/work.dart';
@ -256,4 +257,25 @@ class KernelBackendStrategy implements BackendStrategy {
// elements. // elements.
throw new UnimplementedError('KernelBackendStrategy.createClosureClasses'); throw new UnimplementedError('KernelBackendStrategy.createClosureClasses');
} }
@override
WorkItemBuilder createCodegenWorkItemBuilder(ClosedWorld closedWorld) {
return new KernelCodegenWorkItemBuilder();
}
@override
CodegenWorldBuilder createCodegenWorldBuilder(
NativeBasicData nativeBasicData,
ClosedWorld closedWorld,
SelectorConstraintsStrategy selectorConstraintsStrategy) {
return new KernelCodegenWorldBuilder(
null, nativeBasicData, closedWorld, selectorConstraintsStrategy);
}
}
class KernelCodegenWorkItemBuilder implements WorkItemBuilder {
@override
CodegenWorkItem createWorkItem(MemberEntity entity) {
throw new UnimplementedError('KernelCodegenWorkItemBuilder.createWorkItem');
}
} }

View file

@ -246,7 +246,7 @@ class NativeCodegenEnqueuer extends NativeEnqueuerBase {
this._nativeData) this._nativeData)
: super(options, elementEnvironment, commonElements, dartTypes); : super(options, elementEnvironment, commonElements, dartTypes);
WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { WorldImpact processNativeClasses(Iterable<LibraryEntity> libraries) {
WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
_unusedClasses.addAll(_resolutionEnqueuer._nativeClasses); _unusedClasses.addAll(_resolutionEnqueuer._nativeClasses);

View file

@ -8,7 +8,7 @@ import 'package:js_runtime/shared/embedded_names.dart';
import '../closure.dart'; import '../closure.dart';
import '../common.dart'; import '../common.dart';
import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; import '../common/codegen.dart' show CodegenRegistry;
import '../common/names.dart' show Identifiers, Selectors; import '../common/names.dart' show Identifiers, Selectors;
import '../common/tasks.dart' show CompilerTask; import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart'; import '../compiler.dart';
@ -27,6 +27,7 @@ import '../elements/types.dart';
import '../io/source_information.dart'; import '../io/source_information.dart';
import '../js/js.dart' as js; import '../js/js.dart' as js;
import '../js_backend/backend.dart' show JavaScriptBackend; import '../js_backend/backend.dart' show JavaScriptBackend;
import '../js_backend/element_strategy.dart' show ElementCodegenWorkItem;
import '../js_backend/runtime_types.dart'; import '../js_backend/runtime_types.dart';
import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
import '../native/native.dart' as native; import '../native/native.dart' as native;
@ -65,7 +66,7 @@ class SsaBuilderTask extends CompilerTask {
DiagnosticReporter get reporter => backend.reporter; DiagnosticReporter get reporter => backend.reporter;
HGraph build(CodegenWorkItem work, ClosedWorld closedWorld) { HGraph build(ElementCodegenWorkItem work, ClosedWorld closedWorld) {
return measure(() { return measure(() {
MemberElement element = work.element.implementation; MemberElement element = work.element.implementation;
return reporter.withCurrentElement(element, () { return reporter.withCurrentElement(element, () {

View file

@ -6,7 +6,7 @@ import 'package:kernel/ast.dart' as ir;
import '../closure.dart'; import '../closure.dart';
import '../common.dart'; import '../common.dart';
import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; import '../common/codegen.dart' show CodegenRegistry;
import '../common/names.dart'; import '../common/names.dart';
import '../common/tasks.dart' show CompilerTask; import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart'; import '../compiler.dart';
@ -22,6 +22,7 @@ import '../elements/resolution_types.dart';
import '../io/source_information.dart'; import '../io/source_information.dart';
import '../js/js.dart' as js; import '../js/js.dart' as js;
import '../js_backend/backend.dart' show JavaScriptBackend; import '../js_backend/backend.dart' show JavaScriptBackend;
import '../js_backend/element_strategy.dart' show ElementCodegenWorkItem;
import '../kernel/kernel.dart'; import '../kernel/kernel.dart';
import '../native/native.dart' as native; import '../native/native.dart' as native;
import '../resolution/tree_elements.dart'; import '../resolution/tree_elements.dart';
@ -53,7 +54,7 @@ class SsaKernelBuilderTask extends CompilerTask {
: backend = backend, : backend = backend,
super(backend.compiler.measurer); super(backend.compiler.measurer);
HGraph build(CodegenWorkItem work, ClosedWorld closedWorld) { HGraph build(ElementCodegenWorkItem work, ClosedWorld closedWorld) {
return measure(() { return measure(() {
MemberElement element = work.element.implementation; MemberElement element = work.element.implementation;
Kernel kernel = backend.kernelTask.kernel; Kernel kernel = backend.kernelTask.kernel;

View file

@ -19,6 +19,7 @@ import '../js/js.dart' as js;
import '../js_backend/interceptor_data.dart'; import '../js_backend/interceptor_data.dart';
import '../js_backend/backend.dart'; import '../js_backend/backend.dart';
import '../js_backend/checked_mode_helpers.dart'; import '../js_backend/checked_mode_helpers.dart';
import '../js_backend/element_strategy.dart' show ElementCodegenWorkItem;
import '../js_backend/native_data.dart'; import '../js_backend/native_data.dart';
import '../js_backend/namer.dart'; import '../js_backend/namer.dart';
import '../js_backend/runtime_types.dart'; import '../js_backend/runtime_types.dart';
@ -63,7 +64,7 @@ class SsaCodeGeneratorTask extends CompilerTask {
} }
js.Expression generateCode( js.Expression generateCode(
CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { ElementCodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) {
if (work.element.isField) { if (work.element.isField) {
return generateLazyInitializer(work, graph, closedWorld); return generateLazyInitializer(work, graph, closedWorld);
} else { } else {
@ -72,7 +73,7 @@ class SsaCodeGeneratorTask extends CompilerTask {
} }
js.Expression generateLazyInitializer( js.Expression generateLazyInitializer(
CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { ElementCodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) {
return measure(() { return measure(() {
backend.tracer.traceGraph("codegen", graph); backend.tracer.traceGraph("codegen", graph);
SourceInformation sourceInformation = sourceInformationFactory SourceInformation sourceInformation = sourceInformationFactory
@ -97,7 +98,7 @@ class SsaCodeGeneratorTask extends CompilerTask {
} }
js.Expression generateMethod( js.Expression generateMethod(
CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) { ElementCodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) {
return measure(() { return measure(() {
MethodElement element = work.element; MethodElement element = work.element;
if (element.asyncMarker != AsyncMarker.SYNC) { if (element.asyncMarker != AsyncMarker.SYNC) {

View file

@ -4,12 +4,12 @@
library ssa; library ssa;
import '../common/codegen.dart' show CodegenWorkItem;
import '../common/tasks.dart' show CompilerTask; import '../common/tasks.dart' show CompilerTask;
import '../elements/elements.dart' show Element, FunctionElement; import '../elements/elements.dart' show Element, FunctionElement;
import '../io/source_information.dart'; import '../io/source_information.dart';
import '../js/js.dart' as js; import '../js/js.dart' as js;
import '../js_backend/backend.dart' show JavaScriptBackend, FunctionCompiler; import '../js_backend/backend.dart' show JavaScriptBackend, FunctionCompiler;
import '../js_backend/element_strategy.dart' show ElementCodegenWorkItem;
import '../world.dart' show ClosedWorld; import '../world.dart' show ClosedWorld;
import 'builder.dart'; import 'builder.dart';
@ -37,7 +37,7 @@ class SsaFunctionCompiler implements FunctionCompiler {
/// Generates JavaScript code for `work.element`. /// Generates JavaScript code for `work.element`.
/// Using the ssa builder, optimizer and codegenerator. /// Using the ssa builder, optimizer and codegenerator.
js.Fun compile(CodegenWorkItem work, ClosedWorld closedWorld) { js.Fun compile(ElementCodegenWorkItem work, ClosedWorld closedWorld) {
HGraph graph = useKernel HGraph graph = useKernel
? builderKernel.build(work, closedWorld) ? builderKernel.build(work, closedWorld)
: builder.build(work, closedWorld); : builder.build(work, closedWorld);

View file

@ -28,9 +28,9 @@ abstract class CodegenWorldBuilder implements WorldBuilder {
f(String name, Map<Selector, SelectorConstraints> selectors)); f(String name, Map<Selector, SelectorConstraints> selectors));
/// Returns `true` if [member] is invoked as a setter. /// Returns `true` if [member] is invoked as a setter.
bool hasInvokedSetter(Element member, ClosedWorld world); bool hasInvokedSetter(MemberEntity member, ClosedWorld world);
bool hasInvokedGetter(Element member, ClosedWorld world); bool hasInvokedGetter(MemberEntity member, ClosedWorld world);
Map<Selector, SelectorConstraints> invocationsByName(String name); Map<Selector, SelectorConstraints> invocationsByName(String name);
@ -50,10 +50,10 @@ abstract class CodegenWorldBuilder implements WorldBuilder {
Iterable<FunctionEntity> get closurizedMembers; Iterable<FunctionEntity> get closurizedMembers;
} }
class CodegenWorldBuilderImpl implements CodegenWorldBuilder { abstract class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
final NativeBasicData _nativeData; final ElementEnvironment _elementEnvironment;
final NativeBasicData _nativeBasicData;
final ClosedWorld _world; final ClosedWorld _world;
final JavaScriptConstantCompiler _constants;
/// The set of all directly instantiated classes, that is, classes with a /// The set of all directly instantiated classes, that is, classes with a
/// generative constructor that has been called directly and not only through /// generative constructor that has been called directly and not only through
@ -62,8 +62,7 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
/// Invariant: Elements are declaration elements. /// Invariant: Elements are declaration elements.
// TODO(johnniwinther): [_directlyInstantiatedClasses] and // TODO(johnniwinther): [_directlyInstantiatedClasses] and
// [_instantiatedTypes] sets should be merged. // [_instantiatedTypes] sets should be merged.
final Set<ClassElement> _directlyInstantiatedClasses = final Set<ClassEntity> _directlyInstantiatedClasses = new Set<ClassEntity>();
new Set<ClassElement>();
/// The set of all directly instantiated types, that is, the types of the /// The set of all directly instantiated types, that is, the types of the
/// directly instantiated classes. /// directly instantiated classes.
@ -72,12 +71,12 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
final Set<InterfaceType> _instantiatedTypes = new Set<InterfaceType>(); final Set<InterfaceType> _instantiatedTypes = new Set<InterfaceType>();
/// Classes implemented by directly instantiated classes. /// Classes implemented by directly instantiated classes.
final Set<ClassElement> _implementedClasses = new Set<ClassElement>(); final Set<ClassEntity> _implementedClasses = new Set<ClassEntity>();
/// The set of all referenced static fields. /// The set of all referenced static fields.
/// ///
/// Invariant: Elements are declaration elements. /// Invariant: Elements are declaration elements.
final Set<FieldElement> allReferencedStaticFields = new Set<FieldElement>(); final Set<FieldEntity> allReferencedStaticFields = new Set<FieldEntity>();
/** /**
* Documentation wanted -- johnniwinther * Documentation wanted -- johnniwinther
@ -95,8 +94,8 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
final Map<String, Map<Selector, SelectorConstraints>> _invokedSetters = final Map<String, Map<Selector, SelectorConstraints>> _invokedSetters =
<String, Map<Selector, SelectorConstraints>>{}; <String, Map<Selector, SelectorConstraints>>{};
final Map<ClassElement, _ClassUsage> _processedClasses = final Map<ClassEntity, _ClassUsage> _processedClasses =
<ClassElement, _ClassUsage>{}; <ClassEntity, _ClassUsage>{};
/// Map of registered usage of static members of live classes. /// Map of registered usage of static members of live classes.
final Map<Entity, _StaticMemberUsage> _staticMemberUsage = final Map<Entity, _StaticMemberUsage> _staticMemberUsage =
@ -116,7 +115,7 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
final Map<String, Set<_MemberUsage>> _instanceFunctionsByName = final Map<String, Set<_MemberUsage>> _instanceFunctionsByName =
<String, Set<_MemberUsage>>{}; <String, Set<_MemberUsage>>{};
final Set<ResolutionDartType> isChecks = new Set<ResolutionDartType>(); final Set<DartType> isChecks = new Set<DartType>();
final SelectorConstraintsStrategy selectorConstraintsStrategy; final SelectorConstraintsStrategy selectorConstraintsStrategy;
@ -125,34 +124,17 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
/// Set of methods in instantiated classes that are potentially closurized. /// Set of methods in instantiated classes that are potentially closurized.
final Set<FunctionEntity> closurizedMembers = new Set<FunctionEntity>(); final Set<FunctionEntity> closurizedMembers = new Set<FunctionEntity>();
CodegenWorldBuilderImpl(this._nativeData, this._world, this._constants, CodegenWorldBuilderImpl(this._elementEnvironment, this._nativeBasicData,
this.selectorConstraintsStrategy); this._world, this.selectorConstraintsStrategy);
/// Calls [f] with every instance field, together with its declarer, in an Iterable<ClassEntity> get processedClasses => _processedClasses.keys
/// instance of [cls].
void forEachInstanceField(
ClassElement cls, void f(ClassEntity declarer, FieldEntity field)) {
cls.implementation
.forEachInstanceField(f, includeSuperAndInjectedMembers: true);
}
@override
void forEachParameter(
MethodElement function, void f(DartType type, String name)) {
FunctionSignature parameters = function.functionSignature;
parameters.forEachParameter((ParameterElement parameter) {
f(parameter.type, parameter.name);
});
}
Iterable<ClassElement> get processedClasses => _processedClasses.keys
.where((cls) => _processedClasses[cls].isInstantiated); .where((cls) => _processedClasses[cls].isInstantiated);
/// All directly instantiated classes, that is, classes with a generative /// All directly instantiated classes, that is, classes with a generative
/// constructor that has been called directly and not only through a /// constructor that has been called directly and not only through a
/// super-call. /// super-call.
// TODO(johnniwinther): Improve semantic precision. // TODO(johnniwinther): Improve semantic precision.
Iterable<ClassElement> get directlyInstantiatedClasses { Iterable<ClassEntity> get directlyInstantiatedClasses {
return _directlyInstantiatedClasses; return _directlyInstantiatedClasses;
} }
@ -170,10 +152,10 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
// subclass and through subtype instantiated types/classes. // subclass and through subtype instantiated types/classes.
// TODO(johnniwinther): Support unknown type arguments for generic types. // TODO(johnniwinther): Support unknown type arguments for generic types.
void registerTypeInstantiation( void registerTypeInstantiation(
ResolutionInterfaceType type, ClassUsedCallback classUsed, InterfaceType type, ClassUsedCallback classUsed,
{bool byMirrors: false}) { {bool byMirrors: false}) {
ClassElement cls = type.element; ClassEntity cls = type.element;
bool isNative = _nativeData.isNativeClass(cls); bool isNative = _nativeBasicData.isNativeClass(cls);
_instantiatedTypes.add(type); _instantiatedTypes.add(type);
if (!cls.isAbstract if (!cls.isAbstract
// We can't use the closed-world assumption with native abstract // We can't use the closed-world assumption with native abstract
@ -195,7 +177,7 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
// include the type arguments. // include the type arguments.
if (_implementedClasses.add(cls)) { if (_implementedClasses.add(cls)) {
classUsed(cls, _getClassUsage(cls).implement()); classUsed(cls, _getClassUsage(cls).implement());
cls.allSupertypes.forEach((ResolutionInterfaceType supertype) { _elementEnvironment.forEachSupertype(cls, (InterfaceType supertype) {
if (_implementedClasses.add(supertype.element)) { if (_implementedClasses.add(supertype.element)) {
classUsed( classUsed(
supertype.element, _getClassUsage(supertype.element).implement()); supertype.element, _getClassUsage(supertype.element).implement());
@ -205,7 +187,7 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
} }
bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors, bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors,
MemberElement member, ClosedWorld world) { MemberEntity member, ClosedWorld world) {
if (selectors == null) return false; if (selectors == null) return false;
for (Selector selector in selectors.keys) { for (Selector selector in selectors.keys) {
if (selector.appliesUnnamed(member)) { if (selector.appliesUnnamed(member)) {
@ -218,16 +200,16 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
return false; return false;
} }
bool hasInvocation(Element member, ClosedWorld world) { bool hasInvocation(MemberEntity member, ClosedWorld world) {
return _hasMatchingSelector(_invokedNames[member.name], member, world); return _hasMatchingSelector(_invokedNames[member.name], member, world);
} }
bool hasInvokedGetter(Element member, ClosedWorld world) { bool hasInvokedGetter(MemberEntity member, ClosedWorld world) {
return _hasMatchingSelector(_invokedGetters[member.name], member, world) || return _hasMatchingSelector(_invokedGetters[member.name], member, world) ||
member.isFunction && methodsNeedingSuperGetter.contains(member); member.isFunction && methodsNeedingSuperGetter.contains(member);
} }
bool hasInvokedSetter(Element member, ClosedWorld world) { bool hasInvokedSetter(MemberEntity member, ClosedWorld world) {
return _hasMatchingSelector(_invokedSetters[member.name], member, world); return _hasMatchingSelector(_invokedSetters[member.name], member, world);
} }
@ -318,28 +300,23 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
_invokedSetters.forEach(f); _invokedSetters.forEach(f);
} }
void registerIsCheck(ResolutionDartType type) { void registerIsCheck(DartType type) {
type = type.unaliased; isChecks.add(type.unaliased);
// Even in checked mode, type annotations for return type and argument
// types do not imply type checks, so there should never be a check
// against the type variable of a typedef.
assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef);
isChecks.add(type);
} }
void _registerStaticUse(StaticUse staticUse) { void _registerStaticUse(StaticUse staticUse) {
Element element = staticUse.element; if (staticUse.element is FieldEntity) {
if (Elements.isStaticOrTopLevel(element) && element.isField) { FieldEntity field = staticUse.element;
allReferencedStaticFields.add(element); if (field.isTopLevel || field.isStatic) {
allReferencedStaticFields.add(field);
}
} }
switch (staticUse.kind) { switch (staticUse.kind) {
case StaticUseKind.STATIC_TEAR_OFF: case StaticUseKind.STATIC_TEAR_OFF:
MethodElement method = element; staticFunctionsNeedingGetter.add(staticUse.element);
staticFunctionsNeedingGetter.add(method);
break; break;
case StaticUseKind.SUPER_TEAR_OFF: case StaticUseKind.SUPER_TEAR_OFF:
MethodElement method = element; methodsNeedingSuperGetter.add(staticUse.element);
methodsNeedingSuperGetter.add(method);
break; break;
case StaticUseKind.SUPER_FIELD_SET: case StaticUseKind.SUPER_FIELD_SET:
case StaticUseKind.FIELD_SET: case StaticUseKind.FIELD_SET:
@ -357,12 +334,12 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
} }
void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed) { void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed) {
Element element = staticUse.element; Entity element = staticUse.element;
assert(invariant(element, element.isDeclaration,
message: "Element ${element} is not the declaration."));
_registerStaticUse(staticUse); _registerStaticUse(staticUse);
_StaticMemberUsage usage = _staticMemberUsage.putIfAbsent(element, () { _StaticMemberUsage usage = _staticMemberUsage.putIfAbsent(element, () {
if ((element.isStatic || element.isTopLevel) && element.isFunction) { if (element is MemberEntity &&
(element.isStatic || element.isTopLevel) &&
element.isFunction) {
return new _StaticFunctionUsage(element); return new _StaticFunctionUsage(element);
} else { } else {
return new _GeneralStaticMemberUsage(element); return new _GeneralStaticMemberUsage(element);
@ -413,22 +390,25 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
closurizedMembers.add(element); closurizedMembers.add(element);
} }
void processClassMembers(ClassElement cls, MemberUsedCallback memberUsed) { void processClassMembers(ClassEntity cls, MemberUsedCallback memberUsed) {
cls.implementation.forEachMember((_, MemberElement member) { _elementEnvironment.forEachClassMember(cls,
assert(invariant(member, member.isDeclaration)); (ClassEntity cls, MemberEntity member) {
if (!member.isInstanceMember) return; _processInstantiatedClassMember(cls, member, memberUsed);
if (member.isMalformed) return;
_getMemberUsage(member, memberUsed);
}); });
} }
void _processInstantiatedClassMember(
ClassEntity cls, MemberEntity member, MemberUsedCallback memberUsed) {
if (!member.isInstanceMember) return;
_getMemberUsage(member, memberUsed);
}
_MemberUsage _getMemberUsage( _MemberUsage _getMemberUsage(
MemberElement member, MemberUsedCallback memberUsed) { MemberEntity member, MemberUsedCallback memberUsed) {
assert(invariant(member, member.isDeclaration));
return _instanceMemberUsage.putIfAbsent(member, () { return _instanceMemberUsage.putIfAbsent(member, () {
String memberName = member.name; String memberName = member.name;
ClassElement cls = member.enclosingClass; ClassEntity cls = member.enclosingClass;
bool isNative = _nativeData.isNativeClass(cls); bool isNative = _nativeBasicData.isNativeClass(cls);
_MemberUsage usage = new _MemberUsage(member, isNative: isNative); _MemberUsage usage = new _MemberUsage(member, isNative: isNative);
EnumSet<MemberUse> useSet = new EnumSet<MemberUse>(); EnumSet<MemberUse> useSet = new EnumSet<MemberUse>();
useSet.addAll(usage.appliedUse); useSet.addAll(usage.appliedUse);
@ -477,16 +457,15 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
} }
/// Return the canonical [_ClassUsage] for [cls]. /// Return the canonical [_ClassUsage] for [cls].
_ClassUsage _getClassUsage(ClassElement cls) { _ClassUsage _getClassUsage(ClassEntity cls) {
return _processedClasses.putIfAbsent(cls, () => new _ClassUsage(cls)); return _processedClasses.putIfAbsent(cls, () => new _ClassUsage(cls));
} }
void _processInstantiatedClass( void _processInstantiatedClass(ClassEntity cls, ClassUsedCallback classUsed) {
ClassElement cls, ClassUsedCallback classUsed) {
// Registers [superclass] as instantiated. Returns `true` if it wasn't // Registers [superclass] as instantiated. Returns `true` if it wasn't
// already instantiated and we therefore have to process its superclass as // already instantiated and we therefore have to process its superclass as
// well. // well.
bool processClass(ClassElement superclass) { bool processClass(ClassEntity superclass) {
_ClassUsage usage = _getClassUsage(superclass); _ClassUsage usage = _getClassUsage(superclass);
if (!usage.isInstantiated) { if (!usage.isInstantiated) {
classUsed(usage.cls, usage.instantiate()); classUsed(usage.cls, usage.instantiate());
@ -496,16 +475,108 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
} }
while (cls != null && processClass(cls)) { while (cls != null && processClass(cls)) {
cls = cls.superclass; cls = _elementEnvironment.getSuperClass(cls);
} }
} }
bool registerConstantUse(ConstantUse use);
}
class ElementCodegenWorldBuilderImpl extends CodegenWorldBuilderImpl {
final JavaScriptConstantCompiler _constants;
ElementCodegenWorldBuilderImpl(
ElementEnvironment elementEnvironment,
NativeBasicData nativeBasicData,
ClosedWorld world,
this._constants,
SelectorConstraintsStrategy selectorConstraintsStrategy)
: super(elementEnvironment, nativeBasicData, world,
selectorConstraintsStrategy);
/// Calls [f] with every instance field, together with its declarer, in an
/// instance of [cls].
void forEachInstanceField(
ClassElement cls, void f(ClassEntity declarer, FieldEntity field)) {
cls.implementation
.forEachInstanceField(f, includeSuperAndInjectedMembers: true);
}
@override
void forEachParameter(
MethodElement function, void f(DartType type, String name)) {
FunctionSignature parameters = function.functionSignature;
parameters.forEachParameter((ParameterElement parameter) {
f(parameter.type, parameter.name);
});
}
@override
void _processInstantiatedClassMember(
ClassEntity cls, MemberElement member, MemberUsedCallback memberUsed) {
assert(invariant(member, member.isDeclaration));
if (member.isMalformed) return;
super._processInstantiatedClassMember(cls, member, memberUsed);
}
@override
_MemberUsage _getMemberUsage(
MemberElement member, MemberUsedCallback memberUsed) {
assert(invariant(member, member.isDeclaration));
return super._getMemberUsage(member, memberUsed);
}
void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed) {
Element element = staticUse.element;
assert(invariant(element, element.isDeclaration,
message: "Element ${element} is not the declaration."));
super.registerStaticUse(staticUse, memberUsed);
}
/// Register the constant [use] with this world builder. Returns `true` if /// Register the constant [use] with this world builder. Returns `true` if
/// the constant use was new to the world. /// the constant use was new to the world.
@override
bool registerConstantUse(ConstantUse use) { bool registerConstantUse(ConstantUse use) {
if (use.kind == ConstantUseKind.DIRECT) { if (use.kind == ConstantUseKind.DIRECT) {
_constants.addCompileTimeConstantForEmission(use.value); _constants.addCompileTimeConstantForEmission(use.value);
} }
return _constantValues.add(use.value); return _constantValues.add(use.value);
} }
void registerIsCheck(ResolutionDartType type) {
// Even in checked mode, type annotations for return type and argument
// types do not imply type checks, so there should never be a check
// against the type variable of a typedef.
assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef);
super.registerIsCheck(type);
}
}
class KernelCodegenWorldBuilder extends CodegenWorldBuilderImpl {
KernelCodegenWorldBuilder(
ElementEnvironment elementEnvironment,
NativeBasicData nativeBasicData,
ClosedWorld world,
SelectorConstraintsStrategy selectorConstraintsStrategy)
: super(elementEnvironment, nativeBasicData, world,
selectorConstraintsStrategy);
@override
bool registerConstantUse(ConstantUse use) {
throw new UnimplementedError(
'KernelCodegenWorldBuilder.registerConstantUse');
}
@override
void forEachParameter(
FunctionEntity function, void f(DartType type, String name)) {
throw new UnimplementedError('KernelCodegenWorldBuilder.forEachParameter');
}
@override
void forEachInstanceField(
ClassEntity cls, void f(ClassEntity declarer, FieldEntity field)) {
throw new UnimplementedError(
'KernelCodegenWorldBuilder.forEachInstanceField');
}
} }

View file

@ -13,6 +13,8 @@ import 'package:compiler/src/elements/elements.dart';
export 'package:compiler/src/elements/elements.dart'; export 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/js_backend/js_backend.dart' as js; import 'package:compiler/src/js_backend/js_backend.dart' as js;
import 'package:compiler/src/js_backend/element_strategy.dart'
show ElementCodegenWorkItem;
import 'package:compiler/src/commandline_options.dart'; import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/common/codegen.dart'; import 'package:compiler/src/common/codegen.dart';
@ -83,7 +85,7 @@ Future<String> compile(String code,
resolutionWork.run(); resolutionWork.run();
ClosedWorld closedWorld = compiler.closeResolution().closedWorld; ClosedWorld closedWorld = compiler.closeResolution().closedWorld;
CodegenWorkItem work = CodegenWorkItem work =
new CodegenWorkItem(compiler.backend, closedWorld, element); new ElementCodegenWorkItem(compiler.backend, closedWorld, element);
compiler.phase = Compiler.PHASE_COMPILING; compiler.phase = Compiler.PHASE_COMPILING;
work.run(); work.run();
js.JavaScriptBackend backend = compiler.backend; js.JavaScriptBackend backend = compiler.backend;

View file

@ -49,7 +49,8 @@ void testTypeRepresentations() {
env.compiler.enqueuer.createCodegenEnqueuer(closedWorld); env.compiler.enqueuer.createCodegenEnqueuer(closedWorld);
env.compiler.backend.onCodegenStart( env.compiler.backend.onCodegenStart(
closedWorld, closedWorld,
new CodegenWorldBuilderImpl( new ElementCodegenWorldBuilderImpl(
env.compiler.elementEnvironment,
env.compiler.backend.nativeBasicData, env.compiler.backend.nativeBasicData,
closedWorld, closedWorld,
env.compiler.backend.constants, env.compiler.backend.constants,