D8 Nest based access constructor

- add NestConstructor synthetized class
- rewrite init to new init methods with NestConstructor param

Bug: 130529390
Change-Id: Ic0f7c5986ede324adcac9b20c396dbbec600089e
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 01fc41d..97fd72c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -731,6 +731,39 @@
     return builder.build();
   }
 
+  public DexEncodedMethod toInitializerForwardingBridge(
+      DexClass holder, DexDefinitionSupplier definitions, DexProgramClass nestConstructor) {
+    assert accessFlags.isPrivate()
+        : "Expected to create bridge for private constructor as part of nest-based access"
+            + " desugaring";
+    DexProto newProto =
+        definitions.dexItemFactory().appendTypeToProto(method.proto, nestConstructor.type);
+    DexMethod newMethod =
+        definitions.dexItemFactory().createMethod(method.holder, newProto, method.name);
+    Builder builder = builder(this);
+    builder.setMethod(newMethod);
+    builder.setCode(
+        new SynthesizedCode(
+            callerPosition ->
+                new ForwardMethodSourceCode(
+                    holder.type,
+                    newMethod,
+                    newMethod,
+                    holder.type,
+                    method,
+                    Invoke.Type.DIRECT,
+                    callerPosition,
+                    holder.isInterface(),
+                    false,
+                    true),
+            registry -> registry.registerInvokeDirect(method)));
+    assert !builder.accessFlags.isStatic();
+    builder.accessFlags.unsetPrivate();
+    builder.accessFlags.setSynthetic();
+    builder.accessFlags.setConstructor();
+    return builder.build();
+  }
+
   public static DexEncodedMethod createFieldAccessorBridge(
       DexFieldWithAccess fieldWithAccess,
       DexClass holder,
@@ -783,7 +816,7 @@
     DexProto proto =
         accessFlags.isStatic()
             ? method.proto
-            : definitions.dexItemFactory().createExtendedProto(holder.type, method.proto);
+            : definitions.dexItemFactory().prependTypeToProto(holder.type, method.proto);
     DexMethod newMethod = definitions.dexItemFactory().createMethod(holder.type, proto, newName);
     Builder builder = builder(this);
     builder.setMethod(newMethod);
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 11f90fb..c1c8cc6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -1054,7 +1054,7 @@
         parameters.length == 0 ? DexTypeList.empty() : new DexTypeList(parameters));
   }
 
