Decouple HNode from TypeMask

Change-Id: Ie13d928d51ad7e080ad13402bed3c974da66a2c4
Reviewed-on: https://dart-review.googlesource.com/54020
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/native/ssa.dart b/pkg/compiler/lib/src/native/ssa.dart
index 5fc3b5d..240df64 100644
--- a/pkg/compiler/lib/src/native/ssa.dart
+++ b/pkg/compiler/lib/src/native/ssa.dart
@@ -101,7 +101,7 @@
         effects: new SideEffects()));
     // TODO(johnniwinther): Provide source information.
     builder
-        .close(new HReturn(builder.pop(), null))
+        .close(new HReturn(builder.abstractValueDomain, builder.pop(), null))
         .addSuccessor(builder.graph.exit);
   } else {
     if (parameters.parameterCount != 0) {
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 9224019..a18d29f 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -727,8 +727,8 @@
       push(invokeJsInteropFunction(functionElement, parameters.values.toList(),
           sourceInformationBuilder.buildGeneric(function)));
       var value = pop();
-      closeAndGotoExit(new HReturn(
-          value, sourceInformationBuilder.buildReturn(functionElement.node)));
+      closeAndGotoExit(new HReturn(abstractValueDomain, value,
+          sourceInformationBuilder.buildReturn(functionElement.node)));
       return closeFunction();
     }
     assert(!function.modifiers.isExternal, failedAt(functionElement));
@@ -747,6 +747,7 @@
             },
             visitThen: () {
               closeAndGotoExit(new HReturn(
+                  abstractValueDomain,
                   graph.addConstantBool(false, closedWorld),
                   sourceInformationBuilder
                       .buildImplicitReturn(functionElement)));
@@ -796,7 +797,7 @@
     graph.entry.addBefore(graph.entry.last, parameter);
     HInstruction value = typeBuilder.potentiallyCheckOrTrustTypeOfParameter(
         parameter, field.type);
-    add(new HFieldSet(field, thisInstruction, value));
+    add(new HFieldSet(abstractValueDomain, field, thisInstruction, value));
     return closeFunction();
   }
 
@@ -827,8 +828,8 @@
       }
     }
 
-    closeAndGotoExit(new HReturn(
-        value, sourceInformationBuilder.buildReturn(sourceInfoNode)));
+    closeAndGotoExit(new HReturn(abstractValueDomain, value,
+        sourceInformationBuilder.buildReturn(sourceInfoNode)));
     return closeFunction();
   }
 
@@ -1358,7 +1359,8 @@
       add(new HFieldGet(null, newObject, commonMasks.dynamicType,
           isAssignable: false));
       for (int i = 0; i < fields.length; i++) {
-        add(new HFieldSet(fields[i], newObject, constructorArguments[i]));
+        add(new HFieldSet(abstractValueDomain, fields[i], newObject,
+            constructorArguments[i]));
       }
     }
     removeInlinedInstantiation(type);
@@ -1431,7 +1433,7 @@
       }
     }
     if (inliningStack.isEmpty) {
-      closeAndGotoExit(new HReturn(newObject,
+      closeAndGotoExit(new HReturn(abstractValueDomain, newObject,
           sourceInformationBuilder.buildImplicitReturn(functionElement)));
       return closeFunction();
     } else {
@@ -1466,7 +1468,7 @@
         parameters,
         sourceInformationBuilder.buildDeclaration(element),
         isGenerativeConstructorBody: element.isGenerativeConstructorBody);
-    close(new HGoto()).addSuccessor(block);
+    close(new HGoto(abstractValueDomain)).addSuccessor(block);
 
     open(block);
 
@@ -1598,8 +1600,8 @@
 
   HGraph closeFunction() {
     // TODO(kasperl): Make this goto an implicit return.
-    if (!isAborted()) closeAndGotoExit(new HGoto());
-    graph.finalize();
+    if (!isAborted()) closeAndGotoExit(new HGoto(abstractValueDomain));
+    graph.finalize(abstractValueDomain);
     return graph;
   }
 
@@ -1715,8 +1717,8 @@
     if (throwExpression != null && inliningStack.isEmpty) {
       visitThrowExpression(throwExpression.expression);
       handleInTryStatement();
-      closeAndGotoExit(
-          new HThrow(pop(), sourceInformationBuilder.buildThrow(node)));
+      closeAndGotoExit(new HThrow(abstractValueDomain, pop(),
+          sourceInformationBuilder.buildThrow(node)));
     } else {
       visit(node.expression);
       pop();
@@ -1813,7 +1815,7 @@
     HBasicBlock bodyExitBlock;
     bool isAbortingBody = false;
     if (current != null) {
-      bodyExitBlock = close(new HGoto());
+      bodyExitBlock = close(new HGoto(abstractValueDomain));
     } else {
       isAbortingBody = true;
       bodyExitBlock = lastOpenedBlock;
@@ -1858,13 +1860,13 @@
       visit(node.condition);
       assert(!isAborted());
       HInstruction conditionInstruction = popBoolified();
-      HBasicBlock conditionEndBlock = close(
-          new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP));
+      HBasicBlock conditionEndBlock = close(new HLoopBranch(abstractValueDomain,
+          conditionInstruction, HLoopBranch.DO_WHILE_LOOP));
 
       HBasicBlock avoidCriticalEdge = addNewBlock();
       conditionEndBlock.addSuccessor(avoidCriticalEdge);
       open(avoidCriticalEdge);
-      close(new HGoto());
+      close(new HGoto(abstractValueDomain));
       avoidCriticalEdge.addSuccessor(loopEntryBlock); // The back-edge.
 
       conditionExpression =
@@ -1873,7 +1875,7 @@
       // Avoid a critical edge from the condition to the loop-exit body.
       HBasicBlock conditionExitBlock = addNewBlock();
       open(conditionExitBlock);
-      close(new HGoto());
+      close(new HGoto(abstractValueDomain));
       conditionEndBlock.addSuccessor(conditionExitBlock);
 
       loopHandler.endLoop(
@@ -1913,7 +1915,8 @@
         loopEntryBlock.setBlockFlow(info, current);
         jumpHandler.forEachBreak((HBreak breakInstruction, _) {
           HBasicBlock block = breakInstruction.block;
-          block.addAtExit(new HBreak.toLabel(label, sourceInformation));
+          block.addAtExit(new HBreak.toLabel(
+              abstractValueDomain, label, sourceInformation));
           block.remove(breakInstruction);
         });
       }
@@ -2431,7 +2434,8 @@
         FieldElement field = element;
         value = typeBuilder.potentiallyCheckOrTrustTypeOfAssignment(
             value, field.type);
-        addWithPosition(new HStaticStore(field, value), location);
+        addWithPosition(
+            new HStaticStore(abstractValueDomain, field, value), location);
       }
       stack.add(value);
     } else if (Elements.isError(element)) {
@@ -5219,8 +5223,8 @@
       reporter.internalError(node, 'rethrowableException should not be null.');
     }
     handleInTryStatement();
-    closeAndGotoExit(new HThrow(
-        exception, sourceInformationBuilder.buildThrow(node),
+    closeAndGotoExit(new HThrow(abstractValueDomain, exception,
+        sourceInformationBuilder.buildThrow(node),
         isRethrow: true));
   }
 
@@ -5361,8 +5365,8 @@
     visitThrowExpression(node.expression);
     if (isReachable) {
       handleInTryStatement();
-      push(new HThrowExpression(
-          pop(), sourceInformationBuilder.buildThrow(node)));
+      push(new HThrowExpression(abstractValueDomain, pop(),
+          sourceInformationBuilder.buildThrow(node)));
       isReachable = false;
     }
   }
@@ -5370,8 +5374,8 @@
   visitYield(ast.Yield node) {
     visit(node.expression);
     HInstruction yielded = pop();
-    add(new HYield(
-        yielded, node.hasStar, sourceInformationBuilder.buildYield(node)));
+    add(new HYield(abstractValueDomain, yielded, node.hasStar,
+        sourceInformationBuilder.buildYield(node)));
   }
 
   visitAwait(ast.Await node) {
@@ -6218,7 +6222,8 @@
       return;
     }
 
-    HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]);
+    HSwitch switchInstruction =
+        new HSwitch(abstractValueDomain, <HInstruction>[expression]);
     HBasicBlock expressionEnd = close(switchInstruction);
     LocalsHandler savedLocals = localsHandler;
 
@@ -6249,7 +6254,8 @@
         if (caseIterator.hasNext && isReachable) {
           pushInvokeStatic(switchCase, commonElements.fallThroughError, []);
           HInstruction error = pop();
-          closeAndGotoExit(new HThrow(error, error.sourceInformation));
+          closeAndGotoExit(
+              new HThrow(abstractValueDomain, error, error.sourceInformation));
         } else if (!isDefaultCase(switchCase)) {
           // If there is no default, we will add one later to avoid
           // the critical edge. So we generate a break statement to make
@@ -6278,7 +6284,7 @@
       assert(false, failedAt(errorNode, 'Continue cannot target a switch.'));
     });
     if (!isAborted()) {
-      current.close(new HGoto());
+      current.close(new HGoto(abstractValueDomain));
       lastOpenedBlock.addSuccessor(joinBlock);
       caseHandlers.add(localsHandler);
     }
@@ -6288,7 +6294,7 @@
       HBasicBlock defaultCase = addNewBlock();
       expressionEnd.addSuccessor(defaultCase);
       open(defaultCase);
