Treat 64 bit ints as unsigned until conversion to JS.

Change-Id: Idb9c5d4a3562f59bc75a5bb7eef4b7af8f5df992
Reviewed-on: https://dart-review.googlesource.com/57714
Commit-Queue: Emily Fortuna <efortuna@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
diff --git a/pkg/compiler/lib/src/kernel/element_map_mixins.dart b/pkg/compiler/lib/src/kernel/element_map_mixins.dart
index c661c48..d8c74cc 100644
--- a/pkg/compiler/lib/src/kernel/element_map_mixins.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_mixins.dart
@@ -604,7 +604,8 @@
 
   @override
   ConstantExpression visitIntLiteral(ir.IntLiteral node) {
-    return new IntConstantExpression(new BigInt.from(node.value));
+    return new IntConstantExpression(
+        new BigInt.from(node.value).toUnsigned(64));
   }
 
   @override
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 540ce0b..06dd3fe 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -2634,7 +2634,7 @@
 
   @override
   void visitIntLiteral(ir.IntLiteral node) {
-    stack.add(graph.addConstantInt(node.value, closedWorld));
+    stack.add(graph.addConstantIntAsUnsigned(node.value, closedWorld));
   }
 
   @override
diff --git a/pkg/compiler/lib/src/ssa/kernel_impact.dart b/pkg/compiler/lib/src/ssa/kernel_impact.dart
index 950aa78..2352143 100644
--- a/pkg/compiler/lib/src/ssa/kernel_impact.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_impact.dart
@@ -235,8 +235,23 @@
 
   @override
   void visitIntLiteral(ir.IntLiteral literal) {
-    impactBuilder.registerConstantLiteral(
-        new IntConstantExpression(new BigInt.from(literal.value)));
+    // Check that this value can be precisely represented as a double, and throw
+    // an error if not:
+    if (new BigInt.from(literal.value) !=
+        new BigInt.from(literal.value.toDouble())) {
+      // TODO(efortuna): Switch to error message.
+      reporter.reportWarningMessage(
+          CURRENT_ELEMENT_SPANNABLE, MessageKind.GENERIC, {
+        'text': 'The integer literal '
+            '${new BigInt.from(literal.value)} cannot be represented'
+            ' exactly in JavaScript and will be rounded to '
+            '${new BigInt.from(literal.value.toDouble())}. Use the rounded '
+            'value to avoid this warning.'
+      });
+    }
+
+    impactBuilder.registerConstantLiteral(new IntConstantExpression(
+        new BigInt.from(literal.value).toUnsigned(64)));
   }
 
   @override
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 59ac3b2..2258231 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -301,6 +301,12 @@
         closedWorld.constantSystem.createIntFromInt(i), closedWorld);
   }
 
+  HConstant addConstantIntAsUnsigned(int i, JClosedWorld closedWorld) {
+    return addConstant(
+        closedWorld.constantSystem.createInt(new BigInt.from(i).toUnsigned(64)),
+        closedWorld);
+  }
+
   HConstant addConstantDouble(double d, JClosedWorld closedWorld) {
     return addConstant(closedWorld.constantSystem.createDouble(d), closedWorld);
   }
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 74c7866..1e189df 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -7053,6 +7053,7 @@
 LayoutTests/fast/canvas/rgba-parsing_t01: Pass, RuntimeError
 LibTest/core/Invocation/namedArguments_A01_t01: RuntimeError
 LibTest/core/double/isInfinite_A01_t03: CompileTimeError # Larger than 64 bit int
+LibTest/core/double/operator_GE_A01_t02: RuntimeError # WontFix: Not representable in JS.
 LibTest/core/int/abs_A01_t01: CompileTimeError # Larger than 64 bit int
 LibTest/core/int/ceilToDouble_A01_t01: CompileTimeError # Larger than 64 bit int
 LibTest/core/int/ceil_A01_t01: CompileTimeError # Larger than 64 bit int
@@ -7105,6 +7106,7 @@
 LibTest/html/Window/requestFileSystem_A01_t01: Crash
 LibTest/html/Window/requestFileSystem_A01_t02: Crash
 LibTest/html/Window/requestFileSystem_A02_t01: Crash
