-
Enhancement
-
Resolution: Fixed
-
P4
-
16
-
b08
On 10/06/2020 3:52 am, Christoph Dreis wrote:
I've just stumbled upon JVM_GetDeclaringClass that I think could be optimized.
The basic idea of the attached patch is to avoid repeated calls to JNIHandles::resolve_non_null & java_lang_Class::as_Klass.
With the following benchmark:
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark {
@State(Scope.Benchmark)
public static class ThreadState {
private Class<?> clazz = ThreadState.class;
}
@Benchmark
public Class<?> testClass(ThreadState threadState) {
return threadState.clazz.getDeclaringClass();
}
}
I see the following results:
BEFORE
Benchmark Mode Cnt Score Error Units
MyBenchmark.testClass avgt 10 119,462 ± 3,914 ns/op
PATCHED
Benchmark Mode Cnt Score Error Units
MyBenchmark.testClass avgt 10 102,457 ± 4,746 ns/op
In case you think this is worthwhile, I would appreciate if someone can sponsor the patch.
Let me know what you think & if I'm missing something (my C++ is a bit rusted).
(Because there seem to be similar optimizations possible throughout jvm.cpp.)
Cheers,
Christoph
===== PATCH =====
--- a/src/hotspot/share/prims/jvm.cpp Sat Jun 06 08:13:40 2020 +0000
+++ b/src/hotspot/share/prims/jvm.cpp Tue Jun 09 19:41:02 2020 +0200
@@ -1560,15 +1560,17 @@
JVM_ENTRY(jclass, JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass))
{
// ofClass is a reference to a java_lang_Class object.
- if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass)) ||
- ! java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->is_instance_klass()) {
+ oop mirror = JNIHandles::resolve_non_null(ofClass);
+ if (java_lang_Class::is_primitive(mirror)) {
+ return NULL;
+ }
+ Klass* k = java_lang_Class::as_Klass(mirror);
+ if (!k->is_instance_klass()) {
return NULL;
}
bool inner_is_member = false;
- Klass* outer_klass
- = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))
- )->compute_enclosing_class(&inner_is_member, CHECK_NULL);
+ Klass* outer_klass = InstanceKlass::cast(k)->compute_enclosing_class(&inner_is_member, CHECK_NULL);
if (outer_klass == NULL) return NULL; // already a top-level class
if (!inner_is_member) return NULL; // a hidden or unsafe anonymous class (inside a method)
return (jclass) JNIHandles::make_local(env, outer_klass->java_mirror());
I've just stumbled upon JVM_GetDeclaringClass that I think could be optimized.
The basic idea of the attached patch is to avoid repeated calls to JNIHandles::resolve_non_null & java_lang_Class::as_Klass.
With the following benchmark:
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark {
@State(Scope.Benchmark)
public static class ThreadState {
private Class<?> clazz = ThreadState.class;
}
@Benchmark
public Class<?> testClass(ThreadState threadState) {
return threadState.clazz.getDeclaringClass();
}
}
I see the following results:
BEFORE
Benchmark Mode Cnt Score Error Units
MyBenchmark.testClass avgt 10 119,462 ± 3,914 ns/op
PATCHED
Benchmark Mode Cnt Score Error Units
MyBenchmark.testClass avgt 10 102,457 ± 4,746 ns/op
In case you think this is worthwhile, I would appreciate if someone can sponsor the patch.
Let me know what you think & if I'm missing something (my C++ is a bit rusted).
(Because there seem to be similar optimizations possible throughout jvm.cpp.)
Cheers,
Christoph
===== PATCH =====
--- a/src/hotspot/share/prims/jvm.cpp Sat Jun 06 08:13:40 2020 +0000
+++ b/src/hotspot/share/prims/jvm.cpp Tue Jun 09 19:41:02 2020 +0200
@@ -1560,15 +1560,17 @@
JVM_ENTRY(jclass, JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass))
{
// ofClass is a reference to a java_lang_Class object.
- if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass)) ||
- ! java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->is_instance_klass()) {
+ oop mirror = JNIHandles::resolve_non_null(ofClass);
+ if (java_lang_Class::is_primitive(mirror)) {
+ return NULL;
+ }
+ Klass* k = java_lang_Class::as_Klass(mirror);
+ if (!k->is_instance_klass()) {
return NULL;
}
bool inner_is_member = false;
- Klass* outer_klass
- = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))
- )->compute_enclosing_class(&inner_is_member, CHECK_NULL);
+ Klass* outer_klass = InstanceKlass::cast(k)->compute_enclosing_class(&inner_is_member, CHECK_NULL);
if (outer_klass == NULL) return NULL; // already a top-level class
if (!inner_is_member) return NULL; // a hidden or unsafe anonymous class (inside a method)
return (jclass) JNIHandles::make_local(env, outer_klass->java_mirror());