-      close(new HGoto());
+      close(new HGoto(abstractValueDomain));
       defaultCase.addSuccessor(joinBlock);
       caseHandlers.add(savedLocals);
       statements.add(new HSubGraphBlockInformation(
@@ -6341,7 +6347,7 @@
     // variables were used in a non-dominated block.
     LocalsHandler savedLocals = new LocalsHandler.from(localsHandler);
     HBasicBlock enterBlock = openNewBlock();
-    HTry tryInstruction = new HTry();
+    HTry tryInstruction = new HTry(abstractValueDomain);
     close(tryInstruction);
     bool oldInTryStatement = inTryStatement;
     inTryStatement = true;
@@ -6357,7 +6363,7 @@
     // We use a [HExitTry] instead of a [HGoto] for the try block
     // because it will have two successors: the join block, and
     // the finally block.
-    if (!isAborted()) endTryBlock = close(new HExitTry());
+    if (!isAborted()) endTryBlock = close(new HExitTry(abstractValueDomain));
     SubGraph bodyGraph = new SubGraph(startTryBlock, lastOpenedBlock);
 
     SubGraph finallyGraph = null;
@@ -6366,7 +6372,7 @@
     startFinallyBlock = graph.addNewBlock();
     open(startFinallyBlock);
     buildFinally();
-    if (!isAborted()) endFinallyBlock = close(new HGoto());
+    if (!isAborted()) endFinallyBlock = close(new HGoto(abstractValueDomain));
     tryInstruction.finallyBlock = startFinallyBlock;
     finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock);
 
@@ -6431,7 +6437,7 @@
     // in a non-dominated block.
     LocalsHandler savedLocals = new LocalsHandler.from(localsHandler);
     HBasicBlock enterBlock = openNewBlock();
-    HTry tryInstruction = new HTry();
+    HTry tryInstruction = new HTry(abstractValueDomain);
     close(tryInstruction);
     bool oldInTryStatement = inTryStatement;
     inTryStatement = true;
@@ -6449,7 +6455,7 @@
     // We use a [HExitTry] instead of a [HGoto] for the try block
     // because it will have multiple successors: the join block, and
     // the catch or finally block.
-    if (!isAborted()) endTryBlock = close(new HExitTry());
+    if (!isAborted()) endTryBlock = close(new HExitTry(abstractValueDomain));
     SubGraph bodyGraph = new SubGraph(startTryBlock, lastOpenedBlock);
     SubGraph catchGraph = null;
     HLocalValue exception = null;
@@ -6531,7 +6537,8 @@
 
       void visitElse() {
         if (link.isEmpty) {
-          closeAndGotoExit(new HThrow(exception, exception.sourceInformation,
+          closeAndGotoExit(new HThrow(
+              abstractValueDomain, exception, exception.sourceInformation,
               isRethrow: true));
         } else {
           ast.CatchBlock newBlock = link.head;
@@ -6555,7 +6562,7 @@
           visitThen: visitThen,
           visitElse: visitElse,
           sourceInformation: sourceInformationBuilder.buildCatch(firstBlock));
-      if (!isAborted()) endCatchBlock = close(new HGoto());
+      if (!isAborted()) endCatchBlock = close(new HGoto(abstractValueDomain));
 
       rethrowableException = oldRethrowableException;
       tryInstruction.catchBlock = startCatchBlock;
@@ -6568,7 +6575,7 @@
       startFinallyBlock = graph.addNewBlock();
       open(startFinallyBlock);
       visit(node.finallyBlock);
-      if (!isAborted()) endFinallyBlock = close(new HGoto());
+      if (!isAborted()) endFinallyBlock = close(new HGoto(abstractValueDomain));
       tryInstruction.finallyBlock = startFinallyBlock;
       finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock);
     }
@@ -6693,8 +6700,8 @@
 
   void emitReturn(HInstruction value, ast.Node node) {
     if (inliningStack.isEmpty) {
-      closeAndGotoExit(
-          new HReturn(value, sourceInformationBuilder.buildReturn(node)));
+      closeAndGotoExit(new HReturn(abstractValueDomain, value,
+          sourceInformationBuilder.buildReturn(node)));
     } else {
       localsHandler.updateLocal(returnLocal, value);
     }
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 859e6e7..7f0236d 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -323,7 +323,7 @@
       graph.entry.addBefore(graph.entry.last, parameter);
       HInstruction value = typeBuilder.potentiallyCheckOrTrustTypeOfParameter(
           parameter, _getDartTypeIfValid(node.type));
-      add(new HFieldSet(field, thisInstruction, value));
+      add(new HFieldSet(abstractValueDomain, field, thisInstruction, value));
     } else {
       if (node.initializer != null) {
         node.initializer.accept(this);
@@ -336,8 +336,8 @@
         stack.add(graph.addConstantNull(closedWorld));
       }
       HInstruction value = pop();
-      closeAndGotoExit(
-          new HReturn(value, _sourceInformationBuilder.buildReturn(node)));
+      closeAndGotoExit(new HReturn(abstractValueDomain, value,
+          _sourceInformationBuilder.buildReturn(node)));
     }
     closeFunction();
   }
@@ -496,7 +496,8 @@
       add(new HFieldGet(null, newObject, commonMasks.dynamicType,
           isAssignable: false));
       for (int i = 0; i < fields.length; i++) {
-        add(new HFieldSet(fields[i], newObject, constructorArguments[i]));
+        add(new HFieldSet(abstractValueDomain, fields[i], newObject,
+            constructorArguments[i]));
       }
     } else {
       // Create the runtime type information, if needed.
@@ -604,7 +605,8 @@
     }
 
     if (_inliningStack.isEmpty) {
-      closeAndGotoExit(new HReturn(newObject, sourceInformation));
+      closeAndGotoExit(
+          new HReturn(abstractValueDomain, newObject, sourceInformation));
       closeFunction();
     } else {
       localsHandler.updateLocal(_returnLocal, newObject,
@@ -920,8 +922,8 @@
         typeArguments,
         commonMasks.functionType));
     HInstruction value = pop();
-    close(new HReturn(
-            value, _sourceInformationBuilder.buildReturn(originalClosureNode)))
+    close(new HReturn(abstractValueDomain, value,
+            _sourceInformationBuilder.buildReturn(originalClosureNode)))
         .addSuccessor(graph.exit);
 
     closeFunction();
@@ -954,6 +956,7 @@
             },
             visitThen: () {
               closeAndGotoExit(new HReturn(
+                  abstractValueDomain,
                   graph.addConstantBool(false, closedWorld),
                   _sourceInformationBuilder.buildReturn(functionNode)));
             },
@@ -1083,8 +1086,8 @@
       if (targetElement.isSetter) {
         value = graph.addConstantNull(closedWorld);
       }
-      close(new HReturn(
-              value, _sourceInformationBuilder.buildReturn(functionNode)))
+      close(new HReturn(abstractValueDomain, value,
+              _sourceInformationBuilder.buildReturn(functionNode)))
           .addSuccessor(graph.exit);
     }
     // TODO(sra): Handle JS-interop methods.
@@ -1129,7 +1132,7 @@
         parameterMap,
         _sourceInformationBuilder.buildDeclaration(targetElement),
         isGenerativeConstructorBody: targetElement is ConstructorBodyEntity);
-    close(new HGoto()).addSuccessor(block);
+    close(new HGoto(abstractValueDomain)).addSuccessor(block);
 
     open(block);
 
@@ -1144,8 +1147,8 @@
   }
 
   void closeFunction() {
-    if (!isAborted()) closeAndGotoExit(new HGoto());
-    graph.finalize();
+    if (!isAborted()) closeAndGotoExit(new HGoto(abstractValueDomain));
+    graph.finalize(abstractValueDomain);
   }
 
   @override
@@ -1246,7 +1249,8 @@
       handleInTryStatement();
       SourceInformation sourceInformation =
           _sourceInformationBuilder.buildThrow(node.expression);
-      closeAndGotoExit(new HThrow(pop(), sourceInformation));
+      closeAndGotoExit(
+          new HThrow(abstractValueDomain, pop(), sourceInformation));
     } else {
       expression.accept(this);
       pop();
@@ -1713,7 +1717,7 @@
     HBasicBlock bodyExitBlock;
     bool isAbortingBody = false;
     if (current != null) {
-      bodyExitBlock = close(new HGoto());
+      bodyExitBlock = close(new HGoto(abstractValueDomain));
     } else {
       isAbortingBody = true;
       bodyExitBlock = lastOpenedBlock;
@@ -1758,13 +1762,13 @@
       node.condition.accept(this);
       assert(!isAborted());
       HInstruction conditionInstruction = popBoolified();
-      HBasicBlock conditionEndBlock = close(
-          new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP));
+      HBasicBlock conditionEndBlock = close(new HLoopBranch(abstractValueDomain,
+          conditionInstruction, HLoopBranch.DO_WHILE_LOOP));
 
       HBasicBlock avoidCriticalEdge = addNewBlock();
       conditionEndBlock.addSuccessor(avoidCriticalEdge);
       open(avoidCriticalEdge);
-      close(new HGoto());
+      close(new HGoto(abstractValueDomain));
       avoidCriticalEdge.addSuccessor(loopEntryBlock); // The back-edge.
 
       conditionExpression =
@@ -1773,7 +1777,7 @@
       // Avoid a critical edge from the condition to the loop-exit body.
       HBasicBlock conditionExitBlock = addNewBlock();
       open(conditionExitBlock);
-      close(new HGoto());
+      close(new HGoto(abstractValueDomain));
       conditionEndBlock.addSuccessor(conditionExitBlock);
 
       loopHandler.endLoop(
@@ -1813,7 +1817,8 @@
         loopEntryBlock.setBlockFlow(info, current);
         jumpHandler.forEachBreak((HBreak breakInstruction, _) {
           HBasicBlock block = breakInstruction.block;
-          block.addAtExit(new HBreak.toLabel(label, sourceInformation));
+          block.addAtExit(new HBreak.toLabel(
+              abstractValueDomain, label, sourceInformation));
           block.remove(breakInstruction);
         });
       }
@@ -2312,7 +2317,8 @@
       return;
     }
 
-    HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]);
+    HSwitch switchInstruction =
+        new HSwitch(abstractValueDomain, <HInstruction>[expression]);
     HBasicBlock expressionEnd = close(switchInstruction);
     LocalsHandler savedLocals = localsHandler;
 
@@ -2372,7 +2378,7 @@
               'Continue cannot target a switch.'));
     });
     if (!isAborted()) {
-      current.close(new HGoto());
+      current.close(new HGoto(abstractValueDomain));
       lastOpenedBlock.addSuccessor(joinBlock);
       caseHandlers.add(localsHandler);
     }