+LibTest/math/pow_A09_t01: RuntimeError # WontFix: Not representable in JS.
 LibTest/math/pow_A10_t01: CompileTimeError # Larger than 64 bit int
 WebPlatformTest/html/semantics/embedded-content/the-audio-element/audio_constructor_t01: RuntimeError
 
diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status
index c89576d..aeef609 100644
--- a/tests/corelib_2/corelib_2.status
+++ b/tests/corelib_2/corelib_2.status
@@ -66,6 +66,7 @@
 from_environment_const_type_test/16: MissingCompileTimeError # Flutter Issue 9111
 from_environment_const_type_test/none: Fail # Flutter Issue 9111
 int_from_environment2_test: Fail # Flutter Issue 9111
+int_from_environment_int64_test: Fail # Flutter Issue 9111
 int_from_environment_test: Fail # Flutter Issue 9111
 main_test: RuntimeError # Flutter Issue 9111
 string_from_environment2_test: Fail # Flutter Issue 9111
@@ -212,8 +213,6 @@
 cast_test: RuntimeError
 error_stack_trace1_test: RuntimeError
 growable_list_test: RuntimeError
-int_parse_radix_test/01: RuntimeError
-int_parse_radix_test/02: RuntimeError
 integer_to_radix_string_test/01: RuntimeError
 integer_to_radix_string_test/02: RuntimeError
 integer_to_radix_string_test/none: RuntimeError
@@ -229,15 +228,19 @@
 uri_test: RuntimeError
 
 [ $compiler == dart2js && $fasta ]
-int_from_environment_test: Pass # Issue 31762
-int_parse_radix_test/none: Pass # Issue 31762
+int_from_environment_int64_test: RuntimeError # WontFix: Int not precisely representable in JS
+int_parse_radix_int64_test/01: RuntimeError # WontFix: Int not precisely representable in JS
+int_parse_radix_int64_test/02: RuntimeError # WontFix: Int not precisely representable in JS
+int_parse_radix_int64_test/none: RuntimeError # WontFix: Int not precisely representable in JS
+int_parse_radix_test/01: RuntimeError
+int_parse_radix_test/badTypes: RuntimeError # Issue 33351
+int_parse_radix_test/none: RuntimeError # Issue 33351
+int_try_parse_int64_test: RuntimeError # WontFix: Int not precisely representable in JS
 
 [ $compiler == dart2js && $fasta && $host_checked && $strong ]
 cast_test: RuntimeError
 error_stack_trace1_test: RuntimeError # Issue 12399
 growable_list_test: RuntimeError # Concurrent modifications test always runs
-int_parse_radix_test/01: RuntimeError
-int_parse_radix_test/02: RuntimeError
 integer_to_radix_string_test/01: RuntimeError
 integer_to_radix_string_test/02: RuntimeError
 integer_to_radix_string_test/none: RuntimeError
@@ -260,7 +263,6 @@
 error_stack_trace1_test: RuntimeError # Issue 12399
 growable_list_test: RuntimeError # Concurrent modifications test always runs
 hash_set_test/01: Crash # Assertion failure: Cannot find value Instance of 'ThisLocal' in (local(_CustomHashSet.#x), local(_CustomHashSet.#)) for j:closure_call(_CustomHashSet__CustomHashSet_closure.call).
-int_parse_radix_test/01: RuntimeError
 int_parse_radix_test/02: RuntimeError
 integer_to_radix_string_test/01: RuntimeError
 integer_to_radix_string_test/02: RuntimeError
@@ -414,8 +416,8 @@
 error_stack_trace_test/nullThrown: RuntimeError # .stackTrace not present for exception caught from 'throw null;'
 hash_set_test/01: RuntimeError # Issue 29921
 int_modulo_arith_test/none: RuntimeError # Issue 29921
+int_parse_radix_int64_test/02: RuntimeError
 int_parse_radix_test/01: RuntimeError # Issue 29921
-int_parse_radix_test/02: RuntimeError # Issue 29921
 int_parse_with_limited_ints_test: Skip # Requires fixed-size int64 support.
 integer_arith_vm_test/modPow: RuntimeError # Issue 30170
 integer_parsed_arith_vm_test: RuntimeError # Issue 29921
