Move the JavaScript constant system into constants/constant_system.dart
in preparation to merge it with the base constant system and flatten the
constant system hierarchy.

Change-Id: I6ef27b210515140d4516336fea015f74c8a0cd6a
Reviewed-on: https://dart-review.googlesource.com/c/93840
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 2e39905..744318e 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -7,12 +7,12 @@
 
 import 'common.dart';
 import 'common/names.dart' show Identifiers, Uris;
+import 'constants/constant_system.dart';
 import 'constants/expressions.dart' show ConstantExpression;
 import 'constants/values.dart';
 import 'elements/entities.dart';
 import 'elements/types.dart';
 import 'inferrer/abstract_value_domain.dart';
-import 'js_backend/constant_system_javascript.dart';
 import 'js_backend/native_data.dart' show NativeBasicData;
 import 'kernel/dart2js_target.dart';
 import 'universe/selector.dart' show Selector;
diff --git a/pkg/compiler/lib/src/constants/constant_system.dart b/pkg/compiler/lib/src/constants/constant_system.dart
index e5172ac..17d0688 100644
--- a/pkg/compiler/lib/src/constants/constant_system.dart
+++ b/pkg/compiler/lib/src/constants/constant_system.dart
@@ -5,6 +5,7 @@
 library dart2js.constant_system;
 
 import '../common_elements.dart' show CommonElements;
+import '../elements/entities.dart';
 import '../elements/operators.dart';
 import '../elements/types.dart';
 import 'values.dart';
@@ -24,6 +25,596 @@
   apply(left, right);
 }
 
