d354a28cb2
The introduced "constants" transformation can evaluate constant expressions. The
original use-sites of constant expressions are replaced by a new [ConstantExpression]
node, which points to a subclass of a new [Constant] class hierarchy. Constant
[Field]s and [VariableDeclarations]s will be removed, since all use-sites are
re-written.
The [Constant] class hierarchy is, similarly to the [DartType] class hierarchy, not
part of the AST tree (also has no parent pointer). The constants form a
DAG (directed acyclic graph).
There is no canonicalization requirement of the [Constant] objects referenced by the
AST (via [ConstantExpression]). Although it is beneficial to canonicalize them during
construction, since it reduces time spent in operator==/hashCode.
This CL furthermore adds support for a constant table in the binary format. Similarly
to [String]s, we canonicalize the constants before writing the table to the binary.
The constant table entries in the binary are written in a post-order way, to ensure
easy construction on the backend side.
The text format will be augmented with a "constants { ... }" section at the end,
which lists the constants in the same order as in the binary format.
The transformation can be used by those backends who choose to do so. It is not
enabled by default atm. It should therefore not affect analyzer, fasta or other
components.
Change-Id: I57cd9624fedcf537ab6870db76246149647bed21
Reviewed-on: https://dart-review.googlesource.com/14382
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Kevin Millikin <kmillikin@google.com>
136 lines
4.5 KiB
Dart
Executable File
136 lines
4.5 KiB
Dart
Executable File
#!/usr/bin/env dart
|
|
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:args/args.dart';
|
|
import 'package:kernel/class_hierarchy.dart';
|
|
import 'package:kernel/core_types.dart';
|
|
import 'package:kernel/kernel.dart';
|
|
import 'package:kernel/src/tool/batch_util.dart';
|
|
import 'package:kernel/target/targets.dart';
|
|
import 'package:kernel/transformations/closure_conversion.dart' as closures;
|
|
import 'package:kernel/transformations/constants.dart' as constants;
|
|
import 'package:kernel/transformations/continuation.dart' as cont;
|
|
import 'package:kernel/transformations/empty.dart' as empty;
|
|
import 'package:kernel/transformations/method_call.dart' as method_call;
|
|
import 'package:kernel/transformations/mixin_full_resolution.dart' as mix;
|
|
import 'package:kernel/transformations/treeshaker.dart' as treeshaker;
|
|
// import 'package:kernel/verifier.dart';
|
|
import 'package:kernel/transformations/coq.dart' as coq;
|
|
import 'package:kernel/vm/constants_native_effects.dart';
|
|
|
|
import 'util.dart';
|
|
|
|
ArgParser parser = new ArgParser()
|
|
..addOption('format',
|
|
abbr: 'f',
|
|
allowed: ['text', 'bin'],
|
|
defaultsTo: 'bin',
|
|
help: 'Output format.')
|
|
..addOption('out', abbr: 'o', help: 'Output file.', defaultsTo: null)
|
|
..addFlag('verbose',
|
|
abbr: 'v',
|
|
negatable: false,
|
|
help: 'Be verbose (e.g. prints transformed main library).',
|
|
defaultsTo: false)
|
|
..addOption('embedder-entry-points-manifest',
|
|
allowMultiple: true,
|
|
help: 'A path to a file describing entrypoints '
|
|
'(lines of the form `<library>,<class>,<member>`).')
|
|
..addOption('transformation',
|
|
abbr: 't',
|
|
help: 'The transformation to apply.',
|
|
defaultsTo: 'continuation');
|
|
|
|
main(List<String> arguments) async {
|
|
if (arguments.isNotEmpty && arguments[0] == '--batch') {
|
|
if (arguments.length != 1) {
|
|
throw '--batch cannot be used with other arguments';
|
|
}
|
|
await runBatch((arguments) => runTransformation(arguments));
|
|
} else {
|
|
CompilerOutcome outcome = await runTransformation(arguments);
|
|
exit(outcome == CompilerOutcome.Ok ? 0 : 1);
|
|
}
|
|
}
|
|
|
|
Future<CompilerOutcome> runTransformation(List<String> arguments) async {
|
|
ArgResults options = parser.parse(arguments);
|
|
|
|
if (options.rest.length != 1) {
|
|
throw 'Usage:\n${parser.usage}';
|
|
}
|
|
|
|
var input = options.rest.first;
|
|
var output = options['out'];
|
|
var format = options['format'];
|
|
var verbose = options['verbose'];
|
|
|
|
if (output == null) {
|
|
output = '${input.substring(0, input.lastIndexOf('.'))}.transformed.dill';
|
|
}
|
|
|
|
List<String> embedderEntryPointManifests =
|
|
options['embedder-entry-points-manifest'] as List<String>;
|
|
List<treeshaker.ProgramRoot> programRoots =
|
|
parseProgramRoots(embedderEntryPointManifests);
|
|
|
|
var program = loadProgramFromBinary(input);
|
|
|
|
final coreTypes = new CoreTypes(program);
|
|
final hierarchy = new ClosedWorldClassHierarchy(program);
|
|
switch (options['transformation']) {
|
|
case 'continuation':
|
|
program = cont.transformProgram(coreTypes, program);
|
|
break;
|
|
case 'resolve-mixins':
|
|
mix.transformLibraries(
|
|
new NoneTarget(null), coreTypes, hierarchy, program.libraries);
|
|
break;
|
|
case 'closures':
|
|
program = closures.transformProgram(coreTypes, program);
|
|
break;
|
|
case 'coq':
|
|
program = coq.transformProgram(coreTypes, program);
|
|
break;
|
|
case 'constants':
|
|
final VmConstantsBackend backend = new VmConstantsBackend(coreTypes);
|
|
program = constants.transformProgram(program, backend);
|
|
break;
|
|
case 'treeshake':
|
|
program = treeshaker.transformProgram(coreTypes, hierarchy, program,
|
|
programRoots: programRoots);
|
|
break;
|
|
case 'methodcall':
|
|
program = method_call.transformProgram(coreTypes, hierarchy, program);
|
|
break;
|
|
case 'empty':
|
|
program = empty.transformProgram(program);
|
|
break;
|
|
default:
|
|
throw 'Unknown transformation';
|
|
}
|
|
|
|
// TODO(30631): Fix the verifier so we can check that the transform produced
|
|
// valid output.
|
|
//
|
|
// verifyProgram(program);
|
|
|
|
if (format == 'text') {
|
|
writeProgramToText(program, path: output);
|
|
} else {
|
|
assert(format == 'bin');
|
|
await writeProgramToBinary(program, output);
|
|
}
|
|
|
|
if (verbose) {
|
|
writeLibraryToText(program.mainMethod.parent as Library);
|
|
}
|
|
|
|
return CompilerOutcome.Ok;
|
|
}
|