diff --git a/tests/corelib_2/int_from_environment_int64_test.dart b/tests/corelib_2/int_from_environment_int64_test.dart
new file mode 100644
index 0000000..b734556
--- /dev/null
+++ b/tests/corelib_2/int_from_environment_int64_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2013, 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.
+// SharedOptions=-Df=-9223372036854775808 -Dg=9223372036854775807
+
+import "package:expect/expect.dart";
+
+main() {
+  Expect.equals(-9223372036854775808, const int.fromEnvironment('f'));
+  Expect.equals(9223372036854775807, const int.fromEnvironment('g'));
+}
diff --git a/tests/corelib_2/int_from_environment_test.dart b/tests/corelib_2/int_from_environment_test.dart
index 5628ccd..62b1f1a 100644
--- a/tests/corelib_2/int_from_environment_test.dart
+++ b/tests/corelib_2/int_from_environment_test.dart
@@ -1,7 +1,7 @@
 // Copyright (c) 2013, 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.
-// SharedOptions=-Da=1 -Db=-12 -Dc=0x123 -Dd=-0x1234 -De=+0x112296 -Df=-9223372036854775808 -Dg=9223372036854775807
+// SharedOptions=-Da=1 -Db=-12 -Dc=0x123 -Dd=-0x1234 -De=+0x112296 -Df=-9007199254740991 -Dg=9007199254740991
 
 import "package:expect/expect.dart";
 
@@ -11,6 +11,6 @@
   Expect.equals(0x123, const int.fromEnvironment('c'));
   Expect.equals(-0x1234, const int.fromEnvironment('d'));
   Expect.equals(0x112296, const int.fromEnvironment('e'));
-  Expect.equals(-9223372036854775808, const int.fromEnvironment('f'));
-  Expect.equals(9223372036854775807, const int.fromEnvironment('g'));
+  Expect.equals(-9007199254740991, const int.fromEnvironment('f'));
+  Expect.equals(9007199254740991, const int.fromEnvironment('g'));
 }
