Merge "Fix off-by-one error in range computation."
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 5c12d95..86ee040 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -301,7 +301,7 @@
         ListIterator<LocalRange> it = openRanges.listIterator(0);
         while (it.hasNext()) {
           LocalRange openRange = it.next();
-          if (openRange.end < index) {
+          if (openRange.end <= index) {
             it.remove();
             assert currentLocals.get(openRange.register) == openRange.local;
             currentLocals.put(openRange.register, null);
diff --git a/src/test/java/com/android/tools/r8/debuginfo/ExceptionLocalTest.java b/src/test/java/com/android/tools/r8/debuginfo/ExceptionLocalTest.java
new file mode 100644
index 0000000..8abac60
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/ExceptionLocalTest.java
@@ -0,0 +1,39 @@
+// Copyright (c) 2017, the R8 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.
+
+package com.android.tools.r8.debuginfo;
+
+public class ExceptionLocalTest {
+
+  public void foo(int x) {
+    Integer obj = new Integer(x + x);
+    long l = obj.longValue();
+    try {
+      l = obj.longValue();
+      x = (int) l / x;
+      invokerange(l, l, l, l, l, l);
+      sout(x);
+    } catch (ArithmeticException e) {
+      sout(l);
+    } catch (RuntimeException e) {
+      sout(l); // We should not attempt to read the previous definition of 'e' here or below.
+    } catch (Throwable e) {
+      sout(l);
+    }
+  }
+
+  private void sout(long l) {
+    System.out.print(l);
+  }
+
+  private void invokerange(long a, long b, long c, long d, long e, long f) {
+    if (a != d) {
+      throw new RuntimeException("unexpected");
+    }
+  }
+
+  public static void main(String[] args) {
+    new ExceptionLocalTest().foo(21);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/ExceptionLocalTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/ExceptionLocalTestRunner.java
new file mode 100644
index 0000000..2998c70
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/ExceptionLocalTestRunner.java
@@ -0,0 +1,47 @@
+// Copyright (c) 2017, the R8 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.
+
+package com.android.tools.r8.debuginfo;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.utils.AndroidApp;
+import org.junit.Test;
+
+public class ExceptionLocalTestRunner extends DebugInfoTestBase {
+
+  @Test
+  public void testExceptionLocal() throws Exception {
+    Class clazz = ExceptionLocalTest.class;
+
+    AndroidApp d8App = compileWithD8(clazz);
+    AndroidApp dxApp = getDxCompiledSources();
+
+    String expected = "2";
+    assertEquals(expected, runOnJava(clazz));
+    assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
+    assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
+
+    checkExceptionLocal(inspectMethod(d8App, clazz, "void", "foo", "int"));
+    checkExceptionLocal(inspectMethod(dxApp, clazz, "void", "foo", "int"));
+  }
+
+  private void checkExceptionLocal(DebugInfoInspector info) {
+    String self = ExceptionLocalTest.class.getCanonicalName();
+    String Integer = "java.lang.Integer";
+    info.checkStartLine(10);
+    info.checkLineHasExactLocals(10, "this", self, "x", "int");
+    info.checkLineHasExactLocals(11, "this", self, "x", "int", "obj", Integer);
+    info.checkNoLine(12);
+    info.checkLineHasExactLocals(13, "this", self, "x", "int", "obj", Integer, "l", "long");
+    info.checkLineHasExactLocals(14, "this", self, "x", "int", "obj", Integer, "l", "long");
+    info.checkLineHasExactLocals(15, "this", self, "x", "int", "obj", Integer, "l", "long");
+    info.checkLineHasExactLocals(18, "this", self, "x", "int", "obj", Integer, "l", "long",
+        "e", "java.lang.ArithmeticException");
+    info.checkLineHasExactLocals(20, "this", self, "x", "int", "obj", Integer, "l", "long",
+        "e", "java.lang.RuntimeException");
+    info.checkLineHasExactLocals(22, "this", self, "x", "int", "obj", Integer, "l", "long",
+        "e", "java.lang.Throwable");
+  }
+}