blob: 35cca0277e8b71442516c090a717ae16d27294dd [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 dart2js.js_emitter.code_emitter_task;
import '../common.dart';
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart' show Compiler;
import '../constants/values.dart';
import '../deferred_load.dart' show OutputUnit;
import '../elements/entities.dart';
import '../js/js.dart' as jsAst;
import '../js_backend/js_backend.dart'
show CodegenInputs, JavaScriptBackend, Namer;
import '../js_backend/inferred_data.dart';
import '../universe/codegen_world_builder.dart';
import '../world.dart' show JClosedWorld;
import 'program_builder/program_builder.dart';
import 'startup_emitter/emitter.dart' as startup_js_emitter;
import 'metadata_collector.dart' show MetadataCollector;
import 'model.dart';
import 'native_emitter.dart' show NativeEmitter;
import 'type_test_registry.dart' show TypeTestRegistry;
/// Generates the code for all used classes in the program. Static fields (even
/// in classes) are ignored, since they can be treated as non-class elements.
///
/// The code for the containing (used) methods must exist in the `universe`.
class CodeEmitterTask extends CompilerTask {
TypeTestRegistry typeTestRegistry;
NativeEmitter _nativeEmitter;
MetadataCollector metadataCollector;
Emitter _emitter;
final Compiler _compiler;
final bool _generateSourceMap;
JavaScriptBackend get _backend => _compiler.backend;
@deprecated
// This field should be removed. It's currently only needed for dump-info and
// tests.
// The field is set after the program has been emitted.
/// Contains a list of all classes that are emitted.
Set<ClassEntity> neededClasses;
CodeEmitterTask(this._compiler, this._generateSourceMap)
: super(_compiler.measurer);
NativeEmitter get nativeEmitter {
assert(
_nativeEmitter != null,
failedAt(
NO_LOCATION_SPANNABLE, "NativeEmitter has not been created yet."));
return _nativeEmitter;
}
Emitter get emitter {
assert(_emitter != null,
failedAt(NO_LOCATION_SPANNABLE, "Emitter has not been created yet."));
return _emitter;
}
@override
String get name => 'Code emitter';
void _finalizeRti(CodegenInputs codegen, CodegenWorld codegenWorld) {
// Compute the required type checks to know which classes need a
// 'is$' method.
typeTestRegistry.computeRequiredTypeChecks(
_backend.rtiChecksBuilder, codegenWorld);
// Compute the classes needed by RTI.
typeTestRegistry.computeRtiNeededClasses(
codegen.rtiSubstitutions, _backend.generatedCode.keys);
}
/// Creates the [Emitter] for this task.
void createEmitter(Namer namer, JClosedWorld closedWorld) {
measure(() {
_nativeEmitter =
new NativeEmitter(this, closedWorld, _backend.nativeCodegenEnqueuer);
_emitter = new startup_js_emitter.EmitterImpl(
_compiler.options,
_compiler.reporter,
_compiler.outputProvider,
_compiler.dumpInfoTask,
namer,
closedWorld,
_backend.rtiEncoder,
_backend.sourceInformationStrategy,
this,
_generateSourceMap);
metadataCollector = new MetadataCollector(
_compiler.options,
_compiler.reporter,
_emitter,
_backend.rtiEncoder,
closedWorld.elementEnvironment);
typeTestRegistry = new TypeTestRegistry(
_compiler.options, closedWorld.elementEnvironment);
});
}
int assembleProgram(
Namer namer,
JClosedWorld closedWorld,
InferredData inferredData,
CodegenInputs codegen,
CodegenWorld codegenWorld) {
return measure(() {
_finalizeRti(codegen, codegenWorld);
ProgramBuilder programBuilder = new ProgramBuilder(
_compiler.options,
_compiler.reporter,
closedWorld.elementEnvironment,
closedWorld.commonElements,
closedWorld.outputUnitData,
codegenWorld,
_backend.nativeCodegenEnqueuer,
closedWorld.backendUsage,
closedWorld.nativeData,
closedWorld.rtiNeed,
closedWorld.interceptorData,
codegen.superMemberData,
typeTestRegistry.rtiChecks,
codegen.rtiEncoder,
codegen.oneShotInterceptorData,
_backend.customElementsCodegenAnalysis,
_backend.generatedCode,
namer,
this,
closedWorld,
closedWorld.fieldAnalysis,
inferredData,
_backend.sourceInformationStrategy,
closedWorld.sorter,
typeTestRegistry.rtiNeededClasses,
closedWorld.elementEnvironment.mainFunction);
int size = emitter.emitProgram(programBuilder, codegenWorld);
// TODO(floitsch): we shouldn't need the `neededClasses` anymore.
neededClasses = programBuilder.collector.neededClasses;
return size;
});
}
}
/// Interface for the subset of the [Emitter] that can be used during modular
/// code generation.
///
/// Note that the emission phase is not itself modular but performed on
/// the closed world computed by the codegen enqueuer.
abstract class ModularEmitter {
/// Returns the JS prototype of the given class [e].
jsAst.Expression prototypeAccess(ClassEntity e, {bool hasBeenInstantiated});
/// Returns the JS function representing the given function.
///
/// The function must be invoked and can not be used as closure.
jsAst.Expression staticFunctionAccess(FunctionEntity element);
jsAst.Expression staticFieldAccess(FieldEntity element);
/// Returns the JS function that must be invoked to get the value of the
/// lazily initialized static.
jsAst.Expression isolateLazyInitializerAccess(covariant FieldEntity element);
/// Returns the closure expression of a static function.
jsAst.Expression staticClosureAccess(covariant FunctionEntity element);
/// Returns the JS constructor of the given element.
///
/// The returned expression must only be used in a JS `new` expression.
jsAst.Expression constructorAccess(ClassEntity e);
/// Returns the JS expression representing the type [e].
jsAst.Expression typeAccess(Entity e);
/// Returns the JS code for accessing the embedded [global].
jsAst.Expression generateEmbeddedGlobalAccess(String global);
/// Returns the JS code for accessing the given [constant].
jsAst.Expression constantReference(ConstantValue constant);
/// Returns the JS code for accessing the global property [global].
String generateEmbeddedGlobalAccessString(String global);
}
/// Interface for the emitter that is used during the emission phase on the
/// closed world computed by the codegen enqueuer.
///
/// These methods are _not_ available during modular code generation.
abstract class Emitter implements ModularEmitter {
Program get programForTesting;
/// Uses the [programBuilder] to generate a model of the program, emits
/// the program, and returns the size of the generated output.
int emitProgram(ProgramBuilder programBuilder, CodegenWorld codegenWorld);
/// Returns the JS prototype of the given interceptor class [e].
jsAst.Expression interceptorPrototypeAccess(ClassEntity e);
/// Returns the JS constructor of the given interceptor class [e].
jsAst.Expression interceptorClassAccess(ClassEntity e);
/// Returns the JS expression representing a function that returns 'null'
jsAst.Expression generateFunctionThatReturnsNull();
int compareConstants(ConstantValue a, ConstantValue b);
bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant);
/// Returns the size of the code generated for a given output [unit].
int generatedSize(OutputUnit unit);
}