当前位置: 首页 > article >正文

修改openjdk17源码,手搓native方法调用java method方法(无参,无返回值)

修改openjdk17源码,jvm.cpp新增一个native方法,传入对象和要被调用的方法(无参,无返回值)

 主要功能是通过 JNI 接口和 HotSpot VM 的内部 API,从 Java 层获取方法的元数据,然后在 C++ 层调用该 Java 方法。它涉及到对象的转换、方法的查找、参数的准备以及方法的实际调用。

JVM_ENTRY(void, JVM_invokeJavaMethod(JNIEnv *env, jobject obj1, jobject obj2, jobject obj3))
  • JVM_ENTRY 宏:用于定义一个 JNI 函数入口点。void 表示该函数不返回任何值。
  • 参数
    • JNIEnv *env:JNI 环境指针,用于调用 JNI 函数。
    • jobject obj1:第一个 Java 对象参数。
    • jobject obj2:第二个 Java 对象参数。
    • jobject obj3:第三个 Java 对象参数。

代码主体

  1. 解析 JNI 对象

    • oop oopObj1 = JNIHandles::resolve_non_null(obj1);
      • 将 jobject 类型的 obj1 转换为 oop 类型的 oopObj1JNIHandles::resolve_non_null 是一个 JNI 函数,用于将 JNI 对象句柄转换为 HotSpot VM 的内部对象表示(oop)。
    • oop oopObj2 = JNIHandles::resolve_non_null(obj2);
      • 将 jobject 类型的 obj2 转换为 oop 类型的 oopObj2
    • oop oopObj3 = JNIHandles::resolve_non_null(obj3);
      • 将 jobject 类型的 obj3 转换为 oop 类型的 oopObj3
  2. 创建 Handle 对象

    • Handle receiver(THREAD, oopObj2);
      • 创建一个 Handle 对象 receiver,封装 oopObj2Handle 是 HotSpot VM 中用于管理对象引用的类,确保对象在多线程环境中安全地被访问。
    • Handle method_mirror(THREAD, oopObj3);
      • 创建一个 Handle 对象 method_mirror,封装 oopObj3
  3. 获取方法信息

    • int slot = java_lang_reflect_Method::slot(method_mirror());
      • 从 method_mirror 中获取方法的槽位(slot)。方法槽位是一个整数,表示方法在类的虚方法表中的位置。
    • oop mirror = java_lang_reflect_Method::clazz(method_mirror());
      • 从 method_mirror 中获取方法所属的类的 oop 表示。
  4. 获取类和方法

    • InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(mirror));
      • 将 mirror 转换为 InstanceKlass* 类型的 klassInstanceKlass 是 HotSpot VM 中表示 Java 类的内部类。
    • Method* m = klass->method_with_idnum(slot);
      • 从 klass 中获取与 slot 对应的 Method* 对象 mMethod* 是 HotSpot VM 中表示 Java 方法的内部类。
    • methodHandle method(THREAD, m);
      • 创建一个 methodHandle 对象 method,封装 mmethodHandle 是 HotSpot VM 中用于管理方法引用的类。
  5. 打印调试信息

    • std::cout << "@@@@yym%%%%custom " << "obj1:" << oopObj1 << " mirror:" << mirror << "----custom" << std::endl;
      • 打印调试信息,输出 oopObj1 和 mirror 的地址。
  6. 准备调用参数

    • JavaCallArguments java_args(method->size_of_parameters());
      • 创建一个 JavaCallArguments 对象 java_args,用于存储调用方法时的参数。method->size_of_parameters() 返回方法参数的数量。
    • java_args.push_oop(receiver);
      • 将 receiver 添加到 java_args 中,作为方法调用的第一个参数(通常是 this 指针)。
  7. 调用 Java 方法

    • JavaValue result(T_VOID);
      • 创建一个 JavaValue 对象 result,用于存储方法调用的结果。T_VOID 表示方法没有返回值。
    • JavaCalls::call(&result, method, &java_args, CHECK);
      • 调用 JavaCalls::call 函数,执行方法调用。&result 是结果的存储位置,method 是要调用的方法,&java_args 是方法的参数列表,CHECK 是一个宏,用于处理可能的异常。

##源码

##src/java.base/share/classes/java/lang/MyPrintStringInfo.java文件

/**
     * invokeJavaMethod
     * @param   obj invokeJavaMethod
     * @param   method method
     **/
    public native void invokeJavaMethod(Object obj, Object method);

##src/hotspot/share/include/jvm.h文件

//yym-gaizao
JNIEXPORT void JNICALL
JVM_invokeJavaMethod(JNIEnv *env, jobject obj1, jobject obj2, jobject obj3);

##src/hotspot/share/prims/jvm.cpp

