Version 2.15.0-29.0.dev

Merge commit '120616eefd16ce39d514d953c5dcf7e574801c89' into 'dev'
diff --git a/pkg/compiler/lib/src/deferred_load/algorithm_state.dart b/pkg/compiler/lib/src/deferred_load/algorithm_state.dart
new file mode 100644
index 0000000..3f08d13
--- /dev/null
+++ b/pkg/compiler/lib/src/deferred_load/algorithm_state.dart
@@ -0,0 +1,155 @@
+// Copyright (c) 2021, 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.
+
+import 'entity_data.dart';
+import 'entity_data_info.dart';
+import 'import_set.dart';
+import 'work_queue.dart';
+
+import '../common.dart';
+import '../compiler.dart' show Compiler;
+import '../elements/entities.dart';
+import '../kernel/element_map.dart';
+import '../world.dart' show KClosedWorld;
+
+/// Manages the state of the [EntityData] model. Every class, member, constant,
+/// etc, is wrapped in the deferred loading algorithm by an [EntityData] which
+/// knows how to collect dependencies for a given [Entity].
+class AlgorithmState {
+  final Compiler compiler;
+  final KernelToElementMap elementMap;
+  final KClosedWorld closedWorld;
+  final EntityDataRegistry registry;
+  final Map<EntityData, ImportSet> entityToSet = {};
+  final Map<EntityData, EntityDataInfo> entityDataToInfo = {};
+  final ImportSetLattice importSets;
+  final WorkQueue queue;
+
+  AlgorithmState._(this.closedWorld, this.elementMap, this.compiler,
+      this.importSets, this.registry)
+      : queue = WorkQueue(importSets, registry);
+
+  /// Factory function to create and initialize a [AlgorithmState].
+  factory AlgorithmState.create(
+      FunctionEntity main,
+      Compiler compiler,
+      KernelToElementMap elementMap,
+      KClosedWorld closedWorld,
+      ImportSetLattice importSets) {
+    var entityDataState = AlgorithmState._(
+        closedWorld, elementMap, compiler, importSets, EntityDataRegistry());
+    entityDataState.initialize(main);
+    return entityDataState;
+  }
+
+  /// Given an [EntityData], an [oldSet] and a [newSet], either ignore the
+  /// update, apply the update immediately if we can avoid unions, or apply the
+  /// update later if we cannot. For more detail on [oldSet] and [newSet],
+  /// please see the comment in deferred_load.dart.
+  void update(EntityData entityData, ImportSet oldSet, ImportSet newSet) {
+    ImportSet currentSet = entityToSet[entityData];
+
+    // If [currentSet] == [newSet], then currentSet must include all of newSet.
+    if (currentSet == newSet) return;
+
+    // Elements in the main output unit always remain there.
+    if (currentSet == importSets.mainSet) return;
+
+    // If [currentSet] == [oldSet], then we can safely update the
+    // [entityToSet] map for [entityData] to [newSet] in a single assignment.
+    // If not, then if we are supposed to update [entityData] recursively, we add
+    // it back to the queue so that we can re-enter [update] later after
+    // performing a union. If we aren't supposed to update recursively, we just
+    // perform the union inline.
+    if (currentSet == oldSet) {
+      // Continue recursively updating from [oldSet] to [newSet].
+      entityToSet[entityData] = newSet;
+      updateDependencies(entityData, oldSet, newSet);
+    } else if (entityData.needsRecursiveUpdate) {
+      assert(
+          // Invariant: we must mark main before we mark any deferred import.
+          newSet != importSets.mainSet || oldSet != null,
+          failedAt(
+              NO_LOCATION_SPANNABLE,
+              "Tried to assign to the main output unit, but it was assigned "
+              "to $currentSet."));
+      queue.addEntityData(entityData, newSet);
+    } else {
+      entityToSet[entityData] = importSets.union(currentSet, newSet);
+    }
+  }
+
+  /// Returns the [EntityDataInfo] associated with a given [EntityData].
+  EntityDataInfo getInfo(EntityData data) {
+    // Check for cached [EntityDataInfo], otherwise create a new one and
+    // collect dependencies.
+    var info = entityDataToInfo[data];
+    if (info == null) {
+      var infoBuilder =
+          EntityDataInfoBuilder(closedWorld, elementMap, compiler, registry);
+      var visitor = EntityDataInfoVisitor(infoBuilder);
+      data.accept(visitor);
+      info = infoBuilder.info;
+      entityDataToInfo[data] = info;
+    }
+    return info;
+  }
+
+  /// Whether to enqueue a deferred entityData.
+  ///
+  /// Due to the nature of the algorithm, some dependencies may be visited more
+  /// than once. However, we know that new deferred-imports are only discovered
+  /// when we are visiting the main output unit (size == 0) or code reachable
+  /// from a deferred import (size == 1). After that, we are rediscovering the
+  /// same nodes we have already seen.
+  bool _shouldAddDeferredEntity(ImportSet newSet) => newSet.length <= 1;
+
+  /// Updates the dependencies of a given [EntityData] from [oldSet] to
+  /// [newSet].
+  void updateDependencies(
+      EntityData entityData, ImportSet oldSet, ImportSet newSet) {
+    var info = getInfo(entityData);
+
+    // Process all [DeferredEntityDataInfo]s.
+    if (_shouldAddDeferredEntity(newSet)) {
+      info.deferredRoots.forEach((entity, imports) {
+        for (ImportEntity deferredImport in imports) {
+          queue.addEntityData(entity, importSets.singleton(deferredImport));
+        }
+      });
+    }
+
+    // Process all [directEntityData].
+    for (var entity in info.directDependencies) {
+      update(entity, oldSet, newSet);
+    }
+  }
+
+  /// Initializes the [AlgorithmState] assuming that [main] is the main entry
+  /// point of a given program.
+  void initialize(FunctionEntity main) {
+    // Add `main` and their recursive dependencies to the main output unit.
+    // We do this upfront to avoid wasting time visiting these elements when
+    // analyzing deferred imports.
+    queue.addMember(main, importSets.mainSet);
+
+    // Also add "global" dependencies to the main output unit.  These are
+    // things that the backend needs but cannot associate with a particular
+    // element. This set also contains elements for which we lack precise
+    // information.
+    for (MemberEntity element
+        in closedWorld.backendUsage.globalFunctionDependencies) {
+      queue.addMember(element, importSets.mainSet);
+    }
+    for (ClassEntity element
+        in closedWorld.backendUsage.globalClassDependencies) {
+      queue.addClass(element, importSets.mainSet);
+    }
+
+    // Empty queue.
+    while (queue.isNotEmpty) {
+      queue.processNextItem(this);
+    }
+  }
+}
diff --git a/pkg/compiler/lib/src/deferred_load/deferred_load.dart b/pkg/compiler/lib/src/deferred_load/deferred_load.dart
index c531ba2..360d33e 100644
--- a/pkg/compiler/lib/src/deferred_load/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load/deferred_load.dart
@@ -268,39 +268,26 @@
 // contains a bigger delta.)
 library deferred_load;
 
-import 'dart:collection' show Queue;
-
-import 'package:kernel/ast.dart' as ir;
-
-import 'dependencies.dart';
+import 'algorithm_state.dart';
+import 'entity_data.dart';
 import 'import_set.dart';
 import 'output_unit.dart';
 
 import '../../compiler_new.dart' show OutputType;
-import '../common/metrics.dart' show Metric, Metrics, CountMetric, DurationMetric;
+import '../common/metrics.dart'
+    show Metric, Metrics, CountMetric, DurationMetric;
 import '../common/tasks.dart' show CompilerTask;
 import '../common.dart';
-import '../common_elements.dart' show CommonElements, KElementEnvironment;
+import '../common_elements.dart' show KElementEnvironment;
 import '../compiler.dart' show Compiler;
-import '../constants/values.dart'
-    show
-        ConstantValue,
-        ConstructedConstantValue,
-        InstantiationConstantValue;
+import '../constants/values.dart' show ConstantValue;
 import '../elements/types.dart';
 import '../elements/entities.dart';
-import '../kernel/kelements.dart' show KLocalFunction;
 import '../kernel/element_map.dart';
-import '../universe/use.dart';
-import '../universe/world_impact.dart'
-    show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl;
+import '../universe/world_impact.dart' show ImpactUseCase;
 import '../util/util.dart' show makeUnique;
 import '../world.dart' show KClosedWorld;
 
