blob: 7972516c7543627ddc9d51e55523aedc4a6cf033 [file] [log] [blame]
// Copyright (c) 2018, 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.
import 'dart:async';
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/binary/ast_from_binary.dart' as ir;
import 'package:kernel/binary/ast_to_binary.dart' as ir;
import '../../compiler_api.dart' as api;
import '../commandline_options.dart' show Flags;
import '../common/codegen.dart';
import '../common/tasks.dart';
import '../deferred_load/output_unit.dart';
import '../diagnostics/diagnostic_listener.dart';
import '../dump_info.dart';
import '../elements/entities.dart';
import '../environment.dart';
import '../inferrer/abstract_value_domain.dart';
import '../inferrer/abstract_value_strategy.dart';
import '../inferrer/types.dart';
import '../io/source_information.dart';
import '../js_backend/codegen_inputs.dart';
import '../js_backend/inferred_data.dart';
import '../js_model/js_strategy.dart';
import '../js_model/js_world.dart';
import '../js_model/locals.dart';
import '../options.dart';
import 'deferrable.dart';
import 'serialization.dart';
class _StringInterner implements ir.StringInterner, StringInterner {
final Map<String, String> _map = {};
@override
String internString(String string) {
return _map[string] ??= string;
}
}
class SerializationTask extends CompilerTask {
final CompilerOptions _options;
final DiagnosticReporter _reporter;
final api.CompilerInput _provider;
final api.CompilerOutput _outputProvider;
final _stringInterner = _StringInterner();
final ValueInterner? _valueInterner;
SerializationTask(this._options, this._reporter, this._provider,
this._outputProvider, Measurer measurer)
: _valueInterner =
_options.features.internValues.isEnabled ? ValueInterner() : null,
super(measurer);
@override
String get name => 'Serialization';
void serializeComponent(ir.Component component,
{bool includeSourceBytes = true}) {
measureSubtask('serialize dill', () {
_reporter.log('Writing dill to ${_options.outputUri}');
api.BinaryOutputSink dillOutput =
_outputProvider.createBinarySink(_options.outputUri!);
ir.BinaryPrinter printer =
ir.BinaryPrinter(dillOutput, includeSourceBytes: includeSourceBytes);
printer.writeComponentFile(component);
dillOutput.close();
});
}
Future<ir.Component> deserializeComponent() async {
return measureIoSubtask('deserialize dill', () async {
_reporter.log('Reading dill from ${_options.inputDillUri}');
final dillInput = await _provider.readFromUri(_options.inputDillUri,
inputKind: api.InputKind.binary);
ir.Component component = ir.Component();
// Not using growable lists saves memory.
ir.BinaryBuilder(dillInput.data,
useGrowableLists: false, stringInterner: _stringInterner)
.readComponent(component);
return component;
});
}
void updateOptionsFromComponent(ir.Component component) {
var isStrongDill =
component.mode == ir.NonNullableByDefaultCompiledMode.Strong;
var incompatibleNullSafetyMode =
isStrongDill ? NullSafetyMode.unsound : NullSafetyMode.sound;
if (_options.nullSafetyMode == incompatibleNullSafetyMode) {
var dillMode = isStrongDill ? 'sound' : 'unsound';
var option =
isStrongDill ? Flags.noSoundNullSafety : Flags.soundNullSafety;
throw ArgumentError("${_options.inputDillUri} was compiled with "
"$dillMode null safety and is incompatible with the '$option' "
"option");
}
_options.nullSafetyMode =
component.mode == ir.NonNullableByDefaultCompiledMode.Strong
? NullSafetyMode.sound
: NullSafetyMode.unsound;
}
Future<ir.Component> deserializeComponentAndUpdateOptions() async {
ir.Component component = await deserializeComponent();
updateOptionsFromComponent(component);
return component;
}
void serializeClosedWorld(
JClosedWorld closedWorld, SerializationIndices indices) {
measureSubtask('serialize closed world', () {
final outputUri = _options.dataUriForStage(CompilerStage.closedWorld);
_reporter.log('Writing closed world to $outputUri');
api.BinaryOutputSink dataOutput =
_outputProvider.createBinarySink(outputUri);
DataSinkWriter sink =
DataSinkWriter(BinaryDataSink(dataOutput), _options, indices);
serializeClosedWorldToSink(closedWorld, sink);
});
}
Future<JClosedWorld> deserializeClosedWorld(
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
bool useDeferredSourceReads,
SerializationIndices indices) async {
return await measureIoSubtask('deserialize closed world', () async {
final uri = _options.dataUriForStage(CompilerStage.closedWorld);
_reporter.log('Reading data from $uri');
api.Input<List<int>> dataInput =
await _provider.readFromUri(uri, inputKind: api.InputKind.binary);
DataSourceReader source = DataSourceReader(
BinaryDataSource(dataInput.data, stringInterner: _stringInterner),
_options,
indices,
interner: _valueInterner,
useDeferredStrategy: useDeferredSourceReads);
var closedWorld = deserializeClosedWorldFromSource(
_options, _reporter, abstractValueStrategy, component, source);
return closedWorld;
});
}
void serializeGlobalTypeInference(
GlobalTypeInferenceResults results, SerializationIndices indices) {
measureSubtask('serialize data', () {
final outputUri = _options.dataUriForStage(CompilerStage.globalInference);
_reporter.log('Writing data to $outputUri');
api.BinaryOutputSink dataOutput =
_outputProvider.createBinarySink(outputUri);
DataSinkWriter sink =
DataSinkWriter(BinaryDataSink(dataOutput), _options, indices);
serializeGlobalTypeInferenceResultsToSink(results, sink);
});
}
Future<GlobalTypeInferenceResults> deserializeGlobalTypeInferenceResults(
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
JClosedWorld closedWorld,
bool useDeferredSourceReads,
SerializationIndices indices) async {
return await measureIoSubtask('deserialize data', () async {
final uri = _options.dataUriForStage(CompilerStage.globalInference);
_reporter.log('Reading data from $uri');
api.Input<List<int>> dataInput =
await _provider.readFromUri(uri, inputKind: api.InputKind.binary);
DataSourceReader source = DataSourceReader(
BinaryDataSource(dataInput.data, stringInterner: _stringInterner),
_options,
indices,
interner: _valueInterner,
useDeferredStrategy: useDeferredSourceReads);
return deserializeGlobalTypeInferenceResultsFromSource(
_options,
_reporter,
environment,
abstractValueStrategy,
component,
closedWorld,
source);
});
}
void serializeCodegen(
JsBackendStrategy backendStrategy,
AbstractValueDomain domain,
CodegenResults codegenResults,
SerializationIndices indices) {
int shard = _options.codegenShard!;
int shards = _options.codegenShards!;
Map<MemberEntity, CodegenResult> results = {};
int index = 0;
final lazyMemberBodies =
backendStrategy.forEachCodegenMember((MemberEntity member) {
if (index % shards == shard) {
final (result: codegenResult, isGenerated: _) =
codegenResults.getCodegenResults(member);
results[member] = codegenResult;
}
index++;
});
measureSubtask('serialize codegen', () {
final outputUri = _options.dataUriForStage(CompilerStage.codegenSharded);
Uri uri = Uri.parse('$outputUri$shard');
api.BinaryOutputSink dataOutput = _outputProvider.createBinarySink(uri);
DataSinkWriter sink =
DataSinkWriter(BinaryDataSink(dataOutput), _options, indices);
_reporter.log('Writing data to ${uri}');
sink.writeMembers(lazyMemberBodies);
sink.registerAbstractValueDomain(domain);
sink.writeMemberMap(results, (MemberEntity member, CodegenResult result) {
sink.writeDeferrable(() => result.writeToDataSink(sink));
});
sink.close();
});
}
Future<CodegenResults> deserializeCodegen(
JsBackendStrategy backendStrategy,
JClosedWorld closedWorld,
CodegenInputs codegenInputs,
bool useDeferredSourceReads,
SourceLookup sourceLookup,
SerializationIndices indices) async {
int shards = _options.codegenShards!;
Map<MemberEntity, Deferrable<CodegenResult>> results = {};
for (int shard = 0; shard < shards; shard++) {
Uri uri = Uri.parse(
'${_options.dataUriForStage(CompilerStage.codegenSharded)}$shard');
await measureIoSubtask('deserialize codegen', () async {
_reporter.log('Reading data from ${uri}');
api.Input<List<int>> dataInput =
await _provider.readFromUri(uri, inputKind: api.InputKind.binary);
// TODO(36983): This code is extracted because there appeared to be a
// memory leak for large buffer held by `source`.
_deserializeCodegenInput(backendStrategy, closedWorld, uri, dataInput,
results, useDeferredSourceReads, sourceLookup, indices);
dataInput.release();
});
}
return DeserializedCodegenResults(codegenInputs,
DeferrableValueMap(results), backendStrategy.functionCompiler);
}
void _deserializeCodegenInput(
JsBackendStrategy backendStrategy,
JClosedWorld closedWorld,
Uri uri,
api.Input<List<int>> dataInput,
Map<MemberEntity, Deferrable<CodegenResult>> results,
bool useDeferredSourceReads,
SourceLookup sourceLookup,
SerializationIndices indices) {
DataSourceReader source = DataSourceReader(
BinaryDataSource(dataInput.data, stringInterner: _stringInterner),
_options,
indices,
interner: _valueInterner,
useDeferredStrategy: useDeferredSourceReads);
backendStrategy.prepareCodegenReader(source);
source.registerSourceLookup(sourceLookup);
final lazyMemberBodies = source.readMembers();
closedWorld.elementMap.registerLazyMemberBodies(lazyMemberBodies);
source.registerAbstractValueDomain(closedWorld.abstractValueDomain);
Map<MemberEntity, Deferrable<CodegenResult>> codegenResults =
source.readMemberMap((MemberEntity member) {
return source.readDeferrable(CodegenResult.readFromDataSource,
cacheData: false);
});
_reporter.log('Read ${codegenResults.length} members from ${uri}');
results.addAll(codegenResults);
}
DataSinkWriter dataSinkWriterForDumpInfo(
AbstractValueDomain abstractValueDomain, SerializationIndices indices) {
final outputUri = _options.dataUriForStage(CompilerStage.dumpInfo);
api.BinaryOutputSink dataOutput =
_outputProvider.createBinarySink(outputUri);
final sink = DataSinkWriter(BinaryDataSink(dataOutput), _options, indices);
sink.registerAbstractValueDomain(abstractValueDomain);
return sink;
}
void serializeDumpInfoProgramData(
DataSinkWriter sink,
JsBackendStrategy backendStrategy,
DumpInfoProgramData dumpInfoProgramData,
DumpInfoJsAstRegistry dumpInfoRegistry) {
dumpInfoProgramData.writeToDataSink(sink, dumpInfoRegistry);
sink.close();
}
Future<DumpInfoProgramData> deserializeDumpInfoProgramData(
JsBackendStrategy backendStrategy,
AbstractValueDomain abstractValueDomain,
OutputUnitData outputUnitData,
SerializationIndices indices) async {
final inputUri = _options.dataUriForStage(CompilerStage.dumpInfo);
final dataInput =
await _provider.readFromUri(inputUri, inputKind: api.InputKind.binary);
final source = DataSourceReader(
BinaryDataSource(dataInput.data, stringInterner: _stringInterner),
_options,
indices,
// This must use a deferred strategy so that we can delay reading the
// registered impacts until we are able to read the count of them.
useDeferredStrategy: true);
backendStrategy.prepareCodegenReader(source);
source.registerAbstractValueDomain(abstractValueDomain);
return DumpInfoProgramData.readFromDataSource(source,
includeCodeText: !_options.useDumpInfoBinaryFormat);
}
}
void serializeGlobalTypeInferenceResultsToSink(
GlobalTypeInferenceResults results, DataSinkWriter sink) {
final closedWorld = results.closedWorld;
GlobalLocalsMap globalLocalsMap = results.globalLocalsMap;
InferredData inferredData = results.inferredData;
globalLocalsMap.writeToDataSink(sink);
inferredData.writeToDataSink(sink);
results.writeToDataSink(sink, closedWorld.elementMap);
sink.close();
}
GlobalTypeInferenceResults deserializeGlobalTypeInferenceResultsFromSource(
CompilerOptions options,
DiagnosticReporter reporter,
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
JClosedWorld closedWorld,
DataSourceReader source) {
source.registerComponentLookup(ComponentLookup(component));
GlobalLocalsMap globalLocalsMap = GlobalLocalsMap.readFromDataSource(
closedWorld.closureDataLookup.getEnclosingMember, source);
InferredData inferredData =
InferredData.readFromDataSource(source, closedWorld);
return GlobalTypeInferenceResults.readFromDataSource(source,
closedWorld.elementMap, closedWorld, globalLocalsMap, inferredData);
}
void serializeClosedWorldToSink(JClosedWorld closedWorld, DataSinkWriter sink) {
closedWorld.writeToDataSink(sink);
sink.close();
}
JClosedWorld deserializeClosedWorldFromSource(
CompilerOptions options,
DiagnosticReporter reporter,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
DataSourceReader source) {
return JClosedWorld.readFromDataSource(
options, reporter, abstractValueStrategy, component, source);
}