-  public DexProto createExtendedProto(DexType extraFirstType, DexProto initialProto) {
+  public DexProto prependTypeToProto(DexType extraFirstType, DexProto initialProto) {
     DexType[] parameterTypes = new DexType[initialProto.parameters.size() + 1];
     parameterTypes[0] = extraFirstType;
     System.arraycopy(
@@ -1062,6 +1062,14 @@
     return createProto(initialProto.returnType, parameterTypes);
   }
 
+  public DexProto appendTypeToProto(DexProto initialProto, DexType extraLastType) {
+    DexType[] parameterTypes = new DexType[initialProto.parameters.size() + 1];
+    System.arraycopy(
+        initialProto.parameters.values, 0, parameterTypes, 0, initialProto.parameters.size());
+    parameterTypes[parameterTypes.length - 1] = extraLastType;
+    return createProto(initialProto.returnType, parameterTypes);
+  }
+
   public DexProto applyClassMappingToProto(
       DexProto proto, Function<DexType, DexType> mapping, Map<DexProto, DexProto> cache) {
     assert cache != null;
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 41af11a..801d6f8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.desugar.Java8MethodRewriter;
+import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring;
 import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -248,6 +249,7 @@
         || name.contains(LAMBDA_GROUP_CLASS_NAME_PREFIX)
         || name.contains(OutlineOptions.CLASS_NAME)
         || name.contains(TwrCloseResourceRewriter.UTILITY_CLASS_NAME)
+        || name.contains(NestBasedAccessDesugaring.NEST_CONSTRUCTOR_NAME)
         || name.contains(Java8MethodRewriter.UTILITY_CLASS_NAME_PREFIX);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 0aed270..d104823 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -296,6 +296,12 @@
     }
   }
 
+  private void synthetizeNestConstructor(Builder<?> builder) {
+    if (nestBasedAccessDesugaringRewriter != null) {
+      nestBasedAccessDesugaringRewriter.synthetizeNestConstructor(builder);
+    }
+  }
+
   private void synthesizeLambdaClasses(Builder<?> builder, ExecutorService executorService)
       throws ExecutionException {
     if (lambdaRewriter != null) {
@@ -361,6 +367,7 @@
     Builder<?> builder = application.builder();
     builder.setHighestSortingString(highestSortingString);
 
+    synthetizeNestConstructor(builder);
     synthesizeLambdaClasses(builder, executor);
     desugarInterfaceMethods(builder, ExcludeDexResources, executor);
     synthesizeTwrCloseResourceUtilityClass(builder, executor);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
index 4b64470..a309b6d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -1,7 +1,11 @@
 package com.android.tools.r8.ir.desugar;
 
+import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClassAccessFlags;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -10,9 +14,12 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.NestMemberClassAttribute;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.origin.SynthesizedOrigin;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -33,20 +40,19 @@
   private static final String NEST_ACCESS_FIELD_PUT_NAME_PREFIX = NEST_ACCESS_NAME_PREFIX + "fput";
   private static final String NEST_ACCESS_STATIC_PUT_FIELD_NAME_PREFIX =
       NEST_ACCESS_NAME_PREFIX + "sfput";
+  public static final String NEST_CONSTRUCTOR_NAME = NEST_ACCESS_NAME_PREFIX + "Constructor";
+  private static final String FULL_NEST_CONTRUCTOR_NAME = "L" + NEST_CONSTRUCTOR_NAME + ";";
 
-  private final AppView<?> appView;
+  protected final AppView<?> appView;
   private final HashMap<DexEncodedMethod, DexEncodedMethod> bridges = new HashMap<>();
   private final HashMap<DexFieldWithAccess, DexEncodedMethod> fieldBridges = new HashMap<>();
   private final HashMap<DexEncodedMethod, DexProgramClass> deferredBridgesToAdd = new HashMap<>();
+  private DexProgramClass nestConstructor;
 
   public NestBasedAccessDesugaring(AppView<?> appView) {
     this.appView = appView;
   }
 
-  public AppView<?> getAppView() {
-    return appView;
-  }
-
   public void analyzeNests() {
     // TODO(b/130529338) we don't need to compute a list with all live nests.
     // we just need to iterate all live nests.
@@ -55,6 +61,13 @@
     addDeferredBridges();
   }
 
+  public void synthetizeNestConstructor(DexApplication.Builder<?> builder) {
+    if (nestConstructor != null) {
+      appView.appInfo().addSynthesizedClass(nestConstructor);
+      builder.addSynthesizedClass(nestConstructor, true);
+    }
+  }
+
   private void addDeferredBridges() {
     for (Map.Entry<DexEncodedMethod, DexProgramClass> entry : deferredBridgesToAdd.entrySet()) {
       entry.getValue().addMethod(entry.getKey());
@@ -152,6 +165,8 @@
 
   protected abstract void shouldRewriteCalls(DexMethod method, DexMethod bridge);
 
+  protected abstract void shouldRewriteInitializers(DexMethod method, DexMethod bridge);
+
   protected abstract void shouldRewriteStaticGetFields(DexField field, DexMethod bridge);
 
   protected abstract void shouldRewriteStaticPutFields(DexField field, DexMethod bridge);
@@ -197,6 +212,34 @@
     return appView.dexItemFactory().createString(fullName);
   }
 
+  private DexProgramClass ensureNestConstructorClass() {
+    if (nestConstructor != null) {
+      return nestConstructor;
+    }
+    nestConstructor =
+        new DexProgramClass(
+            appView.dexItemFactory().createType(FULL_NEST_CONTRUCTOR_NAME),
+            null,
+            new SynthesizedOrigin("Nest based access desugaring", getClass()),
+            // Make the synthesized class public since shared in the whole program.
+            ClassAccessFlags.fromDexAccessFlags(
+                Constants.ACC_FINAL | Constants.ACC_SYNTHETIC | Constants.ACC_PUBLIC),
+            appView.dexItemFactory().objectType,
+            DexTypeList.empty(),
+            appView.dexItemFactory().createString("nest"),
+            null,
+            Collections.emptyList(),
+            null,
+            Collections.emptyList(),
+            DexAnnotationSet.empty(),
+            DexEncodedField.EMPTY_ARRAY,
+            DexEncodedField.EMPTY_ARRAY,
+            DexEncodedMethod.EMPTY_ARRAY,
+            DexEncodedMethod.EMPTY_ARRAY,
+            appView.dexItemFactory().getSkipNameValidationForTesting());
+    return nestConstructor;
+  }
+
   private class NestBasedAccessDesugaringUseRegistry extends UseRegistry {
 
     private final List<DexType> nest;
@@ -216,17 +259,17 @@
       if (target == null || !target.accessFlags.isPrivate()) {
         return false;
       }
-      if (target.isInstanceInitializer()) {
-        // TODO(b/130529338): support initializer
-        return false;
-      }
       DexEncodedMethod bridge =
           bridges.computeIfAbsent(
               target,
               k -> {
                 DexClass holder = appView.definitionFor(method.holder);
                 DexEncodedMethod localBridge =
-                    target.toStaticForwardingBridge(holder, appView, methodBridgeName(target));
+                    target.isInstanceInitializer()
+                        ? target.toInitializerForwardingBridge(
+                            holder, appView, ensureNestConstructorClass())
+                        : target.toStaticForwardingBridge(
+                            holder, appView, methodBridgeName(target));
                 // Accesses to program classes private members require bridge insertion.
                 if (holder.isProgramClass()) {
                   deferredBridgesToAdd.put(localBridge, holder.asProgramClass());
@@ -237,7 +280,11 @@
               });
       // In program classes, any access to nest mate private member needs to be rewritten.
       if (currentClass.isProgramClass()) {
-        shouldRewriteCalls(method, bridge.method);
+        if (target.isInstanceInitializer()) {
+          shouldRewriteInitializers(method, bridge.method);
+        } else {
+          shouldRewriteCalls(method, bridge.method);
+        }
       }
       return true;
     }
@@ -269,14 +316,14 @@
               });
       // In program classes, any access to nest mate private member needs to be rewritten.
       if (currentClass.isProgramClass()) {
-        if (isGet){
-          if (target.isStatic()){
+        if (isGet) {
+          if (target.isStatic()) {
             shouldRewriteStaticGetFields(field, bridge.method);
           } else {
             shouldRewriteInstanceGetFields(field, bridge.method);
           }
         } else {
-          if (target.isStatic()){
+          if (target.isStatic()) {
             shouldRewriteStaticPutFields(field, bridge.method);
           } else {
             shouldRewriteInstancePutFields(field, bridge.method);
@@ -328,7 +375,9 @@
 
     @Override
     public boolean registerNewInstance(DexType type) {
-      // TODO(b/130529338): support initializer
+      // Unrelated to access based control.
+      // The <init> method has to be rewritten instead
+      // and <init> is called through registerInvoke.
       return false;
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringAnalysis.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringAnalysis.java
index 6f44d56..b009861 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringAnalysis.java
@@ -15,7 +15,6 @@
   }
 
   public GraphLense run() {
-    AppView<?> appView = this.getAppView();
     if (appView.options().canUseNestBasedAccess()) {
       return appView.graphLense();
     }
@@ -24,27 +23,33 @@
   }
 
   @Override
+  protected void shouldRewriteInitializers(DexMethod method, DexMethod bridge) {
+    // TODO(b/130529338): support initializer in r8
+    // initializerMap.put(method, bridge);
+  }
+
+  @Override
   protected void shouldRewriteCalls(DexMethod method, DexMethod bridge) {
     builder.map(method, bridge);
   }
 
   @Override
   protected void shouldRewriteStaticGetFields(DexField field, DexMethod bridge) {
-    builder.mapStaticGet(field,bridge);
+    builder.mapStaticGet(field, bridge);
   }
 
   @Override
   protected void shouldRewriteStaticPutFields(DexField field, DexMethod bridge) {
-    builder.mapStaticPut(field,bridge);
+    builder.mapStaticPut(field, bridge);
   }
 
   @Override
   protected void shouldRewriteInstanceGetFields(DexField field, DexMethod bridge) {
-    builder.mapInstanceGet(field,bridge);
+    builder.mapInstanceGet(field, bridge);
   }
 
   @Override
   protected void shouldRewriteInstancePutFields(DexField field, DexMethod bridge) {
-    builder.mapInstancePut(field,bridge);
+    builder.mapInstancePut(field, bridge);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java
index 7cec930..ed4cfbe 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaringRewriter.java
@@ -8,16 +8,20 @@
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.InvokeStatic;
-import java.util.HashMap;
+import com.android.tools.r8.ir.code.Value;
+import java.util.ArrayList;
 import java.util.IdentityHashMap;
+import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 
 public class NestBasedAccessDesugaringRewriter extends NestBasedAccessDesugaring {
 
-  private HashMap<DexMethod, DexMethod> methodToRewrite = new HashMap<>();
+  private Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>();
+  private Map<DexMethod, DexMethod> initializerMap = new IdentityHashMap<>();
   private final Map<DexField, DexMethod> staticGetToMethodMap = new IdentityHashMap<>();
   private final Map<DexField, DexMethod> staticPutToMethodMap = new IdentityHashMap<>();
   private final Map<DexField, DexMethod> instanceGetToMethodMap = new IdentityHashMap<>();
@@ -29,7 +33,12 @@
 
   @Override
   protected void shouldRewriteCalls(DexMethod method, DexMethod bridge) {
-    methodToRewrite.put(method, bridge);
+    methodMap.put(method, bridge);
+  }
+
+  @Override
+  protected void shouldRewriteInitializers(DexMethod method, DexMethod bridge) {
+    initializerMap.put(method, bridge);
   }
 
   @Override
@@ -67,9 +76,6 @@
 
   public void rewriteNestBasedAccesses(
       DexEncodedMethod encodedMethod, IRCode code, AppView<?> appView) {
-    if (methodToRewrite.isEmpty()) {
-      return;
-    }
     ListIterator<BasicBlock> blocks = code.listIterator();
     while (blocks.hasNext()) {
       BasicBlock block = blocks.next();
@@ -79,10 +85,23 @@
         if (instruction.isInvokeMethod() && !instruction.isInvokeSuper()) {
           InvokeMethod invokeMethod = instruction.asInvokeMethod();
           DexMethod methodCalled = invokeMethod.getInvokedMethod();
-          DexMethod newTarget = methodToRewrite.get(methodCalled);
+          DexMethod newTarget = methodMap.get(methodCalled);
           if (newTarget != null && encodedMethod.method != newTarget) {
             instructions.replaceCurrentInstruction(
                 new InvokeStatic(newTarget, invokeMethod.outValue(), invokeMethod.arguments()));
+          } else {
+            newTarget = initializerMap.get(methodCalled);
+            if (newTarget != null && encodedMethod.method != newTarget) {
+              // insert extra null value and replace call.
+              instructions.previous();
+              Value extraNullValue =
+                  instructions.insertConstNullInstruction(code, appView.options());
+              instructions.next();
+              List<Value> parameters = new ArrayList<>(invokeMethod.arguments());
+              parameters.add(extraNullValue);
+              instructions.replaceCurrentInstruction(
+                  new InvokeDirect(newTarget, invokeMethod.outValue(), parameters));
+            }
           }
         } else if (instruction.isInstanceGet()) {
           rewriteFieldAccess(
@@ -95,7 +114,6 @@
         } else if (instruction.isStaticPut()) {
           rewriteFieldAccess(instruction, instructions, encodedMethod.method, staticPutToMethodMap);
         }
-        // TODO(b/130529338): support initializers
       }
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
index 76dba16..c49c3e1 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.utils.BooleanUtils;
 import com.google.common.collect.Lists;
 import java.util.ArrayList;
 import java.util.List;
@@ -24,6 +25,7 @@
   private final Invoke.Type invokeType;
   private final boolean castResult;
   private final boolean isInterface;
+  private final boolean extraNullParameter;
 
   public ForwardMethodSourceCode(
       DexType receiver,
@@ -56,6 +58,30 @@
       Position callerPosition,
       boolean isInterface,
       boolean castResult) {
+    this(
+        receiver,
+        method,
+        originalMethod,
+        targetReceiver,
+        target,
+        invokeType,
+        callerPosition,
+        isInterface,
+        castResult,
+        false);
+  }
+
+  public ForwardMethodSourceCode(
+      DexType receiver,
+      DexMethod method,
+      DexMethod originalMethod,
+      DexType targetReceiver,
+      DexMethod target,
+      Type invokeType,
+      Position callerPosition,
+      boolean isInterface,
+      boolean castResult,
+      boolean extraNullParameter) {
     super(receiver, method, callerPosition, originalMethod);
     assert (targetReceiver == null) == (invokeType == Invoke.Type.STATIC);
 
@@ -64,6 +90,7 @@
     this.invokeType = invokeType;
     this.isInterface = isInterface;
     this.castResult = castResult;
+    this.extraNullParameter = extraNullParameter;
     assert checkSignatures();
 
     switch (invokeType) {
@@ -84,6 +111,9 @@
       sourceParams.add(receiver);
     }
     sourceParams.addAll(Lists.newArrayList(proto.parameters.values));
+    if (extraNullParameter) {
+      sourceParams.remove(sourceParams.size() - 1);
+    }
 
     List<DexType> targetParams = new ArrayList<>();
     if (targetReceiver != null) {
@@ -118,7 +148,7 @@
     }
 
     DexType[] accessorParams = proto.parameters.values;
-    for (int i = 0; i < accessorParams.length; i++) {
+    for (int i = 0; i < accessorParams.length - BooleanUtils.intValue(extraNullParameter); i++) {
       argValueTypes.add(ValueType.fromDexType(accessorParams[i]));
       argRegisters.add(getParamRegister(i));
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index b71e9e1..25c61d8 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -951,8 +951,7 @@
                   Rename.ALWAYS,
                   appView
                       .dexItemFactory()
-                      .createExtendedProto(
-                          virtualMethod.method.holder, virtualMethod.method.proto));
+                      .prependTypeToProto(virtualMethod.method.holder, virtualMethod.method.proto));
           makeStatic(resultingDirectMethod);
 
           // Update method pool collection now that we are adding a new public method.
diff --git a/src/test/java/com/android/tools/r8/desugar/NestAccessControl/NestAccessControlTest.java b/src/test/java/com/android/tools/r8/desugar/NestAccessControl/NestAccessControlTest.java
index d40cc47..1fa9dd9 100644
--- a/src/test/java/com/android/tools/r8/desugar/NestAccessControl/NestAccessControlTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/NestAccessControl/NestAccessControlTest.java
@@ -12,7 +12,6 @@
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.D8TestCompileResult;
-import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestBase;
@@ -133,7 +132,7 @@
     this.parameters = parameters;
   }
 
-  public void testJavaAndD8(String id, boolean d8Success) throws Exception {
+  public void testJavaAndD8(String id) throws Exception {
     if (parameters.isCfRuntime()) {
       testForJvm()
           .addProgramFiles(JAR)
@@ -141,32 +140,20 @@
           .assertSuccessWithOutput(getExpectedResult(id));
     } else {
       assert parameters.isDexRuntime();
-      D8TestRunResult run =
-          d8CompilationResult
-              .apply(parameters.getApiLevel())
-              .run(parameters.getRuntime(), getMainClass(id));
-      if (d8Success) {
-        run.assertSuccessWithOutput(getExpectedResult(id));
-      } else {
-        if (parameters.isDexRuntime()
-            && (parameters.getRuntime().asDex().getVm().getVersion() == Version.V6_0_1
-                || parameters.getRuntime().asDex().getVm().getVersion() == Version.V5_1_1)) {
-          run.assertFailure(); // different message, same error
-        } else {
-          run.assertFailureWithErrorThatMatches(containsString("IllegalAccessError"));
-        }
-      }
+      d8CompilationResult
+          .apply(parameters.getApiLevel())
+          .run(parameters.getRuntime(), getMainClass(id))
+          .assertSuccessWithOutput(getExpectedResult(id));
     }
   }
 
   @Test
   public void testJavaAndD8() throws Exception {
-    // TODO(b/130529390): As features are implemented, set success to true in each line.
-    testJavaAndD8("methods", true);
-    testJavaAndD8("fields", true);
-    testJavaAndD8("constructors", false);
-    testJavaAndD8("anonymous", true);
-    testJavaAndD8("all", false);
+    testJavaAndD8("methods");
+    testJavaAndD8("fields");
+    testJavaAndD8("constructors");
+    testJavaAndD8("anonymous");
+    testJavaAndD8("all");
   }
 
   public void testR8(String id, boolean r8Success) throws Exception {