| // 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. |
| |
| // @dart = 2.10 |
| |
| library ssa; |
| |
| import '../common.dart'; |
| import '../common/codegen.dart' show CodegenResult, CodegenRegistry; |
| import '../common/elements.dart' show CommonElements, JElementEnvironment; |
| 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_backend/namer.dart' show ModularNamer, ModularNamerImpl; |
| import '../js_backend/type_reference.dart' show TypeReference; |
| import '../js_emitter/code_emitter_task.dart' show ModularEmitter; |
| import '../js_emitter/startup_emitter/emitter.dart' show ModularEmitterImpl; |
| import '../js_model/elements.dart'; |
| import '../js_model/type_recipe.dart' show TypeExpressionRecipe; |
| import '../js_model/js_strategy.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 CompilerOptions _options; |
| final DiagnosticReporter _reporter; |
| final SsaCodeGeneratorTask generator; |
| final SsaBuilderTask _builder; |
| final SsaOptimizerTask optimizer; |
| final SourceInformationStrategy sourceInformationStrategy; |
| GlobalTypeInferenceResults _globalInferenceResults; |
| CodegenInputs _codegen; |
| |
| SsaFunctionCompiler( |
| this._options, |
| this._reporter, |
| JsBackendStrategy backendStrategy, |
| Measurer measurer, |
| this.sourceInformationStrategy) |
| : generator = |
| SsaCodeGeneratorTask(measurer, _options, sourceInformationStrategy), |
| _builder = SsaBuilderTask( |
| measurer, backendStrategy, sourceInformationStrategy), |
| optimizer = SsaOptimizerTask(measurer, _options); |
| |
| @override |
| void initialize(GlobalTypeInferenceResults globalInferenceResults, |
| CodegenInputs codegen) { |
| _globalInferenceResults = globalInferenceResults; |
| _codegen = codegen; |
| _builder.onCodegenStart(); |
| } |
| |
| /// Generates JavaScript code for [member]. |
| /// Using the ssa builder, optimizer and code generator. |
| @override |
| CodegenResult compile(MemberEntity member) { |
| JClosedWorld closedWorld = _globalInferenceResults.closedWorld; |
| CodegenRegistry registry = |
| CodegenRegistry(closedWorld.elementEnvironment, member); |
| ModularNamer namer = ModularNamerImpl( |
| registry, closedWorld.commonElements, _codegen.fixedNames); |
| ModularEmitter emitter = ModularEmitterImpl(namer, registry, _options); |
| if (member.isConstructor && |
| member.enclosingClass == closedWorld.commonElements.jsNullClass) { |
| // Work around a problem compiling JSNull's constructor. |
| return registry.close(null); |
| } |
| |
| HGraph graph = _builder.build(member, closedWorld, _globalInferenceResults, |
| _codegen, registry, namer, emitter); |
| if (graph == null) { |
| return registry.close(null); |
| } |
| optimizer.optimize(member, graph, _codegen, closedWorld, |
| _globalInferenceResults, registry); |
| js.Expression result = generator.generateCode( |
| member, graph, _codegen, closedWorld, registry, namer, emitter); |
| if (graph.needsAsyncRewrite) { |
| SourceInformationBuilder sourceInformationBuilder = |
| sourceInformationStrategy.createBuilderForContext(member); |
| result = _rewriteAsync( |
| _codegen, |
| closedWorld.commonElements, |
| closedWorld.elementEnvironment, |
| registry, |
| namer, |
| emitter, |
| member, |
| result, |
| graph.asyncElementType, |
| sourceInformationBuilder.buildAsyncBody(), |
| sourceInformationBuilder.buildAsyncExit()); |
| _codegen.tracer |
| .traceJavaScriptText('JavaScript.rewrite', result.debugPrint); |
| } |
| if (result.sourceInformation == null) { |
| result = result.withSourceInformation( |
| sourceInformationStrategy.buildSourceMappedMarker()); |
| } |
| |
| return registry.close(result); |
| } |
| |
| js.Expression _rewriteAsync( |
| CodegenInputs codegen, |
| CommonElements commonElements, |
| JElementEnvironment elementEnvironment, |
| CodegenRegistry registry, |
| ModularNamer namer, |
| ModularEmitter emitter, |
| FunctionEntity element, |
| js.Expression code, |
| DartType asyncTypeParameter, |
| SourceInformation bodySourceInformation, |
| SourceInformation exitSourceInformation) { |
| if (element.asyncMarker == AsyncMarker.SYNC) return code; |
| |
| AsyncRewriterBase rewriter = null; |
| js.Name name = namer.methodPropertyName( |
| element is JGeneratorBody ? element.function : element); |
| |
| switch (element.asyncMarker) { |
| case AsyncMarker.ASYNC: |
| rewriter = _makeAsyncRewriter( |
| codegen, |
| commonElements, |
| elementEnvironment, |
| registry, |
| namer, |
| emitter, |
| element, |
| code, |
| asyncTypeParameter, |
| name); |
| break; |
| case AsyncMarker.SYNC_STAR: |
| rewriter = _makeSyncStarRewriter( |
| codegen, |
| commonElements, |
| elementEnvironment, |
| registry, |
| namer, |
| emitter, |
| element, |
| code, |
| asyncTypeParameter, |
| name); |
| break; |
| case AsyncMarker.ASYNC_STAR: |
| rewriter = _makeAsyncStarRewriter( |
| codegen, |
| commonElements, |
| elementEnvironment, |
| registry, |
| namer, |
| emitter, |
| element, |
| code, |
| asyncTypeParameter, |
| name); |
| 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> _fetchItemTypeNewRti( |
| CommonElements commonElements, CodegenRegistry registry, DartType type) { |
| if (type == null) return null; |
| registry.registerStaticUse( |
| StaticUse.staticInvoke(commonElements.findType, CallStructure.ONE_ARG)); |
| return [TypeReference(TypeExpressionRecipe(type))]; |
| } |
| |
| AsyncRewriter _makeAsyncRewriter( |
| CodegenInputs codegen, |
| CommonElements commonElements, |
| JElementEnvironment elementEnvironment, |
| CodegenRegistry registry, |
| ModularNamer namer, |
| ModularEmitter emitter, |
| FunctionEntity element, |
| js.Expression code, |
| DartType elementType, |
| js.Name name) { |
| FunctionEntity startFunction = commonElements.asyncHelperStartSync; |
| FunctionEntity completerFactory = commonElements.asyncAwaitCompleterFactory; |
| |
| List<js.Expression> itemTypeExpression = |
| _fetchItemTypeNewRti(commonElements, registry, elementType); |
| |
| AsyncRewriter rewriter = AsyncRewriter(_reporter, element, |
| asyncStart: emitter.staticFunctionAccess(startFunction), |
| asyncAwait: |
| emitter.staticFunctionAccess(commonElements.asyncHelperAwait), |
| asyncReturn: |
| emitter.staticFunctionAccess(commonElements.asyncHelperReturn), |
| asyncRethrow: |
| emitter.staticFunctionAccess(commonElements.asyncHelperRethrow), |
| wrapBody: emitter.staticFunctionAccess(commonElements.wrapBody), |
| completerFactory: emitter.staticFunctionAccess(completerFactory), |
| completerFactoryTypeArguments: itemTypeExpression, |
| safeVariableName: namer.safeVariablePrefixForAsyncRewrite, |
| bodyName: namer.deriveAsyncBodyName(name)); |
| |
| registry.registerStaticUse(StaticUse.staticInvoke( |
| completerFactory, |
| CallStructure.unnamed(0, 1), |
| [elementEnvironment.getFunctionAsyncOrSyncStarElementType(element)])); |
| |
| return rewriter; |
| } |
| |
| SyncStarRewriter _makeSyncStarRewriter( |
| CodegenInputs codegen, |
| CommonElements commonElements, |
| JElementEnvironment elementEnvironment, |
| CodegenRegistry registry, |
| ModularNamer namer, |
| ModularEmitter emitter, |
| FunctionEntity element, |
| js.Expression code, |
| DartType asyncTypeParameter, |
| js.Name name) { |
| List<js.Expression> itemTypeExpression = |
| _fetchItemTypeNewRti(commonElements, registry, asyncTypeParameter); |
| |
| SyncStarRewriter rewriter = SyncStarRewriter(_reporter, element, |
| endOfIteration: |
| emitter.staticFunctionAccess(commonElements.endOfIteration), |
| iterableFactory: emitter |
| .staticFunctionAccess(commonElements.syncStarIterableFactory), |
| iterableFactoryTypeArguments: itemTypeExpression, |
| yieldStarExpression: |
| emitter.staticFunctionAccess(commonElements.yieldStar), |
| uncaughtErrorExpression: |
| emitter.staticFunctionAccess(commonElements.syncStarUncaughtError), |
| safeVariableName: namer.safeVariablePrefixForAsyncRewrite, |
| bodyName: namer.deriveAsyncBodyName(name)); |
| |
| registry.registerStaticUse(StaticUse.staticInvoke( |
| commonElements.syncStarIterableFactory, |
| CallStructure.unnamed(1, 1), |
| [elementEnvironment.getFunctionAsyncOrSyncStarElementType(element)])); |
| |
| return rewriter; |
| } |
| |
| AsyncStarRewriter _makeAsyncStarRewriter( |
| CodegenInputs codegen, |
| CommonElements commonElements, |
| JElementEnvironment elementEnvironment, |
| CodegenRegistry registry, |
| ModularNamer namer, |
| ModularEmitter emitter, |
| FunctionEntity element, |
| js.Expression code, |
| DartType asyncTypeParameter, |
| js.Name name) { |
| List<js.Expression> itemTypeExpression = |
| _fetchItemTypeNewRti(commonElements, registry, asyncTypeParameter); |
| |
| AsyncStarRewriter rewriter = AsyncStarRewriter(_reporter, element, |
| asyncStarHelper: |
| emitter.staticFunctionAccess(commonElements.asyncStarHelper), |
| streamOfController: |
| emitter.staticFunctionAccess(commonElements.streamOfController), |
| wrapBody: emitter.staticFunctionAccess(commonElements.wrapBody), |
| newController: emitter.staticFunctionAccess( |
| commonElements.asyncStarStreamControllerFactory), |
| newControllerTypeArguments: itemTypeExpression, |
| safeVariableName: namer.safeVariablePrefixForAsyncRewrite, |
| yieldExpression: |
| emitter.staticFunctionAccess(commonElements.yieldSingle), |
| yieldStarExpression: |
| emitter.staticFunctionAccess(commonElements.yieldStar), |
| bodyName: namer.deriveAsyncBodyName(name)); |
| |
| registry.registerStaticUse(StaticUse.staticInvoke( |
| commonElements.asyncStarStreamControllerFactory, |
| CallStructure.unnamed(1, 1), |
| [elementEnvironment.getFunctionAsyncOrSyncStarElementType(element)])); |
| |
| return rewriter; |
| } |
| |
| @override |
| Iterable<CompilerTask> get tasks { |
| return [_builder, optimizer, generator]; |
| } |
| } |
| |
| abstract class SsaBuilder { |
| /// Creates the [HGraph] for [member] or returns `null` if no code is needed |
| /// for [member]. |
| HGraph build( |
| MemberEntity member, |
| JClosedWorld closedWorld, |
| GlobalTypeInferenceResults globalInferenceResults, |
| CodegenInputs codegen, |
| CodegenRegistry registry, |
| ModularNamer namer, |
| ModularEmitter emitter); |
| } |
| |
| class SsaBuilderTask extends CompilerTask { |
| final JsBackendStrategy _backendStrategy; |
| final SourceInformationStrategy _sourceInformationFactory; |
| SsaBuilder _builder; |
| |
| SsaBuilderTask( |
| Measurer measurer, this._backendStrategy, this._sourceInformationFactory) |
| : super(measurer); |
| |
| @override |
| String get name => 'SSA builder'; |
| |
| void onCodegenStart() { |
| _builder = |
| _backendStrategy.createSsaBuilder(this, _sourceInformationFactory); |
| } |
| |
| /// Creates the [HGraph] for [member] or returns `null` if no code is needed |
| /// for [member]. |
| HGraph build( |
| MemberEntity member, |
| JClosedWorld closedWorld, |
| GlobalTypeInferenceResults globalInferenceResults, |
| CodegenInputs codegen, |
| CodegenRegistry registry, |
| ModularNamer namer, |
| ModularEmitter emitter) { |
| return _builder.build(member, closedWorld, globalInferenceResults, codegen, |
| registry, namer, emitter); |
| } |
| } |