Desugar MultiANewArray to code that also runs on the JVM

Change-Id: Ibeae5b9662e0ff8ba2867247b4997c84fb6173a4
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index c135288..0e878ae 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -38,6 +38,9 @@
   }
 
   public CfConstClass(DexType type, boolean ignoreCompatRules) {
+    // Primitive types and void should be retrieved using, for example, java.lang.Integer.TYPE.
+    assert !type.isPrimitiveType();
+    assert !type.isVoidType();
     this.type = type;
     this.ignoreCompatRules = ignoreCompatRules;
   }
@@ -106,22 +109,6 @@
       case '[':
       case 'L':
         return namingLens.lookupInternalName(rewrittenType);
-      case 'Z':
-        return "java/lang/Boolean/TYPE";
-      case 'B':
-        return "java/lang/Byte/TYPE";
-      case 'S':
-        return "java/lang/Short/TYPE";
-      case 'C':
-        return "java/lang/Character/TYPE";
-      case 'I':
-        return "java/lang/Integer/TYPE";
-      case 'F':
-        return "java/lang/Float/TYPE";
-      case 'J':
-        return "java/lang/Long/TYPE";
-      case 'D':
-        return "java/lang/Double/TYPE";
       default:
         throw new Unreachable("Unexpected type in const-class: " + rewrittenType);
     }
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index 03dd4d6..c32d6cb 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -68,6 +68,7 @@
 import com.android.tools.r8.position.TextRange;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
@@ -994,7 +995,18 @@
         visitInsn(Opcodes.IASTORE);
         // ..., count1, ..., dim-array
       }
-      visitLdcInsn(Type.getType(desc.substring(dims)));
+      String baseDesc = desc.substring(dims);
+      if (DescriptorUtils.isPrimitiveDescriptor(baseDesc)) {
+        visitFieldInsn(
+            Opcodes.GETSTATIC,
+            DescriptorUtils.primitiveDescriptorToBoxedInternalName(baseDesc.charAt(0)),
+            "TYPE",
+            "Ljava/lang/Class;");
+      } else if (DescriptorUtils.isVoidDescriptor(baseDesc)) {
+        visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Void", "TYPE", "Ljava/lang/Class;");
+      } else {
+        visitLdcInsn(Type.getType(baseDesc));
+      }
       // ..., dim-array, dim-member-type
       visitInsn(Opcodes.SWAP);
       // ..., dim-member-type, dim-array
diff --git a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
index bfd8334..7cce06b 100644
--- a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
@@ -229,6 +229,14 @@
         || c == 'D';
   }
 
+  public static boolean isVoidDescriptor(String descriptor) {
+    return descriptor.length() == 1 && isVoidType(descriptor.charAt(0));
+  }
+
+  public static boolean isVoidType(char c) {
+    return c == 'V';
+  }
+
   public static boolean isArrayDescriptor(String descriptor) {
     if (descriptor.length() < 2) {
       return false;
@@ -270,6 +278,31 @@
     }
   }
 
+  public static String primitiveDescriptorToBoxedInternalName(char primitive) {
+    switch (primitive) {
+      case 'V':
+        return "java/lang/Void";
+      case 'Z':
+        return "java/lang/Boolean";
+      case 'B':
+        return "java/lang/Byte";
+      case 'S':
+        return "java/lang/Short";
+      case 'C':
+        return "java/lang/Character";
+      case 'I':
+        return "java/lang/Integer";
+      case 'J':
+        return "java/lang/Long";
+      case 'F':
+        return "java/lang/Float";
+      case 'D':
+        return "java/lang/Double";
+      default:
+        throw new Unreachable("Unknown type " + primitive);
+    }
+  }
+
   /**
    * Get unqualified class name from its descriptor.
    *
@@ -327,7 +360,7 @@
     return Integer.max(classDescriptor.lastIndexOf("/"), 0) + 1;
   }
 
-   /**
+  /**
    * Get canonical class name from its descriptor.
    *
    * @param classDescriptor a class descriptor i.e. "La/b/C$D;"
diff --git a/src/test/java/com/android/tools/r8/examples/newarray/NewArrayTestRunner.java b/src/test/java/com/android/tools/r8/examples/newarray/NewArrayTestRunner.java
index 6e4775b..219dbed 100644
--- a/src/test/java/com/android/tools/r8/examples/newarray/NewArrayTestRunner.java
+++ b/src/test/java/com/android/tools/r8/examples/newarray/NewArrayTestRunner.java
@@ -110,9 +110,6 @@
         .setMinApi(parameters.getApiLevel())
         .setMode(mode)
         .run(parameters.getRuntime(), CLASS)
-        .applyIf(
-            enableMultiANewArrayDesugaringForClassFiles,
-            runResult -> runResult.assertFailureWithErrorThatThrows(NoClassDefFoundError.class),
-            runResult -> runResult.assertSuccessWithOutputLines(EXPECTED));
+        .assertSuccessWithOutputLines(EXPECTED);
   }
 }