//yym-gaizao
JVM_ENTRY(void, JVM_invokeJavaMethod(JNIEnv *env, jobject obj1, jobject obj2, jobject obj3))//
  oop oopObj1 = JNIHandles::resolve_non_null(obj1);
  oop oopObj2 = JNIHandles::resolve_non_null(obj2);
  oop oopObj3 = JNIHandles::resolve_non_null(obj3);
  // Handle mh = (Handle)oopObj2;
  Handle receiver(THREAD, oopObj2);
  Handle method_mirror(THREAD, oopObj3);
  int slot               = java_lang_reflect_Method::slot(method_mirror());
  oop mirror             = java_lang_reflect_Method::clazz(method_mirror());
  InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(mirror));
  Method* m = klass->method_with_idnum(slot);
  methodHandle method(THREAD, m);
  std::cout << "@@@@yym%%%%custom " << "obj1:" << oopObj1 << " mirror:" << mirror << "----custom" << std::endl;
  JavaCallArguments java_args(method->size_of_parameters());
  java_args.push_oop(receiver);
  // JavaCallArguments args; // No arguments
  JavaValue result(T_VOID);
  JavaCalls::call(&result, method, &java_args, CHECK); // Static call (no args)
JVM_END

##make/data/hotspot-symbols/symbols-unix

# yym-gaizao
JVM_invokeJavaMethod

##/home/yym/openjdk17/jdk17-master/build/linux-x86_64-server-slowdebug/support/headers/java.base/java_lang_MyPrintStringInfo.h

/*
 * Class:     java_lang_MyPrintStringInfo
 * Method:    invokeJavaMethod
 * Signature: (Ljava/lang/Object;Ljava/lang/Object;)V
 */
JNIEXPORT void JNICALL Java_java_lang_MyPrintStringInfo_invokeJavaMethod
  (JNIEnv *, jobject, jobject, jobject);

##/home/yym/openjdk17/jdk17-master/src/java.base/share/native/libjava/MyPrintStringInfo.c

JNIEXPORT void JNICALL Java_java_lang_MyPrintStringInfo_invokeJavaMethod
  (JNIEnv *env, jobject obj1, jobject obj2, jobject obj3)
{
    return JVM_invokeJavaMethod(env, obj1, obj2, obj3);
}  

##测试代码

public class MiBigObject {
    public static int CONSTANT_TYPE = 1234567890;
    public void printlnTest() {
        System.out.println("printlnTest");
    }
}


import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class OutOfMemoryTest {

    public static void main(String[] args) throws Exception {
        List<MiBigObject> miBigObjects = new ArrayList<>(260000);
        System.out.println(miBigObjects);
        MyPrintStringInfo myPrintStringInfo = new MyPrintStringInfo();
        //myPrintStringInfo.printStringTable();
        int yym = MiBigObject.CONSTANT_TYPE;
        //myPrintStringInfo.mirrorClassOOPKlassEq(MiBigObject.class);
        MiBigObject miBigObject = (MiBigObject)myPrintStringInfo.newJavaObject(MiBigObject.class);
        try {
            Method method = MiBigObject.class.getDeclaredMethod("printlnTest");
            myPrintStringInfo.invokeJavaMethod(miBigObject,method);
        }catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(miBigObject);
        System.in.read();
    }

}


http://www.kler.cn/a/469556.html

相关文章:

  • Functions
  • ollama安装及本地部署开源大模型
  • 面试高频:一致性hash算法
  • 25上软考中级【嵌入式系统设计师】易混淆知识点
  • 苹果系统MacOS下ObjectC建立的App程序访问opencv加载图片程序
  • Timer、Ticker使用及其注意事项
  • 蓝耘:GPU算力云服务的技术探索与AIGC应用支持
  • 连接github和ai的桥梁:GitIngest
  • 后台管理系统动态面包屑Breadcrumb组件的实现
  • Python视频处理:噪声矩阵与并行计算的完美融合
  • Couchbase 和数据湖技术的区别、联系和相关性分析
  • Uniapp Android 本地离线打包(详细流程)
  • HCIA-Access V2.5_7_5_XG(S)- GPON网络演进为XG(S)-PON网络
  • Golang 入门基础知识
  • flink-connector-kafka 3.4源码编译
  • 贵州省贵安新区地图+全域数据arcgis格式shp数据矢量路网地名+卫星影像底图下载后内容测评
  • 用公网服务代理到本地电脑笔记
  • Go语言的 的同步与异步编程(Synchronization Asynchronous Programming)核心知识
  • 【JVM】总结篇之垃圾回收★
  • 温度传感器不准的原因与LabVIEW校准方法
  • 【Redis经典面试题七】Redis的事务机制是怎样的?
  • CISA 列入高风险漏洞 CVE-2024-12356 至已被利用漏洞名单
  • 简述Linux的信号处理
  • 深入Android架构(从线程到AIDL)_11 线程之间的通信架构
  • 代码随想录 day62 第十一章 图论part11
  • windows C#-字符串和字符串字面量(三)