Merge "Change return type of CfBuilder.build() to CfCode"
diff --git a/.gitignore b/.gitignore
index 86e3098..0e19a6f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,8 @@
 third_party/android_jar/lib-v[0-9][0-9].tar.gz
 third_party/benchmarks/santa-tracker
 third_party/benchmarks/santa-tracker.tar.gz
+third_party/desugar/desugar_*/
+third_party/desugar/desugar_*.tar.gz
 third_party/gmail/*
 !third_party/gmail/*.sha1
 third_party/gmscore/*
diff --git a/build.gradle b/build.gradle
index e0c50ee..4fae469 100644
--- a/build.gradle
+++ b/build.gradle
@@ -366,6 +366,7 @@
         "proguard/proguard_internal_159423826",
         "framework",
         "goyt",
+        "desugar/desugar_20180308"
     ],
 ]
 
diff --git a/src/main/java/com/android/tools/r8/ResourceShrinker.java b/src/main/java/com/android/tools/r8/ResourceShrinker.java
index 1df78be..d2969d6 100644
--- a/src/main/java/com/android/tools/r8/ResourceShrinker.java
+++ b/src/main/java/com/android/tools/r8/ResourceShrinker.java
@@ -91,7 +91,7 @@
 @Deprecated
 final public class ResourceShrinker {
 
-  final static class Command extends BaseCommand {
+  public final static class Command extends BaseCommand {
 
     Command(AndroidApp app) {
       super(app);
@@ -103,7 +103,7 @@
     }
   }
 
-  final public static class Builder extends BaseCommand.Builder<Command, Builder> {
+  public final static class Builder extends BaseCommand.Builder<Command, Builder> {
 
     @Override
     Builder self() {
@@ -120,7 +120,7 @@
    * Classes that would like to process data relevant to resource shrinking should implement this
    * interface.
    */
-  interface ReferenceChecker {
+  public interface ReferenceChecker {
 
     /**
      * Returns if the class with specified internal name should be processed. Typically,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index 86903fe..2f8de76 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -12,11 +12,15 @@
 
   private final DexMethod method;
   private final int opcode;
+  private final boolean itf;
 
-  public CfInvoke(int opcode, DexMethod method) {
+  public CfInvoke(int opcode, DexMethod method, boolean itf) {
     assert Opcodes.INVOKEVIRTUAL <= opcode && opcode <= Opcodes.INVOKEINTERFACE;
+    assert !(opcode == Opcodes.INVOKEVIRTUAL && itf) : "InvokeVirtual on interface type";
+    assert !(opcode == Opcodes.INVOKEINTERFACE && !itf) : "InvokeInterface on class type";
     this.opcode = opcode;
     this.method = method;
+    this.itf = itf;
   }
 
   public DexMethod getMethod() {
@@ -32,8 +36,7 @@
     String owner = method.getHolder().getInternalName();
     String name = method.name.toString();
     String desc = method.proto.toDescriptorString();
-    boolean isInterface = opcode == Opcodes.INVOKEINTERFACE;
-    visitor.visitMethodInsn(opcode, owner, name, desc, isInterface);
+    visitor.visitMethodInsn(opcode, owner, name, desc, itf);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index 0ccd724..958deb4 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -689,21 +689,23 @@
       AttributesAndAnnotations attrs =
           new AttributesAndAnnotations(type, annotationsDirectory.clazz, dexItemFactory);
 
-      DexClass clazz = classKind.create(
-          type,
-          Kind.DEX,
-          origin,
-          flags,
-          superclass,
-          typeListAt(interfacesOffsets[i]),
-          source,
-          attrs.getEnclosingMethodAttribute(),
-          attrs.getInnerClasses(),
-          attrs.getAnnotations(),
-          staticFields,
-          instanceFields,
-          directMethods,
-          virtualMethods);
+      DexClass clazz =
+          classKind.create(
+              type,
+              Kind.DEX,
+              origin,
+              flags,
+              superclass,
+              typeListAt(interfacesOffsets[i]),
+              source,
+              attrs.getEnclosingMethodAttribute(),
+              attrs.getInnerClasses(),
+              attrs.getAnnotations(),
+              staticFields,
+              instanceFields,
+              directMethods,
+              virtualMethods,
+              dexItemFactory.getSkipNameValidationForTesting());
       classCollection.accept(clazz);  // Update the application object.
     }
   }
diff --git a/src/main/java/com/android/tools/r8/graph/ClassKind.java b/src/main/java/com/android/tools/r8/graph/ClassKind.java
index 755cb7b..94b2076 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassKind.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassKind.java
@@ -27,7 +27,8 @@
         DexEncodedField[] staticFields,
         DexEncodedField[] instanceFields,
         DexEncodedMethod[] directMethods,
-        DexEncodedMethod[] virtualMethods);
+        DexEncodedMethod[] virtualMethods,
+        boolean skipNameValidationForTesting);
   }
 
   private final Factory factory;
@@ -52,7 +53,8 @@
       DexEncodedField[] staticFields,
       DexEncodedField[] instanceFields,
       DexEncodedMethod[] directMethods,
-      DexEncodedMethod[] virtualMethods) {
+      DexEncodedMethod[] virtualMethods,
+      boolean skipNameValidationForTesting) {
     return factory.create(
         type,
         kind,
@@ -67,7 +69,8 @@
         staticFields,
         instanceFields,
         directMethods,
-        virtualMethods);
+        virtualMethods,
+        skipNameValidationForTesting);
   }
 
   public boolean isOfKind(DexClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index d6b15eb..58053e2 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -64,7 +64,8 @@
       EnclosingMethodAttribute enclosingMethod,
       List<InnerClassAttribute> innerClasses,
       DexAnnotationSet annotations,
-      Origin origin) {
+      Origin origin,
+      boolean skipNameValidationForTesting) {
     assert origin != null;
     this.origin = origin;
     this.sourceFile = sourceFile;
@@ -87,7 +88,7 @@
         throw new CompilationError("Interface " + type.toString() + " cannot implement itself");
       }
     }
-    if (!type.descriptor.isValidClassDescriptor()) {
+    if (!skipNameValidationForTesting && !type.descriptor.isValidClassDescriptor()) {
       throw new CompilationError(
           "Class descriptor '"
               + type.descriptor.toString()
diff --git a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
index 6148b00..4308dd4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
@@ -29,7 +29,8 @@
       DexEncodedField[] staticFields,
       DexEncodedField[] instanceFields,
       DexEncodedMethod[] directMethods,
-      DexEncodedMethod[] virtualMethods) {
+      DexEncodedMethod[] virtualMethods,
+      boolean skipNameValidationForTesting) {
     super(
         sourceFile,
         interfaces,
@@ -43,7 +44,8 @@
         enclosingMember,
         innerClasses,
         annotations,
-        origin);
+        origin,
+        skipNameValidationForTesting);
     assert kind == Kind.CF : "Invalid kind " + kind + " for class-path class " + type;
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java
index fa3d6ad..ab0d654 100644
--- a/src/main/java/com/android/tools/r8/graph/DexField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -14,11 +14,11 @@
   public final DexType type;
   public final DexString name;
 
-  DexField(DexType clazz, DexType type, DexString name) {
+  DexField(DexType clazz, DexType type, DexString name, boolean skipNameValidationForTesting) {
     this.clazz = clazz;
     this.type = type;
     this.name = name;
-    if (!name.isValidFieldName()) {
+    if (!skipNameValidationForTesting && !name.isValidFieldName()) {
       throw new CompilationError(
           "Field name '" + name.toString() + "' cannot be represented in dex format.");
     }
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index ff3e30d..30d0dbe 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -227,6 +227,16 @@
   public final DexType annotationSynthesizedClassMap =
       createType("Lcom/android/tools/r8/annotations/SynthesizedClassMap;");
 
+  private boolean skipNameValidationForTesting = false;
+
+  public void setSkipNameValidationForTesting(boolean skipNameValidationForTesting) {
+    this.skipNameValidationForTesting = skipNameValidationForTesting;
+  }
+
+  public boolean getSkipNameValidationForTesting() {
+    return skipNameValidationForTesting;
+  }
+
   public synchronized void clearSubtypeInformation() {
     types.values().forEach(DexType::clearSubtypeInformation);
   }
@@ -479,7 +489,7 @@
 
   public DexField createField(DexType clazz, DexType type, DexString name) {
     assert !sorted;
-    DexField field = new DexField(clazz, type, name);
+    DexField field = new DexField(clazz, type, name, skipNameValidationForTesting);
     return canonicalize(fields, field);
   }
 
@@ -510,7 +520,7 @@
 
   public DexMethod createMethod(DexType holder, DexProto proto, DexString name) {
     assert !sorted;
-    DexMethod method = new DexMethod(holder, proto, name);
+    DexMethod method = new DexMethod(holder, proto, name, skipNameValidationForTesting);
     return canonicalize(methods, method);
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
index 4700553..9644558 100644
--- a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
@@ -29,7 +29,8 @@
       DexEncodedField[] staticFields,
       DexEncodedField[] instanceFields,
       DexEncodedMethod[] directMethods,
-      DexEncodedMethod[] virtualMethods) {
+      DexEncodedMethod[] virtualMethods,
+      boolean skipNameValidationForTesting) {
     super(
         sourceFile,
         interfaces,
@@ -43,7 +44,8 @@
         enclosingMember,
         innerClasses,
         annotations,
-        origin);
+        origin,
+        skipNameValidationForTesting);
     // Set all static field values to unknown. We don't want to use the value from the library
     // at compile time, as it can be different at runtime.
     for (DexEncodedField staticField : staticFields) {
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 621878f..c0c2e27 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -19,11 +19,11 @@
   // Caches used during processing.
   private Map<DexType, DexEncodedMethod> singleTargetCache;
 
-  DexMethod(DexType holder, DexProto proto, DexString name) {
+  DexMethod(DexType holder, DexProto proto, DexString name, boolean skipNameValidationForTesting) {
     this.holder = holder;
     this.proto = proto;
     this.name = name;
-    if (!name.isValidMethodName()) {
+    if (!skipNameValidationForTesting && !name.isValidMethodName()) {
       throw new CompilationError(
           "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/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index ffff10f..90db1d2 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -44,7 +44,8 @@
       DexEncodedField[] staticFields,
       DexEncodedField[] instanceFields,
       DexEncodedMethod[] directMethods,
-      DexEncodedMethod[] virtualMethods) {
+      DexEncodedMethod[] virtualMethods,
+      boolean skipNameValidationForTesting) {
     this(
         type,
         originKind,
@@ -60,6 +61,7 @@
         instanceFields,
         directMethods,
         virtualMethods,
+        skipNameValidationForTesting,
         Collections.emptyList());
   }
 
@@ -78,6 +80,7 @@
       DexEncodedField[] instanceFields,
       DexEncodedMethod[] directMethods,
       DexEncodedMethod[] virtualMethods,
+      boolean skipNameValidationForTesting,
       Collection<DexProgramClass> synthesizedDirectlyFrom) {
     super(
         sourceFile,
@@ -92,7 +95,8 @@
         enclosingMember,
         innerClasses,
         classAnnotations,
-        origin);
+        origin,
+        skipNameValidationForTesting);
     assert classAnnotations != null;
     this.originKind = originKind;
     this.synthesizedFrom = accumulateSynthesizedFrom(new HashSet<>(), synthesizedDirectlyFrom);
@@ -108,8 +112,6 @@
 
   @Override
   public void collectIndexedItems(IndexedItemCollection indexedItems) {
-    assert getEnclosingMethod() == null;
-    assert getInnerClasses().isEmpty();
     if (indexedItems.addClass(this)) {
       type.collectIndexedItems(indexedItems);
       if (superType != null) {
@@ -126,6 +128,12 @@
       if (interfaces != null) {
         interfaces.collectIndexedItems(indexedItems);
       }
+      if (getEnclosingMethod() != null) {
+        getEnclosingMethod().collectIndexedItems(indexedItems);
+      }
+      for (InnerClassAttribute attribute : getInnerClasses()) {
+        attribute.collectIndexedItems(indexedItems);
+      }
       synchronizedCollectAll(indexedItems, staticFields);
       synchronizedCollectAll(indexedItems, instanceFields);
       synchronizedCollectAll(indexedItems, directMethods);
diff --git a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
index ce741a3..fc5589f 100644
--- a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.dex.IndexedItemCollection;
 import org.objectweb.asm.ClassWriter;
 
 /**
@@ -61,4 +62,13 @@
         enclosingClass == ((EnclosingMethodAttribute) obj).enclosingClass &&
         enclosingMethod == ((EnclosingMethodAttribute) obj).enclosingMethod;
   }
+
+  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+    if (enclosingClass != null) {
+      enclosingClass.collectIndexedItems(indexedItems);
+    }
+    if (enclosingMethod != null) {
+      enclosingMethod.collectIndexedItems(indexedItems);
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java b/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
index 8a158de..ed22c96 100644
--- a/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.dex.IndexedItemCollection;
 import org.objectweb.asm.ClassWriter;
 
 /** Representation of an entry in the Java InnerClasses attribute table. */
@@ -65,4 +66,14 @@
         innerName == null ? null : innerName.toString(),
         access);
   }
