[dart2js] migrate source_file_provider

This reapplies f740b500e2

The change is not that different from the original, except that a
few changes have landed in between to address the failure
encountered by the SDK roll last time. Namely, the map lookup on
`resolvedUri` is normalized, so that the lookup will always match
how the store operation is done, and hence will succeed when copying
cache entries between resolvedUri and uri (see also
https://dart-review.googlesource.com/c/sdk/+/250440).


Change-Id: Ic3ad778a3e9ea465b515de9800f296c71683970c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/260081
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Sigmund Cherem 2022-09-23 01:41:18 +00:00 committed by Commit Bot
parent 76a4d351b8
commit 8bff8336a4
3 changed files with 54 additions and 41 deletions

View file

@ -2,8 +2,6 @@
// 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.
// @dart = 2.10
library source_file_provider;
import 'dart:async';
@ -14,14 +12,13 @@ import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
import '../compiler_api.dart' as api;
import 'colors.dart' as colors;
import 'dart2js.dart' show AbortLeg;
import 'io/source_file.dart';
abstract class SourceFileProvider implements api.CompilerInput {
bool isWindows = (Platform.operatingSystem == 'windows');
Uri cwd = Uri.base;
Map<Uri, api.Input> utf8SourceFiles = <Uri, api.Input>{};
Map<Uri, api.Input> binarySourceFiles = <Uri, api.Input>{};
Map<Uri, SourceFile<List<int>>> utf8SourceFiles = {};
Map<Uri, api.Input<List<int>>> binarySourceFiles = {};
int dartCharactersRead = 0;
Future<api.Input<List<int>>> readBytesFromUri(
@ -29,7 +26,7 @@ abstract class SourceFileProvider implements api.CompilerInput {
if (!resourceUri.isAbsolute) {
resourceUri = cwd.resolveUri(resourceUri);
}
api.Input<List<int>> input = _loadInputFromCache(resourceUri, inputKind);
api.Input<List<int>>? input = _loadInputFromCache(resourceUri, inputKind);
if (input != null) return Future.value(input);
if (resourceUri.isScheme('file')) {
@ -47,11 +44,11 @@ abstract class SourceFileProvider implements api.CompilerInput {
/// utf8, the CFE file system may read them as binary inputs. In case the CFE
/// needs to report errors, dart2js will only find the location data if it
/// checks both caches.
api.Input<List<int>> _loadInputFromCache(
api.Input<List<int>>? _loadInputFromCache(
Uri resourceUri, api.InputKind inputKind) {
switch (inputKind) {
case api.InputKind.UTF8:
var input = utf8SourceFiles[resourceUri];
api.Input<List<int>>? input = utf8SourceFiles[resourceUri];
if (input != null) return input;
input = binarySourceFiles[resourceUri];
if (input == null) return null;
@ -59,11 +56,10 @@ abstract class SourceFileProvider implements api.CompilerInput {
case api.InputKind.binary:
return binarySourceFiles[resourceUri];
}
return null;
}
/// Adds [source] to the cache under the [resourceUri] key.
api.Input _storeSourceInCache(
api.Input<List<int>> _storeSourceInCache(
Uri resourceUri, List<int> source, api.InputKind inputKind) {
switch (inputKind) {
case api.InputKind.UTF8:
@ -72,7 +68,6 @@ abstract class SourceFileProvider implements api.CompilerInput {
case api.InputKind.binary:
return binarySourceFiles[resourceUri] = Binary(resourceUri, source);
}
return null;
}
@override
@ -85,14 +80,15 @@ abstract class SourceFileProvider implements api.CompilerInput {
}
}
api.Input _readFromFileSync(Uri resourceUri, api.InputKind inputKind) {
api.Input<List<int>> _readFromFileSync(
Uri resourceUri, api.InputKind inputKind) {
assert(resourceUri.isScheme('file'));
List<int> source;
try {
source = readAll(resourceUri.toFilePath(),
zeroTerminated: inputKind == api.InputKind.UTF8);
} on FileSystemException catch (ex) {
String message = ex.osError?.message;
String? message = ex.osError?.message;
String detail = message != null ? ' ($message)' : '';
throw "Error reading '${relativizeUri(resourceUri)}' $detail";
}
@ -102,7 +98,7 @@ abstract class SourceFileProvider implements api.CompilerInput {
/// Read [resourceUri] directly as a UTF-8 file. If reading fails, `null` is
/// returned.
api.Input readUtf8FromFileSyncForTesting(Uri resourceUri) {
api.Input<List<int>>? readUtf8FromFileSyncForTesting(Uri resourceUri) {
try {
return _readFromFileSync(resourceUri, api.InputKind.UTF8);
} catch (e) {
@ -125,18 +121,15 @@ abstract class SourceFileProvider implements api.CompilerInput {
relativizeUri(Uri uri) => fe.relativizeUri(cwd, uri, isWindows);
SourceFile<List<int>> getUtf8SourceFile(Uri resourceUri) {
api.Input<List<int>>? getUtf8SourceFile(Uri resourceUri) {
return _loadInputFromCache(resourceUri, api.InputKind.UTF8);
}
Iterable<Uri> getSourceUris() {
Set<Uri> uris = Set<Uri>();
// Note: this includes also indirect sources that were used to create
// `.dill` inputs to the compiler. This is OK, since this API is only
// used to calculate DEPS for gn build systems.
uris.addAll(utf8SourceFiles.keys);
uris.addAll(binarySourceFiles.keys);
return uris;
return <Uri>{...utf8SourceFiles.keys, ...binarySourceFiles.keys};
}
}
@ -170,16 +163,15 @@ class FormattingDiagnosticHandler implements api.CompilerDiagnostics {
bool enableColors = false;
bool throwOnError = false;
int throwOnErrorCount = 0;
api.Diagnostic lastKind = null;
api.Diagnostic? lastKind = null;
int fatalCount = 0;
final int FATAL = api.Diagnostic.CRASH.ordinal | api.Diagnostic.ERROR.ordinal;
final int INFO =
api.Diagnostic.INFO.ordinal | api.Diagnostic.VERBOSE_INFO.ordinal;
FormattingDiagnosticHandler([SourceFileProvider provider])
: this.provider =
(provider == null) ? CompilerSourceFileProvider() : provider;
FormattingDiagnosticHandler([SourceFileProvider? provider])
: this.provider = provider ?? CompilerSourceFileProvider();
void info(var message, [api.Diagnostic kind = api.Diagnostic.VERBOSE_INFO]) {
if (!verbose && kind == api.Diagnostic.VERBOSE_INFO) return;
@ -209,7 +201,7 @@ class FormattingDiagnosticHandler implements api.CompilerDiagnostics {
}
@override
void report(var code, Uri uri, int begin, int end, String message,
void report(var code, Uri? uri, int? begin, int? end, String message,
api.Diagnostic kind) {
if (isAborting) return;
isAborting = (kind == api.Diagnostic.CRASH);
@ -253,29 +245,41 @@ class FormattingDiagnosticHandler implements api.CompilerDiagnostics {
if (uri == null) {
print('${color(message)}');
} else {
api.Input file = provider.getUtf8SourceFile(uri);
if (file is SourceFile) {
print(file.getLocationMessage(color(message), begin, end,
colorize: color));
api.Input<List<int>>? file = provider.getUtf8SourceFile(uri);
if (file is SourceFile && begin != null && end != null) {
print((file as SourceFile)
.getLocationMessage(color(message), begin, end, colorize: color));
} else {
String position = end - begin > 0 ? '@$begin+${end - begin}' : '';
String position = begin != null && end != null && end - begin > 0
? '@$begin+${end - begin}'
: '';
print('${provider.relativizeUri(uri)}$position:\n'
'${color(message)}');
}
}
if (fatal && ++fatalCount >= throwOnErrorCount && throwOnError) {
isAborting = true;
throw AbortLeg(message);
throw _CompilationErrorError(message);
}
}
}
class _CompilationErrorError {
final message;
_CompilationErrorError(this.message);
@override
toString() => 'Aborted due to --throw-on-error: $message';
}
typedef MessageCallback = void Function(String message);
class RandomAccessFileOutputProvider implements api.CompilerOutput {
final Uri out;
final Uri sourceMapOut;
final MessageCallback onInfo;
// TODO(48820): Make [onFailure] return `Never`. The value passed in for the
// real compiler exits. [onFailure] is not specified or faked in some tests.
final MessageCallback onFailure;
int totalCharactersWritten = 0;
@ -286,7 +290,9 @@ class RandomAccessFileOutputProvider implements api.CompilerOutput {
List<String> allOutputFiles = <String>[];
RandomAccessFileOutputProvider(this.out, this.sourceMapOut,
{this.onInfo, this.onFailure});
{this.onInfo = _ignore, this.onFailure = _ignore});
static void _ignore(String message) {}
Uri createUri(String name, String extension, api.OutputType type) {
Uri uri;
@ -330,6 +336,7 @@ class RandomAccessFileOutputProvider implements api.CompilerOutput {
break;
default:
onFailure('Unknown output type: $type');
throw StateError('unreachable');
}
return uri;
}
@ -350,6 +357,8 @@ class RandomAccessFileOutputProvider implements api.CompilerOutput {
.openSync(mode: FileMode.write);
} on FileSystemException catch (e) {
onFailure('$e');
// TODO(48820): Make onFailure return `Never`
throw StateError('unreachable');
}
allOutputFiles.add(fe.relativizeUri(Uri.base, uri, Platform.isWindows));
@ -414,11 +423,13 @@ class RandomAccessFileOutputProvider implements api.CompilerOutput {
.openSync(mode: FileMode.write);
} on FileSystemException catch (e) {
onFailure('$e');
// TODO(48820): Make `onFailure` return `Never`.
throw StateError('unreachable');
}
int bytesWritten = 0;
void writeBytesSync(List<int> data, [int start = 0, int end]) {
void writeBytesSync(List<int> data, [int start = 0, int? end]) {
output.writeFromSync(data, start, end);
bytesWritten += (end ?? data.length) - start;
}
@ -439,7 +450,7 @@ class RandomAccessBinaryOutputSink implements api.BinaryOutputSink {
: output = File.fromUri(uri).openSync(mode: FileMode.write);
@override
void write(List<int> buffer, [int start = 0, int end]) {
void write(List<int> buffer, [int start = 0, int? end]) {
output.writeFromSync(buffer, start, end);
}
@ -463,13 +474,13 @@ class _OutputSinkWrapper extends api.OutputSink {
}
class _BinaryOutputSinkWrapper extends api.BinaryOutputSink {
void Function(List<int>, [int, int]) onWrite;
void Function(List<int>, [int, int?]) onWrite;
void Function() onClose;
_BinaryOutputSinkWrapper(this.onWrite, this.onClose);
@override
void write(List<int> data, [int start = 0, int end]) =>
void write(List<int> data, [int start = 0, int? end]) =>
onWrite(data, start, end);
@override
@ -543,10 +554,10 @@ class BazelInputProvider extends SourceFileProvider {
}
switch (inputKind) {
case api.InputKind.UTF8:
utf8SourceFiles[uri] = utf8SourceFiles[resolvedUri];
utf8SourceFiles[uri] = utf8SourceFiles[resolvedUri]!;
break;
case api.InputKind.binary:
binarySourceFiles[uri] = binarySourceFiles[resolvedUri];
binarySourceFiles[uri] = binarySourceFiles[resolvedUri]!;
break;
}
}
@ -590,10 +601,10 @@ class MultiRootInputProvider extends SourceFileProvider {
await readBytesFromUri(resolvedUri, inputKind);
switch (inputKind) {
case api.InputKind.UTF8:
utf8SourceFiles[uri] = utf8SourceFiles[resolvedUri];
utf8SourceFiles[uri] = utf8SourceFiles[resolvedUri]!;
break;
case api.InputKind.binary:
binarySourceFiles[uri] = binarySourceFiles[resolvedUri];
binarySourceFiles[uri] = binarySourceFiles[resolvedUri]!;
break;
}
return result;

View file

@ -71,7 +71,8 @@ show<T>(ArgResults argResults, DataComputer<T> dataComputer,
if (show != null && !show.any((f) => '$fileUri'.endsWith(f))) {
continue;
}
SourceFile sourceFile = provider.readUtf8FromFileSyncForTesting(fileUri);
SourceFile<List<int>> sourceFile =
provider.readUtf8FromFileSyncForTesting(fileUri);
String sourceCode = sourceFile?.slowText();
if (sourceCode == null) {
sourceCode = new File.fromUri(fileUri).readAsStringSync();

View file

@ -104,7 +104,8 @@ class ProviderSourceFileManager implements SourceFileManager {
@override
SourceFile getSourceFile(uri) {
SourceFile sourceFile = sourceFileProvider.getUtf8SourceFile(uri);
SourceFile<List<int>> sourceFile =
sourceFileProvider.getUtf8SourceFile(uri);
sourceFile ??= sourceFileProvider.readUtf8FromFileSyncForTesting(uri);
if (sourceFile == null) {
sourceFile = outputProvider.getSourceFile(uri);