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;
import 'compiler.dart';
import 'enqueue.dart';
import 'js_backend/native_data.dart';
import 'js_emitter/sorter.dart';
import 'universe/world_builder.dart';
import 'world.dart';
/// 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.
Sorter get sorter;
}
/// 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);
}
/// Creates the [CodegenWorldBuilder] used by the codegen enqueuer.
CodegenWorldBuilder createCodegenWorldBuilder(
NativeBasicData nativeBasicData,
ClosedWorld closedWorld,
SelectorConstraintsStrategy selectorConstraintsStrategy);
/// Creates the [WorkItemBuilder] used by the codegen enqueuer.
WorkItemBuilder createCodegenWorkItemBuilder(ClosedWorld closedWorld);
}

View file

@ -4,23 +4,15 @@
library dart2js.common.codegen;
import '../common.dart';
import '../elements/elements.dart'
show
AsyncMarker,
ClassElement,
LocalFunctionElement,
MemberElement,
ResolvedAst;
show AsyncMarker, ClassElement, LocalFunctionElement, MemberElement;
import '../elements/entities.dart';
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/world_impact.dart'
show WorldImpact, WorldImpactBuilderImpl, WorldImpactVisitor;
import '../util/enumset.dart';
import '../util/util.dart' show Pair, Setlet;
import '../world.dart' show ClosedWorld;
import 'work.dart' show WorkItem;
class CodegenImpact extends WorldImpact {
@ -181,32 +173,6 @@ class CodegenRegistry {
}
/// [WorkItem] used exclusively by the [CodegenEnqueuer].
class CodegenWorkItem extends WorkItem {
CodegenRegistry 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})';
abstract class CodegenWorkItem extends WorkItem {
CodegenRegistry get registry;
}

View file

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

View file