@@ -2382,7 +2388,7 @@
       HBasicBlock defaultCase = addNewBlock();
       expressionEnd.addSuccessor(defaultCase);
       open(defaultCase);
-      close(new HGoto());
+      close(new HGoto(abstractValueDomain));
       defaultCase.addSuccessor(joinBlock);
       caseHandlers.add(savedLocals);
       statements.add(new HSubGraphBlockInformation(
@@ -2725,6 +2731,7 @@
       pop();
     } else {
       add(new HStaticStore(
+          abstractValueDomain,
           _elementMap.getMember(staticTarget),
           typeBuilder.potentiallyCheckOrTrustTypeOfAssignment(
               value, _getDartTypeIfValid(staticTarget.setterType))));
@@ -4534,7 +4541,7 @@
       SourceInformation sourceInformation =
           _sourceInformationBuilder.buildThrow(node);
       handleInTryStatement();
-      push(new HThrowExpression(pop(), sourceInformation));
+      push(new HThrowExpression(abstractValueDomain, pop(), sourceInformation));
       isReachable = false;
     }
   }
@@ -4551,8 +4558,8 @@
 
   void visitYieldStatement(ir.YieldStatement node) {
     node.expression.accept(this);
-    add(new HYield(
-        pop(), node.isYieldStar, _sourceInformationBuilder.buildYield(node)));
+    add(new HYield(abstractValueDomain, pop(), node.isYieldStar,
+        _sourceInformationBuilder.buildYield(node)));
   }
 
   @override
@@ -4575,7 +4582,9 @@
     handleInTryStatement();
     SourceInformation sourceInformation =
         _sourceInformationBuilder.buildThrow(node);
-    closeAndGotoExit(new HThrow(exception, sourceInformation, isRethrow: true));
+    closeAndGotoExit(new HThrow(
+        abstractValueDomain, exception, sourceInformation,
+        isRethrow: true));
     // ir.Rethrow is an expression so we need to push a value - a constant with
     // no type.
     stack.add(graph.addConstantUnreachable(closedWorld));
@@ -5100,7 +5109,8 @@
 
   void _emitReturn(HInstruction value, SourceInformation sourceInformation) {
     if (_inliningStack.isEmpty) {
-      closeAndGotoExit(new HReturn(value, sourceInformation));
+      closeAndGotoExit(
+          new HReturn(abstractValueDomain, value, sourceInformation));
     } else {
       localsHandler.updateLocal(_returnLocal, value);
     }
@@ -5453,7 +5463,7 @@
   LocalsHandler originalSavedLocals;
 
   TryCatchFinallyBuilder(this.kernelBuilder, this.trySourceInformation) {
-    tryInstruction = new HTry();
+    tryInstruction = new HTry(kernelBuilder.abstractValueDomain);
     originalSavedLocals = new LocalsHandler.from(kernelBuilder.localsHandler);
     enterBlock = kernelBuilder.openNewBlock();
     kernelBuilder.close(tryInstruction);
@@ -5524,7 +5534,8 @@
     kernelBuilder.open(startFinallyBlock);
     buildFinalizer();
     if (!kernelBuilder.isAborted()) {
-      endFinallyBlock = kernelBuilder.close(new HGoto());
+      endFinallyBlock =
+          kernelBuilder.close(new HGoto(kernelBuilder.abstractValueDomain));
     }
     tryInstruction.finallyBlock = startFinallyBlock;
     finallyGraph =
@@ -5536,7 +5547,8 @@
     // because it will have multiple successors: the join block, and
     // the catch or finally block.
     if (!kernelBuilder.isAborted()) {
-      endTryBlock = kernelBuilder.close(new HExitTry());
+      endTryBlock =
+          kernelBuilder.close(new HExitTry(kernelBuilder.abstractValueDomain));
     }
     bodyGraph = new SubGraph(startTryBlock, kernelBuilder.lastOpenedBlock);
   }
@@ -5601,7 +5613,9 @@
     void visitElse() {
       if (catchesIndex >= tryCatch.catches.length) {
         kernelBuilder.closeAndGotoExit(new HThrow(
-            exception, exception.sourceInformation,
+            kernelBuilder.abstractValueDomain,
+            exception,
+            exception.sourceInformation,
             isRethrow: true));
       } else {
         ir.Catch nextCatch = tryCatch.catches[catchesIndex];
@@ -5626,7 +5640,8 @@
         sourceInformation:
             kernelBuilder._sourceInformationBuilder.buildCatch(firstBlock));
     if (!kernelBuilder.isAborted()) {
-      endCatchBlock = kernelBuilder.close(new HGoto());
+      endCatchBlock =
+          kernelBuilder.close(new HGoto(kernelBuilder.abstractValueDomain));
     }
 
     kernelBuilder.rethrowableException = oldRethrowableException;
diff --git a/pkg/compiler/lib/src/ssa/graph_builder.dart b/pkg/compiler/lib/src/ssa/graph_builder.dart
index e13dc3f..4215366 100644
--- a/pkg/compiler/lib/src/ssa/graph_builder.dart
+++ b/pkg/compiler/lib/src/ssa/graph_builder.dart
@@ -202,7 +202,7 @@
   }
 
   void goto(HBasicBlock from, HBasicBlock to) {
-    from.close(new HGoto());
+    from.close(new HGoto(abstractValueDomain));
     from.addSuccessor(to);
   }
 
@@ -275,7 +275,7 @@
   /// specify special successors if we are already in a try/catch/finally block.
   void handleInTryStatement() {
     if (!inTryStatement) return;
-    HBasicBlock block = close(new HExitTry());
+    HBasicBlock block = close(new HExitTry(abstractValueDomain));
     HBasicBlock newBlock = graph.addNewBlock();
     block.addSuccessor(newBlock);
     open(newBlock);
diff --git a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
index b37002d..0ca17d5 100644
--- a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
+++ b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
@@ -139,7 +139,8 @@
         return null;
       }
     }
-    return new HIndexAssign(receiver, index, value, instruction.selector);
+    return new HIndexAssign(closedWorld.abstractValueDomain, receiver, index,
+        value, instruction.selector);
   }
 
   /// Returns [true] if [value] meets the requirements for being stored into
diff --git a/pkg/compiler/lib/src/ssa/jump_handler.dart b/pkg/compiler/lib/src/ssa/jump_handler.dart
index d8dc2ee..3687961 100644
--- a/pkg/compiler/lib/src/ssa/jump_handler.dart
+++ b/pkg/compiler/lib/src/ssa/jump_handler.dart
@@ -88,9 +88,11 @@
       [LabelDefinition label]) {
     HInstruction breakInstruction;
     if (label == null) {
-      breakInstruction = new HBreak(target, sourceInformation);
+      breakInstruction =
+          new HBreak(builder.abstractValueDomain, target, sourceInformation);
     } else {
-      breakInstruction = new HBreak.toLabel(label, sourceInformation);
+      breakInstruction = new HBreak.toLabel(
+          builder.abstractValueDomain, label, sourceInformation);
     }
     LocalsHandler locals = new LocalsHandler.from(builder.localsHandler);
     builder.close(breakInstruction);
@@ -101,9 +103,11 @@
       [LabelDefinition label]) {
     HInstruction continueInstruction;
     if (label == null) {
-      continueInstruction = new HContinue(target, sourceInformation);
+      continueInstruction =
+          new HContinue(builder.abstractValueDomain, target, sourceInformation);
     } else {
-      continueInstruction = new HContinue.toLabel(label, sourceInformation);
+      continueInstruction = new HContinue.toLabel(
+          builder.abstractValueDomain, label, sourceInformation);
       // Switch case continue statements must be handled by the
       // [SwitchCaseJumpHandler].
       assert(!label.target.isSwitchCase);
@@ -171,8 +175,9 @@
       // for a switch statement with continue statements. See
       // [SsaFromAstMixin.buildComplexSwitchStatement] for detail.
 
-      HInstruction breakInstruction =
-          new HBreak(target, sourceInformation, breakSwitchContinueLoop: true);
+      HInstruction breakInstruction = new HBreak(
+          builder.abstractValueDomain, target, sourceInformation,
+          breakSwitchContinueLoop: true);
       LocalsHandler locals = new LocalsHandler.from(builder.localsHandler);
       builder.close(breakInstruction);
       jumps.add(new _JumpHandlerEntry(breakInstruction, locals));
@@ -199,7 +204,7 @@
 
       assert(label.target.labels.contains(label));
       HInstruction continueInstruction =
-          new HContinue(target, sourceInformation);
+          new HContinue(builder.abstractValueDomain, target, sourceInformation);
       LocalsHandler locals = new LocalsHandler.from(builder.localsHandler);
       builder.close(continueInstruction);
       jumps.add(new _JumpHandlerEntry(continueInstruction, locals));
diff --git a/pkg/compiler/lib/src/ssa/locals_handler.dart b/pkg/compiler/lib/src/ssa/locals_handler.dart
index 4922a85..2f3973b 100644
--- a/pkg/compiler/lib/src/ssa/locals_handler.dart
+++ b/pkg/compiler/lib/src/ssa/locals_handler.dart
@@ -443,13 +443,15 @@
       // Inside the closure the box is stored in a closure-field and cannot
       // be accessed directly.
       HInstruction box = readLocal(localBox);
-      builder.add(new HFieldSet(redirect, box, value)
-        ..sourceInformation = sourceInformation);
+      builder.add(
+          new HFieldSet(builder.abstractValueDomain, redirect, box, value)
+            ..sourceInformation = sourceInformation);
     } else {
       assert(_isUsedInTryOrGenerator(local));
       HLocalValue localValue = getLocal(local);
-      builder.add(new HLocalSet(local, localValue, value)
-        ..sourceInformation = sourceInformation);
+      builder.add(
+          new HLocalSet(builder.abstractValueDomain, local, localValue, value)
+            ..sourceInformation = sourceInformation);
     }
   }
 
