blob: 41360b05a6df557ae4bd10abb89f4d8f5c137168 [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 '../common/codegen.dart' show CodegenWorkItem, CodegenRegistry;
import '../common/tasks.dart' show CompilerTask, Measurer;
import '../elements/entities.dart' show MemberEntity;
import '../inferrer/types.dart';
import '../io/source_information.dart';
import '../js/js.dart' as js;
import '../js_backend/field_analysis.dart';
import '../js_backend/backend.dart' show JavaScriptBackend, FunctionCompiler;
import '../universe/call_structure.dart';
import '../universe/use.dart';
import '../world.dart' show JClosedWorld;
import 'codegen.dart';
import 'nodes.dart';
import 'optimize.dart';
class SsaFunctionCompiler implements FunctionCompiler {
final SsaCodeGeneratorTask generator;
final SsaBuilderTask _builder;
final SsaOptimizerTask optimizer;
final JavaScriptBackend backend;
SsaFunctionCompiler(JavaScriptBackend backend, Measurer measurer,
SourceInformationStrategy sourceInformationFactory)
: generator = new SsaCodeGeneratorTask(backend, sourceInformationFactory),
_builder = new SsaBuilderTask(backend, sourceInformationFactory),
optimizer = new SsaOptimizerTask(backend),
backend = backend;
void onCodegenStart() {
_builder.onCodegenStart();
}
/// Generates JavaScript code for `work.element`.
/// Using the ssa builder, optimizer and code generator.
js.Fun compile(CodegenWorkItem work, JClosedWorld closedWorld,
GlobalTypeInferenceResults globalInferenceResults) {
HGraph graph = _builder.build(work, closedWorld, globalInferenceResults);
if (graph == null) return null;
optimizer.optimize(work, graph, closedWorld, globalInferenceResults);
MemberEntity element = work.element;
js.Expression result = generator.generateCode(work, graph, closedWorld);
if (graph.needsAsyncRewrite) {
SourceInformationBuilder sourceInformationBuilder =
backend.sourceInformationStrategy.createBuilderForContext(element);
result = backend.rewriteAsync(
closedWorld.commonElements,
closedWorld.elementEnvironment,
work.registry,
element,
result,
graph.asyncElementType,
sourceInformationBuilder.buildAsyncBody(),
sourceInformationBuilder.buildAsyncExit());
}
return result;
}
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 JavaScriptBackend _backend;
final SourceInformationStrategy _sourceInformationFactory;
SsaBuilder _builder;
SsaBuilderTask(this._backend, this._sourceInformationFactory)
: super(_backend.compiler.measurer);
String get name => 'SSA builder';
void onCodegenStart() {
_builder = _backend.compiler.backendStrategy
.createSsaBuilder(this, _backend, _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);
}
}
abstract class SsaBuilderFieldMixin {
/// Handle field initializer of [element]. Returns `true` if no code
/// is needed for the field.
///
/// If [element] is a field with a constant initializer, the value is
/// registered with the world impact. Otherwise the cyclic-throw helper is
/// registered for the lazy value computation.
///
/// If the field is constant, no code is needed for the field and the method
/// returns `true`.
bool handleConstantField(MemberEntity element, CodegenRegistry registry,
JClosedWorld closedWorld) {
if (element.isField) {
FieldAnalysisData fieldData =
closedWorld.fieldAnalysis.getFieldData(element);
if (fieldData.initialValue != null) {
registry.worldImpact
.registerConstantUse(new ConstantUse.init(fieldData.initialValue));
// We don't need to generate code for static or top-level
// variables. For instance variables, we may need to generate
// the checked setter.
if (element.isStatic || element.isTopLevel) {
/// No code is created for this field: All references inline the
/// constant value.
return true;
}
} else {
// If the constant-handler was not able to produce a result we have to
// go through the builder (below) to generate the lazy initializer for
// the static variable.
// We also need to register the use of the cyclic-error helper.
registry.worldImpact.registerStaticUse(new StaticUse.staticInvoke(
closedWorld.commonElements.cyclicThrowHelper,
CallStructure.ONE_ARG));
}
}
return false;
}
}