Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit afd3be1f authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "[HostStubGen] Support replacing constructor calls to methods" into main...

Merge "[HostStubGen] Support replacing constructor calls to methods" into main am: 59a640e2 am: 37d4ac58

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/3505761



Change-Id: I4211a99bec443907348c2a1f8e2c9b9ac19f267d
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 8931adcb 37d4ac58
Loading
Loading
Loading
Loading
+28 −1
Original line number Diff line number Diff line
@@ -267,6 +267,24 @@ fun writeByteCodeToReturn(methodDescriptor: String, writer: MethodVisitor) {
    }
}

/**
 * Write bytecode to pop the 2 uninitialized instances out of the stack
 * after performing constructor redirection.
 */
fun adjustStackForConstructorRedirection(writer: MethodVisitor) {
    // Stack: { uninitialized, uninitialized, obj }
    writer.visitInsn(Opcodes.SWAP)
    // Stack: { uninitialized, obj, uninitialized }
    writer.visitInsn(Opcodes.POP)
    // Stack: { uninitialized, obj }
    writer.visitInsn(Opcodes.SWAP)
    // Stack: { obj, uninitialized }
    writer.visitInsn(Opcodes.POP)
    // Stack: { obj }

    // We end up with only the desired object on the stack
}

/**
 * Given a method descriptor, insert an [argType] as the first argument to it.
 */
@@ -274,11 +292,20 @@ fun prependArgTypeToMethodDescriptor(methodDescriptor: String, classInternalName
    val returnType = Type.getReturnType(methodDescriptor)
    val argTypes = Type.getArgumentTypes(methodDescriptor).toMutableList()

    argTypes.add(0, Type.getType("L" + classInternalName + ";"))
    argTypes.add(0, Type.getType("L$classInternalName;"))

    return Type.getMethodDescriptor(returnType, *argTypes.toTypedArray())
}

/**
 * Given a method descriptor, change the return type to [classInternalName].
 */
fun changeMethodDescriptorReturnType(methodDescriptor: String, classInternalName: String): String {
    val argTypes = Type.getArgumentTypes(methodDescriptor)
    val returnType = Type.getType("L$classInternalName;")
    return Type.getMethodDescriptor(returnType, *argTypes)
}

