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

Unified Diff: dart/pkg/dart2js_incremental/lib/library_updater.dart

Issue 594843003: Introduce LibraryUpdater. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Address Johnni's comments. Created 6 years, 3 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
« no previous file with comments | « no previous file | dart/site/try/poi/poi.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: dart/pkg/dart2js_incremental/lib/library_updater.dart
diff --git a/dart/pkg/dart2js_incremental/lib/library_updater.dart b/dart/pkg/dart2js_incremental/lib/library_updater.dart
new file mode 100644
index 0000000000000000000000000000000000000000..78e6cc922b87378356f2190c2bc101ffc0bf3878
--- /dev/null
+++ b/dart/pkg/dart2js_incremental/lib/library_updater.dart
@@ -0,0 +1,196 @@
+// Copyright (c) 2014, 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.
+
+library dart2js_incremental.library_updater;
+
+import 'dart:async' show
+ Future;
+
+import 'dart:convert' show
+ UTF8;
+
+import 'package:compiler/compiler.dart' as api;
+
+import 'package:compiler/implementation/dart2jslib.dart' show
+ Compiler,
+ Script;
+
+import 'package:compiler/implementation/elements/elements.dart' show
+ LibraryElement;
+
+import 'package:compiler/implementation/scanner/scannerlib.dart' show
+ EOF_TOKEN,
+ PartialElement,
+ PartialFunctionElement,
+ Token;
+
+import 'package:compiler/implementation/source_file.dart' show
+ StringSourceFile;
+
+import 'package:compiler/implementation/tree/tree.dart' show
+ FunctionExpression;
+
+import 'diff.dart' show
+ Difference,
+ computeDifference;
+
+typedef void Logger(message);
+
+// TODO(ahe): Generalize this class. For now only works for Compiler.mainApp,
+// and only if that library has exactly one compilation unit.
+class LibraryUpdater {
+ final Compiler compiler;
+
+ final api.CompilerInputProvider inputProvider;
+
+ final Logger logTime;
+
+ final Logger logVerbose;
+
+ // TODO(ahe): Get rid of this field. It assumes that only one library has
+ // changed.
+ final Uri uri;
+
+ final List<Update> updates = <Update>[];
+
+ LibraryUpdater(
+ this.compiler,
+ this.inputProvider,
+ this.uri,
+ this.logTime,
+ this.logVerbose);
+
+ /// Used as tear-off passed to [LibraryLoaderTask.resetAsync].
+ Future<bool> reuseLibrary(LibraryElement library) {
+ assert(compiler != null);
+ if (library.isPlatformLibrary || library.isPackageLibrary) {
+ logTime('Reusing $library.');
+ return new Future.value(true);
+ } else if (library != compiler.mainApp) {
+ return new Future.value(false);
+ }
+ return inputProvider(uri).then((List<int> bytes) {
+ if (canReuseLibrary(library, bytes)) {
+ // TODO(ahe): Temporary. Since we don't yet apply the updates, the
+ // library cannot be reused if there are updates.
+ return updates.isEmpty;
+ } else {
+ return false;
+ }
+ });
+ }
+
+ /// Returns true if [library] can be reused.
+ ///
+ /// This methods also computes the [updates] (patches) needed to have
+ /// [library] reflect the modifications in [bytes].
+ bool canReuseLibrary(LibraryElement library, List<int> bytes) {
+ logTime('Attempting to reuse mainApp.');
+ String newSource = UTF8.decode(bytes);
+ logTime('Decoded UTF8');
+
+ // TODO(ahe): Can't use compiler.mainApp in general.
+ if (false && newSource == compiler.mainApp.compilationUnit.script.text) {
+ // TODO(ahe): Need to update the compilationUnit's source code when
+ // doing incremental analysis for this to work.
+ logTime("Source didn't change");
+ return true;
+ }
+
+ logTime("Source did change");
+ Script sourceScript = new Script(
+ uri, uri, new StringSourceFile('$uri', newSource));
+ var dartPrivacyIsBroken = compiler.libraryLoader;
+ LibraryElement newLibrary = dartPrivacyIsBroken.createLibrarySync(
+ null, sourceScript, uri);
+ logTime('New library synthesized.');
+ List<Difference> differences = computeDifference(library, newLibrary);
+ logTime('Differences computed.');
+ for (Difference difference in differences) {
+ logTime('Looking at difference: $difference');
+ if (difference.before == null || difference.after == null) {
+ logVerbose('Scope changed in $difference');
+ // Scope changed, don't reuse library.
+ return false;
+ }
+ Token diffToken = difference.token;
+ if (diffToken == null) {
+ logVerbose('No token stored in difference.');
+ return false;
+ }
+ if (difference.after is! PartialElement &&
+ difference.before is! PartialElement) {
+ logVerbose('Not a PartialElement: $difference');
+ // Don't know how to recompile element.
+ return false;
+ }
+ PartialElement before = difference.before;
+ PartialElement after = difference.after;
+
+ if (before is PartialFunctionElement && after is PartialFunctionElement) {
+ if (!canReuseFunction(diffToken, before, after)) {
+ return false;
+ }
+ } else {
+ // Unhandled kind of element.
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /// Returns true if function [before] can be reused to reflect the changes in
+ /// [after].
+ ///
+ /// If [before] can be reused, an update (patch) is added to [updates].
+ bool canReuseFunction(
+ Token diffToken,
+ PartialFunctionElement before,
+ PartialFunctionElement after) {
+ FunctionExpression node =
+ after.parseNode(compiler).asFunctionExpression();
+ if (node == null) {
+ print('Not a function expression.');
+ return false;
+ }
+ Token last = after.endToken;
+ if (node.body != null) {
+ last = node.body.getBeginToken();
+ }
+ Token token = after.beginToken;
+ while (token != last && token.kind != EOF_TOKEN) {
+ if (token == diffToken) {
+ logVerbose('Signature changed');
+ return false;
+ }
+ token = token.next;
+ }
+ print('Simple modification of ${after} detected');
+ updates.add(new FunctionUpdate(compiler, before, after));
+ return true;
+ }
+}
+
+/// Represents an update (aka patch) of [before] to [after]. We use the word
+/// "update" to avoid confusion with the compiler feature of "patch" methods.
+abstract class Update {
+ final Compiler compiler;
+
+ PartialElement get before;
+
+ PartialElement get after;
+
+ Update(this.compiler);
+}
+
+/// Represents an update of a function element.
+class FunctionUpdate extends Update {
+ final PartialFunctionElement before;
+
+ final PartialFunctionElement after;
+
+ FunctionUpdate(Compiler compiler, this.before, this.after)
+ : super(compiler);
+}
« no previous file with comments | « no previous file | dart/site/try/poi/poi.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698