blob: 5a817a631db6aba75b9a08584264589a37c0c50f [file] [log] [blame]
// Copyright (c) 2020, 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:io' show File;
import 'dart:typed_data' show Uint8List;
import 'package:_fe_analyzer_shared/src/messages/codes.dart';
import 'package:compiler/src/kernel/dart2js_target.dart' show Dart2jsTarget;
import 'package:dev_compiler/src/kernel/target.dart' show DevCompilerTarget;
import 'package:front_end/src/api_prototype/compiler_options.dart'
show CompilerOptions, DiagnosticMessage;
import 'package:front_end/src/api_prototype/experimental_flags.dart'
show ExperimentalFlag;
import 'package:front_end/src/base/processed_options.dart'
show ProcessedOptions;
import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
import 'package:front_end/src/fasta/incremental_compiler.dart'
show IncrementalCompiler;
import 'package:front_end/src/fasta/kernel/constant_evaluator.dart' as constants
show EvaluationMode, transformLibraries, ErrorReporter;
import 'package:front_end/src/fasta/kernel/kernel_target.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/binary/ast_from_binary.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/target/changed_structure_notifier.dart';
import 'package:kernel/target/targets.dart'
show ConstantsBackend, DiagnosticReporter, Target, TargetFlags;
import 'package:kernel/type_environment.dart';
import "package:vm/target/flutter.dart" show FlutterTarget;
import "package:vm/target/vm.dart" show VmTarget;
import 'incremental_suite.dart' show getOptions;
import 'package:front_end/src/fasta/kernel/utils.dart' show serializeComponent;
bool? tryWithNoEnvironment;
bool verbose = false;
bool skipNonNullEnvironment = false;
bool skipNullEnvironment = false;
void benchmark(Component component, List<Library> libraries) {
if (tryWithNoEnvironment == null) throw "tryWithNoEnvironment not set";
KernelTarget target = incrementalCompiler.userCode as KernelTarget;
constants.EvaluationMode evaluationMode =
target.getConstantEvaluationModeForTesting();
Uint8List serializedComponent = serializeComponent(component);
for (int k = 0; k < 3; k++) {
Map<String, String>? environmentDefines = null;
String environmentDefinesDescription = "null environment";
for (int j = 0; j < 2; j++) {
Stopwatch stopwatch = new Stopwatch()..start();
int iterations = 0;
int sum = 0;
for (int i = 0; i < 5; i++) {
if (!tryWithNoEnvironment! && environmentDefines == null) continue;
if (skipNullEnvironment && environmentDefines == null) continue;
if (skipNonNullEnvironment && environmentDefines != null) continue;
stopwatch.reset();
Component component = new Component();
BinaryBuilder binaryBuilder = new BinaryBuilder(serializedComponent,
disableLazyClassReading: true, disableLazyReading: true);
binaryBuilder.readComponent(component);
if (verbose) {
print("Loaded component in ${stopwatch.elapsedMilliseconds} ms");
}
stopwatch.reset();
CoreTypes coreTypes = new CoreTypes(component);
ConstantsBackend constantsBackend =
target.backendTarget.constantsBackend;
ClassHierarchy hierarchy = new ClassHierarchy(component, coreTypes);
TypeEnvironment environment = new TypeEnvironment(coreTypes, hierarchy);
if (verbose) {
print("Created core types and class hierarchy"
" in ${stopwatch.elapsedMilliseconds} ms");
}
stopwatch.reset();
constants.transformLibraries(
component.libraries,
constantsBackend,
environmentDefines,
environment,
new SilentErrorReporter(),
evaluationMode,
evaluateAnnotations: true,
enableTripleShift: target
.isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),
enableConstFunctions: target
.isExperimentEnabledGlobally(ExperimentalFlag.constFunctions),
enableConstructorTearOff: target.isExperimentEnabledGlobally(
ExperimentalFlag.constructorTearoffs),
errorOnUnevaluatedConstant:
incrementalCompiler.context.options.errorOnUnevaluatedConstant);
print("Transformed constants with $environmentDefinesDescription"
" in ${stopwatch.elapsedMilliseconds} ms");
sum += stopwatch.elapsedMilliseconds;
iterations++;
}
if (verbose) {
print("With $environmentDefinesDescription: "
"Did constant evaluation $iterations iterations in $sum ms,"
" i.e. an average of ${sum / iterations} ms per iteration.");
}
environmentDefines = {};
environmentDefinesDescription = "empty environment";
}
}
}
class SilentErrorReporter implements constants.ErrorReporter {
@override
void report(LocatedMessage message, [List<LocatedMessage>? context]) {
// ignore
}
}
late IncrementalCompiler incrementalCompiler;
Future<void> main(List<String> arguments) async {
Uri? platformUri;
Uri mainUri;
bool nnbd = false;
String targetString = "VM";
String? filename;
for (String arg in arguments) {
if (arg.startsWith("--")) {
if (arg == "--nnbd") {
nnbd = true;
} else if (arg.startsWith("--platform=")) {
String platform = arg.substring("--platform=".length);
platformUri = Uri.base.resolve(platform);
} else if (arg == "--target=VM") {
targetString = "VM";
} else if (arg == "--target=flutter") {
targetString = "flutter";
} else if (arg == "--target=ddc") {
targetString = "ddc";
} else if (arg == "--target=dart2js") {
targetString = "dart2js";
} else if (arg == "-v") {
verbose = true;
} else if (arg == "--skip-null-environment") {
skipNullEnvironment = true;
} else if (arg == "--skip-non-null-environment") {
skipNonNullEnvironment = true;
} else {
throw "Unknown option $arg";
}
} else if (filename != null) {
throw "Already got '$filename', '$arg' is also a filename; "
"can only get one";
} else {
filename = arg;
}
}
if (platformUri == null) {
throw "No platform given. Use --platform=/path/to/platform.dill";
}
if (!new File.fromUri(platformUri).existsSync()) {
throw "The platform file '$platformUri' doesn't exist";
}
if (filename == null) {
throw "Need file to operate on";
}
File file = new File(filename);
if (!file.existsSync()) throw "File $filename doesn't exist.";
mainUri = file.absolute.uri;
incrementalCompiler = new IncrementalCompiler(
setupCompilerContext(nnbd, targetString, false, platformUri, mainUri));
await incrementalCompiler.computeDelta();
}
CompilerContext setupCompilerContext(bool nnbd, String targetString,
bool widgetTransformation, Uri platformUri, Uri mainUri) {
CompilerOptions options = getOptions();
if (nnbd) {
options.explicitExperimentalFlags = {ExperimentalFlag.nonNullable: true};
}
TargetFlags targetFlags = new TargetFlags(
enableNullSafety: nnbd, trackWidgetCreation: widgetTransformation);
Target target;
switch (targetString) {
case "VM":
target = new HookInVmTarget(targetFlags);
tryWithNoEnvironment = false;
break;
case "flutter":
target = new HookInFlutterTarget(targetFlags);
tryWithNoEnvironment = false;
break;
case "ddc":
target = new HookInDevCompilerTarget(targetFlags);
tryWithNoEnvironment = false;
break;
case "dart2js":
target = new HookInDart2jsTarget("dart2js", targetFlags);
tryWithNoEnvironment = true;
break;
default:
throw "Unknown target '$targetString'";
}
options.target = target;
options.sdkRoot = null;
options.sdkSummary = platformUri;
options.omitPlatform = false;
options.onDiagnostic = (DiagnosticMessage message) {
// don't care.
};
ProcessedOptions processedOptions =
new ProcessedOptions(options: options, inputs: [mainUri]);
CompilerContext compilerContext = new CompilerContext(processedOptions);
return compilerContext;
}
class HookInVmTarget extends VmTarget {
HookInVmTarget(TargetFlags flags) : super(flags);
@override
void performPreConstantEvaluationTransformations(
Component component,
CoreTypes coreTypes,
List<Library> libraries,
DiagnosticReporter diagnosticReporter,
{void Function(String msg)? logger,
ChangedStructureNotifier? changedStructureNotifier}) {
super.performPreConstantEvaluationTransformations(
component, coreTypes, libraries, diagnosticReporter,
logger: logger, changedStructureNotifier: changedStructureNotifier);
benchmark(component, libraries);
}
}
class HookInDart2jsTarget extends Dart2jsTarget {
HookInDart2jsTarget(String name, TargetFlags flags) : super(name, flags);
@override
void performPreConstantEvaluationTransformations(
Component component,
CoreTypes coreTypes,
List<Library> libraries,
DiagnosticReporter diagnosticReporter,
{void Function(String msg)? logger,
ChangedStructureNotifier? changedStructureNotifier}) {
super.performPreConstantEvaluationTransformations(
component, coreTypes, libraries, diagnosticReporter,
logger: logger, changedStructureNotifier: changedStructureNotifier);
benchmark(component, libraries);
}
}
class HookInDevCompilerTarget extends DevCompilerTarget {
HookInDevCompilerTarget(TargetFlags flags) : super(flags);
@override
void performPreConstantEvaluationTransformations(
Component component,
CoreTypes coreTypes,
List<Library> libraries,
DiagnosticReporter diagnosticReporter,
{void Function(String msg)? logger,
ChangedStructureNotifier? changedStructureNotifier}) {
super.performPreConstantEvaluationTransformations(
component, coreTypes, libraries, diagnosticReporter,
logger: logger, changedStructureNotifier: changedStructureNotifier);
benchmark(component, libraries);
}
}
class HookInFlutterTarget extends FlutterTarget {
HookInFlutterTarget(TargetFlags flags) : super(flags);
@override
void performPreConstantEvaluationTransformations(
Component component,
CoreTypes coreTypes,
List<Library> libraries,
DiagnosticReporter diagnosticReporter,
{void Function(String msg)? logger,
ChangedStructureNotifier? changedStructureNotifier}) {
super.performPreConstantEvaluationTransformations(
component, coreTypes, libraries, diagnosticReporter,
logger: logger, changedStructureNotifier: changedStructureNotifier);
benchmark(component, libraries);
}
}