| // Copyright (c) 2012, 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 ssa; |
| |
| import '../backend_strategy.dart'; |
| import '../common.dart'; |
| import '../common_elements.dart' show CommonElements, JElementEnvironment; |
| import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| import '../common/tasks.dart' show CompilerTask, Measurer; |
| import '../elements/entities.dart'; |
| import '../elements/types.dart'; |
| import '../inferrer/types.dart'; |
| import '../io/source_information.dart'; |
| import '../js/js.dart' as js; |
| import '../js/rewrite_async.dart'; |
| import '../js_backend/backend.dart' show CodegenInputs, FunctionCompiler; |
| import '../js_model/elements.dart'; |
| import '../options.dart'; |
| import '../universe/call_structure.dart' show CallStructure; |
| import '../universe/use.dart' show StaticUse; |
| import '../world.dart' show JClosedWorld; |
| |
| import 'codegen.dart'; |
| import 'nodes.dart'; |
| import 'optimize.dart'; |
| |
| class SsaFunctionCompiler implements FunctionCompiler { |
| final DiagnosticReporter _reporter; |
| final SsaCodeGeneratorTask generator; |
| final SsaBuilderTask _builder; |
| final SsaOptimizerTask optimizer; |
| final SourceInformationStrategy sourceInformationStrategy; |
| |
| SsaFunctionCompiler( |
| CompilerOptions options, |
| this._reporter, |
| BackendStrategy backendStrategy, |
| Measurer measurer, |
| this.sourceInformationStrategy) |
| : generator = new SsaCodeGeneratorTask( |
| measurer, options, sourceInformationStrategy), |
| _builder = new SsaBuilderTask( |
| measurer, backendStrategy, sourceInformationStrategy), |
| optimizer = new SsaOptimizerTask(measurer, options); |
| |
| @override |
| void onCodegenStart(CodegenInputs codegen) { |
| _builder.onCodegenStart(codegen); |
| } |
| |
| /// Generates JavaScript code for `work.element`. |
| /// Using the ssa builder, optimizer and code generator. |
| @override |
| js.Fun compile( |
| CodegenWorkItem work, |
| CodegenInputs codegen, |
| JClosedWorld closedWorld, |
| GlobalTypeInferenceResults globalInferenceResults) { |
| HGraph graph = _builder.build(work, closedWorld, globalInferenceResults); |
| if (graph == null) return null; |
| optimizer.optimize( |
| work, graph, codegen, closedWorld, globalInferenceResults); |
| MemberEntity element = work.element; |
| js.Expression result = |
| generator.generateCode(work, graph, codegen, closedWorld); |
| if (graph.needsAsyncRewrite) { |
| SourceInformationBuilder sourceInformationBuilder = |
| sourceInformationStrategy.createBuilderForContext(element); |
| result = _rewriteAsync( |
| codegen, |
| closedWorld.commonElements, |
| closedWorld.elementEnvironment, |
| work.registry, |
| element, |
| result, |
| graph.asyncElementType, |
| sourceInformationBuilder.buildAsyncBody(), |
| sourceInformationBuilder.buildAsyncExit()); |
| } |
| return result; |
| } |
| |
| js.Expression _rewriteAsync( |
| CodegenInputs codegen, |
| CommonElements commonElements, |
| JElementEnvironment elementEnvironment, |
| CodegenRegistry registry, |
| FunctionEntity element, |
| js.Expression code, |
| DartType asyncTypeParameter, |
| SourceInformation bodySourceInformation, |
| SourceInformation exitSourceInformation) { |
| if (element.asyncMarker == AsyncMarker.SYNC) return code; |
| |
| AsyncRewriterBase rewriter = null; |
| js.Name name = codegen.namer.methodPropertyName( |
| element is JGeneratorBody ? element.function : element); |
| |
| switch (element.asyncMarker) { |
| case AsyncMarker.ASYNC: |
| rewriter = _makeAsyncRewriter( |
| codegen, |
| commonElements, |
| elementEnvironment, |
| registry, |
| element, |
| code, |
| asyncTypeParameter, |
| name); |
| break; |
| case AsyncMarker.SYNC_STAR: |
| rewriter = new SyncStarRewriter(_reporter, element, |
| endOfIteration: codegen.emitter |
| .staticFunctionAccess(commonElements.endOfIteration), |
| iterableFactory: codegen.emitter |
| .staticFunctionAccess(commonElements.syncStarIterableFactory), |
| iterableFactoryTypeArguments: |
| _fetchItemType(codegen, asyncTypeParameter), |
| yieldStarExpression: |
| codegen.emitter.staticFunctionAccess(commonElements.yieldStar), |
| uncaughtErrorExpression: codegen.emitter |
| .staticFunctionAccess(commonElements.syncStarUncaughtError), |
| safeVariableName: codegen.namer.safeVariablePrefixForAsyncRewrite, |
| bodyName: codegen.namer.deriveAsyncBodyName(name)); |
| registry.registerStaticUse(new StaticUse.staticInvoke( |
| commonElements.syncStarIterableFactory, |
| const CallStructure.unnamed(1, 1), [ |
| elementEnvironment.getFunctionAsyncOrSyncStarElementType(element) |
| ])); |
| break; |
| case AsyncMarker.ASYNC_STAR: |
| rewriter = new AsyncStarRewriter(_reporter, element, |
| asyncStarHelper: codegen.emitter |
| .staticFunctionAccess(commonElements.asyncStarHelper), |
| streamOfController: codegen.emitter |
| .staticFunctionAccess(commonElements.streamOfController), |
| wrapBody: |
| codegen.emitter.staticFunctionAccess(commonElements.wrapBody), |
| newController: codegen.emitter.staticFunctionAccess( |
| commonElements.asyncStarStreamControllerFactory), |
| newControllerTypeArguments: |
| _fetchItemType(codegen, asyncTypeParameter), |
| safeVariableName: codegen.namer.safeVariablePrefixForAsyncRewrite, |
| yieldExpression: codegen.emitter |
| .staticFunctionAccess(commonElements.yieldSingle), |
| yieldStarExpression: |
| codegen.emitter.staticFunctionAccess(commonElements.yieldStar), |
| bodyName: codegen.namer.deriveAsyncBodyName(name)); |
| registry.registerStaticUse(new StaticUse.staticInvoke( |
| commonElements.asyncStarStreamControllerFactory, |
| const CallStructure.unnamed(1, 1), [ |
| elementEnvironment.getFunctionAsyncOrSyncStarElementType(element) |
| ])); |
| break; |
| } |
| return rewriter.rewrite(code, bodySourceInformation, exitSourceInformation); |
| } |
| |
| /// Returns an optional expression that evaluates [type]. Returns `null` if |
| /// the type expression is determined by the outside context and should be |
| /// added as a function parameter to the rewritten code. |
| // TODO(sra): We could also return an empty list if the generator takes no |
| // type (e.g. due to rtiNeed optimization). |
| List<js.Expression> _fetchItemType(CodegenInputs codegen, DartType type) { |
| if (type == null) return null; |
| var ast = |
| codegen.rtiEncoder.getTypeRepresentation(codegen.emitter, type, null); |
| return <js.Expression>[ast]; |
| } |
| |
| AsyncRewriter _makeAsyncRewriter( |
| CodegenInputs codegen, |
| CommonElements commonElements, |
| JElementEnvironment elementEnvironment, |
| CodegenRegistry registry, |
| FunctionEntity element, |
| js.Expression code, |
| DartType elementType, |
| js.Name name) { |
| FunctionEntity startFunction = commonElements.asyncHelperStartSync; |
| FunctionEntity completerFactory = commonElements.asyncAwaitCompleterFactory; |
| |
| List<js.Expression> itemTypeExpression = |
| _fetchItemType(codegen, elementType); |
| |
| AsyncRewriter rewriter = new AsyncRewriter(_reporter, element, |
| asyncStart: codegen.emitter.staticFunctionAccess(startFunction), |
| asyncAwait: codegen.emitter |
| .staticFunctionAccess(commonElements.asyncHelperAwait), |
| asyncReturn: codegen.emitter |
| .staticFunctionAccess(commonElements.asyncHelperReturn), |
| asyncRethrow: codegen.emitter |
| .staticFunctionAccess(commonElements.asyncHelperRethrow), |
| wrapBody: codegen.emitter.staticFunctionAccess(commonElements.wrapBody), |
| completerFactory: |
| codegen.emitter.staticFunctionAccess(completerFactory), |
| completerFactoryTypeArguments: itemTypeExpression, |
| safeVariableName: codegen.namer.safeVariablePrefixForAsyncRewrite, |
| bodyName: codegen.namer.deriveAsyncBodyName(name)); |
| |
| registry.registerStaticUse(new StaticUse.staticInvoke( |
| completerFactory, |
| const CallStructure.unnamed(0, 1), |
| [elementEnvironment.getFunctionAsyncOrSyncStarElementType(element)])); |
| |
| return rewriter; |
| } |
| |
| @override |
| Iterable<CompilerTask> get tasks { |
| return <CompilerTask>[_builder, optimizer, generator]; |
| } |
| } |
| |
| abstract class SsaBuilder { |
| /// Creates the [HGraph] for [work] or returns `null` if no code is needed |
| /// for [work]. |
| HGraph build(CodegenWorkItem work, JClosedWorld closedWorld, |
| GlobalTypeInferenceResults globalInferenceResults); |
| } |
| |
| class SsaBuilderTask extends CompilerTask { |
| final BackendStrategy _backendStrategy; |
| final SourceInformationStrategy _sourceInformationFactory; |
| SsaBuilder _builder; |
| |
| SsaBuilderTask( |
| Measurer measurer, this._backendStrategy, this._sourceInformationFactory) |
| : super(measurer); |
| |
| @override |
| String get name => 'SSA builder'; |
| |
| void onCodegenStart(CodegenInputs codegen) { |
| _builder = _backendStrategy.createSsaBuilder( |
| this, codegen, _sourceInformationFactory); |
| } |
| |
| /// Creates the [HGraph] for [work] or returns `null` if no code is needed |
| /// for [work]. |
| HGraph build(CodegenWorkItem work, JClosedWorld closedWorld, |
| GlobalTypeInferenceResults globalInferenceResults) { |
| return _builder.build(work, closedWorld, globalInferenceResults); |
| } |
| } |