learn and grow up

openjdk源码浅析之jni_registerNatives

字数统计: 1.3k阅读时长: 5 min
2020/08/30 Share

写在前面

​ 既然成功编译和搭建了openjdk的源码及调试环境,则更要继续深入探究openjdk的内部。

​ 这篇文章是基于了解了c、c++的基础语法和概念。

​ 这篇主要浅析在平时jdk源码中比较显眼的一个东西:registerNatives

正文

registerNatives在有native方法的jdk基础类里,十分常见,比如:Object,System等等。

​ 常用的写法如下:

1
2
3
4
private static native void registerNatives();
static {
registerNatives();
}

​ 字面意思及过往经验告诉我们这个是用来注册本地方法的,但我们知道里面的具体逻辑吗?这就可以从openjdk源码里找到答案~

​ 这里拿System举例,按照jdk的规范,对应本地源码在:System.*里,我们直接在源码里搜索就可以找到。

system.c

​ 在看源码之前,应该先了解jni默认的函数名规则如下:JNI函数名原型:Java_ + JNI方法所在的完整的类名,把类名里面的”.”替换成”_” + 真实的JNI方法名,这个方法名要和Java代码里面声明的JNI方法名一样。

​ 但是也可以自定义函数名称,这个就是依靠registerNatives进行实现~

​ 截取registerNatives源码相关代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
------------前置代码-------
/*
* used in RegisterNatives to describe native method name, signature,
* and function pointer.
*/
//jni.h中,JNINativeMethod类型的
typedef struct {
char *name;
//方法签名
char *signature;
//方法地址指针
void *fnPtr;
} JNINativeMethod;


///////
//JNIEnv_
struct JNIEnv_;

#ifdef __cplusplus
//如果是c++。则定义JNIEnv=JNIEnv_类
typedef JNIEnv_ JNIEnv;
#else
//c的话:*JNIEnv=JNINativeInterface_类
typedef const struct JNINativeInterface_ *JNIEnv;
#endif

-------------正式代码开始------------
//声明OBJ代表Object类型签名表示
#define OBJ "Ljava/lang/Object;"

//这里声明了主要的、已有的jvm方法,
/* Only register the performance-critical methods */
//
static JNINativeMethod methods[] = {
//currentTimeMillis ,根据字节码中相关对应关系,J对应long,
//综合起来来看:也就是返回值为long currentTimeMillis()对应的是JVM_CurrentTimeMillis方法
{"currentTimeMillis", "()J", (void *)&JVM_CurrentTimeMillis},
{"nanoTime", "()J", (void *)&JVM_NanoTime},
{"arraycopy", "(" OBJ "I" OBJ "II)V", (void *)&JVM_ArrayCopy},
};

#undef OBJ

//JNIEXPORT。这个关键字表明这个函数是一个可导出函数。每一个C/C++库都有一个导出函数列表,只有在这个列表里面的函数才可以被外部直接调用,类似Java的public函数和private函数的区别
//JNICALL。说明这个函数是一个JNI函数,用来和普通的C/C++函数进行区别。
//registerNatives所绑定的方法为:
JNIEXPORT void JNICALL
//*env ,是一个执行JNIENV函数表的指针,在c++代表指向JNIEnv_的指针,env就代表JNIEnv 本身,所以可以直接env->function 调用,
//这里是c,*env代表JNINativeInterface_,所以需要(*env)-> function 这样调用
//jclass 指的就是java的class
Java_java_lang_System_registerNatives(JNIEnv *env, jclass cls)
{
//调用JNINativeInterface_ 或 JNIEnv的RegisterNatives
(*env)->RegisterNatives(env, cls,
methods, sizeof(methods)/sizeof(methods[0]));
}

//这里就是向jvm注册了一个native方法

