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

Commit fd8fcf89 authored by John Wu's avatar John Wu
Browse files

[HostStubGen] Support replacing constructor calls to methods

There are some cases where we need to modify constructors of classes
in the JDK. Update the existing method call replacement mechanism to
support also support constructors.

Test: atest hoststubgen-test-tiny-test
Bug: 397498134
Flag: EXEMPT host side change only
Change-Id: I9a0c1f8a503a42d28202101ed12d1b9c74e27f39
parent c815a25e
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