+class JavaScriptBitNotOperation implements UnaryOperation {
+  final String name = '~';
+  const JavaScriptBitNotOperation();
+
+  ConstantValue fold(ConstantValue constant) {
+    if (JavaScriptConstantSystem.only.isInt(constant)) {
+      // In JavaScript we don't check for -0 and treat it as if it was zero.
+      if (constant.isMinusZero) {
+        constant = JavaScriptConstantSystem.only.createInt(BigInt.zero);
+      }
+      IntConstantValue intConstant = constant;
+      // We convert the result of bit-operations to 32 bit unsigned integers.
+      return JavaScriptConstantSystem.only.createInt32(~intConstant.intValue);
+    }
+    return null;
+  }
+}
+
+class NegateOperation implements UnaryOperation {
+  final String name = 'negate';
+  const NegateOperation();
+  ConstantValue fold(ConstantValue constant) {
+    if (constant.isInt) {
+      IntConstantValue intConstant = constant;
+      return JavaScriptConstantSystem.only.createInt(-intConstant.intValue);
+    }
+    if (constant.isDouble) {
+      DoubleConstantValue doubleConstant = constant;
+      return JavaScriptConstantSystem.only
+          .createDouble(-doubleConstant.doubleValue);
+    }
+    return null;
+  }
+}
+
+class JavaScriptNegateOperation implements UnaryOperation {
+  final NegateOperation dartNegateOperation = const NegateOperation();
+
+  const JavaScriptNegateOperation();
+
+  String get name => dartNegateOperation.name;
+
+  ConstantValue fold(ConstantValue constant) {
+    if (constant.isInt) {
+      IntConstantValue intConstant = constant;
+      if (intConstant.intValue == BigInt.zero) {
+        return JavaScriptConstantSystem.only.createDouble(-0.0);
+      }
+    }
+    return dartNegateOperation.fold(constant);
+  }
+}
+
+class NotOperation implements UnaryOperation {
+  final String name = '!';
+  const NotOperation();
+  ConstantValue fold(ConstantValue constant) {
+    if (constant.isBool) {
+      BoolConstantValue boolConstant = constant;
+      return JavaScriptConstantSystem.only.createBool(!boolConstant.boolValue);
+    }
+    return null;
+  }
+}
+
+/// Operations that only work if both arguments are integers.
+abstract class BinaryBitOperation implements BinaryOperation {
+  const BinaryBitOperation();
+  ConstantValue fold(ConstantValue left, ConstantValue right) {
+    if (left.isInt && right.isInt) {
+      IntConstantValue leftInt = left;
+      IntConstantValue rightInt = right;
+      BigInt resultValue = foldInts(leftInt.intValue, rightInt.intValue);
+      if (resultValue == null) return null;
+      return JavaScriptConstantSystem.only.createInt(resultValue);
+    }
+    return null;
+  }
+
+  BigInt foldInts(BigInt left, BigInt right);
+}
+
+/// In JavaScript we truncate the result to an unsigned 32 bit integer. Also, -0
+/// is treated as if it was the integer 0.
+class JavaScriptBinaryBitOperation implements BinaryOperation {
+  final BinaryBitOperation dartBitOperation;
+
+  const JavaScriptBinaryBitOperation(this.dartBitOperation);
+
+  String get name => dartBitOperation.name;
+
+  ConstantValue fold(ConstantValue left, ConstantValue right) {
+    // In JavaScript we don't check for -0 and treat it as if it was zero.
+    if (left.isMinusZero) {
+      left = JavaScriptConstantSystem.only.createInt(BigInt.zero);
+    }
+    if (right.isMinusZero) {
+      right = JavaScriptConstantSystem.only.createInt(BigInt.zero);
+    }
+    IntConstantValue result = dartBitOperation.fold(left, right);
+    if (result != null) {
+      // We convert the result of bit-operations to 32 bit unsigned integers.
+      return JavaScriptConstantSystem.only.createInt32(result.intValue);
+    }
+    return result;
+  }
+
+  apply(left, right) => dartBitOperation.apply(left, right);
+}
+
+class BitAndOperation extends BinaryBitOperation {
+  final String name = '&';
+  const BitAndOperation();
+  BigInt foldInts(BigInt left, BigInt right) => left & right;
+  apply(left, right) => left & right;
+}
+
+class BitOrOperation extends BinaryBitOperation {
+  final String name = '|';
+  const BitOrOperation();
+  BigInt foldInts(BigInt left, BigInt right) => left | right;
+  apply(left, right) => left | right;
+}
+
+class BitXorOperation extends BinaryBitOperation {
+  final String name = '^';
+  const BitXorOperation();
+  BigInt foldInts(BigInt left, BigInt right) => left ^ right;
+  apply(left, right) => left ^ right;
+}
+
+class ShiftLeftOperation extends BinaryBitOperation {
+  final String name = '<<';
+  const ShiftLeftOperation();
+  BigInt foldInts(BigInt left, BigInt right) {
+    // TODO(floitsch): find a better way to guard against excessive shifts to
+    // the left.
+    if (right > new BigInt.from(100) || right < BigInt.zero) return null;
+    return left << right.toInt();
+  }
+
+  apply(left, right) => left << right;
+}
+
+class ShiftRightOperation extends BinaryBitOperation {
+  final String name = '>>';
+  const ShiftRightOperation();
+  BigInt foldInts(BigInt left, BigInt right) {
+    if (right < BigInt.zero) return null;
+    return left >> right.toInt();
+  }
+
+  apply(left, right) => left >> right;
+}
+
+class JavaScriptShiftRightOperation extends JavaScriptBinaryBitOperation {
+  const JavaScriptShiftRightOperation() : super(const ShiftRightOperation());
+
+  ConstantValue fold(ConstantValue left, ConstantValue right) {
+    // Truncate the input value to 32 bits if necessary.
+    if (left.isInt) {
+      IntConstantValue intConstant = left;
+      BigInt value = intConstant.intValue;
+      BigInt truncatedValue = value & JavaScriptConstantSystem.only.BITS32;
+      if (value < BigInt.zero) {
+        // Sign-extend if the input was negative. The current semantics don't
+        // make much sense, since we only look at bit 31.
+        // TODO(floitsch): we should treat the input to right shifts as
+        // unsigned.
+
+        // A 32 bit complement-two value x can be computed by:
+        //    x_u - 2^32 (where x_u is its unsigned representation).
+        // Example: 0xFFFFFFFF - 0x100000000 => -1.
+        // We simply and with the sign-bit and multiply by two. If the sign-bit
+        // was set, then the result is 0. Otherwise it will become 2^32.
+        final BigInt SIGN_BIT = new BigInt.from(0x80000000);
+        truncatedValue -= BigInt.two * (truncatedValue & SIGN_BIT);
+      }
+      if (value != truncatedValue) {
+        left = JavaScriptConstantSystem.only.createInt(truncatedValue);
+      }
+    }
+    return super.fold(left, right);
+  }
+}
+
+abstract class BinaryBoolOperation implements BinaryOperation {
+  const BinaryBoolOperation();
+  ConstantValue fold(ConstantValue left, ConstantValue right) {
+    if (left.isBool && right.isBool) {
+      BoolConstantValue leftBool = left;
+      BoolConstantValue rightBool = right;
+      bool resultValue = foldBools(leftBool.boolValue, rightBool.boolValue);
+      return JavaScriptConstantSystem.only.createBool(resultValue);
+    }
+    return null;
+  }
+
+  bool foldBools(bool left, bool right);
+}
+
+class BooleanAndOperation extends BinaryBoolOperation {
+  final String name = '&&';
+  const BooleanAndOperation();
+  bool foldBools(bool left, bool right) => left && right;
+  apply(left, right) => left && right;
+}
+
+class BooleanOrOperation extends BinaryBoolOperation {
+  final String name = '||';
+  const BooleanOrOperation();
+  bool foldBools(bool left, bool right) => left || right;
+  apply(left, right) => left || right;
+}
+
+abstract class ArithmeticNumOperation implements BinaryOperation {
+  const ArithmeticNumOperation();
+  ConstantValue fold(ConstantValue left, ConstantValue right) {
+    if (left.isNum && right.isNum) {
+      NumConstantValue leftNum = left;
+      NumConstantValue rightNum = right;
+      var foldedValue;
+      if (left.isInt && right.isInt) {
+        IntConstantValue leftInt = leftNum;
+        IntConstantValue rightInt = rightNum;
+        foldedValue = foldInts(leftInt.intValue, rightInt.intValue);
+      } else {
+        foldedValue = foldNums(leftNum.doubleValue, rightNum.doubleValue);
+      }
+      // A division by 0 means that we might not have a folded value.
+      if (foldedValue == null) return null;
+      if (left.isInt && right.isInt && !isDivide() || isTruncatingDivide()) {
+        assert(foldedValue is BigInt);
+        return JavaScriptConstantSystem.only.createInt(foldedValue);
+      } else {
+        return JavaScriptConstantSystem.only.createDouble(foldedValue);
+      }
+    }
+    return null;
+  }
+
+  bool isDivide() => false;
+  bool isTruncatingDivide() => false;
+  foldInts(BigInt left, BigInt right);
+  foldNums(num left, num right);
+}
+
+class JavaScriptBinaryArithmeticOperation implements BinaryOperation {
+  final BinaryOperation dartArithmeticOperation;
+
+  const JavaScriptBinaryArithmeticOperation(this.dartArithmeticOperation);
+
+  String get name => dartArithmeticOperation.name;
+
+  ConstantValue fold(ConstantValue left, ConstantValue right) {
+    ConstantValue result = dartArithmeticOperation.fold(left, right);
+    if (result == null) return result;
+    return JavaScriptConstantSystem.only.convertToJavaScriptConstant(result);
+  }
+
+  apply(left, right) => dartArithmeticOperation.apply(left, right);
+}
+
+class SubtractOperation extends ArithmeticNumOperation {
+  final String name = '-';
+  const SubtractOperation();
+  BigInt foldInts(BigInt left, BigInt right) => left - right;
+  num foldNums(num left, num right) => left - right;
+  apply(left, right) => left - right;
+}
+
+class MultiplyOperation extends ArithmeticNumOperation {
+  final String name = '*';
+  const MultiplyOperation();
+  BigInt foldInts(BigInt left, BigInt right) => left * right;
+  num foldNums(num left, num right) => left * right;
+  apply(left, right) => left * right;
+}
+
+class ModuloOperation extends ArithmeticNumOperation {
+  final String name = '%';
+  const ModuloOperation();
+  BigInt foldInts(BigInt left, BigInt right) {
+    if (right == BigInt.zero) return null;
+    return left % right;
+  }
+
+  num foldNums(num left, num right) => left % right;
+  apply(left, right) => left % right;
+}
+
+class JavaScriptRemainderOperation extends ArithmeticNumOperation {
+  String get name => 'remainder';
+
+  const JavaScriptRemainderOperation();
+
+  BigInt foldInts(BigInt left, BigInt right) {
+    if (right == BigInt.zero) return null;
+    return left.remainder(right);
+  }
+
+  num foldNums(num left, num right) => left.remainder(right);
+  apply(left, right) => left.remainder(right);
+}
+
+class TruncatingDivideOperation extends ArithmeticNumOperation {
+  final String name = '~/';
+  const TruncatingDivideOperation();
+  BigInt foldInts(BigInt left, BigInt right) {
+    if (right == BigInt.zero) return null;
+    return left ~/ right;
+  }
+
+  BigInt foldNums(num left, num right) {
+    num ratio = left / right;
+    if (ratio.isNaN || ratio.isInfinite) return null;
+    return new BigInt.from(ratio.truncate().toInt());
+  }
+
+  apply(left, right) => left ~/ right;
+  bool isTruncatingDivide() => true;
+}
+
+class DivideOperation extends ArithmeticNumOperation {
+  final String name = '/';
+  const DivideOperation();
+  double foldInts(BigInt left, BigInt right) => left / right;
+  num foldNums(num left, num right) => left / right;
+  bool isDivide() => true;
+  apply(left, right) => left / right;
+}
+
+class AddOperation implements BinaryOperation {
+  final String name = '+';
+  const AddOperation();
+  ConstantValue fold(ConstantValue left, ConstantValue right) {
+    if (left.isInt && right.isInt) {
+      IntConstantValue leftInt = left;
+      IntConstantValue rightInt = right;
+      BigInt result = leftInt.intValue + rightInt.intValue;
+      return JavaScriptConstantSystem.only.createInt(result);
+    } else if (left.isNum && right.isNum) {
+      NumConstantValue leftNum = left;
+      NumConstantValue rightNum = right;
+      double result = leftNum.doubleValue + rightNum.doubleValue;
+      return JavaScriptConstantSystem.only.createDouble(result);
+    } else if (left.isString && right.isString) {
+      StringConstantValue leftString = left;
+      StringConstantValue rightString = right;
+      String result = leftString.stringValue + rightString.stringValue;
+      return JavaScriptConstantSystem.only.createString(result);
+    } else {
+      return null;
+    }
+  }
+
+  apply(left, right) => left + right;
+}
+
+class JavaScriptAddOperation implements BinaryOperation {
+  final _addOperation = const AddOperation();
+  String get name => _addOperation.name;
+
+  const JavaScriptAddOperation();
+
+  ConstantValue fold(ConstantValue left, ConstantValue right) {
+    ConstantValue result = _addOperation.fold(left, right);
+    if (result != null && result.isNum) {
+      return JavaScriptConstantSystem.only.convertToJavaScriptConstant(result);
+    }
+    return result;
+  }
+
+  apply(left, right) => _addOperation.apply(left, right);
+}
+
+abstract class RelationalNumOperation implements BinaryOperation {
+  const RelationalNumOperation();
+  ConstantValue fold(ConstantValue left, ConstantValue right) {
+    if (!left.isNum || !right.isNum) return null;
+    bool foldedValue;
+    if (left.isInt && right.isInt) {
+      IntConstantValue leftInt = left;
+      IntConstantValue rightInt = right;
+      foldedValue = foldInts(leftInt.intValue, rightInt.intValue);
+    } else {
+      NumConstantValue leftNum = left;
+      NumConstantValue rightNum = right;
+      foldedValue = foldNums(leftNum.doubleValue, rightNum.doubleValue);
+    }
+    assert(foldedValue != null);
+    return JavaScriptConstantSystem.only.createBool(foldedValue);
+  }
+
+  bool foldInts(BigInt left, BigInt right);
+  bool foldNums(num left, num right);
+}
+
+class LessOperation extends RelationalNumOperation {
+  final String name = '<';
+  const LessOperation();
+  bool foldInts(BigInt left, BigInt right) => left < right;
+  bool foldNums(num left, num right) => left < right;
+  apply(left, right) => left < right;
+}
+
+class LessEqualOperation extends RelationalNumOperation {
+  final String name = '<=';
+  const LessEqualOperation();
+  bool foldInts(BigInt left, BigInt right) => left <= right;
+  bool foldNums(num left, num right) => left <= right;
+  apply(left, right) => left <= right;
+}
+
+class GreaterOperation extends RelationalNumOperation {
+  final String name = '>';
+  const GreaterOperation();
+  bool foldInts(BigInt left, BigInt right) => left > right;
+  bool foldNums(num left, num right) => left > right;
+  apply(left, right) => left > right;
+}
+
+class GreaterEqualOperation extends RelationalNumOperation {
+  final String name = '>=';
+  const GreaterEqualOperation();
+  bool foldInts(BigInt left, BigInt right) => left >= right;
+  bool foldNums(num left, num right) => left >= right;
+  apply(left, right) => left >= right;
+}
+
+class EqualsOperation implements BinaryOperation {
+  final String name = '==';
+  const EqualsOperation();
+  ConstantValue fold(ConstantValue left, ConstantValue right) {
+    // Numbers need to be treated specially because: NaN != NaN, -0.0 == 0.0,
+    // and 1 == 1.0.
+    if (left.isInt && right.isInt) {
+      IntConstantValue leftInt = left;
+      IntConstantValue rightInt = right;
+      bool result = leftInt.intValue == rightInt.intValue;
+      return JavaScriptConstantSystem.only.createBool(result);
+    }
+
+    if (left.isNum && right.isNum) {
+      NumConstantValue leftNum = left;
+      NumConstantValue rightNum = right;
+      bool result = leftNum.doubleValue == rightNum.doubleValue;
+      return JavaScriptConstantSystem.only.createBool(result);
+    }
+
+    if (left.isConstructedObject) {
+      if (right.isNull) {
+        return JavaScriptConstantSystem.only.createBool(false);
+      }
+      // Unless we know that the user-defined object does not implement the
+      // equality operator we cannot fold here.
+      return null;
+    }
+
+    return JavaScriptConstantSystem.only.createBool(left == right);
+  }
+
+  apply(left, right) => left == right;
+}
+
+class IdentityOperation implements BinaryOperation {
+  final String name = '===';
+  const IdentityOperation();
+  BoolConstantValue fold(ConstantValue left, ConstantValue right) {
+    // In order to preserve runtime semantics which says that NaN !== NaN don't
+    // constant fold NaN === NaN. Otherwise the output depends on inlined
+    // variables and other optimizations.
+    if (left.isNaN && right.isNaN) return null;
+    return JavaScriptConstantSystem.only.createBool(left == right);
+  }
+
+  apply(left, right) => identical(left, right);
+}
+
+class JavaScriptIdentityOperation implements BinaryOperation {
+  final IdentityOperation dartIdentityOperation = const IdentityOperation();
+
+  const JavaScriptIdentityOperation();
+
+  String get name => dartIdentityOperation.name;
+
+  BoolConstantValue fold(ConstantValue left, ConstantValue right) {
+    BoolConstantValue result = dartIdentityOperation.fold(left, right);
+    if (result == null || result.boolValue) return result;
+    // In JavaScript -0.0 === 0 and all doubles are equal to their integer
+    // values. Furthermore NaN !== NaN.
+    if (left.isInt && right.isInt) {
+      IntConstantValue leftInt = left;
+      IntConstantValue rightInt = right;
+      return new BoolConstantValue(leftInt.intValue == rightInt.intValue);
+    }
+    if (left.isNum && right.isNum) {
+      NumConstantValue leftNum = left;
+      NumConstantValue rightNum = right;
+      double leftDouble = leftNum.doubleValue;
+      double rightDouble = rightNum.doubleValue;
+      return new BoolConstantValue(leftDouble == rightDouble);
+    }
+    return result;
+  }
+
+  apply(left, right) => identical(left, right);
+}
+
+class IfNullOperation implements BinaryOperation {
+  final String name = '??';
+  const IfNullOperation();
+  ConstantValue fold(ConstantValue left, ConstantValue right) {
+    if (left.isNull) return right;
+    return left;
+  }
+
+  apply(left, right) => left ?? right;
+}
+
+class CodeUnitAtOperation implements BinaryOperation {
+  String get name => 'charCodeAt';
+  const CodeUnitAtOperation();
+  ConstantValue fold(ConstantValue left, ConstantValue right) => null;
+  apply(left, right) => left.codeUnitAt(right);
+}
+
+class CodeUnitAtRuntimeOperation extends CodeUnitAtOperation {
+  const CodeUnitAtRuntimeOperation();
+  IntConstantValue fold(ConstantValue left, ConstantValue right) {
+    if (left.isString && right.isInt) {
+      StringConstantValue stringConstant = left;
+      IntConstantValue indexConstant = right;
+      String string = stringConstant.stringValue;
+      int index = indexConstant.intValue.toInt();
+      if (index < 0 || index >= string.length) return null;
+      int value = string.codeUnitAt(index);
+      return JavaScriptConstantSystem.only.createIntFromInt(value);
+    }
+    return null;
+  }
+}
+
+class JavaScriptRoundOperation implements UnaryOperation {
+  const JavaScriptRoundOperation();
+  String get name => JavaScriptConstantSystem.only.round.name;
+  ConstantValue fold(ConstantValue constant) {
+    // Be careful to round() only values that do not throw on either the host or
+    // target platform.
+    ConstantValue tryToRound(double value) {
+      // Due to differences between browsers, only 'round' easy cases. Avoid
+      // cases where nudging the value up or down changes the answer.
+      // 13 digits is safely within the ~15 digit precision of doubles.
+      const severalULP = 0.0000000000001;
+      // Use 'roundToDouble()' to avoid exceptions on rounding the nudged value.
+      double rounded = value.roundToDouble();
+      double rounded1 = (value * (1.0 + severalULP)).roundToDouble();
+      double rounded2 = (value * (1.0 - severalULP)).roundToDouble();
+      if (rounded != rounded1 || rounded != rounded2) return null;
+      return JavaScriptConstantSystem.only.convertToJavaScriptConstant(
+          new IntConstantValue(new BigInt.from(value.round())));
+    }
+
+    if (constant.isInt) {
+      IntConstantValue intConstant = constant;
+      double value = intConstant.intValue.toDouble();
+      if (value >= -double.maxFinite && value <= double.maxFinite) {
+        return tryToRound(value);
+      }
+    }
+    if (constant.isDouble) {
+      DoubleConstantValue doubleConstant = constant;
+      double value = doubleConstant.doubleValue;
+      // NaN and infinities will throw.
+      if (value.isNaN) return null;
+      if (value.isInfinite) return null;
+      return tryToRound(value);
+    }
+    return null;
+  }
+}
+
+class UnfoldedUnaryOperation implements UnaryOperation {
+  final String name;
+  const UnfoldedUnaryOperation(this.name);
+  ConstantValue fold(ConstantValue constant) {
+    return null;
+  }
+}
+
 /// A [ConstantSystem] is responsible for creating constants and folding them.
 abstract class ConstantSystem {
   BinaryOperation get add;
@@ -148,3 +739,251 @@
     }
   }
 }