-----------------其他代码补充----------
//jni.h
struct JNINativeInterface_ {
.....
//RegisterNatives 指向JNICALL注册函数,返回int
jint (JNICALL *RegisterNatives)
(JNIEnv *env, jclass clazz, const JNINativeMethod *methods,
jint nMethods);
......
}


struct JNIEnv_ {
const struct JNINativeInterface_ *functions;
.......
#ifdef __cplusplus

jint RegisterNatives(jclass clazz, const JNINativeMethod *methods,
jint nMethods) {
//调用JNINativeInterface_的RegisterNatives方法
return functions->RegisterNatives(this,clazz,methods,nMethods);
}
.......
#endif
}


//上面是RegisterNatives方法的函数定义,真正的代码实现如下:
//jni.cpp
//// Structure containing all jni functions
....
#include "runtime/interfaceSupport.inline.hpp"
.....
struct JNINativeInterface_ jni_NativeInterface = {
....
jni_RegisterNatives,
......
}


//JNI_ENTRY就是在interfaceSupport.inline.hpp中定义的宏,预编译后可以理解为函数声明和功能编写

JNI_ENTRY(jint, jni_RegisterNatives(JNIEnv *env, jclass clazz,
const JNINativeMethod *methods,
jint nMethods))
//env, jvm evn
// clazz jclass
//methods 就是我们自定义的那些本地方法对应关系表
// 注册方法个数
//注册开始,
//基础校验和宏编译
JNIWrapper("RegisterNatives");
HOTSPOT_JNI_REGISTERNATIVES_ENTRY(env, clazz, (void *) methods, nMethods);
jint ret = 0;
DT_RETURN_MARK(RegisterNatives, jint, (const jint&)ret);

//生成Klass
Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz));

for (int index = 0; index < nMethods; index++) {
//循环
const char* meth_name = methods[index].name;
const char* meth_sig = methods[index].signature;
int meth_name_len = (int)strlen(meth_name);

// The class should have been loaded (we have an instance of the class
// passed in) so the method and signature should already be in the symbol
// table. If they're not there, the method doesn't exist.
//解析method
TempNewSymbol name = SymbolTable::probe(meth_name, meth_name_len);
TempNewSymbol signature = SymbolTable::probe(meth_sig, (int)strlen(meth_sig));

if (name == NULL || signature == NULL) {
//异常处理
ResourceMark rm;
stringStream st;
st.print("Method %s.%s%s not found", k->external_name(), meth_name, meth_sig);
// Must return negative value on failure
THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), -1);
}

//开始注册2
bool res = Method::register_native(k, name, signature,
(address) methods[index].fnPtr, THREAD);
if (!res) {
ret = -1;
break;
}
}
return ret;
JNI_END



//method.cpp
........

bool Method::register_native(Klass* k, Symbol* name, Symbol* signature, address entry, TRAPS) {
//根据方法签名找到class对应的方法
Method* method = k->lookup_method(name, signature);
if (method == NULL) {
//异常处理
ResourceMark rm(THREAD);
stringStream st;
st.print("Method '");
print_external_name(&st, k, name, signature);
st.print("' name or signature does not match");
THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false);
}
if (!method->is_native()) {
//英文已有解释
// trying to register to a non-native method, see if a JVM TI agent has added prefix(es)
method = find_prefixed_native(k, name, signature, THREAD);
if (method == NULL) {
ResourceMark rm(THREAD);
stringStream st;
st.print("Method '");
print_external_name(&st, k, name, signature);
st.print("' is not declared as native");
THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false);
}
}

if (entry != NULL) {
//绑定3
method->set_native_function(entry, native_bind_event_is_interesting);
} else {
//clear
method->clear_native_function();
}
if (log_is_enabled(Debug, jni, resolve)) {
ResourceMark rm(THREAD);
log_debug(jni, resolve)("[Registering JNI native method %s.%s]",
method->method_holder()->external_name(),
method->name()->as_C_string());
}
return true;
}

未完待续… …

CATALOG
  1. 1. 写在前面
  2. 2. 正文