惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
爱范儿
爱范儿
WordPress大学
WordPress大学
博客园 - 三生石上(FineUI控件)
J
Java Code Geeks
Vercel News
Vercel News
aimingoo的专栏
aimingoo的专栏
T
Tailwind CSS Blog
罗磊的独立博客
B
Blog
博客园_首页
A
About on SuperTechFans
有赞技术团队
有赞技术团队
V
V2EX
U
Unit 42
I
InfoQ
IT之家
IT之家
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
博客园 - 叶小钗
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Stack Overflow Blog
Stack Overflow Blog
The Cloudflare Blog
H
Help Net Security

博客园 - 方东信

【far 语言】语言文档目录 【far 语言】注解系统 【far 语言】数组 【far 语言】并发编程(协程) 【far 语言】控制流 【far 语言】异常处理 【far 语言】farcc 构建工具 【far 语言】函数 【far 语言】组合与继承 【far 语言】接口与泛型 【far 语言】List 列表 【far 语言】Map 映射 【far 语言】原生内存与 FFI 【far 语言】字符串 【far 语言】语法总览 【far 语言】类型系统 Java 远程调用类,控制类的办法,老了,记不住了。靠 java opc ua 基于s7 音视频:JavaCV 采集桌面画面并显示的方法 pand3d实现服务端渲染并推流 UI弹窗遮罩屏蔽触发事件的处理 far的数据类型 Windows下Tesseract-OCR的安装与使用 LoRA配置 大模型三阶段训练方法(LLaMa Factory) windows系统下anaconda的安装和使用 trl ppo 【手把手从零实现】Qwen2.5-VL:环境配置/功能实验(图片识别理解、目标检测、文字OCR、文档解析、视频理解)/模型微调(MS-Swift 和 LLaMA-Factory) seata 1.8.0 报错大全 Springboot 报错 java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking
Asm生成动态调用指令
方东信 · 2025-04-06 · via 博客园 - 方东信
import org.objectweb.asm.*;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.invoke.*;

// 假设的用户类
class UserClass {
    public String test(int param) {
        System.out.println("Test method is called with param: " + param);
        return "Result from test method";
    }
}

public class InvokeTestWithParamsAndReturnGenerator {
    public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type, String descIdent, Object objVal) throws Throwable {
        Class<?> clazz = Class.forName(descIdent);
        // 根据实际的参数和返回值类型构建 MethodType
        MethodType methodType = MethodType.methodType(String.class, int.class);
        MethodHandle mh = lookup.findVirtual(clazz, name, methodType);
        return new ConstantCallSite(mh.bindTo(objVal));
    }

    public static void main(String[] args) throws IOException {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
        cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "InvokeTestWithParamsAndReturn", null, "java/lang/Object", null);

        // 生成 main 方法
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
        mv.visitCode();

        // 创建 FObj 实例并存储 UserClass 实例
        mv.visitTypeInsn(Opcodes.NEW, "com/faros/lib/typeobj/FObj");
        mv.visitInsn(Opcodes.DUP);
        // 创建 UserClass 实例
        mv.visitTypeInsn(Opcodes.NEW, "UserClass");
        mv.visitInsn(Opcodes.DUP);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "UserClass", "<init>", "()V", false);
        // 调用 FObj 的 fUObj 静态方法创建 FObj 实例
        mv.visitLdcInsn("UserClass");
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/faros/lib/typeobj/FObj", "fUObj", "(Ljava/lang/Object;Ljava/lang/String;)Lcom/faros/lib/typeobj/FObj;", false);

        // 现在栈顶是 FObj 实例,通过 invokedynamic 调用其存储对象的 test 方法
        // 获取 FObj 中的 objVal
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitFieldInsn(Opcodes.GETFIELD, "com/faros/lib/typeobj/FObj", "objVal", "Ljava/lang/Object;");
        // 获取 FObj 中的 descIdent
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitFieldInsn(Opcodes.GETFIELD, "com/faros/lib/typeobj/FObj", "descIdent", "Ljava/lang/String;");

        // 准备 test 方法的参数
        mv.visitLdcInsn(10); // 假设参数为 10

        Handle bootstrapMethod = new Handle(
                Opcodes.H_INVOKESTATIC,
                "InvokeTestWithParamsAndReturnGenerator",
                "bootstrap",
                "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/invoke/CallSite;",
                false
        );

        // 指定 invokedynamic 指令的方法类型,与 test 方法的参数和返回值匹配
        mv.visitInvokeDynamicInsn(
                "test",
                "(Ljava/lang/Object;Ljava/lang/String;I)Ljava/lang/String;",
                bootstrapMethod,
                "descIdent",
                "objVal"
        );

        // 处理返回值,这里简单打印
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "toString", "()Ljava/lang/String;", false);
        mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
        mv.visitInsn(Opcodes.SWAP);
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();

        cw.visitEnd();

        // 输出字节码到文件
        try (FileOutputStream fos = new FileOutputStream("InvokeTestWithParamsAndReturn.class")) {
            fos.write(cw.toByteArray());
        }
    }
}