diff --git a/pkg/compiler/lib/src/ssa/loop_handler.dart b/pkg/compiler/lib/src/ssa/loop_handler.dart
index 4bace0e..89ea833 100644
--- a/pkg/compiler/lib/src/ssa/loop_handler.dart
+++ b/pkg/compiler/lib/src/ssa/loop_handler.dart
@@ -65,8 +65,8 @@
     if (startBlock == null) startBlock = conditionBlock;
 
     HInstruction conditionInstruction = condition();
-    HBasicBlock conditionEndBlock =
-        builder.close(new HLoopBranch(conditionInstruction));
+    HBasicBlock conditionEndBlock = builder.close(
+        new HLoopBranch(builder.abstractValueDomain, conditionInstruction));
     SubExpression conditionExpression =
         new SubExpression(conditionBlock, conditionEndBlock);
 
@@ -85,7 +85,8 @@
 
     SubGraph bodyGraph = new SubGraph(beginBodyBlock, builder.lastOpenedBlock);
     HBasicBlock bodyBlock = builder.current;
-    if (builder.current != null) builder.close(new HGoto());
+    if (builder.current != null)
+      builder.close(new HGoto(builder.abstractValueDomain));
 
     SubExpression updateGraph;
 
@@ -133,7 +134,8 @@
 
       update();
 
-      HBasicBlock updateEndBlock = builder.close(new HGoto());
+      HBasicBlock updateEndBlock =
+          builder.close(new HGoto(builder.abstractValueDomain));
       // The back-edge completing the cycle.
       updateEndBlock.addSuccessor(conditionBlock);
       updateGraph = new SubExpression(updateBlock, updateEndBlock);
@@ -141,7 +143,7 @@
       // Avoid a critical edge from the condition to the loop-exit body.
       HBasicBlock conditionExitBlock = builder.addNewBlock();
       builder.open(conditionExitBlock);
-      builder.close(new HGoto());
+      builder.close(new HGoto(builder.abstractValueDomain));
       conditionEndBlock.addSuccessor(conditionExitBlock);
 
       endLoop(conditionBlock, conditionExitBlock, jumpHandler, savedLocals);
@@ -172,7 +174,7 @@
       // label to the if.
       HBasicBlock elseBlock = builder.addNewBlock();
       builder.open(elseBlock);
-      builder.close(new HGoto());
+      builder.close(new HGoto(builder.abstractValueDomain));
       // Pass the elseBlock as the branchBlock, because that's the block we go
       // to just before leaving the 'loop'.
       endLoop(conditionBlock, elseBlock, jumpHandler, savedLocals);
@@ -184,7 +186,8 @@
       // Remove the [HLoopBranch] instruction and replace it with
       // [HIf].
       HInstruction condition = conditionEndBlock.last.inputs[0];
-      conditionEndBlock.addAtExit(new HIf(condition));
+      conditionEndBlock
+          .addAtExit(new HIf(builder.abstractValueDomain, condition));
       conditionEndBlock.addSuccessor(elseBlock);
       conditionEndBlock.remove(conditionEndBlock.last);
       HIfBlockInformation info = new HIfBlockInformation(
@@ -210,7 +213,8 @@
 
         jumpHandler.forEachBreak((HBreak breakInstruction, _) {
           HBasicBlock block = breakInstruction.block;
-          block.addAtExit(new HBreak.toLabel(label, sourceInformation));
+          block.addAtExit(new HBreak.toLabel(
+              builder.abstractValueDomain, label, sourceInformation));
           block.remove(breakInstruction);
         });
       }
@@ -224,7 +228,8 @@
   /// Also notifies the locals handler that we're entering a loop.
   JumpHandler beginLoopHeader(T node, JumpTarget jumpTarget) {
     assert(!builder.isAborted());
-    HBasicBlock previousBlock = builder.close(new HGoto());
+    HBasicBlock previousBlock =
+        builder.close(new HGoto(builder.abstractValueDomain));
 
     JumpHandler jumpHandler =
         createJumpHandler(node, jumpTarget, isLoopJump: true);
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 984a270..a42c238 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -15,9 +15,7 @@
 import '../js/js.dart' as js;
 import '../js_backend/js_backend.dart';
 import '../native/native.dart' as native;
-import '../types/constants.dart' show computeTypeMask;
 import '../types/abstract_value_domain.dart';
-import '../types/types.dart';
 import '../universe/selector.dart' show Selector;
 import '../universe/side_effects.dart' show SideEffects;
 import '../util/util.dart';
@@ -261,7 +259,8 @@
         // We use `null` as the value for invalid constant expressions.
         constant = const NullConstantValue();
       }
-      TypeMask type = computeTypeMask(closedWorld, constant);
+      AbstractValue type = closedWorld.abstractValueDomain
+          .computeAbstractValueForConstant(constant);
       result = new HConstant.internal(constant, type)
         ..sourceInformation = sourceInformation;
       entry.addAtExit(result);
@@ -318,15 +317,15 @@
     // A constant with an empty type used as the HInstruction of an expression
     // in an unreachable context.
     return addConstant(
-        new SyntheticConstantValue(
-            SyntheticConstantKind.EMPTY_VALUE, const TypeMask.nonNullEmpty()),
+        new SyntheticConstantValue(SyntheticConstantKind.EMPTY_VALUE,
+            closedWorld.abstractValueDomain.emptyType),
         closedWorld);
   }
 
-  void finalize() {
+  void finalize(AbstractValueDomain domain) {
     addBlock(exit);
     exit.open();
-    exit.close(new HExit());
+    exit.close(new HExit(domain));
     assignDominators();
   }
 
@@ -1271,8 +1270,8 @@
       throw 'creating compound check to $type (this = ${this})';
     } else {
       InterfaceType interfaceType = type;
-      TypeMask subtype =
-          new TypeMask.subtype(interfaceType.element, closedWorld);
+      AbstractValue subtype = closedWorld.abstractValueDomain
+          .createNullableSubtype(interfaceType.element);
       return new HTypeConversion(type, kind, subtype, this, sourceInformation);
     }
   }