-// TODO(joshualitt): Refactor logic out of DeferredLoadTask so work_queue.dart
-// can be its own independent library.
-part 'work_queue.dart';
-
 class _DeferredLoadTaskMetrics implements Metrics {
   @override
   String get namespace => 'deferred_load';
@@ -338,21 +325,6 @@
   /// this map.
   final Map<ImportEntity, String> importDeferName = {};
 
-  /// A mapping from classes to their import set.
-  Map<ClassEntity, ImportSet> _classToSet = {};
-
-  /// A mapping from interface types (keyed by classes) to their import set.
-  Map<ClassEntity, ImportSet> _classTypeToSet = {};
-
-  /// A mapping from members to their import set.
-  Map<MemberEntity, ImportSet> _memberToSet = {};
-
-  /// A mapping from local functions to their import set.
-  Map<Local, ImportSet> _localFunctionToSet = {};
-
-  /// A mapping from constants to their import set.
-  Map<ConstantValue, ImportSet> _constantToSet = {};
-
   Iterable<ImportEntity> get _allDeferredImports =>
       _deferredImportDescriptions.keys;
 
@@ -372,6 +344,8 @@
 
   bool get disableProgramSplit => compiler.options.disableProgramSplit;
 
+  AlgorithmState algorithmState;
+
   DeferredLoadTask(this.compiler, this._elementMap) : super(compiler.measurer) {
     _mainOutputUnit = OutputUnit(true, 'main', {});
     importSets.mainSet.unit = _mainOutputUnit;
@@ -381,487 +355,10 @@
   KElementEnvironment get elementEnvironment =>
       compiler.frontendStrategy.elementEnvironment;
 
-  CommonElements get commonElements => compiler.frontendStrategy.commonElements;
-  DartTypes get dartTypes => commonElements.dartTypes;
+  DartTypes get dartTypes => compiler.frontendStrategy.commonElements.dartTypes;
 
   DiagnosticReporter get reporter => compiler.reporter;
 
-  /// Collects all direct dependencies of [element].
-  ///
-  /// The collected dependent elements and constants are are added to
-  /// [elements] and [constants] respectively.
-  void _collectDirectMemberDependencies(KClosedWorld closedWorld,
-      MemberEntity element, Dependencies dependencies) {
-    // TODO(sigurdm): We want to be more specific about this - need a better
-    // way to query "liveness".
-    if (!closedWorld.isMemberUsed(element)) {
-      return;
-    }
-    _collectDependenciesFromImpact(closedWorld, element, dependencies);
-    collectConstantsInBody(element, dependencies);
-  }
-
-  /// Finds all elements and constants that [element] depends directly on.
-  /// (not the transitive closure.)
-  ///
-  /// Adds the results to [elements] and [constants].
-  void _collectAllElementsAndConstantsResolvedFromClass(
-      KClosedWorld closedWorld,
-      ClassEntity element,
-      Dependencies dependencies) {
-    // If we see a class, add everything its live instance members refer
-    // to.  Static members are not relevant, unless we are processing
-    // extra dependencies due to mirrors.
-    void addLiveInstanceMember(MemberEntity member) {
-      if (!closedWorld.isMemberUsed(member)) return;
-      if (!member.isInstanceMember) return;
-      dependencies.addMember(member);
-      _collectDirectMemberDependencies(closedWorld, member, dependencies);
-    }
-
-    void addClassAndMaybeAddEffectiveMixinClass(ClassEntity cls) {
-      dependencies.addClass(cls);
-      if (elementEnvironment.isMixinApplication(cls)) {
-        dependencies.addClass(elementEnvironment.getEffectiveMixinClass(cls));
-      }
-    }
-
-    ClassEntity cls = element;
-    elementEnvironment.forEachLocalClassMember(cls, addLiveInstanceMember);
-    elementEnvironment.forEachSupertype(cls, (InterfaceType type) {
-      _collectTypeDependencies(type, dependencies);
-    });
-    elementEnvironment.forEachSuperClass(cls, (superClass) {
-      addClassAndMaybeAddEffectiveMixinClass(superClass);
-      _collectTypeDependencies(
-          elementEnvironment.getThisType(superClass), dependencies);
-    });
-    addClassAndMaybeAddEffectiveMixinClass(cls);
-  }
-
-  /// Finds all elements and constants that [element] depends directly on.
-  /// (not the transitive closure.)
-  ///
-  /// Adds the results to [elements] and [constants].
-  void _collectAllElementsAndConstantsResolvedFromMember(
-      KClosedWorld closedWorld,
-      MemberEntity element,
-      Dependencies dependencies) {
-    if (element is FunctionEntity) {
-      _collectTypeDependencies(
-          elementEnvironment.getFunctionType(element), dependencies);
-    }
-    if (element.isStatic || element.isTopLevel || element.isConstructor) {
-      dependencies.addMember(element);
-      _collectDirectMemberDependencies(closedWorld, element, dependencies);
-    }
-    if (element is ConstructorEntity && element.isGenerativeConstructor) {
-      // When instantiating a class, we record a reference to the
-      // constructor, not the class itself.  We must add all the
-      // instance members of the constructor's class.
-      ClassEntity cls = element.enclosingClass;
-      _collectAllElementsAndConstantsResolvedFromClass(
-          closedWorld, cls, dependencies);
-    }
-
-    // Other elements, in particular instance members, are ignored as
-    // they are processed as part of the class.
-  }
-
-  /// Extract the set of constants that are used in the body of [element].
-  void collectConstantsInBody(MemberEntity element, Dependencies dependencies) {
-    ir.Member node = _elementMap.getMemberNode(element);
-
-    // Fetch the internal node in order to skip annotations on the member.
-    // TODO(sigmund): replace this pattern when the kernel-ast provides a better
-    // way to skip annotations (issue 31565).
-    var visitor = ConstantCollector(
-        _elementMap, _elementMap.getStaticTypeContext(element), dependencies);
-    if (node is ir.Field) {
-      node.initializer?.accept(visitor);
-      return;
-    }
-
-    if (node is ir.Constructor) {
-      node.initializers.forEach((i) => i.accept(visitor));
-    }
-    node.function?.accept(visitor);
-  }
-
-  /// Recursively collects all the dependencies of [type].
-  void _collectTypeDependencies(DartType type, Dependencies dependencies,
-      [ImportEntity import]) {
-    TypeDependencyVisitor(dependencies, import, commonElements).visit(type);
-  }
-
-  void _collectTypeArgumentDependencies(
-      Iterable<DartType> typeArguments, Dependencies dependencies,
-      [ImportEntity import]) {
-    if (typeArguments == null) return;
-    TypeDependencyVisitor(dependencies, import, commonElements)
-        .visitList(typeArguments);
-  }
-
-  /// Extract any dependencies that are known from the impact of [element].
-  void _collectDependenciesFromImpact(KClosedWorld closedWorld,
-      MemberEntity element, Dependencies dependencies) {
-    WorldImpact worldImpact = compiler.impactCache[element];
-    compiler.impactStrategy.visitImpact(
-        element,
-        worldImpact,
-        WorldImpactVisitorImpl(
-            visitStaticUse: (MemberEntity member, StaticUse staticUse) {
-          void processEntity() {
-            Entity usedEntity = staticUse.element;
-            if (usedEntity is MemberEntity) {
-              dependencies.addMember(usedEntity, staticUse.deferredImport);
-            } else {
-              assert(usedEntity is KLocalFunction,
-                  failedAt(usedEntity, "Unexpected static use $staticUse."));
-              KLocalFunction localFunction = usedEntity;
-              // TODO(sra): Consult KClosedWorld to see if signature is needed.
-              _collectTypeDependencies(
-                  localFunction.functionType, dependencies);
-              dependencies.localFunctions.add(localFunction);
-            }
-          }
-
-          switch (staticUse.kind) {
-            case StaticUseKind.CONSTRUCTOR_INVOKE:
-            case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
-              // The receiver type of generative constructors is a dependency of
-              // the constructor (handled by `addMember` above) and not a
-              // dependency at the call site.
-              // Factory methods, on the other hand, are like static methods so
-              // the target type is not relevant.
-              // TODO(johnniwinther): Use rti need data to skip unneeded type
-              // arguments.
-              _collectTypeArgumentDependencies(
-                  staticUse.type.typeArguments, dependencies);
-              processEntity();
-              break;
-            case StaticUseKind.STATIC_INVOKE:
-            case StaticUseKind.CLOSURE_CALL:
-            case StaticUseKind.DIRECT_INVOKE:
-              // TODO(johnniwinther): Use rti need data to skip unneeded type
-              // arguments.
-              _collectTypeArgumentDependencies(
-                  staticUse.typeArguments, dependencies);
-              processEntity();
-              break;
-            case StaticUseKind.STATIC_TEAR_OFF:
-            case StaticUseKind.CLOSURE:
-            case StaticUseKind.STATIC_GET:
-            case StaticUseKind.STATIC_SET:
-              processEntity();
-              break;
-            case StaticUseKind.SUPER_TEAR_OFF:
-            case StaticUseKind.SUPER_FIELD_SET:
-            case StaticUseKind.SUPER_GET:
-            case StaticUseKind.SUPER_SETTER_SET:
-            case StaticUseKind.SUPER_INVOKE:
-            case StaticUseKind.INSTANCE_FIELD_GET:
-            case StaticUseKind.INSTANCE_FIELD_SET:
-            case StaticUseKind.FIELD_INIT:
-            case StaticUseKind.FIELD_CONSTANT_INIT:
-              // These static uses are not relevant for this algorithm.
-              break;
-            case StaticUseKind.CALL_METHOD:
-            case StaticUseKind.INLINING:
-              failedAt(element, "Unexpected static use: $staticUse.");
-              break;
-          }
-        }, visitTypeUse: (MemberEntity member, TypeUse typeUse) {
-          void addClassIfInterfaceType(DartType t, [ImportEntity import]) {
-            var typeWithoutNullability = t.withoutNullability;
-            if (typeWithoutNullability is InterfaceType) {
-              dependencies.addClass(typeWithoutNullability.element, import);
-            }
-          }
-
-          DartType type = typeUse.type;
-          switch (typeUse.kind) {
-            case TypeUseKind.TYPE_LITERAL:
-              _collectTypeDependencies(
-                  type, dependencies, typeUse.deferredImport);
-              break;
-            case TypeUseKind.CONST_INSTANTIATION:
-              addClassIfInterfaceType(type, typeUse.deferredImport);
-              _collectTypeDependencies(
-                  type, dependencies, typeUse.deferredImport);
-              break;
-            case TypeUseKind.INSTANTIATION:
-            case TypeUseKind.NATIVE_INSTANTIATION:
-              addClassIfInterfaceType(type);
-              _collectTypeDependencies(type, dependencies);
-              break;
-            case TypeUseKind.IS_CHECK:
-            case TypeUseKind.CATCH_TYPE:
-              _collectTypeDependencies(type, dependencies);
-              break;
-            case TypeUseKind.AS_CAST:
-              if (closedWorld.annotationsData
-                  .getExplicitCastCheckPolicy(element)
-                  .isEmitted) {
-                _collectTypeDependencies(type, dependencies);
-              }
-              break;
-            case TypeUseKind.IMPLICIT_CAST:
-              if (closedWorld.annotationsData
-                  .getImplicitDowncastCheckPolicy(element)
-                  .isEmitted) {
-                _collectTypeDependencies(type, dependencies);
-              }
-              break;
-            case TypeUseKind.PARAMETER_CHECK:
-            case TypeUseKind.TYPE_VARIABLE_BOUND_CHECK:
-              if (closedWorld.annotationsData
-                  .getParameterCheckPolicy(element)
-                  .isEmitted) {
-                _collectTypeDependencies(type, dependencies);
-              }
-              break;
-            case TypeUseKind.RTI_VALUE:
-            case TypeUseKind.TYPE_ARGUMENT:
-            case TypeUseKind.NAMED_TYPE_VARIABLE_NEW_RTI:
-            case TypeUseKind.CONSTRUCTOR_REFERENCE:
-              failedAt(element, "Unexpected type use: $typeUse.");
-              break;
-          }
-        }, visitDynamicUse: (MemberEntity member, DynamicUse dynamicUse) {
-          // TODO(johnniwinther): Use rti need data to skip unneeded type
-          // arguments.
-          _collectTypeArgumentDependencies(
-              dynamicUse.typeArguments, dependencies);
-        }),
-        DeferredLoadTask.IMPACT_USE);
-  }
-
-  /// Update the import set of all constants reachable from [constant], as long
-  /// as they had the [oldSet]. As soon as we see a constant with a different
-  /// import set, we stop and enqueue a new recursive update in [queue].
-  ///
-  /// Invariants: oldSet is either null or a subset of newSet.
-  void _updateConstantRecursive(
-      KClosedWorld closedWorld,
-      ConstantValue constant,
-      ImportSet oldSet,
-      ImportSet newSet,
-      WorkQueue queue) {
-    if (constant == null) return;
-    var currentSet = _constantToSet[constant];
-
-    // Already visited.
-    if (currentSet == newSet) return;
-
-    // Elements in the main output unit always remain there.
-    if (currentSet == importSets.mainSet) return;
-
-    if (currentSet == oldSet) {
-      _constantToSet[constant] = newSet;
-      if (constant is ConstructedConstantValue) {
-        ClassEntity cls = constant.type.element;
-        _updateClassRecursive(closedWorld, cls, oldSet, newSet, queue);
-      }
-      if (constant is InstantiationConstantValue) {
-        for (DartType type in constant.typeArguments) {
-          type = type.withoutNullability;
-          if (type is InterfaceType) {
-            _updateClassRecursive(
-                closedWorld, type.element, oldSet, newSet, queue);
-          }
-        }
-      }
-      constant.getDependencies().forEach((ConstantValue dependency) {
-        // Constants are not allowed to refer to deferred constants, so
-        // no need to check for a deferred type literal here.
-        _updateConstantRecursive(
-            closedWorld, dependency, oldSet, newSet, queue);
-      });
-    } else {
-      assert(
-          // Invariant: we must mark main before we mark any deferred import.
-          newSet != importSets.mainSet || oldSet != null,
-          failedAt(
-              NO_LOCATION_SPANNABLE,
-              "Tried to assign ${constant.toDartText(closedWorld.dartTypes)} "
-              "to the main output unit, but it was assigned to $currentSet."));
-      queue.addConstant(constant, newSet);
-    }
-  }
-
-  void _updateClassRecursive(KClosedWorld closedWorld, ClassEntity element,
-      ImportSet oldSet, ImportSet newSet, WorkQueue queue) {
-    if (element == null) return;
-
-    ImportSet currentSet = _classToSet[element];
-
-    // Already visited. We may visit some root nodes a second time with
-    // [isMirrorUsage] in order to mark static members used reflectively.
-    if (currentSet == newSet) return;
-
-    // Elements in the main output unit always remain there.
-    if (currentSet == importSets.mainSet) return;
-
-    if (currentSet == oldSet) {
-      // Continue recursively updating from [oldSet] to [newSet].
-      _classToSet[element] = newSet;
-
-      Dependencies dependencies = Dependencies();
-      _collectAllElementsAndConstantsResolvedFromClass(
-          closedWorld, element, dependencies);
-      LibraryEntity library = element.library;
-      _processDependencies(
-          closedWorld, library, dependencies, oldSet, newSet, queue, element);
-    } else {
-      queue.addClass(element, newSet);
-    }
-  }
-
-  void _updateClassTypeRecursive(KClosedWorld closedWorld, ClassEntity element,
-      ImportSet oldSet, ImportSet newSet, WorkQueue queue) {
-    if (element == null) return;
-
-    ImportSet currentSet = _classTypeToSet[element];
-
-    // Already visited. We may visit some root nodes a second time with
-    // [isMirrorUsage] in order to mark static members used reflectively.
-    if (currentSet == newSet) return;
-
-    // Elements in the main output unit always remain there.
-    if (currentSet == importSets.mainSet) return;
-
-    if (currentSet == oldSet) {
-      // Continue recursively updating from [oldSet] to [newSet].
-      _classTypeToSet[element] = newSet;
-
-      Dependencies dependencies = Dependencies();
-      dependencies.addClassType(element);
-      LibraryEntity library = element.library;
-      _processDependencies(
-          closedWorld, library, dependencies, oldSet, newSet, queue, element);
-    } else {
-      queue.addClassType(element, newSet);
-    }
-  }
-
-  void _updateMemberRecursive(KClosedWorld closedWorld, MemberEntity element,
-      ImportSet oldSet, ImportSet newSet, WorkQueue queue) {
-    if (element == null) return;
-
-    ImportSet currentSet = _memberToSet[element];
-
-    // Already visited. We may visit some root nodes a second time with
-    // [isMirrorUsage] in order to mark static members used reflectively.
-    if (currentSet == newSet) return;
-
-    // Elements in the main output unit always remain there.
-    if (currentSet == importSets.mainSet) return;
-
-    if (currentSet == oldSet) {
-      // Continue recursively updating from [oldSet] to [newSet].
-      _memberToSet[element] = newSet;
-
-      Dependencies dependencies = Dependencies();
-      _collectAllElementsAndConstantsResolvedFromMember(
-          closedWorld, element, dependencies);
-
-      LibraryEntity library = element.library;
-      _processDependencies(
-          closedWorld, library, dependencies, oldSet, newSet, queue, element);
-    } else {
-      queue.addMember(element, newSet);
-    }
-  }
-
-  void _updateLocalFunction(
-      Local localFunction, ImportSet oldSet, ImportSet newSet) {
-    ImportSet currentSet = _localFunctionToSet[localFunction];
-    if (currentSet == newSet) return;
-
-    // Elements in the main output unit always remain there.
-    if (currentSet == importSets.mainSet) return;
-
-    if (currentSet == oldSet) {
-      _localFunctionToSet[localFunction] = newSet;
-    } else {
-      _localFunctionToSet[localFunction] = importSets.union(currentSet, newSet);
-    }
-    // Note: local functions are not updated recursively because the
-    // dependencies are already visited as dependencies of the enclosing member.
-  }
-
-  /// Whether to enqueue a deferred dependency.
-  ///
-  /// Due to the nature of the algorithm, some dependencies may be visited more
-  /// than once. However, we know that new deferred-imports are only discovered
-  /// when we are visiting the main output unit (size == 0) or code reachable
-  /// from a deferred import (size == 1). After that, we are rediscovering the
-  /// same nodes we have already seen.
-  _shouldAddDeferredDependency(ImportSet newSet) => newSet.length <= 1;
-
-  void _processDependencies(
-      KClosedWorld closedWorld,
-      LibraryEntity library,
-      Dependencies dependencies,
-      ImportSet oldSet,
-      ImportSet newSet,
-      WorkQueue queue,
-      Spannable context) {
-    dependencies.classes.forEach((ClassEntity cls, DependencyInfo info) {
-      if (info.isDeferred) {
-        if (_shouldAddDeferredDependency(newSet)) {
-          for (ImportEntity deferredImport in info.imports) {
-            queue.addClass(cls, importSets.singleton(deferredImport));
-          }
-        }
-      } else {
-        _updateClassRecursive(closedWorld, cls, oldSet, newSet, queue);
-      }
-    });
-
-    dependencies.classType.forEach((ClassEntity cls, DependencyInfo info) {
-      if (info.isDeferred) {
-        if (_shouldAddDeferredDependency(newSet)) {
-          for (ImportEntity deferredImport in info.imports) {
-            queue.addClassType(cls, importSets.singleton(deferredImport));
-          }
-        }
-      } else {
-        _updateClassTypeRecursive(closedWorld, cls, oldSet, newSet, queue);
-      }
-    });
-
-    dependencies.members.forEach((MemberEntity member, DependencyInfo info) {
-      if (info.isDeferred) {
-        if (_shouldAddDeferredDependency(newSet)) {
-          for (ImportEntity deferredImport in info.imports) {
-            queue.addMember(member, importSets.singleton(deferredImport));
-          }
-        }
-      } else {
-        _updateMemberRecursive(closedWorld, member, oldSet, newSet, queue);
-      }
-    });
-
-    for (Local localFunction in dependencies.localFunctions) {
-      _updateLocalFunction(localFunction, oldSet, newSet);
-    }
-
-    dependencies.constants
-        .forEach((ConstantValue constant, DependencyInfo info) {
-      if (info.isDeferred) {
-        if (_shouldAddDeferredDependency(newSet)) {
-          for (ImportEntity deferredImport in info.imports) {
-            queue.addConstant(constant, importSets.singleton(deferredImport));
-          }
-        }
-      } else {
-        _updateConstantRecursive(closedWorld, constant, oldSet, newSet, queue);
-      }
-    });
-  }
-
   /// Computes a unique string for the name field for each outputUnit.
   void _createOutputUnits() {
     int counter = 1;
@@ -877,11 +374,7 @@
 
     // Generate an output unit for all import sets that are associated with an
     // element or constant.
-    _classToSet.values.forEach(addUnit);
-    _classTypeToSet.values.forEach(addUnit);
-    _memberToSet.values.forEach(addUnit);
-    _localFunctionToSet.values.forEach(addUnit);
-    _constantToSet.values.forEach(addUnit);
+    algorithmState?.entityToSet?.values?.forEach(addUnit);
 
     // Sort output units to make the output of the compiler more stable.
     _allOutputUnits.sort();
@@ -937,34 +430,8 @@
     }
 
     work() {
-      var queue = WorkQueue(this.importSets);
-
-      // Add `main` and their recursive dependencies to the main output unit.
-      // We do this upfront to avoid wasting time visiting these elements when
-      // analyzing deferred imports.
-      queue.addMember(main, importSets.mainSet);
-
-      // Also add "global" dependencies to the main output unit.  These are
-      // things that the backend needs but cannot associate with a particular
-      // element. This set also contains elements for which we lack precise
-      // information.
-      for (MemberEntity element
-          in closedWorld.backendUsage.globalFunctionDependencies) {
-        queue.addMember(element, importSets.mainSet);
-      }
-      for (ClassEntity element
-          in closedWorld.backendUsage.globalClassDependencies) {
-        queue.addClass(element, importSets.mainSet);
-      }
-
-      void emptyQueue() {
-        while (queue.isNotEmpty) {
-          WorkItem item = queue.nextItem();
-          item.update(this, closedWorld, queue);
-        }
-      }
-
-      emptyQueue();
+      algorithmState = AlgorithmState.create(
+          main, compiler, _elementMap, closedWorld, importSets);
     }
 
     reporter.withCurrentElement(main.library, () => measure(work));
@@ -1014,18 +481,22 @@
     Map<MemberEntity, OutputUnit> memberMap = {};
     Map<Local, OutputUnit> localFunctionMap = {};
     Map<ConstantValue, OutputUnit> constantMap = {};
-    _classToSet.forEach((cls, s) => classMap[cls] = s.unit);
-    _classTypeToSet.forEach((cls, s) => classTypeMap[cls] = s.unit);
-    _memberToSet.forEach((member, s) => memberMap[member] = s.unit);
-    _localFunctionToSet.forEach(
-        (localFunction, s) => localFunctionMap[localFunction] = s.unit);
-    _constantToSet.forEach((constant, s) => constantMap[constant] = s.unit);
-
-    _classToSet = null;
-    _classTypeToSet = null;
-    _memberToSet = null;
-    _localFunctionToSet = null;
-    _constantToSet = null;
+    algorithmState?.entityToSet?.forEach((d, s) {
+      if (d is ClassEntityData) {
+        classMap[d.entity] = s.unit;
+      } else if (d is ClassTypeEntityData) {
+        classTypeMap[d.entity] = s.unit;
+      } else if (d is MemberEntityData) {
+        memberMap[d.entity] = s.unit;
+      } else if (d is LocalFunctionEntityData) {
+        localFunctionMap[d.entity] = s.unit;
+      } else if (d is ConstantEntityData) {
+        constantMap[d.entity] = s.unit;
+      } else {
+        throw 'Unrecognized EntityData $d';
+      }
+    });
+    algorithmState = null;
     importSets = null;
     return OutputUnitData(
         this.isProgramSplit && !disableProgramSplit,
@@ -1057,53 +528,52 @@
     });
   }
 