+
+/// Constant system following the semantics for Dart code that has been
+/// compiled to JavaScript.
+class JavaScriptConstantSystem extends ConstantSystem {
+  final BITS32 = new BigInt.from(0xFFFFFFFF);
+
+  final add = const JavaScriptAddOperation();
+  final bitAnd = const JavaScriptBinaryBitOperation(const BitAndOperation());
+  final bitNot = const JavaScriptBitNotOperation();
+  final bitOr = const JavaScriptBinaryBitOperation(const BitOrOperation());
+  final bitXor = const JavaScriptBinaryBitOperation(const BitXorOperation());
+  final booleanAnd = const BooleanAndOperation();
+  final booleanOr = const BooleanOrOperation();
+  final divide =
+      const JavaScriptBinaryArithmeticOperation(const DivideOperation());
+  final equal = const EqualsOperation();
+  final greaterEqual = const GreaterEqualOperation();
+  final greater = const GreaterOperation();
+  final identity = const JavaScriptIdentityOperation();
+  final ifNull = const IfNullOperation();
+  final lessEqual = const LessEqualOperation();
+  final less = const LessOperation();
+  final modulo =
+      const JavaScriptBinaryArithmeticOperation(const ModuloOperation());
+  final multiply =
+      const JavaScriptBinaryArithmeticOperation(const MultiplyOperation());
+  final negate = const JavaScriptNegateOperation();
+  final not = const NotOperation();
+  final remainder = const JavaScriptRemainderOperation();
+  final shiftLeft =
+      const JavaScriptBinaryBitOperation(const ShiftLeftOperation());
+  final shiftRight = const JavaScriptShiftRightOperation();
+  final subtract =
+      const JavaScriptBinaryArithmeticOperation(const SubtractOperation());
+  final truncatingDivide = const JavaScriptBinaryArithmeticOperation(
+      const TruncatingDivideOperation());
+  final codeUnitAt = const CodeUnitAtRuntimeOperation();
+  final round = const JavaScriptRoundOperation();
+  final abs = const UnfoldedUnaryOperation('abs');
+
+  static final JavaScriptConstantSystem only =
+      new JavaScriptConstantSystem._internal();
+
+  JavaScriptConstantSystem._internal();
+
+  /// Returns true if [value] will turn into NaN or infinity
+  /// at runtime.
+  bool integerBecomesNanOrInfinity(BigInt value) {
+    double doubleValue = value.toDouble();
+    return doubleValue.isNaN || doubleValue.isInfinite;
+  }
+
+  NumConstantValue convertToJavaScriptConstant(NumConstantValue constant) {
+    if (constant.isInt) {
+      IntConstantValue intConstant = constant;
+      BigInt intValue = intConstant.intValue;
+      if (integerBecomesNanOrInfinity(intValue)) {
+        return new DoubleConstantValue(intValue.toDouble());
+      }
+      // If the integer loses precision with JavaScript numbers, use
+      // the floored version JavaScript will use.
+      BigInt floorValue = new BigInt.from(intValue.toDouble());
+      if (floorValue != intValue) {
+        return new IntConstantValue(floorValue);
+      }
+    } else if (constant.isDouble) {
+      DoubleConstantValue doubleResult = constant;
+      double doubleValue = doubleResult.doubleValue;
+      if (!doubleValue.isInfinite &&
+          !doubleValue.isNaN &&
+          !constant.isMinusZero) {
+        double truncated = doubleValue.truncateToDouble();
+        if (truncated == doubleValue) {
+          return new IntConstantValue(new BigInt.from(truncated));
+        }
+      }
+    }
+    return constant;
+  }
+
+  @override
+  NumConstantValue createInt(BigInt i) {
+    return convertToJavaScriptConstant(new IntConstantValue(i));
+  }
+
+  NumConstantValue createInt32(BigInt i) => new IntConstantValue(i & BITS32);
+  NumConstantValue createDouble(double d) =>
+      convertToJavaScriptConstant(new DoubleConstantValue(d));
+  StringConstantValue createString(String string) {
+    return new StringConstantValue(string);
+  }
+
+  BoolConstantValue createBool(bool value) => new BoolConstantValue(value);
+  NullConstantValue createNull() => new NullConstantValue();
+
+  @override
+  ListConstantValue createList(InterfaceType type, List<ConstantValue> values) {
+    return new ListConstantValue(type, values);
+  }
+
+  @override
+  ConstantValue createType(CommonElements commonElements, DartType type) {
+    InterfaceType instanceType = commonElements.typeLiteralType;
+    return new TypeConstantValue(type, instanceType);
+  }
+
+  // Integer checks report true for -0.0, INFINITY, and -INFINITY.  At
+  // runtime an 'X is int' check is implemented as:
+  //
+  // typeof(X) === "number" && Math.floor(X) === X
+  //
+  // We consistently match that runtime semantics at compile time as well.
+  bool isInt(ConstantValue constant) {
+    return constant.isInt ||
+        constant.isMinusZero ||
+        constant.isPositiveInfinity ||
+        constant.isNegativeInfinity;
+  }
+
+  bool isDouble(ConstantValue constant) =>
+      constant.isDouble && !constant.isMinusZero;
+  bool isString(ConstantValue constant) => constant.isString;
+  bool isBool(ConstantValue constant) => constant.isBool;
+  bool isNull(ConstantValue constant) => constant.isNull;
+
+  bool isSubtype(DartTypes types, DartType s, DartType t) {
+    // At runtime, an integer is both an integer and a double: the
+    // integer type check is Math.floor, which will return true only
+    // for real integers, and our double type check is 'typeof number'
+    // which will return true for both integers and doubles.
+    if (s == types.commonElements.intType &&
+        t == types.commonElements.doubleType) {
+      return true;
+    }
+    return types.isSubtype(s, t);
+  }
+
+  @override
+  SetConstantValue createSet(CommonElements commonElements,
+      InterfaceType sourceType, List<ConstantValue> values) {
+    InterfaceType type = commonElements.getConstantSetTypeFor(sourceType);
+    return new JavaScriptSetConstant(commonElements, type, values);
+  }
+
+  MapConstantValue createMap(
+      CommonElements commonElements,
+      InterfaceType sourceType,
+      List<ConstantValue> keys,
+      List<ConstantValue> values) {
+    bool onlyStringKeys = true;
+    ConstantValue protoValue = null;
+    for (int i = 0; i < keys.length; i++) {
+      dynamic key = keys[i];
+      if (key.isString) {
+        if (key.stringValue == JavaScriptMapConstant.PROTO_PROPERTY) {
+          protoValue = values[i];
+        }
+      } else {
+        onlyStringKeys = false;
+        // Don't handle __proto__ values specially in the general map case.
+        protoValue = null;
+        break;
+      }
+    }
+
+    bool hasProtoKey = (protoValue != null);
+    InterfaceType keysType;
+    if (sourceType.treatAsRaw) {
+      keysType = commonElements.listType();
+    } else {
+      keysType = commonElements.listType(sourceType.typeArguments.first);
+    }
+    ListConstantValue keysList = new ListConstantValue(keysType, keys);
+    InterfaceType type = commonElements.getConstantMapTypeFor(sourceType,
+        hasProtoKey: hasProtoKey, onlyStringKeys: onlyStringKeys);
+    return new JavaScriptMapConstant(
+        type, keysList, values, protoValue, onlyStringKeys);
+  }
+
+  @override
+  ConstantValue createSymbol(CommonElements commonElements, String text) {
+    InterfaceType type = commonElements.symbolImplementationType;
+    FieldEntity field = commonElements.symbolField;
+    ConstantValue argument = createString(text);
+    // TODO(johnniwinther): Use type arguments when all uses no longer expect
+    // a [FieldElement].
+    var fields = <FieldEntity, ConstantValue>{field: argument};
+    return new ConstructedConstantValue(type, fields);
+  }
+}
+
+class JavaScriptSetConstant extends SetConstantValue {
+  final MapConstantValue entries;
+
+  JavaScriptSetConstant(CommonElements commonElements, InterfaceType type,
+      List<ConstantValue> values)
+      : entries = JavaScriptConstantSystem.only.createMap(
+            commonElements,
+            commonElements.mapType(
+                type.typeArguments.first, commonElements.nullType),
+            values,
+            new List<NullConstantValue>.filled(
+                values.length, const NullConstantValue())),
+        super(type, values);
+
+  @override
+  List<ConstantValue> getDependencies() => [entries];
+}
+
+class JavaScriptMapConstant extends MapConstantValue {
+  /// The [PROTO_PROPERTY] must not be used as normal property in any JavaScript
+  /// object. It would change the prototype chain.
+  static const String PROTO_PROPERTY = "__proto__";
+
+  /// The dart class implementing constant map literals.
+  static const String DART_CLASS = "ConstantMap";
+  static const String DART_STRING_CLASS = "ConstantStringMap";
+  static const String DART_PROTO_CLASS = "ConstantProtoMap";
+  static const String DART_GENERAL_CLASS = "GeneralConstantMap";
+  static const String LENGTH_NAME = "_length";
+  static const String JS_OBJECT_NAME = "_jsObject";
+  static const String KEYS_NAME = "_keys";
+  static const String PROTO_VALUE = "_protoValue";
+  static const String JS_DATA_NAME = "_jsData";
+
+  final ListConstantValue keyList;
+  final ConstantValue protoValue;
+  final bool onlyStringKeys;
+
+  JavaScriptMapConstant(InterfaceType type, ListConstantValue keyList,
+      List<ConstantValue> values, this.protoValue, this.onlyStringKeys)
+      : this.keyList = keyList,
+        super(type, keyList.entries, values);
+  bool get isMap => true;
+
+  List<ConstantValue> getDependencies() {
+    List<ConstantValue> result = <ConstantValue>[];
+    if (onlyStringKeys) {
+      result.add(keyList);
+    } else {
+      // Add the keys individually to avoid generating an unused list constant
+      // for the keys.
+      result.addAll(keys);
+    }
+    result.addAll(values);
+    return result;
+  }
+}
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index 3cd1c95..44fdb82 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -4,6 +4,7 @@
 
 import '../common.dart';
 import '../common_elements.dart';