详细解释

  • mv.visitInvokeDynamicInsn(
    mv 是 MethodVisitor 的实例,visitInvokeDynamicInsn 是 MethodVisitor 类中的方法,用于在生成的字节码中插入 invokedynamic 指令。该指令的作用是在运行时动态解析要调用的方法。
  • "test"
    这是调用点(call site)的名称,通常与要调用的方法名一致。在这个例子中,我们要调用 UserClass 类的 test 方法,所以这里写 "test"。这个名称主要用于引导方法(bootstrap method)内部逻辑,帮助引导方法识别要调用的目标方法。
  • Ljava/lang/Object;Ljava/lang/String;I)Ljava/lang/String;
    这是 invokedynamic 指令的方法类型(method type)描述符。它定义了调用点的参数类型和返回值类型,遵循 Java 字节码的方法描述符规则:
    (Ljava/lang/Object;Ljava/lang/String;I) 表示参数列表,依次为一个 Object 类型、一个 String 类型和一个 int 类型(I 是 int 的字节码表示)。这里的 Object 对应 FObj 中的 objVal,String 对应 descIdent,int 是 test 方法的参数。
    Ljava/lang/String; 表示返回值类型,即 test 方法返回一个 String 类型的值。
  • bootstrapMethod
    bootstrapMethod 是一个 Handle 对象,它指向引导方法。引导方法是一个静态方法,负责在运行时动态地确定要调用的方法,并返回一个 CallSite 对象。CallSite 对象封装了目标方法的调用逻辑。在这个例子中,引导方法是 InvokeTestWithParamsAndReturnGenerator 类中的 bootstrap 方法。
  • "descIdent" 和 "objVal"
    这两个是动态参数(dynamic arguments),它们会被传递给引导方法。引导方法可以根据这些参数在运行时动态地确定要调用的方法。在这个例子中,"descIdent" 是 FObj 中存储的类的限定符,"objVal" 是 FObj 中存储的实际对象实例。引导方法会根据 descIdent 找到对应的类,然后使用 objVal 作为调用 test 方法的对象。
    总结
    这行代码的作用是在生成的字节码中插入一个 invokedynamic 指令,该指令在运行时会触发引导方法,引导方法根据传入的动态参数动态地确定要调用的 test 方法,并返回一个 CallSite 对象,最终实现对 test 方法的动态调用。

Rust编程语言群 1036955113
java新手自学群 626070845
java/springboot/hadoop/JVM 群 4915800
Hadoop/mongodb(搭建/开发/运维)Q群481975850
GOLang Q1群:6848027
GOLang Q2群:450509103
GOLang Q3群:436173132
GOLang Q4群:141984758
GOLang Q5群:215535604
C/C++/QT群 1414577
单片机嵌入式/电子电路入门群群 306312845
MUD/LIB/交流群 391486684
Electron/koa/Nodejs/express 214737701
大前端群vue/js/ts 165150391
操作系统研发群:15375777
汇编/辅助/破解新手群:755783453
大数据 elasticsearch 群 481975850
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。