From 789fce309f08757c74684b4a4e33a78136a0f331 Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Mon, 22 May 2017 10:05:53 +0200 Subject: [PATCH] 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 . --- pkg/compiler/lib/src/backend_strategy.dart | 30 +-- pkg/compiler/lib/src/common/codegen.dart | 40 +--- pkg/compiler/lib/src/compiler.dart | 1 + pkg/compiler/lib/src/elements/entities.dart | 8 + pkg/compiler/lib/src/js_backend/backend.dart | 6 +- .../lib/src/js_backend/codegen_listener.dart | 7 +- .../lib/src/js_backend/element_strategy.dart | 117 ++++++++++ pkg/compiler/lib/src/js_backend/enqueuer.dart | 32 --- .../src/js_backend/resolution_listener.dart | 6 +- .../js_emitter/program_builder/collector.dart | 4 +- .../src/js_emitter/type_test_registry.dart | 4 +- .../lib/src/kernel/kernel_strategy.dart | 22 ++ pkg/compiler/lib/src/native/enqueue.dart | 2 +- pkg/compiler/lib/src/ssa/builder.dart | 5 +- pkg/compiler/lib/src/ssa/builder_kernel.dart | 5 +- pkg/compiler/lib/src/ssa/codegen.dart | 7 +- pkg/compiler/lib/src/ssa/ssa.dart | 4 +- .../src/universe/codegen_world_builder.dart | 219 ++++++++++++------ tests/compiler/dart2js/compiler_helper.dart | 4 +- .../dart2js/type_representation_test.dart | 3 +- 20 files changed, 338 insertions(+), 188 deletions(-) create mode 100644 pkg/compiler/lib/src/js_backend/element_strategy.dart diff --git a/pkg/compiler/lib/src/backend_strategy.dart b/pkg/compiler/lib/src/backend_strategy.dart index a95aa7aabad..4178d9b448b 100644 --- a/pkg/compiler/lib/src/backend_strategy.dart +++ b/pkg/compiler/lib/src/backend_strategy.dart @@ -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); } diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart index 478085c7de6..6f22d66136c 100644 --- a/pkg/compiler/lib/src/common/codegen.dart +++ b/pkg/compiler/lib/src/common/codegen.dart @@ -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; } diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart index 2cffc6220bd..82daf7def17 100644 --- a/pkg/compiler/lib/src/compiler.dart +++ b/pkg/compiler/lib/src/compiler.dart @@ -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 diff --git a/pkg/compiler/lib/src/elements/entities.dart b/pkg/compiler/lib/src/elements/entities.dart index 9737c210de4..eedc0f65841 100644 --- a/pkg/compiler/lib/src/elements/entities.dart +++ b/pkg/compiler/lib/src/elements/entities.dart @@ -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); + } } diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart index adaf986d5e3..a0a744ebb9a 100644 --- a/pkg/compiler/lib/src/js_backend/backend.dart +++ b/pkg/compiler/lib/src/js_backend/backend.dart @@ -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, diff --git a/pkg/compiler/lib/src/js_backend/codegen_listener.dart b/pkg/compiler/lib/src/js_backend/codegen_listener.dart index 2b561e315ea..96c2118c25f 100644 --- a/pkg/compiler/lib/src/js_backend/codegen_listener.dart +++ b/pkg/compiler/lib/src/js_backend/codegen_listener.dart @@ -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 diff --git a/pkg/compiler/lib/src/js_backend/element_strategy.dart b/pkg/compiler/lib/src/js_backend/element_strategy.dart new file mode 100644 index 00000000000..2fb66213046 --- /dev/null +++ b/pkg/compiler/lib/src/js_backend/element_strategy.dart @@ -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})'; +} diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart index 318bb9f5577..9d0c36a65ed 100644 --- a/pkg/compiler/lib/src/js_backend/enqueuer.dart +++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart @@ -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 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); - } -} diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart index 09eb2ce69b8..2abec233d53 100644 --- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart +++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart @@ -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); diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart index 0b062330b1b..9f654f2ab8a 100644 --- a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart +++ b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart @@ -203,7 +203,7 @@ class Collector { .toList()); // Compute needed classes. - Set instantiatedClasses = + Set instantiatedClasses = // TODO(johnniwinther): This should be accessed from a codegen closed // world. _worldBuilder.directlyInstantiatedClasses @@ -219,7 +219,7 @@ class Collector { } } - void addClassesWithSuperclasses(Iterable classes) { + void addClassesWithSuperclasses(Iterable classes) { for (ClassElement cls in classes) { addClassWithSuperclasses(cls); } diff --git a/pkg/compiler/lib/src/js_emitter/type_test_registry.dart b/pkg/compiler/lib/src/js_emitter/type_test_registry.dart index 2df546a49bc..b6dc0d0ed70 100644 --- a/pkg/compiler/lib/src/js_emitter/type_test_registry.dart +++ b/pkg/compiler/lib/src/js_emitter/type_test_registry.dart @@ -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) { diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart index 5c5c0763794..e7fa21ec430 100644 --- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart +++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart @@ -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'); + } } diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart index 71f66c2c286..3af7a256b1b 100644 --- a/pkg/compiler/lib/src/native/enqueue.dart +++ b/pkg/compiler/lib/src/native/enqueue.dart @@ -246,7 +246,7 @@ class NativeCodegenEnqueuer extends NativeEnqueuerBase { this._nativeData) : super(options, elementEnvironment, commonElements, dartTypes); - WorldImpact processNativeClasses(Iterable libraries) { + WorldImpact processNativeClasses(Iterable libraries) { WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); _unusedClasses.addAll(_resolutionEnqueuer._nativeClasses); diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart index fd7f6ae002c..5093c1db8c2 100644 --- a/pkg/compiler/lib/src/ssa/builder.dart +++ b/pkg/compiler/lib/src/ssa/builder.dart @@ -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, () { diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart index 1e2ebd60fa2..0f94d7f155e 100644 --- a/pkg/compiler/lib/src/ssa/builder_kernel.dart +++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart @@ -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; diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart index 801bec47d81..9b5186281b7 100644 --- a/pkg/compiler/lib/src/ssa/codegen.dart +++ b/pkg/compiler/lib/src/ssa/codegen.dart @@ -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) { diff --git a/pkg/compiler/lib/src/ssa/ssa.dart b/pkg/compiler/lib/src/ssa/ssa.dart index 92f05f94a0b..191fe70d3fb 100644 --- a/pkg/compiler/lib/src/ssa/ssa.dart +++ b/pkg/compiler/lib/src/ssa/ssa.dart @@ -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); diff --git a/pkg/compiler/lib/src/universe/codegen_world_builder.dart b/pkg/compiler/lib/src/universe/codegen_world_builder.dart index 05bcca7e314..c135e726d8d 100644 --- a/pkg/compiler/lib/src/universe/codegen_world_builder.dart +++ b/pkg/compiler/lib/src/universe/codegen_world_builder.dart @@ -28,9 +28,9 @@ abstract class CodegenWorldBuilder implements WorldBuilder { f(String name, Map 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 invocationsByName(String name); @@ -50,10 +50,10 @@ abstract class CodegenWorldBuilder implements WorldBuilder { Iterable 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 _directlyInstantiatedClasses = - new Set(); + final Set _directlyInstantiatedClasses = new Set(); /// 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 _instantiatedTypes = new Set(); /// Classes implemented by directly instantiated classes. - final Set _implementedClasses = new Set(); + final Set _implementedClasses = new Set(); /// The set of all referenced static fields. /// /// Invariant: Elements are declaration elements. - final Set allReferencedStaticFields = new Set(); + final Set allReferencedStaticFields = new Set(); /** * Documentation wanted -- johnniwinther @@ -95,8 +94,8 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder { final Map> _invokedSetters = >{}; - final Map _processedClasses = - {}; + final Map _processedClasses = + {}; /// Map of registered usage of static members of live classes. final Map _staticMemberUsage = @@ -116,7 +115,7 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder { final Map> _instanceFunctionsByName = >{}; - final Set isChecks = new Set(); + final Set isChecks = new Set(); final SelectorConstraintsStrategy selectorConstraintsStrategy; @@ -125,34 +124,17 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder { /// Set of methods in instantiated classes that are potentially closurized. final Set closurizedMembers = new Set(); - 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 get processedClasses => _processedClasses.keys + Iterable 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 get directlyInstantiatedClasses { + Iterable 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 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 useSet = new EnumSet(); 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'); + } } diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart index d97359fef52..33b7576ee9b 100644 --- a/tests/compiler/dart2js/compiler_helper.dart +++ b/tests/compiler/dart2js/compiler_helper.dart @@ -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 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; diff --git a/tests/compiler/dart2js/type_representation_test.dart b/tests/compiler/dart2js/type_representation_test.dart index 3acfddd65f3..bc4feb691a1 100644 --- a/tests/compiler/dart2js/type_representation_test.dart +++ b/tests/compiler/dart2js/type_representation_test.dart @@ -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,