+import '../constants/constant_system.dart';
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
@@ -14,7 +15,6 @@
 import '../options.dart';
 import '../universe/codegen_world_builder.dart';
 import 'field_analysis.dart' show JFieldAnalysis;
-import 'constant_system_javascript.dart';
 import 'js_backend.dart';
 import 'runtime_types.dart';
 
diff --git a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
index fe256f7..fe2a695 100644
--- a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
@@ -6,7 +6,6 @@
 import '../compiler.dart' show Compiler;
 import '../constants/constant_system.dart';
 import '../elements/entities.dart';
-import 'constant_system_javascript.dart';
 
 /// [ConstantCompilerTask] for compilation of constants for the JavaScript
 /// backend.
diff --git a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
deleted file mode 100644
index 3b1b3ce..0000000
--- a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
+++ /dev/null
@@ -1,849 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.constant_system.js;
-
-import '../constants/constant_system.dart';
-import '../constants/values.dart';
-import '../common_elements.dart' show CommonElements;
-import '../elements/types.dart';
-import '../elements/entities.dart';
-
-class JavaScriptBitNotOperation implements UnaryOperation {
-  final String name = '~';
-  const JavaScriptBitNotOperation();
-
-  ConstantValue fold(ConstantValue constant) {
-    if (JavaScriptConstantSystem.only.isInt(constant)) {
-      // In JavaScript we don't check for -0 and treat it as if it was zero.
-      if (constant.isMinusZero) {
-        constant = JavaScriptConstantSystem.only.createInt(BigInt.zero);
-      }
-      IntConstantValue intConstant = constant;
-      // We convert the result of bit-operations to 32 bit unsigned integers.
-      return JavaScriptConstantSystem.only.createInt32(~intConstant.intValue);
-    }
-    return null;
-  }
-}
-
-/// Operations that only work if both arguments are integers.
-abstract class BinaryBitOperation implements BinaryOperation {
-  const BinaryBitOperation();
-  ConstantValue fold(ConstantValue left, ConstantValue right) {
-    if (left.isInt && right.isInt) {
-      IntConstantValue leftInt = left;
-      IntConstantValue rightInt = right;
-      BigInt resultValue = foldInts(leftInt.intValue, rightInt.intValue);
-      if (resultValue == null) return null;
-      return JavaScriptConstantSystem.only.createInt(resultValue);
-    }
-    return null;
-  }
-
-  BigInt foldInts(BigInt left, BigInt right);
-}
-
-/// In JavaScript we truncate the result to an unsigned 32 bit integer. Also, -0
-/// is treated as if it was the integer 0.
-class JavaScriptBinaryBitOperation implements BinaryOperation {
-  final BinaryBitOperation dartBitOperation;
-
-  const JavaScriptBinaryBitOperation(this.dartBitOperation);
-
-  String get name => dartBitOperation.name;
-
-  ConstantValue fold(ConstantValue left, ConstantValue right) {
-    // In JavaScript we don't check for -0 and treat it as if it was zero.
-    if (left.isMinusZero) {
-      left = JavaScriptConstantSystem.only.createInt(BigInt.zero);
-    }
-    if (right.isMinusZero) {
-      right = JavaScriptConstantSystem.only.createInt(BigInt.zero);
-    }
-    IntConstantValue result = dartBitOperation.fold(left, right);
-    if (result != null) {
-      // We convert the result of bit-operations to 32 bit unsigned integers.
-      return JavaScriptConstantSystem.only.createInt32(result.intValue);
-    }
-    return result;
-  }
-
-  apply(left, right) => dartBitOperation.apply(left, right);
-}
-
-class ShiftRightOperation extends BinaryBitOperation {
-  final String name = '>>';
-  const ShiftRightOperation();
-  BigInt foldInts(BigInt left, BigInt right) {
-    if (right < BigInt.zero) return null;
-    return left >> right.toInt();
-  }
-
-  apply(left, right) => left >> right;
-}
-
-class JavaScriptShiftRightOperation extends JavaScriptBinaryBitOperation {
-  const JavaScriptShiftRightOperation() : super(const ShiftRightOperation());
-
-  ConstantValue fold(ConstantValue left, ConstantValue right) {
-    // Truncate the input value to 32 bits if necessary.
-    if (left.isInt) {
-      IntConstantValue intConstant = left;
-      BigInt value = intConstant.intValue;
-      BigInt truncatedValue = value & JavaScriptConstantSystem.only.BITS32;
-      if (value < BigInt.zero) {
-        // Sign-extend if the input was negative. The current semantics don't
-        // make much sense, since we only look at bit 31.
-        // TODO(floitsch): we should treat the input to right shifts as
-        // unsigned.
-
-        // A 32 bit complement-two value x can be computed by:
-        //    x_u - 2^32 (where x_u is its unsigned representation).
-        // Example: 0xFFFFFFFF - 0x100000000 => -1.
-        // We simply and with the sign-bit and multiply by two. If the sign-bit
-        // was set, then the result is 0. Otherwise it will become 2^32.
-        final BigInt SIGN_BIT = new BigInt.from(0x80000000);
-        truncatedValue -= BigInt.two * (truncatedValue & SIGN_BIT);
-      }
-      if (value != truncatedValue) {
-        left = JavaScriptConstantSystem.only.createInt(truncatedValue);
-      }
-    }
-    return super.fold(left, right);
-  }
-}
-
-class NegateOperation implements UnaryOperation {
-  final String name = 'negate';
-  const NegateOperation();
-  ConstantValue fold(ConstantValue constant) {
-    if (constant.isInt) {
-      IntConstantValue intConstant = constant;
-      return JavaScriptConstantSystem.only.createInt(-intConstant.intValue);
-    }
-    if (constant.isDouble) {
-      DoubleConstantValue doubleConstant = constant;
-      return JavaScriptConstantSystem.only
-          .createDouble(-doubleConstant.doubleValue);
-    }
-    return null;
-  }
-}
-
-class JavaScriptNegateOperation implements UnaryOperation {
-  final NegateOperation dartNegateOperation = const NegateOperation();
-
-  const JavaScriptNegateOperation();
-
-  String get name => dartNegateOperation.name;
-
-  ConstantValue fold(ConstantValue constant) {
-    if (constant.isInt) {
-      IntConstantValue intConstant = constant;
-      if (intConstant.intValue == BigInt.zero) {
-        return JavaScriptConstantSystem.only.createDouble(-0.0);
-      }
-    }
-    return dartNegateOperation.fold(constant);
-  }
-}
-
-class AddOperation implements BinaryOperation {
-  final String name = '+';
-  const AddOperation();
-  ConstantValue fold(ConstantValue left, ConstantValue right) {
-    if (left.isInt && right.isInt) {
-      IntConstantValue leftInt = left;
-      IntConstantValue rightInt = right;
-      BigInt result = leftInt.intValue + rightInt.intValue;
-      return JavaScriptConstantSystem.only.createInt(result);
-    } else if (left.isNum && right.isNum) {
-      NumConstantValue leftNum = left;
-      NumConstantValue rightNum = right;
-      double result = leftNum.doubleValue + rightNum.doubleValue;
-      return JavaScriptConstantSystem.only.createDouble(result);
-    } else if (left.isString && right.isString) {
-      StringConstantValue leftString = left;
-      StringConstantValue rightString = right;
-      String result = leftString.stringValue + rightString.stringValue;
-      return JavaScriptConstantSystem.only.createString(result);
-    } else {
-      return null;
-    }
-  }
-
-  apply(left, right) => left + right;
-}
-
-class JavaScriptAddOperation implements BinaryOperation {
-  final _addOperation = const AddOperation();
-  String get name => _addOperation.name;
-
-  const JavaScriptAddOperation();
-
-  ConstantValue fold(ConstantValue left, ConstantValue right) {
-    ConstantValue result = _addOperation.fold(left, right);
-    if (result != null && result.isNum) {
-      return JavaScriptConstantSystem.only.convertToJavaScriptConstant(result);
-    }
-    return result;
-  }
-
-  apply(left, right) => _addOperation.apply(left, right);
-}
-
-abstract class ArithmeticNumOperation implements BinaryOperation {
-  const ArithmeticNumOperation();
-  ConstantValue fold(ConstantValue left, ConstantValue right) {
-    if (left.isNum && right.isNum) {
-      NumConstantValue leftNum = left;
-      NumConstantValue rightNum = right;
-      var foldedValue;
-      if (left.isInt && right.isInt) {
-        IntConstantValue leftInt = leftNum;
-        IntConstantValue rightInt = rightNum;
-        foldedValue = foldInts(leftInt.intValue, rightInt.intValue);
-      } else {
-        foldedValue = foldNums(leftNum.doubleValue, rightNum.doubleValue);
-      }
-      // A division by 0 means that we might not have a folded value.
-      if (foldedValue == null) return null;
-      if (left.isInt && right.isInt && !isDivide() || isTruncatingDivide()) {
-        assert(foldedValue is BigInt);
-        return JavaScriptConstantSystem.only.createInt(foldedValue);
-      } else {
-        return JavaScriptConstantSystem.only.createDouble(foldedValue);
-      }
-    }
-    return null;
-  }
-
-  bool isDivide() => false;
-  bool isTruncatingDivide() => false;
-  foldInts(BigInt left, BigInt right);
-  foldNums(num left, num right);
-}
-
-class JavaScriptRemainderOperation extends ArithmeticNumOperation {
-  String get name => 'remainder';
-
-  const JavaScriptRemainderOperation();
-
-  BigInt foldInts(BigInt left, BigInt right) {
-    if (right == BigInt.zero) return null;
-    return left.remainder(right);
-  }
-
-  num foldNums(num left, num right) => left.remainder(right);
-  apply(left, right) => left.remainder(right);
-}
-
-class JavaScriptBinaryArithmeticOperation implements BinaryOperation {
-  final BinaryOperation dartArithmeticOperation;
-
-  const JavaScriptBinaryArithmeticOperation(this.dartArithmeticOperation);
-
-  String get name => dartArithmeticOperation.name;
-
-  ConstantValue fold(ConstantValue left, ConstantValue right) {
-    ConstantValue result = dartArithmeticOperation.fold(left, right);
-    if (result == null) return result;
-    return JavaScriptConstantSystem.only.convertToJavaScriptConstant(result);
-  }
-
-  apply(left, right) => dartArithmeticOperation.apply(left, right);
-}
-
-class IdentityOperation implements BinaryOperation {
-  final String name = '===';
-  const IdentityOperation();
-  BoolConstantValue fold(ConstantValue left, ConstantValue right) {
-    // In order to preserve runtime semantics which says that NaN !== NaN don't
-    // constant fold NaN === NaN. Otherwise the output depends on inlined
-    // variables and other optimizations.
-    if (left.isNaN && right.isNaN) return null;
-    return JavaScriptConstantSystem.only.createBool(left == right);
-  }
-
-  apply(left, right) => identical(left, right);
-}
-
-class JavaScriptIdentityOperation implements BinaryOperation {
-  final IdentityOperation dartIdentityOperation = const IdentityOperation();
-
-  const JavaScriptIdentityOperation();
-
-  String get name => dartIdentityOperation.name;
-
-  BoolConstantValue fold(ConstantValue left, ConstantValue right) {
-    BoolConstantValue result = dartIdentityOperation.fold(left, right);
-    if (result == null || result.boolValue) return result;
-    // In JavaScript -0.0 === 0 and all doubles are equal to their integer
-    // values. Furthermore NaN !== NaN.
-    if (left.isInt && right.isInt) {
-      IntConstantValue leftInt = left;
-      IntConstantValue rightInt = right;
-      return new BoolConstantValue(leftInt.intValue == rightInt.intValue);
-    }
-    if (left.isNum && right.isNum) {
-      NumConstantValue leftNum = left;
-      NumConstantValue rightNum = right;
-      double leftDouble = leftNum.doubleValue;
-      double rightDouble = rightNum.doubleValue;
-      return new BoolConstantValue(leftDouble == rightDouble);
-    }
-    return result;
-  }
-
-  apply(left, right) => identical(left, right);
-}
-
-class JavaScriptRoundOperation implements UnaryOperation {
-  const JavaScriptRoundOperation();
-  String get name => JavaScriptConstantSystem.only.round.name;
-  ConstantValue fold(ConstantValue constant) {
-    // Be careful to round() only values that do not throw on either the host or
-    // target platform.
-    ConstantValue tryToRound(double value) {
-      // Due to differences between browsers, only 'round' easy cases. Avoid
-      // cases where nudging the value up or down changes the answer.
-      // 13 digits is safely within the ~15 digit precision of doubles.
-      const severalULP = 0.0000000000001;
-      // Use 'roundToDouble()' to avoid exceptions on rounding the nudged value.
-      double rounded = value.roundToDouble();
-      double rounded1 = (value * (1.0 + severalULP)).roundToDouble();
-      double rounded2 = (value * (1.0 - severalULP)).roundToDouble();
-      if (rounded != rounded1 || rounded != rounded2) return null;
-      return JavaScriptConstantSystem.only.convertToJavaScriptConstant(
-          new IntConstantValue(new BigInt.from(value.round())));
-    }
-
-    if (constant.isInt) {
-      IntConstantValue intConstant = constant;
-      double value = intConstant.intValue.toDouble();
-      if (value >= -double.maxFinite && value <= double.maxFinite) {
-        return tryToRound(value);
-      }
-    }
-    if (constant.isDouble) {
-      DoubleConstantValue doubleConstant = constant;
-      double value = doubleConstant.doubleValue;
-      // NaN and infinities will throw.
-      if (value.isNaN) return null;
-      if (value.isInfinite) return null;
-      return tryToRound(value);
-    }
-    return null;
-  }
-}
-
-class BitAndOperation extends BinaryBitOperation {
-  final String name = '&';
-  const BitAndOperation();
-  BigInt foldInts(BigInt left, BigInt right) => left & right;
-  apply(left, right) => left & right;
-}
-
-class BitOrOperation extends BinaryBitOperation {
-  final String name = '|';
-  const BitOrOperation();
-  BigInt foldInts(BigInt left, BigInt right) => left | right;
-  apply(left, right) => left | right;
-}
-
-class BitXorOperation extends BinaryBitOperation {
-  final String name = '^';
-  const BitXorOperation();
-  BigInt foldInts(BigInt left, BigInt right) => left ^ right;
-  apply(left, right) => left ^ right;
-}
-
-abstract class BinaryBoolOperation implements BinaryOperation {
-  const BinaryBoolOperation();
-  ConstantValue fold(ConstantValue left, ConstantValue right) {
-    if (left.isBool && right.isBool) {
-      BoolConstantValue leftBool = left;
-      BoolConstantValue rightBool = right;
-      bool resultValue = foldBools(leftBool.boolValue, rightBool.boolValue);
-      return JavaScriptConstantSystem.only.createBool(resultValue);
-    }
-    return null;
-  }
-
-  bool foldBools(bool left, bool right);
-}
-
-class BooleanAndOperation extends BinaryBoolOperation {
-  final String name = '&&';
-  const BooleanAndOperation();
-  bool foldBools(bool left, bool right) => left && right;
-  apply(left, right) => left && right;
-}
-
-class BooleanOrOperation extends BinaryBoolOperation {
-  final String name = '||';
-  const BooleanOrOperation();
-  bool foldBools(bool left, bool right) => left || right;
-  apply(left, right) => left || right;
-}
-
-class DivideOperation extends ArithmeticNumOperation {
-  final String name = '/';
-  const DivideOperation();
-  double foldInts(BigInt left, BigInt right) => left / right;
-  num foldNums(num left, num right) => left / right;
-  bool isDivide() => true;
-  apply(left, right) => left / right;
-}
-
-class EqualsOperation implements BinaryOperation {
-  final String name = '==';
-  const EqualsOperation();
-  ConstantValue fold(ConstantValue left, ConstantValue right) {
-    // Numbers need to be treated specially because: NaN != NaN, -0.0 == 0.0,
-    // and 1 == 1.0.
-    if (left.isInt && right.isInt) {
-      IntConstantValue leftInt = left;
-      IntConstantValue rightInt = right;
-      bool result = leftInt.intValue == rightInt.intValue;
-      return JavaScriptConstantSystem.only.createBool(result);
-    }
-
-    if (left.isNum && right.isNum) {
-      NumConstantValue leftNum = left;
-      NumConstantValue rightNum = right;
-      bool result = leftNum.doubleValue == rightNum.doubleValue;
-      return JavaScriptConstantSystem.only.createBool(result);
-    }
-
-    if (left.isConstructedObject) {
-      if (right.isNull) {
-        return JavaScriptConstantSystem.only.createBool(false);
-      }
-      // Unless we know that the user-defined object does not implement the
-      // equality operator we cannot fold here.
-      return null;
-    }
-
-    return JavaScriptConstantSystem.only.createBool(left == right);
-  }
-
-  apply(left, right) => left == right;
-}
-
-abstract class RelationalNumOperation implements BinaryOperation {
-  const RelationalNumOperation();
-  ConstantValue fold(ConstantValue left, ConstantValue right) {
-    if (!left.isNum || !right.isNum) return null;
-    bool foldedValue;
-    if (left.isInt && right.isInt) {
-      IntConstantValue leftInt = left;
-      IntConstantValue rightInt = right;
-      foldedValue = foldInts(leftInt.intValue, rightInt.intValue);
-    } else {
-      NumConstantValue leftNum = left;
-      NumConstantValue rightNum = right;
-      foldedValue = foldNums(leftNum.doubleValue, rightNum.doubleValue);
-    }
-    assert(foldedValue != null);
-    return JavaScriptConstantSystem.only.createBool(foldedValue);
-  }
-
-  bool foldInts(BigInt left, BigInt right);
-  bool foldNums(num left, num right);
-}
-
-class GreaterEqualOperation extends RelationalNumOperation {
-  final String name = '>=';
-  const GreaterEqualOperation();
-  bool foldInts(BigInt left, BigInt right) => left >= right;
-  bool foldNums(num left, num right) => left >= right;
-  apply(left, right) => left >= right;
-}
-
-class GreaterOperation extends RelationalNumOperation {
-  final String name = '>';
-  const GreaterOperation();
-  bool foldInts(BigInt left, BigInt right) => left > right;
-  bool foldNums(num left, num right) => left > right;
-  apply(left, right) => left > right;
-}
-
-class IfNullOperation implements BinaryOperation {
-  final String name = '??';
-  const IfNullOperation();
-  ConstantValue fold(ConstantValue left, ConstantValue right) {
-    if (left.isNull) return right;
-    return left;
-  }
-
-  apply(left, right) => left ?? right;
-}
-
-class LessEqualOperation extends RelationalNumOperation {
-  final String name = '<=';
-  const LessEqualOperation();
-  bool foldInts(BigInt left, BigInt right) => left <= right;
-  bool foldNums(num left, num right) => left <= right;
-  apply(left, right) => left <= right;
-}
-
-class LessOperation extends RelationalNumOperation {
-  final String name = '<';
-  const LessOperation();
-  bool foldInts(BigInt left, BigInt right) => left < right;
-  bool foldNums(num left, num right) => left < right;
-  apply(left, right) => left < right;
-}
-
-class ModuloOperation extends ArithmeticNumOperation {
-  final String name = '%';
-  const ModuloOperation();
-  BigInt foldInts(BigInt left, BigInt right) {
-    if (right == BigInt.zero) return null;
-    return left % right;
-  }
-
-  num foldNums(num left, num right) => left % right;
-  apply(left, right) => left % right;
-}
-
-class MultiplyOperation extends ArithmeticNumOperation {
-  final String name = '*';
-  const MultiplyOperation();
-  BigInt foldInts(BigInt left, BigInt right) => left * right;
-  num foldNums(num left, num right) => left * right;
-  apply(left, right) => left * right;
-}
-
-class NotOperation implements UnaryOperation {
-  final String name = '!';
-  const NotOperation();
-  ConstantValue fold(ConstantValue constant) {
-    if (constant.isBool) {
-      BoolConstantValue boolConstant = constant;
-      return JavaScriptConstantSystem.only.createBool(!boolConstant.boolValue);
-    }
-    return null;
-  }
-}
-
-class ShiftLeftOperation extends BinaryBitOperation {
-  final String name = '<<';
-  const ShiftLeftOperation();
-  BigInt foldInts(BigInt left, BigInt right) {
-    // TODO(floitsch): find a better way to guard against excessive shifts to
-    // the left.
-    if (right > new BigInt.from(100) || right < BigInt.zero) return null;
-    return left << right.toInt();
-  }
-
-  apply(left, right) => left << right;
-}
-
-class SubtractOperation extends ArithmeticNumOperation {
-  final String name = '-';
-  const SubtractOperation();
-  BigInt foldInts(BigInt left, BigInt right) => left - right;
-  num foldNums(num left, num right) => left - right;
-  apply(left, right) => left - right;
-}
-
-class TruncatingDivideOperation extends ArithmeticNumOperation {
-  final String name = '~/';
-  const TruncatingDivideOperation();
-  BigInt foldInts(BigInt left, BigInt right) {
-    if (right == BigInt.zero) return null;
-    return left ~/ right;
-  }
-
-  BigInt foldNums(num left, num right) {
-    num ratio = left / right;
-    if (ratio.isNaN || ratio.isInfinite) return null;
-    return new BigInt.from(ratio.truncate().toInt());
-  }
-
-  apply(left, right) => left ~/ right;
-  bool isTruncatingDivide() => true;
-}
-
-class CodeUnitAtOperation implements BinaryOperation {
-  String get name => 'charCodeAt';
-  const CodeUnitAtOperation();
-  ConstantValue fold(ConstantValue left, ConstantValue right) => null;
-  apply(left, right) => left.codeUnitAt(right);
-}
-
-class CodeUnitAtRuntimeOperation extends CodeUnitAtOperation {
-  const CodeUnitAtRuntimeOperation();
-  IntConstantValue fold(ConstantValue left, ConstantValue right) {
-    if (left.isString && right.isInt) {
-      StringConstantValue stringConstant = left;
-      IntConstantValue indexConstant = right;
-      String string = stringConstant.stringValue;
-      int index = indexConstant.intValue.toInt();
-      if (index < 0 || index >= string.length) return null;
-      int value = string.codeUnitAt(index);
-      return JavaScriptConstantSystem.only.createIntFromInt(value);
-    }
-    return null;
-  }
-}
-
-class UnfoldedUnaryOperation implements UnaryOperation {
-  final String name;
-  const UnfoldedUnaryOperation(this.name);
-  ConstantValue fold(ConstantValue constant) {
-    return null;
-  }
-}
-
-/// Constant system following the semantics for Dart code that has been
-/// compiled to JavaScript.
-class JavaScriptConstantSystem extends ConstantSystem {
-  final BITS32 = new BigInt.from(0xFFFFFFFF);
-
-  final add = const JavaScriptAddOperation();
-  final bitAnd = const JavaScriptBinaryBitOperation(const BitAndOperation());
-  final bitNot = const JavaScriptBitNotOperation();
-  final bitOr = const JavaScriptBinaryBitOperation(const BitOrOperation());
-  final bitXor = const JavaScriptBinaryBitOperation(const BitXorOperation());
-  final booleanAnd = const BooleanAndOperation();
-  final booleanOr = const BooleanOrOperation();
-  final divide =
-      const JavaScriptBinaryArithmeticOperation(const DivideOperation());
-  final equal = const EqualsOperation();
-  final greaterEqual = const GreaterEqualOperation();
-  final greater = const GreaterOperation();
-  final identity = const JavaScriptIdentityOperation();
-  final ifNull = const IfNullOperation();
-  final lessEqual = const LessEqualOperation();
-  final less = const LessOperation();
-  final modulo =
-      const JavaScriptBinaryArithmeticOperation(const ModuloOperation());
-  final multiply =
-      const JavaScriptBinaryArithmeticOperation(const MultiplyOperation());
-  final negate = const JavaScriptNegateOperation();
-  final not = const NotOperation();
-  final remainder = const JavaScriptRemainderOperation();
-  final shiftLeft =
-      const JavaScriptBinaryBitOperation(const ShiftLeftOperation());
-  final shiftRight = const JavaScriptShiftRightOperation();
-  final subtract =
-      const JavaScriptBinaryArithmeticOperation(const SubtractOperation());
-  final truncatingDivide = const JavaScriptBinaryArithmeticOperation(
-      const TruncatingDivideOperation());
-  final codeUnitAt = const CodeUnitAtRuntimeOperation();
-  final round = const JavaScriptRoundOperation();
-  final abs = const UnfoldedUnaryOperation('abs');
-
-  static final JavaScriptConstantSystem only =
-      new JavaScriptConstantSystem._internal();
-
-  JavaScriptConstantSystem._internal();
-
-  /// Returns true if [value] will turn into NaN or infinity
-  /// at runtime.
-  bool integerBecomesNanOrInfinity(BigInt value) {
-    double doubleValue = value.toDouble();
-    return doubleValue.isNaN || doubleValue.isInfinite;
-  }
-
-  NumConstantValue convertToJavaScriptConstant(NumConstantValue constant) {
-    if (constant.isInt) {
-      IntConstantValue intConstant = constant;
-      BigInt intValue = intConstant.intValue;
-      if (integerBecomesNanOrInfinity(intValue)) {
-        return new DoubleConstantValue(intValue.toDouble());
-      }
-      // If the integer loses precision with JavaScript numbers, use
-      // the floored version JavaScript will use.
-      BigInt floorValue = new BigInt.from(intValue.toDouble());
-      if (floorValue != intValue) {
-        return new IntConstantValue(floorValue);
-      }
-    } else if (constant.isDouble) {
-      DoubleConstantValue doubleResult = constant;
-      double doubleValue = doubleResult.doubleValue;
-      if (!doubleValue.isInfinite &&
-          !doubleValue.isNaN &&
-          !constant.isMinusZero) {
-        double truncated = doubleValue.truncateToDouble();
-        if (truncated == doubleValue) {
-          return new IntConstantValue(new BigInt.from(truncated));
-        }
-      }
-    }
-    return constant;
-  }
-
-  @override
-  NumConstantValue createInt(BigInt i) {
-    return convertToJavaScriptConstant(new IntConstantValue(i));
-  }
-
-  NumConstantValue createInt32(BigInt i) => new IntConstantValue(i & BITS32);
-  NumConstantValue createDouble(double d) =>
-      convertToJavaScriptConstant(new DoubleConstantValue(d));
-  StringConstantValue createString(String string) {
-    return new StringConstantValue(string);
-  }
-
-  BoolConstantValue createBool(bool value) => new BoolConstantValue(value);
-  NullConstantValue createNull() => new NullConstantValue();
-
-  @override
-  ListConstantValue createList(InterfaceType type, List<ConstantValue> values) {
-    return new ListConstantValue(type, values);
-  }
-
-  @override
-  ConstantValue createType(CommonElements commonElements, DartType type) {
-    InterfaceType instanceType = commonElements.typeLiteralType;
-    return new TypeConstantValue(type, instanceType);
-  }
-
-  // Integer checks report true for -0.0, INFINITY, and -INFINITY.  At
-  // runtime an 'X is int' check is implemented as:
-  //
-  // typeof(X) === "number" && Math.floor(X) === X
-  //
-  // We consistently match that runtime semantics at compile time as well.
-  bool isInt(ConstantValue constant) {
-    return constant.isInt ||
-        constant.isMinusZero ||
-        constant.isPositiveInfinity ||
-        constant.isNegativeInfinity;
-  }
-
-  bool isDouble(ConstantValue constant) =>
-      constant.isDouble && !constant.isMinusZero;
-  bool isString(ConstantValue constant) => constant.isString;
-  bool isBool(ConstantValue constant) => constant.isBool;
-  bool isNull(ConstantValue constant) => constant.isNull;
-
-  bool isSubtype(DartTypes types, DartType s, DartType t) {
-    // At runtime, an integer is both an integer and a double: the
-    // integer type check is Math.floor, which will return true only
-    // for real integers, and our double type check is 'typeof number'
-    // which will return true for both integers and doubles.
-    if (s == types.commonElements.intType &&
-        t == types.commonElements.doubleType) {
-      return true;
-    }
-    return types.isSubtype(s, t);
-  }
-
-  @override
-  SetConstantValue createSet(CommonElements commonElements,
-      InterfaceType sourceType, List<ConstantValue> values) {
-    InterfaceType type = commonElements.getConstantSetTypeFor(sourceType);
-    return new JavaScriptSetConstant(commonElements, type, values);
-  }
-
-  MapConstantValue createMap(
-      CommonElements commonElements,
-      InterfaceType sourceType,
-      List<ConstantValue> keys,
-      List<ConstantValue> values) {
-    bool onlyStringKeys = true;
-    ConstantValue protoValue = null;
-    for (int i = 0; i < keys.length; i++) {
-      dynamic key = keys[i];
-      if (key.isString) {
-        if (key.stringValue == JavaScriptMapConstant.PROTO_PROPERTY) {
-          protoValue = values[i];
-        }
-      } else {
-        onlyStringKeys = false;
-        // Don't handle __proto__ values specially in the general map case.
-        protoValue = null;
-        break;
-      }
-    }
-
-    bool hasProtoKey = (protoValue != null);
-    InterfaceType keysType;
-    if (sourceType.treatAsRaw) {
-      keysType = commonElements.listType();
-    } else {
-      keysType = commonElements.listType(sourceType.typeArguments.first);
-    }
-    ListConstantValue keysList = new ListConstantValue(keysType, keys);
-    InterfaceType type = commonElements.getConstantMapTypeFor(sourceType,
-        hasProtoKey: hasProtoKey, onlyStringKeys: onlyStringKeys);
-    return new JavaScriptMapConstant(
-        type, keysList, values, protoValue, onlyStringKeys);
-  }
-
-  @override
-  ConstantValue createSymbol(CommonElements commonElements, String text) {
-    InterfaceType type = commonElements.symbolImplementationType;
-    FieldEntity field = commonElements.symbolField;
-    ConstantValue argument = createString(text);
-    // TODO(johnniwinther): Use type arguments when all uses no longer expect
-    // a [FieldElement].
-    var fields = <FieldEntity, ConstantValue>{field: argument};
-    return new ConstructedConstantValue(type, fields);
-  }
-}
-
-class JavaScriptSetConstant extends SetConstantValue {
-  final MapConstantValue entries;
-
-  JavaScriptSetConstant(CommonElements commonElements, InterfaceType type,
-      List<ConstantValue> values)
-      : entries = JavaScriptConstantSystem.only.createMap(
-            commonElements,
-            commonElements.mapType(
-                type.typeArguments.first, commonElements.nullType),
-            values,
-            new List<NullConstantValue>.filled(
-                values.length, const NullConstantValue())),
-        super(type, values);
-
-  @override
-  List<ConstantValue> getDependencies() => [entries];
-}
-
-class JavaScriptMapConstant extends MapConstantValue {
-  /// The [PROTO_PROPERTY] must not be used as normal property in any JavaScript
-  /// object. It would change the prototype chain.
-  static const String PROTO_PROPERTY = "__proto__";
-
-  /// The dart class implementing constant map literals.
-  static const String DART_CLASS = "ConstantMap";
-  static const String DART_STRING_CLASS = "ConstantStringMap";
-  static const String DART_PROTO_CLASS = "ConstantProtoMap";
-  static const String DART_GENERAL_CLASS = "GeneralConstantMap";
-  static const String LENGTH_NAME = "_length";
-  static const String JS_OBJECT_NAME = "_jsObject";
-  static const String KEYS_NAME = "_keys";
-  static const String PROTO_VALUE = "_protoValue";
-  static const String JS_DATA_NAME = "_jsData";
-
-  final ListConstantValue keyList;
-  final ConstantValue protoValue;
-  final bool onlyStringKeys;
-
-  JavaScriptMapConstant(InterfaceType type, ListConstantValue keyList,
-      List<ConstantValue> values, this.protoValue, this.onlyStringKeys)
-      : this.keyList = keyList,
-        super(type, keyList.entries, values);
-  bool get isMap => true;
-
-  List<ConstantValue> getDependencies() {
-    List<ConstantValue> result = <ConstantValue>[];
-    if (onlyStringKeys) {
-      result.add(keyList);
-    } else {
-      // Add the keys individually to avoid generating an unused list constant
-      // for the keys.
-      result.addAll(keys);
-    }
-    result.addAll(values);
-    return result;
-  }
-}
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 087ede4..c95a90e 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -14,6 +14,7 @@
 import '../closure.dart';
 import '../common.dart';
 import '../common/names.dart' show Identifiers, Names, Selectors;
