mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 21:50:11 +00:00
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:
parent
610d081947
commit
4aadfe09df
|
@ -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();
|
||||
}
|
||||
}
|
201
pkg/compiler/lib/src/kernel/fasta_support.dart
Normal file
201
pkg/compiler/lib/src/kernel/fasta_support.dart
Normal 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',
|
||||
];
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 = [];
|
||||
}
|
||||
|
|
|
@ -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';
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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"];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
56
pkg/front_end/lib/src/fasta/parser/dart_vm_native.dart
Normal file
56
pkg/front_end/lib/src/fasta/parser/dart_vm_native.dart
Normal 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;
|
||||
}
|
|
@ -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) {}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
///
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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>>[];
|
||||
|
||||
|
|
165
pkg/front_end/lib/src/fasta/vm.dart
Normal file
165
pkg/front_end/lib/src/fasta/vm.dart
Normal 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;
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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});
|
||||
}
|
11
pkg/front_end/lib/src/simple_error.dart
Normal file
11
pkg/front_end/lib/src/simple_error.dart
Normal 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);
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
]),
|
||||
};
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
6
runtime/bin/vmservice_sdk/lib/libraries.json
Normal file
6
runtime/bin/vmservice_sdk/lib/libraries.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"libraries": {
|
||||
"vmservice_io": "../../vmservice/vmservice_io.dart",
|
||||
"_vmservice": "../../../../sdk/lib/vmservice/vmservice.dart"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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})";
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue