Skip to content

Commit 4ad4929

Browse files
committed
Merge branch 'topic/647' into 'master'
Java API: cache global references to classes/fields/methods. Closes AdaCore#647 See merge request eng/libadalang/langkit!831
2 parents 1b6327c + e97ecb7 commit 4ad4929

File tree

7 files changed

+891
-683
lines changed

7 files changed

+891
-683
lines changed

langkit/java_api.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,17 @@ def __init__(self,
257257

258258
# ----- Util methods -----
259259

260+
def should_emit_struct(self, struct_type: ct.StructType) -> bool:
261+
"""
262+
Whether this struct type should be emitted in the Java bindings.
263+
"""
264+
if struct_type.is_entity_type:
265+
return struct_type == T.root_node.entity
266+
else:
267+
return (struct_type is T.entity_info
268+
or struct_type is T.env_md
269+
or struct_type.exposed)
270+
260271
def get_struct_fields(self, struct: ct.StructType) -> list[StructField]:
261272
"""
262273
Get the structure fields as a list.
@@ -1016,6 +1027,8 @@ def jni_sig_type(self, the_type: CompiledType, base_class: str) -> str:
10161027
return dispatch_on_type(the_type, [
10171028
(T.Bool, lambda _: "Z"),
10181029
(T.Int, lambda _: "I"),
1030+
(T.BigInt, lambda _: "Ljava/math/BigInteger;"),
1031+
(T.String, lambda _: "Ljava/lang/String;"),
10191032
(
10201033
ct.ASTNodeType, lambda t:
10211034
f"L{base_class}$PointerWrapper;"

langkit/templates/java_api/array.mako

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,43 @@ ${c_type} ${java_type}_unwrap(
297297
""
298298
)});
299299
void ${java_type}_release(${c_type});
300+
301+
jclass ${java_type}_class_ref = NULL;
302+
jmethodID ${java_type}_create_method_id = NULL;
303+
jmethodID ${java_type}_content_method_id = NULL;
304+
</%def>
305+
306+
<%def name="jni_init_global_refs(cls)">
307+
<%
308+
api = java_api
309+
310+
java_type = api.wrapping_type(cls, False)
311+
312+
sig_base = f"com/adacore/{ctx.lib_name.lower}/{ctx.lib_name.camel}"
313+
sig = f"L{sig_base}${java_type};"
314+
315+
elem_java_type = api.wrapping_type(cls.element_type, False)
316+
elem_sig = f"L{sig_base}${elem_java_type};"
317+
%>
318+
319+
${java_type}_class_ref = (jclass) (*env)->NewGlobalRef(
320+
env,
321+
(*env)->FindClass(env, "${sig}")
322+
);
323+
324+
${java_type}_create_method_id = (*env)->GetStaticMethodID(
325+
env,
326+
${java_type}_class_ref,
327+
"jniCreate",
328+
"([${elem_sig})${sig}"
329+
);
330+
331+
${java_type}_content_method_id = (*env)->GetMethodID(
332+
env,
333+
${java_type}_class_ref,
334+
"jniContent",
335+
"()[${elem_sig}"
336+
);
300337
</%def>
301338

302339
<%def name="jni_c_impl(cls)">
@@ -329,14 +366,10 @@ jobject ${java_type}_wrap(
329366
int array_size = array_native->n;
330367
331368
// Create a new Java array of object of the element type
332-
jclass element_clazz = (*env)->FindClass(
333-
env,
334-
"${elem_sig}"
335-
);
336369
jobjectArray array_content = (*env)->NewObjectArray(
337370
env,
338371
(jsize) array_size,
339-
element_clazz,
372+
${elem_java_type}_class_ref,
340373
NULL
341374
);
342375
@@ -351,25 +384,11 @@ jobject ${java_type}_wrap(
351384
);
352385
}
353386
354-
// Get the array class
355-
jclass clazz = (*env)->FindClass(
356-
env,
357-
"${sig}"
358-
);
359-
360-
// Get the constructor
361-
jmethodID constructor = (*env)->GetStaticMethodID(
362-
env,
363-
clazz,
364-
"jniCreate",
365-
"([${elem_sig})${sig}"
366-
);
367-
368387
// Return the new array
369388
return (*env)->CallStaticObjectMethod(
370389
env,
371-
clazz,
372-
constructor,
390+
${java_type}_class_ref,
391+
${java_type}_create_method_id,
373392
array_content
374393
);
375394
}
@@ -390,20 +409,11 @@ ${c_type} ${java_type}_unwrap(
390409
AnalysisContext_unwrap(env, context);
391410
% endif
392411
393-
// Get the Java array class
394-
jclass clazz = (*env)->GetObjectClass(env, array);
395-
396-
// Get the method to get the content of the array
397-
jmethodID get_jni_content_method = (*env)->GetMethodID(
398-
env,
399-
clazz,
400-
"jniContent",
401-
"()[${elem_sig}"
402-
);
412+
// Retrieve the array's content
403413
jobjectArray content = (jobjectArray) (*env)->CallObjectMethod(
404414
env,
405415
array,
406-
get_jni_content_method
416+
${java_type}_content_method_id
407417
);
408418
409419
// Get the content size

langkit/templates/java_api/enum.mako

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,44 @@
8686
${c_type} ${java_type}_new_value();
8787
jobject ${java_type}_wrap(JNIEnv *, ${c_type});
8888
${c_type} ${java_type}_unwrap(JNIEnv *, jobject);
89+
90+
jclass ${java_type}_class_ref = NULL;
91+
jmethodID ${java_type}_from_c_method_id = NULL;
92+
jmethodID ${java_type}_to_c_method_id = NULL;
8993
</%def>
9094

91-
<%def name="jni_c_impl(cls)">
95+
<%def name="jni_init_global_refs(cls)">
9296
<%
9397
api = java_api
9498
99+
java_type = api.wrapping_type(cls, False)
100+
95101
sig_base = f"com/adacore/{ctx.lib_name.lower}/{ctx.lib_name.camel}"
102+
%>
103+
104+
${java_type}_class_ref = (jclass) (*env)->NewGlobalRef(
105+
env,
106+
(*env)->FindClass(env, "${sig_base}$${java_type}")
107+
);
108+
109+
${java_type}_from_c_method_id = (*env)->GetStaticMethodID(
110+
env,
111+
${java_type}_class_ref,
112+
"fromC",
113+
"(I)L${sig_base}$${java_type};"
114+
);
115+
116+
${java_type}_to_c_method_id = (*env)->GetMethodID(
117+
env,
118+
${java_type}_class_ref,
119+
"toC",
120+
"()I"
121+
);
122+
</%def>
123+
124+
<%def name="jni_c_impl(cls)">
125+
<%
126+
api = java_api
96127
97128
java_type = api.wrapping_type(cls)
98129
c_type = cls.c_type(capi).name
@@ -108,22 +139,11 @@ jobject ${java_type}_wrap(
108139
JNIEnv *env,
109140
${c_type} enum_value_native
110141
) {
111-
// Get the enum class
112-
jclass clazz = (*env)->FindClass(env, "${sig_base}$${java_type}");
113-
114-
// Get the constructing static method
115-
jmethodID from_c_method = (*env)->GetStaticMethodID(
116-
env,
117-
clazz,
118-
"fromC",
119-
"(I)L${sig_base}$${java_type};"
120-
);
121-
122142
// Call the static method
123143
return (*env)->CallStaticObjectMethod(
124144
env,
125-
clazz,
126-
from_c_method,
145+
${java_type}_class_ref,
146+
${java_type}_from_c_method_id,
127147
(jint) enum_value_native
128148
);
129149
}
@@ -133,22 +153,11 @@ ${c_type} ${java_type}_unwrap(
133153
JNIEnv *env,
134154
jobject enum_value
135155
) {
136-
// Get the object class
137-
jclass clazz = (*env)->GetObjectClass(env, enum_value);
138-
139-
// Get the method
140-
jmethodID to_c_method = (*env)->GetMethodID(
141-
env,
142-
clazz,
143-
"toC",
144-
"()I"
145-
);
146-
147156
// Call the Java method
148157
return (${c_type}) (*env)->CallIntMethod(
149158
env,
150159
enum_value,
151-
to_c_method
160+
${java_type}_to_c_method_id
152161
);
153162
}
154163
</%def>

langkit/templates/java_api/iterator.mako

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,48 @@
8989
${c_name} ${j_name}_new_value();
9090
jobject ${j_name}_wrap(JNIEnv *, ${c_name});
9191
${c_name} ${j_name}_unwrap(JNIEnv *, jobject);
92+
93+
jclass ${j_name}_class_ref = NULL;
94+
jmethodID ${j_name}_constructor_id = NULL;
95+
jfieldID ${j_name}_reference_field_id = NULL;
9296
</%def>
9397

94-
<%def name="jni_c_impl(cls)">
98+
<%def name="jni_init_global_refs(cls)">
9599
<%
96100
api = java_api
97101
j_name = api.wrapping_type(cls, False)
98-
c_name = cls.c_type(capi).name
99102
100103
sig_base = f"com/adacore/{ctx.lib_name.lower}/{ctx.lib_name.camel}"
101104
ptr_sig = f"{sig_base}$PointerWrapper"
102105
%>
103106
107+
${j_name}_class_ref = (jclass) (*env)->NewGlobalRef(
108+
env,
109+
(*env)->FindClass(env, "${sig_base}$${j_name}")
110+
);
111+
112+
${j_name}_constructor_id = (*env)->GetMethodID(
113+
env,
114+
${j_name}_class_ref,
115+
"<init>",
116+
"(L${ptr_sig};)V"
117+
);
118+
119+
${j_name}_reference_field_id = (*env)->GetFieldID(
120+
env,
121+
${j_name}_class_ref,
122+
"reference",
123+
"L${ptr_sig};"
124+
);
125+
</%def>
126+
127+
<%def name="jni_c_impl(cls)">
128+
<%
129+
api = java_api
130+
j_name = api.wrapping_type(cls, False)
131+
c_name = cls.c_type(capi).name
132+
%>
133+
104134
// Create a new value for a ${c_name}
105135
${c_name} ${j_name}_new_value() {
106136
return NULL;
@@ -114,25 +144,11 @@ jobject ${j_name}_wrap(
114144
// Verify the iterator nullity
115145
if(struct_native == NULL) return NULL;
116146
117-
// Get the class
118-
jclass clazz = (*env)->FindClass(
119-
env,
120-
"${sig_base}$${j_name}"
121-
);
122-
123-
// Get the construtor
124-
jmethodID constructor = (*env)->GetMethodID(
125-
env,
126-
clazz,
127-
"<init>",
128-
"(L${ptr_sig};)V"
129-
);
130-
131147
// Return the new iterator
132148
return (*env)->NewObject(
133149
env,
134-
clazz,
135-
constructor,
150+
${j_name}_class_ref,
151+
${j_name}_constructor_id,
136152
PointerWrapper_wrap(env, (void *) struct_native)
137153
);
138154
}
@@ -142,6 +158,13 @@ ${c_name} ${j_name}_unwrap(
142158
JNIEnv *env,
143159
jobject object
144160
) {
145-
return (${c_name}) get_reference(env, object);
161+
return (${c_name}) PointerWrapper_unwrap(
162+
env,
163+
(*env)->GetObjectField(
164+
env,
165+
object,
166+
${j_name}_reference_field_id
167+
)
168+
);
146169
}
147170
</%def>

0 commit comments

Comments
 (0)