Revert "Tweak public APIs and use them in patch_sdk, dart2js, and kernel-service."

Reason: broke VM bots, still investigating.

This reverts commit 610d081947.

TBR= paulberry@google.com

Review-Url: https://codereview.chromium.org/2979463002 .
This commit is contained in:
Sigmund Cherem 2017-07-07 15:21:33 -07:00
parent 610d081947
commit 4aadfe09df
53 changed files with 1300 additions and 1964 deletions

View file

@ -1,92 +0,0 @@
// Copyright (c) 2017, 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 compiler.src.kernel.dart2js_target;
import 'package:kernel/kernel.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/target/targets.dart';
import 'package:compiler/src/native/native.dart' show maybeEnableNative;
/// A kernel [Target] to configure the Dart Front End for dart2js.
class Dart2jsTarget extends Target {
final TargetFlags flags;
Dart2jsTarget(this.flags);
bool get strongMode => flags.strongMode;
String get name => 'dart2js';
List<String> get extraRequiredLibraries => const <String>[
'dart:_chrome',
'dart:_foreign_helper',
'dart:_interceptors',
'dart:_internal',
'dart:_isolate_helper',
'dart:_js_embedded_names',
'dart:_js_helper',
'dart:_js_mirrors',
'dart:_js_names',
'dart:_native_typed_data',
'dart:async',
'dart:collection',
'dart:html',
'dart:html_common',
'dart:indexed_db',
'dart:js',
'dart:js_util',
'dart:mirrors',
'dart:svg',
'dart:web_audio',
'dart:web_gl',
'dart:web_sql',
];
@override
bool mayDefineRestrictedType(Uri uri) =>
uri.scheme == 'dart' &&
(uri.path == 'core' || uri.path == '_interceptors');
@override
bool enableNative(Uri uri) => maybeEnableNative(uri);
@override
bool get nativeExtensionExpectsString => false;
@override
void performModularTransformationsOnLibraries(
CoreTypes coreTypes, ClassHierarchy hierarchy, List<Library> libraries,
{void logger(String msg)}) {}
@override
void performGlobalTransformations(CoreTypes coreTypes, Program program,
{void logger(String msg)}) {}
@override
Expression instantiateInvocation(CoreTypes coreTypes, Expression receiver,
String name, Arguments arguments, int offset, bool isSuper) {
// TODO(sigmund): implement;
return new InvalidExpression();
}
@override
Expression instantiateNoSuchMethodError(CoreTypes coreTypes,
Expression receiver, String name, Arguments arguments, int offset,
{bool isMethod: false,
bool isGetter: false,
bool isSetter: false,
bool isField: false,
bool isLocalVariable: false,
bool isDynamic: false,
bool isSuper: false,
bool isStatic: false,
bool isConstructor: false,
bool isTopLevel: false}) {
// TODO(sigmund): implement;
return new InvalidExpression();
}
}

View file

@ -0,0 +1,201 @@
// Copyright (c) 2017, 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.
/// Additions to Fasta for generating .dill (Kernel IR) files with dart2js patch
/// files and native hooks.
library compiler.src.kernel.fasta_support;
// TODO(sigmund): get rid of this file. Fasta should be agnostic of the
// target platform, at which point this should not be necessary. In particular,
// we need to:
// - add a fasta flag to configure the platform library location.
// - add a fasta flag to specify which sdk libraries should be built-in
// (that would replace `loadExtraRequiredLibraries`).
// - add flags to fasta to turn on various transformations.
// - get rid of `native` in dart2js patches or unify the syntax with the VM.
import 'dart:async' show Future;
import 'dart:io' show 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/ast.dart' show Source, Library;
import 'package:kernel/target/targets.dart' show TargetFlags, NoneTarget;
import 'package:front_end/src/fasta/builder/builder.dart' show LibraryBuilder;
import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
import 'package:front_end/src/fasta/dill/dill_target.dart' show DillTarget;
import 'package:front_end/src/fasta/fasta.dart' show CompileTask;
import 'package:front_end/src/fasta/kernel/kernel_target.dart'
show KernelTarget;
import 'package:front_end/src/fasta/loader.dart' show Loader;
import 'package:front_end/src/fasta/parser/parser.dart' show optional;
import 'package:front_end/src/fasta/source/source_loader.dart'
show SourceLoader;
import 'package:front_end/src/scanner/token.dart' show Token;
import 'package:front_end/src/fasta/ticker.dart' show Ticker;
import 'package:front_end/src/fasta/translate_uri.dart' show TranslateUri;
import 'package:compiler/src/native/native.dart' show maybeEnableNative;
/// Generates a platform.dill file containing the compiled Kernel IR of the
/// dart2js SDK.
Future compilePlatform(Uri patchedSdk, Uri fullOutput,
{Uri outlineOutput, Uri packages}) async {
Uri deps = Uri.base.resolveUri(new Uri.file("${fullOutput.toFilePath()}.d"));
TranslateUri uriTranslator = await TranslateUri
.parse(PhysicalFileSystem.instance, patchedSdk, packages: packages);
var ticker = new Ticker(isVerbose: false);
var dillTarget = new DillTargetForDart2js(ticker, uriTranslator);
var kernelTarget =
new KernelTargetForDart2js(dillTarget, uriTranslator, false);
kernelTarget.read(Uri.parse("dart:core"));
await dillTarget.buildOutlines();
var outline = await kernelTarget.buildOutlines();
await writeProgramToFile(outline, outlineOutput);
ticker.logMs("Wrote outline to ${outlineOutput.toFilePath()}");
if (exitCode != 0) return null;
var program = await kernelTarget.buildProgram();
await writeProgramToFile(program, fullOutput);
ticker.logMs("Wrote program to ${fullOutput.toFilePath()}");
await kernelTarget.writeDepsFile(fullOutput, deps);
}
/// Extends the internal fasta [CompileTask] to use a dart2js-aware [DillTarget]
/// and [KernelTarget].
class Dart2jsCompileTask extends CompileTask {
Dart2jsCompileTask(CompilerContext c, Ticker ticker) : super(c, ticker);
@override
DillTarget createDillTarget(TranslateUri uriTranslator) {
return new DillTargetForDart2js(ticker, uriTranslator);
}
@override
KernelTarget createKernelTarget(
DillTarget dillTarget, TranslateUri uriTranslator, bool strongMode) {
return new KernelTargetForDart2js(
dillTarget, uriTranslator, strongMode, c.uriToSource);
}
}
/// Specializes [KernelTarget] to build kernel for dart2js: no transformations
/// are run, JS-specific libraries are included in the SDK, and native clauses
/// have no string parameter.
class KernelTargetForDart2js extends KernelTarget {
KernelTargetForDart2js(
DillTarget target, TranslateUri uriTranslator, bool strongMode,
[Map<String, Source> uriToSource])
: super(PhysicalFileSystem.instance, target, uriTranslator, uriToSource);
@override
SourceLoader<Library> createLoader() =>
new SourceLoaderForDart2js<Library>(fileSystem, this);
@override
bool enableNative(LibraryBuilder library) => maybeEnableNative(library.uri);
@override
Token skipNativeClause(Token token) => _skipNative(token);
@override
String extractNativeMethodName(Token token) => "";
@override
void loadExtraRequiredLibraries(Loader loader) => _loadExtras(loader);
@override
void runBuildTransformations() {}
}
/// Specializes [SourceLoader] to build kernel for dart2js: dart2js extends
/// bool, int, num, double, and String in a different platform library than
/// `dart:core`.
class SourceLoaderForDart2js<L> extends SourceLoader<L> {
LibraryBuilder interceptorsLibrary;
@override
LibraryBuilder read(Uri uri, int charOffset,
{Uri fileUri, LibraryBuilder accessor, bool isPatch: false}) {
var library = super.read(uri, charOffset,
fileUri: fileUri, accessor: accessor, isPatch: isPatch);
if (uri.scheme == 'dart' && uri.path == '_interceptors') {
interceptorsLibrary = library;
}
return library;
}
@override
bool canImplementRestrictedTypes(LibraryBuilder library) =>
library == coreLibrary || library == interceptorsLibrary;
SourceLoaderForDart2js(FileSystem fs, KernelTarget target)
: super(fs, target);
}
/// Specializes [DillTarget] to build kernel for dart2js: JS-specific libraries
/// are included in the SDK, and native clauses have no string parameter.
class DillTargetForDart2js extends DillTarget {
DillTargetForDart2js(Ticker ticker, TranslateUri uriTranslator)
: super(ticker, uriTranslator, new NoneTarget(new TargetFlags()));
@override
Token skipNativeClause(Token token) => _skipNative(token);
@override
String extractNativeMethodName(Token token) => "";
@override
void loadExtraRequiredLibraries(Loader loader) => _loadExtras(loader);
}
/// We use native clauses of this form in our dart2js patch files:
///
/// methodDeclaration() native;
///
/// The default front_end parser doesn't support this, so it will trigger an
/// error recovery condition. This function is used while parsing to detect this
/// form and continue parsing.
///
/// Note that `native` isn't part of the Dart Language Specification, and the VM
/// uses it a slightly different form. We hope to remove this syntax in our
/// dart2js patch files and replace it with the external modifier.
Token _skipNative(Token token) {
if (!optional("native", token)) return null;
if (!optional(";", token.next)) return null;
return token;
}
void _loadExtras(Loader loader) {
for (String uri in _extraDart2jsLibraries) {
loader.read(Uri.parse(uri), -1);
}
}
const _extraDart2jsLibraries = const <String>[
'dart:_chrome',
'dart:_foreign_helper',
'dart:_interceptors',
'dart:_internal',
'dart:_isolate_helper',
'dart:_js_embedded_names',
'dart:_js_helper',
'dart:_js_mirrors',
'dart:_js_names',
'dart:_native_typed_data',
'dart:async',
'dart:collection',
'dart:html',
'dart:html_common',
'dart:indexed_db',
'dart:js',
'dart:js_util',
'dart:mirrors',
'dart:svg',
'dart:web_audio',
'dart:web_gl',
'dart:web_sql',
];

View file

