blob: dc5745a288858b421f12d9c33de72aa5d426f2bc [file] [log] [blame]
// Copyright (c) 2016, 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 fasta;
import 'dart:async' show Future;
import 'dart:convert' show JSON;
import 'dart:io' show BytesBuilder, Directory, File, exitCode;
import 'package:front_end/file_system.dart';
import 'package:front_end/physical_file_system.dart';
import 'package:front_end/src/fasta/kernel/utils.dart';
import 'package:kernel/binary/ast_to_binary.dart'
show LibraryFilteringBinaryPrinter;
import 'package:kernel/kernel.dart' show Library, Program, loadProgramFromBytes;
import 'package:kernel/target/targets.dart' show Target, TargetFlags, getTarget;
import 'compiler_command_line.dart' show CompilerCommandLine;
import 'compiler_context.dart' show CompilerContext;
import 'errors.dart' show InputError, formatUnexpected, inputError, reportCrash;
import 'kernel/kernel_target.dart' show KernelTarget;
import 'dill/dill_target.dart' show DillTarget;
import 'compile_platform.dart' show compilePlatformInternal;
import 'ticker.dart' show Ticker;
import 'translate_uri.dart' show TranslateUri;
import 'vm.dart' show CompilationResult;
const bool summary = const bool.fromEnvironment("summary", defaultValue: false);
const int iterations = const int.fromEnvironment("iterations", defaultValue: 1);
compileEntryPoint(List<String> arguments) async {
// Timing results for each iteration
List<double> elapsedTimes = <double>[];
for (int i = 0; i < iterations; i++) {
if (i > 0) {
print("\n\n=== Iteration ${i+1} of $iterations");
}
var stopwatch = new Stopwatch()..start();
await compile(arguments);
stopwatch.stop();
elapsedTimes.add(stopwatch.elapsedMilliseconds.toDouble());
}
if (summary) {
var json = JSON.encode(<String, dynamic>{'elapsedTimes': elapsedTimes});
print('\nSummary: $json');
}
}
outlineEntryPoint(List<String> arguments) async {
for (int i = 0; i < iterations; i++) {
if (i > 0) {
print("\n");
}
await outline(arguments);
}
}
Future<KernelTarget> outline(List<String> arguments) async {
try {
return await CompilerCommandLine.withGlobalOptions("outline", arguments,
(CompilerContext c) async {
if (c.options.verbose) {
print("Building outlines for ${arguments.join(' ')}");
}
CompileTask task =
new CompileTask(c, new Ticker(isVerbose: c.options.verbose));
return await task.buildOutline(c.options.output);
});
} on InputError catch (e) {
exitCode = 1;
print(e.format());
return null;
}
}
Future<Uri> compile(List<String> arguments) async {
try {
return await CompilerCommandLine.withGlobalOptions("compile", arguments,
(CompilerContext c) async {
if (c.options.verbose) {
print("Compiling directly to Kernel: ${arguments.join(' ')}");
}
CompileTask task =
new CompileTask(c, new Ticker(isVerbose: c.options.verbose));
return await task.compile();
});
} on InputError catch (e) {
exitCode = 1;
print(e.format());
return null;
}
}
class CompileTask {
final CompilerContext c;
final Ticker ticker;
CompileTask(this.c, this.ticker);
DillTarget createDillTarget(TranslateUri uriTranslator) {
return new DillTarget(ticker, uriTranslator, c.options.target);
}
KernelTarget createKernelTarget(
DillTarget dillTarget, TranslateUri uriTranslator, bool strongMode) {
return new KernelTarget(
c.fileSystem, dillTarget, uriTranslator, strongMode, c.uriToSource);
}
Future<KernelTarget> buildOutline([Uri output]) async {
TranslateUri uriTranslator = await TranslateUri.parse(
c.fileSystem, c.options.sdk, c.options.packages);
ticker.logMs("Read packages file");
DillTarget dillTarget = createDillTarget(uriTranslator);
KernelTarget kernelTarget =
createKernelTarget(dillTarget, uriTranslator, c.options.strongMode);
if (c.options.strongMode) {
print("Note: strong mode support is preliminary and may not work.");
}
Uri platform = c.options.platform;
if (platform != null) {
_appendDillForUri(dillTarget, platform);
}
String argument = c.options.arguments.first;
Uri uri = Uri.base.resolve(argument);
String path = uriTranslator.translate(uri)?.path ?? argument;
if (path.endsWith(".dart")) {
kernelTarget.read(uri);
} else {
inputError(uri, -1, "Unexpected input: $uri");
}
await dillTarget.buildOutlines();
var outline = await kernelTarget.buildOutlines();
if (c.options.dumpIr && output != null) {
printProgramText(outline, libraryFilter: kernelTarget.isSourceLibrary);
}
if (output != null) {
await writeProgramToFile(outline, output);
ticker.logMs("Wrote outline to ${output.toFilePath()}");
}
return kernelTarget;
}
Future<Uri> compile() async {
KernelTarget kernelTarget = await buildOutline();
if (exitCode != 0) return null;
Uri uri = c.options.output;
var program = await kernelTarget.buildProgram(verify: c.options.verify);
if (c.options.dumpIr) {
printProgramText(program, libraryFilter: kernelTarget.isSourceLibrary);
}
await writeProgramToFile(program, uri);
ticker.logMs("Wrote program to ${uri.toFilePath()}");
return uri;
}
}
Future<CompilationResult> parseScript(
Uri fileName, Uri packages, Uri patchedSdk,
{bool verbose: false, bool strongMode: false}) async {
return parseScriptInFileSystem(
fileName, PhysicalFileSystem.instance, packages, patchedSdk,
verbose: verbose, strongMode: strongMode);
}
Future<CompilationResult> parseScriptInFileSystem(
Uri fileName, FileSystem fileSystem, Uri packages, Uri patchedSdk,
{bool verbose: false, bool strongMode: false, String backendTarget}) async {
backendTarget ??= "vm";
try {
if (!await fileSystem.entityForUri(fileName).exists()) {
return new CompilationResult.error(
formatUnexpected(fileName, -1, "No such file."));
}
if (!await new Directory.fromUri(patchedSdk).exists()) {
return new CompilationResult.error(
formatUnexpected(patchedSdk, -1, "Patched sdk directory not found."));
}
Program program;
try {
TranslateUri uriTranslator =
await TranslateUri.parse(fileSystem, null, packages);
final Ticker ticker = new Ticker(isVerbose: verbose);
final DillTarget dillTarget =
new DillTarget(ticker, uriTranslator, backendTarget);
_appendDillForUri(dillTarget, patchedSdk.resolve('platform.dill'));
final KernelTarget kernelTarget =
new KernelTarget(fileSystem, dillTarget, uriTranslator, strongMode);
kernelTarget.read(fileName);
await dillTarget.buildOutlines();
await kernelTarget.buildOutlines();
program = await kernelTarget.buildProgram();
if (kernelTarget.errors.isNotEmpty) {
return new CompilationResult.errors(kernelTarget.errors);
}
} on InputError catch (e) {
return new CompilationResult.error(e.format());
}
if (program.mainMethod == null) {
return new CompilationResult.error("No 'main' method found.");
}
// Perform target-specific transformations.
Target target = getTarget("vm", new TargetFlags(strongMode: false));
target.performModularTransformations(program);
target.performGlobalTransformations(program);
// Write the program to a list of bytes and return it. Do not include
// libraries that have a dart: import URI.
//
// TODO(kmillikin): This is intended to exclude platform libraries that are
// included in the Kernel binary platform platform.dill. It does not
// necessarily exclude exactly the platform libraries. Use a better
// predicate that knows what is included in platform.dill.
var sink = new ByteSink();
bool predicate(Library library) => !library.importUri.isScheme('dart');
new LibraryFilteringBinaryPrinter(sink, predicate)
.writeProgramFile(program);
return new CompilationResult.ok(sink.builder.takeBytes());
} catch (e, s) {
return reportCrash(e, s, fileName);
}
}
Future compilePlatform(Uri patchedSdk, Uri fullOutput,
{Uri outlineOutput, Uri packages, bool verbose: false}) async {
Ticker ticker = new Ticker(isVerbose: verbose);
await CompilerCommandLine.withGlobalOptions("", [""], (CompilerContext c) {
c.options.options["--packages"] = packages;
if (verbose) {
c.options.options["--verbose"] = true;
}
return compilePlatformInternal(
c, ticker, patchedSdk, fullOutput, outlineOutput);
});
}
Future writeDepsFile(Uri script, Uri depsFile, Uri output,
{Uri packages,
Uri platform,
Iterable<Uri> extraDependencies,
bool verbose: false,
String backendTarget}) async {
backendTarget ??= "vm";
Ticker ticker = new Ticker(isVerbose: verbose);
await CompilerCommandLine.withGlobalOptions("", [""],
(CompilerContext c) async {
c.options.options["--packages"] = packages;
if (verbose) {
c.options.options["--verbose"] = true;
}
TranslateUri uriTranslator = await TranslateUri.parse(
c.fileSystem, c.options.sdk, c.options.packages);
ticker.logMs("Read packages file");
DillTarget dillTarget =
new DillTarget(ticker, uriTranslator, backendTarget);
_appendDillForUri(dillTarget, platform);
KernelTarget kernelTarget = new KernelTarget(PhysicalFileSystem.instance,
dillTarget, uriTranslator, false, c.uriToSource);
kernelTarget.read(script);
await dillTarget.buildOutlines();
await kernelTarget.loader.buildOutlines();
await kernelTarget.writeDepsFile(output, depsFile,
extraDependencies: extraDependencies);
});
}
/// Load the [Program] from the given [uri] and append its libraries
/// to the [dillTarget].
void _appendDillForUri(DillTarget dillTarget, Uri uri) {
var bytes = new File.fromUri(uri).readAsBytesSync();
var platformProgram = loadProgramFromBytes(bytes);
platformProgram.unbindCanonicalNames();
dillTarget.loader.appendLibraries(platformProgram);
}
// TODO(ahe): https://github.com/dart-lang/sdk/issues/28316
class ByteSink implements Sink<List<int>> {
final BytesBuilder builder = new BytesBuilder();
void add(List<int> data) {
builder.add(data);
}
void close() {
// Nothing to do.
}
}