-  bool ignoreEntityInDump(Entity element) => false;
-
   /// Creates a textual representation of the output unit content.
   String dump() {
     Map<OutputUnit, List<String>> elementMap = {};
     Map<OutputUnit, List<String>> constantMap = {};
-    _classToSet.forEach((ClassEntity element, ImportSet importSet) {
-      if (ignoreEntityInDump(element)) return;
-      var elements = elementMap.putIfAbsent(importSet.unit, () => <String>[]);
-      var id = element.name ?? '$element';
-      id = '$id cls';
-      elements.add(id);
-    });
-    _classTypeToSet.forEach((ClassEntity element, ImportSet importSet) {
-      if (ignoreEntityInDump(element)) return;
-      var elements = elementMap.putIfAbsent(importSet.unit, () => <String>[]);
-      var id = element.name ?? '$element';
-      id = '$id type';
-      elements.add(id);
-    });
-    _memberToSet.forEach((MemberEntity element, ImportSet importSet) {
-      if (ignoreEntityInDump(element)) return;
-      var elements = elementMap.putIfAbsent(importSet.unit, () => []);
-      var id = element.name ?? '$element';
-      var cls = element.enclosingClass?.name;
-      if (cls != null) id = '$cls.$id';
-      if (element.isSetter) id = '$id=';
-      id = '$id member';
-      elements.add(id);
-    });
-    _localFunctionToSet.forEach((Local element, ImportSet importSet) {
-      if (ignoreEntityInDump(element)) return;
-      var elements = elementMap.putIfAbsent(importSet.unit, () => []);
-      var id = element.name ?? '$element';
-      var context = (element as dynamic).memberContext.name;
-      id = element.name == null || element.name == '' ? '<anonymous>' : id;
-      id = '$context.$id';
-      id = '$id local';
-      elements.add(id);
-    });
-    _constantToSet.forEach((ConstantValue value, ImportSet importSet) {
-      // Skip primitive values: they are not stored in the constant tables and
-      // if they are shared, they end up duplicated anyways across output units.
-      if (value.isPrimitive) return;
-      constantMap
-          .putIfAbsent(importSet.unit, () => [])
-          .add(value.toStructuredText(dartTypes));
+    algorithmState?.entityToSet?.forEach((d, importSet) {
+      if (d is ClassEntityData) {
+        var element = d.entity;
+        var elements = elementMap.putIfAbsent(importSet.unit, () => <String>[]);
+        var id = element.name ?? '$element';
+        id = '$id cls';
+        elements.add(id);
+      } else if (d is ClassTypeEntityData) {
+        var element = d.entity;
+        var elements = elementMap.putIfAbsent(importSet.unit, () => <String>[]);
+        var id = element.name ?? '$element';
+        id = '$id type';
+        elements.add(id);
+      } else if (d is MemberEntityData) {
+        var element = d.entity;
+        var elements = elementMap.putIfAbsent(importSet.unit, () => []);
+        var id = element.name ?? '$element';
+        var cls = element.enclosingClass?.name;
+        if (cls != null) id = '$cls.$id';
+        if (element.isSetter) id = '$id=';
+        id = '$id member';
+        elements.add(id);
+      } else if (d is LocalFunctionEntityData) {
+        var element = d.entity;
+        var elements = elementMap.putIfAbsent(importSet.unit, () => []);
+        var id = element.name ?? '$element';
+        var context = (element as dynamic).memberContext.name;
+        id = element.name == null || element.name == '' ? '<anonymous>' : id;
+        id = '$context.$id';
+        id = '$id local';
+        elements.add(id);
+      } else if (d is ConstantEntityData) {
+        var value = d.entity;
+        // Skip primitive values: they are not stored in the constant tables and
+        // if they are shared, they end up duplicated anyways across output units.
+        if (value.isPrimitive) return;
+        constantMap
+            .putIfAbsent(importSet.unit, () => [])
+            .add(value.toStructuredText(dartTypes));
+      } else {
+        throw 'Unrecognized EntityData $d';
+      }
     });
 
     Map<OutputUnit, String> text = {};
diff --git a/pkg/compiler/lib/src/deferred_load/dependencies.dart b/pkg/compiler/lib/src/deferred_load/dependencies.dart
deleted file mode 100644
index c4579a5..0000000
--- a/pkg/compiler/lib/src/deferred_load/dependencies.dart
+++ /dev/null
@@ -1,250 +0,0 @@
-// Copyright (c) 2021, 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.
-
-import 'package:kernel/ast.dart' as ir;
-import 'package:kernel/type_environment.dart' as ir;
-
-import '../common_elements.dart' show CommonElements;
-import '../constants/values.dart'
-    show
-        ConstantValue;
-import '../elements/types.dart';
-import '../elements/entities.dart';
-import '../ir/util.dart';
-import '../kernel/element_map.dart';
-
-/// [Dependencies] is a helper for collecting per [Entity] [DependencyInfo].
-class Dependencies {
-  final Map<ClassEntity, DependencyInfo> classes = {};
-  final Map<ClassEntity, DependencyInfo> classType = {};
-  final Map<MemberEntity, DependencyInfo> members = {};
-  final Set<Local> localFunctions = {};
-  final Map<ConstantValue, DependencyInfo> constants = {};
-
-  void addClass(ClassEntity cls, [ImportEntity import]) {
-    (classes[cls] ??= DependencyInfo()).registerImport(import);
-
-    // Add a classType dependency as well just in case we optimize out
-    // the class later.
-    addClassType(cls, import);
-  }
-
-  void addClassType(ClassEntity cls, [ImportEntity import]) {
-    (classType[cls] ??= DependencyInfo()).registerImport(import);
-  }
-
-  void addMember(MemberEntity m, [ImportEntity import]) {
-    (members[m] ??= DependencyInfo()).registerImport(import);
-  }
-
-  void addConstant(ConstantValue c, [ImportEntity import]) {
-    (constants[c] ??= DependencyInfo()).registerImport(import);
-  }
-}
-
-class DependencyInfo {
-  bool isDeferred = true;
-  List<ImportEntity> imports;
-
-  registerImport(ImportEntity import) {
-    if (!isDeferred) return;
-    // A null import represents a direct non-deferred dependency.
-    if (import != null) {
-      (imports ??= []).add(import);
-    } else {
-      imports = null;
-      isDeferred = false;
-    }
-  }
-}
-
-class TypeDependencyVisitor implements DartTypeVisitor<void, Null> {
-  final Dependencies _dependencies;
-  final ImportEntity _import;
-  final CommonElements _commonElements;
-
-  TypeDependencyVisitor(this._dependencies, this._import, this._commonElements);
-
-  @override
-  void visit(DartType type, [_]) {
-    type.accept(this, null);
-  }
-
-  void visitList(List<DartType> types) {
-    types.forEach(visit);
-  }
-
-  @override
-  void visitLegacyType(LegacyType type, Null argument) {
-    visit(type.baseType);
-  }
-
-  @override
-  void visitNullableType(NullableType type, Null argument) {
-    visit(type.baseType);
-  }
-
-  @override
-  void visitFutureOrType(FutureOrType type, Null argument) {
-    _dependencies.addClassType(_commonElements.futureClass);
-    visit(type.typeArgument);
-  }
-
-  @override
-  void visitNeverType(NeverType type, Null argument) {
-    // Nothing to add.
-  }
-
-  @override
-  void visitDynamicType(DynamicType type, Null argument) {
-    // Nothing to add.
-  }
-
-  @override
-  void visitErasedType(ErasedType type, Null argument) {
-    // Nothing to add.
-  }
-
-  @override
-  void visitAnyType(AnyType type, Null argument) {
-    // Nothing to add.
-  }
-
-  @override
-  void visitInterfaceType(InterfaceType type, Null argument) {
-    visitList(type.typeArguments);
-    _dependencies.addClassType(type.element, _import);
-  }
-
-  @override
-  void visitFunctionType(FunctionType type, Null argument) {
-    for (FunctionTypeVariable typeVariable in type.typeVariables) {
-      visit(typeVariable.bound);
-    }
-    visitList(type.parameterTypes);
-    visitList(type.optionalParameterTypes);
-    visitList(type.namedParameterTypes);
-    visit(type.returnType);
-  }
-
-  @override
-  void visitFunctionTypeVariable(FunctionTypeVariable type, Null argument) {
-    // Nothing to add. Handled in [visitFunctionType].
-  }
-
-  @override
-  void visitTypeVariableType(TypeVariableType type, Null argument) {
-    // TODO(johnniwinther): Do we need to collect the bound?
-  }
-
-  @override
-  void visitVoidType(VoidType type, Null argument) {
-    // Nothing to add.
-  }
-}
-
-class ConstantCollector extends ir.RecursiveVisitor {
-  final KernelToElementMap elementMap;
-  final Dependencies dependencies;
-  final ir.StaticTypeContext staticTypeContext;
-
-  ConstantCollector(this.elementMap, this.staticTypeContext, this.dependencies);
-
-  CommonElements get commonElements => elementMap.commonElements;
-
-  void add(ir.Expression node, {bool required = true}) {
-    ConstantValue constant = elementMap
-        .getConstantValue(staticTypeContext, node, requireConstant: required);
-    if (constant != null) {
-      dependencies.addConstant(
-          constant, elementMap.getImport(getDeferredImport(node)));
-    }
-  }
-
-  @override
-  void visitIntLiteral(ir.IntLiteral literal) {}
-
-  @override
-  void visitDoubleLiteral(ir.DoubleLiteral literal) {}
-
-  @override
-  void visitBoolLiteral(ir.BoolLiteral literal) {}
-
-  @override
-  void visitStringLiteral(ir.StringLiteral literal) {}
-
-  @override
-  void visitSymbolLiteral(ir.SymbolLiteral literal) => add(literal);
-
-  @override
-  void visitNullLiteral(ir.NullLiteral literal) {}
-
-  @override
-  void visitListLiteral(ir.ListLiteral literal) {
-    if (literal.isConst) {
-      add(literal);
-    } else {
-      super.visitListLiteral(literal);
-    }
-  }
-
-  @override
-  void visitSetLiteral(ir.SetLiteral literal) {
-    if (literal.isConst) {
-      add(literal);
-    } else {
-      super.visitSetLiteral(literal);
-    }
-  }
-
-  @override
-  void visitMapLiteral(ir.MapLiteral literal) {
-    if (literal.isConst) {
-      add(literal);
-    } else {
-      super.visitMapLiteral(literal);
-    }
-  }
-
-  @override
-  void visitConstructorInvocation(ir.ConstructorInvocation node) {
-    if (node.isConst) {
-      add(node);
-    } else {
-      super.visitConstructorInvocation(node);
-    }
-  }
-
-  @override
-  void visitTypeParameter(ir.TypeParameter node) {
-    // We avoid visiting metadata on the type parameter declaration. The bound
-    // cannot hold constants so we skip that as well.
-  }
-
-  @override
-  void visitVariableDeclaration(ir.VariableDeclaration node) {
-    // We avoid visiting metadata on the parameter declaration by only visiting
-    // the initializer. The type cannot hold constants so can kan skip that
-    // as well.
-    node.initializer?.accept(this);
-  }
-
-  @override
-  void visitTypeLiteral(ir.TypeLiteral node) {
-    if (node.type is! ir.TypeParameterType) add(node);
-  }
-
-  @override
-  void visitInstantiation(ir.Instantiation node) {
-    // TODO(johnniwinther): The CFE should mark constant instantiations as
-    // constant.
-    add(node, required: false);
-    super.visitInstantiation(node);
-  }
-
-  @override
-  void visitConstantExpression(ir.ConstantExpression node) {
-    add(node);
-  }
-}
diff --git a/pkg/compiler/lib/src/deferred_load/entity_data.dart b/pkg/compiler/lib/src/deferred_load/entity_data.dart
new file mode 100644
index 0000000..bfb81f2
--- /dev/null
+++ b/pkg/compiler/lib/src/deferred_load/entity_data.dart
@@ -0,0 +1,108 @@
+// Copyright (c) 2021, 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.
+
+import '../constants/values.dart' show ConstantValue;
+import '../elements/entities.dart';
+
+/// [EntityData] is the base class of wrapped [Entity] objects. Each
+/// [EntityData] child knows how to use an [EntityDataCollector] to collect
+/// [EntityDataInfo]. [EntityData] objects are canonicalized and must be created
+/// by an [EntityDataRegistry].
+abstract class EntityData<T> {
+  final T entity;
+
+  EntityData(this.entity);
+
+  void accept(EntityDataVisitor visitor);
+
+  /// Whether or not the [EntityData] needs to be updated recursively.
+  bool get needsRecursiveUpdate => true;
+}
+
+class ClassEntityData extends EntityData<ClassEntity> {
+  @override
+  void accept(EntityDataVisitor visitor) {
+    visitor.visitClassEntityData(entity);
+  }
+
+  ClassEntityData(ClassEntity entity) : super(entity);
+}
+
+class ClassTypeEntityData extends EntityData<ClassEntity> {
+  @override
+  void accept(EntityDataVisitor visitor) {
+    visitor.visitClassTypeEntityData(entity);
+  }
+
+  ClassTypeEntityData(ClassEntity entity) : super(entity);
+}
+
+class MemberEntityData extends EntityData<MemberEntity> {
+  @override
+  void accept(EntityDataVisitor visitor) {
+    visitor.visitMemberEntityData(entity);
+  }
+
+  MemberEntityData(MemberEntity entity) : super(entity);
+}
+
+class LocalFunctionEntityData extends EntityData<Local> {
+  @override
+  void accept(EntityDataVisitor) {}
+
+  // Note: local functions are not updated recursively because the
+  // dependencies are already visited as dependencies of the enclosing member.
+  @override
+  bool get needsRecursiveUpdate => false;
+
+  LocalFunctionEntityData(Local entity) : super(entity);
+}
+
+class ConstantEntityData extends EntityData<ConstantValue> {
+  @override
+  void accept(EntityDataVisitor visitor) {
+    visitor.visitConstantEntityData(entity);
+  }
+
+  ConstantEntityData(ConstantValue entity) : super(entity);
+}
+
+/// A registry used to canonicalize [EntityData].
+class EntityDataRegistry {
+  /// Map of [Entity] / [ConstantValue] to [EntityData], used by all non
+  /// [ClassTypeEntityData].
+  final Map<Object, EntityData> _nonClassTypeData = {};
+
+  /// Map of [ClassEntity] to [EntityData], used by [ClassTypeEntityData].
+  final Map<ClassEntity, ClassTypeEntityData> _classTypeData = {};
+
+  EntityData createClassEntityData(ClassEntity cls) {
+    return _nonClassTypeData[cls] ??= ClassEntityData(cls);
+  }
+
+  EntityData createClassTypeEntityData(ClassEntity cls) {
+    return _classTypeData[cls] ??= ClassTypeEntityData(cls);
+  }
+
+  EntityData createConstantEntityData(ConstantValue constant) {
+    return _nonClassTypeData[constant] ??= ConstantEntityData(constant);
+  }
+
+  EntityData createLocalFunctionEntityData(Local localFunction) {
+    return _nonClassTypeData[localFunction] ??=
+        LocalFunctionEntityData(localFunction);
+  }
+
+  EntityData createMemberEntityData(MemberEntity member) {
+    return _nonClassTypeData[member] ??= MemberEntityData(member);
+  }
+}
+
+/// A trivial visitor to facilate interacting with [EntityData].
+abstract class EntityDataVisitor {
+  void visitClassEntityData(ClassEntity element);
+  void visitClassTypeEntityData(ClassEntity element);
+  void visitConstantEntityData(ConstantValue constant);
+  void visitMemberEntityData(MemberEntity member);
+}
diff --git a/pkg/compiler/lib/src/deferred_load/entity_data_info.dart b/pkg/compiler/lib/src/deferred_load/entity_data_info.dart
new file mode 100644
index 0000000..f3d9ecc
--- /dev/null
+++ b/pkg/compiler/lib/src/deferred_load/entity_data_info.dart
@@ -0,0 +1,568 @@
+// Copyright (c) 2021, 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.
+
+import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/type_environment.dart' as ir;
+
+import 'deferred_load.dart';
+import 'entity_data.dart';
+
+import '../common.dart';
+import '../common_elements.dart' show CommonElements, KElementEnvironment;
+import '../compiler.dart' show Compiler;
+import '../constants/values.dart'
+    show ConstantValue, ConstructedConstantValue, InstantiationConstantValue;
+import '../elements/types.dart';
+import '../elements/entities.dart';
+import '../ir/util.dart';
+import '../kernel/kelements.dart' show KLocalFunction;
+import '../kernel/element_map.dart';
+import '../universe/use.dart';
+import '../universe/world_impact.dart'
+    show ImpactStrategy, WorldImpact, WorldImpactVisitorImpl;
+import '../world.dart' show KClosedWorld;
+
+/// [EntityDataInfo] is meta data about [EntityData] for a given compilation
+/// [Entity].
+class EntityDataInfo {
+  /// The deferred [EntityData] roots collected by the collector.
+  final Map<EntityData, List<ImportEntity>> deferredRoots = {};
+
+  /// The direct [EntityData] collected by the collector.
+  final Set<EntityData> directDependencies = {};
+
+  /// Various [add] methods for various types of direct dependencies.
+  void add(EntityData entityData, {ImportEntity import}) {
+    // If we already have a direct dependency on [entityData] then we have
+    // nothing left to do.
+    if (directDependencies.contains(entityData)) return;
+
+    // If [import] is null, then create a direct dependency on [entityData] and
+    // remove any deferred roots. Otherwise, add [import] to [deferredRoots] for
+    // [entityData].
+    if (import == null) {
+      deferredRoots.remove(entityData);
+      directDependencies.add(entityData);
+    } else {
+      (deferredRoots[entityData] ??= []).add(import);
+    }
+  }
+}
+
+/// Builds [EntityDataInfo] to help update dependencies of [EntityData] in the
+/// deferred_load algorithm.
+class EntityDataInfoBuilder {
+  final EntityDataInfo info = EntityDataInfo();
+  final KClosedWorld closedWorld;
+  final KernelToElementMap elementMap;
+  final Compiler compiler;
+  final EntityDataRegistry registry;
+
+  EntityDataInfoBuilder(
+      this.closedWorld, this.elementMap, this.compiler, this.registry);
+
+  Map<Entity, WorldImpact> get impactCache => compiler.impactCache;
+  ImpactStrategy get impactStrategy => compiler.impactStrategy;
+  KElementEnvironment get elementEnvironment =>
+      compiler.frontendStrategy.elementEnvironment;
+  CommonElements get commonElements => compiler.frontendStrategy.commonElements;
+
+  void add(EntityData data, {ImportEntity import}) {
+    info.add(data, import: import);
+  }
+
+  void addClass(ClassEntity cls, {ImportEntity import}) {
+    add(registry.createClassEntityData(cls), import: import);
+
+    // Add a classType entityData as well just in case we optimize out
+    // the class later.
+    addClassType(cls, import: import);
+  }
+
+  void addClassType(ClassEntity cls, {ImportEntity import}) {
+    add(registry.createClassTypeEntityData(cls), import: import);
+  }
+
+  void addMember(MemberEntity m, {ImportEntity import}) {
+    add(registry.createMemberEntityData(m), import: import);
+  }
+
+  void addConstant(ConstantValue c, {ImportEntity import}) {
+    add(registry.createConstantEntityData(c), import: import);
+  }
+
+  void addLocalFunction(Local localFunction) {
+    add(registry.createLocalFunctionEntityData(localFunction));
+  }
+
+  /// Recursively collects all the dependencies of [type].
+  void addTypeDependencies(DartType type, [ImportEntity import]) {
+    TypeEntityDataVisitor(this, import, commonElements).visit(type);
+  }
+
+  /// Recursively collects all the dependencies of [types].
+  void addTypeListDependencies(Iterable<DartType> types,
+      [ImportEntity import]) {
+    if (types == null) return;
+    TypeEntityDataVisitor(this, import, commonElements).visitList(types);
+  }
+
+  /// Collects all direct dependencies of [element].
+  ///
+  /// The collected dependent elements and constants are are added to
+  /// [elements] and [constants] respectively.
+  void addDirectMemberDependencies(MemberEntity element) {
+    // TODO(sigurdm): We want to be more specific about this - need a better
+    // way to query "liveness".
+    if (!closedWorld.isMemberUsed(element)) {
+      return;
+    }
+    _addDependenciesFromImpact(element);
+    ConstantCollector.collect(elementMap, element, this);
+  }
+
+  void _addFromStaticUse(MemberEntity parent, StaticUse staticUse) {
+    void processEntity() {
+      Entity usedEntity = staticUse.element;
+      if (usedEntity is MemberEntity) {
+        addMember(usedEntity, import: staticUse.deferredImport);
+      } else {
+        assert(usedEntity is KLocalFunction,
+            failedAt(usedEntity, "Unexpected static use $staticUse."));
+        KLocalFunction localFunction = usedEntity;
+        // TODO(sra): Consult KClosedWorld to see if signature is needed.
+        addTypeDependencies(localFunction.functionType);
+        addLocalFunction(localFunction);
+      }
+    }
+
+    switch (staticUse.kind) {
+      case StaticUseKind.CONSTRUCTOR_INVOKE:
+      case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
+        // The receiver type of generative constructors is a entityData of
+        // the constructor (handled by `addMember` above) and not a
+        // entityData at the call site.
+        // Factory methods, on the other hand, are like static methods so
+        // the target type is not relevant.
+        // TODO(johnniwinther): Use rti need data to skip unneeded type
+        // arguments.
+        addTypeListDependencies(staticUse.type.typeArguments);
+        processEntity();
+        break;
+      case StaticUseKind.STATIC_INVOKE:
+      case StaticUseKind.CLOSURE_CALL:
+      case StaticUseKind.DIRECT_INVOKE:
+        // TODO(johnniwinther): Use rti need data to skip unneeded type
+        // arguments.
+        addTypeListDependencies(staticUse.typeArguments);
+        processEntity();
+        break;
+      case StaticUseKind.STATIC_TEAR_OFF:
+      case StaticUseKind.CLOSURE:
+      case StaticUseKind.STATIC_GET:
+      case StaticUseKind.STATIC_SET:
+        processEntity();
+        break;
+      case StaticUseKind.SUPER_TEAR_OFF:
+      case StaticUseKind.SUPER_FIELD_SET:
+      case StaticUseKind.SUPER_GET:
+      case StaticUseKind.SUPER_SETTER_SET:
+      case StaticUseKind.SUPER_INVOKE:
+      case StaticUseKind.INSTANCE_FIELD_GET:
+      case StaticUseKind.INSTANCE_FIELD_SET:
+      case StaticUseKind.FIELD_INIT:
+      case StaticUseKind.FIELD_CONSTANT_INIT:
+        // These static uses are not relevant for this algorithm.
+        break;
+      case StaticUseKind.CALL_METHOD:
+      case StaticUseKind.INLINING:
+        failedAt(parent, "Unexpected static use: $staticUse.");
+        break;
+    }
+  }
+
+  void _addFromTypeUse(MemberEntity parent, TypeUse typeUse) {
+    void addClassIfInterfaceType(DartType t, [ImportEntity import]) {
+      var typeWithoutNullability = t.withoutNullability;
+      if (typeWithoutNullability is InterfaceType) {
+        addClass(typeWithoutNullability.element, import: import);
+      }
+    }
+
+    DartType type = typeUse.type;
+    switch (typeUse.kind) {
+      case TypeUseKind.TYPE_LITERAL:
+        addTypeDependencies(type, typeUse.deferredImport);
+        break;
+      case TypeUseKind.CONST_INSTANTIATION:
+        addClassIfInterfaceType(type, typeUse.deferredImport);
+        addTypeDependencies(type, typeUse.deferredImport);
+        break;
+      case TypeUseKind.INSTANTIATION:
+      case TypeUseKind.NATIVE_INSTANTIATION:
+        addClassIfInterfaceType(type);
+        addTypeDependencies(type);
+        break;
+      case TypeUseKind.IS_CHECK:
+      case TypeUseKind.CATCH_TYPE:
+        addTypeDependencies(type);
+        break;
+      case TypeUseKind.AS_CAST:
+        if (closedWorld.annotationsData
+            .getExplicitCastCheckPolicy(parent)
+            .isEmitted) {
+          addTypeDependencies(type);
+        }
+        break;
+      case TypeUseKind.IMPLICIT_CAST:
+        if (closedWorld.annotationsData
+            .getImplicitDowncastCheckPolicy(parent)
+            .isEmitted) {
+          addTypeDependencies(type);
+        }
+        break;
+      case TypeUseKind.PARAMETER_CHECK:
+      case TypeUseKind.TYPE_VARIABLE_BOUND_CHECK:
+        if (closedWorld.annotationsData
+            .getParameterCheckPolicy(parent)
+            .isEmitted) {
+          addTypeDependencies(type);
+        }
+        break;
+      case TypeUseKind.RTI_VALUE:
+      case TypeUseKind.TYPE_ARGUMENT:
+      case TypeUseKind.NAMED_TYPE_VARIABLE_NEW_RTI:
+      case TypeUseKind.CONSTRUCTOR_REFERENCE:
+        failedAt(parent, "Unexpected type use: $typeUse.");
+        break;
+    }
+  }
+
+  /// Extract any dependencies that are known from the impact of [element].
+  void _addDependenciesFromImpact(MemberEntity element) {
+    WorldImpact worldImpact = impactCache[element];
+    impactStrategy.visitImpact(
+        element,
+        worldImpact,
+        WorldImpactVisitorImpl(
+            visitStaticUse: (MemberEntity member, StaticUse staticUse) {
+          _addFromStaticUse(element, staticUse);
+        }, visitTypeUse: (MemberEntity member, TypeUse typeUse) {
+          _addFromTypeUse(element, typeUse);
+        }, visitDynamicUse: (MemberEntity member, DynamicUse dynamicUse) {
+          // TODO(johnniwinther): Use rti need data to skip unneeded type
+          // arguments.
+          addTypeListDependencies(dynamicUse.typeArguments);
+        }),
+        DeferredLoadTask.IMPACT_USE);
+  }
+}
+
+/// Collects the necessary [EntityDataInfo] for a given [EntityData].
+class EntityDataInfoVisitor extends EntityDataVisitor {
+  final EntityDataInfoBuilder infoBuilder;
+
+  EntityDataInfoVisitor(this.infoBuilder);
+
+  KClosedWorld get closedWorld => infoBuilder.closedWorld;
+  KElementEnvironment get elementEnvironment =>
+      infoBuilder.compiler.frontendStrategy.elementEnvironment;
+
+  /// Finds all elements and constants that [element] depends directly on.
+  /// (not the transitive closure.)
+  ///
+  /// Adds the results to [elements] and [constants].
+  @override
+  void visitClassEntityData(ClassEntity element) {
+    // If we see a class, add everything its live instance members refer
+    // to.  Static members are not relevant, unless we are processing
+    // extra dependencies due to mirrors.
+    void addLiveInstanceMember(MemberEntity member) {
+      if (!closedWorld.isMemberUsed(member)) return;
+      if (!member.isInstanceMember) return;
+      infoBuilder.addMember(member);
+      infoBuilder.addDirectMemberDependencies(member);
+    }
+
+    void addClassAndMaybeAddEffectiveMixinClass(ClassEntity cls) {
+      infoBuilder.addClass(cls);
+      if (elementEnvironment.isMixinApplication(cls)) {
+        infoBuilder.addClass(elementEnvironment.getEffectiveMixinClass(cls));
+      }
+    }
+
+    ClassEntity cls = element;
+    elementEnvironment.forEachLocalClassMember(cls, addLiveInstanceMember);
+    elementEnvironment.forEachSupertype(cls, (InterfaceType type) {
+      infoBuilder.addTypeDependencies(type);
+    });
+    elementEnvironment.forEachSuperClass(cls, (superClass) {
+      addClassAndMaybeAddEffectiveMixinClass(superClass);
+      infoBuilder
+          .addTypeDependencies(elementEnvironment.getThisType(superClass));
+    });
+    addClassAndMaybeAddEffectiveMixinClass(cls);
+  }
+
+  @override
+  void visitClassTypeEntityData(ClassEntity element) {
+    infoBuilder.addClassType(element);
+  }
+
+  /// Finds all elements and constants that [element] depends directly on.
+  /// (not the transitive closure.)
+  ///
+  /// Adds the results to [elements] and [constants].
+  @override
+  void visitMemberEntityData(MemberEntity element) {
+    if (element is FunctionEntity) {
+      infoBuilder
+          .addTypeDependencies(elementEnvironment.getFunctionType(element));
+    }
+    if (element.isStatic || element.isTopLevel || element.isConstructor) {
+      infoBuilder.addMember(element);
+      infoBuilder.addDirectMemberDependencies(element);
+    }
+    if (element is ConstructorEntity && element.isGenerativeConstructor) {
+      // When instantiating a class, we record a reference to the
+      // constructor, not the class itself.  We must add all the
+      // instance members of the constructor's class.
+      ClassEntity cls = element.enclosingClass;
+      visitClassEntityData(cls);
+    }
+
+    // Other elements, in particular instance members, are ignored as
+    // they are processed as part of the class.
+  }
+
+  @override
+  void visitConstantEntityData(ConstantValue constant) {
+    if (constant is ConstructedConstantValue) {
+      infoBuilder.addClass(constant.type.element);
+    }
+    if (constant is InstantiationConstantValue) {
+      for (DartType type in constant.typeArguments) {
+        type = type.withoutNullability;
+        if (type is InterfaceType) {
+          infoBuilder.addClass(type.element);
+        }
+      }
+    }
+
+    // Constants are not allowed to refer to deferred constants, so
+    // no need to check for a deferred type literal here.
+    constant.getDependencies().forEach(infoBuilder.addConstant);
+  }
+}
+
+class TypeEntityDataVisitor implements DartTypeVisitor<void, Null> {
+  final EntityDataInfoBuilder _infoBuilder;
+  final ImportEntity _import;
+  final CommonElements _commonElements;
+
+  TypeEntityDataVisitor(this._infoBuilder, this._import, this._commonElements);
+
+  @override
+  void visit(DartType type, [_]) {
+    type.accept(this, null);
+  }
+
+  void visitList(List<DartType> types) {
+    types.forEach(visit);
+  }
+
+  @override
+  void visitLegacyType(LegacyType type, Null argument) {
+    visit(type.baseType);
+  }
+
+  @override
+  void visitNullableType(NullableType type, Null argument) {
+    visit(type.baseType);
+  }
+
+  @override
+  void visitFutureOrType(FutureOrType type, Null argument) {
+    _infoBuilder.addClassType(_commonElements.futureClass);
+    visit(type.typeArgument);
+  }
+
+  @override
+  void visitNeverType(NeverType type, Null argument) {
+    // Nothing to add.
+  }
+
+  @override
+  void visitDynamicType(DynamicType type, Null argument) {
+    // Nothing to add.
+  }
+
+  @override
+  void visitErasedType(ErasedType type, Null argument) {
+    // Nothing to add.
+  }
+
+  @override
+  void visitAnyType(AnyType type, Null argument) {
+    // Nothing to add.
+  }
+
+  @override
+  void visitInterfaceType(InterfaceType type, Null argument) {
+    visitList(type.typeArguments);
+    _infoBuilder.addClassType(type.element, import: _import);
+  }
+
+  @override
+  void visitFunctionType(FunctionType type, Null argument) {
+    for (FunctionTypeVariable typeVariable in type.typeVariables) {
+      visit(typeVariable.bound);
+    }
+    visitList(type.parameterTypes);
+    visitList(type.optionalParameterTypes);
+    visitList(type.namedParameterTypes);
+    visit(type.returnType);
+  }
+
+  @override
+  void visitFunctionTypeVariable(FunctionTypeVariable type, Null argument) {
+    // Nothing to add. Handled in [visitFunctionType].
+  }
+
+  @override
+  void visitTypeVariableType(TypeVariableType type, Null argument) {
+    // TODO(johnniwinther): Do we need to collect the bound?
+  }
+
+  @override
+  void visitVoidType(VoidType type, Null argument) {
+    // Nothing to add.
+  }
+}
+
+class ConstantCollector extends ir.RecursiveVisitor {
+  final KernelToElementMap elementMap;
+  final EntityDataInfoBuilder infoBuilder;
+  final ir.StaticTypeContext staticTypeContext;
+
+  ConstantCollector(this.elementMap, this.staticTypeContext, this.infoBuilder);
+
+  CommonElements get commonElements => elementMap.commonElements;
+
+  /// Extract the set of constants that are used in the body of [member].
+  static void collect(KernelToElementMap elementMap, MemberEntity member,
+      EntityDataInfoBuilder infoBuilder) {
+    ir.Member node = elementMap.getMemberNode(member);
+
+    // Fetch the internal node in order to skip annotations on the member.
+    // TODO(sigmund): replace this pattern when the kernel-ast provides a better
+    // way to skip annotations (issue 31565).
+    var visitor = ConstantCollector(
+        elementMap, elementMap.getStaticTypeContext(member), infoBuilder);
+    if (node is ir.Field) {
+      node.initializer?.accept(visitor);
+      return;
+    }
+
+    if (node is ir.Constructor) {
+      node.initializers.forEach((i) => i.accept(visitor));
+    }
+    node.function?.accept(visitor);
+  }
+
+  void add(ir.Expression node, {bool required = true}) {
+    ConstantValue constant = elementMap
+        .getConstantValue(staticTypeContext, node, requireConstant: required);
+    if (constant != null) {
+      infoBuilder.addConstant(constant,
+          import: elementMap.getImport(getDeferredImport(node)));
+    }
+  }
+
+  @override
+  void visitIntLiteral(ir.IntLiteral literal) {}
+
+  @override
+  void visitDoubleLiteral(ir.DoubleLiteral literal) {}
+
+  @override
+  void visitBoolLiteral(ir.BoolLiteral literal) {}
+
+  @override
+  void visitStringLiteral(ir.StringLiteral literal) {}
+
+  @override
+  void visitSymbolLiteral(ir.SymbolLiteral literal) => add(literal);
+
+  @override
+  void visitNullLiteral(ir.NullLiteral literal) {}
+
+  @override
+  void visitListLiteral(ir.ListLiteral literal) {
+    if (literal.isConst) {
+      add(literal);
+    } else {
+      super.visitListLiteral(literal);
+    }
+  }
+
+  @override
+  void visitSetLiteral(ir.SetLiteral literal) {
+    if (literal.isConst) {
+      add(literal);
+    } else {
+      super.visitSetLiteral(literal);
+    }
+  }
+
+  @override
+  void visitMapLiteral(ir.MapLiteral literal) {
+    if (literal.isConst) {
+      add(literal);
+    } else {
+      super.visitMapLiteral(literal);
+    }
+  }
+
+  @override
+  void visitConstructorInvocation(ir.ConstructorInvocation node) {
+    if (node.isConst) {
+      add(node);
+    } else {
+      super.visitConstructorInvocation(node);
+    }
+  }
+
+  @override
+  void visitTypeParameter(ir.TypeParameter node) {
+    // We avoid visiting metadata on the type parameter declaration. The bound
+    // cannot hold constants so we skip that as well.
+  }
+
+  @override
+  void visitVariableDeclaration(ir.VariableDeclaration node) {
+    // We avoid visiting metadata on the parameter declaration by only visiting
+    // the initializer. The type cannot hold constants so can kan skip that
+    // as well.
+    node.initializer?.accept(this);
+  }
+
+  @override
+  void visitTypeLiteral(ir.TypeLiteral node) {
+    if (node.type is! ir.TypeParameterType) add(node);
+  }
+
+  @override
+  void visitInstantiation(ir.Instantiation node) {
+    // TODO(johnniwinther): The CFE should mark constant instantiations as
+    // constant.
+    add(node, required: false);
+    super.visitInstantiation(node);
+  }
+
+  @override
+  void visitConstantExpression(ir.ConstantExpression node) {
+    add(node);
+  }
+}
diff --git a/pkg/compiler/lib/src/deferred_load/output_unit.dart b/pkg/compiler/lib/src/deferred_load/output_unit.dart
index 1b9f93a..17daef0 100644
--- a/pkg/compiler/lib/src/deferred_load/output_unit.dart
+++ b/pkg/compiler/lib/src/deferred_load/output_unit.dart
@@ -6,9 +6,7 @@
 
 import '../common.dart';
 import '../constants/values.dart'
-    show
-        ConstantValue,
-        DeferredGlobalConstantValue;
+    show ConstantValue, DeferredGlobalConstantValue;
 import '../elements/entities.dart';
 import '../serialization/serialization.dart';
 import '../options.dart';
diff --git a/pkg/compiler/lib/src/deferred_load/work_queue.dart b/pkg/compiler/lib/src/deferred_load/work_queue.dart
index 42adfbc..90bf329 100644
--- a/pkg/compiler/lib/src/deferred_load/work_queue.dart
+++ b/pkg/compiler/lib/src/deferred_load/work_queue.dart
@@ -2,30 +2,30 @@
 // 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.
 
-part of deferred_load;
+import 'dart:collection' show Queue;
 
-/// The deferred_load algorithm work queue.
+import 'algorithm_state.dart';
+import 'entity_data.dart';
+import 'import_set.dart';
+
+import '../elements/entities.dart';
+
+/// The entity_data_state work queue.
 class WorkQueue {
   /// The actual queue of work that needs to be done.
   final Queue<WorkItem> queue = Queue();
 
-  /// An index to find work items in the queue corresponding to a class.
-  final Map<ClassEntity, WorkItem> pendingClasses = {};
-
-  /// An index to find work items in the queue corresponding to an
-  /// [InterfaceType] represented here by its [ClassEntitiy].
-  final Map<ClassEntity, WorkItem> pendingClassType = {};
-
-  /// An index to find work items in the queue corresponding to a member.
-  final Map<MemberEntity, WorkItem> pendingMembers = {};
-
-  /// An index to find work items in the queue corresponding to a constant.
-  final Map<ConstantValue, WorkItem> pendingConstants = {};
+  /// An index to find work items in the queue corresponding to a given
+  /// [EntityData].
+  final Map<EntityData, WorkItem> pendingWorkItems = {};
 
   /// Lattice used to compute unions of [ImportSet]s.
   final ImportSetLattice _importSets;
 
-  WorkQueue(this._importSets);
+  /// Registry used to create [EntityData].
+  final EntityDataRegistry _registry;
+
+  WorkQueue(this._importSets, this._registry);
 
   /// Whether there are no more work items in the queue.
   bool get isNotEmpty => queue.isNotEmpty;
@@ -40,66 +40,40 @@
   /// in [importSet]. If there is already a work item in the queue for
   /// [element], this makes sure that the work item now includes the union of
   /// [importSet] and the existing work item's import set.
-  void addClass(ClassEntity element, ImportSet importSet) {
-    var item = pendingClasses[element];
+  void addEntityData(EntityData entityData, ImportSet importSet) {
+    var item = pendingWorkItems[entityData];
     if (item == null) {
-      item = ClassWorkItem(element, importSet);
-      pendingClasses[element] = item;
+      item = WorkItem(entityData, importSet);
+      pendingWorkItems[entityData] = item;
       queue.add(item);
     } else {
       item.importsToAdd = _importSets.union(item.importsToAdd, importSet);
     }
   }
 
-  /// Add to the queue that class type (represented by [element]) should be
-  /// updated to include all imports in [importSet]. If there is already a
-  /// work item in the queue for [element], this makes sure that the work
-  /// item now includes the union of [importSet] and the existing work
-  /// item's import set.
-  void addClassType(ClassEntity element, ImportSet importSet) {
-    var item = pendingClassType[element];
-    if (item == null) {
-      item = ClassTypeWorkItem(element, importSet);
-      pendingClassType[element] = item;
-      queue.add(item);
-    } else {
-      item.importsToAdd = _importSets.union(item.importsToAdd, importSet);
-    }
+  void addMember(MemberEntity member, ImportSet importSet) {
+    addEntityData(_registry.createMemberEntityData(member), importSet);
   }
 
-  /// Add to the queue that [element] should be updated to include all imports
-  /// in [importSet]. If there is already a work item in the queue for
-  /// [element], this makes sure that the work item now includes the union of
-  /// [importSet] and the existing work item's import set.
-  void addMember(MemberEntity element, ImportSet importSet) {
-    var item = pendingMembers[element];
-    if (item == null) {
-      item = MemberWorkItem(element, importSet);
-      pendingMembers[element] = item;
-      queue.add(item);
-    } else {
-      item.importsToAdd = _importSets.union(item.importsToAdd, importSet);
-    }
+  void addClass(ClassEntity cls, ImportSet importSet) {
+    addEntityData(_registry.createClassEntityData(cls), importSet);
   }
 
-  /// Add to the queue that [constant] should be updated to include all imports
-  /// in [importSet]. If there is already a work item in the queue for
-  /// [constant], this makes sure that the work item now includes the union of
-  /// [importSet] and the existing work item's import set.
-  void addConstant(ConstantValue constant, ImportSet importSet) {
-    var item = pendingConstants[constant];
-    if (item == null) {
-      item = ConstantWorkItem(constant, importSet);
-      pendingConstants[constant] = item;
-      queue.add(item);
-    } else {
-      item.importsToAdd = _importSets.union(item.importsToAdd, importSet);
-    }
+  /// Processes the next item in the queue.
+  void processNextItem(AlgorithmState state) {
+    var item = nextItem();
+    var entityData = item.entityData;
+    pendingWorkItems.remove(entityData);
+    ImportSet oldSet = state.entityToSet[entityData];
+    ImportSet newSet = _importSets.union(oldSet, item.importsToAdd);
+    state.update(entityData, oldSet, newSet);
   }
 }
 
 /// Summary of the work that needs to be done on a class, member, or constant.
-abstract class WorkItem {
+class WorkItem {
+  final EntityData entityData;
+
   /// Additional imports that use [element] or [value] and need to be added by
   /// the algorithm.
   ///
@@ -108,75 +82,5 @@
   /// [WorkQueue.addConstant]).
   ImportSet importsToAdd;
 
-  WorkItem(this.importsToAdd);
-
-  void update(DeferredLoadTask task, KClosedWorld closedWorld, WorkQueue queue);
-}
-
-/// Summary of the work that needs to be done on a class.
-class ClassWorkItem extends WorkItem {
-  /// Class to be recursively updated.
-  final ClassEntity cls;
-
-  ClassWorkItem(this.cls, ImportSet newSet) : super(newSet);
-
-  @override
-  void update(
-      DeferredLoadTask task, KClosedWorld closedWorld, WorkQueue queue) {
-    queue.pendingClasses.remove(cls);
-    ImportSet oldSet = task._classToSet[cls];
-    ImportSet newSet = task.importSets.union(oldSet, importsToAdd);
-    task._updateClassRecursive(closedWorld, cls, oldSet, newSet, queue);
-  }
-}
-
-/// Summary of the work that needs to be done on a class.
-class ClassTypeWorkItem extends WorkItem {
-  /// Class to be recursively updated.
-  final ClassEntity cls;
-
-  ClassTypeWorkItem(this.cls, ImportSet newSet) : super(newSet);
-
-  @override
-  void update(
-      DeferredLoadTask task, KClosedWorld closedWorld, WorkQueue queue) {
-    queue.pendingClassType.remove(cls);
-    ImportSet oldSet = task._classTypeToSet[cls];
-    ImportSet newSet = task.importSets.union(oldSet, importsToAdd);
-    task._updateClassTypeRecursive(closedWorld, cls, oldSet, newSet, queue);
-  }
-}
-
-/// Summary of the work that needs to be done on a member.
-class MemberWorkItem extends WorkItem {
-  /// Member to be recursively updated.
-  final MemberEntity member;
-
-  MemberWorkItem(this.member, ImportSet newSet) : super(newSet);
-
-  @override
-  void update(
-      DeferredLoadTask task, KClosedWorld closedWorld, WorkQueue queue) {
-    queue.pendingMembers.remove(member);
-    ImportSet oldSet = task._memberToSet[member];
-    ImportSet newSet = task.importSets.union(oldSet, importsToAdd);
-    task._updateMemberRecursive(closedWorld, member, oldSet, newSet, queue);
-  }
-}
-
-/// Summary of the work that needs to be done on a constant.
-class ConstantWorkItem extends WorkItem {
-  /// Constant to be recursively updated.
-  final ConstantValue constant;
-
-  ConstantWorkItem(this.constant, ImportSet newSet) : super(newSet);
-
-  @override
-  void update(
-      DeferredLoadTask task, KClosedWorld closedWorld, WorkQueue queue) {
-    queue.pendingConstants.remove(constant);
-    ImportSet oldSet = task._constantToSet[constant];
-    ImportSet newSet = task.importSets.union(oldSet, importsToAdd);
-    task._updateConstantRecursive(closedWorld, constant, oldSet, newSet, queue);
-  }
+  WorkItem(this.entityData, this.importsToAdd);
 }
diff --git a/pkg/compiler/test/deferred/not_in_main_test.dart b/pkg/compiler/test/deferred/not_in_main_test.dart
index 11e92a3..d3e13bd 100644
--- a/pkg/compiler/test/deferred/not_in_main_test.dart
+++ b/pkg/compiler/test/deferred/not_in_main_test.dart
@@ -110,7 +110,7 @@
   dynamic shared = lookupLibrary("memory:shared.dart");
   var a = env.lookupClass(shared, "A");
   Expect.equals(
-      "OutputUnit(1, {import(def2: deferred), import(def3: deferred)})",
+      "OutputUnit(4, {import(def2: deferred), import(def3: deferred)})",
       outputUnitForClass(a).toString());
   Expect.equals(
       "OutputUnit(2, {import(def1: deferred), "
diff --git a/pkg/compiler/test/deferred_loading/data/deferred_overlapping/deferred_overlapping_lib3.dart b/pkg/compiler/test/deferred_loading/data/deferred_overlapping/deferred_overlapping_lib3.dart
index 55ced68..34b9387 100644
--- a/pkg/compiler/test/deferred_loading/data/deferred_overlapping/deferred_overlapping_lib3.dart
+++ b/pkg/compiler/test/deferred_loading/data/deferred_overlapping/deferred_overlapping_lib3.dart
@@ -5,8 +5,8 @@
 // @dart = 2.7
 
 /*class: C3:
- class_unit=1{lib1, lib2},
- type_unit=1{lib1, lib2}
+ class_unit=2{lib1, lib2},
+ type_unit=2{lib1, lib2}
 */
-/*member: C3.:member_unit=1{lib1, lib2}*/
+/*member: C3.:member_unit=2{lib1, lib2}*/
 class C3 {}
diff --git a/pkg/compiler/test/deferred_loading/data/deferred_overlapping/lib1.dart b/pkg/compiler/test/deferred_loading/data/deferred_overlapping/lib1.dart
index ca698b0..39babb0 100644
--- a/pkg/compiler/test/deferred_loading/data/deferred_overlapping/lib1.dart
+++ b/pkg/compiler/test/deferred_loading/data/deferred_overlapping/lib1.dart
@@ -7,8 +7,8 @@
 import "deferred_overlapping_lib3.dart";
 
 /*class: C1:
- class_unit=2{lib1},
- type_unit=2{lib1}
+ class_unit=1{lib1},
+ type_unit=1{lib1}
 */
-/*member: C1.:member_unit=2{lib1}*/
+/*member: C1.:member_unit=1{lib1}*/
 class C1 extends C3 {}
diff --git a/pkg/compiler/test/deferred_loading/data/deferred_overlapping/main.dart b/pkg/compiler/test/deferred_loading/data/deferred_overlapping/main.dart
index 11062ba..acd021d 100644
--- a/pkg/compiler/test/deferred_loading/data/deferred_overlapping/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/deferred_overlapping/main.dart
@@ -4,13 +4,13 @@
 
 /*spec.library: 
  a_pre_fragments=[
-  p1: {units: [2{lib1}], usedBy: [], needs: []},
+  p1: {units: [1{lib1}], usedBy: [], needs: []},
   p2: {units: [3{lib2}], usedBy: [], needs: []},
-  p3: {units: [1{lib1, lib2}], usedBy: [], needs: []}],
+  p3: {units: [2{lib1, lib2}], usedBy: [], needs: []}],
  b_finalized_fragments=[
-  f1: [2{lib1}],
+  f1: [1{lib1}],
   f2: [3{lib2}],
-  f3: [1{lib1, lib2}]],
+  f3: [2{lib1, lib2}]],
  c_steps=[
   lib1=(f3, f1),
   lib2=(f3, f2)]
@@ -18,13 +18,13 @@
 
 /*two-frag|three-frag.library: 
  a_pre_fragments=[
-  p1: {units: [2{lib1}], usedBy: [p3], needs: []},
+  p1: {units: [1{lib1}], usedBy: [p3], needs: []},
   p2: {units: [3{lib2}], usedBy: [p3], needs: []},
-  p3: {units: [1{lib1, lib2}], usedBy: [], needs: [p1, p2]}],
+  p3: {units: [2{lib1, lib2}], usedBy: [], needs: [p1, p2]}],
  b_finalized_fragments=[
-  f1: [2{lib1}],
+  f1: [1{lib1}],
   f2: [3{lib2}],
-  f3: [1{lib1, lib2}]],
+  f3: [2{lib1, lib2}]],
  c_steps=[
   lib1=(f3, f1),
   lib2=(f3, f2)]
diff --git a/pkg/compiler/test/deferred_loading/data/instantiation2/lib1.dart b/pkg/compiler/test/deferred_loading/data/instantiation2/lib1.dart
index 50dde94..59fba08 100644
--- a/pkg/compiler/test/deferred_loading/data/instantiation2/lib1.dart
+++ b/pkg/compiler/test/deferred_loading/data/instantiation2/lib1.dart
@@ -4,14 +4,14 @@
 
 // @dart = 2.7
 
-/*member: getFoo:member_unit=2{b}*/
+/*member: getFoo:member_unit=1{b}*/
 T getFoo<T>(T v) => v;
 
 typedef dynamic G<T>(T v);
 
 /*member: m:
- constants=[InstantiationConstant([int*],FunctionConstant(getFoo))=2{b}],
- member_unit=2{b}
+ constants=[InstantiationConstant([int*],FunctionConstant(getFoo))=1{b}],
+ member_unit=1{b}
 */
 m(int x, {G<int> f: getFoo}) {
   print(f(x));
diff --git a/pkg/compiler/test/deferred_loading/data/instantiation2/main.dart b/pkg/compiler/test/deferred_loading/data/instantiation2/main.dart
index 66b862e..bf10d09 100644
--- a/pkg/compiler/test/deferred_loading/data/instantiation2/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/instantiation2/main.dart
@@ -4,13 +4,13 @@
 
 /*spec.library: 
  a_pre_fragments=[
-  p1: {units: [2{b}], usedBy: [], needs: []},
+  p1: {units: [1{b}], usedBy: [], needs: []},
   p2: {units: [3{c}], usedBy: [], needs: []},
-  p3: {units: [1{b, c}], usedBy: [], needs: []}],
+  p3: {units: [2{b, c}], usedBy: [], needs: []}],
  b_finalized_fragments=[
-  f1: [2{b}],
+  f1: [1{b}],
   f2: [3{c}],
-  f3: [1{b, c}]],
+  f3: [2{b, c}]],
  c_steps=[
   b=(f3, f1),
   c=(f3, f2)]
@@ -18,13 +18,13 @@
 
 /*two-frag|three-frag.library: 
  a_pre_fragments=[
-  p1: {units: [2{b}], usedBy: [p3], needs: []},
+  p1: {units: [1{b}], usedBy: [p3], needs: []},
   p2: {units: [3{c}], usedBy: [p3], needs: []},
-  p3: {units: [1{b, c}], usedBy: [], needs: [p1, p2]}],
+  p3: {units: [2{b, c}], usedBy: [], needs: [p1, p2]}],
  b_finalized_fragments=[
-  f1: [2{b}],
+  f1: [1{b}],
   f2: [3{c}],
-  f3: [1{b, c}]],
+  f3: [2{b, c}]],
  c_steps=[
   b=(f3, f1),
   c=(f3, f2)]
@@ -35,8 +35,14 @@
 // Test instantiations with the same type argument count used only in two
 // deferred libraries.
 
-/*class: global#Instantiation:class_unit=1{b, c},type_unit=1{b, c}*/
-/*class: global#Instantiation1:class_unit=1{b, c},type_unit=1{b, c}*/
+/*class: global#Instantiation:
+ class_unit=2{b, c},
+ type_unit=2{b, c}
+*/
+/*class: global#Instantiation1:
+ class_unit=2{b, c},
+ type_unit=2{b, c}
+*/
 
 import 'lib1.dart' deferred as b;
 import 'lib2.dart' deferred as c;
diff --git a/pkg/compiler/test/deferred_loading/data/instantiation5/lib1.dart b/pkg/compiler/test/deferred_loading/data/instantiation5/lib1.dart
index 506a6b3..a211ccb 100644
--- a/pkg/compiler/test/deferred_loading/data/instantiation5/lib1.dart
+++ b/pkg/compiler/test/deferred_loading/data/instantiation5/lib1.dart
@@ -4,14 +4,14 @@
 
 // @dart = 2.7
 
-/*member: getFoo:member_unit=2{b}*/
+/*member: getFoo:member_unit=1{b}*/
 T getFoo<T>(T v) => v;
 
 typedef dynamic G<T>(T v);
 
 /*member: m:
- constants=[InstantiationConstant([int*],FunctionConstant(getFoo))=2{b}],
- member_unit=2{b}
+ constants=[InstantiationConstant([int*],FunctionConstant(getFoo))=1{b}],
+ member_unit=1{b}
 */
 m(int x, {G<int> f}) {
   f ??= getFoo;
diff --git a/pkg/compiler/test/deferred_loading/data/instantiation5/main.dart b/pkg/compiler/test/deferred_loading/data/instantiation5/main.dart
index 2150985..0ba4442 100644
--- a/pkg/compiler/test/deferred_loading/data/instantiation5/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/instantiation5/main.dart
@@ -4,13 +4,13 @@
 
 /*spec.library: 
  a_pre_fragments=[
-  p1: {units: [2{b}], usedBy: [], needs: []},
+  p1: {units: [1{b}], usedBy: [], needs: []},
   p2: {units: [3{c}], usedBy: [], needs: []},
-  p3: {units: [1{b, c}], usedBy: [], needs: []}],
+  p3: {units: [2{b, c}], usedBy: [], needs: []}],
  b_finalized_fragments=[
-  f1: [2{b}],
+  f1: [1{b}],
   f2: [3{c}],
-  f3: [1{b, c}]],
+  f3: [2{b, c}]],
  c_steps=[
   b=(f3, f1),
   c=(f3, f2)]
@@ -18,13 +18,13 @@
 
 /*two-frag|three-frag.library: 
  a_pre_fragments=[
-  p1: {units: [2{b}], usedBy: [p3], needs: []},
+  p1: {units: [1{b}], usedBy: [p3], needs: []},
   p2: {units: [3{c}], usedBy: [p3], needs: []},
-  p3: {units: [1{b, c}], usedBy: [], needs: [p1, p2]}],
+  p3: {units: [2{b, c}], usedBy: [], needs: [p1, p2]}],
  b_finalized_fragments=[
-  f1: [2{b}],
+  f1: [1{b}],
   f2: [3{c}],
-  f3: [1{b, c}]],
+  f3: [2{b, c}]],
  c_steps=[
   b=(f3, f1),
   c=(f3, f2)]
@@ -35,10 +35,16 @@
 // Test instantiations with the same type argument count used only in two
 // deferred libraries.
 
-/*class: global#Instantiation:class_unit=1{b, c},type_unit=1{b, c}*/
-/*class: global#Instantiation1:class_unit=1{b, c},type_unit=1{b, c}*/
+/*class: global#Instantiation:
+ class_unit=2{b, c},
+ type_unit=2{b, c}
+*/
+/*class: global#Instantiation1:
+ class_unit=2{b, c},
+ type_unit=2{b, c}
+*/
 
-/*member: global#instantiate1:member_unit=1{b, c}*/
+/*member: global#instantiate1:member_unit=2{b, c}*/
 
 import 'lib1.dart' deferred as b;
 import 'lib2.dart' deferred as c;
diff --git a/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart b/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart
index 22064c8..d797b5b 100644
--- a/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart
+++ b/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart
@@ -5,28 +5,28 @@
 // @dart = 2.7
 
 /*class: Foo:
- class_unit=1{libB},
- type_unit=3{libA, libB, libC}
+ class_unit=4{libB},
+ type_unit=2{libA, libB, libC}
 */
 class Foo {
-  /*member: Foo.x:member_unit=1{libB}*/
+  /*member: Foo.x:member_unit=4{libB}*/
   int x;
-  /*member: Foo.:member_unit=1{libB}*/
+  /*member: Foo.:member_unit=4{libB}*/
   Foo() {
     x = DateTime.now().millisecond;
   }
-  /*member: Foo.method:member_unit=1{libB}*/
+  /*member: Foo.method:member_unit=4{libB}*/
   @pragma('dart2js:noInline')
   int method() => x;
 }
 
-/*member: isFoo:member_unit=3{libA, libB, libC}*/
+/*member: isFoo:member_unit=2{libA, libB, libC}*/
 @pragma('dart2js:noInline')
 bool isFoo(o) {
   return o is Foo;
 }
 
-/*member: callFooMethod:member_unit=1{libB}*/
+/*member: callFooMethod:member_unit=4{libB}*/
 @pragma('dart2js:noInline')
 int callFooMethod() {
   return Foo().method();
@@ -35,7 +35,7 @@
 typedef int FunFoo(Foo a);
 typedef int FunFunFoo(FunFoo b, int c);
 
-/*member: isFunFunFoo:member_unit=3{libA, libB, libC}*/
+/*member: isFunFunFoo:member_unit=2{libA, libB, libC}*/
 @pragma('dart2js:noInline')
 bool isFunFunFoo(o) {
   return o is FunFunFoo;
@@ -43,88 +43,88 @@
 
 /*class: Aoo:
  class_unit=none,
- type_unit=2{libC}
+ type_unit=6{libC}
 */
 class Aoo<T> {}
 
 /*class: Boo:
- class_unit=2{libC},
- type_unit=2{libC}
+ class_unit=6{libC},
+ type_unit=6{libC}
 */
 class Boo<T> implements Aoo<T> {}
 
 /*class: Coo:
- class_unit=2{libC},
- type_unit=2{libC}
+ class_unit=6{libC},
+ type_unit=6{libC}
 */
-/*member: Coo.:member_unit=2{libC}*/
+/*member: Coo.:member_unit=6{libC}*/
 class Coo<T> {}
 
 /*class: Doo:
- class_unit=2{libC},
+ class_unit=6{libC},
  type_unit=5{libB, libC}
 */
-/*member: Doo.:member_unit=2{libC}*/
+/*member: Doo.:member_unit=6{libC}*/
 class Doo<T> extends Coo<T> with Boo<T> {}
 
-/*member: createDooFunFunFoo:member_unit=2{libC}*/
+/*member: createDooFunFunFoo:member_unit=6{libC}*/
 @pragma('dart2js:noInline')
 createDooFunFunFoo() => Doo<FunFunFoo>();
 
 /*class: B:
- class_unit=2{libC},
- type_unit=2{libC}
+ class_unit=6{libC},
+ type_unit=6{libC}
 */
-/*member: B.:member_unit=2{libC}*/
+/*member: B.:member_unit=6{libC}*/
 class B {}
 
 /*class: B2:
- class_unit=2{libC},
- type_unit=4{libA, libC}
+ class_unit=6{libC},
+ type_unit=3{libA, libC}
 */
-/*member: B2.:member_unit=2{libC}*/
+/*member: B2.:member_unit=6{libC}*/
 class B2 extends B {}
 
 /*class: C1:
- class_unit=2{libC},
- type_unit=2{libC}
+ class_unit=6{libC},
+ type_unit=6{libC}
 */
 class C1 {}
 
 /*class: C2:
- class_unit=2{libC},
- type_unit=2{libC}
+ class_unit=6{libC},
+ type_unit=6{libC}
 */
-/*member: C2.:member_unit=2{libC}*/
+/*member: C2.:member_unit=6{libC}*/
 class C2 {}
 
 /*class: C3:
- class_unit=2{libC},
- type_unit=4{libA, libC}
+ class_unit=6{libC},
+ type_unit=3{libA, libC}
 */
-/*member: C3.:member_unit=2{libC}*/
+/*member: C3.:member_unit=6{libC}*/
 class C3 extends C2 with C1 {}
 
 /*class: D1:
- class_unit=2{libC},
- type_unit=2{libC}
+ class_unit=6{libC},
+ type_unit=6{libC}
 */
 class D1 {}
 
 /*class: D2:
- class_unit=2{libC},
- type_unit=2{libC}
+ class_unit=6{libC},
+ type_unit=6{libC}
 */
-/*member: D2.:member_unit=2{libC}*/
+/*member: D2.:member_unit=6{libC}*/
 class D2 {}
 
 /*class: D3:
- class_unit=2{libC},
- type_unit=4{libA, libC}
+ class_unit=6{libC},
+ type_unit=3{libA, libC}
 */
 class D3 = D2 with D1;
 
-/*member: isMega:member_unit=6{libA}*/
+/*member: isMega:member_unit=1{libA}*/
 @pragma('dart2js:noInline')
 bool isMega(o) {
   return o is B2 || o is C3 || o is D3;
diff --git a/pkg/compiler/test/deferred_loading/data/lazy_types/liba.dart b/pkg/compiler/test/deferred_loading/data/lazy_types/liba.dart
index 447ec58..072f8fc 100644
--- a/pkg/compiler/test/deferred_loading/data/lazy_types/liba.dart
+++ b/pkg/compiler/test/deferred_loading/data/lazy_types/liba.dart
@@ -6,11 +6,11 @@
 
 import 'lib.dart' as lib;
 
-/*member: isFoo:member_unit=6{libA}*/
+/*member: isFoo:member_unit=1{libA}*/
 bool isFoo(o) => lib.isFoo(o);
 
-/*member: isFunFunFoo:member_unit=6{libA}*/
+/*member: isFunFunFoo:member_unit=1{libA}*/
 bool isFunFunFoo(o) => lib.isFunFunFoo(o);
 
-/*member: isMega:member_unit=6{libA}*/
+/*member: isMega:member_unit=1{libA}*/
 bool isMega(o) => lib.isMega(o);
diff --git a/pkg/compiler/test/deferred_loading/data/lazy_types/libb.dart b/pkg/compiler/test/deferred_loading/data/lazy_types/libb.dart
index 20c2423..fffb803 100644
--- a/pkg/compiler/test/deferred_loading/data/lazy_types/libb.dart
+++ b/pkg/compiler/test/deferred_loading/data/lazy_types/libb.dart
@@ -6,14 +6,14 @@
 
 import 'lib.dart' as lib;
 
-/*member: callFooMethod:member_unit=1{libB}*/
+/*member: callFooMethod:member_unit=4{libB}*/
 int callFooMethod() => lib.callFooMethod();
 
-/*member: isFoo:member_unit=1{libB}*/
+/*member: isFoo:member_unit=4{libB}*/
 bool isFoo(o) => lib.isFoo(o);
 
-/*member: isFunFunFoo:member_unit=1{libB}*/
+/*member: isFunFunFoo:member_unit=4{libB}*/
 bool isFunFunFoo(o) => lib.isFunFunFoo(o);
 
-/*member: isDooFunFunFoo:member_unit=1{libB}*/
+/*member: isDooFunFunFoo:member_unit=4{libB}*/
 bool isDooFunFunFoo(o) => o is lib.Doo<lib.FunFunFoo>;
diff --git a/pkg/compiler/test/deferred_loading/data/lazy_types/libc.dart b/pkg/compiler/test/deferred_loading/data/lazy_types/libc.dart
index ddc592e..a9a20f2 100644
--- a/pkg/compiler/test/deferred_loading/data/lazy_types/libc.dart
+++ b/pkg/compiler/test/deferred_loading/data/lazy_types/libc.dart
@@ -6,20 +6,20 @@
 
 import 'lib.dart' as lib;
 
-/*member: isFoo:member_unit=2{libC}*/
+/*member: isFoo:member_unit=6{libC}*/
 bool isFoo(o) => lib.isFoo(o);
 
-/*member: isFunFunFoo:member_unit=2{libC}*/
+/*member: isFunFunFoo:member_unit=6{libC}*/
 bool isFunFunFoo(o) => lib.isFunFunFoo(o);
 
-/*member: createB2:member_unit=2{libC}*/
+/*member: createB2:member_unit=6{libC}*/
 createB2() => new lib.B2();
 
-/*member: createC3:member_unit=2{libC}*/
+/*member: createC3:member_unit=6{libC}*/
 createC3() => new lib.C3();
 
-/*member: createD3:member_unit=2{libC}*/
+/*member: createD3:member_unit=6{libC}*/
 createD3() => new lib.D3();
 
-/*member: createDooFunFunFoo:member_unit=2{libC}*/
+/*member: createDooFunFunFoo:member_unit=6{libC}*/
 createDooFunFunFoo() => lib.createDooFunFunFoo();
diff --git a/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart b/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart
index 0c00e5e..8ed7162 100644
--- a/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart
@@ -4,17 +4,17 @@
 
 /*spec.library: 
  a_pre_fragments=[
-  p1: {units: [6{libA}], usedBy: [], needs: []},
-  p2: {units: [1{libB}], usedBy: [], needs: []},
-  p3: {units: [2{libC}], usedBy: [], needs: []},
-  p4: {units: [4{libA, libC}], usedBy: [], needs: []},
+  p1: {units: [1{libA}], usedBy: [], needs: []},
+  p2: {units: [4{libB}], usedBy: [], needs: []},
+  p3: {units: [6{libC}], usedBy: [], needs: []},
+  p4: {units: [3{libA, libC}], usedBy: [], needs: []},
   p5: {units: [5{libB, libC}], usedBy: [], needs: []},
-  p6: {units: [3{libA, libB, libC}], usedBy: [], needs: []}],
+  p6: {units: [2{libA, libB, libC}], usedBy: [], needs: []}],
  b_finalized_fragments=[
-  f1: [6{libA}],
-  f2: [1{libB}],
-  f3: [2{libC}],
-  f6: [3{libA, libB, libC}]],
+  f1: [1{libA}],
+  f2: [4{libB}],
+  f3: [6{libC}],
+  f6: [2{libA, libB, libC}]],
  c_steps=[
   libA=(f6, f1),
   libB=(f6, f2),
@@ -23,13 +23,13 @@
 
 /*two-frag.library: 
  a_pre_fragments=[
-  p1: {units: [1{libB}, 6{libA}], usedBy: [p2, p3], needs: []},
-  p2: {units: [4{libA, libC}, 2{libC}], usedBy: [p3], needs: [p1]},
-  p3: {units: [3{libA, libB, libC}, 5{libB, libC}], usedBy: [], needs: [p2, p1]}],
+  p1: {units: [4{libB}, 1{libA}], usedBy: [p2, p3], needs: []},
+  p2: {units: [3{libA, libC}, 6{libC}], usedBy: [p3], needs: [p1]},
+  p3: {units: [2{libA, libB, libC}, 5{libB, libC}], usedBy: [], needs: [p2, p1]}],
  b_finalized_fragments=[
-  f1: [1{libB}, 6{libA}],
-  f2: [2{libC}],
-  f3: [3{libA, libB, libC}]],
+  f1: [4{libB}, 1{libA}],
+  f2: [6{libC}],
+  f3: [2{libA, libB, libC}]],
  c_steps=[
   libA=(f3, f1),
   libB=(f3, f1),
@@ -38,15 +38,15 @@
 
 /*three-frag.library: 
  a_pre_fragments=[
-  p1: {units: [6{libA}], usedBy: [p4], needs: []},
-  p2: {units: [1{libB}], usedBy: [p4], needs: []},
-  p3: {units: [2{libC}], usedBy: [p4], needs: []},
-  p4: {units: [3{libA, libB, libC}, 5{libB, libC}, 4{libA, libC}], usedBy: [], needs: [p3, p2, p1]}],
+  p1: {units: [1{libA}], usedBy: [p4], needs: []},
+  p2: {units: [4{libB}], usedBy: [p4], needs: []},
+  p3: {units: [6{libC}], usedBy: [p4], needs: []},
+  p4: {units: [2{libA, libB, libC}, 5{libB, libC}, 3{libA, libC}], usedBy: [], needs: [p3, p2, p1]}],
  b_finalized_fragments=[
-  f1: [6{libA}],
-  f2: [1{libB}],
-  f3: [2{libC}],
-  f4: [3{libA, libB, libC}]],
+  f1: [1{libA}],
+  f2: [4{libB}],
+  f3: [6{libC}],
+  f4: [2{libA, libB, libC}]],
  c_steps=[
   libA=(f4, f1),
   libB=(f4, f2),
@@ -61,19 +61,19 @@
 
 /*member: foo:
  constants=[
-  FunctionConstant(callFooMethod)=1{libB},
-  FunctionConstant(createB2)=2{libC},
-  FunctionConstant(createC3)=2{libC},
-  FunctionConstant(createD3)=2{libC},
-  FunctionConstant(createDooFunFunFoo)=2{libC},
-  FunctionConstant(isDooFunFunFoo)=1{libB},
-  FunctionConstant(isFoo)=1{libB},
-  FunctionConstant(isFoo)=2{libC},
-  FunctionConstant(isFoo)=6{libA},
-  FunctionConstant(isFunFunFoo)=1{libB},
-  FunctionConstant(isFunFunFoo)=2{libC},
-  FunctionConstant(isFunFunFoo)=6{libA},
-  FunctionConstant(isMega)=6{libA}],
+  FunctionConstant(callFooMethod)=4{libB},
+  FunctionConstant(createB2)=6{libC},
+  FunctionConstant(createC3)=6{libC},
+  FunctionConstant(createD3)=6{libC},
+  FunctionConstant(createDooFunFunFoo)=6{libC},
+  FunctionConstant(isDooFunFunFoo)=4{libB},
+  FunctionConstant(isFoo)=1{libA},
+  FunctionConstant(isFoo)=4{libB},
+  FunctionConstant(isFoo)=6{libC},
+  FunctionConstant(isFunFunFoo)=1{libA},
+  FunctionConstant(isFunFunFoo)=4{libB},
+  FunctionConstant(isFunFunFoo)=6{libC},
+  FunctionConstant(isMega)=1{libA}],
  member_unit=main{}
 */
 void foo() async {
diff --git a/pkg/compiler/test/deferred_loading/data/many_parts/libB.dart b/pkg/compiler/test/deferred_loading/data/many_parts/libB.dart
index 7f86fc1..8fa7f8e 100644
--- a/pkg/compiler/test/deferred_loading/data/many_parts/libB.dart
+++ b/pkg/compiler/test/deferred_loading/data/many_parts/libB.dart
@@ -4,14 +4,14 @@
 
 import "package:expect/expect.dart";
 
-/*member: v:member_unit=1{b1, b2, b3, b4, b5}*/
+/*member: v:member_unit=2{b1, b2, b3, b4, b5}*/
 void v(Set<String> u, String name, int bit) {
   Expect.isTrue(u.add(name));
   Expect.equals(name[bit], '1');
 }
 
 @pragma('dart2js:noInline')
-/*member: f_000_01:member_unit=2{b1}*/
+/*member: f_000_01:member_unit=1{b1}*/
 f_000_01(Set<String> u, int b) => v(u, '00001', b);
 
 @pragma('dart2js:noInline')
@@ -71,7 +71,7 @@
 f_111_01(Set<String> u, int b) => v(u, '11101', b);
 
 @pragma('dart2js:noInline')
-/*member: f_111_11:member_unit=1{b1, b2, b3, b4, b5}*/
+/*member: f_111_11:member_unit=2{b1, b2, b3, b4, b5}*/
 f_111_11(Set<String> u, int b) => v(u, '11111', b);
 
 @pragma('dart2js:noInline')
diff --git a/pkg/compiler/test/deferred_loading/data/many_parts/lib_000_01.dart b/pkg/compiler/test/deferred_loading/data/many_parts/lib_000_01.dart
index 94e3cf7..bb1e6d9 100644
--- a/pkg/compiler/test/deferred_loading/data/many_parts/lib_000_01.dart
+++ b/pkg/compiler/test/deferred_loading/data/many_parts/lib_000_01.dart
@@ -7,7 +7,7 @@
 import 'libB.dart';
 
 @pragma('dart2js:noInline')
-/*member: g_000_01:member_unit=2{b1}*/
+/*member: g_000_01:member_unit=1{b1}*/
 g_000_01() {
   Set<String> uniques = {};
 
diff --git a/pkg/compiler/test/deferred_loading/data/many_parts/main.dart b/pkg/compiler/test/deferred_loading/data/many_parts/main.dart
index cbb56aa..ab6a217 100644
--- a/pkg/compiler/test/deferred_loading/data/many_parts/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/many_parts/main.dart
@@ -14,7 +14,7 @@
   p17: {units: [7{b1, b2, b4}], usedBy: [], needs: []},
   p18: {units: [11{b1, b2, b5}], usedBy: [], needs: []},
   p19: {units: [8{b1, b3, b4}], usedBy: [], needs: []},
-  p1: {units: [2{b1}], usedBy: [], needs: []},
+  p1: {units: [1{b1}], usedBy: [], needs: []},
   p20: {units: [12{b1, b3, b5}], usedBy: [], needs: []},
   p21: {units: [14{b1, b4, b5}], usedBy: [], needs: []},
   p22: {units: [20{b2, b3, b4}], usedBy: [], needs: []},
@@ -27,7 +27,7 @@
   p29: {units: [16{b1, b3, b4, b5}], usedBy: [], needs: []},
   p2: {units: [17{b2}], usedBy: [], needs: []},
   p30: {units: [24{b2, b3, b4, b5}], usedBy: [], needs: []},
-  p31: {units: [1{b1, b2, b3, b4, b5}], usedBy: [], needs: []},
+  p31: {units: [2{b1, b2, b3, b4, b5}], usedBy: [], needs: []},
   p3: {units: [25{b3}], usedBy: [], needs: []},
   p4: {units: [29{b4}], usedBy: [], needs: []},
   p5: {units: [31{b5}], usedBy: [], needs: []},
@@ -46,7 +46,7 @@
   f17: [7{b1, b2, b4}],
   f18: [11{b1, b2, b5}],
   f19: [8{b1, b3, b4}],
-  f1: [2{b1}],
+  f1: [1{b1}],
   f20: [12{b1, b3, b5}],
   f21: [14{b1, b4, b5}],
   f22: [20{b2, b3, b4}],
@@ -59,7 +59,7 @@
   f29: [16{b1, b3, b4, b5}],
   f2: [17{b2}],
   f30: [24{b2, b3, b4, b5}],
-  f31: [1{b1, b2, b3, b4, b5}],
+  f31: [2{b1, b2, b3, b4, b5}],
   f3: [25{b3}],
   f4: [29{b4}],
   f5: [31{b5}],
@@ -77,15 +77,15 @@
 
 /*three-frag.library: 
  a_pre_fragments=[
-  p1: {units: [26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 2{b1}], usedBy: [p2], needs: []},
+  p1: {units: [26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 1{b1}], usedBy: [p2], needs: []},
   p2: {units: [9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}, 12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}], usedBy: [p4, p3], needs: [p1]},
   p3: {units: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}], usedBy: [p4], needs: [p2]},
-  p4: {units: [1{b1, b2, b3, b4, b5}], usedBy: [], needs: [p2, p3]}],
+  p4: {units: [2{b1, b2, b3, b4, b5}], usedBy: [], needs: [p2, p3]}],
  b_finalized_fragments=[
-  f1: [26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 2{b1}],
+  f1: [26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 1{b1}],
   f2: [9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}, 12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}],
   f3: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}],
-  f4: [1{b1, b2, b3, b4, b5}]],
+  f4: [2{b1, b2, b3, b4, b5}]],
  c_steps=[
   b1=(f4, f3, f2, f1),
   b2=(f4, f3, f2, f1),
@@ -96,13 +96,13 @@
 
 /*two-frag.library: 
  a_pre_fragments=[
-  p1: {units: [12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}, 26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 2{b1}], usedBy: [p2], needs: []},
+  p1: {units: [12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}, 26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 1{b1}], usedBy: [p2], needs: []},
   p2: {units: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}, 9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}], usedBy: [p3], needs: [p1]},
-  p3: {units: [1{b1, b2, b3, b4, b5}], usedBy: [], needs: [p2]}],
+  p3: {units: [2{b1, b2, b3, b4, b5}], usedBy: [], needs: [p2]}],
  b_finalized_fragments=[
-  f1: [12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}, 26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 2{b1}],
+  f1: [12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}, 26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 1{b1}],
   f2: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}, 9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}],
-  f3: [1{b1, b2, b3, b4, b5}]],
+  f3: [2{b1, b2, b3, b4, b5}]],
  c_steps=[
   b1=(f3, f2, f1),
   b2=(f3, f2, f1),
diff --git a/pkg/compiler/test/deferred_loading/data/type_arguments/lib3.dart b/pkg/compiler/test/deferred_loading/data/type_arguments/lib3.dart
index 9b56057..3147280 100644
--- a/pkg/compiler/test/deferred_loading/data/type_arguments/lib3.dart
+++ b/pkg/compiler/test/deferred_loading/data/type_arguments/lib3.dart
@@ -5,8 +5,8 @@
 // @dart = 2.7
 
 /*class: E:
- class_unit=2{lib3},
- type_unit=2{lib3}
+ class_unit=3{lib3},
+ type_unit=3{lib3}
 */
 class E<T> {
   const E();
@@ -14,7 +14,7 @@
 
 /*class: F:
  class_unit=none,
- type_unit=3{lib1, lib3}
+ type_unit=2{lib1, lib3}
 */
 class F {}
 
diff --git a/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart b/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart
index 6703cb1..86f5ed6 100644
--- a/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart
@@ -5,11 +5,11 @@
 /*spec.library: 
  a_pre_fragments=[
   p1: {units: [1{lib1}], usedBy: [], needs: []},
-  p2: {units: [2{lib3}], usedBy: [], needs: []},
-  p3: {units: [3{lib1, lib3}], usedBy: [], needs: []}],
+  p2: {units: [3{lib3}], usedBy: [], needs: []},
+  p3: {units: [2{lib1, lib3}], usedBy: [], needs: []}],
  b_finalized_fragments=[
   f1: [1{lib1}],
-  f2: [2{lib3}]],
+  f2: [3{lib3}]],
  c_steps=[
   lib1=(f1),
   lib3=(f2)]
@@ -18,11 +18,11 @@
 /*two-frag|three-frag.library: 
  a_pre_fragments=[
   p1: {units: [1{lib1}], usedBy: [p3], needs: []},
-  p2: {units: [2{lib3}], usedBy: [p3], needs: []},
-  p3: {units: [3{lib1, lib3}], usedBy: [], needs: [p1, p2]}],
+  p2: {units: [3{lib3}], usedBy: [p3], needs: []},
+  p3: {units: [2{lib1, lib3}], usedBy: [], needs: [p1, p2]}],
  b_finalized_fragments=[
   f1: [1{lib1}],
-  f2: [2{lib3}]],
+  f2: [3{lib3}]],
  c_steps=[
   lib1=(f1),
   lib3=(f2)]
@@ -39,7 +39,7 @@
   ConstructedConstant(A<B*>())=1{lib1},
   ConstructedConstant(A<F*>())=1{lib1},
   ConstructedConstant(C<D*>())=main{},
-  ConstructedConstant(E<F*>())=2{lib3}],
+  ConstructedConstant(E<F*>())=3{lib3}],
  member_unit=main{}
 */
 main() async {
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 00061db..5d21abf 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1972,6 +1972,7 @@
 
 DART_EXPORT Dart_Handle Dart_RunLoop() {
   Isolate* I;
+  bool result;
   {
     Thread* T = Thread::Current();
     I = T->isolate();
@@ -1988,14 +1989,21 @@
     RunLoopData data;
     data.monitor = &monitor;
     data.done = false;
-    I->message_handler()->Run(I->group()->thread_pool(), NULL, RunLoopDone,
-                              reinterpret_cast<uword>(&data));
-    while (!data.done) {
-      ml.Wait();
+    result =
+        I->message_handler()->Run(I->group()->thread_pool(), NULL, RunLoopDone,
+                                  reinterpret_cast<uword>(&data));
+    if (result) {
+      while (!data.done) {
+        ml.Wait();
+      }
     }
   }
   ::Dart_EnterIsolate(Api::CastIsolate(I));
-  if (I->sticky_error() != Object::null()) {
+  if (!result) {
+    Thread* T = Thread::Current();
+    TransitionNativeToVM transition(T);
+    return Api::NewError("Run method in isolate message handler failed");
+  } else if (I->sticky_error() != Object::null()) {
     Thread* T = Thread::Current();
     TransitionNativeToVM transition(T);
     return Api::NewHandle(T, I->StealStickyError());
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 5b0bc2b..fc1877f 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -9396,9 +9396,10 @@
         ml.Notify();
       }
       count++;
+    } else {
+      free(error);
     }
   } while (count < 100);
-  free(error);
 }
 
 TEST_CASE(DartAPI_InvokeVMServiceMethod_Loop) {
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index 066c7d4..5d41659 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -436,7 +436,6 @@
                                  false)),
         next_(NULL),
         prev_(NULL) {
-    ASSERT(port_ != ILLEGAL_PORT);
     RegisterRequest(this);
     result_.status = Dart_KernelCompilationStatus_Unknown;
     result_.error = NULL;
@@ -446,7 +445,9 @@
 
   ~KernelCompilationRequest() {
     UnregisterRequest(this);
-    Dart_CloseNativePort(port_);
+    if (port_ != ILLEGAL_PORT) {
+      Dart_CloseNativePort(port_);
+    }
   }
 
   intptr_t setDillData(Dart_CObject** dills_array,
@@ -481,6 +482,13 @@
       char const* klass,
       bool is_static,
       const MallocGrowableArray<char*>* experimental_flags) {
+    if (port_ == ILLEGAL_PORT) {
+      Dart_KernelCompilationResult result = {};
+      result.status = Dart_KernelCompilationStatus_Unknown;
+      result.error =
+          Utils::StrDup("Error Kernel Isolate : unable to create reply port");
+      return result;
+    }
     Thread* thread = Thread::Current();
     TransitionNativeToVM transition(thread);
     Dart_CObject tag;
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index 28a89a2..bbb8211 100644
--- a/runtime/vm/message_handler.cc
+++ b/runtime/vm/message_handler.cc
@@ -100,7 +100,7 @@
   // By default, there is no custom message notification.
 }
 
-void MessageHandler::Run(ThreadPool* pool,
+bool MessageHandler::Run(ThreadPool* pool,
                          StartCallback start_callback,
                          EndCallback end_callback,
                          CallbackData data) {
@@ -118,8 +118,15 @@
   end_callback_ = end_callback;
   callback_data_ = data;
   task_running_ = true;
-  const bool launched_successfully = pool_->Run<MessageHandlerTask>(this);
-  ASSERT(launched_successfully);
+  bool result = pool_->Run<MessageHandlerTask>(this);
+  if (!result) {
+    pool_ = nullptr;
+    start_callback_ = nullptr;
+    end_callback_ = nullptr;
+    callback_data_ = 0;
+    task_running_ = false;
+  }
+  return result;
 }
 
 void MessageHandler::PostMessage(std::unique_ptr<Message> message,
diff --git a/runtime/vm/message_handler.h b/runtime/vm/message_handler.h
index 19b5101..715641b 100644
--- a/runtime/vm/message_handler.h
+++ b/runtime/vm/message_handler.h
@@ -48,7 +48,10 @@
   // no longer has any live ports.  Abnormal termination occurs when
   // HandleMessage() indicates that an error has occurred during
   // message processing.
-  void Run(ThreadPool* pool,
+
+  // Returns false if the handler terminated abnormally, otherwise it
+  // returns true.
+  bool Run(ThreadPool* pool,
            StartCallback start_callback,
            EndCallback end_callback,
            CallbackData data);
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 07a2fec..793accb 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -90,8 +90,13 @@
 
   NativeMessageHandler* nmh = new NativeMessageHandler(name, handler);
   Dart_Port port_id = PortMap::CreatePort(nmh);
-  PortMap::SetPortState(port_id, PortMap::kLivePort);
-  nmh->Run(Dart::thread_pool(), NULL, NULL, 0);
+  if (port_id != ILLEGAL_PORT) {
+    PortMap::SetPortState(port_id, PortMap::kLivePort);
+    if (!nmh->Run(Dart::thread_pool(), NULL, NULL, 0)) {
+      PortMap::ClosePort(port_id);
+      port_id = ILLEGAL_PORT;
+    }
+  }
   Dart::ResetActiveApiCall();
   return port_id;
 }
diff --git a/tools/VERSION b/tools/VERSION
index 79b34c1..2fc2c05 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 28
+PRERELEASE 29
 PRERELEASE_PATCH 0
\ No newline at end of file