+import '../constants/constant_system.dart';
 import '../constants/values.dart';
 import '../common_elements.dart' show CommonElements, ElementEnvironment;
 import '../diagnostics/invariant.dart' show DEBUG_MODE;
@@ -31,7 +32,6 @@
 import '../util/util.dart';
 import '../world.dart' show JClosedWorld;
 import 'backend.dart';
-import 'constant_system_javascript.dart';
 import 'native_data.dart';
 import 'runtime_types.dart';
 
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index ad03cc0..2023e05 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -37,7 +37,6 @@
 import '../ir/static_type_provider.dart';
 import '../ir/util.dart';
 import '../js/js.dart' as js;
-import '../js_backend/constant_system_javascript.dart';
 import '../js_backend/namer.dart';
 import '../js_backend/native_data.dart';
 import '../js_emitter/code_emitter_task.dart';
diff --git a/pkg/compiler/lib/src/js_model/js_world.dart b/pkg/compiler/lib/src/js_model/js_world.dart
index 37c9ff2..a9220c2 100644
--- a/pkg/compiler/lib/src/js_model/js_world.dart
+++ b/pkg/compiler/lib/src/js_model/js_world.dart
@@ -22,7 +22,6 @@
 import '../js_backend/annotations.dart';
 import '../js_backend/field_analysis.dart';
 import '../js_backend/backend_usage.dart';
