blob: 179b9461c75a54018b594ab7eef0d74f9c676bdb [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 CodegenResult, CodegenRegistry;
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 '../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,
BackendStrategy 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());
}
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,
const 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,
const 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,
const CallStructure.unnamed(1, 1),
[elementEnvironment.getFunctionAsyncOrSyncStarElementType(element)]));
return rewriter;
}
@override
Iterable<CompilerTask> get tasks {
return <CompilerTask>[_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 BackendStrategy _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);
}
}