[dart2js] Break out closed world computation from global inference step.

Change-Id: Id743ad11344e94ebc56f732d5580c33ae8e45e46
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/169123
Commit-Queue: Joshua Litt <joshualitt@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Joshua Litt 2020-11-09 21:35:14 +00:00 committed by commit-bot@chromium.org
parent 8df5e31bbc
commit cfccd80ef7
8 changed files with 460 additions and 91 deletions

View file

@ -104,6 +104,8 @@ class Flags {
static const String dillDependencies = '--dill-dependencies'; static const String dillDependencies = '--dill-dependencies';
static const String readData = '--read-data'; static const String readData = '--read-data';
static const String writeData = '--write-data'; static const String writeData = '--write-data';
static const String writeClosedWorld = '--write-closed-world';
static const String readClosedWorld = '--read-closed-world';
static const String readCodegen = '--read-codegen'; static const String readCodegen = '--read-codegen';
static const String writeCodegen = '--write-codegen'; static const String writeCodegen = '--write-codegen';
static const String codegenShard = '--codegen-shard'; static const String codegenShard = '--codegen-shard';

View file

@ -8,6 +8,7 @@ import 'dart:async' show Future;
import 'package:front_end/src/api_unstable/dart2js.dart' import 'package:front_end/src/api_unstable/dart2js.dart'
show clearStringTokenCanonicalizer; show clearStringTokenCanonicalizer;
import 'package:kernel/ast.dart' as ir;
import '../compiler_new.dart' as api; import '../compiler_new.dart' as api;
import 'backend_strategy.dart'; import 'backend_strategy.dart';
@ -37,6 +38,7 @@ import 'io/source_information.dart' show SourceInformation;
import 'js_backend/backend.dart' show CodegenInputs, JavaScriptImpactStrategy; import 'js_backend/backend.dart' show CodegenInputs, JavaScriptImpactStrategy;
import 'js_backend/inferred_data.dart'; import 'js_backend/inferred_data.dart';
import 'js_model/js_strategy.dart'; import 'js_model/js_strategy.dart';
import 'js_model/js_world.dart';
import 'kernel/kernel_strategy.dart'; import 'kernel/kernel_strategy.dart';
import 'kernel/loader.dart' show KernelLoaderTask, KernelResult; import 'kernel/loader.dart' show KernelLoaderTask, KernelResult;
import 'null_compiler_output.dart' show NullCompilerOutput; import 'null_compiler_output.dart' show NullCompilerOutput;
@ -231,10 +233,23 @@ abstract class Compiler {
Future runInternal(Uri uri) async { Future runInternal(Uri uri) async {
clearState(); clearState();
assert(uri != null); assert(uri != null);
// As far as I can tell, this branch is only used by test code.
reporter.log('Compiling $uri (${options.buildId})'); reporter.log('Compiling $uri (${options.buildId})');
if (options.readDataUri != null) { if (options.readClosedWorldUri != null) {
ir.Component component =
await serializationTask.deserializeComponentAndUpdateOptions();
JsClosedWorld closedWorld =
await serializationTask.deserializeClosedWorld(
environment, abstractValueStrategy, component);
GlobalTypeInferenceResults globalTypeInferenceResults =
performGlobalTypeInference(closedWorld);
if (options.writeDataUri != null) {
serializationTask
.serializeGlobalTypeInference(globalTypeInferenceResults);
return;
}
await generateJavaScriptCode(globalTypeInferenceResults);
} else if (options.readDataUri != null) {
GlobalTypeInferenceResults globalTypeInferenceResults = GlobalTypeInferenceResults globalTypeInferenceResults =
await serializationTask.deserializeGlobalTypeInference( await serializationTask.deserializeGlobalTypeInference(
environment, abstractValueStrategy); environment, abstractValueStrategy);
@ -362,9 +377,6 @@ abstract class Compiler {
JClosedWorld closedWorld = JClosedWorld closedWorld =
closeResolution(mainFunction, resolutionEnqueuer.worldBuilder); closeResolution(mainFunction, resolutionEnqueuer.worldBuilder);
if (retainDataForTesting) {
backendClosedWorldForTesting = closedWorld;
}
return closedWorld; return closedWorld;
} }
@ -409,37 +421,50 @@ abstract class Compiler {
checkQueue(codegenEnqueuer); checkQueue(codegenEnqueuer);
} }
GlobalTypeInferenceResults globalTypeInferenceResultsTestMode(
GlobalTypeInferenceResults results) {
SerializationStrategy strategy = const BytesInMemorySerializationStrategy();
List<int> irData = strategy.unpackAndSerializeComponent(results);
List worldData = strategy.serializeGlobalTypeInferenceResults(results);
return strategy.deserializeGlobalTypeInferenceResults(
options,
reporter,
environment,
abstractValueStrategy,
strategy.deserializeComponent(irData),
worldData);
}
void compileFromKernel(Uri rootLibraryUri, Iterable<Uri> libraries) { void compileFromKernel(Uri rootLibraryUri, Iterable<Uri> libraries) {
_userCodeLocations.add(new CodeLocation(rootLibraryUri)); _userCodeLocations.add(new CodeLocation(rootLibraryUri));
selfTask.measureSubtask("compileFromKernel", () { selfTask.measureSubtask("compileFromKernel", () {
JClosedWorld closedWorld = selfTask.measureSubtask("computeClosedWorld", JsClosedWorld closedWorld = selfTask.measureSubtask("computeClosedWorld",
() => computeClosedWorld(rootLibraryUri, libraries)); () => computeClosedWorld(rootLibraryUri, libraries));
if (stopAfterClosedWorld) return; if (closedWorld == null) return;
if (closedWorld != null) {
GlobalTypeInferenceResults globalInferenceResults = if (retainDataForTesting) {
performGlobalTypeInference(closedWorld); backendClosedWorldForTesting = closedWorld;
if (options.writeDataUri != null) {
serializationTask
.serializeGlobalTypeInference(globalInferenceResults);
return;
}
if (options.testMode) {
SerializationStrategy strategy =
const BytesInMemorySerializationStrategy();
List<int> irData =
strategy.serializeComponent(globalInferenceResults);
List worldData = strategy.serializeData(globalInferenceResults);
globalInferenceResults = strategy.deserializeData(
options,
reporter,
environment,
abstractValueStrategy,
strategy.deserializeComponent(irData),
worldData);
}
if (stopAfterTypeInference) return;
generateJavaScriptCode(globalInferenceResults);
} }
if (options.writeClosedWorldUri != null) {
serializationTask.serializeComponent(
closedWorld.elementMap.programEnv.mainComponent);
serializationTask.serializeClosedWorld(closedWorld);
return;
}
if (stopAfterClosedWorld) return;
GlobalTypeInferenceResults globalInferenceResults =
performGlobalTypeInference(closedWorld);
if (options.writeDataUri != null) {
serializationTask.serializeGlobalTypeInference(globalInferenceResults);
return;
}
if (options.testMode) {
globalInferenceResults =
globalTypeInferenceResultsTestMode(globalInferenceResults);
}
if (stopAfterTypeInference) return;
generateJavaScriptCode(globalInferenceResults);
}); });
} }

View file

@ -107,6 +107,8 @@ Future<api.CompilationResult> compile(List<String> argv,
Uri sourceMapOut; Uri sourceMapOut;
Uri readDataUri; Uri readDataUri;
Uri writeDataUri; Uri writeDataUri;
Uri readClosedWorldUri;
Uri writeClosedWorldUri;
Uri readCodegenUri; Uri readCodegenUri;
Uri writeCodegenUri; Uri writeCodegenUri;
int codegenShard; int codegenShard;
@ -267,6 +269,14 @@ Future<api.CompilationResult> compile(List<String> argv,
} }
} }
void setReadClosedWorld(String argument) {
if (argument != Flags.readClosedWorld) {
readClosedWorldUri =
fe.nativeToUri(extractPath(argument, isDirectory: false));
}
readStrategy = ReadStrategy.fromClosedWorld;
}
void setDillDependencies(String argument) { void setDillDependencies(String argument) {
String dependencies = extractParameter(argument); String dependencies = extractParameter(argument);
String uriDependencies = dependencies.splitMapJoin(',', String uriDependencies = dependencies.splitMapJoin(',',
@ -299,6 +309,9 @@ Future<api.CompilationResult> compile(List<String> argv,
fail("Cannot use ${Flags.cfeOnly} " fail("Cannot use ${Flags.cfeOnly} "
"and write serialized data simultaneously."); "and write serialized data simultaneously.");
} }
if (writeStrategy == WriteStrategy.toClosedWorld) {
fail("Cannot write closed world and data simultaneously.");
}
if (writeStrategy == WriteStrategy.toCodegen) { if (writeStrategy == WriteStrategy.toCodegen) {
fail("Cannot write serialized data and codegen simultaneously."); fail("Cannot write serialized data and codegen simultaneously.");
} }
@ -308,11 +321,32 @@ Future<api.CompilationResult> compile(List<String> argv,
writeStrategy = WriteStrategy.toData; writeStrategy = WriteStrategy.toData;
} }
void setWriteClosedWorld(String argument) {
if (writeStrategy == WriteStrategy.toKernel) {
fail("Cannot use ${Flags.cfeOnly} "
"and write serialized data simultaneously.");
}
if (writeStrategy == WriteStrategy.toData) {
fail("Cannot write both closed world and data");
}
if (writeStrategy == WriteStrategy.toCodegen) {
fail("Cannot write serialized data and codegen simultaneously.");
}
if (argument != Flags.writeClosedWorld) {
writeClosedWorldUri =
fe.nativeToUri(extractPath(argument, isDirectory: false));
}
writeStrategy = WriteStrategy.toClosedWorld;
}
void setWriteCodegen(String argument) { void setWriteCodegen(String argument) {
if (writeStrategy == WriteStrategy.toKernel) { if (writeStrategy == WriteStrategy.toKernel) {
fail("Cannot use ${Flags.cfeOnly} " fail("Cannot use ${Flags.cfeOnly} "
"and write serialized codegen simultaneously."); "and write serialized codegen simultaneously.");
} }
if (writeStrategy == WriteStrategy.toClosedWorld) {
fail("Cannot write closed world and codegen simultaneously.");
}
if (writeStrategy == WriteStrategy.toData) { if (writeStrategy == WriteStrategy.toData) {
fail("Cannot write serialized data and codegen data simultaneously."); fail("Cannot write serialized data and codegen data simultaneously.");
} }
@ -415,6 +449,10 @@ Future<api.CompilationResult> compile(List<String> argv,
new OptionHandler('${Flags.dillDependencies}=.+', setDillDependencies), new OptionHandler('${Flags.dillDependencies}=.+', setDillDependencies),
new OptionHandler('${Flags.readData}|${Flags.readData}=.+', setReadData), new OptionHandler('${Flags.readData}|${Flags.readData}=.+', setReadData),
new OptionHandler('${Flags.writeData}|${Flags.writeData}=.+', setWriteData), new OptionHandler('${Flags.writeData}|${Flags.writeData}=.+', setWriteData),
new OptionHandler('${Flags.readClosedWorld}|${Flags.readClosedWorld}=.+',
setReadClosedWorld),
new OptionHandler('${Flags.writeClosedWorld}|${Flags.writeClosedWorld}=.+',
setWriteClosedWorld),
new OptionHandler( new OptionHandler(
'${Flags.readCodegen}|${Flags.readCodegen}=.+', setReadCodegen), '${Flags.readCodegen}|${Flags.readCodegen}=.+', setReadCodegen),
new OptionHandler( new OptionHandler(
@ -614,6 +652,19 @@ Future<api.CompilationResult> compile(List<String> argv,
"and read serialized codegen simultaneously."); "and read serialized codegen simultaneously.");
} }
break; break;
case WriteStrategy.toClosedWorld:
out ??= Uri.base.resolve('out.dill');
writeClosedWorldUri ??= Uri.base.resolve('$out.world');
options.add('${Flags.writeClosedWorld}=${writeClosedWorldUri}');
if (readStrategy == ReadStrategy.fromClosedWorld) {
fail("Cannot read and write serialized data simultaneously.");
} else if (readStrategy == ReadStrategy.fromData) {
fail("Cannot read from both closed world and data");
} else if (readStrategy == ReadStrategy.fromCodegen) {
fail("Cannot read serialized codegen and "
"write serialized data simultaneously.");
}
break;
case WriteStrategy.toData: case WriteStrategy.toData:
out ??= Uri.base.resolve('out.dill'); out ??= Uri.base.resolve('out.dill');
writeDataUri ??= Uri.base.resolve('$out.data'); writeDataUri ??= Uri.base.resolve('$out.data');
@ -657,6 +708,10 @@ Future<api.CompilationResult> compile(List<String> argv,
switch (readStrategy) { switch (readStrategy) {
case ReadStrategy.fromDart: case ReadStrategy.fromDart:
break; break;
case ReadStrategy.fromClosedWorld:
readClosedWorldUri ??= Uri.base.resolve('$scriptName.world');
options.add('${Flags.readClosedWorld}=${readClosedWorldUri}');
break;
case ReadStrategy.fromData: case ReadStrategy.fromData:
readDataUri ??= Uri.base.resolve('$scriptName.data'); readDataUri ??= Uri.base.resolve('$scriptName.data');
options.add('${Flags.readData}=${readDataUri}'); options.add('${Flags.readData}=${readDataUri}');
@ -673,6 +728,7 @@ Future<api.CompilationResult> compile(List<String> argv,
fail("${Flags.codegenShards} must be a positive integer."); fail("${Flags.codegenShards} must be a positive integer.");
} }
options.add('${Flags.codegenShards}=$codegenShards'); options.add('${Flags.codegenShards}=$codegenShards');
break;
} }
options.add('--out=$out'); options.add('--out=$out');
if (writeStrategy == WriteStrategy.toJs) { if (writeStrategy == WriteStrategy.toJs) {
@ -707,6 +763,13 @@ Future<api.CompilationResult> compile(List<String> argv,
inputSize = inputProvider.dartCharactersRead; inputSize = inputProvider.dartCharactersRead;
summary = 'Dart file $input '; summary = 'Dart file $input ';
break; break;
case ReadStrategy.fromClosedWorld:
inputName = 'bytes data';
inputSize = inputProvider.dartCharactersRead;
String dataInput =
fe.relativizeUri(Uri.base, readClosedWorldUri, Platform.isWindows);
summary = 'Data files $input and $dataInput ';
break;
case ReadStrategy.fromData: case ReadStrategy.fromData:
inputName = 'bytes data'; inputName = 'bytes data';
inputSize = inputProvider.dartCharactersRead; inputSize = inputProvider.dartCharactersRead;
@ -742,6 +805,15 @@ Future<api.CompilationResult> compile(List<String> argv,
String output = fe.relativizeUri(Uri.base, out, Platform.isWindows); String output = fe.relativizeUri(Uri.base, out, Platform.isWindows);
summary += 'compiled to dill: ${output}.'; summary += 'compiled to dill: ${output}.';
break; break;
case WriteStrategy.toClosedWorld:
processName = 'Serialized';
outputName = 'bytes data';
outputSize = outputProvider.totalDataWritten;
String output = fe.relativizeUri(Uri.base, out, Platform.isWindows);
String dataOutput =
fe.relativizeUri(Uri.base, writeClosedWorldUri, Platform.isWindows);
summary += 'serialized to dill and data: ${output} and ${dataOutput}.';
break;
case WriteStrategy.toData: case WriteStrategy.toData:
processName = 'Serialized'; processName = 'Serialized';
outputName = 'bytes data'; outputName = 'bytes data';
@ -1235,5 +1307,5 @@ void batchMain(List<String> batchArguments) {
}); });
} }
enum ReadStrategy { fromDart, fromData, fromCodegen } enum ReadStrategy { fromDart, fromClosedWorld, fromData, fromCodegen }
enum WriteStrategy { toKernel, toData, toCodegen, toJs } enum WriteStrategy { toKernel, toClosedWorld, toData, toCodegen, toJs }

View file

@ -77,6 +77,17 @@ class CompilerOptions implements DiagnosticOptions {
/// If this is set, the compilation stops after type inference. /// If this is set, the compilation stops after type inference.
Uri writeDataUri; Uri writeDataUri;
/// Location from which the serialized closed world is read.
///
/// If this is set, the [entryPoint] is expected to be a .dill file and the
/// frontend work is skipped.
Uri readClosedWorldUri;
/// Location to which inference data is serialized.
///
/// If this is set, the compilation stops after computing the closed world.
Uri writeClosedWorldUri;
/// Location from which codegen data is read. /// Location from which codegen data is read.
/// ///
/// If this is set, the compilation starts at codegen enqueueing. /// If this is set, the compilation starts at codegen enqueueing.
@ -497,6 +508,10 @@ class CompilerOptions implements DiagnosticOptions {
_extractUriListOption(options, '${Flags.dillDependencies}') _extractUriListOption(options, '${Flags.dillDependencies}')
..readDataUri = _extractUriOption(options, '${Flags.readData}=') ..readDataUri = _extractUriOption(options, '${Flags.readData}=')
..writeDataUri = _extractUriOption(options, '${Flags.writeData}=') ..writeDataUri = _extractUriOption(options, '${Flags.writeData}=')
..readClosedWorldUri =
_extractUriOption(options, '${Flags.readClosedWorld}=')
..writeClosedWorldUri =
_extractUriOption(options, '${Flags.writeClosedWorld}=')
..readCodegenUri = _extractUriOption(options, '${Flags.readCodegen}=') ..readCodegenUri = _extractUriOption(options, '${Flags.readCodegen}=')
..writeCodegenUri = _extractUriOption(options, '${Flags.writeCodegen}=') ..writeCodegenUri = _extractUriOption(options, '${Flags.writeCodegen}=')
..codegenShard = _extractIntOption(options, '${Flags.codegenShard}=') ..codegenShard = _extractIntOption(options, '${Flags.codegenShard}=')

View file

@ -24,13 +24,18 @@ import 'task.dart';
abstract class SerializationStrategy<T> { abstract class SerializationStrategy<T> {
const SerializationStrategy(); const SerializationStrategy();
List<int> serializeComponent(GlobalTypeInferenceResults results) { List<int> unpackAndSerializeComponent(GlobalTypeInferenceResults results) {
JsClosedWorld closedWorld = results.closedWorld; JsClosedWorld closedWorld = results.closedWorld;
ir.Component component = closedWorld.elementMap.programEnv.mainComponent; ir.Component component = closedWorld.elementMap.programEnv.mainComponent;
return ir.serializeComponent(component); return serializeComponent(component);
} }
List<T> serializeData(GlobalTypeInferenceResults results); List<T> serializeGlobalTypeInferenceResults(
GlobalTypeInferenceResults results);
List<int> serializeComponent(ir.Component component) {
return ir.serializeComponent(component);
}
ir.Component deserializeComponent(List<int> data) { ir.Component deserializeComponent(List<int> data) {
ir.Component component = new ir.Component(); ir.Component component = new ir.Component();
@ -38,7 +43,17 @@ abstract class SerializationStrategy<T> {
return component; return component;
} }
GlobalTypeInferenceResults deserializeData( GlobalTypeInferenceResults deserializeGlobalTypeInferenceResults(
CompilerOptions options,
DiagnosticReporter reporter,
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
List<T> data);
List<T> serializeClosedWorld(JsClosedWorld closedWorld);
JsClosedWorld deserializeClosedWorld(
CompilerOptions options, CompilerOptions options,
DiagnosticReporter reporter, DiagnosticReporter reporter,
Environment environment, Environment environment,
@ -53,15 +68,16 @@ class BytesInMemorySerializationStrategy extends SerializationStrategy<int> {
const BytesInMemorySerializationStrategy({this.useDataKinds: false}); const BytesInMemorySerializationStrategy({this.useDataKinds: false});
@override @override
List<int> serializeData(GlobalTypeInferenceResults results) { List<int> serializeGlobalTypeInferenceResults(
GlobalTypeInferenceResults results) {
ByteSink byteSink = new ByteSink(); ByteSink byteSink = new ByteSink();
DataSink sink = new BinarySink(byteSink, useDataKinds: useDataKinds); DataSink sink = new BinarySink(byteSink, useDataKinds: useDataKinds);
serializeGlobalTypeInferenceResults(results, sink); serializeGlobalTypeInferenceResultsToSink(results, sink);
return byteSink.builder.takeBytes(); return byteSink.builder.takeBytes();
} }
@override @override
GlobalTypeInferenceResults deserializeData( GlobalTypeInferenceResults deserializeGlobalTypeInferenceResults(
CompilerOptions options, CompilerOptions options,
DiagnosticReporter reporter, DiagnosticReporter reporter,
Environment environment, Environment environment,
@ -69,7 +85,28 @@ class BytesInMemorySerializationStrategy extends SerializationStrategy<int> {
ir.Component component, ir.Component component,
List<int> data) { List<int> data) {
DataSource source = new BinarySourceImpl(data, useDataKinds: useDataKinds); DataSource source = new BinarySourceImpl(data, useDataKinds: useDataKinds);
return deserializeGlobalTypeInferenceResults(options, reporter, environment, return deserializeGlobalTypeInferenceResultsFromSource(options, reporter,
environment, abstractValueStrategy, component, source);
}
@override
List<int> serializeClosedWorld(JsClosedWorld closedWorld) {
ByteSink byteSink = new ByteSink();
DataSink sink = new BinarySink(byteSink, useDataKinds: useDataKinds);
serializeClosedWorldToSink(closedWorld, sink);
return byteSink.builder.takeBytes();
}
@override
JsClosedWorld deserializeClosedWorld(
CompilerOptions options,
DiagnosticReporter reporter,
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
List<int> data) {
DataSource source = new BinarySourceImpl(data, useDataKinds: useDataKinds);
return deserializeClosedWorldFromSource(options, reporter, environment,
abstractValueStrategy, component, source); abstractValueStrategy, component, source);
} }
} }
@ -80,17 +117,18 @@ class BytesOnDiskSerializationStrategy extends SerializationStrategy<int> {
const BytesOnDiskSerializationStrategy({this.useDataKinds: false}); const BytesOnDiskSerializationStrategy({this.useDataKinds: false});
@override @override
List<int> serializeData(GlobalTypeInferenceResults results) { List<int> serializeGlobalTypeInferenceResults(
GlobalTypeInferenceResults results) {
Uri uri = Uri.base.resolve('world.data'); Uri uri = Uri.base.resolve('world.data');
DataSink sink = new BinarySink( DataSink sink = new BinarySink(
new BinaryOutputSinkAdapter(new RandomAccessBinaryOutputSink(uri)), new BinaryOutputSinkAdapter(new RandomAccessBinaryOutputSink(uri)),
useDataKinds: useDataKinds); useDataKinds: useDataKinds);
serializeGlobalTypeInferenceResults(results, sink); serializeGlobalTypeInferenceResultsToSink(results, sink);
return new File.fromUri(uri).readAsBytesSync(); return new File.fromUri(uri).readAsBytesSync();
} }
@override @override
GlobalTypeInferenceResults deserializeData( GlobalTypeInferenceResults deserializeGlobalTypeInferenceResults(
CompilerOptions options, CompilerOptions options,
DiagnosticReporter reporter, DiagnosticReporter reporter,
Environment environment, Environment environment,
@ -98,7 +136,30 @@ class BytesOnDiskSerializationStrategy extends SerializationStrategy<int> {
ir.Component component, ir.Component component,
List<int> data) { List<int> data) {
DataSource source = new BinarySourceImpl(data, useDataKinds: useDataKinds); DataSource source = new BinarySourceImpl(data, useDataKinds: useDataKinds);
return deserializeGlobalTypeInferenceResults(options, reporter, environment, return deserializeGlobalTypeInferenceResultsFromSource(options, reporter,
environment, abstractValueStrategy, component, source);
}
@override
List<int> serializeClosedWorld(JsClosedWorld closedWorld) {
Uri uri = Uri.base.resolve('closed_world.data');
DataSink sink = new BinarySink(
new BinaryOutputSinkAdapter(new RandomAccessBinaryOutputSink(uri)),
useDataKinds: useDataKinds);
serializeClosedWorldToSink(closedWorld, sink);
return new File.fromUri(uri).readAsBytesSync();
}
@override
JsClosedWorld deserializeClosedWorld(
CompilerOptions options,
DiagnosticReporter reporter,
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
List<int> data) {
DataSource source = new BinarySourceImpl(data, useDataKinds: useDataKinds);
return deserializeClosedWorldFromSource(options, reporter, environment,
abstractValueStrategy, component, source); abstractValueStrategy, component, source);
} }
} }
@ -110,15 +171,16 @@ class ObjectsInMemorySerializationStrategy
const ObjectsInMemorySerializationStrategy({this.useDataKinds: true}); const ObjectsInMemorySerializationStrategy({this.useDataKinds: true});
@override @override
List<Object> serializeData(GlobalTypeInferenceResults results) { List<Object> serializeGlobalTypeInferenceResults(
GlobalTypeInferenceResults results) {
List<Object> data = []; List<Object> data = [];
DataSink sink = new ObjectSink(data, useDataKinds: useDataKinds); DataSink sink = new ObjectSink(data, useDataKinds: useDataKinds);
serializeGlobalTypeInferenceResults(results, sink); serializeGlobalTypeInferenceResultsToSink(results, sink);
return data; return data;
} }
@override @override
GlobalTypeInferenceResults deserializeData( GlobalTypeInferenceResults deserializeGlobalTypeInferenceResults(
CompilerOptions options, CompilerOptions options,
DiagnosticReporter reporter, DiagnosticReporter reporter,
Environment environment, Environment environment,
@ -126,7 +188,28 @@ class ObjectsInMemorySerializationStrategy
ir.Component component, ir.Component component,
List<Object> data) { List<Object> data) {
DataSource source = new ObjectSource(data, useDataKinds: useDataKinds); DataSource source = new ObjectSource(data, useDataKinds: useDataKinds);
return deserializeGlobalTypeInferenceResults(options, reporter, environment, return deserializeGlobalTypeInferenceResultsFromSource(options, reporter,
environment, abstractValueStrategy, component, source);
}
@override
List<Object> serializeClosedWorld(JsClosedWorld closedWorld) {
List<Object> data = [];
DataSink sink = new ObjectSink(data, useDataKinds: useDataKinds);
serializeClosedWorldToSink(closedWorld, sink);
return data;
}
@override
JsClosedWorld deserializeClosedWorld(
CompilerOptions options,
DiagnosticReporter reporter,
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
List<Object> data) {
DataSource source = new ObjectSource(data, useDataKinds: useDataKinds);
return deserializeClosedWorldFromSource(options, reporter, environment,
abstractValueStrategy, component, source); abstractValueStrategy, component, source);
} }
} }

View file

@ -24,7 +24,7 @@ import '../util/sink_adapter.dart';
import '../world.dart'; import '../world.dart';
import 'serialization.dart'; import 'serialization.dart';
void serializeGlobalTypeInferenceResults( void serializeGlobalTypeInferenceResultsToSink(
GlobalTypeInferenceResults results, DataSink sink) { GlobalTypeInferenceResults results, DataSink sink) {
JsClosedWorld closedWorld = results.closedWorld; JsClosedWorld closedWorld = results.closedWorld;
InferredData inferredData = results.inferredData; InferredData inferredData = results.inferredData;
@ -34,7 +34,7 @@ void serializeGlobalTypeInferenceResults(
sink.close(); sink.close();
} }
GlobalTypeInferenceResults deserializeGlobalTypeInferenceResults( GlobalTypeInferenceResults deserializeGlobalTypeInferenceResultsFromSource(
CompilerOptions options, CompilerOptions options,
DiagnosticReporter reporter, DiagnosticReporter reporter,
Environment environment, Environment environment,
@ -49,6 +49,22 @@ GlobalTypeInferenceResults deserializeGlobalTypeInferenceResults(
source, newClosedWorld.elementMap, newClosedWorld, newInferredData); source, newClosedWorld.elementMap, newClosedWorld, newInferredData);
} }
void serializeClosedWorldToSink(JsClosedWorld closedWorld, DataSink sink) {
closedWorld.writeToDataSink(sink);
sink.close();
}
JsClosedWorld deserializeClosedWorldFromSource(
CompilerOptions options,
DiagnosticReporter reporter,
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
DataSource source) {
return new JsClosedWorld.readFromDataSource(
options, reporter, environment, abstractValueStrategy, component, source);
}
class SerializationTask extends CompilerTask { class SerializationTask extends CompilerTask {
final CompilerOptions _options; final CompilerOptions _options;
final DiagnosticReporter _reporter; final DiagnosticReporter _reporter;
@ -62,7 +78,7 @@ class SerializationTask extends CompilerTask {
@override @override
String get name => 'Serialization'; String get name => 'Serialization';
void serializeGlobalTypeInference(GlobalTypeInferenceResults results) { void serializeComponent(ir.Component component) {
measureSubtask('serialize dill', () { measureSubtask('serialize dill', () {
// TODO(sigmund): remove entirely: we will do this immediately as soon as // TODO(sigmund): remove entirely: we will do this immediately as soon as
// we get the component in the kernel/loader.dart task once we refactor // we get the component in the kernel/loader.dart task once we refactor
@ -70,28 +86,15 @@ class SerializationTask extends CompilerTask {
_reporter.log('Writing dill to ${_options.outputUri}'); _reporter.log('Writing dill to ${_options.outputUri}');
api.BinaryOutputSink dillOutput = api.BinaryOutputSink dillOutput =
_outputProvider.createBinarySink(_options.outputUri); _outputProvider.createBinarySink(_options.outputUri);
JsClosedWorld closedWorld = results.closedWorld;
ir.Component component = closedWorld.elementMap.programEnv.mainComponent;
BinaryOutputSinkAdapter irSink = new BinaryOutputSinkAdapter(dillOutput); BinaryOutputSinkAdapter irSink = new BinaryOutputSinkAdapter(dillOutput);
ir.BinaryPrinter printer = new ir.BinaryPrinter(irSink); ir.BinaryPrinter printer = new ir.BinaryPrinter(irSink);
printer.writeComponentFile(component); printer.writeComponentFile(component);
irSink.close(); irSink.close();
}); });
measureSubtask('serialize data', () {
_reporter.log('Writing data to ${_options.writeDataUri}');
api.BinaryOutputSink dataOutput =
_outputProvider.createBinarySink(_options.writeDataUri);
DataSink sink = new BinarySink(new BinaryOutputSinkAdapter(dataOutput));
serializeGlobalTypeInferenceResults(results, sink);
});
} }
Future<GlobalTypeInferenceResults> deserializeGlobalTypeInference( Future<ir.Component> deserializeComponent() async {
Environment environment, return measureIoSubtask('deserialize dill', () async {
AbstractValueStrategy abstractValueStrategy) async {
ir.Component component =
await measureIoSubtask('deserialize dill', () async {
_reporter.log('Reading dill from ${_options.entryPoint}'); _reporter.log('Reading dill from ${_options.entryPoint}');
api.Input<List<int>> dillInput = await _provider api.Input<List<int>> dillInput = await _provider
.readFromUri(_options.entryPoint, inputKind: api.InputKind.binary); .readFromUri(_options.entryPoint, inputKind: api.InputKind.binary);
@ -99,7 +102,9 @@ class SerializationTask extends CompilerTask {
new ir.BinaryBuilder(dillInput.data).readComponent(component); new ir.BinaryBuilder(dillInput.data).readComponent(component);
return component; return component;
}); });
}
void updateOptionsFromComponent(ir.Component component) {
var isStrongDill = var isStrongDill =
component.mode == ir.NonNullableByDefaultCompiledMode.Strong; component.mode == ir.NonNullableByDefaultCompiledMode.Strong;
var incompatibleNullSafetyMode = var incompatibleNullSafetyMode =
@ -118,14 +123,65 @@ class SerializationTask extends CompilerTask {
} else { } else {
_options.nullSafetyMode = NullSafetyMode.unsound; _options.nullSafetyMode = NullSafetyMode.unsound;
} }
}
Future<ir.Component> deserializeComponentAndUpdateOptions() async {
ir.Component component = await deserializeComponent();
updateOptionsFromComponent(component);
return component;
}
void serializeClosedWorld(JsClosedWorld closedWorld) {
measureSubtask('serialize closed world', () {
_reporter.log('Writing closed world to ${_options.writeClosedWorldUri}');
api.BinaryOutputSink dataOutput =
_outputProvider.createBinarySink(_options.writeClosedWorldUri);
DataSink sink = new BinarySink(new BinaryOutputSinkAdapter(dataOutput));
serializeClosedWorldToSink(closedWorld, sink);
});
}
Future<JsClosedWorld> deserializeClosedWorld(
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component) async {
return await measureIoSubtask('deserialize closed world', () async {
_reporter.log('Reading data from ${_options.readClosedWorldUri}');
api.Input<List<int>> dataInput = await _provider.readFromUri(
_options.readClosedWorldUri,
inputKind: api.InputKind.binary);
DataSource source = new BinarySourceImpl(dataInput.data);
return deserializeClosedWorldFromSource(_options, _reporter, environment,
abstractValueStrategy, component, source);
});
}
void serializeGlobalTypeInference(GlobalTypeInferenceResults results) {
JsClosedWorld closedWorld = results.closedWorld;
ir.Component component = closedWorld.elementMap.programEnv.mainComponent;
serializeComponent(component);
measureSubtask('serialize data', () {
_reporter.log('Writing data to ${_options.writeDataUri}');
api.BinaryOutputSink dataOutput =
_outputProvider.createBinarySink(_options.writeDataUri);
DataSink sink = new BinarySink(new BinaryOutputSinkAdapter(dataOutput));
serializeGlobalTypeInferenceResultsToSink(results, sink);
});
}
Future<GlobalTypeInferenceResults> deserializeGlobalTypeInference(
Environment environment,
AbstractValueStrategy abstractValueStrategy) async {
ir.Component component = await deserializeComponentAndUpdateOptions();
return await measureIoSubtask('deserialize data', () async { return await measureIoSubtask('deserialize data', () async {
_reporter.log('Reading data from ${_options.readDataUri}'); _reporter.log('Reading data from ${_options.readDataUri}');
api.Input<List<int>> dataInput = await _provider api.Input<List<int>> dataInput = await _provider
.readFromUri(_options.readDataUri, inputKind: api.InputKind.binary); .readFromUri(_options.readDataUri, inputKind: api.InputKind.binary);
DataSource source = new BinarySourceImpl(dataInput.data); DataSource source = new BinarySourceImpl(dataInput.data);
return deserializeGlobalTypeInferenceResults(_options, _reporter, return deserializeGlobalTypeInferenceResultsFromSource(_options,
environment, abstractValueStrategy, component, source); _reporter, environment, abstractValueStrategy, component, source);
}); });
} }

View file

@ -101,20 +101,21 @@ runTest(
GlobalTypeInferenceResults cloneInferenceResults(Compiler compiler, GlobalTypeInferenceResults cloneInferenceResults(Compiler compiler,
GlobalTypeInferenceResults results, SerializationStrategy strategy) { GlobalTypeInferenceResults results, SerializationStrategy strategy) {
List<int> irData = strategy.serializeComponent(results); List<int> irData = strategy.unpackAndSerializeComponent(results);
List worldData = strategy.serializeData(results); List worldData = strategy.serializeGlobalTypeInferenceResults(results);
print('data size: ${worldData.length}'); print('data size: ${worldData.length}');
ir.Component newComponent = strategy.deserializeComponent(irData); ir.Component newComponent = strategy.deserializeComponent(irData);
GlobalTypeInferenceResults newResults = strategy.deserializeData( GlobalTypeInferenceResults newResults =
compiler.options, strategy.deserializeGlobalTypeInferenceResults(
compiler.reporter, compiler.options,
compiler.environment, compiler.reporter,
compiler.abstractValueStrategy, compiler.environment,
newComponent, compiler.abstractValueStrategy,
worldData); newComponent,
List newWorldData = strategy.serializeData(newResults); worldData);
List newWorldData = strategy.serializeGlobalTypeInferenceResults(newResults);
Expect.equals(worldData.length, newWorldData.length, Expect.equals(worldData.length, newWorldData.length,
"Reserialization data length mismatch."); "Reserialization data length mismatch.");
for (int i = 0; i < worldData.length; i++) { for (int i = 0; i < worldData.length; i++) {

View file

@ -6,6 +6,7 @@
/// ///
/// This is a shell that runs multiple tests, one per folder under `data/`. /// This is a shell that runs multiple tests, one per folder under `data/`.
import 'dart:io'; import 'dart:io';
import 'dart:async';
import 'package:compiler/src/commandline_options.dart'; import 'package:compiler/src/commandline_options.dart';
import 'package:front_end/src/compute_platform_binaries_location.dart' import 'package:front_end/src/compute_platform_binaries_location.dart'
@ -30,22 +31,40 @@ main(List<String> args) async {
_options = Options.parse(args); _options = Options.parse(args);
_packageConfig = await loadPackageConfigUri(packageConfigUri); _packageConfig = await loadPackageConfigUri(packageConfigUri);
await _resolveScripts(); await _resolveScripts();
await runSuite( await Future.wait([
sdkRoot.resolve('tests/modular/'), runSuite(
'tests/modular', sdkRoot.resolve('tests/modular/'),
_options, 'tests/modular',
new IOPipeline([ _options,
SourceToDillStep(), new IOPipeline([
GlobalAnalysisStep(), SourceToDillStep(),
Dart2jsCodegenStep(codeId0), ComputeClosedWorldStep(),
Dart2jsCodegenStep(codeId1), GlobalAnalysisStep(),
Dart2jsEmissionStep(), Dart2jsCodegenStep(codeId0),
RunD8(), Dart2jsCodegenStep(codeId1),
], cacheSharedModules: true)); Dart2jsEmissionStep(),
RunD8(),
], cacheSharedModules: true)),
// TODO(joshualitt) Delete this when we stop supporting this way of running
// the compiler.
runSuite(
sdkRoot.resolve('tests/modular/'),
'tests/modular',
_options,
new IOPipeline([
SourceToDillStep(),
LegacyGlobalAnalysisStep(),
Dart2jsCodegenStep(codeId0),
Dart2jsCodegenStep(codeId1),
Dart2jsEmissionStep(),
RunD8(),
], cacheSharedModules: true))
]);
} }
const dillId = const DataId("dill"); const dillId = const DataId("dill");
const updatedDillId = const DataId("udill"); const updatedDillId = const DataId("udill");
const closedWorldId = const DataId("world");
const globalDataId = const DataId("gdata"); const globalDataId = const DataId("gdata");
const codeId = const ShardsDataId("code", 2); const codeId = const ShardsDataId("code", 2);
const codeId0 = const ShardDataId(codeId, 0); const codeId0 = const ShardDataId(codeId, 0);
@ -213,9 +232,105 @@ class SourceToDillStep implements IOModularStep {
} }
} }
// Step that invokes the dart2js closed world computation.
class ComputeClosedWorldStep implements IOModularStep {
@override
List<DataId> get resultData => const [closedWorldId, updatedDillId];
@override
bool get needsSources => false;
@override
List<DataId> get dependencyDataNeeded => const [dillId];
@override
List<DataId> get moduleDataNeeded => const [dillId];
@override
bool get onlyOnMain => true;
@override
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
List<String> flags) async {
if (_options.verbose)
print("\nstep: dart2js compute closed world on $module");
Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
Iterable<String> dillDependencies =
transitiveDependencies.map((m) => '${toUri(m, dillId)}');
List<String> args = [
'--packages=${sdkRoot.toFilePath()}/.packages',
_dart2jsScript,
// TODO(sigmund): remove this dependency on libraries.json
if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
'${toUri(module, dillId)}',
for (String flag in flags) '--enable-experiment=$flag',
'${Flags.dillDependencies}=${dillDependencies.join(',')}',
'${Flags.writeClosedWorld}=${toUri(module, closedWorldId)}',
'--out=${toUri(module, updatedDillId)}',
];
var result =
await _runProcess(Platform.resolvedExecutable, args, root.toFilePath());
_checkExitCode(result, this, module);
}
@override
void notifyCached(Module module) {
if (_options.verbose)
print("\ncached step: dart2js compute closed world on $module");
}
}
// Step that invokes the dart2js global analysis on the main module by providing // Step that invokes the dart2js global analysis on the main module by providing
// the .dill files of all transitive modules as inputs. // the .dill files of all transitive modules as inputs.
class GlobalAnalysisStep implements IOModularStep { class GlobalAnalysisStep implements IOModularStep {
@override
List<DataId> get resultData => const [globalDataId];
@override
bool get needsSources => false;
@override
List<DataId> get dependencyDataNeeded => const [updatedDillId];
@override
List<DataId> get moduleDataNeeded => const [closedWorldId, updatedDillId];
@override
bool get onlyOnMain => true;
@override
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
List<String> flags) async {
if (_options.verbose) print("\nstep: dart2js global analysis on $module");
List<String> args = [
'--packages=${sdkRoot.toFilePath()}/.packages',
_dart2jsScript,
// TODO(sigmund): remove this dependency on libraries.json
if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
'${toUri(module, updatedDillId)}',
for (String flag in flags) '--enable-experiment=$flag',
'${Flags.readClosedWorld}=${toUri(module, closedWorldId)}',
'${Flags.writeData}=${toUri(module, globalDataId)}',
];
var result =
await _runProcess(Platform.resolvedExecutable, args, root.toFilePath());
_checkExitCode(result, this, module);
}
@override
void notifyCached(Module module) {
if (_options.verbose)
print("\ncached step: dart2js global analysis on $module");
}
}
// Step that invokes the dart2js global analysis on the main module by providing
// the .dill files of all transitive modules as inputs.
// NOTE: This is the legacy combined closed world computation alongside global
// inference.
class LegacyGlobalAnalysisStep implements IOModularStep {
@override @override
List<DataId> get resultData => const [globalDataId, updatedDillId]; List<DataId> get resultData => const [globalDataId, updatedDillId];