Use AbstractValue in most of ssa

Change-Id: I157081f817e033181d7c314f7567517e5ce85058
Reviewed-on: https://dart-review.googlesource.com/56522
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 884aadb..c4419b5 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -7,6 +7,7 @@
 
 import 'common.dart';
 import 'common/names.dart' show Identifiers, Uris;
+import 'constants/expressions.dart' show ConstantExpression;
 import 'constants/values.dart';
 import 'elements/entities.dart';
 import 'elements/names.dart' show PublicName;
@@ -14,12 +15,10 @@
 import 'js_backend/backend.dart' show JavaScriptBackend;
 import 'js_backend/constant_system_javascript.dart';
 import 'js_backend/native_data.dart' show NativeBasicData;
-import 'constants/expressions.dart' show ConstantExpression;
+import 'types/abstract_value_domain.dart';
 import 'universe/call_structure.dart' show CallStructure;
 import 'universe/selector.dart' show Selector;
 import 'universe/call_structure.dart';
-import 'universe/world_builder.dart';
-import 'world.dart';
 
 /// The common elements and types in Dart.
 class CommonElements {
@@ -748,8 +747,8 @@
   /// in the given [world].
   ///
   /// Returns `false` if `JSString.split` is not available.
-  bool appliesToJsStringSplit(
-      Selector selector, ReceiverConstraint receiver, World world) {
+  bool appliesToJsStringSplit(Selector selector, AbstractValue receiver,
+      AbstractValueDomain abstractValueDomain) {
     if (_jsStringSplit == null) {
       ClassEntity cls =
           _findClass(interceptorsLibrary, 'JSString', required: false);
@@ -758,7 +757,8 @@
       if (_jsStringSplit == null) return false;
     }
     return selector.applies(_jsStringSplit) &&
-        (receiver == null || receiver.canHit(jsStringSplit, selector, world));
+        (receiver == null ||
+            abstractValueDomain.canHit(receiver, jsStringSplit, selector));
   }
 
   FunctionEntity _jsStringSplit;
diff --git a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
index b0487db..f3b7c59 100644
--- a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
@@ -126,7 +126,7 @@
           .resultOfMember(e is ConstructorBodyEntity ? e.constructor : e);
 
   AbstractValue getReturnTypeOf(FunctionEntity function) {
-    return TypeMaskFactory.inferredReturnTypeForElement(
+    return AbstractValueFactory.inferredReturnTypeForElement(
         function, _globalInferenceResults);
   }
 
@@ -173,28 +173,28 @@
   }
 
   AbstractValue inferredIndexType(ir.ForInStatement node) {
-    return TypeMaskFactory.inferredTypeForSelector(
+    return AbstractValueFactory.inferredTypeForSelector(
         new Selector.index(), typeOfIterator(node), _globalInferenceResults);
   }
 
   AbstractValue getInferredTypeOf(MemberEntity member) {
-    return TypeMaskFactory.inferredTypeForMember(
+    return AbstractValueFactory.inferredTypeForMember(
         member, _globalInferenceResults);
   }
 
   AbstractValue getInferredTypeOfParameter(Local parameter) {
-    return TypeMaskFactory.inferredTypeForParameter(
+    return AbstractValueFactory.inferredTypeForParameter(
         parameter, _globalInferenceResults);
   }
 
   AbstractValue selectorTypeOf(Selector selector, AbstractValue mask) {
-    return TypeMaskFactory.inferredTypeForSelector(
+    return AbstractValueFactory.inferredTypeForSelector(
         selector, mask, _globalInferenceResults);
   }
 
   AbstractValue typeFromNativeBehavior(
       NativeBehavior nativeBehavior, ClosedWorld closedWorld) {
-    return TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld);
+    return AbstractValueFactory.fromNativeBehavior(nativeBehavior, closedWorld);
   }
 }
 
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index df419aa..468e038 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -31,7 +31,7 @@
 import '../kernel/element_map.dart';
 import '../kernel/kernel_backend_strategy.dart';
 import '../native/native.dart' as native;
-import '../types/masks.dart';
+import '../types/abstract_value_domain.dart';
 import '../types/types.dart';
 import '../universe/call_structure.dart';
 import '../universe/selector.dart';
@@ -541,7 +541,7 @@
       }
 
       newObject = new HCreate(cls, constructorArguments,
-          new TypeMask.nonNullExact(cls, closedWorld), sourceInformation,
+          abstractValueDomain.createNonNullExact(cls), sourceInformation,
           instantiatedTypes: instantiatedTypes,
           hasRtiInput: needsTypeArguments);
 
@@ -1206,7 +1206,7 @@
       String arguments = templateArguments.join(',');
 
       // TODO(sra): Use declared type or NativeBehavior type.
-      TypeMask typeMask = abstractValueDomain.dynamicType;
+      AbstractValue typeMask = abstractValueDomain.dynamicType;
       String template;
       if (targetElement.isGetter) {
         template = '${templateReceiver}$nativeName';
@@ -1245,7 +1245,7 @@
   }
 
   void openFunction(MemberEntity member, [ir.FunctionNode functionNode]) {
-    Map<Local, TypeMask> parameterMap = <Local, TypeMask>{};
+    Map<Local, AbstractValue> parameterMap = <Local, AbstractValue>{};
     if (functionNode != null) {
       void handleParameter(ir.VariableDeclaration node) {
         Local local = localsMap.getLocalVariable(node);
@@ -1593,7 +1593,7 @@
       // array, as this is stronger than the iterator's `get current` type, for
       // example, `get current` includes null.
       // TODO(sra): The element type of a container type mask might be better.
-      TypeMask type = _typeInferenceMap.inferredIndexType(node);
+      AbstractValue type = _typeInferenceMap.inferredIndexType(node);
 
       SourceInformation sourceInformation =
           _sourceInformationBuilder.buildForInCurrent(node);
@@ -1658,7 +1658,7 @@
     HInstruction iterator;
 
     void buildInitializer() {
-      TypeMask mask = _typeInferenceMap.typeOfIterator(node);
+      AbstractValue mask = _typeInferenceMap.typeOfIterator(node);
       node.iterable.accept(this);
       HInstruction receiver = pop();
       _pushDynamicInvocation(
@@ -1672,7 +1672,7 @@
     }
 
     HInstruction buildCondition() {
-      TypeMask mask = _typeInferenceMap.typeOfIteratorMoveNext(node);
+      AbstractValue mask = _typeInferenceMap.typeOfIteratorMoveNext(node);
       _pushDynamicInvocation(
           node,
           mask,
@@ -1686,7 +1686,7 @@
     void buildBody() {
       SourceInformation sourceInformation =
           _sourceInformationBuilder.buildForInCurrent(node);
-      TypeMask mask = _typeInferenceMap.typeOfIteratorCurrent(node);
+      AbstractValue mask = _typeInferenceMap.typeOfIteratorCurrent(node);
       _pushDynamicInvocation(node, mask, Selectors.current, [iterator],
           const <DartType>[], sourceInformation);
 
@@ -1742,7 +1742,7 @@
     void buildInitializer() {}
 
     HInstruction buildCondition() {
-      TypeMask mask = _typeInferenceMap.typeOfIteratorMoveNext(node);
+      AbstractValue mask = _typeInferenceMap.typeOfIteratorMoveNext(node);
       _pushDynamicInvocation(
           node,
           mask,
@@ -1756,7 +1756,7 @@
     }
 
     void buildBody() {
-      TypeMask mask = _typeInferenceMap.typeOfIteratorCurrent(node);
+      AbstractValue mask = _typeInferenceMap.typeOfIteratorCurrent(node);
       _pushDynamicInvocation(
           node,
           mask,
@@ -2033,8 +2033,8 @@
     }
   }
 
-  void generateError(FunctionEntity function, String message, TypeMask typeMask,
-      SourceInformation sourceInformation) {
+  void generateError(FunctionEntity function, String message,
+      AbstractValue typeMask, SourceInformation sourceInformation) {
     HInstruction errorMessage = graph.addConstantString(message, closedWorld);
     _pushStaticInvocation(
         function, [errorMessage], typeMask, const <DartType>[],
@@ -2687,9 +2687,9 @@
           listInstruction, type, sourceInformation);
     }
 
-    TypeMask type = _typeInferenceMap.typeOfListLiteral(
+    AbstractValue type = _typeInferenceMap.typeOfListLiteral(
         targetElement, node, abstractValueDomain);
-    if (!type.containsAll(closedWorld)) {
+    if (!abstractValueDomain.containsAll(type)) {
       listInstruction.instructionType = type;
     }
     stack.add(listInstruction);
@@ -2762,11 +2762,12 @@
     // type inference might discover a more specific type, or find nothing (in
     // dart2js unit tests).
 
-    TypeMask mapType = new TypeMask.nonNullSubtype(
-        _commonElements.mapLiteralClass, closedWorld);
-    TypeMask returnTypeMask = _typeInferenceMap.getReturnTypeOf(constructor);
-    TypeMask instructionType =
-        mapType.intersection(returnTypeMask, closedWorld);
+    AbstractValue mapType = abstractValueDomain
+        .createNonNullSubtype(_commonElements.mapLiteralClass);
+    AbstractValue returnTypeMask =
+        _typeInferenceMap.getReturnTypeOf(constructor);
+    AbstractValue instructionType =
+        abstractValueDomain.intersection(mapType, returnTypeMask);
 
     addImplicitInstantiation(type);
     _pushStaticInvocation(
@@ -3249,7 +3250,7 @@
       return;
     }
 
-    TypeMask typeMask = _typeInferenceMap.getReturnTypeOf(function);
+    AbstractValue typeMask = _typeInferenceMap.getReturnTypeOf(function);
 
     List<DartType> typeArguments =
         _getStaticTypeArguments(function, node.arguments);
@@ -3279,7 +3280,7 @@
   void handleInvokeFactoryConstructor(
       ir.StaticInvocation invocation,
       ConstructorEntity function,
-      TypeMask typeMask,
+      AbstractValue typeMask,
       List<HInstruction> arguments,
       SourceInformation sourceInformation) {
     if (function.isExternal && function.isFromEnvironmentConstructor) {
@@ -3317,7 +3318,7 @@
       return;
     }
 
-    TypeMask resultType = typeMask;
+    AbstractValue resultType = typeMask;
 
     bool isJSArrayTypedConstructor =
         function == commonElements.jsArrayTypedConstructor;
@@ -3750,7 +3751,7 @@
         failedAt(_elementMap.getSpannable(targetElement, invocation),
             "No NativeBehavior for $invocation"));
 
-    TypeMask ssaType =
+    AbstractValue ssaType =
         _typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);
     push(new HForeignCode(expr, ssaType, const <HInstruction>[],
         nativeBehavior: nativeBehavior));
@@ -3797,7 +3798,7 @@
         failedAt(_elementMap.getSpannable(targetElement, invocation),
             "No NativeBehavior for $invocation"));
 
-    TypeMask ssaType =
+    AbstractValue ssaType =
         _typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);
     push(new HForeignCode(template, ssaType, inputs,
         nativeBehavior: nativeBehavior));
@@ -3893,7 +3894,7 @@
           MessageKind.JS_PLACEHOLDER_CAPTURE);
     }
 
-    TypeMask ssaType =
+    AbstractValue ssaType =
         _typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);
 
     SourceInformation sourceInformation = null;
@@ -3906,7 +3907,7 @@
     push(code);
 
     DartType type = _getDartTypeIfValid(invocation.arguments.types.single);
-    TypeMask trustedMask = typeBuilder.trustTypeMask(type);
+    AbstractValue trustedMask = typeBuilder.trustTypeMask(type);
 
     if (trustedMask != null) {
       // We only allow the type argument to narrow `dynamic`, which probably
@@ -3914,7 +3915,8 @@
       if (abstractValueDomain.containsAll(code.instructionType)) {
         // Overwrite the type with the narrower type.
         code.instructionType = trustedMask;
-      } else if (trustedMask.containsMask(code.instructionType, closedWorld)) {
+      } else if (abstractValueDomain.contains(
+          trustedMask, code.instructionType)) {
         // It is acceptable for the type parameter to be broader than the
         // specified type.
       } else {
@@ -3942,7 +3944,7 @@
   }
 
   void _pushStaticInvocation(MemberEntity target, List<HInstruction> arguments,
-      TypeMask typeMask, List<DartType> typeArguments,
+      AbstractValue typeMask, List<DartType> typeArguments,
       {SourceInformation sourceInformation, InterfaceType instanceType}) {
     // TODO(redemption): Pass current node if needed.
     if (_tryInlineMethod(target, null, null, arguments, null, sourceInformation,
@@ -3970,7 +3972,7 @@
 
   void _pushDynamicInvocation(
       ir.Node node,
-      TypeMask mask,
+      AbstractValue mask,
       Selector selector,
       List<HInstruction> arguments,
       List<DartType> typeArguments,
@@ -4035,7 +4037,7 @@
     }
     inputs.addAll(arguments);
 
-    TypeMask type = _typeInferenceMap.selectorTypeOf(selector, mask);
+    AbstractValue type = _typeInferenceMap.selectorTypeOf(selector, mask);
     if (selector.isGetter) {
       push(new HInvokeDynamicGetter(selector, mask, null, inputs, isIntercepted,
           type, sourceInformation));
@@ -4165,7 +4167,8 @@
           .add(localsHandler.readLocal(closureInfo.getLocalForField(field)));
     });
 
-    TypeMask type = new TypeMask.nonNullExact(closureClassEntity, closedWorld);
+    AbstractValue type =
+        abstractValueDomain.createNonNullExact(closureClassEntity);
     // TODO(efortuna): Add source information here.
     push(new HCreate(
         closureClassEntity, capturedVariables, type, sourceInformation,
@@ -4338,7 +4341,7 @@
     inputs.add(receiver);
     inputs.addAll(arguments);
 
-    TypeMask typeMask;
+    AbstractValue typeMask;
     if (target is FunctionEntity) {
       typeMask = _typeInferenceMap.getReturnTypeOf(target);
     } else {
@@ -4537,7 +4540,7 @@
 
     ConstructorEntity constructor = _elementMap.getConstructor(target);
     ClassEntity cls = constructor.enclosingClass;
-    TypeMask typeMask = new TypeMask.nonNullExact(cls, closedWorld);
+    AbstractValue typeMask = abstractValueDomain.createNonNullExact(cls);
     InterfaceType instanceType = _elementMap.createInterfaceType(
         target.enclosingClass, node.arguments.types);
     instanceType = localsHandler.substInContext(instanceType);
@@ -4819,7 +4822,7 @@
   bool _tryInlineMethod(
       FunctionEntity function,
       Selector selector,
-      TypeMask mask,
+      AbstractValue mask,
       List<HInstruction> providedArguments,
       ir.Node currentNode,
       SourceInformation sourceInformation,
@@ -4857,7 +4860,8 @@
           failedAt(function, "Missing selector for inlining of $function."));
       if (selector != null) {
         if (!selector.applies(function)) return false;
-        if (mask != null && !mask.canHit(function, selector, closedWorld)) {
+        if (mask != null &&
+            !abstractValueDomain.canHit(mask, function, selector)) {
           return false;
         }
       }
@@ -4989,7 +4993,7 @@
       // NoSuchMethodError message as if we had called it.
       if (function.isInstanceMember &&
           function is! ConstructorBodyEntity &&
-          (mask == null || mask.isNullable)) {
+          (mask == null || abstractValueDomain.canBeNull(mask))) {
         add(new HFieldGet(
             null, providedArguments[0], abstractValueDomain.dynamicType,
             isAssignable: false)
diff --git a/pkg/compiler/lib/src/ssa/graph_builder.dart b/pkg/compiler/lib/src/ssa/graph_builder.dart
index 6dc7c0a..aa99124 100644
--- a/pkg/compiler/lib/src/ssa/graph_builder.dart
+++ b/pkg/compiler/lib/src/ssa/graph_builder.dart
@@ -24,7 +24,6 @@
 import '../js_emitter/code_emitter_task.dart';
 import '../options.dart';
 import '../types/abstract_value_domain.dart';
-import '../types/masks.dart';
 import '../types/types.dart';
 import '../world.dart' show ClosedWorld;
 import 'jump_handler.dart';
@@ -215,7 +214,7 @@
     current.add(instruction);
   }
 
-  HParameterValue addParameter(Entity parameter, TypeMask type) {
+  HParameterValue addParameter(Entity parameter, AbstractValue type) {
     HParameterValue result = new HParameterValue(parameter, type);
     if (lastAddedParameter == null) {
       graph.entry.addBefore(graph.entry.first, result);
diff --git a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
index e5b0003..5801f3f 100644
--- a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
+++ b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
@@ -8,7 +8,7 @@
 import '../elements/entities.dart';
 import '../elements/names.dart';
 import '../options.dart';
-import '../types/masks.dart';
+import '../types/abstract_value_domain.dart';
 import '../types/types.dart';
 import '../universe/call_structure.dart';
 import '../universe/selector.dart';
@@ -25,12 +25,12 @@
 class InvokeDynamicSpecializer {
   const InvokeDynamicSpecializer();
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
       ClosedWorld closedWorld) {
-    return TypeMaskFactory.inferredTypeForSelector(
+    return AbstractValueFactory.inferredTypeForSelector(
         instruction.selector, instruction.mask, results);
   }
 
@@ -192,9 +192,9 @@
       // We want the right checked mode error.
       return null;
     }
-    TypeMask receiverType =
+    AbstractValue receiverType =
         instruction.getDartReceiver(closedWorld).instructionType;
-    TypeMask type = TypeMaskFactory.inferredTypeForSelector(
+    AbstractValue type = AbstractValueFactory.inferredTypeForSelector(
         instruction.selector, receiverType, results);
     return new HIndex(instruction.inputs[1], instruction.inputs[2],
         instruction.selector, type);
@@ -208,7 +208,7 @@
     return constantSystem.bitNot;
   }
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -249,7 +249,7 @@
     return constantSystem.negate;
   }
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -296,7 +296,7 @@
     return constantSystem.abs;
   }
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -331,7 +331,7 @@
 abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer {
   const BinaryArithmeticSpecializer();
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -402,7 +402,7 @@
 class AddSpecializer extends BinaryArithmeticSpecializer {
   const AddSpecializer();
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -441,7 +441,7 @@
     return constantSystem.divide;
   }
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInstruction instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -467,7 +467,7 @@
 class ModuloSpecializer extends BinaryArithmeticSpecializer {
   const ModuloSpecializer();
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -553,7 +553,7 @@
 class RemainderSpecializer extends BinaryArithmeticSpecializer {
   const RemainderSpecializer();
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -589,7 +589,7 @@
     return constantSystem.multiply;
   }
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -641,7 +641,7 @@
     return constantSystem.truncatingDivide;
   }
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -727,7 +727,7 @@
 abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer {
   const BinaryBitOpSpecializer();
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -819,7 +819,7 @@
 class ShiftRightSpecializer extends BinaryBitOpSpecializer {
   const ShiftRightSpecializer();
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -887,7 +887,7 @@
     return constantSystem.bitOr;
   }
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -922,7 +922,7 @@
     return constantSystem.bitAnd;
   }
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -958,7 +958,7 @@
     return constantSystem.bitXor;
   }
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -989,7 +989,7 @@
 abstract class RelationalSpecializer extends InvokeDynamicSpecializer {
   const RelationalSpecializer();
 
-  TypeMask computeTypeFromInputTypes(
+  AbstractValue computeTypeFromInputTypes(
       HInvokeDynamic instruction,
       GlobalTypeInferenceResults results,
       CompilerOptions options,
@@ -1034,7 +1034,7 @@
       ClosedWorld closedWorld) {
     HInstruction left = instruction.inputs[1];
     HInstruction right = instruction.inputs[2];
-    TypeMask instructionType = left.instructionType;
+    AbstractValue instructionType = left.instructionType;
     if (right.isConstantNull() ||
         left.isPrimitiveOrNull(closedWorld.abstractValueDomain)) {
       return newBuiltinVariant(instruction, closedWorld);
diff --git a/pkg/compiler/lib/src/ssa/locals_handler.dart b/pkg/compiler/lib/src/ssa/locals_handler.dart
index bf5b34b..1bfef1f 100644
--- a/pkg/compiler/lib/src/ssa/locals_handler.dart
+++ b/pkg/compiler/lib/src/ssa/locals_handler.dart
@@ -12,7 +12,6 @@
 import '../js_model/closure.dart' show JRecordField, JClosureField;
 import '../js_model/locals.dart' show JLocal;
 import '../types/abstract_value_domain.dart';
-import '../types/masks.dart';
 import '../types/types.dart';
 import '../world.dart' show ClosedWorld;
 
@@ -196,12 +195,12 @@
       MemberEntity element,
       ScopeInfo scopeInfo,
       CapturedScope scopeData,
-      Map<Local, TypeMask> parameters,
+      Map<Local, AbstractValue> parameters,
       SourceInformation sourceInformation,
       {bool isGenerativeConstructorBody}) {
     this.scopeInfo = scopeInfo;
 
-    parameters.forEach((Local local, TypeMask typeMask) {
+    parameters.forEach((Local local, AbstractValue typeMask) {
       if (isGenerativeConstructorBody) {
         if (scopeData.isBoxed(local)) {
           // The parameter will be a field in the box passed as the
@@ -275,8 +274,8 @@
       SyntheticLocal parameter = createLocal('receiver');
       // Unlike `this`, receiver is nullable since direct calls to generative
       // constructor call the constructor with `null`.
-      HParameterValue value =
-          new HParameterValue(parameter, new TypeMask.exact(cls, closedWorld));
+      HParameterValue value = new HParameterValue(
+          parameter, closedWorld.abstractValueDomain.createNullableExact(cls));
       builder.graph.explicitReceiverParameter = value;
       builder.graph.entry.addAtEntry(value);
       if (builder.lastAddedParameter == null) {
@@ -341,7 +340,7 @@
       ClosureRepresentationInfo closureData = scopeInfo;
       FieldEntity redirect = redirectionMapping[local];
       HInstruction receiver = readLocal(closureData.closureEntity);
-      TypeMask type = local is BoxLocal
+      AbstractValue type = local is BoxLocal
           ? _abstractValueDomain.nonNullType
           : getTypeOfCapturedVariable(redirect);
       HInstruction fieldGet = new HFieldGet(redirect, receiver, type);
@@ -643,10 +642,10 @@
     return this;
   }
 
-  TypeMask cachedTypeOfThis;
+  AbstractValue cachedTypeOfThis;
 
-  TypeMask getTypeOfThis() {
-    TypeMask result = cachedTypeOfThis;
+  AbstractValue getTypeOfThis() {
+    AbstractValue result = cachedTypeOfThis;
     if (result == null) {
       ThisLocal local = scopeInfo.thisLocal;
       ClassEntity cls = local.enclosingClass;
@@ -655,21 +654,21 @@
         // of the class that mixins the enclosing class. These two
         // classes do not have a subclass relationship, so, for
         // simplicity, we mark the type as an interface type.
-        result = new TypeMask.nonNullSubtype(cls, closedWorld);
+        result = _abstractValueDomain.createNonNullSubtype(cls);
       } else {
-        result = new TypeMask.nonNullSubclass(cls, closedWorld);
+        result = _abstractValueDomain.createNonNullSubclass(cls);
       }
       cachedTypeOfThis = result;
     }
     return result;
   }
 
-  Map<FieldEntity, TypeMask> cachedTypesOfCapturedVariables =
-      new Map<FieldEntity, TypeMask>();
+  Map<FieldEntity, AbstractValue> cachedTypesOfCapturedVariables =
+      new Map<FieldEntity, AbstractValue>();
 
-  TypeMask getTypeOfCapturedVariable(FieldEntity element) {
+  AbstractValue getTypeOfCapturedVariable(FieldEntity element) {
     return cachedTypesOfCapturedVariables.putIfAbsent(element, () {
-      return TypeMaskFactory.inferredTypeForMember(
+      return AbstractValueFactory.inferredTypeForMember(
           element, _globalInferenceResults);
     });
   }
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index cb3258d..67bd1e0 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -18,7 +18,6 @@
 import '../js_backend/js_backend.dart';
 import '../native/native.dart' as native;
 import '../types/abstract_value_domain.dart';
-import '../types/masks.dart' show TypeMask;
 import '../universe/selector.dart' show Selector;
 import '../universe/side_effects.dart' show SideEffects;
 import '../util/util.dart';
@@ -1013,7 +1012,8 @@
 
   bool isExact(AbstractValueDomain domain) => domain.isExact(instructionType);
 
-  bool isValue(AbstractValueDomain domain) => domain.isValue(instructionType);
+  bool isValue(AbstractValueDomain domain) =>
+      domain.isPrimitiveValue(instructionType);
 
   bool canBeNull(AbstractValueDomain domain) =>
       domain.canBeNull(instructionType);
@@ -3204,8 +3204,8 @@
     }
     // Type is refined from `dynamic`, so it might become non-redundant.
     if (abstractValueDomain.containsAll(checkedType)) return false;
-    TypeMask inputType = checkedInput.instructionType;
-    return inputType.isInMask(checkedType, closedWorld);
+    AbstractValue inputType = checkedInput.instructionType;
+    return abstractValueDomain.isIn(inputType, checkedType);
   }
 
   String toString() => 'HTypeConversion(type=$typeExpression, kind=$kind, '
@@ -3253,8 +3253,8 @@
   bool isRedundant(ClosedWorld closedWorld) {
     AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
     if (abstractValueDomain.containsAll(knownType)) return false;
-    TypeMask inputType = checkedInput.instructionType;
-    return inputType.isInMask(knownType, closedWorld);
+    AbstractValue inputType = checkedInput.instructionType;
+    return abstractValueDomain.isIn(inputType, knownType);
   }
 }
 
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 0b25f85..a0ce7be 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -18,7 +18,7 @@
 import '../native/native.dart' as native;
 import '../options.dart';
 import '../types/abstract_value_domain.dart';
-import '../types/masks.dart';
+//import '../types/masks.dart';
 import '../types/types.dart';
 import '../universe/selector.dart' show Selector;
 import '../universe/side_effects.dart' show SideEffects;
@@ -224,7 +224,7 @@
             instruction.isNumberOrNull(_abstractValueDomain))) {
           // If we can replace [instruction] with [replacement], then
           // [replacement]'s type can be narrowed.
-          TypeMask newType = _abstractValueDomain.intersection(
+          AbstractValue newType = _abstractValueDomain.intersection(
               replacement.instructionType, instruction.instructionType);
           replacement.instructionType = newType;
         }
@@ -256,9 +256,10 @@
   ConstantValue getConstantFromType(HInstruction node) {
     if (node.isValue(_abstractValueDomain) &&
         !node.canBeNull(_abstractValueDomain)) {
-      ValueTypeMask valueMask = node.instructionType;
-      if (valueMask.value.isBool) {
-        return valueMask.value;
+      ConstantValue value =
+          _abstractValueDomain.getPrimitiveValue(node.instructionType);
+      if (value.isBool) {
+        return value;
       }
       // TODO(het): consider supporting other values (short strings?)
     }
@@ -314,8 +315,8 @@
     if (_abstractValueDomain.isEmpty(input.instructionType)) return input;
 
     // All values that cannot be 'true' are boolified to false.
-    TypeMask mask = input.instructionType;
-    if (!mask.contains(commonElements.jsBoolClass, _closedWorld)) {
+    AbstractValue mask = input.instructionType;
+    if (!_abstractValueDomain.containsType(mask, commonElements.jsBoolClass)) {
       return _graph.addConstantBool(false, _closedWorld);
     }
     return node;
@@ -364,13 +365,13 @@
       }
       bool isFixed =
           isFixedLength(actualReceiver.instructionType, _closedWorld);
-      TypeMask actualType = node.instructionType;
-      TypeMask resultType = _abstractValueDomain.positiveIntType;
+      AbstractValue actualType = node.instructionType;
+      AbstractValue resultType = _abstractValueDomain.positiveIntType;
       // If we already have computed a more specific type, keep that type.
-      if (_abstractValueDomain.isInstanceOf(
+      if (_abstractValueDomain.isInstanceOfOrNull(
           actualType, commonElements.jsUInt31Class)) {
         resultType = _abstractValueDomain.uint31Type;
-      } else if (_abstractValueDomain.isInstanceOf(
+      } else if (_abstractValueDomain.isInstanceOfOrNull(
           actualType, commonElements.jsUInt32Class)) {
         resultType = _abstractValueDomain.uint32Type;
       }
@@ -406,12 +407,13 @@
     if (instruction != null) return instruction;
 
     Selector selector = node.selector;
-    TypeMask mask = node.mask;
+    AbstractValue mask = node.mask;
     HInstruction input = node.inputs[1];
 
     bool applies(MemberEntity element) {
       return selector.applies(element) &&
-          (mask == null || mask.canHit(element, selector, _closedWorld));
+          (mask == null ||
+              _abstractValueDomain.canHit(mask, element, selector));
     }
 
     if (selector.isCall || selector.isOperator) {
@@ -428,7 +430,7 @@
         }
       } else if (input.isStringOrNull(_abstractValueDomain)) {
         if (commonElements.appliesToJsStringSplit(
-            selector, mask, _closedWorld)) {
+            selector, mask, _abstractValueDomain)) {
           return handleStringSplit(node);
         } else if (applies(commonElements.jsStringOperatorAdd)) {
           // `operator+` is turned into a JavaScript '+' so we need to
@@ -486,7 +488,7 @@
     //     t4 = setRuntimeTypeInfo(t1, t3);
     //
 
-    TypeMask resultMask = _abstractValueDomain.growableListType;
+    AbstractValue resultMask = _abstractValueDomain.growableListType;
 
     HInvokeDynamicMethod splitInstruction = new HInvokeDynamicMethod(
         node.selector,
@@ -541,7 +543,8 @@
       if (folded != node) return folded;
     }
 
-    TypeMask receiverType = node.getDartReceiver(_closedWorld).instructionType;
+    AbstractValue receiverType =
+        node.getDartReceiver(_closedWorld).instructionType;
     MemberEntity element =
         _closedWorld.locateSingleMember(node.selector, receiverType);
     // TODO(ngeoffray): Also fold if it's a getter or variable.
@@ -579,7 +582,7 @@
       if (!_nativeData.isNativeMember(field) &&
           !node.isCallOnInterceptor(_closedWorld)) {
         HInstruction receiver = node.getDartReceiver(_closedWorld);
-        TypeMask type = TypeMaskFactory.inferredTypeForMember(
+        AbstractValue type = AbstractValueFactory.inferredTypeForMember(
             // ignore: UNNECESSARY_CAST
             field as Entity,
             _globalInferenceResults);
@@ -651,8 +654,8 @@
     // dependent instructions.
     native.NativeBehavior nativeBehavior =
         _nativeData.getNativeMethodBehavior(method);
-    TypeMask returnType =
-        TypeMaskFactory.fromNativeBehavior(nativeBehavior, _closedWorld);
+    AbstractValue returnType =
+        AbstractValueFactory.fromNativeBehavior(nativeBehavior, _closedWorld);
     HInvokeDynamicMethod result = new HInvokeDynamicMethod(
         node.selector,
         node.mask,
@@ -745,8 +748,8 @@
   HInstruction handleIdentityCheck(HRelational node) {
     HInstruction left = node.left;
     HInstruction right = node.right;
-    TypeMask leftType = left.instructionType;
-    TypeMask rightType = right.instructionType;
+    AbstractValue leftType = left.instructionType;
+    AbstractValue rightType = right.instructionType;
 
     HInstruction makeTrue() => _graph.addConstantBool(true, _closedWorld);
     HInstruction makeFalse() => _graph.addConstantBool(false, _closedWorld);
@@ -755,7 +758,7 @@
     // we don't optimize on numbers to preserve the runtime semantics.
     if (!(left.isNumberOrNull(_abstractValueDomain) &&
         right.isNumberOrNull(_abstractValueDomain))) {
-      if (leftType.isDisjoint(rightType, _closedWorld)) {
+      if (_abstractValueDomain.areDisjoint(leftType, rightType)) {
         return makeFalse();
       }
     }
@@ -910,14 +913,12 @@
       // a class [:A<T>:], is currently always considered to have the
       // raw type.
     } else if (!RuntimeTypesSubstitutions.hasTypeArguments(type)) {
-      TypeMask expressionMask = expression.instructionType;
-      assert(TypeMask.assertIsNormalized(expressionMask, _closedWorld));
-      TypeMask typeMask = (element == commonElements.nullClass)
-          ? new TypeMask.subtype(element, _closedWorld)
-          : new TypeMask.nonNullSubtype(element, _closedWorld);
-      if (expressionMask.union(typeMask, _closedWorld) == typeMask) {
+      AbstractValue expressionMask = expression.instructionType;
+      AbstractBool isInstanceOf =
+          _abstractValueDomain.isInstanceOf(expressionMask, element);
+      if (isInstanceOf == AbstractBool.True) {
         return _graph.addConstantBool(true, _closedWorld);
-      } else if (expressionMask.isDisjoint(typeMask, _closedWorld)) {
+      } else if (isInstanceOf == AbstractBool.False) {
         return _graph.addConstantBool(false, _closedWorld);
       }
     }
@@ -934,7 +935,7 @@
 
   FieldEntity findConcreteFieldForDynamicAccess(
       HInstruction receiver, Selector selector) {
-    TypeMask receiverType = receiver.instructionType;
+    AbstractValue receiverType = receiver.instructionType;
     return _closedWorld.locateSingleField(selector, receiverType);
   }
 
@@ -1043,12 +1044,12 @@
   HInstruction directFieldGet(HInstruction receiver, FieldEntity field) {
     bool isAssignable = !_closedWorld.fieldNeverChanges(field);
 
-    TypeMask type;
+    AbstractValue type;
     if (_nativeData.isNativeClass(field.enclosingClass)) {
-      type = TypeMaskFactory.fromNativeBehavior(
+      type = AbstractValueFactory.fromNativeBehavior(
           _nativeData.getNativeFieldLoadBehavior(field), _closedWorld);
     } else {
-      type = TypeMaskFactory.inferredTypeForMember(
+      type = AbstractValueFactory.inferredTypeForMember(
           // ignore: UNNECESSARY_CAST
           field as Entity,
           _globalInferenceResults);
@@ -1274,14 +1275,15 @@
       if (input.canBePrimitive(_abstractValueDomain)) return null;
       if (input.canBeNull(_abstractValueDomain)) return null;
       Selector selector = Selectors.toString_;
-      TypeMask toStringType = TypeMaskFactory.inferredTypeForSelector(
+      AbstractValue toStringType = AbstractValueFactory.inferredTypeForSelector(
           selector, input.instructionType, _globalInferenceResults);
-      if (!toStringType.containsOnlyString(_closedWorld)) return null;
+      if (!_abstractValueDomain.containsOnlyType(
+          toStringType, _closedWorld.commonElements.jsStringClass)) {
+        return null;
+      }
       // All intercepted classes extend `Interceptor`, so if the receiver can't
       // be a class extending `Interceptor` then it can be called directly.
-      if (new TypeMask.nonNullSubclass(
-              commonElements.jsInterceptorClass, _closedWorld)
-          .isDisjoint(input.instructionType, _closedWorld)) {
+      if (!_abstractValueDomain.canBeInterceptor(toStringType)) {
         var inputs = <HInstruction>[input, input]; // [interceptor, receiver].
         HInstruction result = new HInvokeDynamicMethod(
             selector,
@@ -1488,9 +1490,7 @@
       // be a class extending `Interceptor` then the substitution methods can be
       // called directly. (We don't care about Null since contexts reading class
       // type variables originate from instance methods.)
-      if (new TypeMask.nonNullSubclass(
-              commonElements.jsInterceptorClass, _closedWorld)
-          .isDisjoint(object.instructionType, _closedWorld)) {
+      if (!_abstractValueDomain.canBeInterceptor(object.instructionType)) {
         return new HTypeInfoReadVariable.noInterceptor(
             variable, object, node.instructionType);
       }
@@ -1539,7 +1539,7 @@
         isAssignable: !isFixedLength(array.instructionType, closedWorld));
     indexNode.block.addBefore(indexNode, length);
 
-    TypeMask type = indexArgument.isPositiveInteger(_abstractValueDomain)
+    AbstractValue type = indexArgument.isPositiveInteger(_abstractValueDomain)
         ? indexArgument.instructionType
         : closedWorld.abstractValueDomain.positiveIntType;
     HBoundsCheck check = new HBoundsCheck(indexArgument, length, array, type)
@@ -1607,7 +1607,7 @@
     if (zapInstructionCache == null) {
       // A constant with no type does not pollute types at phi nodes.
       ConstantValue constant = new SyntheticConstantValue(
-          SyntheticConstantKind.EMPTY_VALUE, const TypeMask.nonNullEmpty());
+          SyntheticConstantKind.EMPTY_VALUE, _abstractValueDomain.emptyType);
       zapInstructionCache = analyzer.graph.addConstant(constant, closedWorld);
     }
     return zapInstructionCache;
@@ -2459,7 +2459,7 @@
   // on the control flow, we mark the inserted [HTypeKnown] nodes as
   // non-movable.
   void insertTypePropagationForDominatedUsers(
-      HBasicBlock dominator, HInstruction input, TypeMask convertedType) {
+      HBasicBlock dominator, HInstruction input, AbstractValue convertedType) {
     DominatedUses dominatedUses = DominatedUses.of(input, dominator.first);
     if (dominatedUses.isEmpty) return;
 
@@ -2498,7 +2498,8 @@
 
     if (trueTargets.isEmpty && falseTargets.isEmpty) return;
 
-    TypeMask convertedType = new TypeMask.nonNullSubtype(cls, closedWorld);
+    AbstractValue convertedType =
+        _abstractValueDomain.createNonNullSubtype(cls);
     HInstruction input = instruction.expression;
 
     for (HBasicBlock block in trueTargets) {
@@ -2531,7 +2532,7 @@
 
     if (trueTargets.isEmpty && falseTargets.isEmpty) return;
 
-    TypeMask nonNullType =
+    AbstractValue nonNullType =
         _abstractValueDomain.excludeNull(input.instructionType);
 
     for (HBasicBlock block in falseTargets) {
@@ -3083,7 +3084,7 @@
         }
       }
     }
-    TypeMask phiType = _abstractValueDomain.union(
+    AbstractValue phiType = _abstractValueDomain.union(
         second.instructionType, first.instructionType);
     if (first is HPhi && first.block == block) {
       HPhi phi = first;
diff --git a/pkg/compiler/lib/src/ssa/type_builder.dart b/pkg/compiler/lib/src/ssa/type_builder.dart
index 6e4c5bb..95cb53e 100644
--- a/pkg/compiler/lib/src/ssa/type_builder.dart
+++ b/pkg/compiler/lib/src/ssa/type_builder.dart
@@ -7,7 +7,7 @@
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../io/source_information.dart';
-import '../types/masks.dart';
+import '../types/abstract_value_domain.dart';
 import '../universe/use.dart' show TypeUse;
 
 /// Enum that defines how a member has access to the current type variables.
@@ -40,7 +40,7 @@
 
   /// Create a type mask for 'trusting' a DartType. Returns `null` if there is
   /// no approximating type mask (i.e. the type mask would be `dynamic`).
-  TypeMask trustTypeMask(DartType type) {
+  AbstractValue trustTypeMask(DartType type) {
     if (type == null) return null;
     type = builder.localsHandler.substInContext(type);
     type = type.unaliased;
@@ -49,13 +49,13 @@
     if (type == builder.commonElements.objectType) return null;
     // The type element is either a class or the void element.
     ClassEntity element = (type as InterfaceType).element;
-    return new TypeMask.subtype(element, builder.closedWorld);
+    return builder.abstractValueDomain.createNullableSubtype(element);
   }
 
   /// Create an instruction to simply trust the provided type.
   HInstruction _trustType(HInstruction original, DartType type) {
     assert(type != null);
-    TypeMask mask = trustTypeMask(type);
+    AbstractValue mask = trustTypeMask(type);
     if (mask == null) return original;
     return new HTypeKnown.pinned(mask, original);
   }
@@ -273,8 +273,8 @@
     type = type.unaliased;
     if (type.isInterfaceType && !type.treatAsRaw) {
       InterfaceType interfaceType = type;
-      TypeMask subtype =
-          new TypeMask.subtype(interfaceType.element, builder.closedWorld);
+      AbstractValue subtype = builder.abstractValueDomain
+          .createNullableSubtype(interfaceType.element);
       HInstruction representations = buildTypeArgumentRepresentations(
           type, builder.sourceElement, sourceInformation);
       builder.add(representations);
@@ -282,7 +282,7 @@
           type, kind, subtype, original, representations)
         ..sourceInformation = sourceInformation;
     } else if (type.isTypeVariable) {
-      TypeMask subtype = original.instructionType;
+      AbstractValue subtype = original.instructionType;
       HInstruction typeVariable =
           addTypeVariableReference(type, builder.sourceElement);
       return new HTypeConversion.withTypeRepresentation(
@@ -292,7 +292,7 @@
       HInstruction reifiedType =
           analyzeTypeArgument(type, builder.sourceElement);
       // TypeMasks don't encode function types or FutureOr types.
-      TypeMask refinedMask = original.instructionType;
+      AbstractValue refinedMask = original.instructionType;
       return new HTypeConversion.withTypeRepresentation(
           type, kind, refinedMask, original, reifiedType)
         ..sourceInformation = sourceInformation;
diff --git a/pkg/compiler/lib/src/ssa/types.dart b/pkg/compiler/lib/src/ssa/types.dart
index 9e938c4..6e7ee44 100644
--- a/pkg/compiler/lib/src/ssa/types.dart
+++ b/pkg/compiler/lib/src/ssa/types.dart
@@ -5,63 +5,66 @@
 import '../common_elements.dart' show CommonElements;
 import '../elements/entities.dart';
 import '../native/native.dart' as native;
-import '../types/masks.dart';
+import '../types/abstract_value_domain.dart';
 import '../types/types.dart';
 import '../universe/selector.dart' show Selector;
 import '../world.dart' show ClosedWorld;
 
-class TypeMaskFactory {
-  static TypeMask inferredReturnTypeForElement(
+class AbstractValueFactory {
+  static AbstractValue inferredReturnTypeForElement(
       FunctionEntity element, GlobalTypeInferenceResults results) {
     return results.resultOfMember(element).returnType ??
         results.closedWorld.abstractValueDomain.dynamicType;
   }
 
-  static TypeMask inferredTypeForMember(
+  static AbstractValue inferredTypeForMember(
       MemberEntity element, GlobalTypeInferenceResults results) {
     return results.resultOfMember(element).type ??
         results.closedWorld.abstractValueDomain.dynamicType;
   }
 
-  static TypeMask inferredTypeForParameter(
+  static AbstractValue inferredTypeForParameter(
       Local element, GlobalTypeInferenceResults results) {
     return results.resultOfParameter(element).type ??
         results.closedWorld.abstractValueDomain.dynamicType;
   }
 
-  static TypeMask inferredTypeForSelector(
-      Selector selector, TypeMask mask, GlobalTypeInferenceResults results) {
-    return results.typeOfSelector(selector, mask) ??
+  static AbstractValue inferredTypeForSelector(Selector selector,
+      AbstractValue receiver, GlobalTypeInferenceResults results) {
+    return results.typeOfSelector(selector, receiver) ??
         results.closedWorld.abstractValueDomain.dynamicType;
   }
 
-  static TypeMask fromNativeBehavior(
+  static AbstractValue fromNativeBehavior(
       native.NativeBehavior nativeBehavior, ClosedWorld closedWorld) {
-    CommonMasks commonMasks = closedWorld.abstractValueDomain;
+    AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
     var typesReturned = nativeBehavior.typesReturned;
-    if (typesReturned.isEmpty) return commonMasks.dynamicType;
+    if (typesReturned.isEmpty) return abstractValueDomain.dynamicType;
 
     CommonElements commonElements = closedWorld.commonElements;
 
     // [type] is either an instance of [DartType] or special objects
     // like [native.SpecialType.JsObject].
-    TypeMask fromNativeType(dynamic type) {
+    AbstractValue fromNativeType(dynamic type) {
       if (type == native.SpecialType.JsObject) {
-        return new TypeMask.nonNullExact(
-            commonElements.objectClass, closedWorld);
+        return abstractValueDomain
+            .createNonNullExact(commonElements.objectClass);
+      } else if (type.isVoid) {
+        return abstractValueDomain.nullType;
+      } else if (type.isDynamic) {
+        return abstractValueDomain.dynamicType;
+      } else if (type == commonElements.nullType) {
+        return abstractValueDomain.nullType;
+      } else if (type.treatAsDynamic) {
+        return abstractValueDomain.dynamicType;
+      } else {
+        return abstractValueDomain.createNonNullSubtype(type.element);
       }
-
-      if (type.isVoid) return commonMasks.nullType;
-      if (type.isDynamic) return commonMasks.dynamicType;
-      if (type.element == commonElements.nullClass) return commonMasks.nullType;
-      if (type.treatAsDynamic) return commonMasks.dynamicType;
-      return new TypeMask.nonNullSubtype(type.element, closedWorld);
     }
 
-    TypeMask result = typesReturned
-        .map(fromNativeType)
-        .reduce((t1, t2) => t1.union(t2, closedWorld));
-    assert(!result.isEmpty);
+    AbstractValue result =
+        abstractValueDomain.unionOfMany(typesReturned.map(fromNativeType));
+    assert(!abstractValueDomain.isEmpty(result));
     return result;
   }
 }
diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart
index 1130029..bbc5153 100644
--- a/pkg/compiler/lib/src/types/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/types/abstract_value_domain.dart
@@ -8,6 +8,8 @@
 import '../elements/entities.dart';
 import '../universe/selector.dart';
 
+enum AbstractBool { True, False, Maybe }
+
 /// A value in an abstraction of runtime values.
 abstract class AbstractValue {}
 
@@ -89,12 +91,20 @@
   /// The [AbstractValue] that represents the empty set of runtime values.
   AbstractValue get emptyType;
 
-  /// Creates an [AbstractValue] for non-null exact instance of [cls].
+  /// Creates an [AbstractValue] for a non-null exact instance of [cls].
   AbstractValue createNonNullExact(ClassEntity cls);
 
-  /// Creates an [AbstractValue] for non-null instance that implements [cls].
+  /// Creates an [AbstractValue] for a potentially null exact instance of [cls].
+  AbstractValue createNullableExact(ClassEntity cls);
+
+  /// Creates an [AbstractValue] for a non-null instance that extends [cls].
+  AbstractValue createNonNullSubclass(ClassEntity cls);
+
+  /// Creates an [AbstractValue] for a non-null instance that implements [cls].
   AbstractValue createNonNullSubtype(ClassEntity cls);
 
+  /// Creates an [AbstractValue] for a potentially null instance that implements
+  /// [cls].
   AbstractValue createNullableSubtype(ClassEntity cls);
 
   /// Returns `true` if [value] is a native typed array or `null` at runtime.
@@ -117,7 +127,18 @@
   bool containsOnlyType(covariant AbstractValue value, ClassEntity cls);
 
   /// Returns `true` if [value] is an instance of [cls] or `null` at runtime.
-  bool isInstanceOf(covariant AbstractValue value, ClassEntity cls);
+  // TODO(johnniwinther): Merge this with [isInstanceOf].
+  bool isInstanceOfOrNull(covariant AbstractValue value, ClassEntity cls);
+
+  /// Returns an [AbstractBool] that describes how [value] is known to be an
+  /// instance of [cls] at runtime.
+  ///
+  /// If the returned value is `Abstract.True`, [value] is known _always_ to be
+  /// an instance of [cls]. If the returned value is `Abstract.False`, [value]
+  /// is known _never_ to be an instance of [cls]. If the returned value is
+  /// `Abstract.Maybe` [value] might or might not be an instance of [cls] at
+  /// runtime.
+  AbstractBool isInstanceOf(AbstractValue value, ClassEntity cls);
 
   /// Returns `true` if [value] is empty set of runtime values.
   bool isEmpty(covariant AbstractValue value);
@@ -126,7 +147,7 @@
   bool isExact(covariant AbstractValue value);
 
   /// Returns `true` if [value] a known primitive JavaScript value at runtime.
-  bool isValue(covariant AbstractValue value);
+  bool isPrimitiveValue(covariant AbstractValue value);
 
   /// Returns `true` if [value] can be `null` at runtime.
   bool canBeNull(covariant AbstractValue value);
@@ -174,6 +195,9 @@
   /// Returns `true` if [value] could be a JavaScript string at runtime.
   bool canBePrimitiveString(covariant AbstractValue value);
 
+  /// Return `true` if [value] could be an interceptor at runtime.
+  bool canBeInterceptor(covariant AbstractValue value);
+
   /// Returns `true` if [value] is a non-null integer value at runtime.
   bool isInteger(covariant AbstractValue value);
 
@@ -233,7 +257,7 @@
 
   /// Returns [AbstractValue] for the runtime values contained in at least one
   /// of [values].
-  AbstractValue unionOfMany(List<AbstractValue> values);
+  AbstractValue unionOfMany(Iterable<AbstractValue> values);
 
   /// Returns [AbstractValue] for the runtime values that [a] and [b] have in
   /// common.
@@ -257,6 +281,11 @@
   /// Returns [dynamicType] otherwise.
   AbstractValue getMapValueType(AbstractValue value);
 
+  /// Returns the primitive JavaScript value of [value] if it represents a
+  /// primitive JavaScript value at runtime, value at runtime. Returns `null`
+  /// otherwise.
+  ConstantValue getPrimitiveValue(covariant AbstractValue value);
+
   /// Compute the type of all potential receivers of the set of live [members].
   AbstractValue computeReceiver(Iterable<MemberEntity> members);
 
@@ -273,6 +302,10 @@
   /// of runtime values of [superset].
   bool contains(AbstractValue superset, AbstractValue subset);
 
+  /// Returns `true` if the set of runtime values of [subset] are all in the set
+  /// of runtime values of [superset].
+  bool isIn(AbstractValue subset, AbstractValue superset);
+
   /// Returns the [MemberEntity] that is known to always be hit at runtime
   /// [receiver].
   ///
diff --git a/pkg/compiler/lib/src/types/masks.dart b/pkg/compiler/lib/src/types/masks.dart
index c8a17fb..aba1f0a 100644
--- a/pkg/compiler/lib/src/types/masks.dart
+++ b/pkg/compiler/lib/src/types/masks.dart
@@ -79,59 +79,77 @@
     return cachedMasks.putIfAbsent(base, createMask);
   }
 
+  @override
   TypeMask get dynamicType => _dynamicType ??= new TypeMask.subclass(
       _closedWorld.commonElements.objectClass, _closedWorld);
 
+  @override
   TypeMask get nonNullType => _nonNullType ??= new TypeMask.nonNullSubclass(
       _closedWorld.commonElements.objectClass, _closedWorld);
 
+  @override
   TypeMask get intType => _intType ??=
       new TypeMask.nonNullSubclass(commonElements.jsIntClass, _closedWorld);
 
+  @override
   TypeMask get uint32Type => _uint32Type ??=
       new TypeMask.nonNullSubclass(commonElements.jsUInt32Class, _closedWorld);
 
+  @override
   TypeMask get uint31Type => _uint31Type ??=
       new TypeMask.nonNullExact(commonElements.jsUInt31Class, _closedWorld);
 
+  @override
   TypeMask get positiveIntType =>
       _positiveIntType ??= new TypeMask.nonNullSubclass(
           commonElements.jsPositiveIntClass, _closedWorld);
 
+  @override
   TypeMask get doubleType => _doubleType ??=
       new TypeMask.nonNullExact(commonElements.jsDoubleClass, _closedWorld);
 
+  @override
   TypeMask get numType => _numType ??=
       new TypeMask.nonNullSubclass(commonElements.jsNumberClass, _closedWorld);
 
+  @override
   TypeMask get boolType => _boolType ??=
       new TypeMask.nonNullExact(commonElements.jsBoolClass, _closedWorld);
 
+  @override
   TypeMask get functionType => _functionType ??=
       new TypeMask.nonNullSubtype(commonElements.functionClass, _closedWorld);
 
+  @override
   TypeMask get listType => _listType ??=
       new TypeMask.nonNullExact(commonElements.jsArrayClass, _closedWorld);
 
+  @override
   TypeMask get constListType => _constListType ??= new TypeMask.nonNullExact(
       commonElements.jsUnmodifiableArrayClass, _closedWorld);
 
+  @override
   TypeMask get fixedListType => _fixedListType ??=
       new TypeMask.nonNullExact(commonElements.jsFixedArrayClass, _closedWorld);
 
+  @override
   TypeMask get growableListType =>
       _growableListType ??= new TypeMask.nonNullExact(
           commonElements.jsExtendableArrayClass, _closedWorld);
 
+  @override
   TypeMask get mapType => _mapType ??=
       new TypeMask.nonNullSubtype(commonElements.mapLiteralClass, _closedWorld);
 
+  @override
   TypeMask get constMapType => _constMapType ??= new TypeMask.nonNullSubtype(
       commonElements.constMapLiteralClass, _closedWorld);
 
+  @override
   TypeMask get stringType => _stringType ??=
       new TypeMask.nonNullExact(commonElements.jsStringClass, _closedWorld);
 
+  @override
   TypeMask get typeType => _typeType ??=
       new TypeMask.nonNullExact(commonElements.typeLiteralClass, _closedWorld);
 
@@ -146,8 +164,10 @@
       new TypeMask.nonNullExact(commonElements.controllerStream, _closedWorld);
 
   // TODO(johnniwinther): Assert that the null type has been resolved.
+  @override
   TypeMask get nullType => _nullType ??= const TypeMask.empty();
 
+  @override
   TypeMask get emptyType => const TypeMask.nonNullEmpty();
 
   TypeMask get indexablePrimitiveType =>
@@ -169,6 +189,7 @@
       _interceptorType ??= new TypeMask.nonNullSubclass(
           commonElements.jsInterceptorClass, _closedWorld);
 
+  @override
   bool isTypedArray(TypeMask mask) {
     // Just checking for `TypedData` is not sufficient, as it is an abstract
     // class any user-defined class can implement. So we also check for the
@@ -181,6 +202,7 @@
             _closedWorld);
   }
 
+  @override
   bool couldBeTypedArray(TypeMask mask) {
     bool intersects(TypeMask type1, TypeMask type2) =>
         !type1.intersection(type2, _closedWorld).isEmpty;
@@ -197,47 +219,94 @@
                 _closedWorld));
   }
 
+  @override
   TypeMask createNonNullExact(ClassEntity cls) {
     return new TypeMask.nonNullExact(cls, _closedWorld);
   }
 
+  @override
+  TypeMask createNullableExact(ClassEntity cls) {
+    return new TypeMask.exact(cls, _closedWorld);
+  }
+
+  @override
+  TypeMask createNonNullSubclass(ClassEntity cls) {
+    return new TypeMask.nonNullSubclass(cls, _closedWorld);
+  }
+
+  @override
   TypeMask createNonNullSubtype(ClassEntity cls) {
     return new TypeMask.nonNullSubtype(cls, _closedWorld);
   }
 
+  @override
   TypeMask createNullableSubtype(ClassEntity cls) {
     return new TypeMask.subtype(cls, _closedWorld);
   }
 
+  @override
   TypeMask excludeNull(TypeMask mask) => mask.nonNullable();
 
   @override
   TypeMask includeNull(TypeMask mask) => mask.nullable();
 
+  @override
   bool containsType(TypeMask typeMask, ClassEntity cls) {
     return _closedWorld.isInstantiated(cls) &&
         typeMask.contains(cls, _closedWorld);
   }
 
+  @override
   bool containsOnlyType(TypeMask typeMask, ClassEntity cls) {
     return _closedWorld.isInstantiated(cls) && typeMask.containsOnly(cls);
   }
 
-  bool isInstanceOf(TypeMask typeMask, ClassEntity cls) {
+  @override
+  bool isInstanceOfOrNull(TypeMask typeMask, ClassEntity cls) {
     return _closedWorld.isImplemented(cls) &&
         typeMask.satisfies(cls, _closedWorld);
   }
 
+  @override
+  AbstractBool isInstanceOf(
+      covariant TypeMask expressionMask, ClassEntity cls) {
+    AbstractValue typeMask = (cls == commonElements.nullClass)
+        ? createNullableSubtype(cls)
+        : createNonNullSubtype(cls);
+    if (expressionMask.union(typeMask, _closedWorld) == typeMask) {
+      return AbstractBool.True;
+    } else if (expressionMask.isDisjoint(typeMask, _closedWorld)) {
+      return AbstractBool.False;
+    } else {
+      return AbstractBool.Maybe;
+    }
+  }
+
+  @override
   bool isEmpty(TypeMask value) => value.isEmpty;
 
+  @override
   bool isExact(TypeMask value) => value.isExact || isNull(value);
 
-  bool isValue(TypeMask value) => value.isValue;
+  @override
+  bool isPrimitiveValue(TypeMask value) => value.isValue;
 
+  @override
+  ConstantValue getPrimitiveValue(TypeMask mask) {
+    if (mask.isValue) {
+      ValueTypeMask valueMask = mask;
+      return valueMask.value;
+    }
+    return null;
+  }
+
+  @override
   bool canBeNull(TypeMask value) => value.isNullable;
 
+  @override
   bool isNull(TypeMask value) => value.isNull;
 
+  @override
   bool canBePrimitive(TypeMask value) {
     return canBePrimitiveNumber(value) ||
         canBePrimitiveArray(value) ||
@@ -246,6 +315,7 @@
         isNull(value);
   }
 
+  @override
   bool canBePrimitiveNumber(TypeMask value) {
     // TODO(sra): It should be possible to test only jsDoubleClass and
     // jsUInt31Class, since all others are superclasses of these two.
@@ -257,10 +327,12 @@
         containsType(value, commonElements.jsDoubleClass);
   }
 
+  @override
   bool canBePrimitiveBoolean(TypeMask value) {
     return containsType(value, commonElements.jsBoolClass);
   }
 
+  @override
   bool canBePrimitiveArray(TypeMask value) {
     return containsType(value, commonElements.jsArrayClass) ||
         containsType(value, commonElements.jsFixedArrayClass) ||
@@ -268,102 +340,123 @@
         containsType(value, commonElements.jsUnmodifiableArrayClass);
   }
 
+  @override
   bool isIndexablePrimitive(TypeMask value) {
     return value.containsOnlyString(_closedWorld) ||
-        isInstanceOf(value, commonElements.jsIndexableClass);
+        isInstanceOfOrNull(value, commonElements.jsIndexableClass);
   }
 
+  @override
   bool isFixedArray(TypeMask value) {
     // TODO(sra): Recognize the union of these types as well.
     return containsOnlyType(value, commonElements.jsFixedArrayClass) ||
         containsOnlyType(value, commonElements.jsUnmodifiableArrayClass);
   }
 
+  @override
   bool isExtendableArray(TypeMask value) {
     return containsOnlyType(value, commonElements.jsExtendableArrayClass);
   }
 
+  @override
   bool isMutableArray(TypeMask value) {
-    return isInstanceOf(value, commonElements.jsMutableArrayClass);
+    return isInstanceOfOrNull(value, commonElements.jsMutableArrayClass);
   }
 
-  bool isReadableArray(TypeMask value) {
-    return isInstanceOf(value, commonElements.jsArrayClass);
-  }
-
+  @override
   bool isMutableIndexable(TypeMask value) {
-    return isInstanceOf(value, commonElements.jsMutableIndexableClass);
+    return isInstanceOfOrNull(value, commonElements.jsMutableIndexableClass);
   }
 
-  bool isArray(TypeMask value) => isReadableArray(value);
+  @override
+  bool isArray(TypeMask value) {
+    return isInstanceOfOrNull(value, commonElements.jsArrayClass);
+  }
 
+  @override
   bool canBePrimitiveString(TypeMask value) {
     return containsType(value, commonElements.jsStringClass);
   }
 
+  @override
   bool isInteger(TypeMask value) {
     return value.containsOnlyInt(_closedWorld) && !value.isNullable;
   }
 
+  @override
   bool isUInt32(TypeMask value) {
     return !value.isNullable &&
-        isInstanceOf(value, commonElements.jsUInt32Class);
+        isInstanceOfOrNull(value, commonElements.jsUInt32Class);
   }
 
+  @override
   bool isUInt31(TypeMask value) {
     return !value.isNullable &&
-        isInstanceOf(value, commonElements.jsUInt31Class);
+        isInstanceOfOrNull(value, commonElements.jsUInt31Class);
   }
 
+  @override
   bool isPositiveInteger(TypeMask value) {
     return !value.isNullable &&
-        isInstanceOf(value, commonElements.jsPositiveIntClass);
+        isInstanceOfOrNull(value, commonElements.jsPositiveIntClass);
   }
 
+  @override
   bool isPositiveIntegerOrNull(TypeMask value) {
-    return isInstanceOf(value, commonElements.jsPositiveIntClass);
+    return isInstanceOfOrNull(value, commonElements.jsPositiveIntClass);
   }
 
+  @override
   bool isIntegerOrNull(TypeMask value) {
     return value.containsOnlyInt(_closedWorld);
   }
 
+  @override
   bool isNumber(TypeMask value) {
     return value.containsOnlyNum(_closedWorld) && !value.isNullable;
   }
 
+  @override
   bool isNumberOrNull(TypeMask value) {
     return value.containsOnlyNum(_closedWorld);
   }
 
+  @override
   bool isDouble(TypeMask value) {
     return value.containsOnlyDouble(_closedWorld) && !value.isNullable;
   }
 
+  @override
   bool isDoubleOrNull(TypeMask value) {
     return value.containsOnlyDouble(_closedWorld);
   }
 
+  @override
   bool isBoolean(TypeMask value) {
     return value.containsOnlyBool(_closedWorld) && !value.isNullable;
   }
 
+  @override
   bool isBooleanOrNull(TypeMask value) {
     return value.containsOnlyBool(_closedWorld);
   }
 
+  @override
   bool isString(TypeMask value) {
     return value.containsOnlyString(_closedWorld) && !value.isNullable;
   }
 
+  @override
   bool isStringOrNull(TypeMask value) {
     return value.containsOnlyString(_closedWorld);
   }
 
+  @override
   bool isPrimitive(TypeMask value) {
     return (isPrimitiveOrNull(value) && !value.isNullable) || isNull(value);
   }
 
+  @override
   bool isPrimitiveOrNull(TypeMask value) {
     return isIndexablePrimitive(value) ||
         isNumberOrNull(value) ||
@@ -371,13 +464,17 @@
         isNull(value);
   }
 
+  @override
   TypeMask union(TypeMask a, TypeMask b) => a.union(b, _closedWorld);
 
+  @override
   TypeMask intersection(TypeMask a, TypeMask b) =>
       a.intersection(b, _closedWorld);
 
+  @override
   bool areDisjoint(TypeMask a, TypeMask b) => a.isDisjoint(b, _closedWorld);
 
+  @override
   bool containsAll(TypeMask a) => a.containsAll(_closedWorld);
 
   @override
@@ -402,7 +499,7 @@
   }
 
   @override
-  AbstractValue unionOfMany(List<AbstractValue> values) {
+  AbstractValue unionOfMany(Iterable<AbstractValue> values) {
     TypeMask result = const TypeMask.nonNullEmpty();
     for (TypeMask value in values) {
       result = result.union(value, _closedWorld);
@@ -449,6 +546,11 @@
   }
 
   @override
+  bool isIn(covariant TypeMask subset, covariant TypeMask superset) {
+    return subset.isInMask(superset, _closedWorld);
+  }
+
+  @override
   MemberEntity locateSingleMember(
       covariant TypeMask receiver, Selector selector) {
     return receiver.locateSingleMember(selector, _closedWorld);
@@ -480,4 +582,9 @@
     }
     return false;
   }
+
+  @override
+  bool canBeInterceptor(TypeMask value) {
+    return !interceptorType.isDisjoint(value, _closedWorld);
+  }
 }