| 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
|
| index b7d41e0090fd5a160c335473171e34bc9382cb1a..09cb6f4bd463fa1767e438752a1f833ef26c49a5 100644
|
| --- a/dart/pkg/dart2js_incremental/lib/library_updater.dart
|
| +++ b/dart/pkg/dart2js_incremental/lib/library_updater.dart
|
| @@ -83,6 +83,9 @@ import 'diff.dart' show
|
| Difference,
|
| computeDifference;
|
|
|
| +import 'dart2js_incremental.dart' show
|
| + IncrementalCompiler;
|
| +
|
| typedef void Logger(message);
|
|
|
| typedef bool Reuser(
|
| @@ -103,8 +106,46 @@ class FailedUpdate {
|
| }
|
| }
|
|
|
| -// TODO(ahe): Generalize this class. For now only works for Compiler.mainApp,
|
| -// and only if that library has exactly one compilation unit.
|
| +abstract class _IncrementalCompilerContext {
|
| + IncrementalCompiler incrementalCompiler;
|
| +
|
| + Set<ClassElementX> _emittedClasses;
|
| +
|
| + Set<ClassElementX> _directlyInstantiatedClasses;
|
| +
|
| + Set<ConstantValue> _compiledConstants;
|
| +}
|
| +
|
| +class IncrementalCompilerContext extends _IncrementalCompilerContext {
|
| + final Set<Uri> _uriWithUpdates = new Set<Uri>();
|
| +
|
| + void set incrementalCompiler(IncrementalCompiler value) {
|
| + if (super.incrementalCompiler != null) {
|
| + throw new StateError("Can't set [incrementalCompiler] more than once.");
|
| + }
|
| + super.incrementalCompiler = value;
|
| + }
|
| +
|
| + void registerUriWithUpdates(Iterable<Uri> uris) {
|
| + _uriWithUpdates.addAll(uris);
|
| + }
|
| +
|
| + void _captureState(Compiler compiler) {
|
| + _emittedClasses = new Set.from(compiler.backend.emitter.neededClasses);
|
| +
|
| + _directlyInstantiatedClasses =
|
| + new Set.from(compiler.codegenWorld.directlyInstantiatedClasses);
|
| +
|
| + List<ConstantValue> constants =
|
| + compiler.backend.emitter.outputConstantLists[
|
| + compiler.deferredLoadTask.mainOutputUnit];
|
| + if (constants == null) constants = <ConstantValue>[];
|
| + _compiledConstants = new Set<ConstantValue>.identity()..addAll(constants);
|
| + }
|
| +
|
| + bool _uriHasUpdate(Uri uri) => _uriWithUpdates.contains(uri);
|
| +}
|
| +
|
| class LibraryUpdater extends JsFeatures {
|
| final Compiler compiler;
|
|
|
| @@ -114,10 +155,6 @@ class LibraryUpdater extends JsFeatures {
|
|
|
| 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>[];
|
|
|
| final List<FailedUpdate> _failedUpdates = <FailedUpdate>[];
|
| @@ -129,50 +166,37 @@ class LibraryUpdater extends JsFeatures {
|
| final Set<ClassElementX> _classesWithSchemaChanges =
|
| new Set<ClassElementX>();
|
|
|
| - final Set<ClassElementX> _emittedClasses;
|
| -
|
| - final Set<ClassElementX> _directlyInstantiatedClasses;
|
| -
|
| - final Set<ConstantValue> _compiledConstants;
|
| + final IncrementalCompilerContext _context;
|
|
|
| bool _hasComputedNeeds = false;
|
|
|
| + bool _hasCapturedCompilerState = false;
|
| +
|
| LibraryUpdater(
|
| - Compiler compiler,
|
| + this.compiler,
|
| this.inputProvider,
|
| - this.uri,
|
| this.logTime,
|
| - this.logVerbose)
|
| - : this.compiler = compiler,
|
| - _emittedClasses = _getEmittedClasses(compiler),
|
| - _directlyInstantiatedClasses =
|
| - _getDirectlyInstantiatedClasses(compiler),
|
| - _compiledConstants = _getEmittedConstants(compiler);
|
| + this.logVerbose,
|
| + this._context) {
|
| + // TODO(ahe): Would like to remove this from the constructor. However, the
|
| + // state must be captured before calling [reuseCompiler].
|
| + // Proper solution might be: [reuseCompiler] should not clear the sets that
|
| + // are captured in [IncrementalCompilerContext._captureState].
|
| + _ensureCompilerStateCaptured();
|
| + }
|
|
|
| /// Returns the classes emitted by [compiler].
|
| - static Set<ClassElementX> _getEmittedClasses(Compiler compiler) {
|
| - if (compiler == null) return null;
|
| - return new Set.from(compiler.backend.emitter.neededClasses);
|
| - }
|
| + Set<ClassElementX> get _emittedClasses => _context._emittedClasses;
|
|
|
| - /// Returns the directly instantantiated classes seen by [compiler].
|
| - static Set<ClassElementX> _getDirectlyInstantiatedClasses(Compiler compiler) {
|
| - if (compiler == null) return null;
|
| - return new Set.from(compiler.codegenWorld.directlyInstantiatedClasses);
|
| + /// Returns the directly instantantiated classes seen by [compiler] (this
|
| + /// includes interfaces and may be different from [_emittedClasses] that only
|
| + /// includes interfaces used in type tests).
|
| + Set<ClassElementX> get _directlyInstantiatedClasses {
|
| + return _context._directlyInstantiatedClasses;
|
| }
|
|
|
| /// Returns the constants emitted by [compiler].
|
| - static Set<ConstantValue> _getEmittedConstants(Compiler compiler) {
|
| - if (compiler != null) {
|
| - List<ConstantValue> constants =
|
| - compiler.backend.emitter.outputConstantLists[
|
| - compiler.deferredLoadTask.mainOutputUnit];
|
| - if (constants != null) {
|
| - return new Set<ConstantValue>.identity()..addAll(constants);
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| + Set<ConstantValue> get _compiledConstants => _context._compiledConstants;
|
|
|
| /// When [true], updates must be applied (using [applyUpdates]) before the
|
| /// [compiler]'s state correctly reflects the updated program.
|
| @@ -182,16 +206,38 @@ class LibraryUpdater extends JsFeatures {
|
|
|
| /// Used as tear-off passed to [LibraryLoaderTask.resetAsync].
|
| Future<bool> reuseLibrary(LibraryElement library) {
|
| + _ensureCompilerStateCaptured();
|
| assert(compiler != null);
|
| - if (library.isPlatformLibrary || library.isPackageLibrary) {
|
| - logTime('Reusing $library.');
|
| + if (library.isPlatformLibrary) {
|
| + logTime('Reusing $library (assumed read-only).');
|
| return new Future.value(true);
|
| - } else if (library != compiler.mainApp) {
|
| - return new Future.value(false);
|
| }
|
| - return inputProvider(uri).then((bytes) {
|
| - return canReuseLibrary(library, bytes);
|
| - });
|
| + for (CompilationUnitElementX unit in library.compilationUnits) {
|
| + Uri uri = unit.script.resourceUri;
|
| + if (_context._uriHasUpdate(uri)) {
|
| + if (!library.compilationUnits.tail.isEmpty) {
|
| + // TODO(ahe): Remove this restriction.
|
| + cannotReuse(library, "Multiple compilation units not supported.");
|
| + return new Future.value(true);
|
| + }
|
| + return inputProvider(uri).then((bytes) {
|
| + return canReuseLibrary(library, bytes);
|
| + });
|
| + }
|
| + }
|
| +
|
| + logTime("Reusing $library, source didn't change.");
|
| + // Source code of [library] wasn't changed.
|
| + return new Future.value(true);
|
| + }
|
| +
|
| + void _ensureCompilerStateCaptured() {
|
| + // TODO(ahe): [compiler] shouldn't be null, remove the following line.
|
| + if (compiler == null) return;
|
| +
|
| + if (_hasCapturedCompilerState) return;
|
| + _context._captureState(compiler);
|
| + _hasCapturedCompilerState = true;
|
| }
|
|
|
| /// Returns true if [library] can be reused.
|
| @@ -199,19 +245,11 @@ class LibraryUpdater extends JsFeatures {
|
| /// This methods also computes the [updates] (patches) needed to have
|
| /// [library] reflect the modifications in [bytes].
|
| bool canReuseLibrary(LibraryElement library, bytes) {
|
| - logTime('Attempting to reuse mainApp.');
|
| + logTime('Attempting to reuse ${library}.');
|
| String newSource = bytes is String ? bytes : 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");
|
| + Uri uri = library.entryCompilationUnit.script.resourceUri;
|
| Script sourceScript = new Script(
|
| uri, uri, new StringSourceFile('$uri', newSource));
|
| var dartPrivacyIsBroken = compiler.libraryLoader;
|
|
|