9e8fdef17c
Closes https://github.com/dart-lang/sdk/pull/63011 GitOrigin-RevId: 926534c2f5d3cd1e9629cf25f6b028ab34c00e64 Change-Id: I88460a060faabeae8f611e88f23b2eb5fc99f21a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/491702 Reviewed-by: Daco Harkes <dacoharkes@google.com> Reviewed-by: Jens Johansen <jensj@google.com> Reviewed-by: Slava Egorov <vegorov@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
184 lines
6.3 KiB
Dart
184 lines
6.3 KiB
Dart
// Copyright (c) 2023, 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:dev_compiler/dev_compiler.dart';
|
|
import 'package:dev_compiler/src/command/command.dart';
|
|
import 'package:dev_compiler/src/js_ast/js_ast.dart';
|
|
import 'package:front_end/src/api_unstable/ddc.dart' as fe;
|
|
import 'package:kernel/target/targets.dart';
|
|
|
|
/// Result compiling using [compileFromMemory].
|
|
///
|
|
/// This is meant for testing and therefore include not only the resulting
|
|
/// [Program] various artifacts of the compilation.
|
|
class MemoryCompilerResult {
|
|
final fe.DdcResult ddcResult;
|
|
final ProgramCompiler compiler;
|
|
final Program program;
|
|
final List<fe.CfeDiagnosticMessage> errors;
|
|
|
|
MemoryCompilerResult(
|
|
this.ddcResult,
|
|
this.compiler,
|
|
this.program,
|
|
this.errors,
|
|
);
|
|
}
|
|
|
|
/// Result of compiling using [componentFromMemory].
|
|
///
|
|
/// This is meant for use in tests and performs the front end compilation to
|
|
/// components without calling DDC.
|
|
class MemoryComponentResult {
|
|
final fe.DdcResult ddcResult;
|
|
final List<fe.CfeDiagnosticMessage> errors;
|
|
fe.InitializedCompilerState? initialCompilerState;
|
|
|
|
MemoryComponentResult(this.ddcResult, this.errors, this.initialCompilerState);
|
|
}
|
|
|
|
/// Uri used as the base uri for files provided in memory through the
|
|
/// [MemoryFileSystem].
|
|
Uri memoryDirectory = Uri.parse('memory://');
|
|
|
|
/// Compiles [entryPoint] to a kernel `Component` using the [memoryFiles] as
|
|
/// sources.
|
|
///
|
|
/// [memoryFiles] maps relative paths to their source text. [entryPoint] must
|
|
/// be absolute, using [baseUri] (defaulted to [memoryDirectory]) to refer to a
|
|
/// file from [memoryFiles].
|
|
Future<MemoryComponentResult> componentFromMemory(
|
|
Map<String, String> memoryFiles,
|
|
Uri entryPoint, {
|
|
Map<fe.ExperimentalFlag, bool> explicitExperimentalFlags = const {},
|
|
Uri? baseUri,
|
|
}) async {
|
|
baseUri ??= memoryDirectory;
|
|
var errors = <fe.CfeDiagnosticMessage>[];
|
|
void diagnosticMessageHandler(fe.CfeDiagnosticMessage message) {
|
|
if (message.severity == fe.CfeSeverity.error) {
|
|
errors.add(message);
|
|
}
|
|
fe.printDiagnosticMessage(message, print);
|
|
}
|
|
|
|
var memoryFileSystem = fe.MemoryFileSystem(baseUri);
|
|
for (var entry in memoryFiles.entries) {
|
|
memoryFileSystem
|
|
.entityForUri(baseUri.resolve(entry.key))
|
|
.writeAsStringSync(entry.value);
|
|
}
|
|
var compilerState = fe.initializeCompiler(
|
|
null,
|
|
false,
|
|
sourcePathToUri(getSdkPath()),
|
|
sourcePathToUri(defaultSdkSummaryPath),
|
|
null,
|
|
sourcePathToUri(defaultLibrarySpecPath),
|
|
[],
|
|
DevCompilerTarget(TargetFlags(trackCreationLocations: false)),
|
|
fileSystem: fe.HybridFileSystem(memoryFileSystem),
|
|
environmentDefines: {},
|
|
explicitExperimentalFlags: explicitExperimentalFlags,
|
|
);
|
|
var result = await fe.compile(compilerState, [
|
|
entryPoint,
|
|
], diagnosticMessageHandler);
|
|
if (result == null) {
|
|
throw 'Memory compilation failed';
|
|
}
|
|
return MemoryComponentResult(result, errors, compilerState);
|
|
}
|
|
|
|
/// Compiles [entryPoint] to a kernel `Component` using the [memoryFiles] as
|
|
/// sources. Uses the incremental compiler.
|
|
///
|
|
/// [memoryFiles] maps relative paths to their source text. [entryPoint] must
|
|
/// be absolute, using [baseUri] (defaulted to [memoryDirectory]) to refer to a
|
|
/// file from [memoryFiles].
|
|
Future<MemoryComponentResult> incrementalComponentFromMemory(
|
|
Map<String, String> memoryFiles,
|
|
Uri entryPoint, {
|
|
Map<fe.ExperimentalFlag, bool> explicitExperimentalFlags = const {},
|
|
Uri? baseUri,
|
|
fe.InitializedCompilerState? initialCompilerState,
|
|
Uri? packageConfigUri,
|
|
}) async {
|
|
baseUri ??= memoryDirectory;
|
|
var errors = <fe.CfeDiagnosticMessage>[];
|
|
void diagnosticMessageHandler(fe.CfeDiagnosticMessage message) {
|
|
if (message.severity == fe.CfeSeverity.error) {
|
|
errors.add(message);
|
|
}
|
|
fe.printDiagnosticMessage(message, print);
|
|
}
|
|
|
|
var memoryFileSystem = fe.MemoryFileSystem(baseUri);
|
|
for (var entry in memoryFiles.entries) {
|
|
memoryFileSystem
|
|
.entityForUri(baseUri.resolve(entry.key))
|
|
.writeAsStringSync(entry.value);
|
|
}
|
|
var inputDigests = {
|
|
sourcePathToUri(defaultSdkSummaryPath): const [0],
|
|
};
|
|
var compilerState = await fe.initializeIncrementalCompiler(
|
|
initialCompilerState,
|
|
{},
|
|
[],
|
|
false,
|
|
sourcePathToUri(getSdkPath()),
|
|
sourcePathToUri(defaultSdkSummaryPath),
|
|
packageConfigUri,
|
|
sourcePathToUri(defaultLibrarySpecPath),
|
|
[],
|
|
inputDigests,
|
|
DevCompilerTarget(TargetFlags(trackCreationLocations: false)),
|
|
fileSystem: fe.HybridFileSystem(memoryFileSystem),
|
|
environmentDefines: {},
|
|
explicitExperimentalFlags: explicitExperimentalFlags,
|
|
);
|
|
var incrementalCompiler = compilerState.incrementalCompiler!;
|
|
compilerState.options.onDiagnostic = diagnosticMessageHandler;
|
|
var incrementalCompilerResult = await incrementalCompiler.computeDelta(
|
|
entryPoints: [entryPoint],
|
|
fullComponent: false,
|
|
);
|
|
var cachedSdkInput =
|
|
compilerState.workerInputCache![sourcePathToUri(defaultSdkSummaryPath)];
|
|
var result = fe.DdcResult(
|
|
incrementalCompilerResult.component,
|
|
cachedSdkInput?.component,
|
|
[],
|
|
incrementalCompilerResult.classHierarchy,
|
|
incrementalCompilerResult.neededDillLibraries,
|
|
);
|
|
return MemoryComponentResult(result, errors, compilerState);
|
|
}
|
|
|
|
/// Compiles [entryPoint] to JavaScript using the [memoryFiles] as sources.
|
|
///
|
|
/// [memoryFiles] maps relative paths to their source text. [entryPoint] must
|
|
/// be absolute, using [memoryDirectory] as a base uri to refer to a file from
|
|
/// [memoryFiles].
|
|
Future<MemoryCompilerResult> compileFromMemory(
|
|
Map<String, String> memoryFiles,
|
|
Uri entryPoint, {
|
|
Map<fe.ExperimentalFlag, bool>? explicitExperimentalFlags,
|
|
Uri? baseUri,
|
|
}) async {
|
|
baseUri ??= memoryDirectory;
|
|
var MemoryComponentResult(ddcResult: result, :errors) =
|
|
await componentFromMemory(memoryFiles, entryPoint, baseUri: baseUri);
|
|
var options = Options(moduleName: 'test');
|
|
var compiler =
|
|
// TODO(nshahan): Do we need to support [importToSummary] and
|
|
// [summaryToModule].
|
|
ProgramCompiler(result.component, result.classHierarchy, options, {}, {});
|
|
|
|
var jsModule = compiler.emitModule(result.compiledLibraries);
|
|
|
|
return MemoryCompilerResult(result, compiler, jsModule, errors);
|
|
}
|