Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(145)

Unified Diff: sdk/lib/_internal/compiler/implementation/compiler.dart

Issue 17759007: First pass at asynchronous input loading in dart2js. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove withCurrentElementAsync Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/compiler.dart
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index 1aa47b763707039c52ea28dda80d0bcf9c61a5b0..7d8bde006c8d4858670604453952d378c4b83545 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -81,6 +81,17 @@ class PostProcessTask {
PostProcessTask(this.element, this.action);
}
+// TODO(rnystrom): Now that file reading is asynchronous, this task is no longer
+// used and the time spent reading files isn't easily measurable (or even that
+// well-defined). As Peter says:
+//
+// As far as I can tell, we can only count how much time is being spent reading
+// files by having a global counter that covers the time from the beginning of
+// the compiler until it reaches a point when all libraries are scanned, and
+// subtract the time spent in other tasks.
+//
+// I think you should drop measureAsync. I think we can measure the time spent
+// reading files in dart2js.dart (you can just add a TODO).
class ReadingFilesTask extends CompilerTask {
ahe 2013/08/06 16:29:17 Can you remove this task?
Johnni Winther 2013/08/27 11:05:00 Done.
ReadingFilesTask(Compiler compiler) : super(compiler);
String get name => 'Reading input files';
@@ -668,14 +679,17 @@ abstract class Compiler implements DiagnosticListener {
reportDiagnostic(null, message, api.Diagnostic.VERBOSE_INFO);
}
- bool run(Uri uri) {
+ Future<bool> run(Uri uri) {
totalCompileTime.start();
- try {
- runCompiler(uri);
- } on CompilerCancelledException catch (exception) {
- log('Error: $exception');
- return false;
- } catch (exception) {
+
+ return runCompiler(uri).then((_) {
+ return true;
ahe 2013/08/06 16:29:17 Can't you eliminate this call to then?
Johnni Winther 2013/08/27 11:05:00 Done.
+ }).catchError((error) {
+ if (error is CompilerCancelledException) {
+ log('Error: $error');
+ return false;
+ }
+
try {
if (!hasCrashed) {
hasCrashed = true;
@@ -687,12 +701,13 @@ abstract class Compiler implements DiagnosticListener {
} catch (doubleFault) {
// Ignoring exceptions in exception handling.
}
- rethrow;
- } finally {
+ throw error;
+ }).whenComplete(() {
tracer.close();
totalCompileTime.stop();
- }
- return !compilationFailed;
+ }).then((_) {
+ return !compilationFailed;
ahe 2013/08/06 16:29:17 As it should be handled by this.
+ });
}
bool hasIsolateSupport() => isolateLibrary != null;
@@ -749,7 +764,7 @@ abstract class Compiler implements DiagnosticListener {
}
}
- LibraryElement scanBuiltinLibrary(String filename);
+ Future<LibraryElement> scanBuiltinLibrary(String filename);
void initializeSpecialClasses() {
final List missingCoreClasses = [];
@@ -825,29 +840,38 @@ abstract class Compiler implements DiagnosticListener {
listClass.lookupConstructor(callConstructor);
}
- void scanBuiltinLibraries() {
- jsHelperLibrary = scanBuiltinLibrary('_js_helper');
- interceptorsLibrary = scanBuiltinLibrary('_interceptors');
- foreignLibrary = scanBuiltinLibrary('_foreign_helper');
- isolateHelperLibrary = scanBuiltinLibrary('_isolate_helper');
-
- assertMethod = jsHelperLibrary.find(const SourceString('assertHelper'));
- identicalFunction = coreLibrary.find(const SourceString('identical'));
-
- initializeSpecialClasses();
-
- functionClass.ensureResolved(this);
- functionApplyMethod =
- functionClass.lookupLocalMember(const SourceString('apply'));
- jsInvocationMirrorClass.ensureResolved(this);
- invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON);
-
- if (preserveComments) {
- var uri = new Uri(scheme: 'dart', path: 'mirrors');
- LibraryElement libraryElement =
- libraryLoader.loadLibrary(uri, null, uri);
- documentClass = libraryElement.find(const SourceString('Comment'));
- }
+ Future scanBuiltinLibraries() {
+ return scanBuiltinLibrary('_js_helper').then((LibraryElement library) {
+ jsHelperLibrary = library;
+ return scanBuiltinLibrary('_interceptors');
+ }).then((LibraryElement library) {
+ interceptorsLibrary = library;
+ return scanBuiltinLibrary('_foreign_helper');
+ }).then((LibraryElement library) {
+ foreignLibrary = library;
+ return scanBuiltinLibrary('_isolate_helper');
+ }).then((LibraryElement library) {
+ isolateHelperLibrary = library;
+
+ assertMethod = jsHelperLibrary.find(const SourceString('assertHelper'));
+ identicalFunction = coreLibrary.find(const SourceString('identical'));
+
+ initializeSpecialClasses();
+
+ functionClass.ensureResolved(this);
+ functionApplyMethod =
+ functionClass.lookupLocalMember(const SourceString('apply'));
+ jsInvocationMirrorClass.ensureResolved(this);
+ invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON);
+
+ if (preserveComments) {
+ var uri = new Uri(scheme: 'dart', path: 'mirrors');
+ return libraryLoader.loadLibrary(uri, null, uri).then(
+ (LibraryElement libraryElement) {
+ documentClass = libraryElement.find(const SourceString('Comment'));
+ });
+ }
+ });
}
void importHelperLibrary(LibraryElement library) {
@@ -862,131 +886,138 @@ abstract class Compiler implements DiagnosticListener {
*/
Uri resolvePatchUri(String dartLibraryPath);
- void runCompiler(Uri uri) {
+ Future runCompiler(Uri uri) {
// TODO(ahe): This prevents memory leaks when invoking the compiler
// multiple times. Implement a better mechanism where StringWrapper
// instances are shared on a per library basis.
SourceString.canonicalizedValues.clear();
assert(uri != null || analyzeOnly);
- scanBuiltinLibraries();
- if (librariesToAnalyzeWhenRun != null) {
- for (Uri libraryUri in librariesToAnalyzeWhenRun) {
- log('analyzing $libraryUri ($buildId)');
- libraryLoader.loadLibrary(libraryUri, null, libraryUri);
- }
- }
- if (uri != null) {
- if (analyzeOnly) {
- log('analyzing $uri ($buildId)');
- } else {
- log('compiling $uri ($buildId)');
+ return scanBuiltinLibraries().then((_) {
+ if (librariesToAnalyzeWhenRun != null) {
+ return Future.forEach(librariesToAnalyzeWhenRun, (libraryUri) {
+ log('analyzing $libraryUri ($buildId)');
+ return libraryLoader.loadLibrary(libraryUri, null, libraryUri);
+ });
}
- mainApp = libraryLoader.loadLibrary(uri, null, uri);
- }
- Element main = null;
- if (mainApp != null) {
- main = mainApp.find(MAIN);
- if (main == null) {
- if (!analyzeOnly) {
- // Allow analyze only of libraries with no main.
- reportFatalError(
- mainApp,
- MessageKind.GENERIC,
- {'text': 'Error: Could not find "${MAIN.slowToString()}".'});
- } else if (!analyzeAll) {
- reportFatalError(
- mainApp,
- MessageKind.GENERIC,
- {'text': 'Error: Could not find "${MAIN.slowToString()}". '
- 'No source will be analyzed. '
- 'Use "--analyze-all" to analyze all code in the library.'});
- }
- } else {
- if (!main.isFunction()) {
- reportFatalError(
- main,
- MessageKind.GENERIC,
- {'text': 'Error: "${MAIN.slowToString()}" is not a function.'});
+ }).then((_) {
+ if (uri != null) {
+ if (analyzeOnly) {
+ log('analyzing $uri ($buildId)');
+ } else {
+ log('compiling $uri ($buildId)');
}
- FunctionElement mainMethod = main;
- FunctionSignature parameters = mainMethod.computeSignature(this);
- parameters.forEachParameter((Element parameter) {
- reportError(
- parameter,
- MessageKind.GENERIC,
- {'text':
- 'Error: "${MAIN.slowToString()}" cannot have parameters.'});
+ return libraryLoader.loadLibrary(uri, null, uri)
+ .then((LibraryElement library) {
+ mainApp = library;
});
}
+ }).then((_) {
+ Element main = null;
ahe 2013/08/06 16:29:17 I think it would make sense to move the rest of th
Johnni Winther 2013/08/27 11:05:00 Done.
+ if (mainApp != null) {
+ main = mainApp.find(MAIN);
+ if (main == null) {
+ if (!analyzeOnly) {
+ // Allow analyze only of libraries with no main.
+ reportFatalError(
+ mainApp,
+ MessageKind.GENERIC,
+ {'text': 'Error: Could not find "${MAIN.slowToString()}".'});
+ } else if (!analyzeAll) {
+ reportFatalError(
+ mainApp,
+ MessageKind.GENERIC,
+ {'text': 'Error: Could not find "${MAIN.slowToString()}". '
+ 'No source will be analyzed. '
+ 'Use "--analyze-all" to analyze all code in the library.'});
+ }
+ } else {
+ if (!main.isFunction()) {
+ reportFatalError(
+ main,
+ MessageKind.GENERIC,
+ {'text': 'Error: "${MAIN.slowToString()}" is not a function.'});
+ }
+ FunctionElement mainMethod = main;
+ FunctionSignature parameters = mainMethod.computeSignature(this);
+ parameters.forEachParameter((Element parameter) {
+ reportError(
+ parameter,
+ MessageKind.GENERIC,
+ {'text':
+ 'Error: "${MAIN.slowToString()}" cannot have parameters.'});
+ });
+ }
- mirrorUsageAnalyzerTask.analyzeUsage(mainApp);
-
- // In order to see if a library is deferred, we must compute the
- // compile-time constants that are metadata. This means adding
- // something to the resolution queue. So we cannot wait with
- // this until after the resolution queue is processed.
- // TODO(ahe): Clean this up, for example, by not enqueueing
- // classes only used for metadata.
- deferredLoadTask.findDeferredLibraries(mainApp);
- }
+ mirrorUsageAnalyzerTask.analyzeUsage(mainApp);
- log('Resolving...');
- phase = PHASE_RESOLVING;
- if (analyzeAll) {
- libraries.forEach(
- (_, lib) => fullyEnqueueLibrary(lib, enqueuer.resolution));
- }
- // Elements required by enqueueHelpers are global dependencies
- // that are not pulled in by a particular element.
- backend.enqueueHelpers(enqueuer.resolution, globalDependencies);
- processQueue(enqueuer.resolution, main);
- enqueuer.resolution.logSummary(log);
+ // In order to see if a library is deferred, we must compute the
+ // compile-time constants that are metadata. This means adding
+ // something to the resolution queue. So we cannot wait with
+ // this until after the resolution queue is processed.
+ // TODO(ahe): Clean this up, for example, by not enqueueing
+ // classes only used for metadata.
+ deferredLoadTask.findDeferredLibraries(mainApp);
+ }
- if (compilationFailed) return;
- if (analyzeOnly) return;
- assert(main != null);
- phase = PHASE_DONE_RESOLVING;
-
- // TODO(ahe): Remove this line. Eventually, enqueuer.resolution
- // should know this.
- world.populate();
- // Compute whole-program-knowledge that the backend needs. (This might
- // require the information computed in [world.populate].)
- backend.onResolutionComplete();
-
- deferredLoadTask.onResolutionComplete(main);
-
- log('Inferring types...');
- typesTask.onResolutionComplete(main);
-
- log('Compiling...');
- phase = PHASE_COMPILING;
- // TODO(johnniwinther): Move these to [CodegenEnqueuer].
- if (hasIsolateSupport()) {
- enqueuer.codegen.addToWorkList(
- isolateHelperLibrary.find(Compiler.START_ROOT_ISOLATE));
- enqueuer.codegen.registerGetOfStaticFunction(mainApp.find(MAIN));
- }
- if (enabledNoSuchMethod) {
- enqueuer.codegen.registerInvocation(noSuchMethodSelector);
- enqueuer.codegen.addToWorkList(createInvocationMirrorElement);
- }
- if (compileAll) {
- libraries.forEach((_, lib) => fullyEnqueueLibrary(lib, enqueuer.codegen));
- }
- processQueue(enqueuer.codegen, main);
- enqueuer.codegen.logSummary(log);
+ log('Resolving...');
+ phase = PHASE_RESOLVING;
+ if (analyzeAll) {
+ libraries.forEach(
+ (_, lib) => fullyEnqueueLibrary(lib, enqueuer.resolution));
+ }
+ // Elements required by enqueueHelpers are global dependencies
+ // that are not pulled in by a particular element.
+ backend.enqueueHelpers(enqueuer.resolution, globalDependencies);
+ processQueue(enqueuer.resolution, main);
+ enqueuer.resolution.logSummary(log);
+
+ if (compilationFailed) return;
+ if (analyzeOnly) return;
+ assert(main != null);
+ phase = PHASE_DONE_RESOLVING;
+
+ // TODO(ahe): Remove this line. Eventually, enqueuer.resolution
+ // should know this.
+ world.populate();
+ // Compute whole-program-knowledge that the backend needs. (This might
+ // require the information computed in [world.populate].)
+ backend.onResolutionComplete();
+
+ deferredLoadTask.onResolutionComplete(main);
+
+ log('Inferring types...');
+ typesTask.onResolutionComplete(main);
+
+ log('Compiling...');
+ phase = PHASE_COMPILING;
+ // TODO(johnniwinther): Move these to [CodegenEnqueuer].
+ if (hasIsolateSupport()) {
+ enqueuer.codegen.addToWorkList(
+ isolateHelperLibrary.find(Compiler.START_ROOT_ISOLATE));
+ enqueuer.codegen.registerGetOfStaticFunction(mainApp.find(MAIN));
+ }
+ if (enabledNoSuchMethod) {
+ enqueuer.codegen.registerInvocation(noSuchMethodSelector);
+ enqueuer.codegen.addToWorkList(createInvocationMirrorElement);
+ }
+ if (compileAll) {
+ libraries.forEach((_, lib) => fullyEnqueueLibrary(lib,
+ enqueuer.codegen));
+ }
+ processQueue(enqueuer.codegen, main);
+ enqueuer.codegen.logSummary(log);
- if (compilationFailed) return;
+ if (compilationFailed) return;
- backend.assembleProgram();
+ backend.assembleProgram();
- checkQueues();
+ checkQueues();
- if (compilationFailed) {
- assembledCode = null; // Signals failure.
- }
+ if (compilationFailed) {
+ assembledCode = null; // Signals failure.
+ }
+ });
}
void fullyEnqueueLibrary(LibraryElement library, Enqueuer world) {
@@ -1318,7 +1349,7 @@ abstract class Compiler implements DiagnosticListener {
*
* See [LibraryLoader] for terminology on URIs.
*/
- Script readScript(Uri readableUri, [Node node]) {
+ Future<Script> readScript(Uri readableUri, [Element element, Node node]) {
unimplemented('Compiler.readScript');
}
@@ -1462,10 +1493,14 @@ class SourceSpan {
bool invariant(Spannable spannable, var condition, {var message: null}) {
// TODO(johnniwinther): Use [spannable] and [message] to provide better
// information on assertion errors.
+ if (spannable == null) {
+ throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE,
+ "Spannable was null for invariant. Use CURRENT_ELEMENT_SPANNABLE.");
+ }
if (condition is Function){
condition = condition();
}
- if (spannable == null || !condition) {
+ if (!condition) {
if (message is Function) {
message = message();
}

Powered by Google App Engine
This is Rietveld 408576698