diff --git a/tests/corelib_2/int_parse_radix_int64_test.dart b/tests/corelib_2/int_parse_radix_int64_test.dart
new file mode 100644
index 0000000..7a6fe18
--- /dev/null
+++ b/tests/corelib_2/int_parse_radix_int64_test.dart
@@ -0,0 +1,68 @@
+// 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.
+
+import "package:expect/expect.dart";
+import "dart:math" show pow, log;
+
+void main() {
+  const String oneByteWhiteSpace = "\x09\x0a\x0b\x0c\x0d\x20"
+      "\x85" //# 01: ok
+      "\xa0";
+  const String whiteSpace = "$oneByteWhiteSpace\u1680"
+      "\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a"
+      "\u2028\u2029\u202f\u205f\u3000\ufeff";
+
+  var digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+  var zeros = "0" * 64;
+
+  void testParse(int result, String radixString, int radix) {
+    var m = "$radixString/$radix->$result";
+    Expect.equals(
+        result, int.parse(radixString.toLowerCase(), radix: radix), m);
+    Expect.equals(
+        result, int.parse(radixString.toUpperCase(), radix: radix), m);
+    Expect.equals(result, int.parse(" $radixString", radix: radix), m);
+    Expect.equals(result, int.parse("$radixString ", radix: radix), m);
+    Expect.equals(result, int.parse(" $radixString ", radix: radix), m);
+    Expect.equals(result, int.parse("+$radixString", radix: radix), m);
+    Expect.equals(result, int.parse(" +$radixString", radix: radix), m);
+    Expect.equals(result, int.parse("+$radixString ", radix: radix), m);
+    Expect.equals(result, int.parse(" +$radixString ", radix: radix), m);
+    Expect.equals(-result, int.parse("-$radixString", radix: radix), m);
+    Expect.equals(-result, int.parse(" -$radixString", radix: radix), m);
+    Expect.equals(-result, int.parse("-$radixString ", radix: radix), m);
+    Expect.equals(-result, int.parse(" -$radixString ", radix: radix), m);
+    Expect.equals(
+        result,
+        int.parse("$oneByteWhiteSpace$radixString$oneByteWhiteSpace",
+            radix: radix),
+        m);
+    Expect.equals(
+        -result,
+        int.parse("$oneByteWhiteSpace-$radixString$oneByteWhiteSpace",
+            radix: radix),
+        m);
+    Expect.equals(result,
+        int.parse("$whiteSpace$radixString$whiteSpace", radix: radix), m);
+    Expect.equals(-result,
+        int.parse("$whiteSpace-$radixString$whiteSpace", radix: radix), m);
+
+    Expect.equals(result, int.parse("$zeros$radixString", radix: radix), m);
+    Expect.equals(result, int.parse("+$zeros$radixString", radix: radix), m);
+    Expect.equals(-result, int.parse("-$zeros$radixString", radix: radix), m);
+  }
+
+  final max = 9223372036854775807;
+  for (int i = 2; i <= 36; i++) { //             //# 02: ok
+    // Test with bignums. //                     //# 02: continued
+    final n = (log(max) / log(i)).truncate(); // //# 02: continued
+    var digit = digits[i - 1]; //                //# 02: continued
+    testParse(pow(i, n) - 1, digit * n, i); //   //# 02: continued
+    testParse(0, zeros, i); //                   //# 02: continued
+  } //                                           //# 02: continued
+
+  // Big number.
+  Expect.equals(9223372036854775807, int.parse("9223372036854775807"));
+  Expect.equals(-9223372036854775808, int.parse("-9223372036854775808"));
+}
diff --git a/tests/corelib_2/int_parse_radix_test.dart b/tests/corelib_2/int_parse_radix_test.dart
index cf49135..d7ca92a 100644
--- a/tests/corelib_2/int_parse_radix_test.dart
+++ b/tests/corelib_2/int_parse_radix_test.dart
@@ -65,7 +65,7 @@
     }
   }
 
