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

View file

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

View file

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