+
+  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+    inner.collectIndexedItems(indexedItems);
+    if (outer != null) {
+      outer.collectIndexedItems(indexedItems);
+    }
+    if (innerName != null) {
+      innerName.collectIndexedItems(indexedItems);
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 945da10..32cc10b 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -251,7 +251,8 @@
               staticFields.toArray(new DexEncodedField[staticFields.size()]),
               instanceFields.toArray(new DexEncodedField[instanceFields.size()]),
               directMethods.toArray(new DexEncodedMethod[directMethods.size()]),
-              virtualMethods.toArray(new DexEncodedMethod[virtualMethods.size()]));
+              virtualMethods.toArray(new DexEncodedMethod[virtualMethods.size()]),
+              application.getFactory().getSkipNameValidationForTesting());
       if (clazz.isProgramClass()) {
         context.owner = clazz.asProgramClass();
         clazz.asProgramClass().setClassFileVersion(version);
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index ff8bd02..bf62fed 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -45,7 +45,7 @@
 
   public final boolean hasDebugPositions;
 
-  private final InternalOptions options;
+  public final InternalOptions options;
 
   public IRCode(
       InternalOptions options,
diff --git a/src/main/java/com/android/tools/r8/ir/code/Invoke.java b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
index 7f24908..af6d5a3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Invoke.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
@@ -39,15 +39,20 @@
 
   public static Invoke create(
       Type type, DexItem target, DexProto proto, Value result, List<Value> arguments) {
+    return create(type, target, proto, result, arguments, false);
+  }
+
+  public static Invoke create(
+      Type type, DexItem target, DexProto proto, Value result, List<Value> arguments, boolean itf) {
     switch (type) {
       case DIRECT:
-        return new InvokeDirect((DexMethod) target, result, arguments);
+        return new InvokeDirect((DexMethod) target, result, arguments, itf);
       case INTERFACE:
         return new InvokeInterface((DexMethod) target, result, arguments);
       case STATIC:
-        return new InvokeStatic((DexMethod) target, result, arguments);
+        return new InvokeStatic((DexMethod) target, result, arguments, itf);
       case SUPER:
-        return new InvokeSuper((DexMethod) target, result, arguments);
+        return new InvokeSuper((DexMethod) target, result, arguments, itf);
       case VIRTUAL:
         return new InvokeVirtual((DexMethod) target, result, arguments);
       case NEW_ARRAY:
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index 7338a2b..fa85845 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -21,8 +21,15 @@
 
 public class InvokeDirect extends InvokeMethodWithReceiver {
 
+  private final boolean itf;
+
   public InvokeDirect(DexMethod target, Value result, List<Value> arguments) {
+    this(target, result, arguments, false);
+  }
+
+  public InvokeDirect(DexMethod target, Value result, List<Value> arguments, boolean itf) {
     super(target, result, arguments);
+    this.itf = itf;
   }
 
   @Override
@@ -114,6 +121,6 @@
 
   @Override
   public void buildCf(CfBuilder builder) {
-    builder.add(new CfInvoke(Opcodes.INVOKESPECIAL, getInvokedMethod()));
+    builder.add(new CfInvoke(Opcodes.INVOKESPECIAL, getInvokedMethod(), itf));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
index 60aee95..d29e3eb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
@@ -103,6 +103,6 @@
 
   @Override
   public void buildCf(CfBuilder builder) {
-    builder.add(new CfInvoke(Opcodes.INVOKEINTERFACE, getInvokedMethod()));
+    builder.add(new CfInvoke(Opcodes.INVOKEINTERFACE, getInvokedMethod(), true));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
index 01cd5f5..0e63cc7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
@@ -90,7 +90,7 @@
     // To translate InvokePolymorphic back into InvokeVirtual, use the original prototype
     // that is stored in getProto().
     DexMethod method = factory.createMethod(dexMethod.holder, getProto(), dexMethod.name);
-    builder.add(new CfInvoke(Opcodes.INVOKEVIRTUAL, method));
+    builder.add(new CfInvoke(Opcodes.INVOKEVIRTUAL, method, false));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index e628f39..896fca9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -22,8 +22,15 @@
 
 public class InvokeStatic extends InvokeMethod {
 
+  private final boolean itf;
+
   public InvokeStatic(DexMethod target, Value result, List<Value> arguments) {
+    this(target, result, arguments, false);
+  }
+
+  public InvokeStatic(DexMethod target, Value result, List<Value> arguments, boolean itf) {
     super(target, result, arguments);
+    this.itf = itf;
   }
 
   @Override
@@ -109,7 +116,7 @@
 
   @Override
   public void buildCf(CfBuilder builder) {
-    builder.add(new CfInvoke(Opcodes.INVOKESTATIC, getInvokedMethod()));
+    builder.add(new CfInvoke(Opcodes.INVOKESTATIC, getInvokedMethod(), itf));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
index 9e9a096..c761184 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
@@ -22,8 +22,11 @@
 
 public class InvokeSuper extends InvokeMethodWithReceiver {
 
-  public InvokeSuper(DexMethod target, Value result, List<Value> arguments) {
+  public final boolean itf;
+
+  public InvokeSuper(DexMethod target, Value result, List<Value> arguments, boolean itf) {
     super(target, result, arguments);
+    this.itf = itf;
   }
 
   @Override
@@ -76,7 +79,7 @@
 
   @Override
   public void buildCf(CfBuilder builder) {
-    builder.add(new CfInvoke(Opcodes.INVOKESPECIAL, getInvokedMethod()));
+    builder.add(new CfInvoke(Opcodes.INVOKESPECIAL, getInvokedMethod(), itf));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index 8a41c4e..5ef74b8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -103,6 +103,6 @@
 
   @Override
   public void buildCf(CfBuilder builder) {
-    builder.add(new CfInvoke(Opcodes.INVOKEVIRTUAL, getInvokedMethod()));
+    builder.add(new CfInvoke(Opcodes.INVOKEVIRTUAL, getInvokedMethod(), false));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 20051f9..72402b3 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -997,7 +997,8 @@
     add(instruction);
   }
 
-  public void addInvoke(Type type, DexItem item, DexProto callSiteProto, List<Value> arguments)
+  public void addInvoke(
+      Type type, DexItem item, DexProto callSiteProto, List<Value> arguments, boolean itf)
       throws ApiLevelException {
     if (type == Invoke.Type.POLYMORPHIC) {
       assert item instanceof DexMethod;
@@ -1014,7 +1015,12 @@
             null /* sourceString */);
       }
     }
-    add(Invoke.create(type, item, callSiteProto, null, arguments));
+    add(Invoke.create(type, item, callSiteProto, null, arguments, itf));
+  }
+
+  public void addInvoke(Type type, DexItem item, DexProto callSiteProto, List<Value> arguments)
+      throws ApiLevelException {
+    addInvoke(type, item, callSiteProto, arguments, false);
   }
 
   public void addInvoke(
@@ -1024,12 +1030,23 @@
       List<ValueType> types,
       List<Integer> registers)
       throws ApiLevelException {
+    addInvoke(type, item, callSiteProto, types, registers, false);
+  }
+
+  public void addInvoke(
+      Invoke.Type type,
+      DexItem item,
+      DexProto callSiteProto,
+      List<ValueType> types,
+      List<Integer> registers,
+      boolean itf)
+      throws ApiLevelException {
     assert types.size() == registers.size();
     List<Value> arguments = new ArrayList<>(types.size());
     for (int i = 0; i < types.size(); i++) {
       arguments.add(readRegister(registers.get(i), types.get(i)));
     }
-    addInvoke(type, item, callSiteProto, arguments);
+    addInvoke(type, item, callSiteProto, arguments, itf);
   }
 
   public void addInvokeCustomRegisters(
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
index b584448..a20a0a1 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
@@ -2606,7 +2606,7 @@
             }
             callSiteProto = application.getProto(insn.desc);
           }
-          builder.addInvoke(invokeType, targetMethod, callSiteProto, types, registers);
+          builder.addInvoke(invokeType, targetMethod, callSiteProto, types, registers, insn.itf);
         });
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 8c17d91..15a90e9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -62,8 +62,10 @@
         newFlags.unsetBridge();
         newFlags.setStatic();
         DexCode dexCode = code.asDexCode();
-        // TODO(ager): Should we give the new first parameter an actual name? Maybe 'this'?
-        dexCode.setDebugInfo(dexCode.debugInfoWithAdditionalFirstParameter(null));
+        // We cannot name the parameter "this" because the debugger may omit it due to the method
+        // actually being static. Instead we prepend it with a special character.
+        dexCode.setDebugInfo(dexCode.debugInfoWithAdditionalFirstParameter(
+            rewriter.factory.createString("-this")));
         assert (dexCode.getDebugInfo() == null)
             || (companionMethod.getArity() == dexCode.getDebugInfo().parameters.length);
 
@@ -172,6 +174,7 @@
             DexEncodedField.EMPTY_ARRAY,
             companionMethods.toArray(new DexEncodedMethod[companionMethods.size()]),
             DexEncodedMethod.EMPTY_ARRAY,
+            rewriter.factory.getSkipNameValidationForTesting(),
             Collections.singletonList(iface));
     companionClasses.put(iface, companionClass);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 05a4d56..82958da 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -139,6 +139,7 @@
         synthesizeInstanceFields(),
         synthesizeDirectMethods(),
         synthesizeVirtualMethods(),
+        rewriter.factory.getSkipNameValidationForTesting(),
         synthesizedFrom);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 30e9bae4..03e314c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -1838,8 +1838,17 @@
 
   private static class CSEExpressionEquivalence extends Equivalence<Instruction> {
 
+    private final IRCode code;
+
+    private CSEExpressionEquivalence(IRCode code) {
+      this.code = code;
+    }
+
     @Override
     protected boolean doEquivalent(Instruction a, Instruction b) {
+      if (a.isCmp() && code.options.canHaveCmpLongBug()) {
+        return false;
+      }
       // Note that we don't consider positions because CSE can at most remove an instruction.
       if (a.getClass() != b.getClass() || !a.identicalNonValueNonPositionParts(b)) {
         return false;
@@ -1923,7 +1932,7 @@
   public void commonSubexpressionElimination(IRCode code) {
     final ListMultimap<Wrapper<Instruction>, Value> instructionToValue = ArrayListMultimap.create();
     final DominatorTree dominatorTree = new DominatorTree(code);
-    final CSEExpressionEquivalence equivalence = new CSEExpressionEquivalence();
+    final CSEExpressionEquivalence equivalence = new CSEExpressionEquivalence(code);
 
     for (int i = 0; i < dominatorTree.getSortedBlocks().length; i++) {
       BasicBlock block = dominatorTree.getSortedBlocks()[i];
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 536e4b7..6c570f4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -1083,8 +1083,8 @@
             DexEncodedField.EMPTY_ARRAY, // Static fields.
             DexEncodedField.EMPTY_ARRAY, // Instance fields.
             direct,
-            DexEncodedMethod.EMPTY_ARRAY // Virtual methods.
-            );
+            DexEncodedMethod.EMPTY_ARRAY, // Virtual methods.
+            options.itemFactory.getSkipNameValidationForTesting());
 
     return clazz;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
index 5127632..10dc013 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
@@ -48,7 +48,8 @@
         buildStaticFields(),
         buildInstanceFields(),
         buildDirectMethods(),
-        buildVirtualMethods());
+        buildVirtualMethods(),
+        factory.getSkipNameValidationForTesting());
   }
 
   protected abstract DexType getSuperClassType();
diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
index c208cea..258aa43 100644
--- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
+++ b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
@@ -1907,11 +1907,6 @@
           // 1) t03
           // java.lang.AssertionError: expected null, but was:<[I@e2603b4>
 
-          .put("lang.ref.SoftReference.enqueue.SoftReference_enqueue_A01",
-                  match(runtimesUpTo(Version.V4_4_4)))
-          // 1) t03(com.google.jctf.test.lib.java.lang.ref.SoftReference.enqueue.SoftReference_enqueue_A01)
-          // java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
-
           .put("lang.ref.ReferenceQueue.poll.ReferenceQueue_poll_A01",
               match(runtimes(Version.DEFAULT, Version.V7_0_0, Version.V6_0_1, Version.V5_1_1)))
           // 1) t03
@@ -4963,12 +4958,24 @@
 
           .put("lang.ref.PhantomReference.isEnqueued.PhantomReference_isEnqueued_A01",
               match(runtimesUpTo(Version.V4_4_4)))
+
           .put("lang.ref.WeakReference.isEnqueued.WeakReference_isEnqueued_A01",
               match(runtimesUpTo(Version.V4_4_4)))
+
+          .put("lang.ref.WeakReference.enqueue.WeakReference_enqueue_A01",
+              match(runtimesUpTo(Version.V4_4_4)))
+          // 1) t03
+          // java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
+
           .put("lang.ref.SoftReference.isEnqueued.SoftReference_isEnqueued_A01",
               match(runtimesUpTo(Version.V4_4_4)))
           // Passes or fails randomly. Check that something is enqueued after 2 seconds.
 
+          .put("lang.ref.SoftReference.enqueue.SoftReference_enqueue_A01",
+              match(runtimesUpTo(Version.V4_4_4)))
+          // 1) t03(com.google.jctf.test.lib.java.lang.ref.SoftReference.enqueue.SoftReference_enqueue_A01)
+          // java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
+
           .put("lang.ref.ReferenceQueue.poll.ReferenceQueue_poll_A01",
               match(runtimesUpTo(Version.V4_4_4)))
           // Passes or fails randomly.
diff --git a/src/test/java/com/android/tools/r8/R8CFRunExamplesJava9Test.java b/src/test/java/com/android/tools/r8/R8CFRunExamplesJava9Test.java
index f4d3da5..b3950b4 100644
--- a/src/test/java/com/android/tools/r8/R8CFRunExamplesJava9Test.java
+++ b/src/test/java/com/android/tools/r8/R8CFRunExamplesJava9Test.java
@@ -107,8 +107,6 @@
 
   private static List<String> expectedFailures =
       ImmutableList.of(
-          "native-private-interface-methods",
-          "desugared-private-interface-methods"
       );
 
   private boolean expectedToFailCf(String testName) {
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 024be59..d7d8b99 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -54,7 +54,7 @@
 public class TestBase {
 
   // Actually running Proguard should only be during development.
-  private boolean runProguard = System.getProperty("run_proguard") != null;
+  private static final boolean RUN_PROGUARD = System.getProperty("run_proguard") != null;
 
   @Rule
   public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
@@ -63,7 +63,7 @@
    * Check if tests should also run Proguard when applicable.
    */
   protected boolean isRunProguard() {
-    return runProguard;
+    return RUN_PROGUARD;
   }
 
   /**
diff --git a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
index c5c21a7..26d3d5c 100644
--- a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
@@ -58,6 +58,8 @@
     // TODO(shertz) we should see the local variable this even when desugaring.
     if (supportsDefaultMethod(config)) {
       commands.add(checkLocal("this"));
+    } else {
+      commands.add(checkLocal("-this"));
     }
     commands.add(checkLocal(parameterName));
     commands.add(stepOver(INTELLIJ_FILTER));
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java
index 40d8ad0..e07f319 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java
@@ -4,11 +4,14 @@
 
 package com.android.tools.r8.desugaring.interfacemethods;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import com.android.tools.r8.AsmTestBase;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.VmTestRunner;
-import com.android.tools.r8.desugaring.interfacemethods.test0.InterfaceWithDefaults;
-import com.android.tools.r8.desugaring.interfacemethods.test0.TestMain;
+import com.android.tools.r8.VmTestRunner.IgnoreForRangeOfVmVersions;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -25,13 +28,35 @@
 
   @Test
   public void testInvokeSpecialToDefaultMethod() throws Exception {
-    ensureSameOutput(TestMain.class.getCanonicalName(),
+    ensureSameOutput(
+        com.android.tools.r8.desugaring.interfacemethods.test0.TestMain.class.getCanonicalName(),
         ToolHelper.getMinApiLevelForDexVm(),
-        ToolHelper.getClassAsBytes(TestMain.class),
-        introduceInvokeSpecial(ToolHelper.getClassAsBytes(InterfaceWithDefaults.class)));
+        ToolHelper.getClassAsBytes(
+            com.android.tools.r8.desugaring.interfacemethods.test0.TestMain.class),
+        introduceInvokeSpecial(ToolHelper.getClassAsBytes(
+            com.android.tools.r8.desugaring.interfacemethods.test0.InterfaceWithDefaults.class)));
+  }
+
+  // NOTE: this particular test is working on pre-N devices since
+  //       it's fixed by interface default method desugaring.
+  @IgnoreForRangeOfVmVersions(from = Version.V7_0_0, to = Version.DEFAULT)
+  @Test
+  public void testInvokeSpecialToDefaultMethodFromStatic() throws Exception {
+    ensureSameOutput(
+        com.android.tools.r8.desugaring.interfacemethods.test1.TestMain.class.getCanonicalName(),
+        ToolHelper.getMinApiLevelForDexVm(),
+        ToolHelper.getClassAsBytes(
+            com.android.tools.r8.desugaring.interfacemethods.test1.TestMain.class),
+        introduceInvokeSpecial(ToolHelper.getClassAsBytes(
+            com.android.tools.r8.desugaring.interfacemethods.test1.InterfaceWithDefaults.class)));
+  }
+
+  private class MutableBoolean {
+    boolean value;
   }
 
   private byte[] introduceInvokeSpecial(byte[] classBytes) throws IOException {
+    MutableBoolean patched = new MutableBoolean();
     try (InputStream input = new ByteArrayInputStream(classBytes)) {
       ClassReader cr = new ClassReader(input);
       ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
@@ -46,9 +71,11 @@
                 public void visitMethodInsn(
                     int opcode, String owner, String name, String desc, boolean itf) {
                   if (opcode == Opcodes.INVOKEINTERFACE &&
-                      owner.endsWith("test0/InterfaceWithDefaults") &&
+                      owner.endsWith("InterfaceWithDefaults") &&
                       name.equals("foo")) {
+                    assertFalse(patched.value);
                     super.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, itf);
+                    patched.value = true;
 
                   } else {
                     super.visitMethodInsn(opcode, owner, name, desc, itf);
@@ -57,6 +84,7 @@
               };
             }
           }, 0);
+      assertTrue(patched.value);
       return cw.toByteArray();
     }
   }
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test0/InterfaceWithDefaults.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test0/InterfaceWithDefaults.java
index fc5ab9e..dc671dc 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test0/InterfaceWithDefaults.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test0/InterfaceWithDefaults.java
@@ -1,3 +1,7 @@
+// Copyright (c) 2018, 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.desugaring.interfacemethods.test0;
 
 public interface InterfaceWithDefaults {
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test0/TestMain.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test0/TestMain.java
index b57cbf3..79ac7b0 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test0/TestMain.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test0/TestMain.java
@@ -1,3 +1,7 @@
+// Copyright (c) 2018, 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.desugaring.interfacemethods.test0;
 
 public class TestMain implements InterfaceWithDefaults {
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test1/InterfaceWithDefaults.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test1/InterfaceWithDefaults.java
new file mode 100644
index 0000000..6f79c96
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test1/InterfaceWithDefaults.java
@@ -0,0 +1,18 @@
+// Copyright (c) 2018, 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.desugaring.interfacemethods.test1;
+
+public interface InterfaceWithDefaults {
+  default void foo() {
+    System.out.println("InterfaceWithDefaults::foo()");
+  }
+
+  static void bar(InterfaceWithDefaults iface) {
+    System.out.println("InterfaceWithDefaults::bar()");
+    iface.foo();
+  }
+
+  void test();
+}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test1/TestMain.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test1/TestMain.java
new file mode 100644
index 0000000..e38a17d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/test1/TestMain.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2018, 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.desugaring.interfacemethods.test1;
+
+public class TestMain implements InterfaceWithDefaults {
+  @Override
+  public void test() {
+    System.out.println("TestMain::test()");
+    this.foo();
+    InterfaceWithDefaults.bar(this);
+  }
+
+  @Override
+  public void foo() {
+    System.out.println("TestMain::foo()");
+  }
+
+  public static void main(String[] args) {
+    new TestMain().test();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
index b99bf6d..9edc735 100644
--- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -103,6 +103,7 @@
         DexEncodedField.EMPTY_ARRAY,
         DexEncodedMethod.EMPTY_ARRAY,
         new DexEncodedMethod[] {makeMethod(type, stringCount, startOffset)},
+        false,
         synthesizedFrom);
   }
 
diff --git a/src/test/java/com/android/tools/r8/jasmin/InvalidClassNames.java b/src/test/java/com/android/tools/r8/jasmin/InvalidClassNames.java
index 6e9efa6..bd462b7 100644
--- a/src/test/java/com/android/tools/r8/jasmin/InvalidClassNames.java
+++ b/src/test/java/com/android/tools/r8/jasmin/InvalidClassNames.java
@@ -3,80 +3,88 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.jasmin;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
 
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.errors.CompilationError;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public class InvalidClassNames extends JasminTestBase {
+public class InvalidClassNames extends NameTestBase {
 
-  public boolean runsOnJVM;
-  public String name;
+  private static final String RESULT = "MAIN";
+  private static final String MAIN_CLASS = "Main";
 
-  public InvalidClassNames(String name, boolean runsOnJVM) {
-    this.name = name;
-    this.runsOnJVM = runsOnJVM;
-  }
-
-  private void runTest(JasminBuilder builder, String main, String expected) throws Exception {
-    if (runsOnJVM) {
-      String javaResult = runOnJava(builder, main);
-      assertEquals(expected, javaResult);
-    }
-    String artResult = null;
-    try {
-      artResult = runOnArtD8(builder, main);
-      fail();
-    } catch (CompilationError t) {
-      // Intentionally left empty.
-    } catch (Throwable t) {
-      t.printStackTrace(System.out);
-      fail("Invalid dex class names should be compilation errors.");
-    }
-    assertNull("Invalid dex class names should be rejected.", artResult);
-  }
-
-  @Parameters
+  @Parameters(name = "\"{0}\", jvm: {1}, art: {2}")
   public static Collection<Object[]> data() {
-    return Arrays.asList(new Object[][]{
-        {"\u00a0", !ToolHelper.isJava9Runtime()},
-        {"\u2000", !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime()},
-        {"\u200f", !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime()},
-        {"\u2028", !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime()},
-        {"\u202f", !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime()},
-        {"\ud800", false},
-        {"\udfff", false},
-        {"\ufff0", !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime()},
-        {"\uffff", !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime()},
-        {"a/b/c/a/D/", true},
-        {"a<b", !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime()},
-        {"a>b", !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime()},
-        {"<a>b", !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime()},
-        {"<a>", !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime()}
-    });
+    Collection<Object[]> data = new ArrayList<>();
+    data.addAll(NameTestBase.getCommonNameTestData(true));
+    data.addAll(
+        Arrays.asList(
+            new Object[][] {
+              {new TestString("a/b/c/a/D/"), true, false},
+              {
+                new TestString("a<b"),
+                !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime(),
+                false
+              },
+              {
+                new TestString("a>b"),
+                !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime(),
+                false
+              },
+              {
+                new TestString("<a>b"),
+                !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime(),
+                false
+              },
+              {
+                new TestString("<a>"),
+                !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime(),
+                false
+              }
+            }));
+    return data;
+  }
+
+  private String name;
+  private boolean validForJVM;
+  private boolean validForArt;
+
+  public InvalidClassNames(TestString name, boolean validForJVM, boolean validForArt) {
+    this.name = name.getValue();
+    this.validForJVM = validForJVM;
+    this.validForArt = validForArt;
+  }
+
+  private JasminBuilder createJasminBuilder() {
+    JasminBuilder builder = new JasminBuilder();
+    JasminBuilder.ClassBuilder clazz = builder.addClass(name);
+    clazz.addStaticMethod(
+        "run",
+        Collections.emptyList(),
+        "V",
+        ".limit stack 2",
+        ".limit locals 0",
+        "  getstatic java/lang/System/out Ljava/io/PrintStream;",
+        "  ldc \"" + RESULT + "\"",
+        "  invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V",
+        "  return");
+
+    clazz = builder.addClass(MAIN_CLASS);
+    clazz.addMainMethod(
+        ".limit stack 0", ".limit locals 1", "invokestatic " + name + "/run()V", "  return");
+
+    return builder;
   }
 
   @Test
   public void invalidClassName() throws Exception {
-    JasminBuilder builder = new JasminBuilder();
-    JasminBuilder.ClassBuilder clazz = builder.addClass(name);
-    clazz.addMainMethod(
-        ".limit stack 2",
-        ".limit locals 1",
-        "  getstatic java/lang/System/out Ljava/io/PrintStream;",
-        "  ldc \"MAIN\"",
-        "  invokevirtual java/io/PrintStream.print(Ljava/lang/String;)V",
-        "  return");
-
-    runTest(builder, clazz.name, "MAIN");
+    runNameTesting(validForJVM, createJasminBuilder(), MAIN_CLASS, RESULT, validForArt, name);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/jasmin/InvalidFieldNames.java b/src/test/java/com/android/tools/r8/jasmin/InvalidFieldNames.java
index bad64ac..8f680ee 100644
--- a/src/test/java/com/android/tools/r8/jasmin/InvalidFieldNames.java
+++ b/src/test/java/com/android/tools/r8/jasmin/InvalidFieldNames.java
@@ -3,117 +3,48 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.jasmin;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.smali.SmaliBuilder;
-import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.FileUtils;
-import com.android.tools.r8.utils.StringUtils;
-import com.google.common.base.Strings;
-import com.google.common.primitives.Bytes;
-import java.nio.file.Paths;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.zip.Adler32;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public class InvalidFieldNames extends JasminTestBase {
+public class InvalidFieldNames extends NameTestBase {
 
   private static final String CLASS_NAME = "Test";
   private static String FIELD_VALUE = "42";
 
   @Parameters(name = "\"{0}\", jvm: {1}, art: {2}")
   public static Collection<Object[]> data() {
-    return Arrays.asList(
-        new Object[][] {
-          {new TestStringParameter("azAZ09$_"), true, true},
-          {new TestStringParameter("_"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("a-b"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("\u00a0"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("\u00a1"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("\u1fff"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("\u2000"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("\u200f"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("\u2010"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("\u2027"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("\u2028"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("\u202f"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("\u2030"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("\ud7ff"), !ToolHelper.isJava9Runtime(), true},
-
-          // Standalone high and low surrogates.
-          {new TestStringParameter("\ud800"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("\udbff"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("\udc00"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("\udfff"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("\ue000"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("\uffef"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("\ufff0"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("\uffff"), !ToolHelper.isJava9Runtime(), false},
-
-          // Single and double code points above 0x10000.
-          {new TestStringParameter("\ud800\udc00"), true, true},
-          {new TestStringParameter("\ud800\udcfa"), true, true},
-          {new TestStringParameter("\ud800\udcfb"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("\udbff\udfff"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("\ud800\udc00\ud800\udcfa"), true, true},
-          {new TestStringParameter("\ud800\udc00\udbff\udfff"), !ToolHelper.isJava9Runtime(), true},
-          {new TestStringParameter("a/b"), false, false},
-          {new TestStringParameter("<a"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("a>"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("a<b>"), !ToolHelper.isJava9Runtime(), false},
-          {new TestStringParameter("<a>b"), !ToolHelper.isJava9Runtime(), false}
-        });
-  }
-
-  // TestStringParameter is a String with modified toString() which prints \\uXXXX for
-  // characters outside 0x20..0x7e.
-  static class TestStringParameter {
-    private final String value;
-
-    TestStringParameter(String value) {
-      this.value = value;
-    }
-
-    String getValue() {
-      return value;
-    }
-
-    @Override
-    public String toString() {
-      return StringUtils.toASCIIString(value);
-    }
+    Collection<Object[]> data = new ArrayList<>();
+    data.addAll(NameTestBase.getCommonNameTestData(false));
+    data.addAll(
+        Arrays.asList(
+            new Object[][] {
+              {new TestString("a/b"), false, false},
+              {new TestString("<a"), !ToolHelper.isJava9Runtime(), false},
+              {new TestString("a>"), !ToolHelper.isJava9Runtime(), false},
+              {new TestString("a<b>"), !ToolHelper.isJava9Runtime(), false},
+              {new TestString("<a>b"), !ToolHelper.isJava9Runtime(), false},
+              {new TestString("<a>"), false, true}
+            }));
+    return data;
   }
 
   private String name;
   private boolean validForJVM;
   private boolean validForArt;
 
-  public InvalidFieldNames(TestStringParameter name, boolean validForJVM, boolean validForArt) {
+  public InvalidFieldNames(TestString name, boolean validForJVM, boolean validForArt) {
     this.name = name.getValue();
     this.validForJVM = validForJVM;
     this.validForArt = validForArt;
   }
 
-  private byte[] trimLastZeroByte(byte[] bytes) {
-    assert bytes.length > 0 && bytes[bytes.length - 1] == 0;
-    byte[] result = new byte[bytes.length - 1];
-    System.arraycopy(bytes, 0, result, 0, result.length);
-    return result;
-  }
-
   private JasminBuilder createJasminBuilder() {
     JasminBuilder builder = new JasminBuilder();
     JasminBuilder.ClassBuilder clazz = builder.addClass(CLASS_NAME);
@@ -130,84 +61,8 @@
     return builder;
   }
 
-  private AndroidApp createAppWithSmali() throws Exception {
-
-    SmaliBuilder smaliBuilder = new SmaliBuilder(CLASS_NAME);
-    String originalSourceFile = CLASS_NAME + FileUtils.JAVA_EXTENSION;
-    smaliBuilder.setSourceFile(originalSourceFile);
-
-    // We're using a valid placeholder string which will be replaced by the actual name.
-    byte[] nameMutf8 = trimLastZeroByte(DexString.encodeToMutf8(name));
-
-    String placeholderString = Strings.repeat("A", nameMutf8.length);
-
-    smaliBuilder.addStaticField(placeholderString, "I", FIELD_VALUE);
-    MethodSignature mainSignature =
-        smaliBuilder.addMainMethod(
-            1,
-            "sget-object p0, Ljava/lang/System;->out:Ljava/io/PrintStream;",
-            "sget v0, LTest;->" + placeholderString + ":I",
-            "invoke-virtual {p0, v0}, Ljava/io/PrintStream;->print(I)V",
-            "return-void");
-    byte[] dexCode = smaliBuilder.compile();
-
-    // Replace placeholder by mutf8-encoded name
-    byte[] placeholderBytes = trimLastZeroByte(DexString.encodeToMutf8(placeholderString));
-    assert placeholderBytes.length == nameMutf8.length;
-    int index = Bytes.indexOf(dexCode, placeholderBytes);
-    if (index >= 0) {
-      System.arraycopy(nameMutf8, 0, dexCode, index, nameMutf8.length);
-    }
-    assert Bytes.indexOf(dexCode, placeholderBytes) < 0;
-
-    // Update checksum
-    Adler32 adler = new Adler32();
-    adler.update(dexCode, Constants.SIGNATURE_OFFSET, dexCode.length - Constants.SIGNATURE_OFFSET);
-    int checksum = (int) adler.getValue();
-    for (int i = 0; i < 4; ++i) {
-      dexCode[Constants.CHECKSUM_OFFSET + i] = (byte) (checksum >> (8 * i) & 0xff);
-    }
-
-    return AndroidApp.builder()
-        .addDexProgramData(dexCode, new PathOrigin(Paths.get(originalSourceFile)))
-        .build();
-  }
-
   @Test
   public void invalidFieldNames() throws Exception {
-    JasminBuilder jasminBuilder = createJasminBuilder();
-
-    if (validForJVM) {
-      String javaResult = runOnJava(jasminBuilder, CLASS_NAME);
-      assertEquals(FIELD_VALUE, javaResult);
-    } else {
-      try {
-        runOnJava(jasminBuilder, CLASS_NAME);
-        fail("Should have failed on JVM.");
-      } catch (AssertionError e) {
-        // Silent on expected failure.
-      }
-    }
-
-    if (validForArt) {
-      String artResult = runOnArtD8(jasminBuilder, CLASS_NAME);
-      assertEquals(FIELD_VALUE, artResult);
-    } else {
-      // Make sure the compiler fails.
-      try {
-        runOnArtD8(jasminBuilder, CLASS_NAME);
-        fail("D8 should have rejected this case.");
-      } catch (CompilationError t) {
-        assertTrue(t.getMessage().contains(name));
-      }
-
-      // Make sure ART also fail, if D8 rejects it.
-      try {
-        runOnArt(createAppWithSmali(), CLASS_NAME);
-        fail("Art should have failed.");
-      } catch (AssertionError e) {
-        // Silent on expected failure.
-      }
-    }
+    runNameTesting(validForJVM, createJasminBuilder(), CLASS_NAME, FIELD_VALUE, validForArt, name);
   }
 }
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 5f83016..fe95845 100644
--- a/src/test/java/com/android/tools/r8/jasmin/InvalidMethodNames.java
+++ b/src/test/java/com/android/tools/r8/jasmin/InvalidMethodNames.java
@@ -3,15 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.jasmin;
 
-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.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import org.junit.Test;
@@ -20,73 +16,79 @@
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public class InvalidMethodNames extends JasminTestBase {
+public class InvalidMethodNames extends NameTestBase {
 
-  public boolean runsOnJVM;
-  public String name;
+  private final String CLASS_NAME = "Test";
+  private final String RESULT = "CALLED";
 
-  public InvalidMethodNames(String name, boolean runsOnJVM) {
-    this.name = name;
-    this.runsOnJVM = runsOnJVM;
-  }
+  private String name;
+  private boolean validForJVM;
+  private boolean validForArt;
 
-  private void runTest(JasminBuilder builder, String main, String expected) throws Exception {
-    if (runsOnJVM) {
-      String javaResult = runOnJava(builder, main);
-      assertEquals(expected, javaResult);
-    }
-    String artResult = null;
-    try {
-      artResult = runOnArtD8(builder, main);
-      fail();
-    } catch (CompilationError t) {
-      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.");
-    }
-    assertNull("Invalid dex method names should be rejected.", artResult);
-  }
-
-  @Parameters
+  @Parameters(name = "\"{0}\", jvm: {1}, art: {2}")
   public static Collection<Object[]> data() {
-    return Arrays.asList(new Object[][]{
-        {"\u00a0", !ToolHelper.isJava9Runtime()},
-        {"\u2000", !ToolHelper.isJava9Runtime()},
-        {"\u200f", !ToolHelper.isJava9Runtime()},
-        {"\u2028", !ToolHelper.isJava9Runtime()},
-        {"\u202f", !ToolHelper.isJava9Runtime()},
-        {"\ud800", !ToolHelper.isJava9Runtime()},
-        {"\udfff", !ToolHelper.isJava9Runtime()},
-        {"\ufff0", !ToolHelper.isJava9Runtime()},
-        {"\uffff", !ToolHelper.isJava9Runtime()},
-        {"a/b", false},
-        {"<a", false},
-        {"a>", !ToolHelper.isJava9Runtime()},
-        {"<a>", false}
-    });
+    Collection<Object[]> data = new ArrayList<>();
+    data.addAll(NameTestBase.getCommonNameTestData(false));
+    data.addAll(
+        Arrays.asList(
+            new Object[][] {
+              {new TestString("a/b"), false, false},
+              {new TestString("<a"), false, false},
+              {new TestString("a>"), !ToolHelper.isJava9Runtime(), false},
+              {new TestString("<a>"), false, false}
+            }));
+    return data;
   }
 
-  @Test
-  public void invalidMethodName() throws Exception {
-    JasminBuilder builder = new JasminBuilder();
-    JasminBuilder.ClassBuilder clazz = builder.addClass("Test");
+  public InvalidMethodNames(TestString name, boolean validForJVM, boolean validForArt) {
+    this.name = name.getValue();
+    this.validForJVM = validForJVM;
+    this.validForArt = validForArt;
+  }
 
-    clazz.addStaticMethod(name, ImmutableList.of(), "V",
+  JasminBuilder createJasminBuilder() {
+    JasminBuilder builder = new JasminBuilder();
+    JasminBuilder.ClassBuilder clazz = builder.addClass(CLASS_NAME);
+
+    clazz.addStaticMethod(
+        name,
+        ImmutableList.of(),
+        "V",
         ".limit stack 2",
         ".limit locals 0",
         "  getstatic java/lang/System/out Ljava/io/PrintStream;",
-        "  ldc \"CALLED\"",
+        "  ldc \"" + RESULT + "\"",
         "  invokevirtual java/io/PrintStream.print(Ljava/lang/String;)V",
         "  return");
 
     clazz.addMainMethod(
         ".limit stack 0",
         ".limit locals 1",
-        "  invokestatic Test/" + name + "()V",
+        "  invokestatic " + CLASS_NAME + "/" + name + "()V",
         "  return");
+    return builder;
+  }
 
-    runTest(builder, clazz.name, "CALLED");
+  static class StringReplaceData {
+    final byte[] inputMutf8;
+    final String placeholderString;
+    final byte[] placeholderBytes;
+
+    StringReplaceData(byte[] inputMutf8, String placeholderString, byte[] placeholderBytes) {
+      this.inputMutf8 = inputMutf8;
+      this.placeholderString = placeholderString;
+      this.placeholderBytes = placeholderBytes;
+    }
+  }
+
+  @Test
+  public void invalidMethodName() throws Exception {
+    runNameTesting(
+        validForJVM,
+        createJasminBuilder(),
+        CLASS_NAME,
+        RESULT,
+        validForArt,
+        StringUtils.toASCIIString(name));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
index ff0a177..c75ea7d 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
@@ -75,7 +75,13 @@
   }
 
   protected String runOnArtD8(JasminBuilder builder, String main) throws Exception {
-    return runOnArt(compileWithD8(builder), main);
+    return runOnArtD8(builder, main, null);
+  }
+
+  protected String runOnArtD8(
+      JasminBuilder builder, String main, Consumer<InternalOptions> optionsConsumer)
+      throws Exception {
+    return runOnArt(compileWithD8(builder, optionsConsumer), main);
   }
 
   protected ProcessResult runOnArtD8Raw(JasminBuilder builder, String main) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/jasmin/NameTestBase.java b/src/test/java/com/android/tools/r8/jasmin/NameTestBase.java
new file mode 100644
index 0000000..1104e54
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/jasmin/NameTestBase.java
@@ -0,0 +1,133 @@
+// Copyright (c) 2018, 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.jasmin;
+
+import static org.junit.Assert.assertEquals;
+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.utils.StringUtils;
+import java.nio.file.InvalidPathException;
+import java.util.Arrays;
+import java.util.Collection;
+
+class NameTestBase extends JasminTestBase {
+  // TestString is a String with modified toString() which prints \\uXXXX for
+  // characters outside 0x20..0x7e.
+  static class TestString {
+    private final String value;
+
+    TestString(String value) {
+      this.value = value;
+    }
+
+    String getValue() {
+      return value;
+    }
+
+    @Override
+    public String toString() {
+      return StringUtils.toASCIIString(value);
+    }
+  }
+
+  // The return value is a collection of rows with the following fields:
+  // - Name (String) to test (can be class name, field name, method name).
+  // - boolean, whether it runs on the JVM.
+  // - boolean, whether it runs on the ART.
+  static Collection<Object[]> getCommonNameTestData(boolean classNames) {
+
+    boolean windowsSensitive = classNames && ToolHelper.isWindows();
+
+    return Arrays.asList(
+        new Object[][] {
+          {new TestString("azAZ09$_"), true, true},
+          {new TestString("_"), !ToolHelper.isJava9Runtime(), true},
+          {new TestString("a-b"), !ToolHelper.isJava9Runtime(), true},
+          {new TestString("\u00a0"), !ToolHelper.isJava9Runtime(), false},
+          {new TestString("\u00a1"), !ToolHelper.isJava9Runtime(), true},
+          {new TestString("\u1fff"), !ToolHelper.isJava9Runtime(), true},
+          {new TestString("\u2000"), !windowsSensitive && !ToolHelper.isJava9Runtime(), false},
+          {new TestString("\u200f"), !windowsSensitive && !ToolHelper.isJava9Runtime(), false},
+          {new TestString("\u2010"), !windowsSensitive && !ToolHelper.isJava9Runtime(), true},
+          {new TestString("\u2027"), !windowsSensitive && !ToolHelper.isJava9Runtime(), true},
+          {new TestString("\u2028"), !windowsSensitive && !ToolHelper.isJava9Runtime(), false},
+          {new TestString("\u202f"), !windowsSensitive && !ToolHelper.isJava9Runtime(), false},
+          {new TestString("\u2030"), !windowsSensitive && !ToolHelper.isJava9Runtime(), true},
+          {new TestString("\ud7ff"), !windowsSensitive && !ToolHelper.isJava9Runtime(), true},
+          {new TestString("\ue000"), !windowsSensitive && !ToolHelper.isJava9Runtime(), true},
+          {new TestString("\uffef"), !windowsSensitive && !ToolHelper.isJava9Runtime(), true},
+          {new TestString("\ufff0"), !windowsSensitive && !ToolHelper.isJava9Runtime(), false},
+          {new TestString("\uffff"), !windowsSensitive && !ToolHelper.isJava9Runtime(), false},
+
+          // Standalone high and low surrogates.
+          {new TestString("\ud800"), !classNames && !ToolHelper.isJava9Runtime(), false},
+          {new TestString("\udbff"), !classNames && !ToolHelper.isJava9Runtime(), false},
+          {new TestString("\udc00"), !classNames && !ToolHelper.isJava9Runtime(), false},
+          {new TestString("\udfff"), !classNames && !ToolHelper.isJava9Runtime(), false},
+
+          // Single and double code points above 0x10000.
+          {new TestString("\ud800\udc00"), true, true},
+          {new TestString("\ud800\udcfa"), true, true},
+          {new TestString("\ud800\udcfb"), !windowsSensitive && !ToolHelper.isJava9Runtime(), true},
+          {new TestString("\udbff\udfff"), !windowsSensitive && !ToolHelper.isJava9Runtime(), true},
+          {new TestString("\ud800\udc00\ud800\udcfa"), true, true},
+          {
+            new TestString("\ud800\udc00\udbff\udfff"),
+            !windowsSensitive && !ToolHelper.isJava9Runtime(),
+            true
+          }
+        });
+  }
+
+  void runNameTesting(
+      boolean validForJVM,
+      JasminBuilder jasminBuilder,
+      String mainClassName,
+      String expectedResult,
+      boolean validForArt,
+      String expectedNameInFailingD8Message)
+      throws Exception {
+
+    if (validForJVM) {
+      String javaResult = runOnJava(jasminBuilder, mainClassName);
+      assertEquals(expectedResult, javaResult);
+    } else {
+      try {
+        runOnJava(jasminBuilder, mainClassName);
+        fail("Should have failed on JVM.");
+      } catch (AssertionError | InvalidPathException e) {
+        // Silent on expected failure.
+      }
+    }
+
+    if (validForArt) {
+      String artResult = runOnArtD8(jasminBuilder, mainClassName);
+      assertEquals(expectedResult, artResult);
+    } else {
+      // Make sure the compiler fails.
+      try {
+        runOnArtD8(jasminBuilder, mainClassName);
+        fail("D8 should have rejected this case.");
+      } catch (CompilationError t) {
+        assertTrue(t.getMessage().contains(expectedNameInFailingD8Message));
+      }
+
+      // Make sure ART also fail, if D8 rejects it.
+      try {
+        runOnArtD8(
+            jasminBuilder,
+            mainClassName,
+            options -> {
+              options.itemFactory.setSkipNameValidationForTesting(true);
+            });
+        fail("Art should have failed.");
+      } catch (AssertionError e) {
+        // Silent on expected failure.
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java
index 65dc98f..315e980 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java
@@ -251,10 +251,10 @@
 
   @Test
   public void testTrivialKs() throws Exception {
-    final String mainClassName = "lambdas.kstyle.trivial.MainKt";
+    final String mainClassName = "lambdas_kstyle_trivial.MainKt";
     runTest("lambdas_kstyle_trivial", mainClassName, null, (app) -> {
       Verifier verifier = new Verifier(app);
-      String pkg = "lambdas/kstyle/trivial";
+      String pkg = "lambdas_kstyle_trivial";
 
       verifier.assertLambdaGroups(
           allowAccessModification ?
@@ -292,10 +292,10 @@
 
   @Test
   public void testCapturesKs() throws Exception {
-    final String mainClassName = "lambdas.kstyle.captures.MainKt";
+    final String mainClassName = "lambdas_kstyle_captures.MainKt";
     runTest("lambdas_kstyle_captures", mainClassName, null, (app) -> {
       Verifier verifier = new Verifier(app);
-      String pkg = "lambdas/kstyle/captures";
+      String pkg = "lambdas_kstyle_captures";
       String grpPkg = allowAccessModification ? "" : pkg;
 
       verifier.assertLambdaGroups(
@@ -317,10 +317,10 @@
 
   @Test
   public void testGenericsNoSignatureKs() throws Exception {
-    final String mainClassName = "lambdas.kstyle.generics.MainKt";
+    final String mainClassName = "lambdas_kstyle_generics.MainKt";
     runTest("lambdas_kstyle_generics", mainClassName, null, (app) -> {
       Verifier verifier = new Verifier(app);
-      String pkg = "lambdas/kstyle/generics";
+      String pkg = "lambdas_kstyle_generics";
       String grpPkg = allowAccessModification ? "" : pkg;
 
       verifier.assertLambdaGroups(
@@ -338,10 +338,10 @@
 
   @Test
   public void testInnerClassesAndEnclosingMethodsKs() throws Exception {
-    final String mainClassName = "lambdas.kstyle.generics.MainKt";
+    final String mainClassName = "lambdas_kstyle_generics.MainKt";
     runTest("lambdas_kstyle_generics", mainClassName, KEEP_INNER_AND_ENCLOSING, (app) -> {
       Verifier verifier = new Verifier(app);
-      String pkg = "lambdas/kstyle/generics";
+      String pkg = "lambdas_kstyle_generics";
       String grpPkg = allowAccessModification ? "" : pkg;
 
       verifier.assertLambdaGroups(
@@ -361,10 +361,10 @@
 
   @Test
   public void testGenericsSignatureInnerEnclosingKs() throws Exception {
-    final String mainClassName = "lambdas.kstyle.generics.MainKt";
+    final String mainClassName = "lambdas_kstyle_generics.MainKt";
     runTest("lambdas_kstyle_generics", mainClassName, KEEP_SIGNATURE_INNER_ENCLOSING, (app) -> {
       Verifier verifier = new Verifier(app);
-      String pkg = "lambdas/kstyle/generics";
+      String pkg = "lambdas_kstyle_generics";
       String grpPkg = allowAccessModification ? "" : pkg;
 
       verifier.assertLambdaGroups(
@@ -386,17 +386,17 @@
 
   @Test
   public void testTrivialJs() throws Exception {
-    final String mainClassName = "lambdas.jstyle.trivial.MainKt";
+    final String mainClassName = "lambdas_jstyle_trivial.MainKt";
     runTest("lambdas_jstyle_trivial", mainClassName, null, (app) -> {
       Verifier verifier = new Verifier(app);
-      String pkg = "lambdas/jstyle/trivial";
+      String pkg = "lambdas_jstyle_trivial";
       String grp = allowAccessModification ? "" : pkg;
 
-      String supplier = "Lambdas$Supplier";
-      String intSupplier = "Lambdas$IntSupplier";
-      String consumer = "Lambdas$Consumer";
-      String intConsumer = "Lambdas$IntConsumer";
-      String multiFunction = "Lambdas$MultiFunction";
+      String supplier = "lambdas_jstyle_trivial.Lambdas$Supplier";
+      String intSupplier = "lambdas_jstyle_trivial.Lambdas$IntSupplier";
+      String consumer = "lambdas_jstyle_trivial.Lambdas$Consumer";
+      String intConsumer = "lambdas_jstyle_trivial.Lambdas$IntConsumer";
+      String multiFunction = "lambdas_jstyle_trivial.Lambdas$MultiFunction";
 
       verifier.assertLambdaGroups(
           jstyle(grp, 0, intSupplier, 2),
@@ -434,10 +434,10 @@
 
   @Test
   public void testSingleton() throws Exception {
-    final String mainClassName = "lambdas.singleton.MainKt";
+    final String mainClassName = "lambdas_singleton.MainKt";
     runTest("lambdas_singleton", mainClassName, null, (app) -> {
       Verifier verifier = new Verifier(app);
-      String pkg = "lambdas/singleton";
+      String pkg = "lambdas_singleton";
       String grp = allowAccessModification ? "" : pkg;
 
       verifier.assertLambdaGroups(
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 5df6bd5..35df33e 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -639,7 +639,8 @@
               DexEncodedField.EMPTY_ARRAY,
               DexEncodedField.EMPTY_ARRAY,
               directMethods,
-              DexEncodedMethod.EMPTY_ARRAY));
+              DexEncodedMethod.EMPTY_ARRAY,
+              false));
     }
     DirectMappedDexApplication application = builder.build().toDirect();
     ApplicationWriter writer =
diff --git a/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/Lambdas.java b/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/Lambdas.java
index 69e9a78..2352efd 100644
--- a/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/Lambdas.java
+++ b/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/Lambdas.java
@@ -2,6 +2,8 @@
 // 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 lambdas_jstyle_trivial;
+
 public class Lambdas {
   public interface IntConsumer {
     void put(int value);
diff --git a/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/inner.kt b/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/inner/inner.kt
similarity index 85%
rename from src/test/kotlinR8TestResources/lambdas_jstyle_trivial/inner.kt
rename to src/test/kotlinR8TestResources/lambdas_jstyle_trivial/inner/inner.kt
index 5da8884..b0afcc3 100644
--- a/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/inner.kt
+++ b/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/inner/inner.kt
@@ -2,11 +2,11 @@
 // 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 lambdas.jstyle.trivial.inner
+package lambdas_jstyle_trivial.inner
 
-import Lambdas
-import lambdas.jstyle.trivial.next
-import lambdas.jstyle.trivial.nextInt
+import lambdas_jstyle_trivial.Lambdas
+import lambdas_jstyle_trivial.next
+import lambdas_jstyle_trivial.nextInt
 
 fun testInner() {
     testInner1(nextInt(), nextInt(), nextInt(), nextInt())
diff --git a/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/main.kt b/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/main.kt
index 39673af..6cdae60 100644
--- a/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/main.kt
+++ b/src/test/kotlinR8TestResources/lambdas_jstyle_trivial/main.kt
@@ -2,10 +2,10 @@
 // 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 lambdas.jstyle.trivial
+package lambdas_jstyle_trivial
 
-import Lambdas
-import lambdas.jstyle.trivial.inner.testInner
+import lambdas_jstyle_trivial.Lambdas
+import lambdas_jstyle_trivial.inner.testInner
 
 private var COUNT = 0
 
diff --git a/src/test/kotlinR8TestResources/lambdas_kstyle_captures/main.kt b/src/test/kotlinR8TestResources/lambdas_kstyle_captures/main.kt
index 3ee0bf8..62727bd 100644
--- a/src/test/kotlinR8TestResources/lambdas_kstyle_captures/main.kt
+++ b/src/test/kotlinR8TestResources/lambdas_kstyle_captures/main.kt
@@ -2,7 +2,7 @@
 // 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 lambdas.kstyle.captures
+package lambdas_kstyle_captures
 
 fun consume(l: () -> String) = l()
 
diff --git a/src/test/kotlinR8TestResources/lambdas_kstyle_generics/main.kt b/src/test/kotlinR8TestResources/lambdas_kstyle_generics/main.kt
index 7fb22eb..e2d044d 100644
--- a/src/test/kotlinR8TestResources/lambdas_kstyle_generics/main.kt
+++ b/src/test/kotlinR8TestResources/lambdas_kstyle_generics/main.kt
@@ -2,7 +2,7 @@
 // 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 lambdas.kstyle.generics
+package lambdas_kstyle_generics
 
 private var COUNT = 11
 
diff --git a/src/test/kotlinR8TestResources/lambdas_kstyle_trivial/inner.kt b/src/test/kotlinR8TestResources/lambdas_kstyle_trivial/inner/inner.kt
similarity index 79%
rename from src/test/kotlinR8TestResources/lambdas_kstyle_trivial/inner.kt
rename to src/test/kotlinR8TestResources/lambdas_kstyle_trivial/inner/inner.kt
index 00587a9..c22a3b8 100644
--- a/src/test/kotlinR8TestResources/lambdas_kstyle_trivial/inner.kt
+++ b/src/test/kotlinR8TestResources/lambdas_kstyle_trivial/inner/inner.kt
@@ -2,11 +2,11 @@
 // 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 lambdas.kstyle.trivial.inner
+package lambdas_kstyle_trivial.inner
 
-import lambdas.kstyle.trivial.consumeEmpty
-import lambdas.kstyle.trivial.consumeOne
-import lambdas.kstyle.trivial.consumeTwo
+import lambdas_kstyle_trivial.consumeEmpty
+import lambdas_kstyle_trivial.consumeOne
+import lambdas_kstyle_trivial.consumeTwo
 
 fun testInner() {
     testInnerStateless()
diff --git a/src/test/kotlinR8TestResources/lambdas_kstyle_trivial/main.kt b/src/test/kotlinR8TestResources/lambdas_kstyle_trivial/main.kt
index 34ba194..42cce37 100644
--- a/src/test/kotlinR8TestResources/lambdas_kstyle_trivial/main.kt
+++ b/src/test/kotlinR8TestResources/lambdas_kstyle_trivial/main.kt
@@ -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.
 
-package lambdas.kstyle.trivial
+package lambdas_kstyle_trivial
 
-import lambdas.kstyle.trivial.inner.testInner
+import lambdas_kstyle_trivial.inner.testInner
 
 private var COUNT = 11
 
diff --git a/src/test/kotlinR8TestResources/lambdas_singleton/Lambdas.java b/src/test/kotlinR8TestResources/lambdas_singleton/Lambdas.java
deleted file mode 100644
index 4140293..0000000
--- a/src/test/kotlinR8TestResources/lambdas_singleton/Lambdas.java
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2018, 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.
-
-public class Lambdas {
-  public interface Function<R, P1, P2> {
-    R get(P1 a, P2 b);
-  }
-
-  public synchronized static <R, P1, P2> void accept(Function<R, P1, P2> s, P1 a, P2 b) {
-    System.out.println(s.get(a, b));
-  }
-}
diff --git a/src/test/kotlinR8TestResources/lambdas_singleton/main.kt b/src/test/kotlinR8TestResources/lambdas_singleton/main.kt
index 8e34a0c..f06904a 100644
--- a/src/test/kotlinR8TestResources/lambdas_singleton/main.kt
+++ b/src/test/kotlinR8TestResources/lambdas_singleton/main.kt
@@ -2,7 +2,7 @@
 // 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 lambdas.singleton
+package lambdas_singleton
 
 private var COUNT = 0
 
diff --git a/third_party/desugar/desugar_20180308.tar.gz.sha1 b/third_party/desugar/desugar_20180308.tar.gz.sha1
new file mode 100644
index 0000000..bc15c22
--- /dev/null
+++ b/third_party/desugar/desugar_20180308.tar.gz.sha1
@@ -0,0 +1 @@
+e31fb39c34a94592056e878462f086ffb922d1d0
\ No newline at end of file