@ -8,51 +8,29 @@
// command line.
library compiler.tool.generate_kernel;
import 'dart:io';
import 'dart:io' show exitCode;
import 'package:args/args.dart';
import 'package:compiler/src/kernel/dart2js_target.dart';
import 'package:front_end/front_end.dart';
import 'package:front_end/src/fasta/util/relativize.dart';
import 'package:kernel/kernel.dart';
import 'package:kernel/target/targets.dart';
import 'package:front_end/src/fasta/compiler_command_line.dart'
show CompilerCommandLine;
import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
import 'package:front_end/src/fasta/errors.dart' show InputError;
import 'package:front_end/src/fasta/ticker.dart' show Ticker;
import 'package:compiler/src/kernel/fasta_support.dart' show Dart2jsCompileTask;
main(List<String> args) async {
ArgResults flags = _argParser.parse(args);
var options = new CompilerOptions()
..target = new Dart2jsTarget(new TargetFlags())
..packagesFileUri = Platform.script.resolve('../../../.packages')
..compileSdk = true
..linkedDependencies = [Uri.base.resolve(flags['platform'])]
..onError = errorHandler;
if (flags.rest.isEmpty) {
var script = relativizeUri(Platform.script);
var platform = relativizeUri(Uri.base.resolve(flags['platform']));
print('usage: ${Platform.executable} $script '
'[--platform=$platform] [--out=out.dill] program.dart');
exit(1);
main(List<String> arguments) async {
try {
await CompilerCommandLine.withGlobalOptions("generate_kernel", arguments,
(CompilerContext c) async {
if (c.options.verbose) {
print("Compiling directly to Kernel: ${arguments.join(' ')}");
}
var task =
new Dart2jsCompileTask(c, new Ticker(isVerbose: c.options.verbose));
await task.compile();
});
} on InputError catch (e) {
exitCode = 1;
print(e.format());
return null;
}
Uri entry = Uri.base.resolve(flags.rest.first);
var program = await kernelForProgram(entry, options);
program.uriToSource.clear();
await writeProgramToBinary(program, flags['out']);
}
void errorHandler(CompilationError e) {
exitCode = 1;
print(e.message);
}
ArgParser _argParser = new ArgParser()
..addOption('platform',
help: 'location of the precompiled dart2js sdk',
defaultsTo: _defaultPlatform)
..addOption('out',
abbr: 'o', help: 'output location', defaultsTo: 'out.dill');
String _defaultPlatform = Uri
.parse(Platform.resolvedExecutable)
.resolve('patched_dart2js_sdk/platform.dill')
.toString();

View file

@ -163,7 +163,7 @@ Future<CompilationResult> rebuild(
// TODO(sigmund): should the incremental generator always filter these
// libraries instead?
new LimitedBinaryPrinter(
sink, (library) => library.importUri.scheme != 'dart', false)
sink, (library) => library.importUri.scheme != 'dart')
.writeProgramFile(program);
await sink.close();
}

View file

@ -6,7 +6,6 @@ library front_end.compiler_options;
import 'package:front_end/src/base/performace_logger.dart';
import 'package:front_end/src/incremental/byte_store.dart';
import 'package:kernel/target/targets.dart' show Target;
import 'compilation_error.dart';
import 'file_system.dart';
@ -26,20 +25,13 @@ class CompilerOptions {
///
/// If `null`, the SDK will be searched for using
/// [Platform.resolvedExecutable] as a starting point.
///
/// This option is mutually exclusive with [sdkSummary].
Uri sdkRoot;
/// Map of `dart:*` libraries to URIs in the [fileSystem].
///
/// Keys in the map are the name of the library with no `dart:` prefix, for
/// example:
///
/// {'core': 'file:///sdk/lib/core/core.dart'}
///
/// If `null`, the default set of libraries will be loaded from
/// `sdkRoot/lib/libraries.json`.
// TODO(sigmund): also provide an option to specify the .json file, then
// consider dropping this option.
Map<String, Uri> dartLibraries;
/// Map of `dart.xyz` libraries to URIs in the [fileSystem].
/// E.g. {'core': 'file:///sdk/lib/core/core.dart'} (no `dart:` prefix).
Map<String, Uri> dartLibraries = {};
/// Callback to which compilation errors should be delivered.
///
@ -57,42 +49,41 @@ class CompilerOptions {
Uri packagesFileUri;
/// URIs of input summary files (excluding the SDK summary; typically these
/// will be "file:" URIs).
///
/// These files should be summary files generated by this package (and not the
/// similarly named summary files from `package:analyzer`.)
///
/// Summaries may be provided in any order, but they should be acyclic and
/// closed: any libraries that they reference should be defined in either one
/// of [inputSummaries] or [sdkSummary].
/// will be "file:" URIs). These files should all be linked summaries. They
/// should also be closed, in the sense that any libraries they reference
/// should also appear in [inputSummaries] or [sdkSummary].
List<Uri> inputSummaries = [];
/// URIs of other kernel programs to link.
///
/// Commonly used to link the code for the SDK libraries that was compiled
/// separately. For example, dart2js needs to link the SDK so it can
/// optimize and tree-shake the code for the application, whereas the VM
/// always embeds the SDK internally and doesn't need it as part of the
/// program.
///
/// The programs provided here should be closed and acyclic: any libraries
/// that they reference should be defined in a program in [linkedDependencies]
/// or any of the [inputSummaries] or [sdkSummary].
List<Uri> linkedDependencies = [];
/// URI of the SDK summary file (typically a "file:" URI).
///
/// This should should be a summary previosly generated by this package (and
/// not the similarly named summary files from `package:analyzer`.)
/// This should be a linked summary. If `null`, the SDK summary will be
/// searched for at a default location within [sdkRoot].
///
/// If `null` and [compileSdk] is false, the SDK summary will be searched for
/// at a default location within [sdkRoot].
/// This option is mutually exclusive with [sdkRoot]. TODO(paulberry): if the
/// VM does not contain a pickled copy of the SDK, we might need to change
/// this.
Uri sdkSummary;
/// URI override map.
///
/// This is a map from URIs that might appear in import/export/part statements
/// to URIs that should be used to locate the corresponding files in the
/// [fileSystem]. Any URI override listed in this map takes precedence over
/// the URI resolution that would be implied by the packages file (see
/// [packagesFileUri]) and/or [multiRoots].
///
/// If a URI is not listed in this map, then the normal URI resolution
/// algorithm will be used.
///
/// TODO(paulberry): transition analyzer and dev_compiler to use the
/// "multi-root:" mechanism, and then remove this.
@deprecated
Map<Uri, Uri> uriOverride = {};
/// Multi-roots.
///
/// Any Uri that resolves to "multi-root:///$absolute_path" will be searched
/// for at "$root/$absolute_path", where "$root" is drawn from this list.
/// Any Uri that resolves to "multi-root:///$rest" will be searched for
/// at "$root/$rest", where "$root" is drawn from this list.
///
/// Intended use: if the user has a Bazel workspace located at path
/// "$workspace", this could be set to the file URIs corresponding to the
@ -113,84 +104,46 @@ class CompilerOptions {
/// file system. TODO(paulberry): fix this.
FileSystem fileSystem = PhysicalFileSystem.instance;
/// The byte storage to access serialized data.
/// The byte storage to get and put serialized data.
ByteStore byteStore = new NullByteStore();
/// The logger to report compilation progress.
PerformanceLog logger = new PerformanceLog(new StringBuffer());
/// Whether to generate code for the SDK.
///
/// By default the front end resolves programs using a prebuilt SDK summary.
/// When this option is `true`, [sdkSummary] must be null.
/// Whether to generate code for the SDK when compiling a whole-program.
bool compileSdk = false;
/// Whether the compiler should read files that are discovered as
/// dependencies, or only access the files listed explicitly.
/// Whether a modular build compiles only the files listed explicitly or if it
/// compiles dependencies as well.
///
/// This option has different defaults depending on the API.
/// This option is intended only for modular APIs like `kernelForBuildUnit`.
/// These APIs by default ensure that builds are hermetic, where all files
/// that will be compiled are listed explicitly and all other dependencies
/// are covered by summary files.
///
/// For modular APIs like `kernelForBuildUnit` and `summaryFor` the default
/// behavior is `false`. These APIs want to ensure that builds are hermetic,
/// where all files that will be compiled are listed explicitly and all other
/// dependencies are covered by summary files.
///
/// For whole-program APIs like `kernelForProgram`, this option is true by
/// default, so they can treat any dependency that is not described in a
/// summary as if it was explicitly listed as an input.
bool chaseDependencies;
/// When this option is true, these APIs will treat any dependency that is
/// not described in a summary as if it was explicitly listed as an input.
bool chaseDependencies = false;
/// Whether to interpret Dart sources in strong-mode.
bool strongMode = true;
// All options below are target-specific options.
//
// TODO(sigmund): revisit the right layout for these options. We might want to
// split them out into a separate bag of options or provide factories for
// common combinations of these options.
/// Patch files to apply on the core libraries for a specific target platform.
///
/// Keys in the map are the name of the library with no `dart:` prefix, for
/// example:
///
/// {'core': [
/// 'file:///location/of/core/patch_file1.dart',
/// 'file:///location/of/core/patch_file2.dart',
/// ]}
///
/// The values can be either absolute or relative URIs. Absolute URIs are read
/// directly, while relative URIs are resolved from the [sdkRoot].
// TODO(sigmund): provide also a flag to load this data from a file (like
// libraries.json)
Map<String, List<Uri>> targetPatches = {};
/// Keys on this map are expected to be `dart:*` URIs. The values can be
/// either absolute or relative URIs. Absolute URIs are read directly, while
/// relative URIs are resolved from the [sdkRoot].
Map<Uri, List<Uri>> targetPatches = {};
/// The target platform that will consume the compiled code.
///
/// Used to provide platform-specific details to the compiler like:
/// * the set of libraries are part of a platform's SDK (e.g. dart:html for
/// dart2js, dart:ui for flutter).
///
/// * what kernel transformations should be applied to the program
/// (async/await, mixin inlining, etc).
///
/// * how to deal with non-standard features like `native` extensions.
///
/// If not specified, the default target is the VM.
Target target;
/// Whether to show verbose messages (mainly for debugging and performance
/// tracking).
///
/// Messages are printed on stdout.
// TODO(sigmund): improve the diagnotics API to provide mechanism to intercept
// verbose data (Issue #30056)
bool verbose = false;
/// Whether to run extra verification steps to validate that compiled programs
/// are well formed.
///
/// Errors are reported via the [onError] callback.
// TODO(sigmund): ensure we don't print errors to stdout (Issue #30056)
bool verify = false;
/// Whether to dump generated programs in a text format (also mainly for
/// debugging).
///
/// Dumped data is printed in stdout.
bool debugDump = false;
/// Additional core libraries to be loaded when building a program.
// TODO(sigmund): delete. Ideally building a program only needs what's
// reachable and we can use kernelForBuildUnit when creating a snapshot of the
// SDK itself.
List<Uri> additionalLibraries = [];
}

View file

@ -1,14 +0,0 @@
// Copyright (c) 2017, 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.
/// The Dart Front End contains logic to build summaries and kernel programs
/// from Dart sources. The APIs exposed here are designed for tools in the Dart
/// ecosystem that need to load sources and convert them to these formats.
library front_end.front_end;
export 'compiler_options.dart';
export 'compilation_error.dart';
export 'kernel_generator.dart';
export 'summary_generator.dart';
export 'file_system.dart';

View file

@ -5,14 +5,19 @@
/// Defines the front-end API for converting source code to Dart Kernel objects.
library front_end.kernel_generator;
import 'compiler_options.dart';
import 'dart:async' show Future;
import 'dart:async';
import 'package:front_end/src/base/processed_options.dart';
import 'src/fasta/dill/dill_target.dart' show DillTarget;
import 'src/fasta/errors.dart' show InputError;
import 'src/fasta/kernel/kernel_target.dart' show KernelTarget;
import 'package:kernel/kernel.dart' show Program;
import 'compiler_options.dart';
import 'src/base/processed_options.dart';
import 'src/kernel_generator_impl.dart';
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget;
import 'src/fasta/ticker.dart' show Ticker;
import 'src/fasta/translate_uri.dart' show TranslateUri;
import 'src/simple_error.dart';
/// Generates a kernel representation of the program whose main library is in
/// the given [source].
@ -26,36 +31,73 @@ import 'src/kernel_generator_impl.dart';
/// If `compileSdk` in [options] is true, the generated program will include
/// code for the SDK.
///
/// If summaries are provided in [options], the compiler will use them instead
/// of compiling the libraries contained in those summaries. This is useful, for
/// example, when compiling for platforms that already embed those sources (like
/// the sdk in the standalone VM).
///
/// The input [source] is expected to be a script with a main method, otherwise
/// an error is reported.
// TODO(sigmund): rename to kernelForScript?
/// If summaries are provided in [options], they will be used to speed up
/// the process. If in addition `compileSdk` is false, then the resulting
/// program will not contain the sdk contents. This is useful when building apps
/// for platforms that already embed the sdk (e.g. the VM), so there is no need
/// to spend time and space rebuilding it.
Future<Program> kernelForProgram(Uri source, CompilerOptions options) async {
var pOptions = new ProcessedOptions(options, false, [source]);
var program = (await generateKernel(pOptions))?.program;
if (program == null) return null;
if (program.mainMethod == null) {
pOptions.reportError("No 'main' method found.");
var fs = options.fileSystem;
report(String msg) {
options.onError(new SimpleError(msg));
return null;
}
return program;
if (!await fs.entityForUri(source).exists()) {
return report("Entry-point file not found: $source");
}
var pOptions = new ProcessedOptions(options);
if (!await pOptions.validateOptions()) return null;
try {
TranslateUri uriTranslator = await pOptions.getUriTranslator();
var dillTarget = new DillTarget(new Ticker(isVerbose: false), uriTranslator,
new VmFastaTarget(new TargetFlags(strongMode: options.strongMode)));
var summary = await pOptions.sdkSummaryProgram;
if (summary != null) {
dillTarget.loader.appendLibraries(summary);
}
var kernelTarget =
new KernelTarget(options.fileSystem, dillTarget, uriTranslator);
kernelTarget.read(source);
await dillTarget.buildOutlines();
await kernelTarget.buildOutlines();
Program program = await kernelTarget.buildProgram(trimDependencies: true);
if (kernelTarget.errors.isNotEmpty) {
kernelTarget.errors.forEach(report);
return null;
}
if (program.mainMethod == null) {
return report("No 'main' method found.");
}
if (!options.compileSdk) {
// TODO(sigmund): ensure that the result is not including
// sources for the sdk, only external references.
}
return program;
} on InputError catch (e) {
options.onError(new SimpleError(e.format()));
return null;
}
}
/// Generates a kernel representation for a build unit containing [sources].
/// Generates a kernel representation for a build unit.
///
/// A build unit is a collection of libraries that are compiled together.
/// Libraries in the build unit may depend on each other and may have
/// dependencies to libraries in other build units. Unlinke library
/// dependencies, build unit dependencies must be acyclic.
/// Intended for modular compilation.
///
/// This API is intended for modular compilation. Dependencies to other build
/// units are specified using [CompilerOptions.inputSummaries].
/// The build unit by default contains only the source files in [sources]
/// (including library and part files), but if
/// [CompilerOptions.chaseDependencies] is true, it may include some additional
/// source files. All of the library files are transformed into Dart Kernel
/// Library objects.
///
/// By default, the compilation process is hermetic, meaning that the only files
/// which will be read are those listed in [sources],
@ -73,11 +115,72 @@ Future<Program> kernelForProgram(Uri source, CompilerOptions options) async {
/// are also listed in the build unit sources, otherwise an error results. (It
/// is not permitted to refer to a part file declared in another build unit).
///
/// The return value is a [Program] object with no main method set. The
/// [Program] includes external libraries for those libraries loaded through
/// summaries.
/// The return value is a [Program] object with no main method set.
/// TODO(paulberry): would it be better to define a data type in kernel to
/// represent a bundle of all the libraries in a given build unit?
///
/// TODO(paulberry): does additional information need to be output to allow the
/// caller to match up referenced elements to the summary files they were
/// obtained from?
Future<Program> kernelForBuildUnit(
List<Uri> sources, CompilerOptions options) async {
return (await generateKernel(new ProcessedOptions(options, true, sources)))
?.program;
var fs = options.fileSystem;
report(String msg) {
options.onError(new SimpleError(msg));
return null;
}
if (!options.chaseDependencies) {
// TODO(sigmund): add support, most likely we can do so by adding a wrapper
// on top of filesystem that restricts reads to a set of known files.
report("hermetic mode (chaseDependencies = false) is not implemented");
return null;
}
for (var source in sources) {
if (!await fs.entityForUri(source).exists()) {
return report("Entry-point file not found: $source");
}
}
var pOptions = new ProcessedOptions(options);
if (!await pOptions.validateOptions()) return null;
try {
TranslateUri uriTranslator = await pOptions.getUriTranslator();
var dillTarget = new DillTarget(new Ticker(isVerbose: false), uriTranslator,
new VmFastaTarget(new TargetFlags(strongMode: options.strongMode)));
var summary = await pOptions.sdkSummaryProgram;
if (summary != null) {
dillTarget.loader.appendLibraries(summary);
}
// TODO(sigmund): this is likely not going to work if done naively: if
// summaries contain external references we need to ensure they are loaded
// in a specific order.
for (var inputSummary in await pOptions.inputSummariesPrograms) {
dillTarget.loader.appendLibraries(inputSummary);
}
await dillTarget.buildOutlines();
var kernelTarget =
new KernelTarget(options.fileSystem, dillTarget, uriTranslator);
sources.forEach(kernelTarget.read);
await kernelTarget.buildOutlines();
Program program = await kernelTarget.buildProgram(trimDependencies: true);
if (kernelTarget.errors.isNotEmpty) {
kernelTarget.errors.forEach(report);
return null;
}
return program;
} on InputError catch (e) {
options.onError(new SimpleError(e.format()));
return null;
}
}

View file

@ -4,27 +4,17 @@
import 'dart:async';
import 'package:front_end/compilation_error.dart';
import 'package:front_end/compiler_options.dart';
import 'package:front_end/file_system.dart';
import 'package:front_end/src/base/performace_logger.dart';
import 'package:front_end/src/fasta/ticker.dart';
import 'package:front_end/src/fasta/translate_uri.dart';
import 'package:front_end/src/base/performace_logger.dart';
import 'package:front_end/src/incremental/byte_store.dart';
import 'package:kernel/kernel.dart'
show Program, loadProgramFromBytes, CanonicalName;
import 'package:kernel/target/targets.dart';
import 'package:kernel/target/vm_fasta.dart';
import 'package:front_end/src/simple_error.dart';
import 'package:package_config/packages_file.dart' as package_config;
import 'package:source_span/source_span.dart' show SourceSpan;
import 'package:kernel/kernel.dart' show Program, loadProgramFromBytes;
/// All options needed for the front end implementation.
///
/// This includes: all of [CompilerOptions] in a form useful to the
/// implementation, default values for options that were not provided,
/// and information derived from how the compiler was invoked (like the
/// entry-points given to the compiler and whether a modular or whole-program
/// API was used).
/// Wrapper around [CompilerOptions] which exposes the options in a form useful
/// to the front end implementation.
///
/// The intent is that the front end should immediately wrap any incoming
/// [CompilerOptions] object in this class before doing further processing, and
@ -44,58 +34,19 @@ class ProcessedOptions {
TranslateUri _uriTranslator;
/// The SDK summary, or `null` if it has not been read yet.
///
/// A summary, also referred to as "outline" internally, is a [Program] where
/// all method bodies are left out. In essence, it contains just API
/// signatures and constants. When strong-mode is enabled, the summary already
/// includes inferred types.
Program _sdkSummaryProgram;
/// The summary for each uri in `options.inputSummaries`.
///
/// A summary, also referred to as "outline" internally, is a [Program] where
/// all method bodies are left out. In essence, it contains just API
/// signatures and constants. When strong-mode is enabled, the summary already
/// includes inferred types.
List<Program> _inputSummariesPrograms;
/// Other programs that are meant to be linked and compiled with the input
/// sources.
List<Program> _linkedDependencies;
/// The location of the SDK, or `null` if the location hasn't been determined
/// yet.
Uri _sdkRoot;
Uri get sdkRoot => _sdkRoot ??= _normalizeSdkRoot();
Uri _sdkSummary;
Uri get sdkSummary => _sdkSummary ??= _computeSdkSummaryUri();
Ticker ticker;
bool get verbose => _raw.verbose;
bool get verify => _raw.verify;
bool get debugDump => _raw.debugDump;
/// Like [CompilerOptions.chaseDependencies] but with the appropriate default
/// value filled in.
bool get chaseDependencies => _raw.chaseDependencies ?? !_modularApi;
/// Whether the compiler was invoked with a modular API.
///
/// Used to determine the default behavior for [chaseDependencies].
final bool _modularApi;
/// The entry-points provided to the compiler.
final List<Uri> inputs;
/// Initializes a [ProcessedOptions] object wrapping the given [rawOptions].
ProcessedOptions(CompilerOptions rawOptions,
[this._modularApi = false, this.inputs = const []])
: this._raw = rawOptions,
ticker = new Ticker(isVerbose: rawOptions.verbose);
ProcessedOptions(CompilerOptions rawOptions) : this._raw = rawOptions;
/// The logger to report compilation progress.
PerformanceLog get logger {
@ -107,40 +58,28 @@ class ProcessedOptions {
return _raw.byteStore;
}
// TODO(sigmund): delete. We should use messages with error codes directly
// instead.
void reportError(String message) {
_raw.onError(new _CompilationError(message));
}
/// Runs various validations checks on the input options. For instance,
/// if an option is a path to a file, it checks that the file exists.
Future<bool> validateOptions() async {
for (var source in inputs) {
if (source.scheme == 'file' &&
!await fileSystem.entityForUri(source).exists()) {
reportError("Entry-point file not found: $source");
return false;
}
}
var fs = _raw.fileSystem;
var root = _raw.sdkRoot;
if (_raw.sdkRoot != null &&
!await fileSystem.entityForUri(sdkRoot).exists()) {
reportError("SDK root directory not found: ${sdkRoot}");
bool _report(String msg) {
_raw.onError(new SimpleError(msg));
return false;
}
var summary = sdkSummary;
if (summary != null && !await fileSystem.entityForUri(summary).exists()) {
reportError("SDK summary not found: ${summary}");
return false;
if (root != null && !await fs.entityForUri(root).exists()) {
return _report("SDK root directory not found: ${_raw.sdkRoot}");
}
if (compileSdk && summary != null) {
reportError(
"The compileSdk and sdkSummary options are mutually exclusive");
return false;
var summary = _raw.sdkSummary;
if (summary != null && !await fs.entityForUri(summary).exists()) {
return _report("SDK summary not found: ${_raw.sdkSummary}");
}
// TODO(sigmund): add checks for options that are meant to be disjoint (like
// sdkRoot and sdkSummary).
return true;
}
@ -148,67 +87,43 @@ class ProcessedOptions {
/// whole-program.
bool get compileSdk => _raw.compileSdk;
FileSystem _fileSystem;
/// Get the [FileSystem] which should be used by the front end to access
/// files.
///
/// If the client supplied roots using [CompilerOptions.multiRoots], the
/// returned [FileSystem] will automatically perform the appropriate mapping.
FileSystem get fileSystem => _fileSystem ??= _createFileSystem();
FileSystem get fileSystem {
// TODO(paulberry): support multiRoots.
assert(_raw.multiRoots.isEmpty);
return _raw.fileSystem;
}
/// Whether to interpret Dart sources in strong-mode.
bool get strongMode => _raw.strongMode;
Target _target;
Target get target => _target ??=
_raw.target ?? new VmFastaTarget(new TargetFlags(strongMode: strongMode));
/// Get an outline program that summarizes the SDK, if any.
// TODO(sigmund): move, this doesn't feel like an "option".
Future<Program> loadSdkSummary(CanonicalName nameRoot) async {
/// Get an outline program that summarizes the SDK.
Future<Program> get sdkSummaryProgram async {
if (_sdkSummaryProgram == null) {
if (sdkSummary == null) return null;
var bytes = await fileSystem.entityForUri(sdkSummary).readAsBytes();
_sdkSummaryProgram = loadProgram(bytes, nameRoot);
if (_raw.sdkSummary == null) return null;
_sdkSummaryProgram = await _loadProgram(_raw.sdkSummary);
}
return _sdkSummaryProgram;
}
/// Get the summary programs for each of the underlying `inputSummaries`
/// provided via [CompilerOptions].
// TODO(sigmund): move, this doesn't feel like an "option".
Future<List<Program>> loadInputSummaries(CanonicalName nameRoot) async {
Future<List<Program>> get inputSummariesPrograms async {
if (_inputSummariesPrograms == null) {
var uris = _raw.inputSummaries;
if (uris == null || uris.isEmpty) return const <Program>[];
// TODO(sigmund): throttle # of concurrent opreations.
var allBytes = await Future
.wait(uris.map((uri) => fileSystem.entityForUri(uri).readAsBytes()));
_inputSummariesPrograms =
allBytes.map((bytes) => loadProgram(bytes, nameRoot)).toList();
_inputSummariesPrograms = await Future.wait(uris.map(_loadProgram));
}
return _inputSummariesPrograms;
}
/// Load each of the [CompilerOptions.linkedDependencies] programs.
// TODO(sigmund): move, this doesn't feel like an "option".
Future<List<Program>> loadLinkDependencies(CanonicalName nameRoot) async {
if (_linkedDependencies == null) {
var uris = _raw.linkedDependencies;
if (uris == null || uris.isEmpty) return const <Program>[];
// TODO(sigmund): throttle # of concurrent opreations.
var allBytes = await Future
.wait(uris.map((uri) => fileSystem.entityForUri(uri).readAsBytes()));
_linkedDependencies =
allBytes.map((bytes) => loadProgram(bytes, nameRoot)).toList();
}
return _linkedDependencies;
}
/// Helper to load a .dill file from [uri] using the existing [nameRoot].
Program loadProgram(List<int> bytes, CanonicalName nameRoot) {
return loadProgramFromBytes(bytes, new Program(nameRoot: nameRoot));
Future<Program> _loadProgram(Uri uri) async {
var bytes = await fileSystem.entityForUri(uri).readAsBytes();
return loadProgramFromBytes(bytes)..unbindCanonicalNames();
}
/// Get the [TranslateUri] which resolves "package:" and "dart:" URIs.
@ -220,19 +135,13 @@ class ProcessedOptions {
await _getPackages();
// TODO(scheglov) Load SDK libraries from whatever format we decide.
// TODO(scheglov) Remove the field "_raw.dartLibraries".
var libraries = _raw.dartLibraries ?? await _parseLibraries();
_uriTranslator =
new TranslateUri(_packages, libraries, const <String, List<Uri>>{});
ticker.logMs("Read packages file");
_uriTranslator = new TranslateUri(
_packages, _raw.dartLibraries, const <String, List<Uri>>{});
_uriTranslator.dartLibraries.addAll(_raw.dartLibraries);
}
return _uriTranslator;
}
Future<Map<String, Uri>> _parseLibraries() async {
Uri librariesJson = _raw.sdkRoot?.resolve("lib/libraries.json");
return await computeLibraries(fileSystem, librariesJson);
}
/// Get the package map which maps package names to URIs.
///
/// This is an asynchronous getter since file system operations may be
@ -240,8 +149,7 @@ class ProcessedOptions {
Future<Map<String, Uri>> _getPackages() async {
if (_packages == null) {
if (_raw.packagesFileUri == null) {
// TODO(sigmund,paulberry): implement
throw new UnimplementedError('search for .packages');
throw new UnimplementedError(); // TODO(paulberry): search for .packages
} else if (_raw.packagesFileUri.path.isEmpty) {
_packages = {};
} else {
@ -254,6 +162,9 @@ class ProcessedOptions {
}
/// Get the location of the SDK.
///
/// This is an asynchronous getter since file system operations may be
/// required to locate the SDK.
Uri _normalizeSdkRoot() {
// If an SDK summary location was provided, the SDK itself should not be
// needed.
@ -261,89 +172,12 @@ class ProcessedOptions {
if (_raw.sdkRoot == null) {
// TODO(paulberry): implement the algorithm for finding the SDK
// automagically.
throw new UnimplementedError('infer the default sdk location');
throw new UnimplementedError();
}
var root = _raw.sdkRoot;
if (!root.path.endsWith('/')) {
root = root.replace(path: root.path + '/');
root = root.replace(path: _sdkRoot.path + '/');
}
return root;
}
/// Get or infer the location of the SDK summary.
Uri _computeSdkSummaryUri() {
if (_raw.sdkSummary != null) return _raw.sdkSummary;
// Infer based on the sdkRoot, but only when `compileSdk` is false,
// otherwise the default intent was to compile the sdk from sources and not
// to load an sdk summary file.
if (_raw.compileSdk) return null;
return sdkRoot.resolve('outline.dill');
}
/// Create a [FileSystem] specific to the current options.
///
/// If [chaseDependencies] is false, the resulting file system will be
/// hermetic.
FileSystem _createFileSystem() {
var result = _raw.fileSystem;
if (!chaseDependencies) {
var allInputs = inputs.toSet();
allInputs.addAll(_raw.inputSummaries);
allInputs.addAll(_raw.linkedDependencies);
if (sdkSummary != null) allInputs.add(sdkSummary);
if (_raw.sdkRoot != null) {
// TODO(sigmund): refine this, we should be more explicit about when
// sdkRoot and libraries.json are allowed to be used.
allInputs.add(sdkRoot);
allInputs.add(sdkRoot.resolve("lib/libraries.json"));
}
/// Note: Searching the file-system for the package-config is not
/// supported in hermetic builds.
if (_raw.packagesFileUri != null) allInputs.add(_raw.packagesFileUri);
result = new HermeticFileSystem(allInputs, result);
}
// TODO(paulberry): support multiRoots.
assert(_raw.multiRoots.isEmpty);
return result;
}
}
/// A [FileSystem] that only allows access to files that have been explicitly
/// whitelisted.
class HermeticFileSystem implements FileSystem {
final Set<Uri> includedFiles;
final FileSystem _realFileSystem;
HermeticFileSystem(this.includedFiles, this._realFileSystem);
FileSystemEntity entityForUri(Uri uri) {
if (includedFiles.contains(uri)) return _realFileSystem.entityForUri(uri);
throw new HermeticAccessException(uri);
}
}
class HermeticAccessException extends FileSystemException {
HermeticAccessException(Uri uri)
: super(
uri,
'Invalid access to $uri: '
'the file is accessed in a modular hermetic build, '
'but it was not explicitly listed as an input.');
@override
String toString() => message;
}
/// An error that only contains a message and no error location.
class _CompilationError implements CompilationError {
String get correction => null;
SourceSpan get span => null;
final String message;
_CompilationError(this.message);
String toString() => message;
}

View file

@ -47,8 +47,6 @@ abstract class LibraryBuilder<T extends TypeBuilder, R> extends Builder {
/// True if a compile-time error has been reported in this library.
bool hasCompileTimeErrors = false;
bool mayImplementRestrictedTypes = false;
LibraryBuilder(Uri fileUri, this.scope, this.exports)
: fileUri = fileUri,
relativeFileUri = relativizeUri(fileUri),

View file

@ -6,24 +6,24 @@ library fasta.compile_platform;
import 'dart:async' show Future;
import 'dart:io' show exitCode, File;
import '../../compiler_options.dart' show CompilerOptions;
import '../base/processed_options.dart' show ProcessedOptions;
import '../kernel_generator_impl.dart' show generateKernel;
import 'dart:io' show exitCode;
import 'compiler_command_line.dart' show CompilerCommandLine;
import 'compiler_context.dart' show CompilerContext;
import 'dill/dill_target.dart' show DillTarget;
import 'errors.dart' show InputError;
import 'kernel/utils.dart' show writeProgramToFile;
import 'kernel/kernel_target.dart' show KernelTarget;
import 'kernel/utils.dart' show printProgramText, writeProgramToFile;
import 'ticker.dart' show Ticker;
import 'translate_uri.dart' show TranslateUri;
const int iterations = const int.fromEnvironment("iterations", defaultValue: 1);
Future mainEntryPoint(List<String> arguments) async {
@ -56,31 +56,38 @@ Future compilePlatform(List<String> arguments) async {
Future compilePlatformInternal(CompilerContext c, Ticker ticker, Uri patchedSdk,
Uri fullOutput, Uri outlineOutput) async {
var options = new CompilerOptions()
..strongMode = c.options.strongMode
..sdkRoot = patchedSdk
..packagesFileUri = c.options.packages
..compileSdk = true
..chaseDependencies = true
..target = c.options.target
..debugDump = c.options.dumpIr
..verify = c.options.verify
..verbose = c.options.verbose;
if (options.strongMode) {
if (c.options.strongMode) {
print("Note: strong mode support is preliminary and may not work.");
}
if (options.verbose) {
ticker.isVerbose = c.options.verbose;
Uri deps = Uri.base.resolveUri(new Uri.file("${fullOutput.toFilePath()}.d"));
ticker.logMs("Parsed arguments");
if (ticker.isVerbose) {
print("Generating outline of $patchedSdk into $outlineOutput");
print("Compiling $patchedSdk to $fullOutput");
}
var result = await generateKernel(
new ProcessedOptions(options, false, [Uri.parse('dart:core')]),
buildSummary: true,
buildProgram: true);
new File.fromUri(outlineOutput).writeAsBytesSync(result.summary);
TranslateUri uriTranslator = await TranslateUri
.parse(c.fileSystem, patchedSdk, packages: c.options.packages);
ticker.logMs("Read packages file");
DillTarget dillTarget =
new DillTarget(ticker, uriTranslator, c.options.target);
KernelTarget kernelTarget =
new KernelTarget(c.fileSystem, dillTarget, uriTranslator, c.uriToSource);
kernelTarget.read(Uri.parse("dart:core"));
await dillTarget.buildOutlines();
var outline = await kernelTarget.buildOutlines();
await writeProgramToFile(outline, outlineOutput);
ticker.logMs("Wrote outline to ${outlineOutput.toFilePath()}");
await writeProgramToFile(result.program, fullOutput);
if (exitCode != 0) return null;
var program = await kernelTarget.buildProgram(verify: c.options.verify);
if (c.options.dumpIr) printProgramText(program);
await writeProgramToFile(program, fullOutput);
ticker.logMs("Wrote program to ${fullOutput.toFilePath()}");
await kernelTarget.writeDepsFile(fullOutput, deps);
}

View file

@ -8,18 +8,23 @@ import 'dart:async' show Future;
import 'dart:convert' show JSON;
import 'dart:io' show BytesBuilder, File, exitCode;
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 Program, loadProgramFromBytes;
import 'package:kernel/kernel.dart' show Library, Program, loadProgramFromBytes;
import 'package:kernel/target/targets.dart' show Target;
import 'compiler_command_line.dart' show CompilerCommandLine;
import 'compiler_context.dart' show CompilerContext;
import 'errors.dart' show InputError, inputError;
import 'errors.dart' show InputError, formatUnexpected, inputError, reportCrash;
import 'kernel/kernel_target.dart' show KernelTarget;
@ -31,6 +36,8 @@ 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);
@ -164,6 +171,69 @@ class CompileTask {
}
}
Future<CompilationResult> parseScript(
Uri fileName, Uri packages, Uri patchedSdk, Target backendTarget,
{bool verbose: false}) async {
return parseScriptInFileSystem(fileName, PhysicalFileSystem.instance,
packages, patchedSdk, backendTarget,
verbose: verbose);
}
Future<CompilationResult> parseScriptInFileSystem(Uri fileName,
FileSystem fileSystem, Uri packages, Uri patchedSdk, Target backendTarget,
{bool verbose: false}) async {
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, patchedSdk, packages: 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);
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.");
}
// 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,
@ -183,16 +253,16 @@ Future compilePlatform(Uri patchedSdk, Uri fullOutput,
});
}
// TODO(sigmund): reimplement this API using the directive listener intead.
Future<List<Uri>> getDependencies(Uri script,
Future writeDepsFile(Uri script, Uri depsFile, Uri output,
{Uri sdk,
Uri packages,
Uri platform,
Iterable<Uri> extraDependencies,
bool verbose: false,
String backendTarget}) async {
backendTarget ??= "vm_fasta";
Ticker ticker = new Ticker(isVerbose: verbose);
return await CompilerCommandLine.withGlobalOptions("", [""],
await CompilerCommandLine.withGlobalOptions("", [""],
(CompilerContext c) async {
c.options.options["--target"] = backendTarget;
c.options.options["--strong-mode"] = false;
@ -208,14 +278,15 @@ Future<List<Uri>> getDependencies(Uri script,
ticker.logMs("Read packages file");
DillTarget dillTarget =
new DillTarget(ticker, uriTranslator, c.options.target);
if (platform != null) _appendDillForUri(dillTarget, platform);
_appendDillForUri(dillTarget, platform);
KernelTarget kernelTarget = new KernelTarget(
PhysicalFileSystem.instance, dillTarget, uriTranslator, c.uriToSource);
kernelTarget.read(script);
await dillTarget.buildOutlines();
await kernelTarget.loader.buildOutlines();
return await kernelTarget.loader.getDependencies();
await kernelTarget.writeDepsFile(output, depsFile,
extraDependencies: extraDependencies);
});
}

View file

@ -17,8 +17,6 @@ import '../parser/parser.dart'
import '../parser/identifier_context.dart' show IdentifierContext;
import '../parser/native_support.dart' show skipNativeClause;
import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart';
import 'package:front_end/src/fasta/kernel/utils.dart' show offsetForToken;
@ -95,7 +93,6 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
final Scope enclosingScope;
final bool enableNative;
final bool stringExpectedAfterNative;
/// Whether to ignore an unresolved reference to `main` within the body of
/// `_getMainClosure` when compiling the current library.
@ -183,10 +180,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
this._typeInferrer)
: enclosingScope = scope,
library = library,
enableNative =
library.loader.target.backendTarget.enableNative(library.uri),
stringExpectedAfterNative =
library.loader.target.backendTarget.nativeExtensionExpectsString,
enableNative = library.loader.target.enableNative(library),
ignoreMainInGetMainClosure = library.uri.scheme == 'dart' &&
(library.uri.path == "_builtin" || library.uri.path == "ui"),
needsImplicitSuperInitializer =
@ -3007,7 +3001,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
@override
Token handleUnrecoverableError(Token token, FastaMessage message) {
if (enableNative && message.code == codeExpectedFunctionBody) {
Token recover = skipNativeClause(token, stringExpectedAfterNative);
Token recover = library.loader.target.skipNativeClause(token);
if (recover != null) return recover;
} else if (message.code == codeExpectedButGot) {
String expected = message.arguments["string"];

View file

@ -15,8 +15,9 @@ import '../errors.dart' show internalError;
///
/// This applies a simple "tree-shaking" technique: the full body of libraries
/// whose URI match [isIncluded] is preserved, and so is the outline of the
/// members and classes which are transitively visible from the
/// included libraries.
/// members and classes which are indicated by [data] (which should
/// practically include all members and classes transitively visible from the
/// included libraries).
///
/// The intent is that the resulting program has the entire code that is meant
/// to be included and the minimum required to prevent dangling references and
@ -25,9 +26,7 @@ import '../errors.dart' show internalError;
/// Note that the resulting program may include libraries not in [isIncluded],
/// but those will be marked as external. There should be no method bodies for
/// any members of those libraries.
void trimProgram(Program program, bool isIncluded(Uri uri)) {
var data = new RetainedDataBuilder();
new RootsMarker(new CoreTypes(program), data).run(program, isIncluded);
void trimProgram(Program program, RetainedData data, bool isIncluded(Uri uri)) {
new KernelOutlineShaker(data, isIncluded).transform(program);
}

View file

@ -6,6 +6,8 @@ library fasta.kernel_target;
import 'dart:async' show Future;
import 'dart:io' show File;
import 'package:front_end/file_system.dart';
import 'package:kernel/ast.dart'
@ -76,6 +78,8 @@ import 'kernel_builder.dart'
TypeVariableBuilder;
import 'verifier.dart' show verifyProgram;
import 'kernel_outline_shaker.dart'
show trimProgram, RetainedDataBuilder, RootsMarker;
class KernelTarget extends TargetImplementation {
/// The [FileSystem] which should be used to access files.
@ -210,7 +214,8 @@ class KernelTarget extends TargetImplementation {
builder.mixedInType = null;
}
void handleInputError(InputError error, {bool isFullProgram}) {
void handleInputError(InputError error,
{bool isFullProgram, bool trimDependencies: false}) {
if (error != null) {
String message = error.format();
print(message);
@ -258,12 +263,20 @@ class KernelTarget extends TargetImplementation {
/// not include method bodies (depending on what was loaded into that target,
/// an outline or a full kernel program).
///
/// When [trimDependencies] is true, this also runs a tree-shaker that deletes
/// anything from the [DillTarget] that is not needed for the source program,
/// this includes function bodies and types that are not reachable. This
/// option is currently in flux and the internal implementation might change.
/// See [trimDependenciesInProgram] for more details.
///
/// If [verify], run the default kernel verification on the resulting program.
@override
Future<Program> buildProgram({bool verify: false}) async {
Future<Program> buildProgram(
{bool verify: false, bool trimDependencies: false}) async {
if (loader.first == null) return null;
if (errors.isNotEmpty) {
handleInputError(null, isFullProgram: true);
handleInputError(null,
isFullProgram: true, trimDependencies: trimDependencies);
return program;
}
@ -276,17 +289,64 @@ class KernelTarget extends TargetImplementation {
if (verify) this.verify();
if (errors.isNotEmpty) {
handleInputError(null, isFullProgram: true);
handleInputError(null,
isFullProgram: true, trimDependencies: trimDependencies);
}
handleRecoverableErrors(loader.unhandledErrors);
} on InputError catch (e) {
handleInputError(e, isFullProgram: true);
handleInputError(e,
isFullProgram: true, trimDependencies: trimDependencies);
} catch (e, s) {
return reportCrash(e, s, loader?.currentUriForCrashReporting);
}
if (trimDependencies) trimDependenciesInProgram();
return program;
}
Future writeDepsFile(Uri output, Uri depsFile,
{Iterable<Uri> extraDependencies}) async {
String toRelativeFilePath(Uri uri) {
// Ninja expects to find file names relative to the current working
// directory. We've tried making them relative to the deps file, but that
// doesn't work for downstream projects. Making them absolute also
// doesn't work.
//
// We can test if it works by running ninja twice, for example:
//
// ninja -C xcodebuild/ReleaseX64 runtime_kernel -d explain
// ninja -C xcodebuild/ReleaseX64 runtime_kernel -d explain
//
// The second time, ninja should say:
//
// ninja: Entering directory `xcodebuild/ReleaseX64'
// ninja: no work to do.
//
// It's broken if it says something like this:
//
// ninja explain: expected depfile 'patched_sdk.d' to mention
// 'patched_sdk/platform.dill', got
// '/.../xcodebuild/ReleaseX64/patched_sdk/platform.dill'
return Uri.parse(relativizeUri(uri, base: Uri.base)).toFilePath();
}
if (loader.first == null) return null;
StringBuffer sb = new StringBuffer();
sb.write(toRelativeFilePath(output));
sb.write(":");
Set<String> allDependencies = new Set<String>();
allDependencies.addAll(loader.getDependencies().map(toRelativeFilePath));
if (extraDependencies != null) {
allDependencies.addAll(extraDependencies.map(toRelativeFilePath));
}
for (String path in allDependencies) {
sb.write(" ");
sb.write(path);
}
sb.writeln();
await new File.fromUri(depsFile).writeAsString("$sb");
ticker.logMs("Wrote deps file");
}
/// Adds a synthetic field named `#errors` to the main library that contains
/// [recoverableErrors] formatted.
///
@ -630,6 +690,27 @@ class KernelTarget extends TargetImplementation {
ticker.logMs("Verified program");
}
/// Tree-shakes most code from the [dillTarget] by visiting all other
/// libraries in [program] and marking the APIs from the [dillTarget]
/// libraries that are in use.
///
/// Note: while it's likely we'll do some trimming of programs for modular
/// compilation, it is unclear at this time when and how that trimming should
/// happen. We are likely going to remove the extra visitor my either marking
/// things while code is built, or by handling tree-shaking after the fact
/// (e.g. during serialization).
trimDependenciesInProgram() {
var toShake =
dillTarget.loader.libraries.map((lib) => lib.importUri).toSet();
var isIncluded = (Uri uri) => !toShake.contains(uri);
var data = new RetainedDataBuilder();
// TODO(sigmund): replace this step with data that is directly computed from
// the builders: we should know the tree-shaking roots without having to do
// a second visit over the tree.
new RootsMarker(loader.coreTypes, data).run(program, isIncluded);
trimProgram(program, data, isIncluded);
}
/// Return `true` if the given [library] was built by this [KernelTarget]
/// from sources, and not loaded from a [DillTarget].
bool isSourceLibrary(Library library) {

View file

@ -8,7 +8,6 @@ import 'dart:io';
import 'package:front_end/src/scanner/token.dart' show Token;
import 'package:kernel/ast.dart';
import 'package:kernel/binary/ast_to_binary.dart';
import 'package:kernel/binary/limited_ast_to_binary.dart';
import 'package:kernel/text/ast_to_text.dart';
/// A null-aware alternative to `token.offset`. If [token] is `null`, returns
@ -40,26 +39,3 @@ Future<Null> writeProgramToFile(Program program, Uri uri) async {
await sink.close();
}
}
/// Serialize the libraries in [program] that match [filter].
List<int> serializeProgram(Program program,
{bool filter(Library library), bool excludeUriToSource: false}) {
ByteSink byteSink = new ByteSink();
BinaryPrinter printer = filter == null && !excludeUriToSource
? new BinaryPrinter(byteSink)
: new LimitedBinaryPrinter(
byteSink, filter ?? (_) => true, excludeUriToSource);
printer.writeProgramFile(program);
return byteSink.builder.takeBytes();
}
/// A [Sink] that directly writes data into a byte builder.
class ByteSink implements Sink<List<int>> {
final BytesBuilder builder = new BytesBuilder();
void add(List<int> data) {
builder.add(data);
}
void close() {}
}

View file

@ -84,9 +84,6 @@ abstract class Loader<L> {
coreLibrary = library;
target.loadExtraRequiredLibraries(this);
}
if (target.backendTarget.mayDefineRestrictedType(uri)) {
library.mayImplementRestrictedTypes = true;
}
if (uri.scheme == "dart") {
target.readPatchFiles(library);
}

View file

@ -0,0 +1,56 @@
// Copyright (c) 2017, 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.
/// Implements support for Dart VM native method bodies of this form:
///
/// native STRING
///
/// This support is kept separate from parser.dart as this isn't specified in
/// the Dart Language Specification, also we hope to remove this syntax long
/// term and replace it with annotations as in `dart2js`.
library fasta.parser.dart_vm_native;
import '../../scanner/token.dart' show Token;
import '../scanner/token_constants.dart' show STRING_TOKEN;
import '../util/link.dart' show Link;
import 'parser.dart' show optional;
/// When parsing a Dart VM library file, we may encounter a native clause
/// instead of a function body. This method skips such a clause.
///
/// This method is designed to be called when encountering
/// [ErrorKind.ExpectedBlockToSkip] in [Listener.handleUnrecoverableError].
Token skipNativeClause(Token token) {
if (!optional("native", token)) return null;
token = token.next;
if (token.kind != STRING_TOKEN) return null;
if (!optional(";", token.next)) return null;
return token;
}
/// When parsing a Dart VM library file, we may encounter native getters like
///
/// int get length native "List_getLength";
///
/// This will result in [identifiers] being
///
/// [";", '"List_getLength"', "native", "length", "get"]
///
/// We need to remove '"List_getLength"' and "native" from that list.
///
/// This method designed to be called from [Listener.handleMemberName].
Link<Token> removeNativeClause(Link<Token> identifiers) {
Link<Token> result = identifiers.tail;
if (result.isEmpty) return identifiers;
if (result.head.kind != STRING_TOKEN) return identifiers;
result = result.tail;
if (result.isEmpty) return identifiers;
if (optional('native', result.head)) {
return result.tail.prepend(identifiers.head);
}
return identifiers;
}

View file

@ -535,7 +535,7 @@ class Listener {
/// This event can be used to support non-compliant (with respect to Dart
/// Language Specification) Dart VM native clauses. See
/// [native_support.dart].
/// [dart_vm_native.dart].
Link<Token> handleMemberName(Link<Token> identifiers) => identifiers;
void beginMethod(Token token, Token name) {}

View file

@ -1,86 +0,0 @@
// Copyright (c) 2017, 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.
/// Implements support for two variants of the native syntax extension.
///
/// * The Dart VM variant, where native method bodies have this form:
///
/// methodDeclaration() native STRING;
///
/// * The Dart2js and DDC variant, where native method bodies have this form:
///
/// methodDeclaration() native;
///
/// This support is kept separate from parser.dart as this isn't specified in
/// the Dart Language Specification, also we hope to remove this syntax long
/// term and replace it with annotations and external declarations.
library fasta.parser.dart_vm_native;
import '../../scanner/token.dart' show Token;
import '../scanner/token_constants.dart' show STRING_TOKEN;
import '../util/link.dart' show Link;
import 'parser.dart' show optional;
import '../quote.dart' show unescapeString;
/// When parsing a library file, we may encounter a native clause
/// instead of a function body. This method skips such a clause. The
/// [expectString] argument is used to choose which variant of the native clause
/// we expect to parse.
///
/// This method is designed to be called when encountering
/// [ErrorKind.ExpectedBlockToSkip] in [Listener.handleUnrecoverableError].
Token skipNativeClause(Token token, bool expectString) {
if (!optional("native", token)) return null;
if (expectString) {
token = token.next;
if (token.kind != STRING_TOKEN) return null;
}
if (!optional(";", token.next)) return null;
return token;
}
/// When parsing a library file, we may encounter native getters like
///
/// int get length native "List_getLength";
///
/// This will result in [identifiers] being
///
/// [";", '"List_getLength"', "native", "length", "get"]
///
/// Similarly if [expectString] is false, we expect a getter like:
///
/// int get length native;
///
/// And [identifiers] being
///
/// [";", "native", "length", "get"]
///
/// This method returns a new list where '"List_getLength"' and "native" are
/// removed.
///
/// This method is designed to be called from [Listener.handleMemberName].
Link<Token> removeNativeClause(Link<Token> identifiers, bool expectString) {
Link<Token> result = identifiers.tail;
if (result.isEmpty) return identifiers;
if (expectString) {
if (result.head.kind != STRING_TOKEN) return identifiers;
result = result.tail;
}
if (result.isEmpty) return identifiers;
if (optional('native', result.head)) {
return result.tail.prepend(identifiers.head);
}
return identifiers;
}
/// When the parser encounters a native clause and expects a string (like in VM
/// and flutter patch files), this method extracts the native name in that
/// string.
String extractNativeMethodName(Token token) {
return unescapeString(token.next.lexeme);
}

View file

@ -280,7 +280,7 @@ enum TypeContinuation {
/// [parseFunctionBody]. This method will report an unrecoverable error to the
/// listener with the code [fasta.codeExpectedFunctionBody]. The listener can
/// then look at the error code and the token and use the methods in
/// [native_support.dart](native_support.dart) to parse the native syntax.
/// [dart_vm_native.dart](dart_vm_native.dart) to parse the native syntax.
///
/// #### Implementation of Diet Parsing
///

View file

@ -25,8 +25,7 @@ import '../parser/parser.dart' show MemberKind, Parser, optional;
import '../../scanner/token.dart' show BeginToken, Token;
import '../parser/native_support.dart'
show removeNativeClause, skipNativeClause;
import '../parser/dart_vm_native.dart' show removeNativeClause;
import '../util/link.dart' show Link;
@ -49,8 +48,6 @@ class DietListener extends StackListener {
final bool enableNative;
final bool stringExpectedAfterNative;
final TypeInferenceEngine typeInferenceEngine;
ClassBuilder currentClass;
@ -67,10 +64,7 @@ class DietListener extends StackListener {
: library = library,
uri = library.fileUri,
memberScope = library.scope,
enableNative =
library.loader.target.backendTarget.enableNative(library.uri),
stringExpectedAfterNative =
library.loader.target.backendTarget.nativeExtensionExpectsString;
enableNative = library.loader.target.enableNative(library);
void discard(int n) {
for (int i = 0; i < n; i++) {
@ -521,7 +515,7 @@ class DietListener extends StackListener {
@override
Token handleUnrecoverableError(Token token, FastaMessage message) {
if (enableNative && message.code == codeExpectedBlockToSkip) {
Token recover = skipNativeClause(token, stringExpectedAfterNative);
Token recover = library.loader.target.skipNativeClause(token);
if (recover != null) return recover;
}
return super.handleUnrecoverableError(token, message);
@ -530,7 +524,7 @@ class DietListener extends StackListener {
@override
Link<Token> handleMemberName(Link<Token> identifiers) {
if (!enableNative || identifiers.isEmpty) return identifiers;
return removeNativeClause(identifiers, stringExpectedAfterNative);
return removeNativeClause(identifiers);
}
AsyncMarker getAsyncMarker(StackListener listener) => listener.pop();

View file

@ -28,8 +28,7 @@ import 'source_library_builder.dart' show SourceLibraryBuilder;
import 'unhandled_listener.dart' show NullValue, Unhandled, UnhandledListener;
import '../parser/native_support.dart'
show extractNativeMethodName, removeNativeClause, skipNativeClause;
import '../parser/dart_vm_native.dart' show removeNativeClause;
import '../operator.dart'
show
@ -50,7 +49,6 @@ class OutlineBuilder extends UnhandledListener {
final SourceLibraryBuilder library;
final bool enableNative;
final bool stringExpectedAfterNative;
/// When true, recoverable parser errors are silently ignored. This is
/// because they will be reported by the BodyBuilder later. However, typedefs
@ -62,10 +60,7 @@ class OutlineBuilder extends UnhandledListener {
OutlineBuilder(SourceLibraryBuilder library)
: library = library,
enableNative =
library.loader.target.backendTarget.enableNative(library.uri),
stringExpectedAfterNative =
library.loader.target.backendTarget.nativeExtensionExpectsString;
enableNative = library.loader.target.enableNative(library);
@override
Uri get uri => library.fileUri;
@ -854,10 +849,10 @@ class OutlineBuilder extends UnhandledListener {
@override
Token handleUnrecoverableError(Token token, FastaMessage message) {
if (enableNative && message.code == codeExpectedBlockToSkip) {
Token recover = skipNativeClause(token, stringExpectedAfterNative);
var target = library.loader.target;
Token recover = target.skipNativeClause(token);
if (recover != null) {
nativeMethodName =
stringExpectedAfterNative ? extractNativeMethodName(token) : "";
nativeMethodName = target.extractNativeMethodName(token);
return recover;
}
}
@ -873,7 +868,7 @@ class OutlineBuilder extends UnhandledListener {
@override
Link<Token> handleMemberName(Link<Token> identifiers) {
if (!enableNative || identifiers.isEmpty) return identifiers;
return removeNativeClause(identifiers, stringExpectedAfterNative);
return removeNativeClause(identifiers);
}
@override

View file

@ -339,6 +339,14 @@ class SourceLoader<L> extends Loader<L> {
return output;
}
/// Whether [library] is allowed to define classes that extend or implement
/// restricted types, such as `bool`, `int`, `double`, `num`, and `String`. By
/// default this is only allowed within the implementation of `dart:core`, but
/// some target implementations may need to override this to allow doing this
/// in other internal platform libraries.
bool canImplementRestrictedTypes(LibraryBuilder library) =>
library == coreLibrary;
void checkSemantics() {
List<ClassBuilder> allClasses = target.collectAllClasses();
Iterable<ClassBuilder> candidates = cyclicCandidates(allClasses);
@ -387,7 +395,7 @@ class SourceLoader<L> extends Loader<L> {
cls.charOffset,
"'${supertype.name}' is an enum and can't be extended or "
"implemented.");
} else if (!cls.library.mayImplementRestrictedTypes &&
} else if (!canImplementRestrictedTypes(cls.library) &&
blackListedClasses.contains(supertype)) {
cls.addCompileTimeError(
cls.charOffset,

View file

@ -8,8 +8,14 @@ import 'package:kernel/target/targets.dart' as backend show Target;
import 'builder/builder.dart' show Builder, ClassBuilder, LibraryBuilder;
import 'parser/dart_vm_native.dart' as vm show skipNativeClause;
import '../scanner/token.dart' show Token;
import 'loader.dart' show Loader;
import 'quote.dart' show unescapeString;
import 'target.dart' show Target;
import 'ticker.dart' show Ticker;
@ -96,6 +102,25 @@ abstract class TargetImplementation extends Target {
}
}
/// Whether the `native` language extension is supported within [library].
///
/// The `native` language extension is not part of the language specification,
/// means something else to each target, and is enabled differently for each
/// target implementation. For example, the VM target enables it everywhere
/// because of existing support for "dart-ext:" native extensions, but targets
/// like dart2js only enable it on the core libraries.
///
/// This default implementation assumes a VM target, but it can be overriden
/// in subclasses to change the behavior.
// TODO(sigmund,ahe): limit this to `dart-ext` libraries only (see
// https://github.com/dart-lang/sdk/issues/29763).
bool enableNative(LibraryBuilder library) => true;
Token skipNativeClause(Token token) => vm.skipNativeClause(token);
String extractNativeMethodName(Token token) =>
unescapeString(token.next.lexeme);
void addSourceInformation(
Uri uri, List<int> lineStarts, List<int> sourceCode);

View file

@ -28,14 +28,10 @@ import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilder;
import 'package:testing/testing.dart'
show ChainContext, Result, StdioProcess, Step, TestDescription;
show ChainContext, Result, StdioProcess, Step;
import 'package:kernel/ast.dart' show Program;
import 'package:front_end/front_end.dart';
import 'patched_sdk_location.dart' show computePatchedSdk;
class Print extends Step<Program, Program, ChainContext> {
const Print();
@ -174,40 +170,6 @@ class Copy extends Step<Program, Program, ChainContext> {
}
}
/// A `package:testing` step that runs the `package:front_end` compiler to
/// generate a kernel program for an individual file.
///
/// Most options are hard-coded, but if necessary they could be moved to the
/// [CompileContext] object in the future.
class Compile extends Step<TestDescription, Program, CompileContext> {
const Compile();
String get name => "fasta compilation";
Future<Result<Program>> run(
TestDescription description, CompileContext context) async {
Result<Program> result;
reportError(CompilationError error) {
result ??= fail(null, error.message);
}
Uri sdk = await computePatchedSdk();
Program p = await kernelForProgram(
description.uri,
new CompilerOptions()
..sdkRoot = sdk
..packagesFileUri = Uri.base.resolve('.packages')
..strongMode = context.strongMode
..linkedDependencies = [sdk.resolve('platform.dill')]
..onError = reportError);
return result ??= pass(p);
}
}
abstract class CompileContext implements ChainContext {
bool get strongMode;
}
class BytesCollector implements Sink<List<int>> {
final List<List<int>> lists = <List<int>>[];

View file

@ -0,0 +1,165 @@
// Copyright (c) 2017, 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.
/// API for compiling Dart source code to .dill (Kernel IR) files.
library front_end.vm;
// TODO(ahe): Convert this file to use the API in `../../kernel_generator.dart`
// and `../../compiler_options.dart`.
import 'dart:async' show Future;
import 'dart:io' show File, Platform;
import 'dart:typed_data' show Uint8List;
import 'package:front_end/file_system.dart';
import 'package:front_end/physical_file_system.dart';
import 'fasta.dart' as fasta;
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget;
/// Compilation status codes.
///
/// Note: The [index] property of these constants must match
/// `Dart_KernelCompilationStatus` in
/// [dart_api.h](../../../../runtime/include/dart_api.h).
enum Status {
/// Compilation was successful.
ok,
/// Compilation failed with a compile time error.
error,
/// Compiler crashed.
crash,
}
abstract class CompilationResult {
CompilationResult._();
factory CompilationResult.ok(Uint8List bytes) = _CompilationOk;
factory CompilationResult.errors(List<String> errors) = _CompilationError;
factory CompilationResult.error(String error) {
return new _CompilationError(<String>[error]);
}
factory CompilationResult.crash(Object exception, StackTrace stack) =
_CompilationCrash;
Status get status;
get payload;
List toResponse() => [status.index, payload];
}
Future<CompilationResult> parseScript(Uri script,
{bool verbose: false, bool strongMode: false}) async {
return parseScriptInFileSystem(script, PhysicalFileSystem.instance,
verbose: verbose, strongMode: strongMode);
}
Future<CompilationResult> parseScriptInFileSystem(
Uri script, FileSystem fileSystem,
{bool verbose: false, bool strongMode: false}) async {
final Uri packagesUri = (Platform.packageConfig != null)
? Uri.parse(Platform.packageConfig)
: await _findPackagesFile(fileSystem, script);
if (packagesUri == null) {
throw "Could not find .packages";
}
final Uri patchedSdk = Uri.base
.resolveUri(new Uri.file(Platform.resolvedExecutable))
.resolveUri(new Uri.directory("patched_sdk"));
if (verbose) {
print("""DFE: Requesting compilation {
scriptUri: ${script}
packagesUri: ${packagesUri}
patchedSdk: ${patchedSdk}
}""");
}
try {
return await fasta.parseScriptInFileSystem(script, fileSystem, packagesUri,
patchedSdk, new VmFastaTarget(new TargetFlags(strongMode: strongMode)),
verbose: verbose);
} catch (err, stack) {
return new CompilationResult.crash(err, stack);
}
}
class _CompilationOk extends CompilationResult {
final Uint8List bytes;
_CompilationOk(this.bytes) : super._();
@override
Status get status => Status.ok;
@override
get payload => bytes;
String toString() => "_CompilationOk(${bytes.length} bytes)";
}
abstract class _CompilationFail extends CompilationResult {
_CompilationFail() : super._();
String get errorString;
@override
get payload => errorString;
}
class _CompilationError extends _CompilationFail {
final List<String> errors;
_CompilationError(this.errors);
@override
Status get status => Status.error;
@override
String get errorString => errors.take(10).join('\n');
String toString() => "_CompilationError(${errorString})";
}
class _CompilationCrash extends _CompilationFail {
final Object exception;
final StackTrace stack;
_CompilationCrash(this.exception, this.stack);
@override
Status get status => Status.crash;
@override
String get errorString => "${exception}\n${stack}";
String toString() => "_CompilationCrash(${errorString})";
}
/// This duplicates functionality from the Loader which we can't easily
/// access from here.
Future<Uri> _findPackagesFile(FileSystem fileSystem, Uri base) async {
var dir = new File.fromUri(base).parent;
while (true) {
final packagesFile = dir.uri.resolve(".packages");
if (await fileSystem.entityForUri(packagesFile).exists()) {
return packagesFile;
}
if (dir.parent.path == dir.path) {
break;
}
dir = dir.parent;
}
return null;
}

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:front_end/file_system.dart';
import 'package:front_end/incremental_kernel_generator.dart';
@ -12,17 +13,27 @@ import 'package:front_end/src/base/processed_options.dart';
import 'package:front_end/src/fasta/dill/dill_library_builder.dart';
import 'package:front_end/src/fasta/dill/dill_target.dart';
import 'package:front_end/src/fasta/kernel/kernel_target.dart';
import 'package:front_end/src/fasta/kernel/utils.dart';
import 'package:front_end/src/fasta/ticker.dart';
import 'package:front_end/src/fasta/translate_uri.dart';
import 'package:front_end/src/incremental/byte_store.dart';
import 'package:front_end/src/incremental/file_state.dart';
import 'package:kernel/binary/ast_from_binary.dart';
import 'package:kernel/binary/limited_ast_to_binary.dart';
import 'package:kernel/kernel.dart' hide Source;
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget;
import 'package:meta/meta.dart';
class ByteSink implements Sink<List<int>> {
final BytesBuilder builder = new BytesBuilder();
void add(List<int> data) {
builder.add(data);
}
void close() {}
}
/// Implementation of [IncrementalKernelGenerator].
///
/// TODO(scheglov) Update the documentation.
@ -257,8 +268,7 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
_logger.run('Serialize ${kernelLibraries.length} libraries', () {
program.uriToSource.clear();
List<int> bytes =
serializeProgram(program, filter: kernelLibraries.contains);
List<int> bytes = _writeProgramBytes(program, kernelLibraries.contains);
_byteStore.put(kernelKey, bytes);
_logger.writeln('Stored ${bytes.length} bytes.');
});
@ -364,6 +374,12 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
}
});
}
List<int> _writeProgramBytes(Program program, bool filter(Library library)) {
ByteSink byteSink = new ByteSink();
new LimitedBinaryPrinter(byteSink, filter).writeProgramFile(program);
return byteSink.builder.takeBytes();
}
}
/// Compilation result for a library cycle.

View file

@ -1,171 +0,0 @@
// Copyright (c) 2017, 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.
/// Defines the front-end API for converting source code to Dart Kernel objects.
library front_end.kernel_generator_impl;
import 'dart:async' show Future;
import 'dart:async';
import 'package:kernel/kernel.dart' show Program, CanonicalName;
import 'base/processed_options.dart';
import 'fasta/dill/dill_target.dart' show DillTarget;
import 'fasta/errors.dart' show InputError, reportCrash;
import 'fasta/kernel/kernel_outline_shaker.dart';
import 'fasta/kernel/kernel_target.dart' show KernelTarget;
import 'fasta/kernel/verifier.dart';
import 'fasta/kernel/utils.dart';
import 'fasta/compiler_command_line.dart';
import 'fasta/translate_uri.dart' show TranslateUri;
/// Implementation for the `package:front_end/kernel_generator.dart` and
/// `package:front_end/summary_generator.dart` APIs.
Future<CompilerResult> generateKernel(ProcessedOptions options,
{bool buildSummary: false,
bool buildProgram: true,
bool trimDependencies: false}) async {
// TODO(sigmund): Replace CompilerCommandLine and instead simply use a
// CompilerContext that directly uses the ProcessedOptions throught the
// system.
return await CompilerCommandLine.withGlobalOptions("", [""], (context) async {
context.options.options['--target'] = options.target;
context.options.options['--strong-mode'] = options.strongMode;
context.options.options['--verbose'] = options.verbose;
return await generateKernelInternal(options,
buildSummary: buildSummary,
buildProgram: buildProgram,
trimDependencies: trimDependencies);
});
}
Future<CompilerResult> generateKernelInternal(ProcessedOptions options,
{bool buildSummary: false,
bool buildProgram: true,
bool trimDependencies: false}) async {
var fs = options.fileSystem;
if (!await options.validateOptions()) return null;
options.ticker.logMs("Validated arguments");
try {
TranslateUri uriTranslator = await options.getUriTranslator();
var dillTarget =
new DillTarget(options.ticker, uriTranslator, options.target);
CanonicalName nameRoot = new CanonicalName.root();
Set<Uri> externalLibs(Program program) {
return program.libraries
.where((lib) => lib.isExternal)
.map((lib) => lib.importUri)
.toSet();
}
var sdkSummary = await options.loadSdkSummary(nameRoot);
if (sdkSummary != null) {
var excluded = externalLibs(sdkSummary);
dillTarget.loader
.appendLibraries(sdkSummary, (uri) => !excluded.contains(uri));
}
// TODO(sigmund): provide better error reporting if input summaries or
// linked dependencies were listed out of order (or provide mechanism to
// sort them).
for (var inputSummary in await options.loadInputSummaries(nameRoot)) {
var excluded = externalLibs(inputSummary);
dillTarget.loader
.appendLibraries(inputSummary, (uri) => !excluded.contains(uri));
}
// All summaries are considered external and shouldn't include source-info.
dillTarget.loader.libraries.forEach((lib) => lib.isExternal = true);
// Linked dependencies are meant to be part of the program so they are not
// marked external.
for (var dependency in await options.loadLinkDependencies(nameRoot)) {
var excluded = externalLibs(dependency);
dillTarget.loader
.appendLibraries(dependency, (uri) => !excluded.contains(uri));
}
await dillTarget.buildOutlines();
var kernelTarget = new KernelTarget(fs, dillTarget, uriTranslator);
options.inputs.forEach(kernelTarget.read);
Program summaryProgram =
await kernelTarget.buildOutlines(nameRoot: nameRoot);
List<int> summary = null;
if (buildSummary) {
if (trimDependencies) {
// TODO(sigmund): see if it is worth supporting this. Note: trimming the
// program is destructive, so if we are emitting summaries and the
// program in a single API call, we would need to clone the program here
// to avoid deleting pieces that are needed by kernelTarget.buildProgram
// below.
assert(!buildProgram);
var excluded =
dillTarget.loader.libraries.map((lib) => lib.importUri).toSet();
trimProgram(summaryProgram, (uri) => !excluded.contains(uri));
}
if (options.verify) {
verifyProgram(summaryProgram).forEach((e) => options.reportError('$e'));
}
if (options.debugDump) {
printProgramText(summaryProgram,
libraryFilter: kernelTarget.isSourceLibrary);
}
if (kernelTarget.errors.isEmpty) {
summary = serializeProgram(summaryProgram, excludeUriToSource: true);
}
options.ticker.logMs("Generated outline");
}
Program program;
if (buildProgram && kernelTarget.errors.isEmpty) {
program = await kernelTarget.buildProgram(verify: options.verify);
if (trimDependencies) {
var excluded =
dillTarget.loader.libraries.map((lib) => lib.importUri).toSet();
trimProgram(program, (uri) => !excluded.contains(uri));
}
if (options.debugDump) {
printProgramText(program, libraryFilter: kernelTarget.isSourceLibrary);
}
options.ticker.logMs("Generated program");
}
if (kernelTarget.errors.isNotEmpty) {
kernelTarget.errors.forEach(options.reportError);
return null;
}
return new CompilerResult(
summary: summary,
program: program,
deps: kernelTarget.loader.getDependencies());
} on InputError catch (e) {
options.reportError(e.format());
return null;
} catch (e, t) {
return reportCrash(e, t);
}
}
/// Result object of [generateKernel].
class CompilerResult {
/// The generated summary bytes, if it was requested.
final List<int> summary;
/// The generated program, if it was requested.
final Program program;
/// Dependencies traversed by the compiler. Used only for generating
/// dependency .GN files in the dart-sdk build system.
/// Note this might be removed when we switch to compute depencencies without
/// using the compiler itself.
final List<Uri> deps;
CompilerResult({this.summary, this.program, this.deps});
}

View file

@ -0,0 +1,11 @@
import 'package:front_end/compilation_error.dart';
import 'package:source_span/source_span.dart' show SourceSpan;
/// An error that only contains a message and no error location.
class SimpleError implements CompilationError {
String get correction => null;
SourceSpan get span => null;
final String message;
SimpleError(this.message);
}

View file

@ -1,123 +0,0 @@
// Copyright (c) 2017, 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.
/// Common compiler options and helper functions used for testing.
library front_end.testing.compiler_options_common;
import 'dart:async';
import 'package:front_end/front_end.dart';
import 'package:front_end/memory_file_system.dart';
import 'package:front_end/src/fasta/testing/patched_sdk_location.dart';
import 'package:front_end/src/testing/hybrid_file_system.dart';
import 'package:kernel/ast.dart';
/// Generate kernel for a script.
///
/// [scriptOrSources] can be a String, in which case it is the script to be
/// compiled, or a Map containing source files. In which case, this function
/// compiles the entry whose name is [fileName].
///
/// Wraps [kernelForProgram] with some default testing options (see [setup]).
Future<Program> compileScript(dynamic scriptOrSources,
{fileName: 'main.dart',
List<String> inputSummaries: const [],
List<String> linkedDependencies: const [],
CompilerOptions options}) async {
options ??= new CompilerOptions();
Map<String, dynamic> sources;
if (scriptOrSources is String) {
sources = {fileName: scriptOrSources};
} else {
assert(scriptOrSources is Map);
sources = scriptOrSources;
}
await setup(options, sources,
inputSummaries: inputSummaries, linkedDependencies: linkedDependencies);
return await kernelForProgram(toTestUri(fileName), options);
}
/// Generate a program for a modular complation unit.
///
/// Wraps [kernelForBuildUnit] with some default testing options (see [setup]).
Future<Program> compileUnit(List<String> inputs, Map<String, dynamic> sources,
{List<String> inputSummaries: const [],
List<String> linkedDependencies: const [],
CompilerOptions options}) async {
options ??= new CompilerOptions();
await setup(options, sources,
inputSummaries: inputSummaries, linkedDependencies: linkedDependencies);
return await kernelForBuildUnit(inputs.map(toTestUri).toList(), options);
}
/// Generate a summary for a modular complation unit.
///
/// Wraps [summaryFor] with some default testing options (see [setup]).
Future<List<int>> summarize(List<String> inputs, Map<String, dynamic> sources,
{List<String> inputSummaries: const [], CompilerOptions options}) async {
options ??= new CompilerOptions();
await setup(options, sources, inputSummaries: inputSummaries);
return await summaryFor(inputs.map(toTestUri).toList(), options);
}
/// Defines a default set of options for testing:
///
/// * create a hybrid file system that stores [sources] in memory but allows
/// access to the physical file system to load the SDK. [sources] can
/// contain either source files (value is [String]) or .dill files (value
/// is [List<int>]).
///
/// * define an empty .packages file
///
/// * specify the location of the sdk and sdk summaries based on
/// the path where the `patched_sdk` is generated in the sdk-repo.
Future<Null> setup(CompilerOptions options, Map<String, dynamic> sources,
{List<String> inputSummaries: const [],
List<String> linkedDependencies: const []}) async {
var fs = new MemoryFileSystem(_defaultDir);
sources.forEach((name, data) {
var entity = fs.entityForUri(toTestUri(name));
if (data is String) {
entity.writeAsStringSync(data);
} else {
entity.writeAsBytesSync(data);
}
});
fs.entityForUri(toTestUri('.packages')).writeAsStringSync('');
options
..verify = true
..fileSystem = new HybridFileSystem(fs)
..inputSummaries = inputSummaries.map(toTestUri).toList()
..linkedDependencies = linkedDependencies.map(toTestUri).toList()
..packagesFileUri = toTestUri('.packages');
if (options.sdkSummary == null) {
options.sdkRoot = await computePatchedSdk();
}
}
/// A fake absolute directory used as the root of a memory-file system in the
/// helpers above.
Uri _defaultDir = Uri.parse('file:///a/b/c/');
/// Convert relative file paths into an absolute Uri as expected by the test
/// helpers above.
Uri toTestUri(String relativePath) => _defaultDir.resolve(relativePath);
/// A map defining the location of core libraries that purposely provides
/// invalid Uris. Used by tests that want to ensure that the sdk libraries are
/// not loaded from sources, but read from a .dill file.
Map<String, Uri> invalidCoreLibs = {
'core': Uri.parse('file:///non_existing_file/core.dart'),
'async': Uri.parse('file:///non_existing_file/async.dart'),
};
bool isDartCoreLibrary(Library lib) => isDartCore(lib.importUri);
bool isDartCore(Uri uri) => uri.scheme == 'dart' && uri.path == 'core';
/// Find a library in [program] whose Uri ends with the given [suffix]
Library findLibrary(Program program, String suffix) {
return program.libraries
.firstWhere((lib) => lib.importUri.path.endsWith(suffix));
}

View file

@ -8,9 +8,6 @@ library front_end.summary_generator;
import 'dart:async';
import 'compiler_options.dart';
import 'src/base/processed_options.dart';
import 'src/kernel_generator_impl.dart';
/// Creates a summary representation of the build unit whose source files are in
/// [sources].
///
@ -19,25 +16,17 @@ import 'src/kernel_generator_impl.dart';
/// [sources] should be the complete set of source files for a build unit
/// (including both library and part files).
///
/// By default, the compilation process is hermetic, meaning that the only files
/// which will be read are those listed in [sources],
/// The summarization process is hermetic, meaning that the only files which
/// will be read are those listed in [sources],
/// [CompilerOptions.inputSummaries], and [CompilerOptions.sdkSummary]. If a
/// source file attempts to refer to a file which is not obtainable from these
/// URIs, that will result in an error, even if the file exists on the
/// paths, that will result in an error, even if the file exists on the
/// filesystem.
///
/// When [CompilerOptions.chaseDependencies] is true, this default behavior
/// changes, and any dependency of [sources] that is not listed in
/// [CompilerOptions.inputSummaries] and [CompilerOptions.sdkSummary] is treated
/// as an additional source file for the build unit.
///
/// Any `part` declarations found in [sources] must refer to part files which
/// are also listed in the build unit sources, otherwise an error results. (It
/// is not permitted to refer to a part file declared in another build unit).
/// are also listed in [sources], otherwise an error results. (It is not
/// permitted to refer to a part file declared in another build unit).
///
/// The return value is a list of bytes to write to the summary file.
Future<List<int>> summaryFor(List<Uri> sources, CompilerOptions options) async {
return (await generateKernel(new ProcessedOptions(options, true, sources),
buildSummary: true, buildProgram: false))
?.summary;
}
Future<List<int>> summaryFor(List<Uri> sources, CompilerOptions options) =>
throw new UnimplementedError();

View file

@ -23,7 +23,6 @@ export 'package:testing/testing.dart' show Chain, runMe;
import 'package:front_end/physical_file_system.dart';
import 'package:front_end/src/fasta/dill/dill_target.dart' show DillTarget;
import 'package:front_end/src/fasta/errors.dart' show InputError;
import 'package:front_end/src/fasta/kernel/kernel_outline_shaker.dart';
import 'package:front_end/src/fasta/kernel/kernel_target.dart'
show KernelTarget;
import 'package:front_end/src/fasta/kernel/verifier.dart' show verifyProgram;
@ -66,8 +65,8 @@ class TreeShakerContext extends ChainContext {
];
Program loadPlatformOutline() {
// Note: we rebuild the platform outline on every test because the
// tree-shaker mutates the in-memory representation of the program without
// Note: we rebuild the platform outline on every test because the compiler
// currently mutates the in-memory representation of the program without
// cloning it.
return loadProgramFromBytes(outlineBytes);
}
@ -108,15 +107,31 @@ class BuildProgram
await dillTarget.buildOutlines();
var inputUri = description.uri;
/// We treat the lib.dart library as a special dependency that was
/// previously built. To do so, we build it and append it back to the
/// dillTarget before building the actual test.
var libUri = inputUri.resolve('lib/lib.dart');
sourceTarget.read(libUri);
dillTarget.loader.appendLibraries(
await sourceTarget.buildOutlines(), (uri) => uri == libUri);
/// This new KernelTarget contains only sources from the test without
/// lib.dart.
sourceTarget = new KernelTarget(
PhysicalFileSystem.instance, dillTarget, context.uriTranslator);
await dillTarget.buildOutlines();
sourceTarget.read(inputUri);
var contents = new File.fromUri(inputUri).readAsStringSync();
var showCoreLibraries = contents.contains("@@SHOW_CORE_LIBRARIES@@");
await sourceTarget.buildOutlines();
var program = await sourceTarget.buildProgram();
bool isIncluded(Uri uri) => !_isTreeShaken(uri);
trimProgram(program, isIncluded);
// Note: We run the tree-shaker as a separate step on this suite to be
// able to specify what libraries to tree shake (by default only the code
// in the dillTarget gets tree-shaken). We could apply the tree-shaker
// twice, but that seems unnecessary.
var program = await sourceTarget.buildProgram(trimDependencies: true);
return pass(new _IntermediateData(inputUri, program, showCoreLibraries));
} on InputError catch (e, s) {
return fail(null, e.error, s);
@ -148,10 +163,18 @@ class CheckShaker extends Step<_IntermediateData, String, ChainContext> {
String get name => "match shaker expectation";
/// Tree-shake dart:* libraries and the library under [_specialLibraryPath].
bool _isTreeShaken(Uri uri) =>
uri.isScheme('dart') ||
Uri.base.resolveUri(uri).path.endsWith(_specialLibraryPath);
Future<Result<String>> run(
_IntermediateData data, ChainContext context) async {
String actualResult;
var entryUri = data.uri;
var entryUri = data.program.libraries
.firstWhere((l) => !l.importUri.isScheme('dart'))
.importUri;
var program = data.program;
var errors = verifyProgram(program, isOutline: false);
@ -221,8 +244,3 @@ $buffer""");
/// A special library used only to test the shaker. The suite above will
/// tree-shake the contents of this library.
const _specialLibraryPath = 'pkg/front_end/testcases/shaker/lib/lib.dart';
/// Tree-shake dart:* libraries and the library under [_specialLibraryPath].
bool _isTreeShaken(Uri uri) =>
uri.isScheme('dart') ||
Uri.base.resolveUri(uri).path.endsWith(_specialLibraryPath);

View file

@ -98,7 +98,7 @@ class FastaContext extends ChainContext {
Uri sdk;
Uri platformUri;
Uri outlineUri;
Program outline;
List<int> outlineBytes;
final ExpectationSet expectationSet =
new ExpectationSet.fromJsonList(JSON.decode(EXPECTATIONS));
@ -139,12 +139,15 @@ class FastaContext extends ChainContext {
}
Future<Program> loadPlatformOutline() async {
if (outline == null) {
if (outlineBytes == null) {
await ensurePlatformUris();
outline =
loadProgramFromBytes(new File.fromUri(outlineUri).readAsBytesSync());
outlineBytes = new File.fromUri(outlineUri).readAsBytesSync();
}
return outline;
// Note: we rebuild the platform outline on every test because the compiler
// currently mutates the in-memory representation of the program without
// cloning it.
// TODO(sigmund): investigate alternatives to this approach.
return loadProgramFromBytes(outlineBytes);
}
static Future<FastaContext> create(
@ -256,7 +259,7 @@ class Outline extends Step<TestDescription, Program, FastaContext> {
}
p = await sourceTarget.buildOutlines();
if (fullCompile) {
p = await sourceTarget.buildProgram();
p = await sourceTarget.buildProgram(trimDependencies: true);
instrumentation?.finish();
if (instrumentation != null && instrumentation.hasProblems) {
if (updateComments) {

View file

@ -7,11 +7,11 @@ import 'dart:async';
import 'package:front_end/compiler_options.dart';
import 'package:front_end/incremental_kernel_generator.dart';
import 'package:front_end/memory_file_system.dart';
import 'package:front_end/src/fasta/kernel/utils.dart';
import 'package:front_end/src/incremental/byte_store.dart';
import 'package:front_end/src/incremental_kernel_generator_impl.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/binary/ast_from_binary.dart';
import 'package:kernel/binary/limited_ast_to_binary.dart';
import 'package:kernel/text/ast_to_text.dart';
import 'package:kernel/verifier.dart';
import 'package:test/test.dart';
@ -506,8 +506,11 @@ main() {
Library initialLibrary = _getLibrary(program, bUri);
initialKernelText = _getLibraryText(initialLibrary);
bytes = serializeProgram(program,
filter: (library) => library.importUri == bUri);
var byteSink = new ByteSink();
var printer = new LimitedBinaryPrinter(
byteSink, (library) => library.importUri == bUri);
printer.writeProgramFile(program);
bytes = byteSink.builder.takeBytes();
// Remove b.dart from the program.
// So, the program is now ready for re-adding the library.

View file

@ -1,210 +0,0 @@
// Copyright (c) 2017, 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 'package:front_end/front_end.dart';
import 'package:front_end/src/fasta/kernel/utils.dart';
import 'package:front_end/src/testing/compiler_common.dart';
import 'package:kernel/ast.dart';
import 'package:test/test.dart';
main() {
group('kernelForProgram', () {
test('compiler fails if it cannot find sdk sources', () async {
var errors = [];
var options = new CompilerOptions()
..dartLibraries = invalidCoreLibs
..sdkSummary = null
..compileSdk = true // To prevent FE from loading an sdk-summary.
..onError = (e) => errors.add(e);
var program =
await compileScript('main() => print("hi");', options: options);
expect(program, isNull);
expect(errors, isNotEmpty);
});
test('compiler fails if it cannot find sdk summary', () async {
var errors = [];
var options = new CompilerOptions()
..sdkSummary = Uri.parse('file:///not_existing_summary_file')
..onError = (e) => errors.add(e);
var program =
await compileScript('main() => print("hi");', options: options);
expect(program, isNull);
expect(errors, isNotEmpty);
});
test('by default program is compiled using summaries', () async {
var options = new CompilerOptions()
// Note: we define [dartLibraries] with broken URIs to ensure we do not
// attempt to lookup for sources of the sdk directly.
..dartLibraries = invalidCoreLibs;
var program =
await compileScript('main() => print("hi");', options: options);
var core = program.libraries.firstWhere(isDartCoreLibrary);
var printMember = core.members.firstWhere((m) => m.name.name == 'print');
// Note: summaries created by the SDK today contain empty statements as
// method bodies.
expect(printMember.function.body is EmptyStatement, isTrue);
});
test('compiler requires a main method', () async {
var errors = [];
var options = new CompilerOptions()..onError = (e) => errors.add(e);
await compileScript('a() => print("hi");', options: options);
expect('${errors.first}', contains("No 'main' method found"));
});
test('default error handler throws', () async {
var exceptionThrown = false;
try {
await compileScript('a() => print("hi");');
} catch (e) {
exceptionThrown = true;
expect('$e', contains("No 'main' method found"));
}
expect(exceptionThrown, isTrue);
});
test('generated program contains source-info', () async {
var program = await compileScript('a() => print("hi"); main() {}',
fileName: 'a.dart');
// Kernel always store an empty '' key in the map, so there is always at
// least one. Having more means that source-info is added.
expect(program.uriToSource.keys.length, greaterThan(1));
expect(program.uriToSource['file:///a/b/c/a.dart'], isNotNull);
});
test('code from summary dependencies are marked external', () async {
var program = await compileScript('a() => print("hi"); main() {}',
fileName: 'a.dart');
for (var lib in program.libraries) {
if (lib.importUri.scheme == 'dart') {
expect(lib.isExternal, isTrue);
}
}
// Pretend that the compiled code is a summary
var bytes = serializeProgram(program);
program = await compileScript(
{
'b.dart': 'import "a.dart" as m; b() => m.a(); main() {}',
'summary.dill': bytes
},
fileName: 'b.dart',
inputSummaries: ['summary.dill']);
var aLib = program.libraries
.firstWhere((lib) => lib.importUri.path == '/a/b/c/a.dart');
expect(aLib.isExternal, isTrue);
});
test('code from linked dependencies are not marked external', () async {
var program = await compileScript('a() => print("hi"); main() {}',
fileName: 'a.dart');
for (var lib in program.libraries) {
if (lib.importUri.scheme == 'dart') {
expect(lib.isExternal, isTrue);
}
}
var bytes = serializeProgram(program);
program = await compileScript(
{
'b.dart': 'import "a.dart" as m; b() => m.a(); main() {}',
'link.dill': bytes
},
fileName: 'b.dart',
linkedDependencies: ['link.dill']);
var aLib = program.libraries
.firstWhere((lib) => lib.importUri.path == '/a/b/c/a.dart');
expect(aLib.isExternal, isFalse);
});
// TODO(sigmund): add tests discovering libraries.json
});
group('kernelForBuildUnit', () {
test('compiler does not require a main method', () async {
var errors = [];
var options = new CompilerOptions()..onError = (e) => errors.add(e);
await compileUnit(['a.dart'], {'a.dart': 'a() => print("hi");'},
options: options);
expect(errors, isEmpty);
});
test('compiler by default is hermetic', () async {
var errors = [];
var options = new CompilerOptions()..onError = (e) => errors.add(e);
var sources = {
'a.dart': 'import "b.dart"; a() => print("hi");',
'b.dart': ''
};
await compileUnit(['a.dart'], sources, options: options);
expect(errors.first.toString(), contains('Invalid access'));
errors.clear();
await compileUnit(['a.dart', 'b.dart'], sources, options: options);
expect(errors, isEmpty);
});
test('chaseDependencies=true removes hermetic restriction', () async {
var errors = [];
var options = new CompilerOptions()
..chaseDependencies = true
..onError = (e) => errors.add(e);
await compileUnit([
'a.dart'
], {
'a.dart': 'import "b.dart"; a() => print("hi");',
'b.dart': ''
}, options: options);
expect(errors, isEmpty);
});
test('dependencies can be loaded in any order', () async {
var sources = <String, dynamic>{
'a.dart': 'a() => print("hi");',
'b.dart': 'import "a.dart"; b() => a();',
'c.dart': 'import "b.dart"; c() => b();',
'd.dart': 'import "c.dart"; d() => c();',
};
var unitA = await compileUnit(['a.dart'], sources);
// Pretend that the compiled code is a summary
sources['a.dill'] = serializeProgram(unitA);
var unitBC = await compileUnit(['b.dart', 'c.dart'], sources,
inputSummaries: ['a.dill']);
// Pretend that the compiled code is a summary
sources['bc.dill'] = serializeProgram(unitBC);
void checkDCallsC(Program program) {
var dLib = findLibrary(program, 'd.dart');
var cLib = findLibrary(program, 'c.dart');
var dMethod = dLib.procedures.first;
var dBody = dMethod.function.body;
var dCall = (dBody as ReturnStatement).expression;
var callTarget =
(dCall as StaticInvocation).targetReference.asProcedure;
expect(callTarget, same(cLib.procedures.first));
}
var unitD1 = await compileUnit(['d.dart'], sources,
inputSummaries: ['a.dill', 'bc.dill']);
checkDCallsC(unitD1);
var unitD2 = await compileUnit(['d.dart'], sources,
inputSummaries: ['bc.dill', 'a.dill']);
checkDCallsC(unitD2);
});
// TODO(sigmund): add tests with trimming dependencies
});
}

View file

@ -9,7 +9,7 @@ import 'package:front_end/memory_file_system.dart';
import 'package:front_end/src/base/processed_options.dart';
import 'package:front_end/src/fasta/fasta.dart' show ByteSink;
import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
import 'package:kernel/kernel.dart' show Program, Library, CanonicalName;
import 'package:kernel/kernel.dart' show Program, Library;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@ -37,22 +37,6 @@ class ProcessedOptionsTest {
}
}
test_sdk_summary_inferred() {
// The sdk-summary is inferred by default form sdk-root, when compile-sdk is
// false
var raw = new CompilerOptions()
..sdkRoot = Uri.parse('file:///sdk/dir/')
..compileSdk = false;
expect(new ProcessedOptions(raw).sdkSummary,
Uri.parse('file:///sdk/dir/outline.dill'));
// But it is left null when compile-sdk is true
raw = new CompilerOptions()
..sdkRoot = Uri.parse('file:///sdk/dir/')
..compileSdk = true;
expect(new ProcessedOptions(raw).sdkSummary, null);
}
test_fileSystem_noBazelRoots() {
// When no bazel roots are specified, the filesystem should be passed
// through unmodified.
@ -77,7 +61,7 @@ class ProcessedOptionsTest {
Future<Null> checkMockSummary(CompilerOptions raw) async {
var processed = new ProcessedOptions(raw);
var sdkSummary = await processed.loadSdkSummary(new CanonicalName.root());
var sdkSummary = await processed.sdkSummaryProgram;
expect(sdkSummary.libraries.single.importUri,
mockSummary.libraries.single.importUri);
}
@ -129,97 +113,4 @@ class ProcessedOptionsTest {
var uriTranslator = await processed.getUriTranslator();
expect(uriTranslator.packages, isEmpty);
}
test_validateOptions_root_exists() async {
var sdkRoot = Uri.parse('file:///sdk/root/');
fileSystem
// Note: this test is a bit hackish because the memory file system
// doesn't have the notion of directories.
.entityForUri(sdkRoot)
.writeAsStringSync('\n');
fileSystem
.entityForUri(sdkRoot.resolve('outline.dill'))
.writeAsStringSync('\n');
var errors = [];
var raw = new CompilerOptions()
..sdkRoot = sdkRoot
..fileSystem = fileSystem
..onError = (e) => errors.add(e);
var options = new ProcessedOptions(raw);
var result = await options.validateOptions();
// Note: we check this first so test failures show the cause directly.
expect(errors, isEmpty);
expect(result, isTrue);
}
test_validateOptions_root_doesnt_exists() async {
var sdkRoot = Uri.parse('file:///sdk/root');
var errors = [];
var raw = new CompilerOptions()
..sdkRoot = sdkRoot
..fileSystem = fileSystem
..onError = (e) => errors.add(e);
var options = new ProcessedOptions(raw);
expect(await options.validateOptions(), isFalse);
expect('${errors.first}', contains("SDK root directory not found"));
}
test_validateOptions_summary_exists() async {
var sdkSummary = Uri.parse('file:///sdk/root/outline.dill');
fileSystem.entityForUri(sdkSummary).writeAsStringSync('\n');
var errors = [];
var raw = new CompilerOptions()
..sdkSummary = sdkSummary
..fileSystem = fileSystem
..onError = (e) => errors.add(e);
var options = new ProcessedOptions(raw);
var result = await options.validateOptions();
expect(errors, isEmpty);
expect(result, isTrue);
}
test_validateOptions_summary_doesnt_exists() async {
var sdkSummary = Uri.parse('file:///sdk/root/outline.dill');
var errors = [];
var raw = new CompilerOptions()
..sdkSummary = sdkSummary
..fileSystem = fileSystem
..onError = (e) => errors.add(e);
var options = new ProcessedOptions(raw);
expect(await options.validateOptions(), isFalse);
expect('${errors.first}', contains("SDK summary not found"));
}
test_validateOptions_inferred_summary_exists() async {
var sdkRoot = Uri.parse('file:///sdk/root/');
var sdkSummary = Uri.parse('file:///sdk/root/outline.dill');
fileSystem.entityForUri(sdkRoot).writeAsStringSync('\n');
fileSystem.entityForUri(sdkSummary).writeAsStringSync('\n');
var errors = [];
var raw = new CompilerOptions()
..sdkRoot = sdkRoot
..fileSystem = fileSystem
..onError = (e) => errors.add(e);
var options = new ProcessedOptions(raw);
var result = await options.validateOptions();
expect(errors, isEmpty);
expect(result, isTrue);
}
test_validateOptions_inferred_summary_doesnt_exists() async {
var sdkRoot = Uri.parse('file:///sdk/root/');
var sdkSummary = Uri.parse('file:///sdk/root/outline.dill');
fileSystem.entityForUri(sdkRoot).writeAsStringSync('\n');
var errors = [];
var raw = new CompilerOptions()
..sdkSummary = sdkSummary
..fileSystem = fileSystem
..onError = (e) => errors.add(e);
var options = new ProcessedOptions(raw);
expect(await options.validateOptions(), isFalse);
expect('${errors.first}', contains("SDK summary not found"));
}
}

View file

@ -197,7 +197,7 @@ Future<Null> writeProgram(Program program, Uri outputUri) async {
// TODO(sigmund): the incremental generator should always filter these
// libraries instead.
new LimitedBinaryPrinter(
sink, (library) => library.importUri.scheme != 'dart', false)
sink, (library) => library.importUri.scheme != 'dart')
.writeProgramFile(program);
await sink.close();
}

View file

@ -41,7 +41,10 @@ final subpackageRules = {
'lib': new SubpackageRules(allowedDependencies: [
'lib/src',
'lib/src/base',
'lib/src/incremental',
'lib/src/fasta',
'lib/src/fasta/dill',
'lib/src/fasta/kernel',
'lib/src/incremental'
]),
'lib/src': new SubpackageRules(allowedDependencies: [
'lib',
@ -52,13 +55,15 @@ final subpackageRules = {
'lib/src/fasta/source',
'lib/src/incremental',
]),
'lib/src/base': new SubpackageRules(
allowedDependencies: ['lib', 'lib/src/fasta', 'lib/src/incremental']),
'lib/src/base': new SubpackageRules(allowedDependencies: [
'lib',
'lib/src',
'lib/src/fasta',
'lib/src/incremental'
]),
'lib/src/codegen': new SubpackageRules(),
'lib/src/fasta': new SubpackageRules(allowedDependencies: [
'lib',
'lib/src',
'lib/src/base',
'lib/src/fasta/builder',
'lib/src/fasta/dill',
'lib/src/fasta/kernel',
@ -116,7 +121,6 @@ final subpackageRules = {
'lib/src/scanner',
]),
'lib/src/fasta/testing': new SubpackageRules(allowedDependencies: [
'lib',
'lib/src/fasta',
'lib/src/base',
'lib/src/fasta/kernel',
@ -148,7 +152,6 @@ final subpackageRules = {
]),
'lib/src/testing': new SubpackageRules(allowedDependencies: [
'lib',
'lib/src/fasta/testing',
]),
};

View file

@ -1,152 +0,0 @@
// Copyright (c) 2017, 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 'package:front_end/front_end.dart';
import 'package:front_end/src/testing/compiler_common.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/kernel.dart';
import 'package:test/test.dart';
main() {
test('summary has no source-info by default', () async {
var summary = await summarize(['a.dart'], allSources);
var program = loadProgramFromBytes(summary);
// Note: the kernel representation always has an empty '' key in the map,
// but otherwise no other data is included here.
expect(program.uriToSource.keys.single, '');
});
test('summary includes declarations, but no method bodies', () async {
var summary = await summarize(['a.dart'], allSources);
var program = loadProgramFromBytes(summary);
var aLib = findLibrary(program, 'a.dart');
expect(aLib.importUri.path, '/a/b/c/a.dart');
var classA = aLib.classes.first;
expect(classA.name, 'A');
var fooMethod = classA.procedures.first;
expect(fooMethod.name.name, 'foo');
expect(fooMethod.function.body is EmptyStatement, isTrue);
});
test('summarized libraries are not marked external', () async {
var summary = await summarize(['a.dart'], allSources);
var program = loadProgramFromBytes(summary);
var aLib = findLibrary(program, 'a.dart');
expect(aLib.importUri.path, '/a/b/c/a.dart');
expect(aLib.isExternal, isFalse);
});
test('sdk dependencies are marked external', () async {
// Note: by default this test is loading the SDK from summaries.
var summary = await summarize(['a.dart'], allSources);
var program = loadProgramFromBytes(summary);
var coreLib = findLibrary(program, 'core');
expect(coreLib.isExternal, isTrue);
});
test('non-sdk dependencies are marked external', () async {
var summaryA = await summarize(['a.dart'], allSources);
var sourcesWithA = new Map.from(allSources);
sourcesWithA['a.dill'] = summaryA;
var summaryB =
await summarize(['b.dart'], sourcesWithA, inputSummaries: ['a.dill']);
var program = loadProgramFromBytes(summaryB);
var aLib = findLibrary(program, 'a.dart');
var bLib = findLibrary(program, 'b.dart');
expect(aLib.isExternal, isTrue);
expect(bLib.isExternal, isFalse);
});
test('dependencies can be combined without conflict', () async {
var summaryA = await summarize(['a.dart'], allSources);
var sourcesWithA = new Map.from(allSources);
sourcesWithA['a.dill'] = summaryA;
var summaryBC = await summarize(['b.dart', 'c.dart'], sourcesWithA,
inputSummaries: ['a.dill']);
var sourcesWithABC = new Map.from(sourcesWithA);
sourcesWithABC['bc.dill'] = summaryBC;
// Note: a is loaded first, bc.dill have a.dart as an external reference so
// we want to ensure loading them here will not create a problem.
var summaryD = await summarize(['d.dart'], sourcesWithABC,
inputSummaries: ['a.dill', 'bc.dill']);
checkDSummary(summaryD);
});
test('dependencies can be combined in any order', () async {
var summaryA = await summarize(['a.dart'], allSources);
var sourcesWithA = new Map.from(allSources);
sourcesWithA['a.dill'] = summaryA;
var summaryBC = await summarize(['b.dart', 'c.dart'], sourcesWithA,
inputSummaries: ['a.dill']);
var sourcesWithABC = new Map.from(sourcesWithA);
sourcesWithABC['bc.dill'] = summaryBC;
// Note: unlinke the previous test now bc.dill is loaded first and contains
// an external definition of library a.dart. Using this order also works
// because we share a CanonicalName root to resolve names across multiple
// dill files and because of how the kernel loader merges definitions.
var summaryD = await summarize(['d.dart'], sourcesWithABC,
inputSummaries: ['bc.dill', 'a.dill']);
checkDSummary(summaryD);
});
test('summarization by default is hermetic', () async {
var errors = [];
var options = new CompilerOptions()..onError = (e) => errors.add(e);
await summarize(['b.dart'], allSources, options: options);
expect(errors.first.toString(), contains('Invalid access'));
errors.clear();
await summarize(['a.dart', 'b.dart'], allSources, options: options);
expect(errors, isEmpty);
});
// TODO(sigmund): test trimDependencies when it is part of the public API.
}
var allSources = {
'a.dart': 'class A { foo() { print("hi"); } }',
'b.dart': 'import "a.dart"; class B extends A {}',
'c.dart': 'class C { bar() => 1; }',
'd.dart': '''
import "a.dart";
import "b.dart";
import "c.dart";
class D extends B with C implements A { }''',
};
/// Helper function to check that some expectations from the summary of D.
checkDSummary(List<int> summary) {
var program = loadProgramFromBytes(summary);
var aLib = findLibrary(program, 'a.dart');
var bLib = findLibrary(program, 'b.dart');
var cLib = findLibrary(program, 'c.dart');
var dLib = findLibrary(program, 'd.dart');
// All libraries but `d.dart` are marked external.
expect(aLib.isExternal, isTrue);
expect(bLib.isExternal, isTrue);
expect(cLib.isExternal, isTrue);
expect(dLib.isExternal, isFalse);
// The type-hierarchy for A, B, D is visible and correct
var aClass = aLib.classes.firstWhere((c) => c.name == 'A');
var bClass = bLib.classes.firstWhere((c) => c.name == 'B');
expect(bClass.superclass, same(aClass));
var dClass = dLib.classes.firstWhere((c) => c.name == 'D');
expect(dClass.superclass.superclass, same(bClass));
var dInterface = dClass.implementedTypes.first.classNode;
expect(dInterface, same(aClass));
}

View file

@ -9,15 +9,21 @@ import 'dart:async';
import 'dart:io';
import 'package:analyzer/src/fasta/ast_builder.dart';
import 'package:front_end/front_end.dart';
import 'package:front_end/physical_file_system.dart';
import 'package:front_end/src/fasta/dill/dill_target.dart' show DillTarget;
import 'package:front_end/src/fasta/kernel/kernel_target.dart'
show KernelTarget;
import 'package:front_end/src/fasta/parser.dart';
import 'package:front_end/src/fasta/scanner.dart';
import 'package:front_end/src/fasta/scanner/io.dart' show readBytesFromFileSync;
import 'package:front_end/src/fasta/source/directive_listener.dart';
import 'package:front_end/src/fasta/ticker.dart' show Ticker;
import 'package:front_end/src/fasta/translate_uri.dart' show TranslateUri;
import 'package:front_end/src/fasta/parser/native_support.dart'
import 'package:front_end/src/fasta/translate_uri.dart';
import 'package:front_end/src/fasta/parser/dart_vm_native.dart'
show skipNativeClause;
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget;
/// Cumulative total number of chars scanned.
int inputSize = 0;
@ -44,9 +50,11 @@ main(List<String> args) async {
'kernel_gen_e2e': () async {
await generateKernel(entryUri);
},
'kernel_gen_e2e_sum': () async {
await generateKernel(entryUri, compileSdk: false);
},
// TODO(sigmund): enable once we add a build step to create the
// platform.dill files.
// 'kernel_gen_e2e_sum': () async {
// await generateKernel(entryUri, compileSdk: false);
// },
};
var handler = handlers[bench];
@ -68,17 +76,16 @@ main(List<String> args) async {
}
}
// TODO(sigmund): use `perf.dart::_findSdkPath` here when fasta can patch the
// sdk directly.
Uri sdkRoot =
Uri.base.resolve(Platform.resolvedExecutable).resolve('patched_sdk/');
/// Translates `dart:*` and `package:*` URIs to resolved URIs.
TranslateUri uriResolver;
/// Preliminary set up to be able to correctly resolve URIs on the given
/// program.
Future setup(Uri entryUri) async {
// TODO(sigmund): use `perf.dart::_findSdkPath` here when fasta can patch the
// sdk directly.
var sdkRoot =
Uri.base.resolve(Platform.resolvedExecutable).resolve('patched_sdk/');
uriResolver = await TranslateUri.parse(PhysicalFileSystem.instance, sdkRoot);
}
@ -165,7 +172,7 @@ Set<String> extractDirectiveUris(List<int> contents) {
class DirectiveListenerWithNative extends DirectiveListener {
@override
Token handleNativeClause(Token token) => skipNativeClause(token, true);
Token handleNativeClause(Token token) => skipNativeClause(token);
}
/// Parses every file in [files] and reports the time spent doing so.
@ -200,6 +207,7 @@ class _PartialAstBuilder extends AstBuilder {
}
// Invoke the fasta kernel generator for the program starting in [entryUri]
// TODO(sigmund): update to use the frontend api once fasta is being hit.
generateKernel(Uri entryUri,
{bool compileSdk: true, bool strongMode: false}) async {
// TODO(sigmund): this is here only to compute the input size,
@ -207,15 +215,11 @@ generateKernel(Uri entryUri,
scanReachableFiles(entryUri);
var timer = new Stopwatch()..start();
var options = new CompilerOptions()
..sdkRoot = sdkRoot
..chaseDependencies = true
..packagesFileUri = Uri.base.resolve('.packages')
..compileSdk = compileSdk;
if (!compileSdk) {
options.sdkSummary = sdkRoot.resolve('outline.dill');
}
final Ticker ticker = new Ticker();
final DillTarget dillTarget = new DillTarget(ticker, uriResolver,
new VmFastaTarget(new TargetFlags(strongMode: strongMode)));
final KernelTarget kernelTarget =
new KernelTarget(PhysicalFileSystem.instance, dillTarget, uriResolver);
var entrypoints = [
entryUri,
// These extra libraries are added to match the same set of libraries
@ -232,11 +236,20 @@ generateKernel(Uri entryUri,
Uri.parse('dart:mirrors'),
Uri.parse('dart:typed_data'),
];
var program = await kernelForBuildUnit(entrypoints, options);
entrypoints.forEach(kernelTarget.read);
if (!compileSdk) {
dillTarget.read(
Uri.base.resolve(Platform.resolvedExecutable).resolve('platform.dill'));
}
await dillTarget.buildOutlines();
await kernelTarget.buildOutlines();
var program = await kernelTarget.buildProgram();
if (kernelTarget.errors.isNotEmpty) {
throw kernelTarget.errors.first;
}
timer.stop();
var name = 'kernel_gen_e2e${compileSdk ? "" : "_sum"}';
report(name, timer.elapsedMicroseconds);
report('kernel_gen_e2e', timer.elapsedMicroseconds);
return program;
}

View file

@ -145,6 +145,9 @@ Future<Program> generateKernel(Uri entryUri,
_kernelForProgramViaDartk(Uri source, CompilerOptions options) async {
var loader = await _createLoader(options, entry: source);
if (options.compileSdk) {
options.additionalLibraries.forEach(loader.loadLibrary);
}
loader.loadProgram(source, compileSdk: options.compileSdk);
_reportErrors(loader.errors, options.onError);
return loader.program;
@ -167,8 +170,8 @@ Future<DartLoader> _createLoader(CompilerOptions options,
// URIs correctly even if sdkRoot is inferred and not specified explicitly.
String resolve(Uri patch) => _uriToPath(options.sdkRoot.resolveUri(patch));
options.targetPatches.forEach((name, patches) {
patchPaths['dart:$name'] = patches.map(resolve).toList();
options.targetPatches.forEach((uri, patches) {
patchPaths['$uri'] = patches.map(resolve).toList();
});
AnalysisOptionsImpl analysisOptions = loader.context.analysisOptions;
analysisOptions.patchPaths = patchPaths;
@ -183,6 +186,7 @@ DartOptions _convertOptions(CompilerOptions options) {
// sdk sources.
sdkSummary: options.compileSdk ? null : _uriToPath(options.sdkSummary),
packagePath: _uriToPath(options.packagesFileUri),
customUriMappings: options.uriOverride,
declaredVariables: options.declaredVariables);
}

View file

@ -159,27 +159,16 @@ class BinaryBuilder {
void _fillTreeNodeList(
List<TreeNode> list, TreeNode buildObject(), TreeNode parent) {
var length = readUInt();
list.length = length;
for (int i = 0; i < length; ++i) {
TreeNode object = buildObject();
list[i] = object..parent = parent;
list.length = readUInt();
for (int i = 0; i < list.length; ++i) {
list[i] = buildObject()..parent = parent;
}
}
void _fillNonTreeNodeList(List<Node> list, Node buildObject()) {
var length = readUInt();
list.length = length;
for (int i = 0; i < length; ++i) {
Node object = buildObject();
list[i] = object;
}
}
void _skipNodeList(Node skipObject()) {
var length = readUInt();
for (int i = 0; i < length; ++i) {
skipObject();
list.length = readUInt();
for (int i = 0; i < list.length; ++i) {
list[i] = buildObject();
}
}
@ -381,11 +370,7 @@ class BinaryBuilder {
debugPath.add(library.name ?? library.importUri?.toString() ?? 'library');
if (shouldWriteData) {
_fillTreeNodeList(library.annotations, readExpression, library);
} else {
_skipNodeList(readExpression);
}
_fillTreeNodeList(library.annotations, readExpression, library);
_readLibraryDependencies(library);
_mergeNamedNodeList(library.typedefs, readTypedef, library);
_mergeNamedNodeList(library.classes, readClass, library);
@ -475,11 +460,7 @@ class BinaryBuilder {
readAndPushTypeParameterList(node.typeParameters, node);
var supertype = readSupertypeOption();
var mixedInType = readSupertypeOption();
if (shouldWriteData) {
_fillNonTreeNodeList(node.implementedTypes, readSupertype);
} else {
_skipNodeList(readSupertype);
}
_fillNonTreeNodeList(node.implementedTypes, readSupertype);
_mergeNamedNodeList(node.fields, readField, node);
_mergeNamedNodeList(node.constructors, readConstructor, node);
_mergeNamedNodeList(node.procedures, readProcedure, node);
@ -563,11 +544,7 @@ class BinaryBuilder {
var function = readFunctionNode();
pushVariableDeclarations(function.positionalParameters);
pushVariableDeclarations(function.namedParameters);
if (shouldWriteData) {
_fillTreeNodeList(node.initializers, readInitializer, node);
} else {
_skipNodeList(readInitializer);
}
_fillTreeNodeList(node.initializers, readInitializer, node);
variableStack.length = 0;
var transformerFlags = getAndResetTransformerFlags();
debugPath.removeLast();

View file

@ -13,17 +13,7 @@ import 'package:kernel/binary/ast_to_binary.dart';
class LimitedBinaryPrinter extends BinaryPrinter {
final LibraryFilter predicate;
/// Excludes all uriToSource information.
///
/// By default the [predicate] above will only exclude canonical names and
/// kernel libraries, but it will still emit the sources for all libraries.
/// filtered by libraries matching [predicate].
// TODO(sigmund): provide a way to filter sources directly based on
// [predicate]. That requires special logic to handle sources from part files.
final bool excludeUriToSource;
LimitedBinaryPrinter(
Sink<List<int>> sink, this.predicate, this.excludeUriToSource)
LimitedBinaryPrinter(Sink<List<int>> sink, this.predicate)
: super(sink, stringIndexer: new ReferencesStringIndexer());
@override
@ -78,19 +68,6 @@ class LimitedBinaryPrinter extends BinaryPrinter {
var librariesToWrite = libraries.where(predicate).toList();
super.writeProgramIndex(program, librariesToWrite);
}
void writeUriToSource(Program program) {
if (!excludeUriToSource) {
super.writeUriToSource(program);
} else {
// Emit a practically empty uriToSrouce table.
writeStringTable(new StringIndexer());
// Add an entry for '', which is always included by default.
writeUtf8Bytes(const <int>[]);
writeUInt30(0);
}
}
}
/// Extension of [StringIndexer] that also indexes canonical names of

View file

@ -121,29 +121,6 @@ abstract class Target {
void performGlobalTransformations(CoreTypes coreTypes, Program program,
{void logger(String msg)});
/// Whether a platform library may define a restricted type, such as `bool`,
/// `int`, `double`, `num`, and `String`.
///
/// By default only `dart:core` may define restricted types, but some target
/// implementations override this.
bool mayDefineRestrictedType(Uri uri) =>
uri.scheme == 'dart' && uri.path == 'core';
/// Whether the `native` language extension is supported within [library].
///
/// The `native` language extension is not part of the language specification,
/// it means something else to each target, and it is enabled under different
/// circumstances for each target implementation. For example, the VM target
/// enables it everywhere because of existing support for "dart-ext:" native
/// extensions, but targets like dart2js only enable it on the core libraries.
bool enableNative(Uri uri) => false;
/// There are two variants of the `native` language extension. The VM expects
/// the native token to be followed by string, whereas dart2js and DDC do not.
// TODO(sigmund, ahe): ideally we should remove the `native` syntax, if not,
// we should at least unify the VM and non-VM variants.
bool get nativeExtensionExpectsString => false;
/// Builds an expression that instantiates an [Invocation] that can be passed
/// to [noSuchMethod].
Expression instantiateInvocation(CoreTypes coreTypes, Expression receiver,

View file

@ -269,12 +269,4 @@ class VmTarget extends Target {
new NamedExpression("growable", new BoolLiteral(false))
]));
}
// TODO(sigmund,ahe): limit this to `dart-ext` libraries only (see
// https://github.com/dart-lang/sdk/issues/29763).
@override
bool enableNative(Uri uri) => true;
@override
bool get nativeExtensionExpectsString => true;
}

View file

@ -6,10 +6,15 @@ library test.kernel.closures.suite;
import 'dart:async' show Future;
import 'package:front_end/physical_file_system.dart' show PhysicalFileSystem;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:testing/testing.dart'
show Chain, ChainContext, Result, Step, runMe;
show Chain, ChainContext, Result, Step, TestDescription, runMe;
import 'package:front_end/src/fasta/testing/patched_sdk_location.dart'
show computePatchedSdk;
import 'package:kernel/ast.dart' show Program, Library;
@ -17,25 +22,40 @@ import 'package:kernel/transformations/closure_conversion.dart'
as closure_conversion;
import 'package:front_end/src/fasta/testing/kernel_chain.dart'
show
Print,
MatchExpectation,
WriteDill,
ReadDill,
Verify,
Compile,
CompileContext;
show Print, MatchExpectation, WriteDill, ReadDill, Verify;
import 'package:front_end/src/fasta/ticker.dart' show Ticker;
import 'package:front_end/src/fasta/dill/dill_target.dart' show DillTarget;
import 'package:front_end/src/fasta/kernel/kernel_target.dart'
show KernelTarget;
import 'package:front_end/src/fasta/translate_uri.dart' show TranslateUri;
import 'package:front_end/src/fasta/errors.dart' show InputError;
import 'package:front_end/src/fasta/testing/patched_sdk_location.dart';
import 'package:kernel/kernel.dart' show loadProgramFromBinary;
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget;
const String STRONG_MODE = " strong mode ";
class ClosureConversionContext extends ChainContext implements CompileContext {
class ClosureConversionContext extends ChainContext {
final bool strongMode;
final TranslateUri uriTranslator;
final List<Step> steps;
ClosureConversionContext(this.strongMode, bool updateExpectations)
ClosureConversionContext(
this.strongMode, bool updateExpectations, this.uriTranslator)
: steps = <Step>[
const Compile(),
const FastaCompile(),
const Print(),
const Verify(true),
const ClosureConversion(),
@ -48,11 +68,21 @@ class ClosureConversionContext extends ChainContext implements CompileContext {
// TODO(29143): add `Run` step when Vectors are added to VM.
];
Future<Program> loadPlatform() async {
Uri sdk = await computePatchedSdk();
return loadProgramFromBinary(sdk.resolve('platform.dill').toFilePath());
}
static Future<ClosureConversionContext> create(
Chain suite, Map<String, String> environment) async {
Uri sdk = await computePatchedSdk();
Uri packages = Uri.base.resolve(".packages");
bool strongMode = environment.containsKey(STRONG_MODE);
bool updateExpectations = environment["updateExpectations"] == "true";
return new ClosureConversionContext(strongMode, updateExpectations);
TranslateUri uriTranslator = await TranslateUri
.parse(PhysicalFileSystem.instance, sdk, packages: packages);
return new ClosureConversionContext(
strongMode, updateExpectations, uriTranslator);
}
}
@ -63,6 +93,36 @@ Future<ClosureConversionContext> createContext(
return ClosureConversionContext.create(suite, environment);
}
class FastaCompile
extends Step<TestDescription, Program, ClosureConversionContext> {
const FastaCompile();
String get name => "fasta compilation";
Future<Result<Program>> run(
TestDescription description, ClosureConversionContext context) async {
Program platform = await context.loadPlatform();
Ticker ticker = new Ticker();
DillTarget dillTarget = new DillTarget(ticker, context.uriTranslator,
new VmFastaTarget(new TargetFlags(strongMode: context.strongMode)));
platform.unbindCanonicalNames();
dillTarget.loader.appendLibraries(platform);
KernelTarget sourceTarget = new KernelTarget(
PhysicalFileSystem.instance, dillTarget, context.uriTranslator);
Program p;
try {
sourceTarget.read(description.uri);
await dillTarget.buildOutlines();
await sourceTarget.buildOutlines();
p = await sourceTarget.buildProgram();
} on InputError catch (e, s) {
return fail(null, e.error, s);
}
return pass(p);
}
}
class ClosureConversion
extends Step<Program, Program, ClosureConversionContext> {
const ClosureConversion();

View file

@ -8,34 +8,99 @@ import 'dart:async' show Future;
import 'dart:io' show File;
import 'package:front_end/physical_file_system.dart' show PhysicalFileSystem;
import 'package:testing/testing.dart'
show Chain, ChainContext, Result, Step, runMe;
show Chain, ChainContext, Result, Step, TestDescription, runMe;
import 'package:front_end/src/fasta/testing/patched_sdk_location.dart'
show computePatchedSdk;
import 'package:kernel/ast.dart' show Program, Library;
import 'package:front_end/src/fasta/testing/kernel_chain.dart'
show runDiff, Compile, CompileContext;
import 'package:front_end/src/fasta/testing/kernel_chain.dart' show runDiff;
import 'package:front_end/src/fasta/ticker.dart' show Ticker;
import 'package:front_end/src/fasta/dill/dill_target.dart' show DillTarget;
import 'package:front_end/src/fasta/kernel/kernel_target.dart'
show KernelTarget;
import 'package:front_end/src/fasta/translate_uri.dart' show TranslateUri;
import 'package:front_end/src/fasta/errors.dart' show InputError;
import 'package:front_end/src/fasta/testing/patched_sdk_location.dart';
import 'package:kernel/kernel.dart' show loadProgramFromBinary;
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget;
import 'package:kernel/interpreter/interpreter.dart';
const String STRONG_MODE = " strong mode ";
class InterpreterContext extends ChainContext implements CompileContext {
class InterpreterContext extends ChainContext {
final bool strongMode;
final TranslateUri uriTranslator;
final List<Step> steps;
InterpreterContext(this.strongMode)
Future<Program> platform;
InterpreterContext(this.strongMode, this.uriTranslator)
: steps = <Step>[
const Compile(),
const FastaCompile(),
const Interpret(),
const MatchLogExpectation(".expect"),
];
Future<Program> loadPlatform() async {
Uri sdk = await computePatchedSdk();
return loadProgramFromBinary(sdk.resolve('platform.dill').toFilePath());
}
static Future<InterpreterContext> create(
Chain suite, Map<String, String> environment) async {
Uri sdk = await computePatchedSdk();
Uri packages = Uri.base.resolve(".packages");
bool strongMode = environment.containsKey(STRONG_MODE);
return new InterpreterContext(strongMode);
TranslateUri uriTranslator = await TranslateUri
.parse(PhysicalFileSystem.instance, sdk, packages: packages);
return new InterpreterContext(strongMode, uriTranslator);
}
}
class FastaCompile extends Step<TestDescription, Program, InterpreterContext> {
const FastaCompile();
String get name => "fasta compile";
Future<Result<Program>> run(
TestDescription description, InterpreterContext context) async {
Program platform = await context.loadPlatform();
Ticker ticker = new Ticker();
DillTarget dillTarget = new DillTarget(ticker, context.uriTranslator,
new VmFastaTarget(new TargetFlags(strongMode: context.strongMode)));
platform.unbindCanonicalNames();
dillTarget.loader.appendLibraries(platform);
KernelTarget sourceTarget = new KernelTarget(
PhysicalFileSystem.instance, dillTarget, context.uriTranslator);
Program p;
try {
sourceTarget.read(description.uri);
await dillTarget.buildOutlines();
await sourceTarget.buildOutlines();
p = await sourceTarget.buildProgram();
} on InputError catch (e, s) {
return fail(null, e.error, s);
}
return pass(p);
}
}

View file

@ -98,8 +98,6 @@ front_end/tool/perf_test: Skip # Issue 28698
[ $runtime == vm && $use_sdk ]
front_end/tool/fasta_perf_test: SkipByDesign # depends on patched_sdk which is not built into the sdk
front_end/test/kernel_generator_test: SkipByDesign # depends on patched_sdk which is not built into the sdk
front_end/test/summary_generator_test: SkipByDesign # depends on patched_sdk which is not built into the sdk
[ $runtime == vm && $system == windows]
analysis_server/*: Skip # Issue 27557

View file

@ -0,0 +1,6 @@
{
"libraries": {
"vmservice_io": "../../vmservice/vmservice_io.dart",
"_vmservice": "../../../../sdk/lib/vmservice/vmservice.dart"
}
}

View file

@ -71,6 +71,8 @@ check_elements_invariants_test: Slow, Pass, Timeout # Slow due to inlining in th
uri_retention_test: Fail # Issue 26504
dill_loader_test: Fail # Issue 29856
[ ! $checked ]
exit_code_test: Skip # This tests requires checked mode.
serialization*: Slow, Pass

View file

@ -16,10 +16,22 @@ import 'package:compiler/src/library_loader.dart' show ScriptLoader;
import 'package:compiler/src/script.dart' show Script;
import 'package:compiler/src/apiimpl.dart' show CompilerImpl;
import "package:expect/expect.dart";
import 'package:front_end/front_end.dart';
import 'package:front_end/src/fasta/kernel/utils.dart' show serializeProgram;
import 'package:compiler/src/kernel/dart2js_target.dart';
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:path/path.dart' as path;
final String dartkExecutable = Platform.isWindows
? 'tools/dartk_wrappers/dartk.bat'
: 'tools/dartk_wrappers/dartk';
/// Run the dartk.dart script, and return the binary encoded results.
List<int> runDartk(String filename) {
String basePath = path.fromUri(Uri.base);
String dartkPath = path.normalize(path.join(basePath, dartkExecutable));
var args = [filename, '-fbin', '-ostdout'];
ProcessResult result = Process.runSync(dartkPath, args, stdoutEncoding: null);
Expect.equals(0, result.exitCode, result.stderr);
return result.stdout;
}
class TestScriptLoader implements ScriptLoader {
CompilerImpl compiler;
@ -41,19 +53,8 @@ main() {
DiagnosticCollector diagnostics = new DiagnosticCollector();
OutputCollector output = new OutputCollector();
Uri entryPoint = Uri.parse('memory:main.dill');
List<int> kernelBinary = runDartk(filename);
var platform = Uri
.parse(Platform.resolvedExecutable)
.resolve('patched_dart2js_sdk/platform.dill');
var options = new CompilerOptions()
..target = new Dart2jsTarget(new TargetFlags())
..packagesFileUri = Platform.script.resolve('../../../.packages')
..linkedDependencies = [platform]
..verify = true
..onError = errorHandler;
List<int> kernelBinary =
serializeProgram(await kernelForProgram(uri, options));
CompilerImpl compiler = compilerFor(
entryPoint: entryPoint,
memorySourceFiles: {'main.dill': kernelBinary},
@ -76,8 +77,3 @@ main() {
Expect.isNotNull(member);
});
}
void errorHandler(CompilationError e) {
exitCode = 1;
print(e.message);
}

View file

@ -16,18 +16,11 @@ import 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:path/path.dart' as path;
import 'package:front_end/front_end.dart';
import 'package:front_end/src/base/processed_options.dart';
import 'package:front_end/src/kernel_generator_impl.dart';
import 'package:front_end/src/fasta/util/relativize.dart' show relativizeUri;
import 'package:front_end/src/fasta/fasta.dart' as fasta
show compile, compilePlatform, writeDepsFile;
import 'package:front_end/src/fasta/fasta.dart' as fasta show getDependencies;
import 'package:front_end/src/fasta/kernel/utils.dart' show writeProgramToFile;
import 'package:kernel/target/targets.dart';
import 'package:kernel/target/vm_fasta.dart';
import 'package:kernel/target/flutter_fasta.dart';
import 'package:compiler/src/kernel/dart2js_target.dart' show Dart2jsTarget;
import 'package:compiler/src/kernel/fasta_support.dart' as dart2js
show compilePlatform;
/// Set of input files that were read by this script to generate patched SDK.
/// We will dump it out into the depfile for ninja to use.
@ -126,32 +119,34 @@ Future _main(List<String> argv) async {
await _writeSync(
librariesJson.toFilePath(), JSON.encode({"libraries": locations}));
var flags = new TargetFlags();
var target = forVm
? new VmFastaTarget(flags)
: (forFlutter ? new FlutterFastaTarget(flags) : new Dart2jsTarget(flags));
var platformDeps =
await compilePlatform(outDirUri, target, packages, platform, outline);
deps.addAll(platformDeps);
if (forVm || forFlutter) {
await fasta.compilePlatform(outDirUri, platform,
packages: packages,
outlineOutput: outline,
backendTarget: forVm ? 'vm_fasta' : 'flutter_fasta');
} else {
await dart2js.compilePlatform(outDirUri, platform,
packages: packages, outlineOutput: outline);
}
if (forVm) {
// TODO(sigmund): add support for the flutter vmservice_sky as well.
var vmserviceName = 'vmservice_io';
var base = path.fromUri(Platform.script);
Uri dartDir =
Uri repositoryDir =
new Uri.directory(path.dirname(path.dirname(path.absolute(base))));
var program = await kernelForProgram(
Uri.parse('dart:$vmserviceName'),
new CompilerOptions()
..sdkSummary = outline
..dartLibraries = <String, Uri>{
'_vmservice': outDirUri.resolve('lib/vmservice/vmservice.dart'),
'vmservice_io':
dartDir.resolve('runtime/bin/vmservice/vmservice_io.dart'),
}
..packagesFileUri = packages);
var vmserviceName = 'vmservice_io';
Uri vmserviceSdk = repositoryDir.resolve('runtime/bin/vmservice_sdk/');
Uri vmserviceUri = outDirUri.resolve('$vmserviceName.dill');
await writeProgramToFile(program, vmserviceUri);
// TODO(sigmundch): Specify libraries.json directly instead of "--sdk"
// after #29882 is fixed.
await fasta.compile([
"--sdk=$vmserviceSdk",
"--platform=$outline",
"--target=vm_fasta",
"--packages=$packages",
"dart:$vmserviceName",
"-o",
"$vmserviceUri",
]);
}
Uri platformFinalLocation = outDirUri.resolve('platform.dill');
@ -172,8 +167,18 @@ Future _main(List<String> argv) async {
// sdk library used by this script indirectly depends on a VM-specific
// patch file.
//
// These set of files is discovered by `getDependencies` below, and the
// These set of files is discovered by `writeDepsFile` below, and the
// [platformForDeps] is always the VM-specific `platform.dill` file.
//
// TODO(sigmund): we should change this:
// - we should rewrite writeDepsFile: fasta could provide an API to crawl
// the dependencies, but anything that is GN specific, should be on
// this file instead.
//
// - We don't need to include sdk dependencies of the script because
// those are already included indirectly (either in [deps] when
// building the sdk for the VM, or via the .GN dependencies in the
// build files for dart2js and flutter).
var platformForDeps = platform;
var sdkDir = outDirUri;
if (forDart2js || forFlutter) {
@ -183,80 +188,16 @@ Future _main(List<String> argv) async {
platformForDeps = outDirUri.resolve('../patched_sdk/platform.dill');
sdkDir = outDirUri.resolve('../patched_sdk/');
}
deps.addAll(await fasta.getDependencies(Platform.script,
sdk: sdkDir, packages: packages, platform: platformForDeps));
await writeDepsFile(Uri.base.resolveUri(new Uri.file("$outDir.d")),
platformFinalLocation, deps);
await fasta.writeDepsFile(Platform.script,
Uri.base.resolveUri(new Uri.file("$outDir.d")), platformFinalLocation,
sdk: sdkDir,
packages: packages,
platform: platformForDeps,
extraDependencies: deps);
await new File.fromUri(platform).rename(platformFinalLocation.toFilePath());
}
/// Generates an outline.dill and platform.dill file containing the result of
/// compiling a platform's SDK.
///
/// Returns a list of dependencies read by the compiler. This list can be used
/// to create GN dependency files.
Future<List<Uri>> compilePlatform(Uri patchedSdk, Target target, Uri packages,
Uri fullOutput, Uri outlineOutput) async {
var options = new CompilerOptions()
..strongMode = false
..compileSdk = true
..sdkRoot = patchedSdk
..packagesFileUri = packages
..chaseDependencies = true
..target = target;
var result = await generateKernel(
new ProcessedOptions(
options,
// TODO(sigmund): pass all sdk libraries needed here, and make this
// hermetic.
false,
[Uri.parse('dart:core')]),
buildSummary: true,
buildProgram: true);
new File.fromUri(outlineOutput).writeAsBytesSync(result.summary);
await writeProgramToFile(result.program, fullOutput);
return result.deps;
}
Future writeDepsFile(
Uri output, Uri depsFile, Iterable<Uri> allDependencies) async {
if (allDependencies.isEmpty) return;
String toRelativeFilePath(Uri uri) {
// Ninja expects to find file names relative to the current working
// directory. We've tried making them relative to the deps file, but that
// doesn't work for downstream projects. Making them absolute also
// doesn't work.
//
// We can test if it works by running ninja twice, for example:
//
// ninja -C xcodebuild/ReleaseX64 runtime_kernel -d explain
// ninja -C xcodebuild/ReleaseX64 runtime_kernel -d explain
//
// The second time, ninja should say:
//
// ninja: Entering directory `xcodebuild/ReleaseX64'
// ninja: no work to do.
//
// It's broken if it says something like this:
//
// ninja explain: expected depfile 'patched_sdk.d' to mention
// 'patched_sdk/platform.dill', got
// '/.../xcodebuild/ReleaseX64/patched_sdk/platform.dill'
return Uri.parse(relativizeUri(uri, base: Uri.base)).toFilePath();
}
StringBuffer sb = new StringBuffer();
sb.write(toRelativeFilePath(output));
sb.write(":");
for (Uri uri in allDependencies) {
sb.write(" ");
sb.write(toRelativeFilePath(uri));
}
sb.writeln();
await new File.fromUri(depsFile).writeAsString("$sb");
}
/// Updates the contents of
/// sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart to include
/// declarations for vm internal libraries.

View file

@ -20,91 +20,21 @@
///
library runtime.tools.kernel_service;
import 'dart:async' show Future;
import 'dart:io' show File, Platform hide FileSystemEntity;
import 'dart:async';
import 'dart:io' hide FileSystemEntity;
import 'dart:isolate';
import 'dart:typed_data' show Uint8List;
import 'package:front_end/file_system.dart';
import 'package:front_end/front_end.dart';
import 'package:front_end/memory_file_system.dart';
import 'package:front_end/physical_file_system.dart';
import 'package:front_end/src/fasta/kernel/utils.dart';
import 'package:front_end/src/fasta/vm.dart'
show CompilationResult, Status, parseScriptInFileSystem;
import 'package:front_end/src/testing/hybrid_file_system.dart';
import 'package:kernel/kernel.dart' show Program;
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget;
const bool verbose = const bool.fromEnvironment('DFE_VERBOSE');
const bool strongMode = const bool.fromEnvironment('DFE_STRONG_MODE');
Future<CompilationResult> _parseScriptInFileSystem(
Uri script, FileSystem fileSystem,
{bool verbose: false, bool strongMode: false}) async {
final Uri packagesUri = (Platform.packageConfig != null)
? Uri.parse(Platform.packageConfig)
: await _findPackagesFile(fileSystem, script);
if (packagesUri == null) {
throw "Could not find .packages";
}
final Uri patchedSdk = Uri.base
.resolveUri(new Uri.file(Platform.resolvedExecutable))
.resolveUri(new Uri.directory("patched_sdk"));
if (verbose) {
print("""DFE: Requesting compilation {
scriptUri: ${script}
packagesUri: ${packagesUri}
patchedSdk: ${patchedSdk}
}""");
}
try {
var errors = <String>[];
var options = new CompilerOptions()
..strongMode = strongMode
..fileSystem = fileSystem
..target = new VmFastaTarget(new TargetFlags(strongMode: strongMode))
..packagesFileUri = packagesUri
// TODO(sigmund): use outline.dill when the mixin transformer is modular.
..sdkSummary = patchedSdk.resolve('platform.dill')
..verbose = verbose
..onError = (CompilationError e) => errors.add(e.message);
Program program = await kernelForProgram(script, options);
if (errors.isNotEmpty) return new CompilationResult.errors(errors);
// We serialize the program excluding platform.dill because the VM has these
// sources built-in. Everything loaded as a summary in [kernelForProgram] is
// marked `external`, so we can use that bit to decide what to excluce.
return new CompilationResult.ok(
serializeProgram(program, filter: (lib) => !lib.isExternal));
} catch (err, stack) {
return new CompilationResult.crash(err, stack);
}
}
/// This duplicates functionality from the Loader which we can't easily
/// access from here.
// TODO(sigmund): delete, this should be supported by the default options in
// package:front_end.
Future<Uri> _findPackagesFile(FileSystem fileSystem, Uri base) async {
var dir = new File.fromUri(base).parent;
while (true) {
final packagesFile = dir.uri.resolve(".packages");
if (await fileSystem.entityForUri(packagesFile).exists()) {
return packagesFile;
}
if (dir.parent.path == dir.path) {
break;
}
dir = dir.parent;
}
return null;
}
Future<CompilationResult> _processLoadRequestImpl(
String inputFilePathOrUri, FileSystem fileSystem) {
Uri scriptUri = Uri.parse(inputFilePathOrUri);
@ -120,10 +50,10 @@ Future<CompilationResult> _processLoadRequestImpl(
if (!scriptUri.isScheme('file')) {
// TODO(vegorov): Reuse loader code to support other schemes.
return new Future<CompilationResult>.value(new CompilationResult.errors(
["Expected 'file' scheme for a script uri: got ${scriptUri.scheme}"]));
return new Future<CompilationResult>.value(new CompilationResult.error(
"Expected 'file' scheme for a script uri: got ${scriptUri.scheme}"));
}
return _parseScriptInFileSystem(scriptUri, fileSystem,
return parseScriptInFileSystem(scriptUri, fileSystem,
verbose: verbose, strongMode: strongMode);
}
@ -216,88 +146,3 @@ main([args]) {
return new RawReceivePort()..handler = _processLoadRequest;
}
}
/// Compilation status codes.
///
/// Note: The [index] property of these constants must match
/// `Dart_KernelCompilationStatus` in
/// [dart_api.h](../../../../runtime/include/dart_api.h).
enum Status {
/// Compilation was successful.
ok,
/// Compilation failed with a compile time error.
error,
/// Compiler crashed.
crash,
}
abstract class CompilationResult {
CompilationResult._();
factory CompilationResult.ok(Uint8List bytes) = _CompilationOk;
factory CompilationResult.errors(List<String> errors) = _CompilationError;
factory CompilationResult.crash(Object exception, StackTrace stack) =
_CompilationCrash;
Status get status;
get payload;
List toResponse() => [status.index, payload];
}
class _CompilationOk extends CompilationResult {
final Uint8List bytes;
_CompilationOk(this.bytes) : super._();
@override
Status get status => Status.ok;
@override
get payload => bytes;
String toString() => "_CompilationOk(${bytes.length} bytes)";
}
abstract class _CompilationFail extends CompilationResult {
_CompilationFail() : super._();
String get errorString;
@override
get payload => errorString;
}
class _CompilationError extends _CompilationFail {
final List<String> errors;
_CompilationError(this.errors);
@override
Status get status => Status.error;
@override
String get errorString => errors.take(10).join('\n');
String toString() => "_CompilationError(${errorString})";
}
class _CompilationCrash extends _CompilationFail {
final Object exception;
final StackTrace stack;
_CompilationCrash(this.exception, this.stack);
@override
Status get status => Status.crash;
@override
String get errorString => "${exception}\n${stack}";
String toString() => "_CompilationCrash(${errorString})";
}