This repository has been archived by the owner on Feb 2, 2023. It is now read-only.
/
jni.cpp
4380 lines (3760 loc) · 167 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, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 Red Hat, Inc.
* 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/javaClasses.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/modules.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc/shared/gcLocker.inline.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.inline.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/instanceOop.hpp"
#include "oops/markOop.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/compilationPolicy.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/orderAccess.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/histogram.hpp"
#include "utilities/macros.hpp"
#include "utilities/vmError.hpp"
static jint CurrentVersion = JNI_VERSION_10;
#ifdef _WIN32
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");
}
// Wrapper to trace JNI functions
#ifdef ASSERT
Histogram* JNIHistogram;
static volatile int JNIHistogram_lock = 0;
class JNIHistogramElement : public HistogramElement {
public:
JNIHistogramElement(const char* name);
};
JNIHistogramElement::JNIHistogramElement(const char* elementName) {
_name = elementName;
uintx count = 0;
while (Atomic::cmpxchg(1, &JNIHistogram_lock, 0) != 0) {
while (OrderAccess::load_acquire(&JNIHistogram_lock) != 0) {
count +=1;
if ( (WarnOnStalledSpinLock > 0)
&& (count % WarnOnStalledSpinLock == 0)) {
warning("JNIHistogram_lock seems to be stalled");
}
}
}
if(JNIHistogram == NULL)
JNIHistogram = new Histogram("JNI Call Counts",100);
JNIHistogram->add_element(this);
Atomic::dec(&JNIHistogram_lock);
}
#define JNICountWrapper(arg) \
static JNIHistogramElement* e = new JNIHistogramElement(arg); \
/* There is a MT-race condition in VC++. So we need to make sure that that e has been initialized */ \
if (e != NULL) e->increment_count()
#define JNIWrapper(arg) JNICountWrapper(arg);
#else
#define JNIWrapper(arg)
#endif
// 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))
JNIWrapper("DefineClass");
HOTSPOT_JNI_DEFINECLASS_ENTRY(
env, (char*) name, loaderRef, (char*) buf, bufLen);
jclass cls = NULL;
DT_RETURN_MARK(DefineClass, jclass, (const jclass&)cls);
TempNewSymbol class_name = NULL;
// Since exceptions can be thrown, class initialization can take place
// if name is NULL no check for class name in .class stream has to be made.
if (name != NULL) {
const int str_len = (int)strlen(name);
if (str_len > Symbol::max_length()) {
// It's impossible to create this class; the name cannot fit
// into the constant pool.
Exceptions::fthrow(THREAD_AND_LOCATION,
vmSymbols::java_lang_NoClassDefFoundError(),
"Class name exceeds maximum length of %d: %s",
Symbol::max_length(),
name);
return 0;
}
class_name = SymbolTable::new_symbol(name);
}
ResourceMark rm(THREAD);
ClassFileStream st((u1*)buf, bufLen, NULL, ClassFileStream::verify);
Handle class_loader (THREAD, JNIHandles::resolve(loaderRef));
if (UsePerfData && !class_loader.is_null()) {
// check whether the current caller thread holds the lock or not.
// If not, increment the corresponding counter
if (ObjectSynchronizer::
query_lock_ownership((JavaThread*)THREAD, class_loader) !=
ObjectSynchronizer::owner_self) {
ClassLoader::sync_JNIDefineClassLockFreeCounter()->inc();
}
}
Klass* k = SystemDictionary::resolve_from_stream(class_name,
class_loader,
Handle(),
&st,
CHECK_NULL);
if (log_is_enabled(Debug, class, resolve) && k != NULL) {
trace_class_resolution(k);
}
cls = (jclass)JNIHandles::make_local(
env, 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))
JNIWrapper("FindClass");
HOTSPOT_JNI_FINDCLASS_ENTRY(env, (char *)name);
jclass result = NULL;
DT_RETURN_MARK(FindClass, jclass, (const jclass&)result);
// Sanity check the name: it cannot be null or larger than the maximum size
// name we can fit in the constant pool.
if (name == NULL) {
THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), "No class name given");
}
if ((int)strlen(name) > Symbol::max_length()) {
Exceptions::fthrow(THREAD_AND_LOCATION,
vmSymbols::java_lang_NoClassDefFoundError(),
"Class name exceeds maximum length of %d: %s",
Symbol::max_length(),
name);
return 0;
}
//%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::java_lang_ClassLoader_NativeLibrary()) {
JavaValue result(T_OBJECT);
JavaCalls::call_static(&result, k,
vmSymbols::getFromClass_name(),
vmSymbols::void_class_signature(),
CHECK_NULL);
// When invoked from JNI_OnLoad, NativeLibrary::getFromClass returns
// a non-NULL Class object. When invoked from JNI_OnUnload,
// it will return NULL to indicate no context.
oop mirror = (oop) result.get_jobject();
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());
}
}
TempNewSymbol sym = SymbolTable::new_symbol(name);
result = find_class_from_class_loader(env, sym, 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))
JNIWrapper("FromReflectedMethod");
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() == SystemDictionary::reflect_Constructor_klass()) {
mirror = java_lang_reflect_Constructor::clazz(reflected);
slot = java_lang_reflect_Constructor::slot(reflected);
} else {
assert(reflected->klass() == SystemDictionary::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))
JNIWrapper("FromReflectedField");
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))
JNIWrapper("ToReflectedMethod");
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(env, 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))
JNIWrapper("GetSuperclass");
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()
? SystemDictionary::Object_klass()
: k->super() ) );
assert(super == super2,
"java_super computation depends on interface, array, other super");
obj = (super == NULL) ? NULL : (jclass) JNIHandles::make_local(super->java_mirror());
return obj;
JNI_END
JNI_QUICK_ENTRY(jboolean, jni_IsAssignableFrom(JNIEnv *env, jclass sub, jclass super))
JNIWrapper("IsSubclassOf");
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 = oopDesc::equals(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))
JNIWrapper("Throw");
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))
JNIWrapper("ThrowNew");
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))
JNIWrapper("ExceptionOccurred");
HOTSPOT_JNI_EXCEPTIONOCCURRED_ENTRY(env);
jni_check_async_exceptions(thread);
oop exception = thread->pending_exception();
jthrowable ret = (jthrowable) JNIHandles::make_local(env, exception);
HOTSPOT_JNI_EXCEPTIONOCCURRED_RETURN(ret);
return ret;
JNI_END
JNI_ENTRY_NO_PRESERVE(void, jni_ExceptionDescribe(JNIEnv *env))
JNIWrapper("ExceptionDescribe");
HOTSPOT_JNI_EXCEPTIONDESCRIBE_ENTRY(env);
if (thread->has_pending_exception()) {
Handle ex(thread, thread->pending_exception());
thread->clear_pending_exception();
if (ex->is_a(SystemDictionary::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(SystemDictionary::Throwable_klass())) {
JavaValue result(T_VOID);
JavaCalls::call_virtual(&result,
ex,
SystemDictionary::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_QUICK_ENTRY(void, jni_ExceptionClear(JNIEnv *env))
JNIWrapper("ExceptionClear");
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))
JNIWrapper("FatalError");
HOTSPOT_JNI_FATALERROR_ENTRY(env, (char *) msg);
tty->print_cr("FATAL ERROR in native method: %s", msg);
thread->print_stack();
os::abort(); // Dump core and abort
JNI_END
JNI_ENTRY(jint, jni_PushLocalFrame(JNIEnv *env, jint capacity))
JNIWrapper("PushLocalFrame");
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))
JNIWrapper("PopLocalFrame");
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))
JNIWrapper("NewGlobalRef");
HOTSPOT_JNI_NEWGLOBALREF_ENTRY(env, ref);
Handle ref_handle(thread, JNIHandles::resolve(ref));
jobject ret = JNIHandles::make_global(ref_handle);
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))
JNIWrapper("DeleteGlobalRef");
HOTSPOT_JNI_DELETEGLOBALREF_ENTRY(env, ref);
JNIHandles::destroy_global(ref);
HOTSPOT_JNI_DELETEGLOBALREF_RETURN();
JNI_END
JNI_QUICK_ENTRY(void, jni_DeleteLocalRef(JNIEnv *env, jobject obj))
JNIWrapper("DeleteLocalRef");
HOTSPOT_JNI_DELETELOCALREF_ENTRY(env, obj);
JNIHandles::destroy_local(obj);
HOTSPOT_JNI_DELETELOCALREF_RETURN();
JNI_END
JNI_QUICK_ENTRY(jboolean, jni_IsSameObject(JNIEnv *env, jobject r1, jobject r2))
JNIWrapper("IsSameObject");
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))
JNIWrapper("NewLocalRef");
HOTSPOT_JNI_NEWLOCALREF_ENTRY(env, ref);
jobject ret = JNIHandles::make_local(env, JNIHandles::resolve(ref));
HOTSPOT_JNI_NEWLOCALREF_RETURN(ret);
return ret;
JNI_END
JNI_LEAF(jint, jni_EnsureLocalCapacity(JNIEnv *env, jint capacity))
JNIWrapper("EnsureLocalCapacity");
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))
JNIWrapper("GetObjectRefType");
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;
virtual void get_bool () = 0;
virtual void get_char () = 0;
virtual void get_short () = 0;
virtual void get_byte () = 0;
virtual void get_int () = 0;
virtual void get_long () = 0;
virtual void get_float () = 0;
virtual void get_double () = 0;
virtual void get_object () = 0;
JNI_ArgumentPusher(Symbol* signature) : SignatureIterator(signature) {
this->_return_type = T_ILLEGAL;
_arguments = NULL;
}
public:
virtual void iterate( uint64_t fingerprint ) = 0;
void set_java_argument_object(JavaCallArguments *arguments) { _arguments = arguments; }
inline void do_bool() { if (!is_return_type()) get_bool(); }
inline void do_char() { if (!is_return_type()) get_char(); }
inline void do_short() { if (!is_return_type()) get_short(); }
inline void do_byte() { if (!is_return_type()) get_byte(); }
inline void do_int() { if (!is_return_type()) get_int(); }
inline void do_long() { if (!is_return_type()) get_long(); }
inline void do_float() { if (!is_return_type()) get_float(); }
inline void do_double() { if (!is_return_type()) get_double(); }
inline void do_object(int begin, int end) { if (!is_return_type()) get_object(); }
inline void do_array(int begin, int end) { if (!is_return_type()) get_object(); } // do_array uses get_object -- there is no get_array
inline void do_void() { }
JavaCallArguments* arguments() { return _arguments; }
void push_receiver(Handle h) { _arguments->push_oop(h); }
};
class JNI_ArgumentPusherVaArg : public JNI_ArgumentPusher {
protected:
va_list _ap;
inline void get_bool() {
// 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.
jboolean b = va_arg(_ap, jint);
_arguments->push_int((jint)(b == 0 ? JNI_FALSE : JNI_TRUE));
}
inline void get_char() { _arguments->push_int(va_arg(_ap, jint)); } // char is coerced to int when using va_arg
inline void get_short() { _arguments->push_int(va_arg(_ap, jint)); } // short is coerced to int when using va_arg
inline void get_byte() { _arguments->push_int(va_arg(_ap, jint)); } // byte is coerced to int when using va_arg
inline void get_int() { _arguments->push_int(va_arg(_ap, jint)); }
// each of these paths is exercized by the various jck Call[Static,Nonvirtual,][Void,Int,..]Method[A,V,] tests
inline void get_long() { _arguments->push_long(va_arg(_ap, jlong)); }
inline void get_float() { _arguments->push_float((jfloat)va_arg(_ap, jdouble)); } // float is coerced to double w/ va_arg
inline void get_double() { _arguments->push_double(va_arg(_ap, jdouble)); }
inline void get_object() { _arguments->push_jobject(va_arg(_ap, jobject)); }
inline void set_ap(va_list rap) {
va_copy(_ap, rap);
}
public:
JNI_ArgumentPusherVaArg(Symbol* signature, va_list rap)
: JNI_ArgumentPusher(signature) {
set_ap(rap);
}
JNI_ArgumentPusherVaArg(jmethodID method_id, va_list rap)
: JNI_ArgumentPusher(Method::resolve_jmethod_id(method_id)->signature()) {
set_ap(rap);
}
// Optimized path if we have the bitvector form of signature
void iterate( uint64_t fingerprint ) {
if (fingerprint == (uint64_t)CONST64(-1)) {
SignatureIterator::iterate(); // Must be too many arguments
} else {
_return_type = (BasicType)((fingerprint >> static_feature_size) &
result_feature_mask);
assert(fingerprint, "Fingerprint should not be 0");
fingerprint = fingerprint >> (static_feature_size + result_feature_size);
while ( 1 ) {
switch ( fingerprint & parameter_feature_mask ) {
case bool_parm:
get_bool();
break;
case char_parm:
get_char();
break;
case short_parm:
get_short();
break;
case byte_parm:
get_byte();
break;
case int_parm:
get_int();
break;
case obj_parm:
get_object();
break;
case long_parm:
get_long();
break;
case float_parm:
get_float();
break;
case double_parm:
get_double();
break;
case done_parm:
return;
break;
default:
ShouldNotReachHere();
break;
}
fingerprint >>= parameter_feature_size;
}
}
}
};
class JNI_ArgumentPusherArray : public JNI_ArgumentPusher {
protected:
const jvalue *_ap;
inline void get_bool() {
// 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.