-
Notifications
You must be signed in to change notification settings - Fork 149
/
jni.cpp
4057 lines (3476 loc) · 158 KB
/
jni.cpp
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 Red Hat, Inc.
* Copyright (c) 2021, Azul Systems, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "jni.h"
#include "jvm.h"
#include "ci/ciReplay.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoadInfo.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/javaThreadStatus.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/modules.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "compiler/compiler_globals.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/gcLocker.inline.hpp"
#include "gc/shared/stringdedup/stringDedup.hpp"
#include "interpreter/linkResolver.hpp"
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrThreadId.hpp"
#include "logging/log.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/access.inline.hpp"
#include "oops/arrayOop.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "oops/instanceOop.hpp"
#include "oops/klass.inline.hpp"
#include "oops/markWord.hpp"
#include "oops/method.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "oops/typeArrayKlass.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "prims/jniCheck.hpp"
#include "prims/jniExport.hpp"
#include "prims/jniFastGetField.hpp"
#include "prims/jvm_misc.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/atomic.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jfieldIDWorkaround.hpp"
#include "runtime/jniHandles.inline.hpp"
#include "runtime/reflection.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/vmOperations.hpp"
#include "services/memTracker.hpp"
#include "services/runtimeService.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#include "utilities/macros.hpp"
#include "utilities/vmError.hpp"
#if INCLUDE_JVMCI
#include "jvmci/jvmciCompiler.hpp"
#endif
static jint CurrentVersion = JNI_VERSION_10;
#if defined(_WIN32) && !defined(USE_VECTORED_EXCEPTION_HANDLING)
extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* );
#endif
// The DT_RETURN_MARK macros create a scoped object to fire the dtrace
// '-return' probe regardless of the return path is taken out of the function.
// Methods that have multiple return paths use this to avoid having to
// instrument each return path. Methods that use CHECK or THROW must use this
// since those macros can cause an immedate uninstrumented return.
//
// In order to get the return value, a reference to the variable containing
// the return value must be passed to the contructor of the object, and
// the return value must be set before return (since the mark object has
// a reference to it).
//
// Example:
// DT_RETURN_MARK_DECL(SomeFunc, int);
// JNI_ENTRY(int, SomeFunc, ...)
// int return_value = 0;
// DT_RETURN_MARK(SomeFunc, int, (const int&)return_value);
// foo(CHECK_0)
// return_value = 5;
// return return_value;
// JNI_END
#define DT_RETURN_MARK_DECL(name, type, probe) \
DTRACE_ONLY( \
class DTraceReturnProbeMark_##name { \
public: \
const type& _ret_ref; \
DTraceReturnProbeMark_##name(const type& v) : _ret_ref(v) {} \
~DTraceReturnProbeMark_##name() { \
probe; \
} \
} \
)
// Void functions are simpler since there's no return value
#define DT_VOID_RETURN_MARK_DECL(name, probe) \
DTRACE_ONLY( \
class DTraceReturnProbeMark_##name { \
public: \
~DTraceReturnProbeMark_##name() { \
probe; \
} \
} \
)
// Place these macros in the function to mark the return. Non-void
// functions need the type and address of the return value.
#define DT_RETURN_MARK(name, type, ref) \
DTRACE_ONLY( DTraceReturnProbeMark_##name dtrace_return_mark(ref) )
#define DT_VOID_RETURN_MARK(name) \
DTRACE_ONLY( DTraceReturnProbeMark_##name dtrace_return_mark )
// Use these to select distinct code for floating-point vs. non-floating point
// situations. Used from within common macros where we need slightly
// different behavior for Float/Double
#define FP_SELECT_Boolean(intcode, fpcode) intcode
#define FP_SELECT_Byte(intcode, fpcode) intcode
#define FP_SELECT_Char(intcode, fpcode) intcode
#define FP_SELECT_Short(intcode, fpcode) intcode
#define FP_SELECT_Object(intcode, fpcode) intcode
#define FP_SELECT_Int(intcode, fpcode) intcode
#define FP_SELECT_Long(intcode, fpcode) intcode
#define FP_SELECT_Float(intcode, fpcode) fpcode
#define FP_SELECT_Double(intcode, fpcode) fpcode
#define FP_SELECT(TypeName, intcode, fpcode) \
FP_SELECT_##TypeName(intcode, fpcode)
// Choose DT_RETURN_MARK macros based on the type: float/double -> void
// (dtrace doesn't do FP yet)
#define DT_RETURN_MARK_DECL_FOR(TypeName, name, type, probe) \
FP_SELECT(TypeName, \
DT_RETURN_MARK_DECL(name, type, probe), DT_VOID_RETURN_MARK_DECL(name, probe) )
#define DT_RETURN_MARK_FOR(TypeName, name, type, ref) \
FP_SELECT(TypeName, \
DT_RETURN_MARK(name, type, ref), DT_VOID_RETURN_MARK(name) )
// out-of-line helpers for class jfieldIDWorkaround:
bool jfieldIDWorkaround::is_valid_jfieldID(Klass* k, jfieldID id) {
if (jfieldIDWorkaround::is_instance_jfieldID(k, id)) {
uintptr_t as_uint = (uintptr_t) id;
intptr_t offset = raw_instance_offset(id);
if (is_checked_jfieldID(id)) {
if (!klass_hash_ok(k, id)) {
return false;
}
}
return InstanceKlass::cast(k)->contains_field_offset(offset);
} else {
JNIid* result = (JNIid*) id;
#ifdef ASSERT
return result != NULL && result->is_static_field_id();
#else
return result != NULL;
#endif
}
}
intptr_t jfieldIDWorkaround::encode_klass_hash(Klass* k, intptr_t offset) {
if (offset <= small_offset_mask) {
Klass* field_klass = k;
Klass* super_klass = field_klass->super();
// With compressed oops the most super class with nonstatic fields would
// be the owner of fields embedded in the header.
while (InstanceKlass::cast(super_klass)->has_nonstatic_fields() &&
InstanceKlass::cast(super_klass)->contains_field_offset(offset)) {
field_klass = super_klass; // super contains the field also
super_klass = field_klass->super();
}
debug_only(NoSafepointVerifier nosafepoint;)
uintptr_t klass_hash = field_klass->identity_hash();
return ((klass_hash & klass_mask) << klass_shift) | checked_mask_in_place;
} else {
#if 0
#ifndef PRODUCT
{
ResourceMark rm;
warning("VerifyJNIFields: long offset %d in %s", offset, k->external_name());
}
#endif
#endif
return 0;
}
}
bool jfieldIDWorkaround::klass_hash_ok(Klass* k, jfieldID id) {
uintptr_t as_uint = (uintptr_t) id;
intptr_t klass_hash = (as_uint >> klass_shift) & klass_mask;
do {
debug_only(NoSafepointVerifier nosafepoint;)
// Could use a non-blocking query for identity_hash here...
if ((k->identity_hash() & klass_mask) == klass_hash)
return true;
k = k->super();
} while (k != NULL);
return false;
}
void jfieldIDWorkaround::verify_instance_jfieldID(Klass* k, jfieldID id) {
guarantee(jfieldIDWorkaround::is_instance_jfieldID(k, id), "must be an instance field" );
uintptr_t as_uint = (uintptr_t) id;
intptr_t offset = raw_instance_offset(id);
if (VerifyJNIFields) {
if (is_checked_jfieldID(id)) {
guarantee(klass_hash_ok(k, id),
"Bug in native code: jfieldID class must match object");
} else {
#if 0
#ifndef PRODUCT
if (Verbose) {
ResourceMark rm;
warning("VerifyJNIFields: unverified offset %d for %s", offset, k->external_name());
}
#endif
#endif
}
}
guarantee(InstanceKlass::cast(k)->contains_field_offset(offset),
"Bug in native code: jfieldID offset must address interior of object");
}
// Implementation of JNI entries
DT_RETURN_MARK_DECL(DefineClass, jclass
, HOTSPOT_JNI_DEFINECLASS_RETURN(_ret_ref));
JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderRef,
const jbyte *buf, jsize bufLen))
HOTSPOT_JNI_DEFINECLASS_ENTRY(
env, (char*) name, loaderRef, (char*) buf, bufLen);
jclass cls = NULL;
DT_RETURN_MARK(DefineClass, jclass, (const jclass&)cls);
// Class resolution will get the class name from the .class stream if the name is null.
TempNewSymbol class_name = name == NULL ? NULL :
SystemDictionary::class_name_symbol(name, vmSymbols::java_lang_NoClassDefFoundError(),
CHECK_NULL);
ResourceMark rm(THREAD);
ClassFileStream st((u1*)buf, bufLen, NULL, ClassFileStream::verify);
Handle class_loader (THREAD, JNIHandles::resolve(loaderRef));
Handle protection_domain;
ClassLoadInfo cl_info(protection_domain);
Klass* k = SystemDictionary::resolve_from_stream(&st, class_name,
class_loader,
cl_info,
CHECK_NULL);
if (log_is_enabled(Debug, class, resolve)) {
trace_class_resolution(k);
}
cls = (jclass)JNIHandles::make_local(THREAD, k->java_mirror());
return cls;
JNI_END
DT_RETURN_MARK_DECL(FindClass, jclass
, HOTSPOT_JNI_FINDCLASS_RETURN(_ret_ref));
JNI_ENTRY(jclass, jni_FindClass(JNIEnv *env, const char *name))
HOTSPOT_JNI_FINDCLASS_ENTRY(env, (char *)name);
jclass result = NULL;
DT_RETURN_MARK(FindClass, jclass, (const jclass&)result);
// This should be ClassNotFoundException imo.
TempNewSymbol class_name =
SystemDictionary::class_name_symbol(name, vmSymbols::java_lang_NoClassDefFoundError(),
CHECK_NULL);
//%note jni_3
Handle protection_domain;
// Find calling class
Klass* k = thread->security_get_caller_class(0);
// default to the system loader when no context
Handle loader(THREAD, SystemDictionary::java_system_loader());
if (k != NULL) {
// Special handling to make sure JNI_OnLoad and JNI_OnUnload are executed
// in the correct class context.
if (k->class_loader() == NULL &&
k->name() == vmSymbols::jdk_internal_loader_NativeLibraries()) {
JavaValue result(T_OBJECT);
JavaCalls::call_static(&result, k,
vmSymbols::getFromClass_name(),
vmSymbols::void_class_signature(),
CHECK_NULL);
// When invoked from JNI_OnLoad, NativeLibraries::getFromClass returns
// a non-NULL Class object. When invoked from JNI_OnUnload,
// it will return NULL to indicate no context.
oop mirror = result.get_oop();
if (mirror != NULL) {
Klass* fromClass = java_lang_Class::as_Klass(mirror);
loader = Handle(THREAD, fromClass->class_loader());
protection_domain = Handle(THREAD, fromClass->protection_domain());
}
} else {
loader = Handle(THREAD, k->class_loader());
}
}
result = find_class_from_class_loader(env, class_name, true, loader,
protection_domain, true, thread);
if (log_is_enabled(Debug, class, resolve) && result != NULL) {
trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result)));
}
return result;
JNI_END
DT_RETURN_MARK_DECL(FromReflectedMethod, jmethodID
, HOTSPOT_JNI_FROMREFLECTEDMETHOD_RETURN((uintptr_t)_ret_ref));
JNI_ENTRY(jmethodID, jni_FromReflectedMethod(JNIEnv *env, jobject method))
HOTSPOT_JNI_FROMREFLECTEDMETHOD_ENTRY(env, method);
jmethodID ret = NULL;
DT_RETURN_MARK(FromReflectedMethod, jmethodID, (const jmethodID&)ret);
// method is a handle to a java.lang.reflect.Method object
oop reflected = JNIHandles::resolve_non_null(method);
oop mirror = NULL;
int slot = 0;
if (reflected->klass() == vmClasses::reflect_Constructor_klass()) {
mirror = java_lang_reflect_Constructor::clazz(reflected);
slot = java_lang_reflect_Constructor::slot(reflected);
} else {
assert(reflected->klass() == vmClasses::reflect_Method_klass(), "wrong type");
mirror = java_lang_reflect_Method::clazz(reflected);
slot = java_lang_reflect_Method::slot(reflected);
}
Klass* k1 = java_lang_Class::as_Klass(mirror);
// Make sure class is initialized before handing id's out to methods
k1->initialize(CHECK_NULL);
Method* m = InstanceKlass::cast(k1)->method_with_idnum(slot);
ret = m==NULL? NULL : m->jmethod_id(); // return NULL if reflected method deleted
return ret;
JNI_END
DT_RETURN_MARK_DECL(FromReflectedField, jfieldID
, HOTSPOT_JNI_FROMREFLECTEDFIELD_RETURN((uintptr_t)_ret_ref));
JNI_ENTRY(jfieldID, jni_FromReflectedField(JNIEnv *env, jobject field))
HOTSPOT_JNI_FROMREFLECTEDFIELD_ENTRY(env, field);
jfieldID ret = NULL;
DT_RETURN_MARK(FromReflectedField, jfieldID, (const jfieldID&)ret);
// field is a handle to a java.lang.reflect.Field object
oop reflected = JNIHandles::resolve_non_null(field);
oop mirror = java_lang_reflect_Field::clazz(reflected);
Klass* k1 = java_lang_Class::as_Klass(mirror);
int slot = java_lang_reflect_Field::slot(reflected);
int modifiers = java_lang_reflect_Field::modifiers(reflected);
// Make sure class is initialized before handing id's out to fields
k1->initialize(CHECK_NULL);
// First check if this is a static field
if (modifiers & JVM_ACC_STATIC) {
intptr_t offset = InstanceKlass::cast(k1)->field_offset( slot );
JNIid* id = InstanceKlass::cast(k1)->jni_id_for(offset);
assert(id != NULL, "corrupt Field object");
debug_only(id->set_is_static_field_id();)
// A jfieldID for a static field is a JNIid specifying the field holder and the offset within the Klass*
ret = jfieldIDWorkaround::to_static_jfieldID(id);
return ret;
}
// The slot is the index of the field description in the field-array
// The jfieldID is the offset of the field within the object
// It may also have hash bits for k, if VerifyJNIFields is turned on.
intptr_t offset = InstanceKlass::cast(k1)->field_offset( slot );
assert(InstanceKlass::cast(k1)->contains_field_offset(offset), "stay within object");
ret = jfieldIDWorkaround::to_instance_jfieldID(k1, offset);
return ret;
JNI_END
DT_RETURN_MARK_DECL(ToReflectedMethod, jobject
, HOTSPOT_JNI_TOREFLECTEDMETHOD_RETURN(_ret_ref));
JNI_ENTRY(jobject, jni_ToReflectedMethod(JNIEnv *env, jclass cls, jmethodID method_id, jboolean isStatic))
HOTSPOT_JNI_TOREFLECTEDMETHOD_ENTRY(env, cls, (uintptr_t) method_id, isStatic);
jobject ret = NULL;
DT_RETURN_MARK(ToReflectedMethod, jobject, (const jobject&)ret);
methodHandle m (THREAD, Method::resolve_jmethod_id(method_id));
assert(m->is_static() == (isStatic != 0), "jni_ToReflectedMethod access flags doesn't match");
oop reflection_method;
if (m->is_initializer()) {
reflection_method = Reflection::new_constructor(m, CHECK_NULL);
} else {
reflection_method = Reflection::new_method(m, false, CHECK_NULL);
}
ret = JNIHandles::make_local(THREAD, reflection_method);
return ret;
JNI_END
DT_RETURN_MARK_DECL(GetSuperclass, jclass
, HOTSPOT_JNI_GETSUPERCLASS_RETURN(_ret_ref));
JNI_ENTRY(jclass, jni_GetSuperclass(JNIEnv *env, jclass sub))
HOTSPOT_JNI_GETSUPERCLASS_ENTRY(env, sub);
jclass obj = NULL;
DT_RETURN_MARK(GetSuperclass, jclass, (const jclass&)obj);
oop mirror = JNIHandles::resolve_non_null(sub);
// primitive classes return NULL
if (java_lang_Class::is_primitive(mirror)) return NULL;
// Rules of Class.getSuperClass as implemented by KLass::java_super:
// arrays return Object
// interfaces return NULL
// proper classes return Klass::super()
Klass* k = java_lang_Class::as_Klass(mirror);
if (k->is_interface()) return NULL;
// return mirror for superclass
Klass* super = k->java_super();
// super2 is the value computed by the compiler's getSuperClass intrinsic:
debug_only(Klass* super2 = ( k->is_array_klass()
? vmClasses::Object_klass()
: k->super() ) );
assert(super == super2,
"java_super computation depends on interface, array, other super");
obj = (super == NULL) ? NULL : (jclass) JNIHandles::make_local(THREAD, super->java_mirror());
return obj;
JNI_END
JNI_ENTRY_NO_PRESERVE(jboolean, jni_IsAssignableFrom(JNIEnv *env, jclass sub, jclass super))
HOTSPOT_JNI_ISASSIGNABLEFROM_ENTRY(env, sub, super);
oop sub_mirror = JNIHandles::resolve_non_null(sub);
oop super_mirror = JNIHandles::resolve_non_null(super);
if (java_lang_Class::is_primitive(sub_mirror) ||
java_lang_Class::is_primitive(super_mirror)) {
jboolean ret = (sub_mirror == super_mirror);
HOTSPOT_JNI_ISASSIGNABLEFROM_RETURN(ret);
return ret;
}
Klass* sub_klass = java_lang_Class::as_Klass(sub_mirror);
Klass* super_klass = java_lang_Class::as_Klass(super_mirror);
assert(sub_klass != NULL && super_klass != NULL, "invalid arguments to jni_IsAssignableFrom");
jboolean ret = sub_klass->is_subtype_of(super_klass) ?
JNI_TRUE : JNI_FALSE;
HOTSPOT_JNI_ISASSIGNABLEFROM_RETURN(ret);
return ret;
JNI_END
DT_RETURN_MARK_DECL(Throw, jint
, HOTSPOT_JNI_THROW_RETURN(_ret_ref));
JNI_ENTRY(jint, jni_Throw(JNIEnv *env, jthrowable obj))
HOTSPOT_JNI_THROW_ENTRY(env, obj);
jint ret = JNI_OK;
DT_RETURN_MARK(Throw, jint, (const jint&)ret);
THROW_OOP_(JNIHandles::resolve(obj), JNI_OK);
ShouldNotReachHere();
return 0; // Mute compiler.
JNI_END
DT_RETURN_MARK_DECL(ThrowNew, jint
, HOTSPOT_JNI_THROWNEW_RETURN(_ret_ref));
JNI_ENTRY(jint, jni_ThrowNew(JNIEnv *env, jclass clazz, const char *message))
HOTSPOT_JNI_THROWNEW_ENTRY(env, clazz, (char *) message);
jint ret = JNI_OK;
DT_RETURN_MARK(ThrowNew, jint, (const jint&)ret);
InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)));
Symbol* name = k->name();
Handle class_loader (THREAD, k->class_loader());
Handle protection_domain (THREAD, k->protection_domain());
THROW_MSG_LOADER_(name, (char *)message, class_loader, protection_domain, JNI_OK);
ShouldNotReachHere();
return 0; // Mute compiler.
JNI_END
// JNI functions only transform a pending async exception to a synchronous
// exception in ExceptionOccurred and ExceptionCheck calls, since
// delivering an async exception in other places won't change the native
// code's control flow and would be harmful when native code further calls
// JNI functions with a pending exception. Async exception is also checked
// during the call, so ExceptionOccurred/ExceptionCheck won't return
// false but deliver the async exception at the very end during
// state transition.
static void jni_check_async_exceptions(JavaThread *thread) {
assert(thread == Thread::current(), "must be itself");
thread->check_and_handle_async_exceptions();
}
JNI_ENTRY_NO_PRESERVE(jthrowable, jni_ExceptionOccurred(JNIEnv *env))
HOTSPOT_JNI_EXCEPTIONOCCURRED_ENTRY(env);
jni_check_async_exceptions(thread);
oop exception = thread->pending_exception();
jthrowable ret = (jthrowable) JNIHandles::make_local(THREAD, exception);
HOTSPOT_JNI_EXCEPTIONOCCURRED_RETURN(ret);
return ret;
JNI_END
JNI_ENTRY_NO_PRESERVE(void, jni_ExceptionDescribe(JNIEnv *env))
HOTSPOT_JNI_EXCEPTIONDESCRIBE_ENTRY(env);
if (thread->has_pending_exception()) {
Handle ex(thread, thread->pending_exception());
thread->clear_pending_exception();
if (ex->is_a(vmClasses::ThreadDeath_klass())) {
// Don't print anything if we are being killed.
} else {
jio_fprintf(defaultStream::error_stream(), "Exception ");
if (thread != NULL && thread->threadObj() != NULL) {
ResourceMark rm(THREAD);
jio_fprintf(defaultStream::error_stream(),
"in thread \"%s\" ", thread->get_thread_name());
}
if (ex->is_a(vmClasses::Throwable_klass())) {
JavaValue result(T_VOID);
JavaCalls::call_virtual(&result,
ex,
vmClasses::Throwable_klass(),
vmSymbols::printStackTrace_name(),
vmSymbols::void_method_signature(),
THREAD);
// If an exception is thrown in the call it gets thrown away. Not much
// we can do with it. The native code that calls this, does not check
// for the exception - hence, it might still be in the thread when DestroyVM gets
// called, potentially causing a few asserts to trigger - since no pending exception
// is expected.
CLEAR_PENDING_EXCEPTION;
} else {
ResourceMark rm(THREAD);
jio_fprintf(defaultStream::error_stream(),
". Uncaught exception of type %s.",
ex->klass()->external_name());
}
}
}
HOTSPOT_JNI_EXCEPTIONDESCRIBE_RETURN();
JNI_END
JNI_ENTRY_NO_PRESERVE(void, jni_ExceptionClear(JNIEnv *env))
HOTSPOT_JNI_EXCEPTIONCLEAR_ENTRY(env);
// The jni code might be using this API to clear java thrown exception.
// So just mark jvmti thread exception state as exception caught.
JvmtiThreadState *state = JavaThread::current()->jvmti_thread_state();
if (state != NULL && state->is_exception_detected()) {
state->set_exception_caught();
}
thread->clear_pending_exception();
HOTSPOT_JNI_EXCEPTIONCLEAR_RETURN();
JNI_END
JNI_ENTRY(void, jni_FatalError(JNIEnv *env, const char *msg))
HOTSPOT_JNI_FATALERROR_ENTRY(env, (char *) msg);
tty->print_cr("FATAL ERROR in native method: %s", msg);
thread->print_jni_stack();
os::abort(); // Dump core and abort
JNI_END
JNI_ENTRY(jint, jni_PushLocalFrame(JNIEnv *env, jint capacity))
HOTSPOT_JNI_PUSHLOCALFRAME_ENTRY(env, capacity);
//%note jni_11
if (capacity < 0 ||
((MaxJNILocalCapacity > 0) && (capacity > MaxJNILocalCapacity))) {
HOTSPOT_JNI_PUSHLOCALFRAME_RETURN((uint32_t)JNI_ERR);
return JNI_ERR;
}
JNIHandleBlock* old_handles = thread->active_handles();
JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(thread);
assert(new_handles != NULL, "should not be NULL");
new_handles->set_pop_frame_link(old_handles);
thread->set_active_handles(new_handles);
jint ret = JNI_OK;
HOTSPOT_JNI_PUSHLOCALFRAME_RETURN(ret);
return ret;
JNI_END
JNI_ENTRY(jobject, jni_PopLocalFrame(JNIEnv *env, jobject result))
HOTSPOT_JNI_POPLOCALFRAME_ENTRY(env, result);
//%note jni_11
Handle result_handle(thread, JNIHandles::resolve(result));
JNIHandleBlock* old_handles = thread->active_handles();
JNIHandleBlock* new_handles = old_handles->pop_frame_link();
if (new_handles != NULL) {
// As a sanity check we only release the handle blocks if the pop_frame_link is not NULL.
// This way code will still work if PopLocalFrame is called without a corresponding
// PushLocalFrame call. Note that we set the pop_frame_link to NULL explicitly, otherwise
// the release_block call will release the blocks.
thread->set_active_handles(new_handles);
old_handles->set_pop_frame_link(NULL); // clear link we won't release new_handles below
JNIHandleBlock::release_block(old_handles, thread); // may block
result = JNIHandles::make_local(thread, result_handle());
}
HOTSPOT_JNI_POPLOCALFRAME_RETURN(result);
return result;
JNI_END
JNI_ENTRY(jobject, jni_NewGlobalRef(JNIEnv *env, jobject ref))
HOTSPOT_JNI_NEWGLOBALREF_ENTRY(env, ref);
Handle ref_handle(thread, JNIHandles::resolve(ref));
jobject ret = JNIHandles::make_global(ref_handle, AllocFailStrategy::RETURN_NULL);
HOTSPOT_JNI_NEWGLOBALREF_RETURN(ret);
return ret;
JNI_END
// Must be JNI_ENTRY (with HandleMark)
JNI_ENTRY_NO_PRESERVE(void, jni_DeleteGlobalRef(JNIEnv *env, jobject ref))
HOTSPOT_JNI_DELETEGLOBALREF_ENTRY(env, ref);
JNIHandles::destroy_global(ref);
HOTSPOT_JNI_DELETEGLOBALREF_RETURN();
JNI_END
JNI_ENTRY_NO_PRESERVE(void, jni_DeleteLocalRef(JNIEnv *env, jobject obj))
HOTSPOT_JNI_DELETELOCALREF_ENTRY(env, obj);
JNIHandles::destroy_local(obj);
HOTSPOT_JNI_DELETELOCALREF_RETURN();
JNI_END
JNI_ENTRY_NO_PRESERVE(jboolean, jni_IsSameObject(JNIEnv *env, jobject r1, jobject r2))
HOTSPOT_JNI_ISSAMEOBJECT_ENTRY(env, r1, r2);
jboolean ret = JNIHandles::is_same_object(r1, r2) ? JNI_TRUE : JNI_FALSE;
HOTSPOT_JNI_ISSAMEOBJECT_RETURN(ret);
return ret;
JNI_END
JNI_ENTRY(jobject, jni_NewLocalRef(JNIEnv *env, jobject ref))
HOTSPOT_JNI_NEWLOCALREF_ENTRY(env, ref);
jobject ret = JNIHandles::make_local(THREAD, JNIHandles::resolve(ref),
AllocFailStrategy::RETURN_NULL);
HOTSPOT_JNI_NEWLOCALREF_RETURN(ret);
return ret;
JNI_END
JNI_LEAF(jint, jni_EnsureLocalCapacity(JNIEnv *env, jint capacity))
HOTSPOT_JNI_ENSURELOCALCAPACITY_ENTRY(env, capacity);
jint ret;
if (capacity >= 0 &&
((MaxJNILocalCapacity <= 0) || (capacity <= MaxJNILocalCapacity))) {
ret = JNI_OK;
} else {
ret = JNI_ERR;
}
HOTSPOT_JNI_ENSURELOCALCAPACITY_RETURN(ret);
return ret;
JNI_END
// Return the Handle Type
JNI_LEAF(jobjectRefType, jni_GetObjectRefType(JNIEnv *env, jobject obj))
HOTSPOT_JNI_GETOBJECTREFTYPE_ENTRY(env, obj);
jobjectRefType ret = JNIInvalidRefType;
if (obj != NULL) {
ret = JNIHandles::handle_type(thread, obj);
}
HOTSPOT_JNI_GETOBJECTREFTYPE_RETURN((void *) ret);
return ret;
JNI_END
class JNI_ArgumentPusher : public SignatureIterator {
protected:
JavaCallArguments* _arguments;
void push_int(jint x) { _arguments->push_int(x); }
void push_long(jlong x) { _arguments->push_long(x); }
void push_float(jfloat x) { _arguments->push_float(x); }
void push_double(jdouble x) { _arguments->push_double(x); }
void push_object(jobject x) { _arguments->push_jobject(x); }
void push_boolean(jboolean b) {
// Normalize boolean arguments from native code by converting 1-255 to JNI_TRUE and
// 0 to JNI_FALSE. Boolean return values from native are normalized the same in
// TemplateInterpreterGenerator::generate_result_handler_for and
// SharedRuntime::generate_native_wrapper.
push_int(b == 0 ? JNI_FALSE : JNI_TRUE);
}
JNI_ArgumentPusher(Method* method)
: SignatureIterator(method->signature(),
Fingerprinter(methodHandle(Thread::current(), method)).fingerprint())
{
_arguments = NULL;
}
public:
virtual void push_arguments_on(JavaCallArguments* arguments) = 0;
};
class JNI_ArgumentPusherVaArg : public JNI_ArgumentPusher {
va_list _ap;
void set_ap(va_list rap) {
va_copy(_ap, rap);
}
friend class SignatureIterator; // so do_parameters_on can call do_type
void do_type(BasicType type) {
switch (type) {
// these are coerced to int when using va_arg
case T_BYTE:
case T_CHAR:
case T_SHORT:
case T_INT: push_int(va_arg(_ap, jint)); break;
case T_BOOLEAN: push_boolean((jboolean) va_arg(_ap, jint)); break;
// each of these paths is exercised by the various jck Call[Static,Nonvirtual,][Void,Int,..]Method[A,V,] tests
case T_LONG: push_long(va_arg(_ap, jlong)); break;
// float is coerced to double w/ va_arg
case T_FLOAT: push_float((jfloat) va_arg(_ap, jdouble)); break;
case T_DOUBLE: push_double(va_arg(_ap, jdouble)); break;
case T_ARRAY:
case T_OBJECT: push_object(va_arg(_ap, jobject)); break;
default: ShouldNotReachHere();
}
}
public:
JNI_ArgumentPusherVaArg(jmethodID method_id, va_list rap)
: JNI_ArgumentPusher(Method::resolve_jmethod_id(method_id)) {
set_ap(rap);
}
~JNI_ArgumentPusherVaArg() {
va_end(_ap);
}
virtual void push_arguments_on(JavaCallArguments* arguments) {
_arguments = arguments;
do_parameters_on(this);
}
};
class JNI_ArgumentPusherArray : public JNI_ArgumentPusher {
protected:
const jvalue *_ap;
inline void set_ap(const jvalue *rap) { _ap = rap; }
friend class SignatureIterator; // so do_parameters_on can call do_type
void do_type(BasicType type) {
switch (type) {
case T_CHAR: push_int((_ap++)->c); break;
case T_SHORT: push_int((_ap++)->s); break;
case T_BYTE: push_int((_ap++)->b); break;
case T_INT: push_int((_ap++)->i); break;
case T_BOOLEAN: push_boolean((_ap++)->z); break;
case T_LONG: push_long((_ap++)->j); break;
case T_FLOAT: push_float((_ap++)->f); break;
case T_DOUBLE: push_double((_ap++)->d); break;
case T_ARRAY:
case T_OBJECT: push_object((_ap++)->l); break;
default: ShouldNotReachHere();
}
}
public:
JNI_ArgumentPusherArray(jmethodID method_id, const jvalue *rap)
: JNI_ArgumentPusher(Method::resolve_jmethod_id(method_id)) {
set_ap(rap);
}
virtual void push_arguments_on(JavaCallArguments* arguments) {
_arguments = arguments;
do_parameters_on(this);
}
};
enum JNICallType {
JNI_STATIC,
JNI_VIRTUAL,
JNI_NONVIRTUAL
};
static void jni_invoke_static(JNIEnv *env, JavaValue* result, jobject receiver, JNICallType call_type, jmethodID method_id, JNI_ArgumentPusher *args, TRAPS) {
methodHandle method(THREAD, Method::resolve_jmethod_id(method_id));
// Create object to hold arguments for the JavaCall, and associate it with
// the jni parser
ResourceMark rm(THREAD);
int number_of_parameters = method->size_of_parameters();
JavaCallArguments java_args(number_of_parameters);
assert(method->is_static(), "method should be static");
// Fill out JavaCallArguments object
args->push_arguments_on(&java_args);
// Initialize result type
result->set_type(args->return_type());
// Invoke the method. Result is returned as oop.
JavaCalls::call(result, method, &java_args, CHECK);
// Convert result
if (is_reference_type(result->get_type())) {
result->set_jobject(JNIHandles::make_local(THREAD, result->get_oop()));
}
}
static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receiver, JNICallType call_type, jmethodID method_id, JNI_ArgumentPusher *args, TRAPS) {
oop recv = JNIHandles::resolve(receiver);
if (recv == NULL) {
THROW(vmSymbols::java_lang_NullPointerException());
}
Handle h_recv(THREAD, recv);
int number_of_parameters;
Method* selected_method;
{
Method* m = Method::resolve_jmethod_id(method_id);
number_of_parameters = m->size_of_parameters();
InstanceKlass* holder = m->method_holder();
if (call_type != JNI_VIRTUAL) {
selected_method = m;
} else if (!m->has_itable_index()) {
// non-interface call -- for that little speed boost, don't handlize
debug_only(NoSafepointVerifier nosafepoint;)
// jni_GetMethodID makes sure class is linked and initialized
// so m should have a valid vtable index.
assert(m->valid_vtable_index(), "no valid vtable index");
int vtbl_index = m->vtable_index();
if (vtbl_index != Method::nonvirtual_vtable_index) {
selected_method = h_recv->klass()->method_at_vtable(vtbl_index);
} else {
// final method
selected_method = m;
}
} else {
// interface call
int itbl_index = m->itable_index();
Klass* k = h_recv->klass();
selected_method = InstanceKlass::cast(k)->method_at_itable(holder, itbl_index, CHECK);
}
}
if (selected_method->is_abstract()) {
ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), selected_method->name()->as_C_string());
}
methodHandle method(THREAD, selected_method);
// Create object to hold arguments for the JavaCall, and associate it with
// the jni parser
ResourceMark rm(THREAD);
JavaCallArguments java_args(number_of_parameters);
// handle arguments
assert(!method->is_static(), "method %s should not be static", method->name_and_sig_as_C_string());
java_args.push_oop(h_recv); // Push jobject handle
// Fill out JavaCallArguments object
args->push_arguments_on(&java_args);
// Initialize result type
result->set_type(args->return_type());
// Invoke the method. Result is returned as oop.
JavaCalls::call(result, method, &java_args, CHECK);
// Convert result
if (is_reference_type(result->get_type())) {
result->set_jobject(JNIHandles::make_local(THREAD, result->get_oop()));
}
}
DT_RETURN_MARK_DECL(AllocObject, jobject
, HOTSPOT_JNI_ALLOCOBJECT_RETURN(_ret_ref));
JNI_ENTRY(jobject, jni_AllocObject(JNIEnv *env, jclass clazz))
HOTSPOT_JNI_ALLOCOBJECT_ENTRY(env, clazz);
jobject ret = NULL;
DT_RETURN_MARK(AllocObject, jobject, (const jobject&)ret);
instanceOop i = InstanceKlass::allocate_instance(JNIHandles::resolve_non_null(clazz), CHECK_NULL);
ret = JNIHandles::make_local(THREAD, i);
return ret;
JNI_END
DT_RETURN_MARK_DECL(NewObjectA, jobject
, HOTSPOT_JNI_NEWOBJECTA_RETURN(_ret_ref));
JNI_ENTRY(jobject, jni_NewObjectA(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args))
HOTSPOT_JNI_NEWOBJECTA_ENTRY(env, clazz, (uintptr_t) methodID);
jobject obj = NULL;
DT_RETURN_MARK(NewObjectA, jobject, (const jobject&)obj);
instanceOop i = InstanceKlass::allocate_instance(JNIHandles::resolve_non_null(clazz), CHECK_NULL);
obj = JNIHandles::make_local(THREAD, i);
JavaValue jvalue(T_VOID);
JNI_ArgumentPusherArray ap(methodID, args);
jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_NULL);
return obj;
JNI_END
DT_RETURN_MARK_DECL(NewObjectV, jobject
, HOTSPOT_JNI_NEWOBJECTV_RETURN(_ret_ref));
JNI_ENTRY(jobject, jni_NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args))
HOTSPOT_JNI_NEWOBJECTV_ENTRY(env, clazz, (uintptr_t) methodID);