@ -5,6 +5,7 @@
library entities;
import '../common.dart';
import '../universe/call_structure.dart' show CallStructure;
/// Abstract interface for entities.
///
@ -183,4 +184,11 @@ class ParameterStructure {
/// The number of optional parameters (positional or named).
int get optionalParameters =>
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,
compiler.options,
const TreeShakingEnqueuerStrategy(),
new CodegenWorldBuilderImpl(
nativeBasicData, closedWorld, constants, const TypeMaskStrategy()),
new CodegenWorkItemBuilder(this, closedWorld, compiler.options),
compiler.backendStrategy.createCodegenWorldBuilder(
nativeBasicData, closedWorld, const TypeMaskStrategy()),
compiler.backendStrategy.createCodegenWorkItemBuilder(closedWorld),
new CodegenEnqueuerListener(
compiler.elementEnvironment,
commonElements,

View file

@ -105,13 +105,14 @@ class CodegenEnqueuerListener extends EnqueuerListener {
}
/// Computes the [WorldImpact] of calling [mainMethod] as the entry point.
WorldImpact _computeMainImpact(MethodElement mainMethod) {
WorldImpact _computeMainImpact(FunctionEntity mainMethod) {
WorldImpactBuilderImpl mainImpact = new WorldImpactBuilderImpl();
if (mainMethod.parameters.isNotEmpty) {
CallStructure callStructure = mainMethod.parameterStructure.callStructure;
if (callStructure.argumentCount > 0) {
_impacts.mainWithArguments
.registerImpact(mainImpact, _elementEnvironment);
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
// target of Isolate.spawnUri. Strictly speaking, that can happen also if
// 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 '../common/codegen.dart' show CodegenWorkItem;
import '../common/tasks.dart' show CompilerTask;
import '../common/work.dart' show WorkItem;
import '../common.dart';
import '../common_elements.dart' show ElementEnvironment;
import '../elements/resolution_types.dart'
show ResolutionDartType, ResolutionInterfaceType;
import '../elements/elements.dart' show MemberElement;
import '../elements/entities.dart';
import '../enqueue.dart';
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../options.dart';
import '../universe/world_builder.dart';
import '../universe/use.dart'
@ -31,7 +28,6 @@ import '../universe/world_impact.dart'
show ImpactUseCase, WorldImpact, WorldImpactVisitor;
import '../util/enumset.dart';
import '../util/util.dart' show Setlet;
import '../world.dart' show ClosedWorld;
/// [Enqueuer] which is specific to code generation.
class CodegenEnqueuer extends EnqueuerImpl {
@ -268,31 +264,3 @@ class CodegenEnqueuer extends EnqueuerImpl {
@override
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.
WorldImpact _computeMainImpact(FunctionEntity mainMethod) {
WorldImpactBuilderImpl mainImpact = new WorldImpactBuilderImpl();
ParameterStructure parameterStructure = mainMethod.parameterStructure;
CallStructure callStructure = new CallStructure(
parameterStructure.positionalParameters +
parameterStructure.namedParameters.length,
parameterStructure.namedParameters);
CallStructure callStructure = mainMethod.parameterStructure.callStructure;
if (callStructure.argumentCount > 0) {
_impacts.mainWithArguments
.registerImpact(mainImpact, _elementEnvironment);

View file

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

View file

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

View file

@ -9,6 +9,7 @@ import '../backend_strategy.dart';
import '../common.dart';
import '../common_elements.dart';
import '../common/backend_api.dart';
import '../common/codegen.dart' show CodegenWorkItem;
import '../common/resolution.dart';
import '../common/tasks.dart';
import '../common/work.dart';
@ -256,4 +257,25 @@ class KernelBackendStrategy implements BackendStrategy {
// elements.
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)
: super(options, elementEnvironment, commonElements, dartTypes);
WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) {
WorldImpact processNativeClasses(Iterable<LibraryEntity> libraries) {
WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
_unusedClasses.addAll(_resolutionEnqueuer._nativeClasses);

View file

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

View file

@ -6,7 +6,7 @@ import 'package:kernel/ast.dart' as ir;
import '../closure.dart';
import '../common.dart';
import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
import '../common/codegen.dart' show CodegenRegistry;
import '../common/names.dart';
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart';
@ -22,6 +22,7 @@ import '../elements/resolution_types.dart';
import '../io/source_information.dart';
import '../js/js.dart' as js;
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../js_backend/element_strategy.dart' show ElementCodegenWorkItem;
import '../kernel/kernel.dart';
import '../native/native.dart' as native;
import '../resolution/tree_elements.dart';
@ -53,7 +54,7 @@ class SsaKernelBuilderTask extends CompilerTask {
: backend = backend,
super(backend.compiler.measurer);
HGraph build(CodegenWorkItem work, ClosedWorld closedWorld) {
HGraph build(ElementCodegenWorkItem work, ClosedWorld closedWorld) {
return measure(() {
MemberElement element = work.element.implementation;
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/backend.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/namer.dart';
import '../js_backend/runtime_types.dart';
@ -63,7 +64,7 @@ class SsaCodeGeneratorTask extends CompilerTask {
}
js.Expression generateCode(
CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) {
ElementCodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) {
if (work.element.isField) {
return generateLazyInitializer(work, graph, closedWorld);
} else {
@ -72,7 +73,7 @@ class SsaCodeGeneratorTask extends CompilerTask {
}
js.Expression generateLazyInitializer(
CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) {
ElementCodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) {
return measure(() {
backend.tracer.traceGraph("codegen", graph);
SourceInformation sourceInformation = sourceInformationFactory
@ -97,7 +98,7 @@ class SsaCodeGeneratorTask extends CompilerTask {
}
js.Expression generateMethod(
CodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) {
ElementCodegenWorkItem work, HGraph graph, ClosedWorld closedWorld) {
return measure(() {
MethodElement element = work.element;
if (element.asyncMarker != AsyncMarker.SYNC) {

View file

@ -4,12 +4,12 @@
library ssa;
import '../common/codegen.dart' show CodegenWorkItem;
import '../common/tasks.dart' show CompilerTask;
import '../elements/elements.dart' show Element, FunctionElement;
import '../io/source_information.dart';
import '../js/js.dart' as js;
import '../js_backend/backend.dart' show JavaScriptBackend, FunctionCompiler;
import '../js_backend/element_strategy.dart' show ElementCodegenWorkItem;
import '../world.dart' show ClosedWorld;
import 'builder.dart';
@ -37,7 +37,7 @@ class SsaFunctionCompiler implements FunctionCompiler {
/// Generates JavaScript code for `work.element`.
/// Using the ssa builder, optimizer and codegenerator.
js.Fun compile(CodegenWorkItem work, ClosedWorld closedWorld) {
js.Fun compile(ElementCodegenWorkItem work, ClosedWorld closedWorld) {
HGraph graph = useKernel
? builderKernel.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));
/// 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);
@ -50,10 +50,10 @@ abstract class CodegenWorldBuilder implements WorldBuilder {
Iterable<FunctionEntity> get closurizedMembers;
}
class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
final NativeBasicData _nativeData;
abstract class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
final ElementEnvironment _elementEnvironment;
final NativeBasicData _nativeBasicData;
final ClosedWorld _world;
final JavaScriptConstantCompiler _constants;
/// The set of all directly instantiated classes, that is, classes with a
/// generative constructor that has been called directly and not only through
@ -62,8 +62,7 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
/// Invariant: Elements are declaration elements.
// TODO(johnniwinther): [_directlyInstantiatedClasses] and
// [_instantiatedTypes] sets should be merged.
final Set<ClassElement> _directlyInstantiatedClasses =
new Set<ClassElement>();
final Set<ClassEntity> _directlyInstantiatedClasses = new Set<ClassEntity>();
/// The set of all directly instantiated types, that is, the types of the
/// directly instantiated classes.
@ -72,12 +71,12 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
final Set<InterfaceType> _instantiatedTypes = new Set<InterfaceType>();
/// 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.
///
/// Invariant: Elements are declaration elements.
final Set<FieldElement> allReferencedStaticFields = new Set<FieldElement>();
final Set<FieldEntity> allReferencedStaticFields = new Set<FieldEntity>();
/**
* Documentation wanted -- johnniwinther
@ -95,8 +94,8 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
final Map<String, Map<Selector, SelectorConstraints>> _invokedSetters =
<String, Map<Selector, SelectorConstraints>>{};
final Map<ClassElement, _ClassUsage> _processedClasses =
<ClassElement, _ClassUsage>{};
final Map<ClassEntity, _ClassUsage> _processedClasses =
<ClassEntity, _ClassUsage>{};
/// Map of registered usage of static members of live classes.
final Map<Entity, _StaticMemberUsage> _staticMemberUsage =
@ -116,7 +115,7 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
final Map<String, Set<_MemberUsage>> _instanceFunctionsByName =
<String, Set<_MemberUsage>>{};
final Set<ResolutionDartType> isChecks = new Set<ResolutionDartType>();
final Set<DartType> isChecks = new Set<DartType>();
final SelectorConstraintsStrategy selectorConstraintsStrategy;
@ -125,34 +124,17 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
/// Set of methods in instantiated classes that are potentially closurized.
final Set<FunctionEntity> closurizedMembers = new Set<FunctionEntity>();
CodegenWorldBuilderImpl(this._nativeData, this._world, this._constants,
this.selectorConstraintsStrategy);
CodegenWorldBuilderImpl(this._elementEnvironment, this._nativeBasicData,
this._world, this.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);
});
}
Iterable<ClassElement> get processedClasses => _processedClasses.keys
Iterable<ClassEntity> get processedClasses => _processedClasses.keys
.where((cls) => _processedClasses[cls].isInstantiated);
/// All directly instantiated classes, that is, classes with a generative
/// constructor that has been called directly and not only through a
/// super-call.
// TODO(johnniwinther): Improve semantic precision.
Iterable<ClassElement> get directlyInstantiatedClasses {
Iterable<ClassEntity> get directlyInstantiatedClasses {
return _directlyInstantiatedClasses;
}
@ -170,10 +152,10 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
// subclass and through subtype instantiated types/classes.
// TODO(johnniwinther): Support unknown type arguments for generic types.
void registerTypeInstantiation(
ResolutionInterfaceType type, ClassUsedCallback classUsed,
InterfaceType type, ClassUsedCallback classUsed,
{bool byMirrors: false}) {
ClassElement cls = type.element;
bool isNative = _nativeData.isNativeClass(cls);
ClassEntity cls = type.element;
bool isNative = _nativeBasicData.isNativeClass(cls);
_instantiatedTypes.add(type);
if (!cls.isAbstract
// We can't use the closed-world assumption with native abstract
@ -195,7 +177,7 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
// include the type arguments.
if (_implementedClasses.add(cls)) {
classUsed(cls, _getClassUsage(cls).implement());
cls.allSupertypes.forEach((ResolutionInterfaceType supertype) {
_elementEnvironment.forEachSupertype(cls, (InterfaceType supertype) {
if (_implementedClasses.add(supertype.element)) {
classUsed(
supertype.element, _getClassUsage(supertype.element).implement());
@ -205,7 +187,7 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
}
bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors,
MemberElement member, ClosedWorld world) {
MemberEntity member, ClosedWorld world) {
if (selectors == null) return false;
for (Selector selector in selectors.keys) {
if (selector.appliesUnnamed(member)) {
@ -218,16 +200,16 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
return false;
}
bool hasInvocation(Element member, ClosedWorld world) {
bool hasInvocation(MemberEntity member, ClosedWorld 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) ||
member.isFunction && methodsNeedingSuperGetter.contains(member);
}
bool hasInvokedSetter(Element member, ClosedWorld world) {
bool hasInvokedSetter(MemberEntity member, ClosedWorld world) {
return _hasMatchingSelector(_invokedSetters[member.name], member, world);
}
@ -318,28 +300,23 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
_invokedSetters.forEach(f);
}
void registerIsCheck(ResolutionDartType type) {
type = 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 registerIsCheck(DartType type) {
isChecks.add(type.unaliased);
}
void _registerStaticUse(StaticUse staticUse) {
Element element = staticUse.element;
if (Elements.isStaticOrTopLevel(element) && element.isField) {
allReferencedStaticFields.add(element);
if (staticUse.element is FieldEntity) {
FieldEntity field = staticUse.element;
if (field.isTopLevel || field.isStatic) {
allReferencedStaticFields.add(field);
}
}
switch (staticUse.kind) {
case StaticUseKind.STATIC_TEAR_OFF:
MethodElement method = element;
staticFunctionsNeedingGetter.add(method);
staticFunctionsNeedingGetter.add(staticUse.element);
break;
case StaticUseKind.SUPER_TEAR_OFF:
MethodElement method = element;
methodsNeedingSuperGetter.add(method);
methodsNeedingSuperGetter.add(staticUse.element);
break;
case StaticUseKind.SUPER_FIELD_SET:
case StaticUseKind.FIELD_SET:
@ -357,12 +334,12 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
}
void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed) {
Element element = staticUse.element;
assert(invariant(element, element.isDeclaration,
message: "Element ${element} is not the declaration."));
Entity element = staticUse.element;
_registerStaticUse(staticUse);
_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);
} else {
return new _GeneralStaticMemberUsage(element);
@ -413,22 +390,25 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
closurizedMembers.add(element);
}
void processClassMembers(ClassElement cls, MemberUsedCallback memberUsed) {
cls.implementation.forEachMember((_, MemberElement member) {
assert(invariant(member, member.isDeclaration));
if (!member.isInstanceMember) return;
if (member.isMalformed) return;
_getMemberUsage(member, memberUsed);
void processClassMembers(ClassEntity cls, MemberUsedCallback memberUsed) {
_elementEnvironment.forEachClassMember(cls,
(ClassEntity cls, MemberEntity member) {
_processInstantiatedClassMember(cls, member, memberUsed);
});
}
void _processInstantiatedClassMember(
ClassEntity cls, MemberEntity member, MemberUsedCallback memberUsed) {
if (!member.isInstanceMember) return;
_getMemberUsage(member, memberUsed);
}
_MemberUsage _getMemberUsage(
MemberElement member, MemberUsedCallback memberUsed) {
assert(invariant(member, member.isDeclaration));
MemberEntity member, MemberUsedCallback memberUsed) {
return _instanceMemberUsage.putIfAbsent(member, () {
String memberName = member.name;
ClassElement cls = member.enclosingClass;
bool isNative = _nativeData.isNativeClass(cls);
ClassEntity cls = member.enclosingClass;
bool isNative = _nativeBasicData.isNativeClass(cls);
_MemberUsage usage = new _MemberUsage(member, isNative: isNative);
EnumSet<MemberUse> useSet = new EnumSet<MemberUse>();
useSet.addAll(usage.appliedUse);
@ -477,16 +457,15 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
}
/// Return the canonical [_ClassUsage] for [cls].
_ClassUsage _getClassUsage(ClassElement cls) {
_ClassUsage _getClassUsage(ClassEntity cls) {
return _processedClasses.putIfAbsent(cls, () => new _ClassUsage(cls));
}
void _processInstantiatedClass(
ClassElement cls, ClassUsedCallback classUsed) {
void _processInstantiatedClass(ClassEntity cls, ClassUsedCallback classUsed) {
// Registers [superclass] as instantiated. Returns `true` if it wasn't
// already instantiated and we therefore have to process its superclass as
// well.
bool processClass(ClassElement superclass) {
bool processClass(ClassEntity superclass) {
_ClassUsage usage = _getClassUsage(superclass);
if (!usage.isInstantiated) {
classUsed(usage.cls, usage.instantiate());
@ -496,16 +475,108 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
}
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
/// the constant use was new to the world.
@override
bool registerConstantUse(ConstantUse use) {
if (use.kind == ConstantUseKind.DIRECT) {
_constants.addCompileTimeConstantForEmission(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';
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/common/codegen.dart';
@ -83,7 +85,7 @@ Future<String> compile(String code,
resolutionWork.run();
ClosedWorld closedWorld = compiler.closeResolution().closedWorld;
CodegenWorkItem work =
new CodegenWorkItem(compiler.backend, closedWorld, element);
new ElementCodegenWorkItem(compiler.backend, closedWorld, element);
compiler.phase = Compiler.PHASE_COMPILING;
work.run();
js.JavaScriptBackend backend = compiler.backend;

View file

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