Merge "[CF] Implement simple store/load elimination and avoid storing constants."
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index cc8e0db..2fe0796 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -23,7 +23,8 @@
     this.name = name;
     if (!name.isValidMethodName()) {
       throw new CompilationError(
-          "Method name '" + name.toString() + "' cannot be represented in dex format.");
+          "Method name '" + name.toASCIIString() + "' in class '" + holder.toSourceString() +
+              "' cannot be represented in dex format.");
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexString.java b/src/main/java/com/android/tools/r8/graph/DexString.java
index 434bad7..4bc9a50 100644
--- a/src/main/java/com/android/tools/r8/graph/DexString.java
+++ b/src/main/java/com/android/tools/r8/graph/DexString.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.StringUtils;
 import java.io.UTFDataFormatException;
 import java.util.Arrays;
 
@@ -49,6 +50,23 @@
     }
   }
 
+  public String toASCIIString() {
+    try {
+      String s = decode();
+      StringBuilder builder = new StringBuilder();
+      for (char ch : s.toCharArray()) {
+        if (0x1f < ch && ch < 0x7f) {  // 0 - 0x1f and 0x7f are control characters.
+          builder.append(ch);
+        } else {
+          builder.append("\\u").append(StringUtils.hexString(ch, 4, false));
+        }
+      }
+      return builder.toString();
+    } catch (UTFDataFormatException e) {
+      throw new RuntimeException("Bad format", e);
+    }
+  }
+
   public int numberOfLeadingSquareBrackets() {
     int result = 0;
     while (content.length > result && content[result] == ((byte) '[')) {
diff --git a/src/main/java/com/android/tools/r8/utils/StringUtils.java b/src/main/java/com/android/tools/r8/utils/StringUtils.java
index 8712b7a..de77dac 100644
--- a/src/main/java/com/android/tools/r8/utils/StringUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/StringUtils.java
@@ -155,26 +155,36 @@
   }
 
   public static String hexString(int value, int width) {
+    return hexString(value, width, false);
+  }
+
+  public static String hexString(int value, int width, boolean zeroXPrefix) {
     assert(0 <= width && width <= 8);
+    String prefix = zeroXPrefix ? "0x" : "";
     String hex = Integer.toHexString(value);
     if (value >= 0) {
-      return "0x" + zeroPrefixString(hex, width);
+      return prefix + zeroPrefixString(hex, width);
     } else {
       // Negative ints are always formatted as 8 characters.
       assert(hex.length() == 8);
-      return "0x" + hex;
+      return prefix + hex;
     }
   }
 
   public static String hexString(long value, int width) {
+    return hexString(value, width, false);
+  }
+
+  public static String hexString(long value, int width, boolean zeroXPrefix) {
     assert(0 <= width && width <= 16);
+    String prefix = zeroXPrefix ? "0x" : "";
     String hex = Long.toHexString(value);
     if (value >= 0) {
-      return "0x" + zeroPrefixString(hex, width);
+      return prefix + zeroPrefixString(hex, width);
     } else {
       // Negative longs are always formatted as 16 characters.
       assert(hex.length() == 16);
-      return "0x" + hex;
+      return prefix + hex;
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/dex/DexStringTest.java b/src/test/java/com/android/tools/r8/dex/DexStringTest.java
index fa7f332..b12d876 100644
--- a/src/test/java/com/android/tools/r8/dex/DexStringTest.java
+++ b/src/test/java/com/android/tools/r8/dex/DexStringTest.java
@@ -88,4 +88,21 @@
     assertEquals(0, s.content[length - 1]);
     assertEquals(encodedLength, length - 1);
   }
+
+  @Test
+  public void testToASCIIString() {
+    DexItemFactory factory = new DexItemFactory();
+    assertEquals("\\u0000", factory.createString("\u0000").toASCIIString());
+    assertEquals("\\u0001", factory.createString("\u0001").toASCIIString());
+    assertEquals("\\u001f", factory.createString("\u001f").toASCIIString());
+    assertEquals(" ", factory.createString("\u0020").toASCIIString());
+    assertEquals("~", factory.createString("\u007e").toASCIIString());
+    assertEquals("\\u007f", factory.createString("\u007f").toASCIIString());
+    assertEquals("\\u0080", factory.createString("\u0080").toASCIIString());
+    assertEquals("\\u07ff", factory.createString("\u07ff").toASCIIString());
+    assertEquals("\\u0800", factory.createString("\u0800").toASCIIString());
+    assertEquals("\\uffff", factory.createString("\uffff").toASCIIString());
+    assertEquals("\\ud800\\udc00", factory.createString("\ud800\udc00").toASCIIString());
+    assertEquals("\\udbff\\udfff", factory.createString("\udbff\udfff").toASCIIString());
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/jasmin/InvalidMethodNames.java b/src/test/java/com/android/tools/r8/jasmin/InvalidMethodNames.java
index 7b035f6..0aa0f59 100644
--- a/src/test/java/com/android/tools/r8/jasmin/InvalidMethodNames.java
+++ b/src/test/java/com/android/tools/r8/jasmin/InvalidMethodNames.java
@@ -3,12 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.jasmin;
 
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.DexString;
 import com.google.common.collect.ImmutableList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -43,6 +45,8 @@
         t.printStackTrace(System.out);
         fail("Invalid dex method names should be compilation errors.");
       }
+      String asciiString = new DexString(name).toASCIIString();
+      assertTrue(t.getMessage().contains(asciiString));
     } catch (Throwable t) {
       t.printStackTrace(System.out);
       fail("Invalid dex method names should be compilation errors.");