/**
 * Return the "visibility" modifier from an `access` integer.
 *
+3 −4
Original line number Diff line number Diff line
@@ -100,7 +100,6 @@ interface PolicyFileProcessor {
        methodName: String,
        methodDesc: String,
        replaceSpec: TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec,
        policy: FilterPolicyWithReason,
    )
}

@@ -286,9 +285,10 @@ class TextFileFilterPolicyBuilder(
            methodName: String,
            methodDesc: String,
            replaceSpec: TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec,
            policy: FilterPolicyWithReason,
        ) {
            imf.setPolicyForMethod(className, methodName, methodDesc, policy)
            // Keep the source method, because the target method may call it.
            imf.setPolicyForMethod(className, methodName, methodDesc,
                FilterPolicy.Keep.withReason(FILTER_REASON))
            methodReplaceSpec.add(replaceSpec)
        }
    }
@@ -642,7 +642,6 @@ class TextFileFilterPolicyParser {
                    methodName,
                    signature,
                    spec,
                    policyWithReason,
                )
            } else {
                // It's an in-class replace.
+71 −30
Original line number Diff line number Diff line
@@ -17,7 +17,10 @@ package com.android.hoststubgen.visitors

import com.android.hoststubgen.asm.CLASS_INITIALIZER_DESC
import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME
import com.android.hoststubgen.asm.CTOR_NAME
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.adjustStackForConstructorRedirection
import com.android.hoststubgen.asm.changeMethodDescriptorReturnType
import com.android.hoststubgen.asm.prependArgTypeToMethodDescriptor
import com.android.hoststubgen.asm.writeByteCodeToPushArguments
import com.android.hoststubgen.asm.writeByteCodeToReturn
@@ -33,6 +36,7 @@ import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Opcodes.INVOKEINTERFACE
import org.objectweb.asm.Opcodes.INVOKESPECIAL
import org.objectweb.asm.Opcodes.INVOKESTATIC
import org.objectweb.asm.Opcodes.INVOKEVIRTUAL
import org.objectweb.asm.Type
@@ -376,43 +380,46 @@ class ImplGeneratingAdapter(
        val callerMethodName: String,
        next: MethodVisitor?,
    ) : MethodVisitor(OPCODE_VERSION, next) {
        override fun visitMethodInsn(

        private fun doReplace(
            opcode: Int,
            owner: String?,
            name: String?,
            descriptor: String?,
            isInterface: Boolean,
        ) {
            owner: String,
            name: String,
            descriptor: String,
        ): Boolean {
            when (opcode) {
                INVOKESTATIC, INVOKEVIRTUAL, INVOKEINTERFACE -> {}
                else -> {
                // We only support INVOKESPECIAL when replacing constructors.
                INVOKESPECIAL -> if (name != CTOR_NAME) return false
                // Don't touch other opcodes.
                    super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
                    return
                }
                else -> return false
            }

            val to = filter.getMethodCallReplaceTo(
                currentClassName, callerMethodName, owner!!, name!!, descriptor!!
                currentClassName, callerMethodName, owner, name, descriptor
            )

            if (to == null
                // Don't replace if the target is the callsite.
                || (to.className == currentClassName && to.methodName == callerMethodName)
            ) {
                super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
                return
                return false
            }

            // Replace the method call with a (static) call to the target method.
            // If it's a non-static call, the target method's first argument will receive "this".
            // (Because of that, we don't need to manipulate the stack. Just replace the
            // method call.)
            if (opcode != INVOKESPECIAL) {
                // It's either a static method call or virtual method call.
                // Either way, we don't manipulate the stack and send the original arguments
                // as is to the target method.
                //
                // If the call is a virtual call (INVOKEVIRTUAL or INVOKEINTERFACE), then
                // the first argument in the stack is the "this" object, so the target
                // method must have an extra argument as the first argument to receive it.
                // We update the method descriptor with prependArgTypeToMethodDescriptor()
                // to absorb this difference.

                val toDesc = if (opcode == INVOKESTATIC) {
                // Static call to static call, no need to change the desc.
                    descriptor
                } else {
                // Need to prepend the "this" type to the descriptor.
                    prependArgTypeToMethodDescriptor(descriptor, owner)
                }

@@ -423,6 +430,40 @@ class ImplGeneratingAdapter(
                    toDesc,
                    false
                )
            } else {
                // Because an object initializer does not return a value, the newly created
                // but uninitialized object will be dup-ed at the bottom of the stack.
                // We first call the target method to consume the constructor arguments at the top.

                val toDesc = changeMethodDescriptorReturnType(descriptor, owner)

                // Before stack: { uninitialized, uninitialized, args... }
                mv.visitMethodInsn(
                    INVOKESTATIC,
                    to.className,
                    to.methodName,
                    toDesc,
                    false
                )
                // After stack: { uninitialized, uninitialized, obj }

                // Next we pop the 2 uninitialized instances out of the stack.
                adjustStackForConstructorRedirection(mv)
            }

            return true
        }

        override fun visitMethodInsn(
            opcode: Int,
            owner: String,
            name: String,
            descriptor: String,
            isInterface: Boolean,
        ) {
            if (!doReplace(opcode, owner, name, descriptor)) {
                super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
            }
        }
    }
}
+74 −3
Original line number Diff line number Diff line
@@ -1883,6 +1883,42 @@ BootstrapMethods:
InnerClasses:
  public static #x= #x of #x;          // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas
  public static final #x= #x of #x;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester.class
  Compiled from "TinyFrameworkMethodCallReplace.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester
  minor version: 0
  major version: 65
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 1, methods: 1, attributes: 3
Constant pool:
{
  public int i;
    descriptor: I
    flags: (0x0001) ACC_PUBLIC

  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester(int);
    descriptor: (I)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         x: aload_0
         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
         x: aload_0
         x: iload_1
         x: putfield      #x                  // Field i:I
         x: return
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester;
            0      10     1     i   I
}
SourceFile: "TinyFrameworkMethodCallReplace.java"
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
InnerClasses:
  public static #x= #x of #x;           // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
  Compiled from "TinyFrameworkMethodCallReplace.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
@@ -1891,7 +1927,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 3, attributes: 3
  interfaces: 0, fields: 0, methods: 4, attributes: 3
Constant pool:
{
  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
@@ -1937,10 +1973,28 @@ Constant pool:
        Start  Length  Slot  Name   Signature
            0       4     0     a   I
            0       4     1     b   I

  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester newConstructorTester(int);
    descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester;
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=1, args_size=1
         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester
         x: dup
         x: iload_0
         x: iconst_1
         x: iadd
         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester."<init>":(I)V
        x: areturn
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      11     0     i   I
}
SourceFile: "TinyFrameworkMethodCallReplace.java"
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
InnerClasses:
  public static #x= #x of #x;          // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
  public static #x= #x of #x;          // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.class
  Compiled from "TinyFrameworkMethodCallReplace.java"
@@ -1950,7 +2004,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 5, attributes: 5
  interfaces: 0, fields: 0, methods: 6, attributes: 5
Constant pool:
{
  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
@@ -2008,6 +2062,21 @@ Constant pool:
         x: ireturn
      LineNumberTable:

  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester constructorReplaceTester(int);
    descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester;
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=1, args_size=1
         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester
         x: dup
         x: iload_0
         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester."<init>":(I)V
         x: areturn
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0     i   I

  private static int originalAdd(int, int);
    descriptor: (II)I
    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -2046,6 +2115,7 @@ RuntimeInvisibleAnnotations:
    android.hosttest.annotation.HostSideTestWholeClassKeep
NestMembers:
  com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
  com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester
BootstrapMethods:
  x: #x REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:
@@ -2053,6 +2123,7 @@ BootstrapMethods:
      #x REF_invokeStatic com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace.lambda$nonStaticMethodCallReplaceTester$0:(Ljava/util/concurrent/atomic/AtomicBoolean;)V
      #x ()V
InnerClasses:
  public static #x= #x of #x;          // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
  public static #x= #x of #x;          // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
  public static final #x= #x of #x;   // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+113 −3
Original line number Diff line number Diff line
@@ -2002,6 +2002,51 @@ BootstrapMethods:
      #x ()Ljava/lang/Integer;
NestMembers:
  com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester.class
  Compiled from "TinyFrameworkMethodCallReplace.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester
  minor version: 0
  major version: 65
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 1, methods: 1, attributes: 4
Constant pool:
{
  public int i;
    descriptor: I
    flags: (0x0001) ACC_PUBLIC
    RuntimeVisibleAnnotations:
      x: #x()
        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep

  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester(int);
    descriptor: (I)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         x: aload_0
         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
         x: aload_0
         x: iload_1
         x: putfield      #x                 // Field i:I
         x: return
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester;
            0      10     1     i   I
    RuntimeVisibleAnnotations:
      x: #x()
        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
}
InnerClasses:
  public static #x= #x of #x;             // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
SourceFile: "TinyFrameworkMethodCallReplace.java"
RuntimeVisibleAnnotations:
  x: #x()
    com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.class
  Compiled from "TinyFrameworkMethodCallReplace.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo
@@ -2010,7 +2055,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 3, attributes: 4
  interfaces: 0, fields: 0, methods: 4, attributes: 4
Constant pool:
{
  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ReplaceTo();
@@ -2065,8 +2110,29 @@ Constant pool:
    RuntimeVisibleAnnotations:
      x: #x()
        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep

  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester newConstructorTester(int);
    descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester;
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=1, args_size=1
         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester
         x: dup
         x: iload_0
         x: iconst_1
         x: iadd
         x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester."<init>":(I)V
        x: areturn
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      11     0     i   I
    RuntimeVisibleAnnotations:
      x: #x()
        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
}
InnerClasses:
  public static #x= #x of #x;           // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
  public static #x= #x of #x;            // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
SourceFile: "TinyFrameworkMethodCallReplace.java"
RuntimeVisibleAnnotations:
@@ -2081,7 +2147,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 4, attributes: 6
  interfaces: 0, fields: 0, methods: 6, attributes: 6
Constant pool:
{
  public com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace();
@@ -2148,6 +2214,48 @@ Constant pool:
      x: #x()
        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep

  public static com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallReplace$ConstructorTester constructorReplaceTester(int);
    descriptor: (I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester;
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=1, args_size=1
         x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester
         x: dup
         x: iload_0
         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo.newConstructorTester:(I)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester;
         x: swap
         x: pop
        x: swap
        x: pop
        x: areturn
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0     i   I
    RuntimeVisibleAnnotations:
      x: #x()
        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep

  private static int originalAdd(int, int);
    descriptor: (II)I
    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=2
         x: iload_0
         x: iload_1
         x: iadd
         x: iconst_1
         x: isub
         x: ireturn
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0     a   I
            0       6     1     b   I
    RuntimeVisibleAnnotations:
      x: #x()
        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep

  private static void lambda$nonStaticMethodCallReplaceTester$0(java.util.concurrent.atomic.AtomicBoolean);
    descriptor: (Ljava/util/concurrent/atomic/AtomicBoolean;)V
    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
@@ -2167,6 +2275,7 @@ Constant pool:
        com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
}
InnerClasses:
  public static #x= #x of #x;           // ConstructorTester=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
  public static #x= #x of #x;            // ReplaceTo=class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo of class com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace
  public static final #x= #x of #x;    // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
SourceFile: "TinyFrameworkMethodCallReplace.java"
@@ -2184,6 +2293,7 @@ BootstrapMethods:
      #x ()V
NestMembers:
  com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo
  com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ConstructorTester
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
  Compiled from "TinyFrameworkNative.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
Loading