-  final max = 9223372036854775807;
+  final max = 0x1FFFFFFFFFFFFF;
   for (int i = 2; i <= 36; i++) { //             //# 02: ok
     // Test with bignums. //                     //# 02: continued
     final n = (log(max) / log(i)).truncate(); // //# 02: continued
@@ -78,8 +78,9 @@
   Expect.equals(0xABCD, int.parse("ABCD", radix: 16));
   Expect.equals(0xABCD, int.parse("abcd", radix: 16));
   Expect.equals(15628859, int.parse("09azAZ", radix: 36));
-  // Big number.
-  Expect.equals(9223372036854775807, int.parse("9223372036854775807"));
+  // Big-ish number. (2^53)
+  Expect.equals(9007199254740991, int.parse("9007199254740991"));
+  Expect.equals(-9007199254740991, int.parse("-9007199254740991"));
   Expect.equals(-9223372036854775808, int.parse("-9223372036854775808"));
   // Allow whitespace before and after the number.
   Expect.equals(1, int.parse(" 1", radix: 2));
diff --git a/tests/corelib_2/int_try_parse_int64_test.dart b/tests/corelib_2/int_try_parse_int64_test.dart
new file mode 100644
index 0000000..419da75
--- /dev/null
+++ b/tests/corelib_2/int_try_parse_int64_test.dart
@@ -0,0 +1,12 @@
+// 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.
+
+import "package:expect/expect.dart";
+import "dart:math" show pow, log;
+
+void main() {
+  // Big numbers (representable as both Int64 and double).
+  Expect.equals(9223372036854774784, int.tryParse("9223372036854774784"));
+  Expect.equals(-9223372036854775808, int.tryParse("-9223372036854775808"));
+}
diff --git a/tests/corelib_2/int_try_parse_test.dart b/tests/corelib_2/int_try_parse_test.dart
index eb1fc86..3d9d294 100644
--- a/tests/corelib_2/int_try_parse_test.dart
+++ b/tests/corelib_2/int_try_parse_test.dart
@@ -87,9 +87,9 @@
   Expect.equals(0xABCD, int.tryParse("ABCD", radix: 16));
   Expect.equals(0xABCD, int.tryParse("abcd", radix: 16));
   Expect.equals(15628859, int.tryParse("09azAZ", radix: 36));
-  // Big numbers (representable as both Int64 and double).
-  Expect.equals(9223372036854774784, int.tryParse("9223372036854774784"));
-  Expect.equals(-9223372036854775808, int.tryParse("-9223372036854775808"));
+  // Bigish numbers (representable precisely as both Int64 and double (2^53)).
+  Expect.equals(9007199254740991, int.tryParse("9007199254740991"));
+  Expect.equals(-9007199254740991, int.tryParse("-9007199254740991"));
   // Allow whitespace before and after the number.
   Expect.equals(1, int.tryParse(" 1", radix: 2));
   Expect.equals(1, int.tryParse("1 ", radix: 2));
diff --git a/tests/language_2/arithmetic_int64_test.dart b/tests/language_2/arithmetic_int64_test.dart
new file mode 100644
index 0000000..6354af0
--- /dev/null
+++ b/tests/language_2/arithmetic_int64_test.dart
@@ -0,0 +1,28 @@
+// 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.
+// Dart test program to test arithmetic operations.
+// VMOptions=--optimization-counter-threshold=10 --no-use-osr --no-background-compilation
+
+library arithmetic_test;
+
+import "package:expect/expect.dart";
+import 'dart:math';
+
+class ArithmeticTest {
+  static runOne() {
+    // Math functions.
+    Expect.equals(1234567890123456789, int.parse("1234567890123456789"));
+    Expect.equals(-1234567890123456789, int.parse("-1234567890123456789"));
+    Expect.equals(9223372036854775807, int.parse("9223372036854775807"));
+    Expect.equals(-9223372036854775808, int.parse("-9223372036854775808"));
+  }
+
+  static testMain() {
+    runOne();
+  }
+}
+
+main() {
+  ArithmeticTest.testMain();
+}
diff --git a/tests/language_2/arithmetic_test.dart b/tests/language_2/arithmetic_test.dart
index 6ec3a6a..7784f35 100644
--- a/tests/language_2/arithmetic_test.dart
+++ b/tests/language_2/arithmetic_test.dart
@@ -403,10 +403,8 @@
 
     Expect.equals(12, int.parse("12"));
     Expect.equals(-12, int.parse("-12"));
-    Expect.equals(1234567890123456789, int.parse("1234567890123456789"));
-    Expect.equals(-1234567890123456789, int.parse("-1234567890123456789"));
-    Expect.equals(9223372036854775807, int.parse("9223372036854775807"));
-    Expect.equals(-9223372036854775808, int.parse("-9223372036854775808"));
+    Expect.equals(9007199254740991, int.parse("9007199254740991"));
+    Expect.equals(-9007199254740991, int.parse("-9007199254740991"));
     // Type checks.
     {
       int i = int.parse("12");
diff --git a/tests/language_2/language_2_dart2js.status b/tests/language_2/language_2_dart2js.status
index 59f8197..75a84ff 100644
--- a/tests/language_2/language_2_dart2js.status
+++ b/tests/language_2/language_2_dart2js.status
@@ -844,6 +844,7 @@
 type_variable_promotion_test: RuntimeError
 
 [ $compiler == dart2js && $fasta ]
+arithmetic_int64_test: RuntimeError # WontFix: Int not precisely representable in JS
 call_method_as_cast_test/06: RuntimeError
 call_method_implicit_tear_off_implements_function_test/05: RuntimeError
 call_method_implicit_tear_off_implements_function_test/06: RuntimeError
@@ -856,6 +857,7 @@
 function_propagation_test: RuntimeError
 generic_test/01: MissingCompileTimeError # front end does not validate `extends`
 instantiate_tearoff_of_call_test: RuntimeError
+mint_compares_test: RuntimeError # WontFix: Int not precisely representable in JS
 mixin_type_parameter_inference_error_test/none: CompileTimeError
 mixin_type_parameter_inference_previous_mixin_test/01: CompileTimeError
 mixin_type_parameter_inference_previous_mixin_test/02: CompileTimeError