blob: c6e963e9ea4cba8ea9a1b28290f389d0a7e0ad51 [file] [log] [blame]
// 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);
}
}