blob: f9c45ea95295d1478506063009ac064b08825063 [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 '../constants/values.dart';
import '../elements/entities.dart'
show FieldEntity, FunctionEntity, MemberEntity;
import '../io/source_information.dart';
import '../js/js.dart' as js;
import '../js_backend/backend.dart' show JavaScriptBackend, FunctionCompiler;
import '../universe/call_structure.dart';
import '../universe/use.dart';
import '../world.dart' show ClosedWorld;
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 codegenerator.
js.Fun compile(CodegenWorkItem work, ClosedWorld closedWorld) {
HGraph graph = _builder.build(work, closedWorld);
if (graph == null) return null;
optimizer.optimize(work, graph, closedWorld);
MemberEntity element = work.element;
js.Expression result = generator.generateCode(work, graph, closedWorld);
if (element is FunctionEntity) {
SourceInformationBuilder sourceInformationBuilder =
backend.sourceInformationStrategy.createBuilderForContext(element);
result = backend.rewriteAsync(
closedWorld.commonElements,
closedWorld.elementEnvironment,
work.registry,
element,
result,
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, ClosedWorld closedWorld);
}
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, ClosedWorld closedWorld) {
return _builder.build(work, closedWorld);
}
}
abstract class SsaBuilderFieldMixin {
ConstantValue getFieldInitialConstantValue(covariant FieldEntity field);
/// 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, ClosedWorld closedWorld) {
if (element.isField) {
ConstantValue initialValue = getFieldInitialConstantValue(element);
if (initialValue != null) {
registry.worldImpact
.registerConstantUse(new ConstantUse.init(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;
}
}