Canonicalize item-based const-string.

Bug: 133672419
Change-Id: I3540c7810d438718539aee2540b1918eee5dcb15
diff --git a/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java b/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
index 6b151b2..21633fc 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
@@ -43,6 +43,14 @@
     return visitor.visit(this);
   }
 
+  public static DexItemBasedConstString copyOf(IRCode code, DexItemBasedConstString original) {
+    Value newValue =
+        new Value(code.valueNumberGenerator.next(),
+            original.outValue().getTypeLattice(),
+            original.getLocalInfo());
+    return copyOf(newValue, original);
+  }
+
   public static DexItemBasedConstString copyOf(Value newValue, DexItemBasedConstString original) {
     return new DexItemBasedConstString(
         newValue, original.getItem(), original.throwingInfo, original.classNameComputationInfo);
@@ -77,7 +85,10 @@
 
   @Override
   public boolean identicalNonValueNonPositionParts(Instruction other) {
-    return other.isDexItemBasedConstString() && other.asDexItemBasedConstString().item == item;
+    return other.isDexItemBasedConstString()
+        && other.asDexItemBasedConstString().item == item
+        && other.asDexItemBasedConstString().classNameComputationInfo
+            .equals(classNameComputationInfo);
   }
 
   @Override
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 cc75b41..2aea633 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
@@ -133,6 +133,7 @@
   private final InternalOptions options;
   private final CfgPrinter printer;
   private final CodeRewriter codeRewriter;
+  private final ConstantCanonicalizer constantCanonicalizer;
   private final MemberValuePropagation memberValuePropagation;
   private final LensCodeRewriter lensCodeRewriter;
   private final NonNullTracker nonNullTracker;
@@ -169,6 +170,7 @@
     this.printer = printer;
     this.mainDexClasses = mainDexClasses.getClasses();
     this.codeRewriter = new CodeRewriter(appView, this);
+    this.constantCanonicalizer = new ConstantCanonicalizer();
     this.classInitializerDefaultsOptimization =
         options.debug ? null : new ClassInitializerDefaultsOptimization(appView, this);
     this.stringConcatRewriter = new StringConcatRewriter(appView);
@@ -612,6 +614,7 @@
     }
 
     if (Log.ENABLED) {
+      constantCanonicalizer.logResults();
       if (idempotentFunctionCallCanonicalizer != null) {
         idempotentFunctionCallCanonicalizer.logResults();
       }
@@ -1119,7 +1122,7 @@
 
     // TODO(mkroghj) Test if shorten live ranges is worth it.
     if (!options.isGeneratingClassFiles()) {
-      ConstantCanonicalizer.canonicalize(appView, code);
+      constantCanonicalizer.canonicalize(appView, code);
       codeRewriter.useDedicatedConstantForLitInstruction(code);
       codeRewriter.shortenLiveRanges(code);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java
index 3ff6074..7c333ea 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java
@@ -9,12 +9,17 @@
 import com.android.tools.r8.ir.code.ConstInstruction;
 import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.ConstString;
+import com.android.tools.r8.ir.code.DexItemBasedConstString;
 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.Position;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.logging.Log;
+import com.android.tools.r8.utils.StringUtils;
 import it.unimi.dsi.fastutil.Hash.Strategy;
+import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
 import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenCustomHashMap;
 import it.unimi.dsi.fastutil.objects.Object2ObjectSortedMap.FastSortedEntrySet;
 import java.util.ArrayList;
@@ -25,9 +30,40 @@
  */
 public class ConstantCanonicalizer {
   // Threshold to limit the number of constant canonicalization.
-  private static final int MAX_CANONICALIZED_CONSTANT = 15;
+  private static final int MAX_CANONICALIZED_CONSTANT = 22;
 
-  public static void canonicalize(AppView<?> appView, IRCode code) {
+  private int numberOfConstNumberCanonicalization = 0;
+  private int numberOfConstStringCanonicalization = 0;
+  private int numberOfDexItemBasedConstStringCanonicalization = 0;
+  private int numberOfConstClassCanonicalization = 0;
+  private Object2IntMap<Long> histogramOfCanonicalizationCandidatesPerMethod = null;
+
+  public ConstantCanonicalizer() {
+    if (Log.ENABLED) {
+      histogramOfCanonicalizationCandidatesPerMethod = new Object2IntArrayMap<>();
+    }
+  }
+
+  public void logResults() {
+    assert Log.ENABLED;
+    Log.info(getClass(),
+        "# const-number canonicalization: %s", numberOfConstNumberCanonicalization);
+    Log.info(getClass(),
+        "# const-string canonicalization: %s", numberOfConstStringCanonicalization);
+    Log.info(getClass(),
+        "# item-based const-string canonicalization: %s",
+        numberOfDexItemBasedConstStringCanonicalization);
+    Log.info(getClass(),
+        "# const-class canonicalization: %s", numberOfConstClassCanonicalization);
+    assert histogramOfCanonicalizationCandidatesPerMethod != null;
+    Log.info(getClass(), "------ histogram of constant canonicalization candidates ------");
+    histogramOfCanonicalizationCandidatesPerMethod.forEach((length, count) -> {
+      Log.info(getClass(),
+          "%s: %s (%s)", length, StringUtils.times("*", Math.min(count, 53)), count);
+    });
+  }
+
+  public void canonicalize(AppView<?> appView, IRCode code) {
     Object2ObjectLinkedOpenCustomHashMap<ConstInstruction, List<Value>> valuesDefinedByConstant =
         new Object2ObjectLinkedOpenCustomHashMap<>(
             new Strategy<ConstInstruction>() {
@@ -35,6 +71,7 @@
               public int hashCode(ConstInstruction constInstruction) {
                 assert constInstruction.isConstNumber()
                     || constInstruction.isConstString()
+                    || constInstruction.isDexItemBasedConstString()
                     || constInstruction.isConstClass();
                 if (constInstruction.isConstNumber()) {
                   return Long.hashCode(constInstruction.asConstNumber().getRawValue())
@@ -43,6 +80,9 @@
                 if (constInstruction.isConstString()) {
                   return constInstruction.asConstString().getValue().hashCode();
                 }
+                if (constInstruction.isDexItemBasedConstString()) {
+                  return constInstruction.asDexItemBasedConstString().getItem().hashCode();
+                }
                 return constInstruction.asConstClass().getValue().hashCode();
               }
 
@@ -61,8 +101,11 @@
       InstructionListIterator it = block.listIterator();
       while (it.hasNext()) {
         Instruction current = it.next();
-        // Interested in ConstNumber, ConstString, and ConstClass
-        if (!current.isConstNumber() && !current.isConstString() && !current.isConstClass()) {
+        // Interested in ConstNumber, (DexItemBased)?ConstString, and ConstClass
+        if (!current.isConstNumber()
+            && !current.isConstString()
+            && !current.isDexItemBasedConstString()
+            && !current.isConstClass()) {
           continue;
         }
         // Do not canonicalize ConstClass that may have side effects. Its original instructions
@@ -74,7 +117,8 @@
         // Do not canonicalize ConstString instructions if there are monitor operations in the code.
         // That could lead to unbalanced locking and could lead to situations where OOM exceptions
         // could leave a synchronized method without unlocking the monitor.
-        if (current.isConstString() && code.hasMonitorInstruction) {
+        if ((current.isConstString() || current.isDexItemBasedConstString())
+            && code.hasMonitorInstruction) {
           continue;
         }
         // Constants with local info must not be canonicalized and must be filtered.
@@ -107,6 +151,11 @@
         valuesDefinedByConstant.object2ObjectEntrySet();
     // Sort the most frequently used constant first and exclude constant use only one time, such
     // as the {@code MAX_CANONICALIZED_CONSTANT} will be canonicalized into the entry block.
+    if (Log.ENABLED) {
+      Long numOfCandidates = entries.stream().filter(a -> a.getValue().size() > 1).count();
+      int count = histogramOfCanonicalizationCandidatesPerMethod.getOrDefault(numOfCandidates, 0);
+      histogramOfCanonicalizationCandidatesPerMethod.put(numOfCandidates, count + 1);
+    }
     entries.stream()
         .filter(a -> a.getValue().size() > 1)
         .sorted((a, b) -> Integer.compare(b.getValue().size(), a.getValue().size()))
@@ -115,17 +164,30 @@
           ConstInstruction canonicalizedConstant = entry.getKey().asConstInstruction();
           assert canonicalizedConstant.isConstNumber()
               || canonicalizedConstant.isConstString()
+              || canonicalizedConstant.isDexItemBasedConstString()
               || canonicalizedConstant.isConstClass();
           ConstInstruction newConst;
           if (canonicalizedConstant.isConstNumber()) {
-            ConstNumber canonicalizedConstantNumber = canonicalizedConstant.asConstNumber();
-            newConst = ConstNumber.copyOf(code, canonicalizedConstantNumber);
+            if (Log.ENABLED) {
+              numberOfConstNumberCanonicalization++;
+            }
+            newConst = ConstNumber.copyOf(code, canonicalizedConstant.asConstNumber());
           } else if (canonicalizedConstant.isConstString()) {
-            ConstString canonicalizedConstantString = canonicalizedConstant.asConstString();
-            newConst = ConstString.copyOf(code, canonicalizedConstantString);
+            if (Log.ENABLED) {
+              numberOfConstStringCanonicalization++;
+            }
+            newConst = ConstString.copyOf(code, canonicalizedConstant.asConstString());
+          } else if (canonicalizedConstant.isDexItemBasedConstString()) {
+            if (Log.ENABLED) {
+              numberOfDexItemBasedConstStringCanonicalization++;
+            }
+            newConst = DexItemBasedConstString.copyOf(
+                code, canonicalizedConstant.asDexItemBasedConstString());
           } else {
-            ConstClass canonicalizedConstClass = canonicalizedConstant.asConstClass();
-            newConst = ConstClass.copyOf(code, canonicalizedConstClass);
+            if (Log.ENABLED) {
+              numberOfConstClassCanonicalization++;
+            }
+            newConst = ConstClass.copyOf(code, canonicalizedConstant.asConstClass());
           }
           newConst.setPosition(firstNonNonePosition);
           insertCanonicalizedConstant(code, newConst);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index d61758b..eb03573 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -73,6 +73,21 @@
     public boolean needsToRegisterTypeReference() {
       return classNameComputationOption.needsToRegisterTypeReference();
     }
+
+    @Override
+    public boolean equals(Object other) {
+      if (!(other instanceof ClassNameComputationInfo)) {
+        return false;
+      }
+      ClassNameComputationInfo otherInfo = (ClassNameComputationInfo) other;
+      return this.classNameComputationOption == otherInfo.classNameComputationOption
+          && this.arrayDepth == otherInfo.arrayDepth;
+    }
+
+    @Override
+    public int hashCode() {
+      return classNameComputationOption.ordinal() * 31 + arrayDepth;
+    }
   }
 
   // Rewrite getClass() call to const-class if the type of the given instance is effectively final.
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/DexItemBasedConstStringCanonicalizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/DexItemBasedConstStringCanonicalizationTest.java
new file mode 100644
index 0000000..0f2e532
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/DexItemBasedConstStringCanonicalizationTest.java
@@ -0,0 +1,125 @@
+// Copyright (c) 2019, 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.ir.optimize.reflection;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.D8TestRunResult;
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.Streams;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+class CanonicalizationTestClass {}
+
+class CanonicalizationTestMain {
+  public static void main(String... args) {
+    System.out.println(CanonicalizationTestClass.class.getSimpleName());
+    // Canonicalized.
+    System.out.println(CanonicalizationTestClass.class.getSimpleName());
+    try {
+      // Canonicalized (not a monitor block)
+      System.out.println(CanonicalizationTestClass.class.getSimpleName());
+    } catch (Exception e) {
+      // Intentionally empty.
+    }
+  }
+}
+
+@RunWith(Parameterized.class)
+public class DexItemBasedConstStringCanonicalizationTest extends GetNameTestBase {
+  private static final Class<?> MAIN = CanonicalizationTestMain.class;
+  private static final String JAVA_OUTPUT = StringUtils.lines(
+      "CanonicalizationTestClass",
+      "CanonicalizationTestClass",
+      "CanonicalizationTestClass"
+  );
+  private static final String RENAMED_OUTPUT = StringUtils.lines(
+      "a",
+      "a",
+      "a"
+  );
+
+  public DexItemBasedConstStringCanonicalizationTest(
+      TestParameters parameters, boolean enableMinification) {
+    super(parameters, enableMinification);
+  }
+
+  @Test
+  public void testJVMOutput() throws Exception {
+    assumeTrue(
+        "Only run JVM reference on CF runtimes",
+        parameters.isCfRuntime() && !enableMinification);
+    testForJvm()
+        .addTestClasspath()
+        .run(parameters.getRuntime(), MAIN)
+        .assertSuccessWithOutput(JAVA_OUTPUT);
+  }
+
+  private void test(
+      TestRunResult result, int expectedGetNameCount, int expectedConstString) throws Exception {
+    CodeInspector codeInspector = result.inspector();
+    ClassSubject mainClass = codeInspector.clazz(MAIN);
+    MethodSubject mainMethod = mainClass.mainMethod();
+    assertThat(mainMethod, isPresent());
+    assertEquals(expectedGetNameCount, countGetName(mainMethod));
+    assertEquals(
+        expectedConstString,
+        Streams.stream(mainMethod.iterateInstructions(
+            i -> i.isConstString(JumboStringMode.ALLOW))).count());
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    assumeTrue("Only run D8 for Dex backend", parameters.isDexRuntime() && !enableMinification);
+
+    D8TestRunResult result =
+        testForD8()
+            .debug()
+            .addProgramClasses(MAIN, CanonicalizationTestClass.class)
+            .setMinApi(parameters.getRuntime())
+            .addOptionsModification(this::configure)
+            .run(parameters.getRuntime(), MAIN)
+            .assertSuccessWithOutput(JAVA_OUTPUT);
+    test(result, 3, 0);
+
+    result =
+        testForD8()
+            .release()
+            .addProgramClasses(MAIN, CanonicalizationTestClass.class)
+            .setMinApi(parameters.getRuntime())
+            .addOptionsModification(this::configure)
+            .run(parameters.getRuntime(), MAIN)
+            .assertSuccessWithOutput(JAVA_OUTPUT);
+    test(result, 0, 1);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    R8TestRunResult result =
+        testForR8(parameters.getBackend())
+            .addProgramClasses(MAIN, CanonicalizationTestClass.class)
+            .addKeepMainRule(MAIN)
+            .addKeepRules("-keep class **.TestClass")
+            .minification(enableMinification)
+            .setMinApi(parameters.getRuntime())
+            .addOptionsModification(this::configure)
+            .run(parameters.getRuntime(), MAIN)
+            .assertSuccessWithOutput(enableMinification ? RENAMED_OUTPUT : JAVA_OUTPUT);
+    // Due to the different behavior regarding constant canonicalization.
+    int expectedConstStringCount = parameters.isCfRuntime() ? 3 : 1;
+    test(result, 0, expectedConstStringCount);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java b/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
index 7fa8b54..28f4e92 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
@@ -8,12 +8,12 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexValue.DexValueString;
-import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -25,7 +25,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
 import com.google.common.collect.Streams;
-import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -34,9 +33,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
 import java.util.stream.Stream;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -45,50 +43,34 @@
 @RunWith(Parameterized.class)
 public class IdentifierMinifierTest extends TestBase {
 
+  private final TestParameters parameters;
   private final String appFileName;
   private final List<String> keepRulesFiles;
-  private final Consumer<CodeInspector> inspection;
-  private final Backend backend;
+  private final BiConsumer<TestParameters, CodeInspector> inspection;
 
   public IdentifierMinifierTest(
-      Backend backend,
+      TestParameters parameters,
       String test,
       List<String> keepRulesFiles,
-      Consumer<CodeInspector> inspection) {
-    assert backend == Backend.DEX || backend == Backend.CF;
-    this.appFileName =
-        ToolHelper.EXAMPLES_BUILD_DIR + test + (backend == Backend.DEX ? "/classes.dex" : ".jar");
+      BiConsumer<TestParameters, CodeInspector> inspection) {
+    this.parameters = parameters;
+    this.appFileName = ToolHelper.EXAMPLES_BUILD_DIR + test + FileUtils.JAR_EXTENSION;
     this.keepRulesFiles = keepRulesFiles;
     this.inspection = inspection;
-    this.backend = backend;
-  }
-
-  private AndroidApp processedApp;
-
-  @Before
-  public void generateR8ProcessedApp() throws Exception {
-    Path out = temp.getRoot().toPath();
-    R8Command.Builder builder =
-        ToolHelper.addProguardConfigurationConsumer(
-                R8Command.builder(),
-                pgConfig -> {
-                  pgConfig.setPrintMapping(true);
-                  pgConfig.setPrintMappingFile(out.resolve(ToolHelper.DEFAULT_PROGUARD_MAP_FILE));
-                })
-            .setOutput(out, outputMode(backend))
-            .addLibraryFiles(runtimeJar(backend))
-            .addProguardConfigurationFiles(ListUtils.map(keepRulesFiles, Paths::get));
-    ToolHelper.getAppBuilder(builder).addProgramFiles(Paths.get(appFileName));
-    processedApp = ToolHelper.runR8(builder.build(), o -> o.debug = false);
   }
 
   @Test
   public void identiferMinifierTest() throws Exception {
-    CodeInspector codeInspector = new CodeInspector(processedApp);
-    inspection.accept(codeInspector);
+    CodeInspector codeInspector =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(Paths.get(appFileName))
+            .addKeepRuleFiles(ListUtils.map(keepRulesFiles, Paths::get))
+            .setMinApi(parameters.getRuntime())
+            .compile().inspector();
+    inspection.accept(parameters, codeInspector);
   }
 
-  @Parameters(name = "[{0}] test: {1} keep: {2}")
+  @Parameters(name = "{0} test: {1} keep: {2}")
   public static Collection<Object[]> data() {
     List<String> tests = Arrays.asList(
         "adaptclassstrings",
@@ -97,7 +79,7 @@
         "getmembers",
         "identifiernamestring");
 
-    Map<String, Consumer<CodeInspector>> inspections = new HashMap<>();
+    Map<String, BiConsumer<TestParameters, CodeInspector>> inspections = new HashMap<>();
     inspections.put("adaptclassstrings:keep-rules-1.txt", IdentifierMinifierTest::test1_rule1);
     inspections.put("adaptclassstrings:keep-rules-2.txt", IdentifierMinifierTest::test1_rule2);
     inspections.put("adaptclassstrings:keep-rules-3.txt", IdentifierMinifierTest::test1_rule3);
@@ -110,12 +92,11 @@
     inspections.put("identifiernamestring:keep-rules-3.txt", IdentifierMinifierTest::test2_rule3);
     Collection<Object[]> parameters = NamingTestBase.createTests(tests, inspections);
 
-    // Duplicate parameters for each backend.
     List<Object[]> parametersWithBackend = new ArrayList<>();
-    for (Backend backend : ToolHelper.getBackends()) {
+    for (TestParameters testParameter : getTestParameters().withAllRuntimes().build()) {
       for (Object[] row : parameters) {
         Object[] newRow = new Object[row.length + 1];
-        newRow[0] = backend;
+        newRow[0] = testParameter;
         System.arraycopy(row, 0, newRow, 1, row.length);
         parametersWithBackend.add(newRow);
       }
@@ -125,18 +106,21 @@
   }
 
   // Without -adaptclassstrings
-  private static void test1_rule1(CodeInspector inspector) {
-    test1_rules(inspector, 4, 0, 0);
+  private static void test1_rule1(TestParameters parameters, CodeInspector inspector) {
+    int expectedRenamedIdentifierInMain = parameters.isCfRuntime() ? 4 : 3;
+    test1_rules(inspector, expectedRenamedIdentifierInMain, 0, 0);
   }
 
   // With -adaptclassstrings *.*A
-  private static void test1_rule2(CodeInspector inspector) {
-    test1_rules(inspector, 4, 1, 1);
+  private static void test1_rule2(TestParameters parameters, CodeInspector inspector) {
+    int expectedRenamedIdentifierInMain = parameters.isCfRuntime() ? 4 : 3;
+    test1_rules(inspector, expectedRenamedIdentifierInMain, 1, 1);
   }
 
   // With -adaptclassstrings (no filter)
-  private static void test1_rule3(CodeInspector inspector) {
-    test1_rules(inspector, 5, 1, 1);
+  private static void test1_rule3(TestParameters parameters, CodeInspector inspector) {
+    int expectedRenamedIdentifierInMain = parameters.isCfRuntime() ? 5 : 4;
+    test1_rules(inspector, expectedRenamedIdentifierInMain, 1, 1);
   }
 
   private static void test1_rules(
@@ -162,7 +146,7 @@
     assertEquals(countInAFields, renamedYetFoundIdentifierCount);
   }
 
-  private static void test_atomicfieldupdater(CodeInspector inspector) {
+  private static void test_atomicfieldupdater(TestParameters parameters, CodeInspector inspector) {
     ClassSubject mainClass = inspector.clazz("atomicfieldupdater.Main");
     MethodSubject main = mainClass.method(CodeInspector.MAIN);
     assertTrue(main instanceof FoundMethodSubject);
@@ -175,7 +159,7 @@
     assertEquals(3, constStringInstructions.size());
   }
 
-  private static void test_forname(CodeInspector inspector) {
+  private static void test_forname(TestParameters parameters, CodeInspector inspector) {
     ClassSubject mainClass = inspector.clazz("forname.Main");
     MethodSubject main = mainClass.method(CodeInspector.MAIN);
     assertTrue(main instanceof FoundMethodSubject);
@@ -185,7 +169,7 @@
     assertEquals(1, renamedYetFoundIdentifierCount);
   }
 
-  private static void test_getmembers(CodeInspector inspector) {
+  private static void test_getmembers(TestParameters parameters, CodeInspector inspector) {
     ClassSubject mainClass = inspector.clazz("getmembers.Main");
     MethodSubject main = mainClass.method(CodeInspector.MAIN);
     assertTrue(main instanceof FoundMethodSubject);
@@ -206,7 +190,7 @@
   }
 
   // Without -identifiernamestring
-  private static void test2_rule1(CodeInspector inspector) {
+  private static void test2_rule1(TestParameters parameters, CodeInspector inspector) {
     ClassSubject mainClass = inspector.clazz("identifiernamestring.Main");
     MethodSubject main = mainClass.method(CodeInspector.MAIN);
     assertTrue(main instanceof FoundMethodSubject);
@@ -230,14 +214,14 @@
   }
 
   // With -identifiernamestring for annotations and name-based filters
-  private static void test2_rule2(CodeInspector inspector) {
+  private static void test2_rule2(TestParameters parameters, CodeInspector inspector) {
     ClassSubject mainClass = inspector.clazz("identifiernamestring.Main");
     MethodSubject main = mainClass.method(CodeInspector.MAIN);
     assertTrue(main instanceof FoundMethodSubject);
     FoundMethodSubject foundMain = (FoundMethodSubject) main;
     verifyPresenceOfConstString(foundMain);
     int renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, foundMain);
-    assertEquals(2, renamedYetFoundIdentifierCount);
+    assertEquals(parameters.isCfRuntime() ? 2 : 1, renamedYetFoundIdentifierCount);
 
     ClassSubject aClass = inspector.clazz("identifiernamestring.A");
     MethodSubject aInit =
@@ -254,7 +238,7 @@
   }
 
   // With -identifiernamestring for reflective methods in testing class R.
-  private static void test2_rule3(CodeInspector inspector) {
+  private static void test2_rule3(TestParameters parameters, CodeInspector inspector) {
     ClassSubject mainClass = inspector.clazz("identifiernamestring.Main");
     MethodSubject main = mainClass.method(CodeInspector.MAIN);
     assertTrue(main instanceof FoundMethodSubject);