Reland "Remove the Dart constant system and move all required classes into the JavaScript constant system."

This is a reland of 5af8de8954224ab2de19a3a657ebef37478edfc9

Original change's description:
> Remove the Dart constant system and move all required classes into the
> JavaScript constant system.
>
> Change-Id: I2a31ea743270459284c42b615b0dffd1c7aa2584
> Reviewed-on: https://dart-review.googlesource.com/c/93746
> Reviewed-by: Sigmund Cherem <sigmund@google.com>
> Reviewed-by: Johnni Winther <johnniwinther@google.com>

Change-Id: I8c8399e94dd80c1f543a54454efc9cf59ef6ac7b
Reviewed-on: https://dart-review.googlesource.com/c/94104
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/constant_system_dart.dart b/pkg/compiler/lib/src/constant_system_dart.dart
deleted file mode 100644
index c610490..0000000
--- a/pkg/compiler/lib/src/constant_system_dart.dart
+++ /dev/null
@@ -1,503 +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.dart;
-
-import 'constants/constant_system.dart';
-import 'constants/values.dart';
-import 'common_elements.dart' show CommonElements;
-import 'elements/types.dart';
-
-const DART_CONSTANT_SYSTEM = const DartConstantSystem();
-
-class BitNotOperation implements UnaryOperation {
-  final String name = '~';
-  const BitNotOperation();
-  ConstantValue fold(ConstantValue constant) {
-    if (constant.isInt) {
-      IntConstantValue intConstant = constant;
-      return DART_CONSTANT_SYSTEM.createInt(~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 DART_CONSTANT_SYSTEM.createInt(-intConstant.intValue);
-    }
-    if (constant.isDouble) {
-      DoubleConstantValue doubleConstant = constant;
-      return DART_CONSTANT_SYSTEM.createDouble(-doubleConstant.doubleValue);
-    }
-    return null;
-  }
-}
-
-class NotOperation implements UnaryOperation {
-  final String name = '!';
-  const NotOperation();
-  ConstantValue fold(ConstantValue constant) {
-    if (constant.isBool) {
-      BoolConstantValue boolConstant = constant;
-      return DART_CONSTANT_SYSTEM.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 DART_CONSTANT_SYSTEM.createInt(resultValue);
-    }
-    return null;
-  }
-
-  BigInt foldInts(BigInt left, BigInt right);
-}
-
-class BitOrOperation extends BinaryBitOperation {
-  final String name = '|';
-  const BitOrOperation();
-  BigInt foldInts(BigInt left, BigInt right) => left | right;
-  apply(left, right) => 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 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;
-}
-
-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 DART_CONSTANT_SYSTEM.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 DART_CONSTANT_SYSTEM.createInt(foldedValue);
-      } else {
-        return DART_CONSTANT_SYSTEM.createDouble(foldedValue);
-      }
-    }
-    return null;
-  }
-
-  bool isDivide() => false;
-  bool isTruncatingDivide() => false;
-  foldInts(BigInt left, BigInt right);
-  foldNums(num left, num 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 RemainderOperation extends ArithmeticNumOperation {
-  final String name = 'remainder';
-  const RemainderOperation();
-  BigInt foldInts(BigInt left, BigInt right) => null;
-  // Not a defined constant operation.
-  num foldNums(num left, num right) => null;
-  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 DART_CONSTANT_SYSTEM.createInt(result);
-    } else if (left.isNum && right.isNum) {
-      NumConstantValue leftNum = left;
-      NumConstantValue rightNum = right;
-      double result = leftNum.doubleValue + rightNum.doubleValue;
-      return DART_CONSTANT_SYSTEM.createDouble(result);
-    } else if (left.isString && right.isString) {
-      StringConstantValue leftString = left;
-      StringConstantValue rightString = right;
-      String result = leftString.stringValue + rightString.stringValue;
-      return DART_CONSTANT_SYSTEM.createString(result);
-    } else {
-      return null;
-    }
-  }
-
-  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 DART_CONSTANT_SYSTEM.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 DART_CONSTANT_SYSTEM.createBool(result);
-    }
-
-    if (left.isNum && right.isNum) {
-      NumConstantValue leftNum = left;
-      NumConstantValue rightNum = right;
-      bool result = leftNum.doubleValue == rightNum.doubleValue;
-      return DART_CONSTANT_SYSTEM.createBool(result);
-    }
-
-    if (left.isConstructedObject) {
-      if (right.isNull) {
-        return DART_CONSTANT_SYSTEM.createBool(false);
-      }
-      // Unless we know that the user-defined object does not implement the
-      // equality operator we cannot fold here.
-      return null;
-    }
-
-    return DART_CONSTANT_SYSTEM.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 DART_CONSTANT_SYSTEM.createBool(left == right);
-  }
-
-  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 DART_CONSTANT_SYSTEM.createIntFromInt(value);
-    }
-    return null;
-  }
-}
-
-class UnfoldedUnaryOperation implements UnaryOperation {
-  final String name;
-  const UnfoldedUnaryOperation(this.name);
-  ConstantValue fold(ConstantValue constant) {
-    return null;
-  }
-}
-
-/// A constant system implementing the Dart semantics. This system relies on
-/// the underlying runtime-system. That is, if dart2js is run in an environment
-/// that doesn't correctly implement Dart's semantics this constant system will
-/// not return the correct values.
-class DartConstantSystem extends ConstantSystem {
-  final add = const AddOperation();
-  final bitAnd = const BitAndOperation();
-  final bitNot = const BitNotOperation();
-  final bitOr = const BitOrOperation();
-  final bitXor = const BitXorOperation();
-  final booleanAnd = const BooleanAndOperation();
-  final booleanOr = const BooleanOrOperation();
-  final divide = const DivideOperation();
-  final equal = const EqualsOperation();
-  final greaterEqual = const GreaterEqualOperation();
-  final greater = const GreaterOperation();
-  final identity = const IdentityOperation();
-  final ifNull = const IfNullOperation();
-  final lessEqual = const LessEqualOperation();
-  final less = const LessOperation();
-  final modulo = const ModuloOperation();
-  final multiply = const MultiplyOperation();
-  final negate = const NegateOperation();
-  final not = const NotOperation();
-  final remainder = const RemainderOperation();
-  final shiftLeft = const ShiftLeftOperation();
-  final shiftRight = const ShiftRightOperation();
-  final subtract = const SubtractOperation();
-  final truncatingDivide = const TruncatingDivideOperation();
-  final codeUnitAt = const CodeUnitAtOperation();
-  final round = const UnfoldedUnaryOperation('round');
-  final abs = const UnfoldedUnaryOperation('abs');
-
-  // TODO(johnniwinther): Delete this (embed parts into JavaScript constant
-  // system where needed).
-  const DartConstantSystem();
-
-  @override
-  IntConstantValue createInt(BigInt i) => new IntConstantValue(i);
-
-  @override
-  DoubleConstantValue createDouble(double d) => new DoubleConstantValue(d);
-
-  @override
-  StringConstantValue createString(String string) {
-    return new StringConstantValue(string);
-  }
-
-  @override
-  BoolConstantValue createBool(bool value) => new BoolConstantValue(value);
-
-  @override
-  NullConstantValue createNull() => new NullConstantValue();
-
-  @override
-  ListConstantValue createList(InterfaceType type, List<ConstantValue> values) {
-    return new ListConstantValue(type, values);
-  }
-
-  @override
-  SetConstantValue createSet(CommonElements commonElements, InterfaceType type,
-          List<ConstantValue> values) =>
-      new SetConstantValue(type, values);
-
-  @override
-  MapConstantValue createMap(CommonElements commonElements, InterfaceType type,
-      List<ConstantValue> keys, List<ConstantValue> values) {
-    throw new UnsupportedError('DartConstantSystem.createMap');
-  }
-
-  @override
-  ConstantValue createType(CommonElements commonElements, DartType type) {
-    InterfaceType implementationType = commonElements.typeLiteralType;
-    return new TypeConstantValue(type, implementationType);
-  }
-
-  @override
-  ConstantValue createSymbol(CommonElements commonElements, String text) {
-    throw new UnsupportedError('DartConstantSystem.createSymbol');
-  }
-
-  bool isInt(ConstantValue constant) => constant.isInt;
-  bool isDouble(ConstantValue constant) => constant.isDouble;
-  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) {
-    return types.isSubtype(s, t);
-  }
-}
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 6b9de6a..fe256f7 100644
--- a/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart
@@ -5,7 +5,6 @@
 import '../compile_time_constants.dart';
 import '../compiler.dart' show Compiler;
 import '../constants/constant_system.dart';
-import '../constant_system_dart.dart';
 import '../elements/entities.dart';
 import 'constant_system_javascript.dart';
 
@@ -17,18 +16,16 @@
 /// [DartConstantCompiler] for the frontend interpretation of the constants and
 /// to a [JavaScriptConstantCompiler] for the backend interpretation.
 class JavaScriptConstantTask extends ConstantCompilerTask {
-  ConstantSystem dartConstantSystem;
   JavaScriptConstantCompiler jsConstantCompiler;
 
   JavaScriptConstantTask(Compiler compiler)
-      : this.dartConstantSystem = const DartConstantSystem(),
-        this.jsConstantCompiler = new JavaScriptConstantCompiler(),
+      : this.jsConstantCompiler = new JavaScriptConstantCompiler(),
         super(compiler.measurer);
 
   String get name => 'ConstantHandler';
 
   @override
-  ConstantSystem get constantSystem => dartConstantSystem;
+  ConstantSystem get constantSystem => JavaScriptConstantSystem.only;
 }
 
 /// The [JavaScriptConstantCompiler] is used to keep track of compile-time
diff --git a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
index 5d3c205..3b1b3ce 100644
--- a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
@@ -4,21 +4,21 @@
 
 library dart2js.constant_system.js;
 
-import '../constant_system_dart.dart';
 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 extends BitNotOperation {
+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 = DART_CONSTANT_SYSTEM.createInt(BigInt.zero);
+        constant = JavaScriptConstantSystem.only.createInt(BigInt.zero);
       }
       IntConstantValue intConstant = constant;
       // We convert the result of bit-operations to 32 bit unsigned integers.