@@ -1449,12 +1448,12 @@
  * codegen decisions just prior to generating JavaScript.
  */
 abstract class HLateInstruction extends HInstruction {
-  HLateInstruction(List<HInstruction> inputs, TypeMask type)
+  HLateInstruction(List<HInstruction> inputs, AbstractValue type)
       : super(inputs, type);
 }
 
 class HBoolify extends HInstruction {
-  HBoolify(HInstruction value, TypeMask type)
+  HBoolify(HInstruction value, AbstractValue type)
       : super(<HInstruction>[value], type) {
     setUseGvn();
     sourceInformation = value.sourceInformation;
@@ -1514,14 +1513,19 @@
 }
 
 abstract class HConditionalBranch extends HControlFlow {
-  HConditionalBranch(inputs) : super(inputs);
+  HConditionalBranch(AbstractValueDomain domain, List<HInstruction> inputs)
+      : super(domain, inputs);
   HInstruction get condition => inputs[0];
   HBasicBlock get trueBranch => block.successors[0];
   HBasicBlock get falseBranch => block.successors[1];
 }
 
 abstract class HControlFlow extends HInstruction {
-  HControlFlow(inputs) : super(inputs, const TypeMask.nonNullEmpty());
+  HControlFlow(AbstractValueDomain domain, List<HInstruction> inputs)
+      // TODO(johnniwinther): May only expression-like [HInstruction]s should
+      // have an `instructionType`, or statement-like [HInstruction]s should
+      // have a throwing getter.
+      : super(inputs, domain.emptyType);
   bool isControlFlow() => true;
   bool isJsStatement() => true;
 }
@@ -1543,7 +1547,7 @@
   /// the closure class.
   FunctionEntity callMethod;
 
-  HCreate(this.element, List<HInstruction> inputs, TypeMask type,
+  HCreate(this.element, List<HInstruction> inputs, AbstractValue type,
       SourceInformation sourceInformation,
       {this.instantiatedTypes, this.hasRtiInput: false, this.callMethod})
       : super(inputs, type) {
@@ -1564,7 +1568,7 @@
 
 // Allocates a box to hold mutated captured variables.
 class HCreateBox extends HInstruction {
-  HCreateBox(TypeMask type) : super(<HInstruction>[], type);
+  HCreateBox(AbstractValue type) : super(<HInstruction>[], type);
 
   bool isAllocation(AbstractValueDomain domain) => true;
 
@@ -1595,11 +1599,11 @@
 abstract class HInvokeDynamic extends HInvoke {
   final InvokeDynamicSpecializer specializer;
   Selector selector;
-  TypeMask mask;
+  AbstractValue mask;
   MemberEntity element;
 
   HInvokeDynamic(Selector selector, this.mask, this.element,
-      List<HInstruction> inputs, bool isIntercepted, TypeMask type)
+      List<HInstruction> inputs, bool isIntercepted, AbstractValue type)
       : this.selector = selector,
         specializer = isIntercepted
             ? InvokeDynamicSpecializer.lookupSpecializer(selector)
@@ -1638,8 +1642,8 @@
 class HInvokeClosure extends HInvokeDynamic {
   final List<DartType> typeArguments;
 
-  HInvokeClosure(Selector selector, List<HInstruction> inputs, TypeMask type,
-      this.typeArguments)
+  HInvokeClosure(Selector selector, List<HInstruction> inputs,
+      AbstractValue type, this.typeArguments)
       : super(selector, null, null, inputs, false, type) {
     assert(selector.isClosureCall);
     assert(selector.callStructure.typeArgumentCount == typeArguments.length);
@@ -1653,9 +1657,9 @@
 
   HInvokeDynamicMethod(
       Selector selector,
-      TypeMask mask,
+      AbstractValue mask,
       List<HInstruction> inputs,
-      TypeMask type,
+      AbstractValue type,
       this.typeArguments,
       SourceInformation sourceInformation,
       {bool isIntercepted: false})
@@ -1669,8 +1673,13 @@
 }
 
 abstract class HInvokeDynamicField extends HInvokeDynamic {
-  HInvokeDynamicField(Selector selector, TypeMask mask, MemberEntity element,
-      List<HInstruction> inputs, bool isIntercepted, TypeMask type)
+  HInvokeDynamicField(
+      Selector selector,
+      AbstractValue mask,
+      MemberEntity element,
+      List<HInstruction> inputs,
+      bool isIntercepted,
+      AbstractValue type)
       : super(selector, mask, element, inputs, isIntercepted, type);
 
   String toString() => 'invoke dynamic field: selector=$selector, mask=$mask';
@@ -1679,11 +1688,11 @@
 class HInvokeDynamicGetter extends HInvokeDynamicField {
   HInvokeDynamicGetter(
       Selector selector,
-      TypeMask mask,
+      AbstractValue mask,
       MemberEntity element,
       List<HInstruction> inputs,
       bool isIntercepted,
-      TypeMask type,
+      AbstractValue type,
       SourceInformation sourceInformation)
       : super(selector, mask, element, inputs, isIntercepted, type) {
     this.sourceInformation = sourceInformation;
@@ -1705,11 +1714,11 @@
 class HInvokeDynamicSetter extends HInvokeDynamicField {
   HInvokeDynamicSetter(
       Selector selector,
-      TypeMask mask,
+      AbstractValue mask,
       MemberEntity element,
       List<HInstruction> inputs,
       bool isIntercepted,
-      TypeMask type,
+      AbstractValue type,
       SourceInformation sourceInformation)
       : super(selector, mask, element, inputs, isIntercepted, type) {
     this.sourceInformation = sourceInformation;
@@ -1739,7 +1748,7 @@
   List<DartType> instantiatedTypes;
 
   /** The first input must be the target. */
-  HInvokeStatic(this.element, inputs, TypeMask type, this.typeArguments,
+  HInvokeStatic(this.element, inputs, AbstractValue type, this.typeArguments,
       {this.targetCanThrow: true, bool isIntercepted: false})
       : super(inputs, type) {
     isInterceptedCall = isIntercepted;
@@ -1764,7 +1773,7 @@
       this.selector,
       List<HInstruction> inputs,
       bool isIntercepted,
-      TypeMask type,
+      AbstractValue type,
       List<DartType> typeArguments,
       SourceInformation sourceInformation,
       {this.isSetter})
@@ -1802,7 +1811,7 @@
   HInvokeConstructorBody(
       ConstructorBodyEntity element,
       List<HInstruction> inputs,
-      TypeMask type,
+      AbstractValue type,
       SourceInformation sourceInformation)
       : super(element, inputs, type, const <DartType>[]) {
     this.sourceInformation = sourceInformation;
@@ -1815,7 +1824,7 @@
 abstract class HFieldAccess extends HInstruction {
   final FieldEntity element;
 
-  HFieldAccess(this.element, List<HInstruction> inputs, TypeMask type)
+  HFieldAccess(this.element, List<HInstruction> inputs, AbstractValue type)
       : super(inputs, type);
 
   HInstruction get receiver => inputs[0];
@@ -1824,7 +1833,7 @@
 class HFieldGet extends HFieldAccess {
   final bool isAssignable;
 
-  HFieldGet(FieldEntity element, HInstruction receiver, TypeMask type,
+  HFieldGet(FieldEntity element, HInstruction receiver, AbstractValue type,
       {bool isAssignable})
       : this.isAssignable =
             (isAssignable != null) ? isAssignable : element.isAssignable,
@@ -1865,9 +1874,9 @@
 }
 
 class HFieldSet extends HFieldAccess {
-  HFieldSet(FieldEntity element, HInstruction receiver, HInstruction value)
-      : super(element, <HInstruction>[receiver, value],
-            const TypeMask.nonNullEmpty()) {
+  HFieldSet(AbstractValueDomain domain, FieldEntity element,
+      HInstruction receiver, HInstruction value)
+      : super(element, <HInstruction>[receiver, value], domain.emptyType) {
     sideEffects.clearAllSideEffects();
     sideEffects.clearAllDependencies();
     sideEffects.setChangesInstanceProperty();
@@ -1887,7 +1896,8 @@
 
 class HGetLength extends HInstruction {
   final bool isAssignable;
-  HGetLength(HInstruction receiver, TypeMask type, {bool this.isAssignable})
+  HGetLength(HInstruction receiver, AbstractValue type,
+      {bool this.isAssignable})
       : super(<HInstruction>[receiver], type) {
     assert(isAssignable != null);
     sideEffects.clearAllSideEffects();
@@ -1926,7 +1936,7 @@
   final int opKind;
 
   HReadModifyWrite._(this.element, this.jsOp, this.opKind,
-      List<HInstruction> inputs, TypeMask type)
+      List<HInstruction> inputs, AbstractValue type)
       : super(inputs, type) {
     sideEffects.clearAllSideEffects();
     sideEffects.clearAllDependencies();
@@ -1935,16 +1945,16 @@
   }
 
   HReadModifyWrite.assignOp(FieldEntity element, String jsOp,
-      HInstruction receiver, HInstruction operand, TypeMask type)
+      HInstruction receiver, HInstruction operand, AbstractValue type)
       : this._(
             element, jsOp, ASSIGN_OP, <HInstruction>[receiver, operand], type);
 
-  HReadModifyWrite.preOp(
-      FieldEntity element, String jsOp, HInstruction receiver, TypeMask type)
+  HReadModifyWrite.preOp(FieldEntity element, String jsOp,
+      HInstruction receiver, AbstractValue type)
       : this._(element, jsOp, PRE_OP, <HInstruction>[receiver], type);
 
-  HReadModifyWrite.postOp(
-      FieldEntity element, String jsOp, HInstruction receiver, TypeMask type)
+  HReadModifyWrite.postOp(FieldEntity element, String jsOp,
+      HInstruction receiver, AbstractValue type)
       : this._(element, jsOp, POST_OP, <HInstruction>[receiver], type);
 
   HInstruction get receiver => inputs[0];
@@ -1968,7 +1978,7 @@
 abstract class HLocalAccess extends HInstruction {
   final Local variable;
 
-  HLocalAccess(this.variable, List<HInstruction> inputs, TypeMask type)
+  HLocalAccess(this.variable, List<HInstruction> inputs, AbstractValue type)
       : super(inputs, type);
 
   HInstruction get receiver => inputs[0];
@@ -1977,7 +1987,7 @@
 class HLocalGet extends HLocalAccess {
   // No need to use GVN for a [HLocalGet], it is just a local
   // access.
-  HLocalGet(Local variable, HLocalValue local, TypeMask type,
+  HLocalGet(Local variable, HLocalValue local, AbstractValue type,
       SourceInformation sourceInformation)
       : super(variable, <HInstruction>[local], type) {
     this.sourceInformation = sourceInformation;
@@ -1989,9 +1999,9 @@
 }
 
 class HLocalSet extends HLocalAccess {
-  HLocalSet(Local variable, HLocalValue local, HInstruction value)
-      : super(variable, <HInstruction>[local, value],
-            const TypeMask.nonNullEmpty());
+  HLocalSet(AbstractValueDomain domain, Local variable, HLocalValue local,
+      HInstruction value)
+      : super(variable, <HInstruction>[local, value], domain.emptyType);
 
   accept(HVisitor visitor) => visitor.visitLocalSet(this);
 
@@ -2001,7 +2011,7 @@
 }
 
 abstract class HForeign extends HInstruction {
-  HForeign(TypeMask type, List<HInstruction> inputs) : super(inputs, type);
+  HForeign(AbstractValue type, List<HInstruction> inputs) : super(inputs, type);
 
   bool get isStatement => false;
   native.NativeBehavior get nativeBehavior => null;
@@ -2018,7 +2028,7 @@
   native.NativeThrowBehavior throwBehavior;
   final FunctionEntity foreignFunction;
 
-  HForeignCode(this.codeTemplate, TypeMask type, List<HInstruction> inputs,
+  HForeignCode(this.codeTemplate, AbstractValue type, List<HInstruction> inputs,
       {this.isStatement: false,
       SideEffects effects,
       native.NativeBehavior nativeBehavior,
@@ -2044,8 +2054,12 @@
     }
   }
 
-  HForeignCode.statement(js.Template codeTemplate, List<HInstruction> inputs,
-      SideEffects effects, native.NativeBehavior nativeBehavior, TypeMask type)
+  HForeignCode.statement(
+      js.Template codeTemplate,
+      List<HInstruction> inputs,
+      SideEffects effects,
+      native.NativeBehavior nativeBehavior,
+      AbstractValue type)
       : this(codeTemplate, type, inputs,
             isStatement: true,
             effects: effects,
@@ -2083,7 +2097,7 @@
 abstract class HInvokeBinary extends HInstruction {
   final Selector selector;
   HInvokeBinary(
-      HInstruction left, HInstruction right, this.selector, TypeMask type)
+      HInstruction left, HInstruction right, this.selector, AbstractValue type)
       : super(<HInstruction>[left, right], type) {
     sideEffects.clearAllSideEffects();
     sideEffects.clearAllDependencies();
@@ -2097,14 +2111,15 @@
 }
 
 abstract class HBinaryArithmetic extends HInvokeBinary {
-  HBinaryArithmetic(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HBinaryArithmetic(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   BinaryOperation operation(ConstantSystem constantSystem);
 }
 
 class HAdd extends HBinaryArithmetic {
-  HAdd(HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HAdd(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   accept(HVisitor visitor) => visitor.visitAdd(this);
 
@@ -2116,8 +2131,8 @@
 }
 
 class HDivide extends HBinaryArithmetic {
-  HDivide(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HDivide(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   accept(HVisitor visitor) => visitor.visitDivide(this);
 
@@ -2129,8 +2144,8 @@
 }
 
 class HMultiply extends HBinaryArithmetic {
-  HMultiply(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HMultiply(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   accept(HVisitor visitor) => visitor.visitMultiply(this);
 
@@ -2141,8 +2156,8 @@
 }
 
 class HSubtract extends HBinaryArithmetic {
-  HSubtract(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HSubtract(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   accept(HVisitor visitor) => visitor.visitSubtract(this);
 
@@ -2154,8 +2169,8 @@
 }
 
 class HTruncatingDivide extends HBinaryArithmetic {
-  HTruncatingDivide(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HTruncatingDivide(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   accept(HVisitor visitor) => visitor.visitTruncatingDivide(this);
 
@@ -2167,8 +2182,8 @@
 }
 
 class HRemainder extends HBinaryArithmetic {
-  HRemainder(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HRemainder(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   accept(HVisitor visitor) => visitor.visitRemainder(this);
 
@@ -2185,7 +2200,8 @@
  * Its block has one successor per constant, and one for the default.
  */
 class HSwitch extends HControlFlow {
-  HSwitch(List<HInstruction> inputs) : super(inputs);
+  HSwitch(AbstractValueDomain domain, List<HInstruction> inputs)
+      : super(domain, inputs);
 
   HConstant constant(int index) => inputs[index + 1];
   HInstruction get expression => inputs[0];
@@ -2203,14 +2219,14 @@
 }
 
 abstract class HBinaryBitOp extends HInvokeBinary {
-  HBinaryBitOp(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HBinaryBitOp(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
 }
 
 class HShiftLeft extends HBinaryBitOp {
-  HShiftLeft(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HShiftLeft(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   accept(HVisitor visitor) => visitor.visitShiftLeft(this);
 
@@ -2222,8 +2238,8 @@
 }
 
 class HShiftRight extends HBinaryBitOp {
-  HShiftRight(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HShiftRight(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   accept(HVisitor visitor) => visitor.visitShiftRight(this);
 
@@ -2235,8 +2251,8 @@
 }
 
 class HBitOr extends HBinaryBitOp {
-  HBitOr(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HBitOr(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   accept(HVisitor visitor) => visitor.visitBitOr(this);
 
@@ -2248,8 +2264,8 @@
 }
 
 class HBitAnd extends HBinaryBitOp {
-  HBitAnd(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HBitAnd(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   accept(HVisitor visitor) => visitor.visitBitAnd(this);
 
@@ -2261,8 +2277,8 @@
 }
 
 class HBitXor extends HBinaryBitOp {
-  HBitXor(
-      HInstruction left, HInstruction right, Selector selector, TypeMask type)
+  HBitXor(HInstruction left, HInstruction right, Selector selector,
+      AbstractValue type)
       : super(left, right, selector, type);
   accept(HVisitor visitor) => visitor.visitBitXor(this);
 
@@ -2288,7 +2304,7 @@
 }
 
 class HNegate extends HInvokeUnary {
-  HNegate(HInstruction input, Selector selector, TypeMask type)
+  HNegate(HInstruction input, Selector selector, AbstractValue type)
       : super(input, selector, type);
   accept(HVisitor visitor) => visitor.visitNegate(this);
 
@@ -2300,7 +2316,7 @@
 }
 
 class HAbs extends HInvokeUnary {
-  HAbs(HInstruction input, Selector selector, TypeMask type)
+  HAbs(HInstruction input, Selector selector, AbstractValue type)
       : super(input, selector, type);
   accept(HVisitor visitor) => visitor.visitAbs(this);
 
@@ -2311,7 +2327,7 @@
 }
 
 class HBitNot extends HInvokeUnary {
-  HBitNot(HInstruction input, Selector selector, TypeMask type)
+  HBitNot(HInstruction input, Selector selector, AbstractValue type)
       : super(input, selector, type);
   accept(HVisitor visitor) => visitor.visitBitNot(this);
 
@@ -2323,13 +2339,13 @@
 }
 
 class HExit extends HControlFlow {
-  HExit() : super(const <HInstruction>[]);
+  HExit(AbstractValueDomain domain) : super(domain, const <HInstruction>[]);
   toString() => 'exit';
   accept(HVisitor visitor) => visitor.visitExit(this);
 }
 
 class HGoto extends HControlFlow {
-  HGoto() : super(const <HInstruction>[]);
+  HGoto(AbstractValueDomain domain) : super(domain, const <HInstruction>[]);
   toString() => 'goto';
   accept(HVisitor visitor) => visitor.visitGoto(this);
 }
@@ -2337,15 +2353,17 @@
 abstract class HJump extends HControlFlow {
   final JumpTarget target;
   final LabelDefinition label;
-  HJump(this.target, SourceInformation sourceInformation)
+  HJump(AbstractValueDomain domain, this.target,
+      SourceInformation sourceInformation)
       : label = null,
-        super(const <HInstruction>[]) {
+        super(domain, const <HInstruction>[]) {
     this.sourceInformation = sourceInformation;
   }
-  HJump.toLabel(LabelDefinition label, SourceInformation sourceInformation)
+  HJump.toLabel(AbstractValueDomain domain, LabelDefinition label,
+      SourceInformation sourceInformation)
       : label = label,
         target = label.target,
-        super(const <HInstruction>[]) {
+        super(domain, const <HInstruction>[]) {
     this.sourceInformation = sourceInformation;
   }
 }
@@ -2356,13 +2374,15 @@
   /// [SsaFromAstMixin.buildComplexSwitchStatement] for detail.
   final bool breakSwitchContinueLoop;
 
-  HBreak(JumpTarget target, SourceInformation sourceInformation,
+  HBreak(AbstractValueDomain domain, JumpTarget target,
+      SourceInformation sourceInformation,
       {bool this.breakSwitchContinueLoop: false})
-      : super(target, sourceInformation);
+      : super(domain, target, sourceInformation);
 
-  HBreak.toLabel(LabelDefinition label, SourceInformation sourceInformation)
+  HBreak.toLabel(AbstractValueDomain domain, LabelDefinition label,
+      SourceInformation sourceInformation)
       : breakSwitchContinueLoop = false,
-        super.toLabel(label, sourceInformation);
+        super.toLabel(domain, label, sourceInformation);
 
   String toString() => (label != null) ? 'break ${label.labelName}' : 'break';
 
@@ -2370,11 +2390,13 @@
 }
 
 class HContinue extends HJump {
-  HContinue(JumpTarget target, SourceInformation sourceInformation)
-      : super(target, sourceInformation);
+  HContinue(AbstractValueDomain domain, JumpTarget target,
+      SourceInformation sourceInformation)
+      : super(domain, target, sourceInformation);
 
-  HContinue.toLabel(LabelDefinition label, SourceInformation sourceInformation)
-      : super.toLabel(label, sourceInformation);
+  HContinue.toLabel(AbstractValueDomain domain, LabelDefinition label,
+      SourceInformation sourceInformation)
+      : super.toLabel(domain, label, sourceInformation);
 
   String toString() =>
       (label != null) ? 'continue ${label.labelName}' : 'continue';
@@ -2386,7 +2408,7 @@
   HLocalValue exception;
   HBasicBlock catchBlock;
   HBasicBlock finallyBlock;
-  HTry() : super(const <HInstruction>[]);
+  HTry(AbstractValueDomain domain) : super(domain, const <HInstruction>[]);
   toString() => 'try';
   accept(HVisitor visitor) => visitor.visitTry(this);
   HBasicBlock get joinBlock => this.block.successors.last;
@@ -2398,7 +2420,7 @@
 // leads to one of this instruction a predecessor of catch and
 // finally.
 class HExitTry extends HControlFlow {
-  HExitTry() : super(const <HInstruction>[]);
+  HExitTry(AbstractValueDomain domain) : super(domain, const <HInstruction>[]);
   toString() => 'exit try';
   accept(HVisitor visitor) => visitor.visitExitTry(this);
   HBasicBlock get bodyTrySuccessor => block.successors[0];
@@ -2406,7 +2428,8 @@
 
 class HIf extends HConditionalBranch {
   HBlockFlow blockInformation = null;
-  HIf(HInstruction condition) : super(<HInstruction>[condition]);
+  HIf(AbstractValueDomain domain, HInstruction condition)
+      : super(domain, <HInstruction>[condition]);
   toString() => 'if';
   accept(HVisitor visitor) => visitor.visitIf(this);
 
@@ -2428,15 +2451,16 @@
   static const int DO_WHILE_LOOP = 1;
 
   final int kind;
-  HLoopBranch(HInstruction condition, [this.kind = CONDITION_FIRST_LOOP])
-      : super(<HInstruction>[condition]);
+  HLoopBranch(AbstractValueDomain domain, HInstruction condition,
+      [this.kind = CONDITION_FIRST_LOOP])
+      : super(domain, <HInstruction>[condition]);
   toString() => 'loop-branch';
   accept(HVisitor visitor) => visitor.visitLoopBranch(this);
 }
 
 class HConstant extends HInstruction {
   final ConstantValue constant;
-  HConstant.internal(this.constant, TypeMask constantType)
+  HConstant.internal(this.constant, AbstractValue constantType)
       : super(<HInstruction>[], constantType);
 
   toString() => 'literal: ${constant.toStructuredText()}';
@@ -2468,7 +2492,8 @@
 }
 
 class HNot extends HInstruction {
-  HNot(HInstruction value, TypeMask type) : super(<HInstruction>[value], type) {
+  HNot(HInstruction value, AbstractValue type)
+      : super(<HInstruction>[value], type) {
     setUseGvn();
   }
 
@@ -2484,7 +2509,8 @@
   * value from the start, whereas [HLocalValue]s need to be initialized first.
   */
 class HLocalValue extends HInstruction {
-  HLocalValue(Entity variable, TypeMask type) : super(<HInstruction>[], type) {
+  HLocalValue(Entity variable, AbstractValue type)
+      : super(<HInstruction>[], type) {
     sourceElement = variable;
   }
 
@@ -2511,7 +2537,7 @@
 }
 
 class HThis extends HParameterValue {
-  HThis(ThisLocal element, TypeMask type) : super(element, type);
+  HThis(ThisLocal element, AbstractValue type) : super(element, type);
 
   ThisLocal get sourceElement => super.sourceElement;
   void set sourceElement(covariant ThisLocal local) {
@@ -2540,15 +2566,15 @@
   // The order of the [inputs] must correspond to the order of the
   // predecessor-edges. That is if an input comes from the first predecessor
   // of the surrounding block, then the input must be the first in the [HPhi].
-  HPhi(Local variable, List<HInstruction> inputs, TypeMask type)
+  HPhi(Local variable, List<HInstruction> inputs, AbstractValue type)
       : super(inputs, type) {
     sourceElement = variable;
   }
-  HPhi.noInputs(Local variable, TypeMask type)
+  HPhi.noInputs(Local variable, AbstractValue type)
       : this(variable, <HInstruction>[], type);
-  HPhi.singleInput(Local variable, HInstruction input, TypeMask type)
+  HPhi.singleInput(Local variable, HInstruction input, AbstractValue type)
       : this(variable, <HInstruction>[input], type);
-  HPhi.manyInputs(Local variable, List<HInstruction> inputs, TypeMask type)
+  HPhi.manyInputs(Local variable, List<HInstruction> inputs, AbstractValue type)
       : this(variable, inputs, type);
 
   void addInput(HInstruction input) {
@@ -2627,8 +2653,9 @@
 }
 
 class HReturn extends HControlFlow {
-  HReturn(HInstruction value, SourceInformation sourceInformation)
-      : super(<HInstruction>[value]) {
+  HReturn(AbstractValueDomain domain, HInstruction value,
+      SourceInformation sourceInformation)
+      : super(domain, <HInstruction>[value]) {
     this.sourceInformation = sourceInformation;
   }
   toString() => 'return';
@@ -2636,8 +2663,9 @@
 }
 
 class HThrowExpression extends HInstruction {
-  HThrowExpression(HInstruction value, SourceInformation sourceInformation)
-      : super(<HInstruction>[value], const TypeMask.nonNullEmpty()) {
+  HThrowExpression(AbstractValueDomain domain, HInstruction value,
+      SourceInformation sourceInformation)
+      : super(<HInstruction>[value], domain.emptyType) {
     this.sourceInformation = sourceInformation;
   }
   toString() => 'throw expression';
@@ -2646,7 +2674,7 @@
 }
 
 class HAwait extends HInstruction {
-  HAwait(HInstruction value, TypeMask type)
+  HAwait(HInstruction value, AbstractValue type)
       : super(<HInstruction>[value], type);
   toString() => 'await';
   accept(HVisitor visitor) => visitor.visitAwait(this);
@@ -2656,8 +2684,9 @@
 }
 
 class HYield extends HInstruction {
-  HYield(HInstruction value, this.hasStar, SourceInformation sourceInformation)
-      : super(<HInstruction>[value], const TypeMask.nonNullEmpty()) {
+  HYield(AbstractValueDomain domain, HInstruction value, this.hasStar,
+      SourceInformation sourceInformation)
+      : super(<HInstruction>[value], domain.emptyType) {
     this.sourceInformation = sourceInformation;
   }
   bool hasStar;
@@ -2669,9 +2698,10 @@
 
 class HThrow extends HControlFlow {
   final bool isRethrow;
-  HThrow(HInstruction value, SourceInformation sourceInformation,
+  HThrow(AbstractValueDomain domain, HInstruction value,
+      SourceInformation sourceInformation,
       {this.isRethrow: false})
-      : super(<HInstruction>[value]) {
+      : super(domain, <HInstruction>[value]) {
     this.sourceInformation = sourceInformation;
   }
   toString() => 'throw';
@@ -2680,7 +2710,7 @@
 
 class HStatic extends HInstruction {
   final MemberEntity element;
-  HStatic(this.element, TypeMask type, SourceInformation sourceInformation)
+  HStatic(this.element, AbstractValue type, SourceInformation sourceInformation)
       : super(<HInstruction>[], type) {
     assert(element != null);
     sideEffects.clearAllSideEffects();
@@ -2715,7 +2745,7 @@
   //     (a && C.JSArray_methods).get$first(a)
   //
 
-  HInterceptor(HInstruction receiver, TypeMask type)
+  HInterceptor(HInstruction receiver, AbstractValue type)
       : super(<HInstruction>[receiver], type) {
     this.sourceInformation = receiver.sourceInformation;
     sideEffects.clearAllSideEffects();
@@ -2760,9 +2790,9 @@
   HOneShotInterceptor(
       AbstractValueDomain domain,
       Selector selector,
-      TypeMask mask,
+      AbstractValue mask,
       List<HInstruction> inputs,
-      TypeMask type,
+      AbstractValue type,
       this.typeArguments,
       this.interceptedClasses)
       : super(selector, mask, null, inputs, true, type) {
@@ -2780,7 +2810,8 @@
 class HLazyStatic extends HInstruction {
   final FieldEntity element;
 
-  HLazyStatic(this.element, TypeMask type, SourceInformation sourceInformation)
+  HLazyStatic(
+      this.element, AbstractValue type, SourceInformation sourceInformation)
       : super(<HInstruction>[], type) {
     // TODO(4931): The first access has side-effects, but we afterwards we
     // should be able to GVN.
@@ -2800,8 +2831,8 @@
 
 class HStaticStore extends HInstruction {
   MemberEntity element;
-  HStaticStore(this.element, HInstruction value)
-      : super(<HInstruction>[value], const TypeMask.nonNullEmpty()) {
+  HStaticStore(AbstractValueDomain domain, this.element, HInstruction value)
+      : super(<HInstruction>[value], domain.emptyType) {
     sideEffects.clearAllSideEffects();
     sideEffects.clearAllDependencies();
     sideEffects.setChangesStaticProperty();
@@ -2816,7 +2847,8 @@
 }
 
 class HLiteralList extends HInstruction {
-  HLiteralList(List<HInstruction> inputs, TypeMask type) : super(inputs, type);
+  HLiteralList(List<HInstruction> inputs, AbstractValue type)
+      : super(inputs, type);
   toString() => 'literal list';
   accept(HVisitor visitor) => visitor.visitLiteralList(this);
 
@@ -2829,8 +2861,8 @@
  */
 class HIndex extends HInstruction {
   final Selector selector;
-  HIndex(
-      HInstruction receiver, HInstruction index, this.selector, TypeMask type)
+  HIndex(HInstruction receiver, HInstruction index, this.selector,
+      AbstractValue type)
       : super(<HInstruction>[receiver, index], type) {
     sideEffects.clearAllSideEffects();
     sideEffects.clearAllDependencies();
@@ -2863,10 +2895,9 @@
  */
 class HIndexAssign extends HInstruction {
   final Selector selector;
-  HIndexAssign(HInstruction receiver, HInstruction index, HInstruction value,
-      this.selector)
-      : super(<HInstruction>[receiver, index, value],
-            const TypeMask.nonNullEmpty()) {
+  HIndexAssign(AbstractValueDomain domain, HInstruction receiver,
+      HInstruction index, HInstruction value, this.selector)
+      : super(<HInstruction>[receiver, index, value], domain.emptyType) {
     sideEffects.clearAllSideEffects();
     sideEffects.clearAllDependencies();
     sideEffects.setChangesIndex();
@@ -2901,14 +2932,14 @@
   final int kind;
   final bool useInstanceOf;
 
-  HIs.direct(DartType typeExpression, HInstruction expression, TypeMask type,
-      SourceInformation sourceInformation)
+  HIs.direct(DartType typeExpression, HInstruction expression,
+      AbstractValue type, SourceInformation sourceInformation)
       : this.internal(
             typeExpression, [expression], RAW_CHECK, type, sourceInformation);
 
   // Pre-verified that the check can be done using 'instanceof'.
   HIs.instanceOf(DartType typeExpression, HInstruction expression,
-      TypeMask type, SourceInformation sourceInformation)
+      AbstractValue type, SourceInformation sourceInformation)
       : this.internal(
             typeExpression, [expression], RAW_CHECK, type, sourceInformation,
             useInstanceOf: true);
@@ -2917,7 +2948,7 @@
       DartType typeExpression,
       HInstruction expression,
       HInterceptor interceptor,
-      TypeMask type,
+      AbstractValue type,
       SourceInformation sourceInformation) {
     assert(
         (typeExpression.isFunctionType || typeExpression.isInterfaceType) &&
@@ -2927,18 +2958,26 @@
         RAW_CHECK, type, sourceInformation);
   }
 
-  HIs.compound(DartType typeExpression, HInstruction expression,
-      HInstruction call, TypeMask type, SourceInformation sourceInformation)
+  HIs.compound(
+      DartType typeExpression,
+      HInstruction expression,
+      HInstruction call,
+      AbstractValue type,
+      SourceInformation sourceInformation)
       : this.internal(typeExpression, [expression, call], COMPOUND_CHECK, type,
             sourceInformation);
 
-  HIs.variable(DartType typeExpression, HInstruction expression,
-      HInstruction call, TypeMask type, SourceInformation sourceInformation)
+  HIs.variable(
+      DartType typeExpression,
+      HInstruction expression,
+      HInstruction call,
+      AbstractValue type,
+      SourceInformation sourceInformation)
       : this.internal(typeExpression, [expression, call], VARIABLE_CHECK, type,
             sourceInformation);
 
   HIs.internal(this.typeExpression, List<HInstruction> inputs, this.kind,
-      TypeMask type, SourceInformation sourceInformation,
+      AbstractValue type, SourceInformation sourceInformation,
       {bool this.useInstanceOf: false})
       : super(inputs, type) {
     assert(kind >= RAW_CHECK && kind <= VARIABLE_CHECK);
@@ -2983,7 +3022,7 @@
 class HIsViaInterceptor extends HLateInstruction {
   final DartType typeExpression;
   HIsViaInterceptor(
-      this.typeExpression, HInstruction interceptor, TypeMask type)
+      this.typeExpression, HInstruction interceptor, AbstractValue type)
       : super(<HInstruction>[interceptor], type) {
     setUseGvn();
   }
@@ -3017,10 +3056,11 @@
   //
   final Selector receiverTypeCheckSelector;
 
-  TypeMask checkedType; // Not final because we refine it.
-  TypeMask inputType; // Holds input type for codegen after HTypeKnown removal.
+  AbstractValue checkedType; // Not final because we refine it.
+  AbstractValue
+      inputType; // Holds input type for codegen after HTypeKnown removal.
 
-  HTypeConversion(this.typeExpression, this.kind, TypeMask type,
+  HTypeConversion(this.typeExpression, this.kind, AbstractValue type,
       HInstruction input, SourceInformation sourceInformation,
       {this.receiverTypeCheckSelector})
       : checkedType = type,
@@ -3032,7 +3072,7 @@
   }
 
   HTypeConversion.withTypeRepresentation(this.typeExpression, this.kind,
-      TypeMask type, HInstruction input, HInstruction typeRepresentation)
+      AbstractValue type, HInstruction input, HInstruction typeRepresentation)
       : checkedType = type,
         receiverTypeCheckSelector = null,
         super(<HInstruction>[input, typeRepresentation], type) {
@@ -3040,8 +3080,8 @@
     sourceElement = input.sourceElement;
   }
 
-  HTypeConversion.viaMethodOnType(this.typeExpression, this.kind, TypeMask type,
-      HInstruction reifiedType, HInstruction input)
+  HTypeConversion.viaMethodOnType(this.typeExpression, this.kind,
+      AbstractValue type, HInstruction reifiedType, HInstruction input)
       : checkedType = type,
         receiverTypeCheckSelector = null,
         super(<HInstruction>[reifiedType, input], type) {
@@ -3104,16 +3144,16 @@
 
 /// The [HTypeKnown] instruction marks a value with a refined type.
 class HTypeKnown extends HCheck {
-  TypeMask knownType;
+  AbstractValue knownType;
   final bool _isMovable;
 
-  HTypeKnown.pinned(TypeMask knownType, HInstruction input)
+  HTypeKnown.pinned(AbstractValue knownType, HInstruction input)
       : this.knownType = knownType,
         this._isMovable = false,
         super(<HInstruction>[input], knownType);
 
   HTypeKnown.witnessed(
-      TypeMask knownType, HInstruction input, HInstruction witness)
+      AbstractValue knownType, HInstruction input, HInstruction witness)
       : this.knownType = knownType,
         this._isMovable = true,
         super(<HInstruction>[input, witness], knownType);
@@ -3152,7 +3192,7 @@
 }
 
 class HStringConcat extends HInstruction {
-  HStringConcat(HInstruction left, HInstruction right, TypeMask type)
+  HStringConcat(HInstruction left, HInstruction right, AbstractValue type)
       : super(<HInstruction>[left, right], type) {
     // TODO(sra): Until Issue 9293 is fixed, this false dependency keeps the
     // concats bunched with stringified inputs for much better looking code with
@@ -3172,7 +3212,7 @@
  * into a String value.
  */
 class HStringify extends HInstruction {
-  HStringify(HInstruction input, TypeMask type)
+  HStringify(HInstruction input, AbstractValue type)
       : super(<HInstruction>[input], type) {
     sideEffects.setAllSideEffects();
     sideEffects.setDependsOnSomething();
@@ -3462,7 +3502,7 @@
 
 /// Reads raw reified type info from an object.
 class HTypeInfoReadRaw extends HInstruction {
-  HTypeInfoReadRaw(HInstruction receiver, TypeMask instructionType)
+  HTypeInfoReadRaw(HInstruction receiver, AbstractValue instructionType)
       : super(<HInstruction>[receiver], instructionType) {
     setUseGvn();
   }
@@ -3488,14 +3528,14 @@
   final bool isIntercepted;
 
   HTypeInfoReadVariable.intercepted(this.variable, HInstruction interceptor,
-      HInstruction receiver, TypeMask instructionType)
+      HInstruction receiver, AbstractValue instructionType)
       : isIntercepted = true,
         super(<HInstruction>[interceptor, receiver], instructionType) {
     setUseGvn();
   }
 
   HTypeInfoReadVariable.noInterceptor(
-      this.variable, HInstruction receiver, TypeMask instructionType)
+      this.variable, HInstruction receiver, AbstractValue instructionType)
       : isIntercepted = false,
         super(<HInstruction>[receiver], instructionType) {
     setUseGvn();
@@ -3578,7 +3618,7 @@
   final TypeInfoExpressionKind kind;
   final DartType dartType;
   HTypeInfoExpression(this.kind, this.dartType, List<HInstruction> inputs,
-      TypeMask instructionType)
+      AbstractValue instructionType)
       : super(inputs, instructionType) {
     setUseGvn();
   }
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index f3174f2..170afb3 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -1130,7 +1130,7 @@
         value = other;
       }
     }
-    return new HFieldSet(field, receiver, value);
+    return new HFieldSet(_abstractValueDomain, field, receiver, value);
   }
 
   HInstruction visitInvokeClosure(HInvokeClosure node) {
diff --git a/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart b/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart
index 537fd50..f628a1e 100644
--- a/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_branch_builder.dart
@@ -42,7 +42,8 @@
     checkNotAborted();
     assert(identical(builder.current, builder.lastOpenedBlock));
     HInstruction conditionValue = builder.popBoolified();
-    HIf branch = new HIf(conditionValue)..sourceInformation = sourceInformation;
+    HIf branch = new HIf(builder.abstractValueDomain, conditionValue)
+      ..sourceInformation = sourceInformation;
     HBasicBlock conditionExitBlock = builder.current;
     builder.close(branch);
     conditionBranch.exitLocals = builder.localsHandler;
diff --git a/pkg/compiler/lib/src/ssa/types_propagation.dart b/pkg/compiler/lib/src/ssa/types_propagation.dart
index 5b84020..f5e50bb 100644
--- a/pkg/compiler/lib/src/ssa/types_propagation.dart
+++ b/pkg/compiler/lib/src/ssa/types_propagation.dart
@@ -258,7 +258,7 @@
     HInstruction input = instruction.checkedInput;
     TypeMask inputType = input.instructionType;
     TypeMask outputType =
-        instruction.knownType.intersection(inputType, closedWorld);
+        abstractValueDomain.intersection(instruction.knownType, inputType);
     if (inputType != outputType) {
       input.replaceAllUsersDominatedBy(instruction.next, instruction);
     }
diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart
index 0bf4247..3ce4ce1 100644
--- a/pkg/compiler/lib/src/types/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/types/abstract_value_domain.dart
@@ -4,6 +4,7 @@
 
 library dart2js.abstract_value_domain;
 
+import '../constants/values.dart' show ConstantValue;
 import '../elements/entities.dart';
 
 /// A value in an abstraction of runtime values.
@@ -93,6 +94,8 @@
   /// Creates an [AbstractValue] for non-null instance that implements [cls].
   AbstractValue createNonNullSubtype(ClassEntity cls);
 
+  AbstractValue createNullableSubtype(ClassEntity cls);
+
   /// Returns `true` if [value] is a native typed array or `null` at runtime.
   bool isTypedArray(covariant AbstractValue value);
 
@@ -237,4 +240,7 @@
 
   /// Returns `true` if [a] contains all non-null runtime values.
   bool containsAll(covariant AbstractValue a);
+
+  /// Computes the [AbstractValue] corresponding to the constant [value].
+  AbstractValue computeAbstractValueForConstant(ConstantValue value);
 }
diff --git a/pkg/compiler/lib/src/types/masks.dart b/pkg/compiler/lib/src/types/masks.dart
index 2f8448f..24203e1 100644
--- a/pkg/compiler/lib/src/types/masks.dart
+++ b/pkg/compiler/lib/src/types/masks.dart
@@ -6,7 +6,7 @@
 
 import '../common.dart';
 import '../common_elements.dart' show CommonElements;
-import '../constants/values.dart' show PrimitiveConstantValue;
+import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue;
 import '../elements/entities.dart';
 import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
 import '../universe/selector.dart' show Selector;
@@ -18,6 +18,7 @@
 import '../util/util.dart';
 import '../world.dart' show ClassQuery, ClosedWorld;
 import 'abstract_value_domain.dart';
+import 'constants.dart';
 
 part 'container_type_mask.dart';
 part 'dictionary_type_mask.dart';
@@ -195,6 +196,10 @@
     return new TypeMask.nonNullSubtype(cls, _closedWorld);
   }
 
+  TypeMask createNullableSubtype(ClassEntity cls) {
+    return new TypeMask.subtype(cls, _closedWorld);
+  }
+
   TypeMask excludeNull(TypeMask mask) => mask.nonNullable();
 
   @override
@@ -365,4 +370,9 @@
   bool areDisjoint(TypeMask a, TypeMask b) => a.isDisjoint(b, _closedWorld);
 
   bool containsAll(TypeMask a) => a.containsAll(_closedWorld);
+
+  @override
+  AbstractValue computeAbstractValueForConstant(ConstantValue value) {
+    return computeTypeMask(_closedWorld, value);
+  }
 }
diff --git a/tests/compiler/dart2js/codegen/value_range2_test.dart b/tests/compiler/dart2js/codegen/value_range2_test.dart
index f4b9376..be9df0f 100644
--- a/tests/compiler/dart2js/codegen/value_range2_test.dart
+++ b/tests/compiler/dart2js/codegen/value_range2_test.dart
@@ -5,12 +5,24 @@
 import "package:expect/expect.dart";
 import "package:compiler/src/ssa/nodes.dart";
 import "package:compiler/src/ssa/value_range_analyzer.dart";
+import "package:compiler/src/types/abstract_value_domain.dart";
 import "package:compiler/src/js_backend/constant_system_javascript.dart";
 
 ValueRangeInfo info = new ValueRangeInfo(const JavaScriptConstantSystem());
 
-Value instructionValue = info.newInstructionValue(new HBreak(null, null));
-Value lengthValue = info.newPositiveValue(new HBreak(null, null));
+class AbstractValueDomainMock implements AbstractValueDomain {
+  const AbstractValueDomainMock();
+
+  @override
+  noSuchMethod(Invocation invocation) => null;
+}
+
+AbstractValueDomain abstractValueDomain = const AbstractValueDomainMock();
+
+Value instructionValue =
+    info.newInstructionValue(new HBreak(abstractValueDomain, null, null));
+Value lengthValue =
+    info.newPositiveValue(new HBreak(abstractValueDomain, null, null));
 
 Range createSingleRange(Value value) => info.newNormalizedRange(value, value);