blob: 34e9ec02a0c88eab394aee031cf0d860610005b9 [file] [log] [blame]
// Copyright (c) 2015, 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;
import '../../../compiler_api.dart' as api;
import '../../common.dart';
import '../../common/codegen.dart';
import '../../constants/values.dart';
import '../../deferred_load/output_unit.dart' show OutputUnit;
import '../../dump_info.dart';
import '../../elements/entities.dart';
import '../../io/source_information.dart';
import '../../js/js.dart' as js;
import '../../js_backend/constant_emitter.dart';
import '../../js_backend/namer.dart';
import '../../js_backend/runtime_types_new.dart' show RecipeEncoder;
import '../../js_model/js_world.dart' show JClosedWorld;
import '../../options.dart';
import '../../universe/codegen_world_builder.dart' show CodegenWorld;
import '../js_emitter.dart' show CodeEmitterTask, Emitter, ModularEmitter;
import '../model.dart';
import '../native_emitter.dart';
import '../program_builder/program_builder.dart' show ProgramBuilder;
import 'fragment_merger.dart';
import 'model_emitter.dart';
abstract class ModularEmitterBase implements ModularEmitter {
final ModularNamer _namer;
ModularEmitterBase(this._namer);
js.PropertyAccess globalPropertyAccessForClass(ClassEntity element) {
js.Name name = _namer.globalPropertyNameForClass(element);
js.PropertyAccess pa = js.PropertyAccess(
_namer.readGlobalObjectForClass(element),
name,
);
return pa;
}
js.PropertyAccess globalPropertyAccessForMember(MemberEntity element) {
js.Name name = _namer.globalPropertyNameForMember(element);
js.PropertyAccess pa = js.PropertyAccess(
_namer.readGlobalObjectForMember(element),
name,
);
return pa;
}
@override
js.PropertyAccess constructorAccess(ClassEntity element) {
return globalPropertyAccessForClass(element);
}
@override
js.Expression isolateLazyInitializerAccess(FieldEntity element) {
return js.PropertyAccess(
_namer.readGlobalObjectForMember(element),
_namer.lazyInitializerName(element),
);
}
@override
js.PropertyAccess staticFunctionAccess(FunctionEntity element) {
return globalPropertyAccessForMember(element);
}
@override
js.PropertyAccess staticFieldAccess(FieldEntity element) {
return globalPropertyAccessForMember(element);
}
@override
js.PropertyAccess prototypeAccess(ClassEntity element) {
js.Expression constructor = constructorAccess(element);
return js.js('#.prototype', constructor) as js.PropertyAccess;
}
@override
js.Name typeAccessNewRti(ClassEntity element) {
return _namer.className(element);
}
@override
js.Name typeVariableAccessNewRti(TypeVariableEntity element) {
return _namer.globalNameForInterfaceTypeVariable(element);
}
@override
js.Expression staticClosureAccess(FunctionEntity element) {
return js.Call(
js.PropertyAccess(
_namer.readGlobalObjectForMember(element),
_namer.staticClosureName(element),
),
const [],
);
}
@override
String generateEmbeddedGlobalAccessString(String global) {
// TODO(floitsch): don't use 'init' as global embedder storage.
return 'init.$global';
}
}
class ModularEmitterImpl extends ModularEmitterBase {
final CodegenRegistry _registry;
final ModularConstantEmitter _constantEmitter;
ModularEmitterImpl(super.namer, this._registry, CompilerOptions options)
: _constantEmitter = ModularConstantEmitter(options, namer);
@override
js.Expression constantReference(ConstantValue constant) {
if (constant is FunctionConstantValue) {
return staticClosureAccess(constant.element);
}
js.Expression? expression = _constantEmitter.generate(constant);
if (expression != null) {
return expression;
}
final modularExpression = ModularExpression(
ModularExpressionKind.constant,
constant,
);
_registry.registerModularExpression(modularExpression);
return modularExpression;
}
@override
js.Expression generateEmbeddedGlobalAccess(String global) {
final expression = ModularExpression(
ModularExpressionKind.embeddedGlobalAccess,
global,
);
_registry.registerModularExpression(expression);
return expression;
}
}
class EmitterImpl extends ModularEmitterBase implements Emitter {
final DiagnosticReporter _reporter;
final JClosedWorld _closedWorld;
final RecipeEncoder _rtiRecipeEncoder;
final CodeEmitterTask _task;
late final ModelEmitter _emitter;
final NativeEmitter _nativeEmitter;
@override
Program? programForTesting;
@override
List<PreFragment>? preDeferredFragmentsForTesting;
@override
late final Set<OutputUnit> omittedOutputUnits;
@override
late final Map<String, List<FinalizedFragment>> finalizedFragmentsToLoad;
@override
late final FragmentMerger fragmentMerger;
EmitterImpl(
CompilerOptions options,
this._reporter,
api.CompilerOutput outputProvider,
DumpInfoJsAstRegistry dumpInfoRegistry,
Namer namer,
this._closedWorld,
this._rtiRecipeEncoder,
this._nativeEmitter,
SourceInformationStrategy sourceInformationStrategy,
this._task,
bool shouldGenerateSourceMap,
) : super(namer) {
_emitter = ModelEmitter(
options,
_reporter,
outputProvider,
dumpInfoRegistry,
namer,
_closedWorld,
_task,
this,
_nativeEmitter,
sourceInformationStrategy,
_rtiRecipeEncoder,
shouldGenerateSourceMap,
);
}
@override
int emitProgram(ProgramBuilder programBuilder, CodegenWorld codegenWorld) {
Program program = _task.measureSubtask('build program', () {
return programBuilder.buildProgram();
});
if (retainDataForTesting) {
programForTesting = program;
}
return _task.measureSubtask('emit program', () {
var size = _emitter.emitProgram(program, codegenWorld);
omittedOutputUnits = _emitter.omittedOutputUnits;
finalizedFragmentsToLoad = _emitter.finalizedFragmentsToLoad;
fragmentMerger = _emitter.fragmentMerger;
for (var fragments in finalizedFragmentsToLoad.values) {
_task.emitterMetrics.hunkListElements.add(fragments.length);
}
if (retainDataForTesting) {
preDeferredFragmentsForTesting =
_emitter.preDeferredFragmentsForTesting;
}
return size;
});
}
@override
js.Expression interceptorClassAccess(ClassEntity element) {
return globalPropertyAccessForClass(element);
}
@override
bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) {
return _emitter.isConstantInlinedOrAlreadyEmitted(constant);
}
@override
int compareConstants(ConstantValue a, ConstantValue b) {
return _emitter.compareConstants(a, b);
}
@override
js.Expression constantReference(ConstantValue value) {
return _emitter.generateConstantReference(value);
}
@override
js.Expression generateEmbeddedGlobalAccess(String global) {
return js.js(generateEmbeddedGlobalAccessString(global));
}
@override
// TODO(herhut): Use a single shared function.
js.Expression generateFunctionThatReturnsNull() {
return js.js('function() {}');
}
@override
js.Expression interceptorPrototypeAccess(ClassEntity e) {
return js.js('#.prototype', interceptorClassAccess(e));
}
@override
Map<OutputUnit, int> get generatedSizes {
final mappedSizes = <OutputUnit, int>{};
_emitter.emittedOutputSizes.forEach((outputUnit, dataLength) {
mappedSizes[outputUnit] = dataLength;
});
for (var outputUnit in _emitter.omittedOutputUnits) {
mappedSizes[outputUnit] = 0;
}
return mappedSizes;
}
}