@@ -28,6 +28,23 @@
   }
 }
 
+/// 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 {
@@ -40,10 +57,10 @@
   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 = DART_CONSTANT_SYSTEM.createInt(BigInt.zero);
+      left = JavaScriptConstantSystem.only.createInt(BigInt.zero);
     }
     if (right.isMinusZero) {
-      right = DART_CONSTANT_SYSTEM.createInt(BigInt.zero);
+      right = JavaScriptConstantSystem.only.createInt(BigInt.zero);
     }
     IntConstantValue result = dartBitOperation.fold(left, right);
     if (result != null) {
@@ -56,6 +73,17 @@
   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());
 
@@ -80,13 +108,30 @@
         truncatedValue -= BigInt.two * (truncatedValue & SIGN_BIT);
       }
       if (value != truncatedValue) {
-        left = DART_CONSTANT_SYSTEM.createInt(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();
 
@@ -105,6 +150,33 @@
   }
 }
 
+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;
@@ -122,6 +194,38 @@
   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';
 
@@ -152,6 +256,20 @@
   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();
 
@@ -184,7 +302,7 @@
 
 class JavaScriptRoundOperation implements UnaryOperation {
   const JavaScriptRoundOperation();
-  String get name => DART_CONSTANT_SYSTEM.round.name;
+  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.
@@ -221,6 +339,267 @@
   }
 }
 
+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 {
diff --git a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
index a4bfd96..f0c2da5 100644
--- a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
+++ b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
@@ -2,9 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import '../constant_system_dart.dart';
 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 916228a..215449d 100644
--- a/tests/compiler/dart2js/analyses/dart2js_allowed.json
+++ b/tests/compiler/dart2js/analyses/dart2js_allowed.json
@@ -147,7 +147,23 @@
     "Dynamic invocation of '-'.": 1
   },
   "pkg/compiler/lib/src/js_backend/constant_system_javascript.dart": {
-    "Dynamic invocation of 'remainder'.": 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 '<'.": 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": {
     "Dynamic access of 'index'.": 1
@@ -200,25 +216,6 @@
     "Dynamic access of 'usedBy'.": 2,
     "Dynamic access of 'inputs'.": 1
   },
-  "pkg/compiler/lib/src/constant_system_dart.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 '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
-  },
   "third_party/pkg/dart2js_info/lib/src/util.dart": {
     "Dynamic access of 'name'.": 1,
     "Dynamic invocation of '-'.": 1
diff --git a/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart b/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart
index 0660b7f..98366be 100644
--- a/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart
+++ b/tests/compiler/dart2js/model/constant_expression_evaluate_test.dart
@@ -147,7 +147,6 @@
     const ConstantData('true', 'BoolConstant(true)'),
     const ConstantData('0', 'IntConstant(0)'),
     const ConstantData('0.0', 'IntConstant(0)'),
-    const ConstantData('0.5', 'DoubleConstant(0.5)'),
     const ConstantData('"foo"', 'StringConstant("foo")'),
     const ConstantData('1 + 2', 'IntConstant(3)'),
     const ConstantData('-(1)', 'IntConstant(-1)'),