-import '../js_backend/constant_system_javascript.dart';
 import '../js_backend/interceptor_data.dart';
 import '../js_backend/native_data.dart';
 import '../js_backend/no_such_method_registry.dart';
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 343e484..3286c3c 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -40,7 +40,6 @@
 import '../js/js.dart' as js;
 import '../js_backend/annotations.dart';
 import '../js_backend/backend.dart' show JavaScriptBackend;
-import '../js_backend/constant_system_javascript.dart';
 import '../js_backend/namer.dart';
 import '../js_backend/native_data.dart';
 import '../js_backend/no_such_method_registry.dart';
diff --git a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
index f0c2da5..028bb17 100644
--- a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
+++ b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
@@ -4,7 +4,6 @@
 
 import '../constants/constant_system.dart';
 import '../constants/values.dart';
-import '../js_backend/constant_system_javascript.dart';
 import '../world.dart' show JClosedWorld;
 import 'nodes.dart';
 import 'optimize.dart';
diff --git a/tests/compiler/dart2js/analyses/dart2js_allowed.json b/tests/compiler/dart2js/analyses/dart2js_allowed.json
index 215449d..a095c40 100644
--- a/tests/compiler/dart2js/analyses/dart2js_allowed.json
+++ b/tests/compiler/dart2js/analyses/dart2js_allowed.json
@@ -146,23 +146,23 @@
     "Dynamic invocation of '+'.": 2,
     "Dynamic invocation of '-'.": 1
   },
