[vm] Initial support for bytecode generation in front-end server

Change-Id: I612dd2cb74534a5368e830a97ca73a469cfce82e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112520
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
This commit is contained in:
Alexander Markov
2019-08-09 21:16:01 +00:00
committed by commit-bot@chromium.org
parent daf0de7408
commit ffefa124a7
2 changed files with 64 additions and 4 deletions
+48 -4
View File
@@ -25,6 +25,9 @@ import 'package:kernel/kernel.dart'
import 'package:path/path.dart' as path;
import 'package:usage/uuid/uuid.dart';
import 'package:vm/bytecode/gen_bytecode.dart'
show generateBytecode, createFreshComponentWithBytecode;
import 'package:vm/bytecode/options.dart' show BytecodeOptions;
import 'package:vm/incremental_compiler.dart' show IncrementalCompiler;
import 'package:vm/kernel_front_end.dart'
show
@@ -34,6 +37,7 @@ import 'package:vm/kernel_front_end.dart'
convertFileOrUriArgumentToUri,
createFrontEndTarget,
createFrontEndFileSystem,
runWithFrontEndCompilerContext,
setVMEnvironmentDefines,
writeDepfile;
@@ -116,6 +120,16 @@ ArgParser argParser = new ArgParser(allowTrailingOptions: true)
..addFlag('track-widget-creation',
help: 'Run a kernel transformer to track creation locations for widgets.',
defaultsTo: false)
..addFlag('gen-bytecode', help: 'Generate bytecode', defaultsTo: false)
..addMultiOption('bytecode-options',
help: 'Specify options for bytecode generation:',
valueHelp: 'opt1,opt2,...',
allowed: BytecodeOptions.commandLineFlags.keys,
allowedHelp: BytecodeOptions.commandLineFlags)
..addFlag('drop-ast',
help: 'Include only bytecode into the output file', defaultsTo: false)
..addFlag('enable-asserts',
help: 'Whether asserts will be enabled.', defaultsTo: false)
..addMultiOption('enable-experiment',
help: 'Comma separated list of experimental features, eg set-literals.',
hide: true);
@@ -238,6 +252,7 @@ class FrontendCompiler implements CompilerInterface {
bool unsafePackageSerialization;
CompilerOptions _compilerOptions;
BytecodeOptions _bytecodeOptions;
FileSystem _fileSystem;
Uri _mainSource;
ArgResults _options;
@@ -323,6 +338,12 @@ class FrontendCompiler implements CompilerInterface {
return false;
}
compilerOptions.bytecode = options['gen-bytecode'];
final BytecodeOptions bytecodeOptions = new BytecodeOptions(
enableAsserts: options['enable-asserts'],
environmentDefines: environmentDefines)
..parseCommandLineFlags(options['bytecode-options']);
compilerOptions.target = createFrontEndTarget(
options['target'],
trackWidgetCreation: options['track-widget-creation'],
@@ -342,13 +363,15 @@ class FrontendCompiler implements CompilerInterface {
Component component;
if (options['incremental']) {
_compilerOptions = compilerOptions;
_bytecodeOptions = bytecodeOptions;
setVMEnvironmentDefines(environmentDefines, _compilerOptions);
_compilerOptions.omitPlatform = false;
_generator =
generator ?? _createGenerator(new Uri.file(_initializeFromDill));
await invalidateIfInitializingFromDill();
component = await _runWithPrintRedirection(() => _generator.compile());
component = await _runWithPrintRedirection(() async =>
await _generateBytecodeIfNeeded(await _generator.compile()));
} else {
if (options['link-platform']) {
// TODO(aam): Remove linkedDependencies once platform is directly embedded
@@ -362,6 +385,9 @@ class FrontendCompiler implements CompilerInterface {
aot: options['aot'],
useGlobalTypeFlowAnalysis: options['tfa'],
environmentDefines: environmentDefines,
genBytecode: compilerOptions.bytecode,
bytecodeOptions: bytecodeOptions,
dropAST: options['drop-ast'],
useProtobufTreeShaker: options['protobuf-tree-shaker']));
}
if (component != null) {
@@ -388,6 +414,22 @@ class FrontendCompiler implements CompilerInterface {
return errors.isEmpty;
}
Future<Component> _generateBytecodeIfNeeded(Component component) async {
if (_compilerOptions.bytecode && errors.isEmpty) {
await runWithFrontEndCompilerContext(
_mainSource, _compilerOptions, component, () {
generateBytecode(component,
coreTypes: _generator.getCoreTypes(),
hierarchy: _generator.getClassHierarchy(),
options: _bytecodeOptions);
if (_options['drop-ast']) {
component = createFreshComponentWithBytecode(component);
}
});
}
return component;
}
void _outputDependenciesDelta(Component component) async {
Set<Uri> uris = new Set<Uri>();
for (Uri uri in component.uriToSource.keys) {
@@ -501,12 +543,12 @@ class FrontendCompiler implements CompilerInterface {
_mainSource = _getFileOrUri(entryPoint);
}
errors.clear();
final Component deltaProgram =
await _generator.compile(entryPoint: _mainSource);
Component deltaProgram = await _generator.compile(entryPoint: _mainSource);
if (deltaProgram != null && transformer != null) {
transformer.transform(deltaProgram);
}
deltaProgram = await _generateBytecodeIfNeeded(deltaProgram);
await writeDillFile(deltaProgram, _kernelBinaryFilename);
_outputStream.writeln(boundaryKey);
await _outputDependenciesDelta(deltaProgram);
@@ -528,8 +570,10 @@ class FrontendCompiler implements CompilerInterface {
Procedure procedure = await _generator.compileExpression(
expression, definitions, typeDefinitions, libraryUri, klass, isStatic);
if (procedure != null) {
Component component = createExpressionEvaluationComponent(procedure);
component = await _generateBytecodeIfNeeded(component);
final IOSink sink = new File(_kernelBinaryFilename).openWrite();
sink.add(serializeProcedure(procedure));
sink.add(serializeComponent(component));
await sink.close();
_outputStream
.writeln('$boundaryKey $_kernelBinaryFilename ${errors.length}');
+16
View File
@@ -978,6 +978,22 @@ true
expect(await starter(args), 0);
});
test('compile with bytecode', () async {
var file = new File('${tempDir.path}/foo.dart')..createSync();
file.writeAsStringSync("main() {}\n");
var dillFile = new File('${tempDir.path}/app.dill');
expect(dillFile.existsSync(), equals(false));
final List<String> args = <String>[
'--sdk-root=${sdkRoot.toFilePath()}',
'--incremental',
'--platform=${platformKernel.path}',
'--output-dill=${dillFile.path}',
'--gen-bytecode',
file.path,
];
expect(await starter(args), 0);
});
test('compile "package:"-file', () async {
Directory lib = new Directory('${tempDir.path}/lib')..createSync();
new File('${lib.path}/foo.dart')