-  "pkg/compiler/lib/src/js_backend/constant_system_javascript.dart": {
-    "Dynamic invocation of '>>'.": 1,
-    "Dynamic invocation of '+'.": 1,
-    "Dynamic invocation of 'remainder'.": 1,
+  "pkg/compiler/lib/src/constants/constant_system.dart": {
     "Dynamic invocation of '&'.": 1,
     "Dynamic invocation of '|'.": 1,
     "Dynamic invocation of '^'.": 1,
-    "Dynamic invocation of '/'.": 1,
-    "Dynamic invocation of '>='.": 1,
-    "Dynamic invocation of '>'.": 1,
-    "Dynamic invocation of '<='.": 1,
-    "Dynamic invocation of '<'.": 1,
-    "Dynamic invocation of '%'.": 1,
-    "Dynamic invocation of '*'.": 1,
     "Dynamic invocation of '<<'.": 1,
+    "Dynamic invocation of '>>'.": 1,
     "Dynamic invocation of '-'.": 1,
+    "Dynamic invocation of '*'.": 1,
+    "Dynamic invocation of '%'.": 1,
+    "Dynamic invocation of 'remainder'.": 1,
     "Dynamic invocation of '~/'.": 1,
+    "Dynamic invocation of '/'.": 1,
+    "Dynamic invocation of '+'.": 1,
+    "Dynamic invocation of '<'.": 1,
+    "Dynamic invocation of '<='.": 1,
+    "Dynamic invocation of '>'.": 1,
+    "Dynamic invocation of '>='.": 1,
     "Dynamic invocation of 'codeUnitAt'.": 1
   },
   "pkg/compiler/lib/src/serialization/binary_sink.dart": {
diff --git a/tests/compiler/dart2js/codegen/value_range2_test.dart b/tests/compiler/dart2js/codegen/value_range2_test.dart
index aacfc98..f5d65d8 100644
--- a/tests/compiler/dart2js/codegen/value_range2_test.dart
+++ b/tests/compiler/dart2js/codegen/value_range2_test.dart
@@ -3,10 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
+import "package:compiler/src/constants/constant_system.dart";
 import "package:compiler/src/inferrer/abstract_value_domain.dart";
 import "package:compiler/src/ssa/nodes.dart";
 import "package:compiler/src/ssa/value_range_analyzer.dart";
-import "package:compiler/src/js_backend/constant_system_javascript.dart";
 
 ValueRangeInfo info = new ValueRangeInfo(JavaScriptConstantSystem.only);
 
diff --git a/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart b/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart
index 98366be..af3679d 100644
--- a/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart
+++ b/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart
@@ -10,6 +10,7 @@
 import 'package:compiler/src/common.dart';
 import 'package:compiler/src/common_elements.dart';
 import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/constants/constant_system.dart';
 import 'package:compiler/src/constants/constructors.dart';
 import 'package:compiler/src/constants/evaluation.dart';
 import 'package:compiler/src/constants/expressions.dart';
@@ -17,7 +18,6 @@
 import 'package:compiler/src/diagnostics/messages.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/elements/types.dart';
-import 'package:compiler/src/js_backend/constant_system_javascript.dart';
 import 'package:compiler/src/kernel/kernel_strategy.dart';
 import 'package:compiler/src/kernel/element_map_impl.dart';
 import '../helpers/memory_compiler.dart';