Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/jcl/common/java_lang_Class.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 1998, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
#include "jni.h"
24
#include "jcl.h"
25
#include "jclglob.h"
26
#include "jclprots.h"
27
#include "jcl_internal.h"
28
#include "objhelp.h"
29
#include "rommeth.h"
30
#include "vmaccess.h"
31
#include "java_lang_Class.h"
32
#include "ArrayCopyHelpers.hpp"
33
#include "j9jclnls.h"
34
35
36
#include "VMHelpers.hpp"
37
38
extern "C" {
39
40
typedef enum {
41
STATE_INITIAL = -2,
42
STATE_ERROR = -1,
43
STATE_STOP = 0,
44
STATE_IMPLIED = 1
45
} StackWalkingStates;
46
47
typedef enum {
48
OBJS_ARRAY_IDX_ACC = 0,
49
OBJS_ARRAY_IDX_PDS = 1,
50
OBJS_ARRAY_IDX_PERMS_OR_CACHECHECKED = 2,
51
OBJS_ARRAY_SIZE = 3
52
} ObjsArraySizeNindex;
53
54
#define STACK_WALK_STATE_MAGIC (void *)1
55
#define STACK_WALK_STATE_LIMITED_DOPRIVILEGED (void *)2
56
#define STACK_WALK_STATE_FULL_DOPRIVILEGED (void *)3
57
58
static UDATA isPrivilegedFrameIterator(J9VMThread * currentThread, J9StackWalkState * walkState);
59
static UDATA isPrivilegedFrameIteratorGetAccSnapshot(J9VMThread * currentThread, J9StackWalkState * walkState);
60
static UDATA frameIteratorGetAccSnapshotHelper(J9VMThread * currentThread, J9StackWalkState * walkState, j9object_t acc, j9object_t perm);
61
static j9object_t storePDobjectsHelper(J9VMThread* vmThread, J9Class* arrayClass, J9StackWalkState* walkState, j9object_t contextObject, U_32 arraySize, UDATA framesWalked, I_32 startPos, BOOLEAN dupCallerPD);
62
static BOOLEAN checkInnerClassHelper(J9Class* declaringClass, J9Class* declaredClass);
63
64
jobject JNICALL
65
Java_java_lang_Class_getDeclaredAnnotationsData(JNIEnv *env, jobject jlClass)
66
{
67
jobject result = NULL;
68
j9object_t clazz = NULL;
69
J9VMThread *vmThread = (J9VMThread *) env;
70
71
enterVMFromJNI(vmThread);
72
clazz = J9_JNI_UNWRAP_REFERENCE(jlClass);
73
if (NULL != clazz) {
74
j9object_t annotationsData = getClassAnnotationData(vmThread, J9VM_J9CLASS_FROM_HEAPCLASS(vmThread, clazz));
75
if (NULL != annotationsData) {
76
result = vmThread->javaVM->internalVMFunctions->j9jni_createLocalRef(env, annotationsData);
77
}
78
}
79
exitVMToJNI(vmThread);
80
return result;
81
}
82
83
static UDATA
84
isPrivilegedFrameIterator(J9VMThread * currentThread, J9StackWalkState * walkState)
85
{
86
J9JavaVM *vm = currentThread->javaVM;
87
J9JNIMethodID *doPrivilegedMethodID1 = (J9JNIMethodID *) vm->doPrivilegedMethodID1;
88
J9JNIMethodID *doPrivilegedMethodID2 = (J9JNIMethodID *) vm->doPrivilegedMethodID2;
89
J9JNIMethodID *doPrivilegedWithContextMethodID1 = (J9JNIMethodID *) vm->doPrivilegedWithContextMethodID1;
90
J9JNIMethodID *doPrivilegedWithContextMethodID2 = (J9JNIMethodID *) vm->doPrivilegedWithContextMethodID2;
91
J9Method *currentMethod = walkState->method;
92
93
if (J9_ARE_ALL_BITS_SET(J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod)->modifiers, J9AccMethodFrameIteratorSkip)) {
94
/* Skip methods with java.lang.invoke.FrameIteratorSkip / jdk.internal.vm.annotation.Hidden / java.lang.invoke.LambdaForm$Hidden annotation */
95
return J9_STACKWALK_KEEP_ITERATING;
96
}
97
98
if (NULL == walkState->userData2) {
99
J9Class * currentClass = J9_CLASS_FROM_CP(walkState->constantPool);
100
if ((walkState->method == vm->jlrMethodInvoke)
101
#if JAVA_SPEC_VERSION >= 18
102
|| (walkState->method == vm->jlrMethodInvokeMH)
103
#endif /* JAVA_SPEC_VERSION >= 18 */
104
|| (walkState->method == vm->jliMethodHandleInvokeWithArgs)
105
|| (walkState->method == vm->jliMethodHandleInvokeWithArgsList)
106
|| (vm->srMethodAccessor && VM_VMHelpers::isSameOrSuperclass(J9VM_J9CLASS_FROM_JCLASS(currentThread, vm->srMethodAccessor), currentClass))
107
) {
108
/* skip reflection/MethodHandleInvoke frames */
109
} else {
110
return J9_STACKWALK_STOP_ITERATING;
111
}
112
}
113
114
if ( ((doPrivilegedMethodID1 != NULL) && (currentMethod == doPrivilegedMethodID1->method)) ||
115
((doPrivilegedMethodID2 != NULL) && (currentMethod == doPrivilegedMethodID2->method))
116
) {
117
/* Context is NULL */
118
walkState->userData1 = NULL;
119
walkState->userData2 = NULL;
120
}
121
122
if ( ((doPrivilegedWithContextMethodID1 != NULL) && (currentMethod == doPrivilegedWithContextMethodID1->method)) ||
123
((doPrivilegedWithContextMethodID2 != NULL) && (currentMethod == doPrivilegedWithContextMethodID2->method))
124
) {
125
/* Grab the Context from the arguments: ultra-scary: fetch arg2 from the doPrivileged() method */
126
walkState->userData1 = (void *)walkState->arg0EA[-1];
127
walkState->userData2 = NULL;
128
}
129
130
return J9_STACKWALK_KEEP_ITERATING;
131
}
132
133
jobject JNICALL
134
Java_java_lang_Class_getStackClasses(JNIEnv *env, jclass jlHeapClass, jint maxDepth, jboolean stopAtPrivileged)
135
{
136
J9VMThread *vmThread = (J9VMThread *) env;
137
J9JavaVM *vm = vmThread->javaVM;
138
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
139
J9StackWalkState walkState = {0};
140
J9Class *jlClass = NULL;
141
J9Class *arrayClass = NULL;
142
UDATA walkFlags = J9_STACKWALK_CACHE_METHODS | J9_STACKWALK_COUNT_SPECIFIED | J9_STACKWALK_VISIBLE_ONLY | J9_STACKWALK_INCLUDE_NATIVES;
143
UDATA framesWalked = 0;
144
UDATA *cacheContents = NULL;
145
UDATA i = 0;
146
j9object_t arrayObject = NULL;
147
jobject result = NULL;
148
149
vmFuncs->internalEnterVMFromJNI(vmThread);
150
151
/* Fetch the Class[] class before doing the stack walk. */
152
jlClass = J9VMJAVALANGCLASS(vm);
153
154
arrayClass = fetchArrayClass(vmThread, jlClass);
155
if (NULL != vmThread->currentException) {
156
goto _throwException;
157
}
158
159
/* Walk the stack, caching the constant pools of the frames. If we're stopping at
160
* privileged frames, specify a frame walk function.
161
*/
162
walkState.skipCount = 2; /*skip this JNI frame and the local caller */
163
walkState.userData1 = STACK_WALK_STATE_MAGIC; /* value which will not be written into userData1 by the frame walk function (which writes only null or an object pointer) */
164
walkState.userData2 = STACK_WALK_STATE_MAGIC; /* value which will not be written into userData2 by the frame walk function (which writes only null) */
165
walkState.maxFrames = maxDepth;
166
walkState.walkThread = vmThread;
167
168
if (stopAtPrivileged) {
169
walkFlags |= J9_STACKWALK_ITERATE_FRAMES;
170
walkState.frameWalkFunction = isPrivilegedFrameIterator;
171
}
172
walkState.flags = walkFlags;
173
174
if (vm->walkStackFrames(vmThread, &walkState) != J9_STACKWALK_RC_NONE) {
175
vmFuncs->setNativeOutOfMemoryError(vmThread, 0, 0);
176
goto _throwException;
177
}
178
179
/* If a privileged frame caused us to stop walking, do not include that
180
* frame (the last one walked) in the array.
181
*/
182
framesWalked = walkState.framesWalked;
183
if (STACK_WALK_STATE_MAGIC != walkState.userData1) {
184
framesWalked -= 1;
185
}
186
187
/* Translate cached CPs into J9Class * and nil any entries that are for reflect frames. */
188
cacheContents = walkState.cache;
189
190
for (i = framesWalked; i > 0; i--) {
191
J9Method *currentMethod = (J9Method *)*cacheContents;
192
J9Class *currentClass = J9_CLASS_FROM_METHOD(currentMethod);
193
194
if ( J9_ARE_ALL_BITS_SET(J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod)->modifiers, J9AccMethodFrameIteratorSkip) ||
195
(vm->jliArgumentHelper && instanceOfOrCheckCast(currentClass, J9VM_J9CLASS_FROM_JCLASS(vmThread, vm->jliArgumentHelper))) ||
196
(vm->srMethodAccessor && vmFuncs->instanceOfOrCheckCast(currentClass, J9VM_J9CLASS_FROM_HEAPCLASS(vmThread, *((j9object_t*) vm->srMethodAccessor)))) ||
197
(vm->srConstructorAccessor && vmFuncs->instanceOfOrCheckCast(currentClass, J9VM_J9CLASS_FROM_HEAPCLASS(vmThread, *((j9object_t*) vm->srConstructorAccessor))))
198
) {
199
currentClass = NULL;
200
framesWalked--;
201
}
202
*cacheContents++ = (UDATA) currentClass;
203
}
204
205
/* Allocate the result array. */
206
arrayObject = vm->memoryManagerFunctions->J9AllocateIndexableObject(vmThread, arrayClass, (U_32)framesWalked, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
207
if (NULL == arrayObject) {
208
vmFuncs->freeStackWalkCaches(vmThread, &walkState);
209
vmFuncs->setHeapOutOfMemoryError(vmThread);
210
goto _throwException;
211
}
212
213
/* Fill in the array. */
214
if (framesWalked != 0) {
215
I_32 resultIndex = 0;
216
217
cacheContents = walkState.cache;
218
219
for (i = framesWalked; i > 0; i--) {
220
J9Class *clazz = (J9Class *)(*cacheContents++);
221
/* Ignore zero entries (removed reflect frames). */
222
while (NULL == clazz) {
223
clazz = (J9Class *)(*cacheContents++);
224
}
225
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, resultIndex, J9VM_J9CLASS_TO_HEAPCLASS(clazz));
226
resultIndex++;
227
}
228
}
229
230
vmFuncs->freeStackWalkCaches(vmThread, &walkState);
231
result = vmFuncs->j9jni_createLocalRef(env, arrayObject);
232
233
_throwException:
234
vmFuncs->internalExitVMToJNI(vmThread);
235
236
return result;
237
}
238
239
jboolean JNICALL
240
Java_java_lang_Class_isClassADeclaredClass(JNIEnv *env, jobject jlClass, jobject aClass)
241
{
242
J9VMThread *vmThread = (J9VMThread *) env;
243
J9Class *declaringClass = NULL;
244
J9Class *declaredClass = NULL;
245
jboolean result = JNI_FALSE;
246
247
enterVMFromJNI(vmThread);
248
249
declaringClass = J9VM_J9CLASS_FROM_HEAPCLASS(vmThread, J9_JNI_UNWRAP_REFERENCE(jlClass));
250
declaredClass = J9VM_J9CLASS_FROM_HEAPCLASS(vmThread, J9_JNI_UNWRAP_REFERENCE(aClass));
251
252
if (checkInnerClassHelper(declaringClass, declaredClass)) {
253
result = JNI_TRUE;
254
}
255
256
exitVMToJNI(vmThread);
257
return result;
258
}
259
260
jboolean JNICALL
261
Java_java_lang_Class_isClassAnEnclosedClass(JNIEnv *env, jobject jlClass, jobject aClass)
262
{
263
J9VMThread *vmThread = (J9VMThread *) env;
264
J9Class *enclosingClass = NULL;
265
U_32 enclosedInnerClassCount = 0;
266
J9Class *enclosedClass = NULL;
267
J9UTF8 *enclosedClassName = NULL;
268
J9SRP *srpCursor = NULL;
269
jboolean result = JNI_FALSE;
270
U_32 i = 0;
271
272
enterVMFromJNI(vmThread);
273
274
enclosingClass = J9VM_J9CLASS_FROM_HEAPCLASS(vmThread, J9_JNI_UNWRAP_REFERENCE(jlClass));
275
enclosedInnerClassCount = enclosingClass->romClass->enclosedInnerClassCount;
276
enclosedClass = J9VM_J9CLASS_FROM_HEAPCLASS(vmThread, J9_JNI_UNWRAP_REFERENCE(aClass));
277
enclosedClassName = J9ROMCLASS_CLASSNAME(enclosedClass->romClass);
278
279
if (checkInnerClassHelper(enclosingClass, enclosedClass)) {
280
result = JNI_TRUE;
281
} else {
282
srpCursor = J9ROMCLASS_ENCLOSEDINNERCLASSES(enclosingClass->romClass);
283
for (i = 0; i < enclosedInnerClassCount; i++) {
284
J9UTF8 *enclosedInnerClassName = SRP_PTR_GET(srpCursor, J9UTF8 *);
285
if (0 == compareUTF8Length(J9UTF8_DATA(enclosedClassName), J9UTF8_LENGTH(enclosedClassName),
286
J9UTF8_DATA(enclosedInnerClassName), J9UTF8_LENGTH(enclosedInnerClassName))) {
287
/* aClass' class name matches one of the enclosed inner classes of 'this',
288
* therefore aClass is one of this' enclosed classes */
289
result = JNI_TRUE;
290
break;
291
}
292
srpCursor++;
293
}
294
}
295
296
exitVMToJNI(vmThread);
297
return result;
298
}
299
300
static BOOLEAN
301
checkInnerClassHelper(J9Class* declaringClass, J9Class* declaredClass)
302
{
303
U_32 innerClassCount = declaringClass->romClass->innerClassCount;
304
J9SRP *srpCursor = J9ROMCLASS_INNERCLASSES(declaringClass->romClass);
305
J9UTF8* declaredClassName = J9ROMCLASS_CLASSNAME(declaredClass->romClass);
306
U_32 i = 0;
307
308
for (i = 0; i < innerClassCount; i++) {
309
J9UTF8 *innerClassName = SRP_PTR_GET(srpCursor, J9UTF8 *);
310
if (0 == compareUTF8Length(J9UTF8_DATA(declaredClassName), J9UTF8_LENGTH(declaredClassName),
311
J9UTF8_DATA(innerClassName), J9UTF8_LENGTH(innerClassName))) {
312
/* aClass' class name matches one of the inner classes of 'this',
313
* therefore aClass is one of this' declared classes */
314
return TRUE;
315
}
316
srpCursor++;
317
}
318
return FALSE;
319
}
320
321
jboolean JNICALL
322
Java_java_lang_Class_isCircularDeclaringClass(JNIEnv *env, jobject recv)
323
{
324
J9VMThread *currentThread = (J9VMThread*)env;
325
J9JavaVM *vm = currentThread->javaVM;
326
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
327
jboolean result = JNI_FALSE;
328
329
vmFuncs->internalEnterVMFromJNI(currentThread);
330
331
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
332
J9Class *currentClazz = clazz;
333
J9UTF8 *outerClassName = J9ROMCLASS_OUTERCLASSNAME(currentClazz->romClass);
334
while (NULL != outerClassName) {
335
J9Class *outerClass = vmFuncs->internalFindClassUTF8(currentThread, J9UTF8_DATA(outerClassName),
336
J9UTF8_LENGTH(outerClassName), currentClazz->classLoader, 0);
337
if (NULL == outerClass) {
338
break;
339
} else if (clazz == outerClass) {
340
result = JNI_TRUE;
341
break;
342
}
343
currentClazz = outerClass;
344
outerClassName = J9ROMCLASS_OUTERCLASSNAME(currentClazz->romClass);
345
}
346
347
vmFuncs->internalExitVMToJNI(currentThread);
348
return result;
349
}
350
351
jobject JNICALL
352
Java_com_ibm_oti_vm_VM_getClassNameImpl(JNIEnv *env, jclass recv, jclass jlClass, jboolean internAndAssign)
353
{
354
J9VMThread *currentThread = (J9VMThread *) env;
355
J9JavaVM *vm = currentThread->javaVM;
356
J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
357
jobject classNameRef = NULL;
358
359
vmFuncs->internalEnterVMFromJNI(currentThread);
360
361
j9object_t classNameObject = VM_VMHelpers::getClassNameString(currentThread, J9_JNI_UNWRAP_REFERENCE(jlClass), JNI_FALSE != internAndAssign);
362
if (NULL != classNameObject) {
363
classNameRef = vmFuncs->j9jni_createLocalRef(env, classNameObject);
364
if (NULL == classNameRef) {
365
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
366
}
367
}
368
369
vmFuncs->internalExitVMToJNI(currentThread);
370
return classNameRef;
371
}
372
373
jarray JNICALL
374
Java_java_lang_Class_getDeclaredFieldsImpl(JNIEnv *env, jobject recv)
375
{
376
return getDeclaredFieldsHelper(env, recv);
377
}
378
379
jobject JNICALL
380
Java_java_lang_Class_getGenericSignature(JNIEnv *env, jobject recv)
381
{
382
J9VMThread *currentThread = (J9VMThread*)env;
383
J9JavaVM *vm = currentThread->javaVM;
384
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
385
jobject result = NULL;
386
j9object_t classObject = NULL;
387
J9Class *clazz = NULL;
388
J9ROMClass *romClass = NULL;
389
J9UTF8 *signature = NULL;
390
391
vmFuncs->internalEnterVMFromJNI(currentThread);
392
classObject = J9_JNI_UNWRAP_REFERENCE(recv);
393
clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, classObject);
394
romClass = clazz->romClass;
395
signature = getGenericSignatureForROMClass(vm, clazz->classLoader, romClass);
396
if (NULL != signature) {
397
j9object_t stringObject = vm->memoryManagerFunctions->j9gc_createJavaLangString(currentThread, J9UTF8_DATA(signature), J9UTF8_LENGTH(signature), 0);
398
result = vmFuncs->j9jni_createLocalRef(env, stringObject);
399
releaseOptInfoBuffer(vm, romClass);
400
}
401
vmFuncs->internalExitVMToJNI(currentThread);
402
return result;
403
}
404
405
/**
406
* Determines if a method is a normal method (not <clinit> or <init>).
407
*
408
* @param romMethod[in] the ROM method
409
*
410
* @returns true if the method is <init> or <clinit>, false if not
411
*/
412
static VMINLINE bool
413
isSpecialMethod(J9ROMMethod *romMethod)
414
{
415
return '<' == (char)*J9UTF8_DATA(J9ROMMETHOD_NAME(romMethod));
416
}
417
418
/**
419
* Determines if a method is <init>.
420
*
421
* @param romMethod[in] the ROM method
422
*
423
* @returns true if this is <init>, false if not
424
*/
425
static VMINLINE bool
426
isConstructor(J9ROMMethod *romMethod)
427
{
428
return (J9_ARE_NO_BITS_SET(romMethod->modifiers, J9AccStatic)) && isSpecialMethod(romMethod);
429
}
430
431
/**
432
* Determines if a method is a static method which should be reported.
433
*
434
* @param romMethod[in] the ROM method
435
*
436
* @returns true if this is public, static and not <clinit>, false if not
437
*/
438
static VMINLINE bool
439
isNormalStaticMethod(J9ROMMethod *romMethod)
440
{
441
return J9_ARE_ALL_BITS_SET(romMethod->modifiers, J9AccPublic | J9AccStatic) && !isSpecialMethod(romMethod);
442
}
443
444
/**
445
* Get the constructors for a Class.
446
*
447
* @param env[in] the JNIEnv
448
* @param recv[in] the receiver
449
* @param mustBePublic[in] true if only public methods are to be returned, false if not
450
*
451
* @returns true if this is <init>, false if not
452
*/
453
static jobject
454
getConstructorsHelper(JNIEnv *env, jobject recv, bool mustBePublic)
455
{
456
J9VMThread *currentThread = (J9VMThread*)env;
457
J9JavaVM *vm = currentThread->javaVM;
458
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
459
J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;
460
j9object_t resultObject = NULL;
461
vmFuncs->internalEnterVMFromJNI(currentThread);
462
463
J9Class *arrayClass = fetchArrayClass(currentThread, J9VMJAVALANGREFLECTCONSTRUCTOR_OR_NULL(vm));
464
465
retry:
466
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
467
J9ROMClass *romClass = clazz->romClass;
468
U_32 size = 0;
469
UDATA preCount = vm->hotSwapCount;
470
471
/* primitives/arrays don't have local methods */
472
if (!J9ROMCLASS_IS_PRIMITIVE_OR_ARRAY(romClass)) {
473
J9Method *currentMethod = clazz->ramMethods;
474
J9Method *endOfMethods = currentMethod + romClass->romMethodCount;
475
while (currentMethod != endOfMethods) {
476
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
477
if (isConstructor(romMethod) && (!mustBePublic || J9_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccPublic))) {
478
size += 1;
479
}
480
currentMethod += 1;
481
}
482
}
483
484
if (NULL != arrayClass) {
485
resultObject = mmFuncs->J9AllocateIndexableObject(currentThread, arrayClass, size, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
486
if (vm->hotSwapCount != preCount) {
487
goto retry;
488
} else if (NULL == resultObject) {
489
vmFuncs->setHeapOutOfMemoryError(currentThread);
490
} else {
491
J9Method *currentMethod = clazz->ramMethods;
492
U_32 index = 0;
493
J9Method *endOfMethods = currentMethod + romClass->romMethodCount;
494
while (currentMethod != endOfMethods) {
495
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
496
if (isConstructor(romMethod) && (!mustBePublic || J9_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccPublic))) {
497
PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, resultObject);
498
j9object_t element = vm->reflectFunctions.createConstructorObject(currentMethod, clazz, NULL, currentThread);
499
resultObject = POP_OBJECT_IN_SPECIAL_FRAME(currentThread);
500
if (vm->hotSwapCount != preCount) {
501
goto retry;
502
} else if (NULL == element) {
503
break;
504
}
505
J9JAVAARRAYOFOBJECT_STORE(currentThread, resultObject, index, element);
506
index += 1;
507
}
508
currentMethod += 1;
509
}
510
}
511
}
512
jobject result = vmFuncs->j9jni_createLocalRef(env, resultObject);
513
vmFuncs->internalExitVMToJNI(currentThread);
514
return result;
515
}
516
517
/**
518
* Get a particular constructor for a Class.
519
*
520
* @param env[in] the JNIEnv
521
* @param recv[in] the receiver
522
* @param parameterTypes[in] the parameter types array
523
* @param signature[in] the signature
524
* @param mustBePublic[in] true if only public methods are to be returned, false if not
525
*
526
* @returns true if this is <init>, false if not
527
*/
528
static jobject
529
getConstructorHelper(JNIEnv *env, jobject recv, jobject parameterTypes, jobject signature, bool mustBePublic)
530
{
531
J9VMThread *currentThread = (J9VMThread*)env;
532
J9JavaVM *vm = currentThread->javaVM;
533
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
534
j9object_t resultObject = NULL;
535
vmFuncs->internalEnterVMFromJNI(currentThread);
536
537
retry:
538
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
539
if (NULL == signature) {
540
vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL);
541
} else {
542
J9ROMClass *romClass = clazz->romClass;
543
/* primitives/arrays don't have local methods */
544
if (!J9ROMCLASS_IS_PRIMITIVE_OR_ARRAY(romClass)) {
545
j9object_t signatureObject = J9_JNI_UNWRAP_REFERENCE(signature);
546
J9Method *currentMethod = clazz->ramMethods;
547
J9Method *endOfMethods = currentMethod + romClass->romMethodCount;
548
UDATA preCount = vm->hotSwapCount;
549
while (currentMethod != endOfMethods) {
550
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
551
if (isConstructor(romMethod) && (!mustBePublic || J9_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccPublic))) {
552
J9UTF8 *signatureUTF = J9ROMMETHOD_SIGNATURE(romMethod);
553
if (0 != vmFuncs->compareStringToUTF8(currentThread, signatureObject, TRUE, J9UTF8_DATA(signatureUTF), J9UTF8_LENGTH(signatureUTF))) {
554
j9object_t parameterTypesObject = NULL;
555
if (NULL != parameterTypes) {
556
parameterTypesObject = J9_JNI_UNWRAP_REFERENCE(parameterTypes);
557
}
558
resultObject = vm->reflectFunctions.createConstructorObject(currentMethod, clazz, (j9array_t)parameterTypesObject, currentThread);
559
if (vm->hotSwapCount != preCount) {
560
goto retry;
561
}
562
break;
563
}
564
}
565
currentMethod += 1;
566
}
567
}
568
}
569
jobject result = vmFuncs->j9jni_createLocalRef(env, resultObject);
570
vmFuncs->internalExitVMToJNI(currentThread);
571
return result;
572
}
573
574
jobject JNICALL
575
Java_java_lang_Class_allocateAndFillArray(JNIEnv *env, jobject recv, jint size)
576
{
577
J9VMThread *currentThread = (J9VMThread*)env;
578
J9JavaVM *vm = currentThread->javaVM;
579
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
580
J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;
581
j9object_t resultObject = NULL;
582
vmFuncs->internalEnterVMFromJNI(currentThread);
583
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
584
J9Class *arrayClass = fetchArrayClass(currentThread, clazz);
585
if (NULL != arrayClass) {
586
resultObject = mmFuncs->J9AllocateIndexableObject(currentThread, arrayClass, (U_32)size, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
587
if (NULL == resultObject) {
588
oom:
589
vmFuncs->setHeapOutOfMemoryError(currentThread);
590
} else {
591
for (U_32 i = 0; i < (U_32)size; ++i) {
592
PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, resultObject);
593
j9object_t element = mmFuncs->J9AllocateObject(currentThread, clazz, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
594
resultObject = POP_OBJECT_IN_SPECIAL_FRAME(currentThread);
595
if (NULL == element) {
596
goto oom;
597
}
598
J9JAVAARRAYOFOBJECT_STORE(currentThread, resultObject, i, element);
599
}
600
}
601
}
602
jobject result = vmFuncs->j9jni_createLocalRef(env, resultObject);
603
vmFuncs->internalExitVMToJNI(currentThread);
604
return result;
605
}
606
607
jobject JNICALL
608
Java_java_lang_Class_getConstructorImpl(JNIEnv *env, jobject recv, jobject parameterTypes, jobject signature)
609
{
610
return getConstructorHelper(env, recv, parameterTypes, signature, true);
611
}
612
613
jobject JNICALL
614
Java_java_lang_Class_getConstructorsImpl(JNIEnv *env, jobject recv)
615
{
616
return getConstructorsHelper(env, recv, true);
617
}
618
619
jobject JNICALL
620
Java_java_lang_Class_getDeclaredClassesImpl(JNIEnv *env, jobject recv)
621
{
622
J9VMThread *currentThread = (J9VMThread*)env;
623
J9JavaVM *vm = currentThread->javaVM;
624
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
625
J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;
626
j9object_t resultObject = NULL;
627
vmFuncs->internalEnterVMFromJNI(currentThread);
628
J9Class *arrayClass = fetchArrayClass(currentThread, J9VMJAVALANGCLASS_OR_NULL(vm));
629
630
retry:
631
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
632
J9ROMClass *romClass = clazz->romClass;
633
U_32 size = romClass->innerClassCount;
634
UDATA preCount = vm->hotSwapCount;
635
636
if (NULL != arrayClass) {
637
resultObject = mmFuncs->J9AllocateIndexableObject(currentThread, arrayClass, size, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
638
if (vm->hotSwapCount != preCount) {
639
goto retry;
640
} else if (NULL == resultObject) {
641
vmFuncs->setHeapOutOfMemoryError(currentThread);
642
} else {
643
J9ClassLoader *classLoader = clazz->classLoader;
644
J9SRP *innerClasses = J9ROMCLASS_INNERCLASSES(romClass);
645
646
for (U_32 i = 0; i < size; ++i) {
647
J9UTF8 *className = NNSRP_PTR_GET(innerClasses, J9UTF8*);
648
PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, resultObject);
649
J9Class *innerClazz = vmFuncs->internalFindClassUTF8(currentThread, J9UTF8_DATA(className), J9UTF8_LENGTH(className), classLoader, J9_FINDCLASS_FLAG_THROW_ON_FAIL);
650
resultObject = POP_OBJECT_IN_SPECIAL_FRAME(currentThread);
651
if (vm->hotSwapCount != preCount) {
652
goto retry;
653
}
654
if (NULL == innerClazz) {
655
break;
656
}
657
J9JAVAARRAYOFOBJECT_STORE(currentThread, resultObject, i, J9VM_J9CLASS_TO_HEAPCLASS(innerClazz));
658
innerClasses += 1;
659
}
660
}
661
}
662
jobject result = vmFuncs->j9jni_createLocalRef(env, resultObject);
663
vmFuncs->internalExitVMToJNI(currentThread);
664
return result;
665
}
666
667
jobject JNICALL
668
Java_java_lang_Class_getDeclaredConstructorImpl(JNIEnv *env, jobject recv, jobject parameterTypes, jobject signature)
669
{
670
return getConstructorHelper(env, recv, parameterTypes, signature, false);
671
}
672
673
jobject JNICALL
674
Java_java_lang_Class_getDeclaredConstructorsImpl(JNIEnv *env, jobject recv)
675
{
676
return getConstructorsHelper(env, recv, false);
677
}
678
679
jobject JNICALL
680
Java_java_lang_Class_getDeclaredMethodImpl(JNIEnv *env, jobject recv, jobject name, jobject parameterTypes, jobject partialSignature, jobject startingPoint)
681
{
682
J9VMThread *currentThread = (J9VMThread*)env;
683
J9JavaVM *vm = currentThread->javaVM;
684
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
685
j9object_t resultObject = NULL;
686
vmFuncs->internalEnterVMFromJNI(currentThread);
687
688
retry:
689
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
690
if ((NULL == name) || (NULL == partialSignature)) {
691
vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL);
692
} else {
693
J9ROMClass *romClass = clazz->romClass;
694
UDATA preCount = vm->hotSwapCount;
695
696
/* primitives/arrays don't have local methods */
697
if (!J9ROMCLASS_IS_PRIMITIVE_OR_ARRAY(romClass)) {
698
j9object_t nameObject = J9_JNI_UNWRAP_REFERENCE(name);
699
j9object_t signatureObject = J9_JNI_UNWRAP_REFERENCE(partialSignature);
700
J9Method *currentMethod = clazz->ramMethods;
701
J9Method *endOfMethods = currentMethod + romClass->romMethodCount;
702
if (NULL != startingPoint) {
703
j9object_t methodObject = J9_JNI_UNWRAP_REFERENCE(startingPoint);
704
J9JNIMethodID *id = vm->reflectFunctions.idFromMethodObject(currentThread, methodObject);
705
currentMethod = id->method + 1;
706
}
707
while (currentMethod != endOfMethods) {
708
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
709
if (!isSpecialMethod(romMethod)) {
710
J9UTF8 *nameUTF = J9ROMMETHOD_NAME(romMethod);
711
J9UTF8 *signatureUTF = J9ROMMETHOD_SIGNATURE(romMethod);
712
if (0 != vmFuncs->compareStringToUTF8(currentThread, nameObject, FALSE, J9UTF8_DATA(nameUTF), J9UTF8_LENGTH(nameUTF))) {
713
if (0 != compareJavaStringToPartialUTF8(currentThread, signatureObject, J9UTF8_DATA(signatureUTF), J9UTF8_LENGTH(signatureUTF))) {
714
j9object_t parameterTypesObject = NULL;
715
if (NULL != parameterTypes) {
716
parameterTypesObject = J9_JNI_UNWRAP_REFERENCE(parameterTypes);
717
}
718
resultObject = vm->reflectFunctions.createDeclaredMethodObject(currentMethod, clazz, (j9array_t)parameterTypesObject, currentThread);
719
if (vm->hotSwapCount != preCount) {
720
goto retry;
721
}
722
break;
723
}
724
}
725
}
726
currentMethod += 1;
727
}
728
}
729
}
730
jobject result = vmFuncs->j9jni_createLocalRef(env, resultObject);
731
vmFuncs->internalExitVMToJNI(currentThread);
732
return result;
733
}
734
735
jobject JNICALL
736
Java_java_lang_Class_getDeclaredMethodsImpl(JNIEnv *env, jobject recv)
737
{
738
J9VMThread *currentThread = (J9VMThread*)env;
739
J9JavaVM *vm = currentThread->javaVM;
740
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
741
J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;
742
j9object_t resultObject = NULL;
743
vmFuncs->internalEnterVMFromJNI(currentThread);
744
J9Class *arrayClass = fetchArrayClass(currentThread, J9VMJAVALANGREFLECTMETHOD_OR_NULL(vm));
745
746
retry:
747
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
748
J9ROMClass *romClass = clazz->romClass;
749
U_32 size = 0;
750
UDATA preCount = vm->hotSwapCount;
751
752
/* primitives/arrays don't have local methods */
753
if (!J9ROMCLASS_IS_PRIMITIVE_OR_ARRAY(romClass)) {
754
J9Method *currentMethod = clazz->ramMethods;
755
J9Method *endOfMethods = currentMethod + romClass->romMethodCount;
756
while (currentMethod != endOfMethods) {
757
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
758
if (!isSpecialMethod(romMethod)) {
759
size += 1;
760
}
761
currentMethod += 1;
762
}
763
}
764
765
if (NULL != arrayClass) {
766
resultObject = mmFuncs->J9AllocateIndexableObject(currentThread, arrayClass, size, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
767
if (vm->hotSwapCount != preCount) {
768
goto retry;
769
} else if (NULL == resultObject) {
770
vmFuncs->setHeapOutOfMemoryError(currentThread);
771
} else {
772
J9Method *currentMethod = clazz->ramMethods;
773
U_32 index = 0;
774
J9Method *endOfMethods = currentMethod + romClass->romMethodCount;
775
while (currentMethod != endOfMethods) {
776
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
777
if (!isSpecialMethod(romMethod)) {
778
PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, resultObject);
779
j9object_t element = vm->reflectFunctions.createDeclaredMethodObject(currentMethod, clazz, NULL, currentThread);
780
resultObject = POP_OBJECT_IN_SPECIAL_FRAME(currentThread);
781
if (vm->hotSwapCount != preCount) {
782
goto retry;
783
}
784
if (NULL == element) {
785
break;
786
}
787
J9JAVAARRAYOFOBJECT_STORE(currentThread, resultObject, index, element);
788
index += 1;
789
}
790
currentMethod += 1;
791
}
792
}
793
}
794
jobject result = vmFuncs->j9jni_createLocalRef(env, resultObject);
795
vmFuncs->internalExitVMToJNI(currentThread);
796
return result;
797
}
798
799
jobject JNICALL
800
Java_java_lang_Class_getDeclaringClassImpl(JNIEnv *env, jobject recv)
801
{
802
J9VMThread *currentThread = (J9VMThread*)env;
803
J9JavaVM *vm = currentThread->javaVM;
804
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
805
j9object_t resultObject = NULL;
806
vmFuncs->internalEnterVMFromJNI(currentThread);
807
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
808
J9ROMClass *romClass = clazz->romClass;
809
J9UTF8 *outerClassName = J9ROMCLASS_OUTERCLASSNAME(romClass);
810
if (NULL != outerClassName) {
811
J9Class *outerClass = vmFuncs->internalFindClassUTF8(currentThread, J9UTF8_DATA(outerClassName), J9UTF8_LENGTH(outerClassName), clazz->classLoader, J9_FINDCLASS_FLAG_THROW_ON_FAIL);
812
resultObject = J9VM_J9CLASS_TO_HEAPCLASS(outerClass);
813
}
814
jobject result = vmFuncs->j9jni_createLocalRef(env, resultObject);
815
vmFuncs->internalExitVMToJNI(currentThread);
816
return result;
817
}
818
819
jobject JNICALL
820
Java_java_lang_Class_getEnclosingObject(JNIEnv *env, jobject recv)
821
{
822
J9VMThread *currentThread = (J9VMThread*)env;
823
J9JavaVM *vm = currentThread->javaVM;
824
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
825
j9object_t resultObject = NULL;
826
vmFuncs->internalEnterVMFromJNI(currentThread);
827
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
828
J9ROMClass *romClass = clazz->romClass;
829
/* primitives/arrays don't have enclosing objects */
830
if (!J9ROMCLASS_IS_PRIMITIVE_OR_ARRAY(romClass)) {
831
J9EnclosingObject *methodRef = getEnclosingMethodForROMClass(vm, clazz->classLoader, romClass);
832
if (NULL != methodRef) {
833
J9ROMNameAndSignature *nas = J9ENCLOSINGOBJECT_NAMEANDSIGNATURE(methodRef);
834
if (NULL != nas) {
835
J9Class *resolvedClass = vmFuncs->resolveClassRef(currentThread, J9_CP_FROM_CLASS(clazz), methodRef->classRefCPIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE);
836
if (NULL != resolvedClass) {
837
J9UTF8 *enclosingMethodNameUTF = J9ROMNAMEANDSIGNATURE_NAME(nas);
838
J9UTF8 *enclosingMethodSigUTF = J9ROMNAMEANDSIGNATURE_SIGNATURE(nas);
839
J9Method *method = vmFuncs->searchClassForMethod(resolvedClass, J9UTF8_DATA(enclosingMethodNameUTF), J9UTF8_LENGTH(enclosingMethodNameUTF), J9UTF8_DATA(enclosingMethodSigUTF), J9UTF8_LENGTH(enclosingMethodSigUTF));
840
if (NULL != method) {
841
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);
842
if (!isSpecialMethod(romMethod)) {
843
resultObject = vm->reflectFunctions.createDeclaredMethodObject(method, resolvedClass, NULL, currentThread);
844
} else if (isConstructor(romMethod)) {
845
resultObject = vm->reflectFunctions.createDeclaredConstructorObject(method, resolvedClass, NULL, currentThread);
846
}
847
}
848
}
849
}
850
releaseOptInfoBuffer(vm, romClass);
851
}
852
}
853
jobject result = vmFuncs->j9jni_createLocalRef(env, resultObject);
854
vmFuncs->internalExitVMToJNI(currentThread);
855
return result;
856
}
857
858
jobject JNICALL
859
Java_java_lang_Class_getEnclosingObjectClass(JNIEnv *env, jobject recv)
860
{
861
J9VMThread *currentThread = (J9VMThread*)env;
862
J9JavaVM *vm = currentThread->javaVM;
863
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
864
j9object_t resultObject = NULL;
865
vmFuncs->internalEnterVMFromJNI(currentThread);
866
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
867
J9ROMClass *romClass = clazz->romClass;
868
/* primitives/arrays don't have enclosing objects */
869
if (!J9ROMCLASS_IS_PRIMITIVE_OR_ARRAY(romClass)) {
870
J9EnclosingObject *methodRef = getEnclosingMethodForROMClass(vm, clazz->classLoader, romClass);
871
if (NULL != methodRef) {
872
J9Class *resolvedClass = vmFuncs->resolveClassRef(currentThread, J9_CP_FROM_CLASS(clazz), methodRef->classRefCPIndex, J9_RESOLVE_FLAG_RUNTIME_RESOLVE);
873
resultObject = J9VM_J9CLASS_TO_HEAPCLASS(resolvedClass);
874
releaseOptInfoBuffer(vm, romClass);
875
}
876
}
877
jobject result = vmFuncs->j9jni_createLocalRef(env, resultObject);
878
vmFuncs->internalExitVMToJNI(currentThread);
879
return result;
880
}
881
882
jobject JNICALL
883
Java_java_lang_Class_getFieldImpl(JNIEnv *env, jobject recv, jstring name)
884
{
885
return getFieldHelper(env, recv, name);
886
}
887
888
jobject JNICALL
889
Java_java_lang_Class_getDeclaredFieldImpl(JNIEnv *env, jobject recv, jstring name)
890
{
891
return getDeclaredFieldHelper(env, recv, name);
892
}
893
894
jarray JNICALL
895
Java_java_lang_Class_getFieldsImpl(JNIEnv *env, jobject recv)
896
{
897
return getFieldsHelper(env, recv);
898
}
899
900
jobject JNICALL
901
Java_java_lang_Class_getMethodImpl(JNIEnv *env, jobject recv, jobject name, jobject parameterTypes, jobject partialSignature)
902
{
903
J9VMThread *currentThread = (J9VMThread*)env;
904
J9JavaVM *vm = currentThread->javaVM;
905
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
906
j9object_t resultObject = NULL;
907
vmFuncs->internalEnterVMFromJNI(currentThread);
908
909
PORT_ACCESS_FROM_VMC(currentThread);
910
if ((NULL == name) || (NULL == partialSignature)) {
911
vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL);
912
} else {
913
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
914
J9ROMClass *romClass = clazz->romClass;
915
916
/* primitives doesn't have local methods */
917
if (!J9ROMCLASS_IS_PRIMITIVE_TYPE(romClass)) {
918
J9Method *currentMethod = NULL;
919
j9object_t nameObject = J9_JNI_UNWRAP_REFERENCE(name);
920
j9object_t signatureObject = J9_JNI_UNWRAP_REFERENCE(partialSignature);
921
UDATA lookupFLags = J9_LOOK_JNI | J9_LOOK_NO_THROW | J9_LOOK_PARTIAL_SIGNATURE | (J9ROMCLASS_IS_INTERFACE(romClass) ? (J9_LOOK_INTERFACE | J9_LOOK_NO_JLOBJECT) : 0);
922
923
J9JNINameAndSignature nameAndSig;
924
char nameBuffer[J9VM_PACKAGE_NAME_BUFFER_LENGTH];
925
UDATA nameBufferLength = 0;
926
char signatureBuffer[J9VM_PACKAGE_NAME_BUFFER_LENGTH];
927
UDATA signatureLength = 0;
928
nameAndSig.name = nameBuffer;
929
nameAndSig.nameLength = 0;
930
nameAndSig.signature = signatureBuffer;
931
nameAndSig.signatureLength = 0;
932
933
nameAndSig.name = vmFuncs->copyStringToUTF8WithMemAlloc(
934
currentThread, nameObject, J9_STR_NULL_TERMINATE_RESULT, "", 0, nameBuffer, J9VM_PACKAGE_NAME_BUFFER_LENGTH, &nameBufferLength);
935
if (NULL == nameAndSig.name) {
936
goto _done;
937
}
938
nameAndSig.nameLength = (U_32)nameBufferLength;
939
940
nameAndSig.signature = vmFuncs->copyStringToUTF8WithMemAlloc(
941
currentThread, signatureObject, J9_STR_NULL_TERMINATE_RESULT | J9_STR_XLAT, "", 0, signatureBuffer, J9VM_PACKAGE_NAME_BUFFER_LENGTH, &signatureLength);
942
if (NULL == nameAndSig.signature) {
943
goto _done;
944
}
945
nameAndSig.signatureLength = (U_32)signatureLength;
946
947
currentMethod = (J9Method *) vmFuncs->javaLookupMethodImpl(currentThread, clazz, ((J9ROMNameAndSignature *) &nameAndSig), NULL, lookupFLags, NULL);
948
if (NULL == currentMethod) { /* by default we look for virtual methods. Try static methods. */
949
lookupFLags |= J9_LOOK_STATIC;
950
currentMethod = (J9Method *) vmFuncs->javaLookupMethodImpl(currentThread, clazz, ((J9ROMNameAndSignature *) &nameAndSig), NULL, lookupFLags, NULL);
951
}
952
953
954
Trc_JCL_getMethodImpl_result(currentThread, nameAndSig.nameLength, nameAndSig.name, nameAndSig.signatureLength, nameAndSig.signature, currentMethod);
955
_done:
956
if (nameAndSig.name != nameBuffer) {
957
j9mem_free_memory((void *)nameAndSig.name);
958
}
959
if (nameAndSig.signature != signatureBuffer) {
960
j9mem_free_memory((void *)nameAndSig.signature);
961
}
962
963
if (NULL != currentMethod) {
964
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
965
if (J9_ARE_ALL_BITS_SET(romMethod->modifiers, J9AccPublic) && !isSpecialMethod(romMethod)) {
966
j9object_t parameterTypesObject = NULL;
967
if (NULL != parameterTypes) {
968
parameterTypesObject = J9_JNI_UNWRAP_REFERENCE(parameterTypes);
969
}
970
resultObject = vm->reflectFunctions.createMethodObject(currentMethod, clazz, (j9array_t)parameterTypesObject, currentThread);
971
}
972
}
973
}
974
}
975
jobject result = vmFuncs->j9jni_createLocalRef(env, resultObject);
976
vmFuncs->internalExitVMToJNI(currentThread);
977
return result;
978
}
979
980
jint JNICALL
981
Java_java_lang_Class_getStaticMethodCountImpl(JNIEnv *env, jobject recv)
982
{
983
J9VMThread *currentThread = (J9VMThread*)env;
984
J9JavaVM *vm = currentThread->javaVM;
985
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
986
jint result = 0;
987
vmFuncs->internalEnterVMFromJNI(currentThread);
988
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
989
do {
990
J9ROMClass *romClass = clazz->romClass;
991
J9Method *currentMethod = clazz->ramMethods;
992
J9Method *endOfMethods = currentMethod + romClass->romMethodCount;
993
while (currentMethod != endOfMethods) {
994
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
995
if (isNormalStaticMethod(romMethod)) {
996
result += 1;
997
}
998
currentMethod += 1;
999
}
1000
clazz = VM_VMHelpers::getSuperclass(clazz);
1001
} while (NULL != clazz);
1002
vmFuncs->internalExitVMToJNI(currentThread);
1003
return result;
1004
}
1005
1006
jboolean JNICALL
1007
Java_java_lang_Class_getStaticMethodsImpl(JNIEnv *env, jobject recv, jobject array, jint start, jint count)
1008
{
1009
J9VMThread *currentThread = (J9VMThread*)env;
1010
J9JavaVM *vm = currentThread->javaVM;
1011
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
1012
vmFuncs->internalEnterVMFromJNI(currentThread);
1013
1014
jboolean result = JNI_TRUE;
1015
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
1016
U_32 index = (U_32)start;
1017
jint numMethodFound = 0;
1018
UDATA preCount = vm->hotSwapCount;
1019
1020
do {
1021
J9ROMClass *romClass = clazz->romClass;
1022
J9Method *currentMethod = clazz->ramMethods;
1023
J9Method *endOfMethods = currentMethod + romClass->romMethodCount;
1024
1025
while ((currentMethod != endOfMethods) && (numMethodFound < count)) {
1026
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
1027
if (isNormalStaticMethod(romMethod)) {
1028
J9JNIMethodID *methodID = vmFuncs->getJNIMethodID(currentThread, currentMethod);
1029
j9object_t resultObject = J9_JNI_UNWRAP_REFERENCE(array);
1030
j9object_t methodObject = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultObject, index);
1031
vm->reflectFunctions.fillInReflectMethod(methodObject, clazz, (jmethodID)methodID, currentThread);
1032
if (VM_VMHelpers::exceptionPending(currentThread)) {
1033
goto done;
1034
}
1035
index += 1;
1036
numMethodFound += 1;
1037
}
1038
currentMethod += 1;
1039
if (vm->hotSwapCount != preCount) {
1040
result = JNI_FALSE;
1041
goto done;
1042
}
1043
}
1044
clazz = VM_VMHelpers::getSuperclass(clazz);
1045
} while (NULL != clazz);
1046
1047
if (numMethodFound != count) {
1048
result = JNI_FALSE;
1049
}
1050
done:
1051
vmFuncs->internalExitVMToJNI(currentThread);
1052
return result;
1053
}
1054
1055
jint JNICALL
1056
Java_java_lang_Class_getVirtualMethodCountImpl(JNIEnv *env, jobject recv)
1057
{
1058
J9VMThread *currentThread = (J9VMThread*)env;
1059
J9JavaVM *vm = currentThread->javaVM;
1060
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
1061
vmFuncs->internalEnterVMFromJNI(currentThread);
1062
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
1063
1064
J9VTableHeader *vTableHeader = J9VTABLE_HEADER_FROM_RAM_CLASS(clazz);
1065
UDATA count = vTableHeader->size;
1066
J9Method **vTableMethods = J9VTABLE_FROM_HEADER(vTableHeader);
1067
/* assuming constant number of public final methods in java.lang.Object */
1068
jint result = 6;
1069
for (UDATA index = 0; index < count; ++index) {
1070
J9Method *currentMethod = vTableMethods[index];
1071
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
1072
if (J9_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccPublic)) {
1073
if (VM_VMHelpers::hasDefaultConflictSendTarget(currentMethod)) {
1074
/*
1075
* PR 104809: getMethods() does not report multiple default implementations of the same method.
1076
* The method pointer has a link to the actual conflicting method. Return the method that's actually in the VTable.
1077
* Class.getMethods() will pick up the alternate implementation when it scans the class's interfaces.
1078
*/
1079
currentMethod = (J9Method *) (((UDATA)currentMethod->extra) & ~J9_STARTPC_NOT_TRANSLATED);
1080
}
1081
/* found a candidate, now reverse scan for a duplicate */
1082
for (UDATA scan = 0; scan < index; ++scan) {
1083
if (currentMethod == vTableMethods[scan]) {
1084
goto skip;
1085
}
1086
}
1087
result += 1;
1088
}
1089
skip: ;
1090
}
1091
vmFuncs->internalExitVMToJNI(currentThread);
1092
return result;
1093
}
1094
1095
jboolean JNICALL
1096
Java_java_lang_Class_getVirtualMethodsImpl(JNIEnv *env, jobject recv, jobject array, jint start, jint count)
1097
{
1098
J9VMThread *currentThread = (J9VMThread*)env;
1099
J9JavaVM *vm = currentThread->javaVM;
1100
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
1101
vmFuncs->internalEnterVMFromJNI(currentThread);
1102
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
1103
U_32 index = (U_32)start;
1104
jint numMethodFound = 0;
1105
jboolean result = JNI_TRUE;
1106
UDATA preCount = vm->hotSwapCount;
1107
1108
/* First walk the vTable */
1109
{
1110
J9VTableHeader *vTableHeader = J9VTABLE_HEADER_FROM_RAM_CLASS(clazz);
1111
UDATA vTableSize = vTableHeader->size;
1112
J9Method **vTableMethods = J9VTABLE_FROM_HEADER(vTableHeader);
1113
for (UDATA progress = 0; ((progress < vTableSize) && (numMethodFound < count)); ++progress) {
1114
J9Method *currentMethod = vTableMethods[progress];
1115
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
1116
if (J9_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccPublic)) {
1117
if (VM_VMHelpers::hasDefaultConflictSendTarget(currentMethod)) {
1118
/*
1119
* PR 104809: getMethods() does not report multiple default implementations of the same method.
1120
* Does this affect Class.getMethods()?
1121
*/
1122
currentMethod = (J9Method *) (((UDATA)currentMethod->extra) & ~J9_STARTPC_NOT_TRANSLATED);
1123
}
1124
/* found a candidate, now reverse scan for a duplicate */
1125
for (UDATA scan = 0; scan < progress; ++scan) {
1126
if (currentMethod == vTableMethods[scan]) {
1127
goto skip;
1128
}
1129
}
1130
J9Class *declaringClass = J9_CLASS_FROM_METHOD(currentMethod);
1131
J9JNIMethodID *methodID = vmFuncs->getJNIMethodID(currentThread, currentMethod);
1132
j9object_t resultObject = J9_JNI_UNWRAP_REFERENCE(array);
1133
j9object_t methodObject = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultObject, index);
1134
vm->reflectFunctions.fillInReflectMethod(methodObject, declaringClass, (jmethodID)methodID, currentThread);
1135
if (VM_VMHelpers::exceptionPending(currentThread)) {
1136
goto done;
1137
}
1138
index += 1;
1139
numMethodFound += 1;
1140
}
1141
1142
if (vm->hotSwapCount != preCount) {
1143
result = JNI_FALSE;
1144
goto done;
1145
}
1146
skip: ;
1147
}
1148
}
1149
/* Now add the public final methods from Object */
1150
{
1151
J9Class *objectClass = J9VMJAVALANGOBJECT_OR_NULL(vm);
1152
J9ROMClass *romClass = objectClass->romClass;
1153
J9Method *currentMethod = objectClass->ramMethods;
1154
J9Method *endOfMethods = currentMethod + romClass->romMethodCount;
1155
while ((currentMethod != endOfMethods) && (numMethodFound < count)) {
1156
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
1157
if (J9_ARE_ALL_BITS_SET(romMethod->modifiers, J9AccPublic | J9AccFinal)) {
1158
J9JNIMethodID *methodID = vmFuncs->getJNIMethodID(currentThread, currentMethod);
1159
j9object_t resultObject = J9_JNI_UNWRAP_REFERENCE(array);
1160
j9object_t methodObject = J9JAVAARRAYOFOBJECT_LOAD(currentThread, resultObject, index);
1161
vm->reflectFunctions.fillInReflectMethod(methodObject, objectClass, (jmethodID)methodID, currentThread);
1162
if (VM_VMHelpers::exceptionPending(currentThread)) {
1163
goto done;
1164
}
1165
index += 1;
1166
numMethodFound += 1;
1167
}
1168
1169
if (vm->hotSwapCount != preCount) {
1170
result = JNI_FALSE;
1171
goto done;
1172
}
1173
1174
currentMethod += 1;
1175
}
1176
1177
if (numMethodFound != count) {
1178
result = JNI_FALSE;
1179
goto done;
1180
}
1181
}
1182
done:
1183
vmFuncs->internalExitVMToJNI(currentThread);
1184
return result;
1185
}
1186
1187
#if JAVA_SPEC_VERSION >= 14
1188
jarray JNICALL
1189
Java_java_lang_Class_getRecordComponentsImpl(JNIEnv *env, jobject cls)
1190
{
1191
return getRecordComponentsHelper(env, cls);
1192
}
1193
#endif /* JAVA_SPEC_VERSION >= 14 */
1194
1195
jarray JNICALL
1196
Java_java_lang_Class_permittedSubclassesImpl(JNIEnv *env, jobject cls)
1197
{
1198
return permittedSubclassesHelper(env, cls);
1199
}
1200
1201
static UDATA
1202
frameIteratorGetAccSnapshotHelper(J9VMThread * currentThread, J9StackWalkState * walkState, j9object_t acc, j9object_t perm)
1203
{
1204
PORT_ACCESS_FROM_VMC(currentThread);
1205
1206
DoPrivilegedMethodArgs* doPrivilegedMethodsArgs = (DoPrivilegedMethodArgs*)walkState->userData2;
1207
DoPrivilegedMethodArgs* doPrivilegedMethodsArgsTmp = (DoPrivilegedMethodArgs*)j9mem_allocate_memory(sizeof(DoPrivilegedMethodArgs), J9MEM_CATEGORY_VM_JCL);
1208
if (NULL == doPrivilegedMethodsArgsTmp) {
1209
currentThread->javaVM->internalVMFunctions->setNativeOutOfMemoryError(currentThread, 0, 0);
1210
return J9_STACKWALK_STOP_ITERATING;
1211
}
1212
memset(doPrivilegedMethodsArgsTmp, 0, sizeof(DoPrivilegedMethodArgs));
1213
1214
doPrivilegedMethodsArgsTmp->accControlContext = acc;
1215
doPrivilegedMethodsArgsTmp->permissions = perm;
1216
while (NULL != doPrivilegedMethodsArgs->next) {
1217
doPrivilegedMethodsArgs = doPrivilegedMethodsArgs->next;
1218
}
1219
doPrivilegedMethodsArgs->next = doPrivilegedMethodsArgsTmp;
1220
return J9_STACKWALK_KEEP_ITERATING;
1221
}
1222
1223
/**
1224
* PrivilegedFrameIterator method to perform stack walking for doPrivileged & doPrivilegedWithCombiner methods
1225
* For doPrivileged methods, this finds the callers of each doPrivileged method and the AccessControlContext discovered during stack walking,
1226
* either from a privilege frame or the contextObject from current thread
1227
* For doPrivilegedWithCombiner, this finds the caller of doPrivilegedWithCombiner method, and the AccessControlContext
1228
* discovered during stack walking, either from a privilege frame or the contextObject from current thread
1229
*
1230
* Notes:
1231
* walkState.userData1
1232
* initial value is STACK_WALK_STATE_MAGIC((void*)1), set to NULL when a limited doPrivileged frame is discovered
1233
* walkState.userData2
1234
* initial value is contextObject from current thread, set to DoPrivilegedMethodArgs* when a limited doPrivileged frame is discovered
1235
* walkState.userData3
1236
* initial value is STACK_WALK_STATE_MAGIC((void*)1),
1237
* set to STACK_WALK_STATE_LIMITED_DOPRIVILEGED((void*)2) for searching the caller of a limited doPrivileged method,
1238
* and reset to STACK_WALK_STATE_MAGIC after identified the caller of that limited doPrivileged method
1239
* set to STACK_WALK_STATE_FULL_DOPRIVILEGED ((void*)3) for searching the caller of a full privileged doPrivileged method,
1240
* there is no need for resetting cause PrivilegedFrameIterator method exits with J9_STACKWALK_STOP_ITERATING
1241
* walkState.userData4 (only for doPrivilegedWithCombiner)
1242
* initial value is NULL, set to walkState->framesWalked when found the non reflection/MethodHandleInvoke frame caller of doPrivilegedWithCombiner
1243
*
1244
* @param currentThread the VM Thread
1245
* @param walkState the stack walk state
1246
*
1247
* @return J9_STACKWALK_STOP_ITERATING, J9_STACKWALK_KEEP_ITERATING
1248
*/
1249
static UDATA
1250
isPrivilegedFrameIteratorGetAccSnapshot(J9VMThread * currentThread, J9StackWalkState * walkState)
1251
{
1252
J9JavaVM *vm = currentThread->javaVM;
1253
PORT_ACCESS_FROM_JAVAVM(vm);
1254
J9JNIMethodID *doPrivilegedMethodID1 = (J9JNIMethodID *) vm->doPrivilegedMethodID1;
1255
J9JNIMethodID *doPrivilegedMethodID2 = (J9JNIMethodID *) vm->doPrivilegedMethodID2;
1256
J9JNIMethodID *doPrivilegedWithContextMethodID1 = (J9JNIMethodID *) vm->doPrivilegedWithContextMethodID1;
1257
J9JNIMethodID *doPrivilegedWithContextMethodID2 = (J9JNIMethodID *) vm->doPrivilegedWithContextMethodID2;
1258
J9JNIMethodID *doPrivilegedWithContextPermissionMethodID1 = (J9JNIMethodID *) vm->doPrivilegedWithContextPermissionMethodID1;
1259
J9JNIMethodID *doPrivilegedWithContextPermissionMethodID2 = (J9JNIMethodID *) vm->doPrivilegedWithContextPermissionMethodID2;
1260
J9Method *currentMethod = walkState->method;
1261
1262
if (J9_ARE_ALL_BITS_SET(J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod)->modifiers, J9AccMethodFrameIteratorSkip)) {
1263
/* Skip methods with java.lang.invoke.FrameIteratorSkip / jdk.internal.vm.annotation.Hidden / java.lang.invoke.LambdaForm$Hidden annotation */
1264
return J9_STACKWALK_KEEP_ITERATING;
1265
}
1266
1267
if ((NULL == walkState->userData4)
1268
|| (STACK_WALK_STATE_LIMITED_DOPRIVILEGED == walkState->userData3)
1269
|| (STACK_WALK_STATE_FULL_DOPRIVILEGED == walkState->userData3)
1270
) {
1271
/* find the callers of each doPrivileged method */
1272
J9Class * currentClass = J9_CLASS_FROM_CP(walkState->constantPool);
1273
if ((walkState->method == vm->jlrMethodInvoke)
1274
#if JAVA_SPEC_VERSION >= 18
1275
|| (walkState->method == vm->jlrMethodInvokeMH)
1276
#endif /* JAVA_SPEC_VERSION >= 18 */
1277
|| (walkState->method == vm->jliMethodHandleInvokeWithArgs)
1278
|| (walkState->method == vm->jliMethodHandleInvokeWithArgsList)
1279
|| (vm->srMethodAccessor && VM_VMHelpers::isSameOrSuperclass(J9VM_J9CLASS_FROM_JCLASS(currentThread, vm->srMethodAccessor), currentClass))
1280
) {
1281
/* skip reflection/MethodHandleInvoke frames */
1282
return J9_STACKWALK_KEEP_ITERATING;
1283
} else {
1284
if (NULL == walkState->userData4) {
1285
/* find the caller of doPrivilegedWithCombiner */
1286
walkState->userData4 = (void*)walkState->framesWalked;
1287
} else {
1288
if (STACK_WALK_STATE_FULL_DOPRIVILEGED == walkState->userData3) {
1289
/* find the caller of full doPrivileged method */
1290
return J9_STACKWALK_STOP_ITERATING;
1291
}
1292
/* find the caller of limited doPrivileged method */
1293
Assert_JCL_notNull(walkState->userData2);
1294
DoPrivilegedMethodArgs* doPrivilegedMethodsArgs = (DoPrivilegedMethodArgs*)walkState->userData2;
1295
while (NULL != doPrivilegedMethodsArgs->next) {
1296
doPrivilegedMethodsArgs = doPrivilegedMethodsArgs->next;
1297
}
1298
doPrivilegedMethodsArgs->frameCounter = walkState->framesWalked;
1299
/* reset to magic value to finish the search for the caller of current limited doPrivileged method */
1300
walkState->userData3 = STACK_WALK_STATE_MAGIC;
1301
}
1302
}
1303
}
1304
1305
if ( ((doPrivilegedMethodID1 != NULL) && (currentMethod == doPrivilegedMethodID1->method))
1306
|| ((doPrivilegedMethodID2 != NULL) && (currentMethod == doPrivilegedMethodID2->method))
1307
) {
1308
/* Context is NULL */
1309
walkState->userData3 = STACK_WALK_STATE_FULL_DOPRIVILEGED;
1310
if (NULL == walkState->userData1) { /* a limited doPrivileged frame was discovered */
1311
return frameIteratorGetAccSnapshotHelper(currentThread, walkState, NULL, NULL);
1312
} else {
1313
walkState->userData2 = NULL; /* set NULL context */
1314
}
1315
}
1316
1317
if ( ((doPrivilegedWithContextMethodID1 != NULL) && (currentMethod == doPrivilegedWithContextMethodID1->method)) ||
1318
((doPrivilegedWithContextMethodID2 != NULL) && (currentMethod == doPrivilegedWithContextMethodID2->method))
1319
) {
1320
/* Grab the Context from the arguments: ultra-scary: fetch arg2 from the doPrivileged() method */
1321
walkState->userData3 = STACK_WALK_STATE_FULL_DOPRIVILEGED;
1322
if (NULL == walkState->userData1) { /* a limited doPrivileged frame was discovered */
1323
return frameIteratorGetAccSnapshotHelper(currentThread, walkState, (j9object_t)walkState->arg0EA[-1], NULL);
1324
} else {
1325
walkState->userData2 = (void *)walkState->arg0EA[-1]; /* grab context from doPrivileged frame */
1326
}
1327
}
1328
1329
if ( ((doPrivilegedWithContextPermissionMethodID1 != NULL) && (currentMethod == doPrivilegedWithContextPermissionMethodID1->method))
1330
|| ((doPrivilegedWithContextPermissionMethodID2 != NULL) && (currentMethod == doPrivilegedWithContextPermissionMethodID2->method))
1331
) {
1332
walkState->userData3 = STACK_WALK_STATE_LIMITED_DOPRIVILEGED;
1333
if (NULL != walkState->userData1) {
1334
DoPrivilegedMethodArgs* doPrivilegedMethodsArgsTmp = (DoPrivilegedMethodArgs*)j9mem_allocate_memory(sizeof(DoPrivilegedMethodArgs), J9MEM_CATEGORY_VM_JCL);
1335
walkState->userData1 = NULL; /* set to NULL when a limited doPrivileged frame is discovered */
1336
if (NULL == doPrivilegedMethodsArgsTmp) {
1337
currentThread->javaVM->internalVMFunctions->setNativeOutOfMemoryError(currentThread, 0, 0);
1338
return J9_STACKWALK_STOP_ITERATING;
1339
}
1340
memset(doPrivilegedMethodsArgsTmp, 0, sizeof(DoPrivilegedMethodArgs));
1341
doPrivilegedMethodsArgsTmp->accControlContext = (j9object_t)walkState->arg0EA[-1];
1342
doPrivilegedMethodsArgsTmp->permissions = (j9object_t)walkState->arg0EA[-2];
1343
1344
walkState->userData2 = doPrivilegedMethodsArgsTmp;
1345
} else {
1346
return frameIteratorGetAccSnapshotHelper(currentThread, walkState, (j9object_t)walkState->arg0EA[-1], (j9object_t)walkState->arg0EA[-2]);
1347
}
1348
}
1349
1350
return J9_STACKWALK_KEEP_ITERATING;
1351
}
1352
1353
/**
1354
* The object array returned has following format:
1355
*
1356
* Pre-JEP140 format: AccessControlContext/ProtectionDomain..., and the length of the object array is NOT divisible by OBJS_ARRAY_SIZE
1357
* First element is an AccessControlContext object which might be null, either from a full permission privileged frame or from current thread if there is no such privileged frames
1358
* ProtectionDomain elements after AccessControlContext object could be in one of following two formats:
1359
* For doPrivileged methods - flag forDoPrivilegedWithCombiner is false:
1360
* the ProtectionDomain element might be null, first ProtectionDomain element is a duplicate of the ProtectionDomain of the caller of doPrivileged
1361
* rest of ProtectionDomain elements are from the callers discovered during stack walking
1362
* the start index of the actual ProtectionDomain element is 2 of the object array returned
1363
* For doPrivilegedWithCombiner methods - flag forDoPrivilegedWithCombiner is true:
1364
* there are only two ProtectionDomain elements, first one is the ProtectionDomain of the caller of doPrivileged
1365
* and the other is the ProtectionDomain of the caller of doPrivilegedWithCombiner
1366
* the fourth element of the object array is NULL for padding to ensure that the length of the object array is NOT divisible by OBJS_ARRAY_SIZE either
1367
*
1368
* JEP 140 format: AccessControlContext/ProtectionDomain[]/Permission[]
1369
* The length of the object array is always divisible by OBJS_ARRAY_SIZE.
1370
* Depends on number of limited permission privileged frames, the result are in following format:
1371
* First element is an AccessControlContext object
1372
* Second element could be in one of following two formats:
1373
* For doPrivileged methods - flag forDoPrivilegedWithCombiner is false:
1374
* an array of ProtectionDomain objects in which first ProtectionDomain element is a duplicate of the ProtectionDomain of the caller of doPrivileged
1375
* the start index of the actual ProtectionDomain element is 1 of this ProtectionDomain objects array
1376
* For doPrivilegedWithCombiner methods - flag forDoPrivilegedWithCombiner is true:
1377
* an array of ProtectionDomain objects with only two elements
1378
* first one is the ProtectionDomain of the caller of doPrivileged
1379
* and the other is the ProtectionDomain of the caller of doPrivilegedWithCombiner
1380
* Third element is an array of Limited Permission objects
1381
* Repeating this format:
1382
* AccessControlContext object,
1383
* ProtectionDomain objects array with same format above when flag forDoPrivilegedWithCombiner is false
1384
* or just the ProtectionDomain of the caller of doPrivileged in case of flag forDoPrivilegedWithCombiner is true
1385
* Permission object array
1386
* Until a full permission privileged frame or the end of the stack reached.
1387
*
1388
* Note: 1. The reason to have Pre-JEP140 and JEP 140 format is to keep similar format and processing logic
1389
* when there is no limited doPrivileged method (JEP 140 implementation) involved.
1390
* This helped to address performance issue raised by JAZZ 66091: Perf work for LIR 28261 (Limited doPrivileged / JEP 140)
1391
* 2. The reason to duplicate the ProtectionDomain object of the caller of doPrivileged is to avoid creating a new object array
1392
* without NULL and duplicate ProtectionDomain objects discovered during stack walking while still keeping same order of
1393
* those objects.
1394
*
1395
* @param env The current thread.
1396
* @param jsAccessController The receiver class
1397
* @param startingFrame The frame to start stack walking
1398
* @param forDoPrivilegedWithCombiner the flag to indicate if it is for doPrivilegedWithCombiner method
1399
*
1400
* @return an array of objects as per comment above
1401
*/
1402
jobject JNICALL
1403
Java_java_security_AccessController_getAccSnapshot(JNIEnv* env, jclass jsAccessController, jint startingFrame, jboolean forDoPrivilegedWithCombiner)
1404
{
1405
J9VMThread *vmThread = (J9VMThread *) env;
1406
J9JavaVM *vm = vmThread->javaVM;
1407
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
1408
J9StackWalkState walkState = {0};
1409
J9Class *arrayClass = NULL;
1410
UDATA i = 0;
1411
j9object_t contextObject = NULL;
1412
j9object_t arrayObject = NULL;
1413
jobject result = NULL;
1414
1415
/* Trc_JCL_java_security_AccessController_getAccSnapshot_Entry(vmThread, startingFrame); */
1416
vmFuncs->internalEnterVMFromJNI(vmThread);
1417
1418
/* Fetch the Object[] class before doing the stack walk. */
1419
arrayClass = fetchArrayClass(vmThread, J9VMJAVALANGOBJECT(vm));
1420
if (NULL != vmThread->currentException) {
1421
goto _walkStateUninitialized;
1422
}
1423
/* AccessControlContext is allocated in the same space as the thread, so no exception can occur */
1424
contextObject = vmThread->threadObject;
1425
if (NULL != contextObject) {
1426
contextObject = J9VMJAVALANGTHREAD_INHERITEDACCESSCONTROLCONTEXT(vmThread, contextObject);
1427
}
1428
/* Walk the stack, caching the constant pools of the frames. */
1429
walkState.skipCount = startingFrame + 1; /* skip this JNI frame as well */
1430
walkState.userData1 = STACK_WALK_STATE_MAGIC; /* set to NULL when a limited doPrivileged frame is discovered */
1431
walkState.userData2 = contextObject; /* initially set to contextObject, set to DoPrivilegedMethodArgs* when a limited doPrivileged frame is discovered */
1432
walkState.userData3 = STACK_WALK_STATE_MAGIC; /* set to NULL when to find the caller of a limited doPrivileged method */
1433
walkState.userData4 = NULL; /* when forDoPrivilegedWithCombiner is true, set to walkState->framesWalked of non reflection/MethodHandleInvoke frame caller of doPrivilegedWithCombiner */
1434
walkState.frameWalkFunction = isPrivilegedFrameIteratorGetAccSnapshot;
1435
walkState.flags = J9_STACKWALK_CACHE_CPS | J9_STACKWALK_VISIBLE_ONLY | J9_STACKWALK_INCLUDE_NATIVES | J9_STACKWALK_ITERATE_FRAMES;
1436
walkState.walkThread = vmThread;
1437
1438
if (vm->walkStackFrames(vmThread, &walkState) != J9_STACKWALK_RC_NONE) {
1439
vmFuncs->setNativeOutOfMemoryError(vmThread, 0, 0);
1440
goto _throwException;
1441
}
1442
if (STACK_WALK_STATE_MAGIC == walkState.userData1) {
1443
/* No limited doPrivileged or no doPrivileged frame discovered */
1444
if (forDoPrivilegedWithCombiner) {
1445
/* for doPrivilegedWithCombiner methods
1446
* first slot: contextObject
1447
* second slot: the caller of the ProtectionDomain of the caller of doPrivileged
1448
* third slot: the ProtectionDomain of the caller of doPrivilegedWithCombiner
1449
* fourth slot: NULL to ensure the total length of object array is not divisible by OBJS_ARRAY_SIZE
1450
* */
1451
UDATA *cachePtr = NULL;
1452
UDATA framesWalked = (UDATA)walkState.userData4;
1453
Assert_JCL_true(framesWalked > 0);
1454
contextObject = (j9object_t)walkState.userData2;
1455
PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, contextObject);
1456
arrayObject = vmThread->javaVM->memoryManagerFunctions->J9AllocateIndexableObject(vmThread, arrayClass, 4, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
1457
contextObject = POP_OBJECT_IN_SPECIAL_FRAME(vmThread);
1458
if (NULL == arrayObject) {
1459
vmThread->javaVM->internalVMFunctions->setHeapOutOfMemoryError(vmThread);
1460
goto _throwException;
1461
}
1462
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, 0, contextObject);
1463
cachePtr = walkState.cache + (walkState.framesWalked - 1);
1464
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, 1, J9VMJAVALANGCLASS_PROTECTIONDOMAIN(vmThread, J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_CP(*cachePtr))));
1465
cachePtr = walkState.cache + (framesWalked - 1);
1466
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, 2, J9VMJAVALANGCLASS_PROTECTIONDOMAIN(vmThread, J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_CP(*cachePtr))));
1467
} else {
1468
/* contextObject in first slot, duplicate of the ProtectionDomain of the caller of doPrivileged in second slot (add 2 to size before allocation). */
1469
U_32 arraySize = (U_32)(walkState.framesWalked + 2);
1470
if (0 == (arraySize % OBJS_ARRAY_SIZE)) {
1471
arraySize++; /* increase one more slot to make sure the size of arrayObject is NOT divisible by OBJS_ARRAY_SIZE */
1472
}
1473
arrayObject = storePDobjectsHelper(vmThread, arrayClass, &walkState, (j9object_t)walkState.userData2, arraySize, walkState.framesWalked, 2, TRUE);
1474
if (NULL == arrayObject) {
1475
goto _throwException;
1476
}
1477
}
1478
result = vmFuncs->j9jni_createLocalRef(env, arrayObject);
1479
} else {
1480
/* at least a limited doPrivileged frame discovered */
1481
IDATA signedCounter = 0;
1482
UDATA nbrPDblockToBuild = 1; /* the number of ProtectionDomain block walked, minimum 1 when no target method walked, i.e., walked whole stack */
1483
UDATA counter = 0;
1484
DoPrivilegedMethodArgs* dpMethodsArgs = NULL; /* args found within target methods */
1485
DoPrivilegedMethodArgs* dpMethodsArgsTmp = NULL;
1486
1487
PORT_ACCESS_FROM_JAVAVM(vm);
1488
1489
dpMethodsArgs = (DoPrivilegedMethodArgs*)walkState.userData2;
1490
if (NULL == dpMethodsArgs) {
1491
goto _clearAllocation;
1492
}
1493
/* Array structure: AccessControlContext (could be null), ProtectionDomain object array, Permission object array (null means a normal method) */
1494
dpMethodsArgsTmp = dpMethodsArgs;
1495
if (NULL != dpMethodsArgsTmp->next) {
1496
/* look for top doPrivileged frame */
1497
do {
1498
nbrPDblockToBuild++;
1499
dpMethodsArgsTmp = dpMethodsArgsTmp->next;
1500
} while (NULL != dpMethodsArgsTmp->next);
1501
} else {
1502
/* only one frame */
1503
}
1504
if (NULL != dpMethodsArgsTmp->permissions) {
1505
/* top frame is a limited doPrivilege frame */
1506
DoPrivilegedMethodArgs* doPrivilegedMethodsArgsTmp2 = (DoPrivilegedMethodArgs*)j9mem_allocate_memory(sizeof(DoPrivilegedMethodArgs), J9MEM_CATEGORY_VM_JCL);
1507
if (NULL == doPrivilegedMethodsArgsTmp2) {
1508
vmFuncs->setNativeOutOfMemoryError(vmThread, 0, 0);
1509
goto _clearAllocation;
1510
}
1511
memset(doPrivilegedMethodsArgsTmp2, 0, sizeof(DoPrivilegedMethodArgs));
1512
doPrivilegedMethodsArgsTmp2->accControlContext = contextObject;
1513
doPrivilegedMethodsArgsTmp2->frameCounter = walkState.framesWalked;
1514
dpMethodsArgsTmp->next = doPrivilegedMethodsArgsTmp2;
1515
1516
nbrPDblockToBuild++;
1517
} else {
1518
dpMethodsArgsTmp->frameCounter = walkState.framesWalked;
1519
}
1520
1521
dpMethodsArgsTmp = dpMethodsArgs;
1522
counter = 0;
1523
do {
1524
PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, (j9object_t)dpMethodsArgsTmp->accControlContext);
1525
PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, (j9object_t)dpMethodsArgsTmp->permissions);
1526
dpMethodsArgsTmp = dpMethodsArgsTmp->next;
1527
counter++;
1528
} while (NULL != dpMethodsArgsTmp);
1529
arrayObject = vm->memoryManagerFunctions->J9AllocateIndexableObject(vmThread, arrayClass, (U_32)nbrPDblockToBuild*OBJS_ARRAY_SIZE, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
1530
if (NULL == arrayObject) {
1531
for (signedCounter = (counter - 1); signedCounter >= 0; signedCounter--) {
1532
DROP_OBJECT_IN_SPECIAL_FRAME(vmThread);
1533
DROP_OBJECT_IN_SPECIAL_FRAME(vmThread);
1534
}
1535
vmFuncs->setHeapOutOfMemoryError(vmThread);
1536
goto _clearAllocation;
1537
}
1538
for (signedCounter = (counter - 1); signedCounter >= 0; signedCounter--) {
1539
j9object_t permissions = POP_OBJECT_IN_SPECIAL_FRAME(vmThread);
1540
j9object_t accControlContext = POP_OBJECT_IN_SPECIAL_FRAME(vmThread);
1541
/* store accControlContext at index OBJS_ARRAY_IDX_ACC(0) */
1542
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, signedCounter*OBJS_ARRAY_SIZE, accControlContext);
1543
/* store permissions at index OBJS_ARRAY_IDX_PERMS_OR_CACHECHECKED(2) */
1544
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, (signedCounter*OBJS_ARRAY_SIZE + OBJS_ARRAY_IDX_PERMS_OR_CACHECHECKED), permissions);
1545
}
1546
1547
if (forDoPrivilegedWithCombiner) {
1548
/* for doPrivilegedWithCombiner methods
1549
* first arrayObject[signedCounter*OBJS_ARRAY_SIZE + OBJS_ARRAY_IDX_PDS] is an object array with length 2
1550
* in which first element is the ProtectionDomain of the caller of doPrivileged
1551
* second slot: the ProtectionDomain of the caller of doPrivilegedWithCombiner
1552
* rest of arrayObject[signedCounter*OBJS_ARRAY_SIZE + OBJS_ARRAY_IDX_PDS] are a single ProtectionDomain object of the callers of each limited/full doPrivileged methods
1553
* */
1554
signedCounter = 0;
1555
dpMethodsArgsTmp = dpMethodsArgs;
1556
do {
1557
UDATA *cachePtr = NULL;
1558
if (0 == signedCounter) {
1559
/* this is first frame */
1560
UDATA framesWalked = (UDATA)walkState.userData4;
1561
j9object_t pdArrayTmp = NULL;
1562
Assert_JCL_true(framesWalked > 0);
1563
1564
PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, (j9object_t)arrayObject);
1565
pdArrayTmp = vm->memoryManagerFunctions->J9AllocateIndexableObject(vmThread, arrayClass, 2, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
1566
arrayObject = POP_OBJECT_IN_SPECIAL_FRAME(vmThread);
1567
if (NULL == pdArrayTmp) {
1568
vmFuncs->setHeapOutOfMemoryError(vmThread);
1569
goto _clearAllocation;
1570
}
1571
cachePtr = walkState.cache + (dpMethodsArgsTmp->frameCounter - 1);
1572
J9JAVAARRAYOFOBJECT_STORE(vmThread, pdArrayTmp, 0, J9VMJAVALANGCLASS_PROTECTIONDOMAIN(vmThread, J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_CP(*cachePtr))));
1573
cachePtr = walkState.cache + (framesWalked - 1);
1574
J9JAVAARRAYOFOBJECT_STORE(vmThread, pdArrayTmp, 1, J9VMJAVALANGCLASS_PROTECTIONDOMAIN(vmThread, J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_CP(*cachePtr))));
1575
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, (signedCounter*OBJS_ARRAY_SIZE + OBJS_ARRAY_IDX_PDS), pdArrayTmp);
1576
} else {
1577
cachePtr = walkState.cache + (dpMethodsArgsTmp->frameCounter - 1);
1578
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, (signedCounter*OBJS_ARRAY_SIZE + OBJS_ARRAY_IDX_PDS), J9VMJAVALANGCLASS_PROTECTIONDOMAIN(vmThread, J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_CP(*cachePtr))));
1579
}
1580
signedCounter++;
1581
dpMethodsArgsTmp = dpMethodsArgsTmp->next;
1582
} while (NULL != dpMethodsArgsTmp);
1583
} else {
1584
UDATA *cachePtr = walkState.cache;
1585
j9object_t lastPD = NULL;
1586
j9object_t pdArrayTmp = NULL;
1587
UDATA lastFrameCounter = 0;
1588
signedCounter = 0;
1589
i = 0;
1590
1591
dpMethodsArgsTmp = dpMethodsArgs;
1592
do {
1593
j9object_t pd = NULL;
1594
I_32 resultIndex = 1;
1595
1596
/* The layout of ProtectionDomain object array is changed to following format:
1597
* first element: the ProtectionDomain of the caller of doPrivileged
1598
* rest elements: the ProtectionDomains of the callers discovered during stack walking including the caller of doPrivileged
1599
* The reason to duplicate the ProtectionDomain of the caller of doPrivileged is to keep current structure and performance
1600
* */
1601
PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, (j9object_t)arrayObject);
1602
pdArrayTmp = vm->memoryManagerFunctions->J9AllocateIndexableObject(vmThread, arrayClass, (U_32)(dpMethodsArgsTmp->frameCounter - lastFrameCounter + 1), J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
1603
arrayObject = POP_OBJECT_IN_SPECIAL_FRAME(vmThread);
1604
if (NULL == pdArrayTmp) {
1605
vmFuncs->setHeapOutOfMemoryError(vmThread);
1606
goto _clearAllocation;
1607
}
1608
lastFrameCounter = dpMethodsArgsTmp->frameCounter;
1609
do {
1610
pd = J9VMJAVALANGCLASS_PROTECTIONDOMAIN(vmThread, J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_CP(*cachePtr)));
1611
cachePtr += 1;
1612
if ((NULL != pd) && (pd != lastPD)) {
1613
BOOLEAN duplicate = FALSE;
1614
IDATA sc = 0;
1615
1616
while (sc < signedCounter) {
1617
/* Scanning over object array already in previous limited doPrivileged frames */
1618
UDATA j = 0;
1619
j9object_t pdTmp = J9JAVAARRAYOFOBJECT_LOAD(vmThread, arrayObject, (sc*OBJS_ARRAY_SIZE + OBJS_ARRAY_IDX_PDS));
1620
for (j = 1; j < J9INDEXABLEOBJECT_SIZE(vmThread, pdTmp); j++) {
1621
if (pd == J9JAVAARRAYOFOBJECT_LOAD(vmThread, pdTmp, j)) {
1622
duplicate = TRUE;
1623
break;
1624
}
1625
}
1626
if (TRUE == duplicate) {
1627
break;
1628
}
1629
sc++;
1630
}
1631
if (!duplicate) {
1632
I_32 scanIndex = 1;
1633
while (scanIndex < resultIndex) {
1634
/* Scanning over objects just saved in this doPrivileged frame */
1635
if (pd == J9JAVAARRAYOFOBJECT_LOAD(vmThread, pdArrayTmp, scanIndex)) {
1636
duplicate = TRUE;
1637
break;
1638
}
1639
scanIndex++;
1640
}
1641
if (!duplicate) {
1642
J9JAVAARRAYOFOBJECT_STORE(vmThread, pdArrayTmp, resultIndex, pd);
1643
resultIndex++;
1644
}
1645
}
1646
lastPD = pd;
1647
}
1648
i++;
1649
} while (i < dpMethodsArgsTmp->frameCounter);
1650
/* save the PD of the caller of doPrivileged at first element */
1651
if (NULL != pd) {
1652
J9JAVAARRAYOFOBJECT_STORE(vmThread, pdArrayTmp, 0, pd);
1653
}
1654
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, (signedCounter*OBJS_ARRAY_SIZE + OBJS_ARRAY_IDX_PDS), pdArrayTmp);
1655
signedCounter++;
1656
dpMethodsArgsTmp = dpMethodsArgsTmp->next;
1657
} while (i < walkState.framesWalked);
1658
}
1659
result = vmFuncs->j9jni_createLocalRef(env, arrayObject);
1660
1661
_clearAllocation:
1662
if (NULL != dpMethodsArgs) {
1663
do {
1664
dpMethodsArgsTmp = dpMethodsArgs->next;
1665
j9mem_free_memory(dpMethodsArgs);
1666
dpMethodsArgs = dpMethodsArgsTmp;
1667
} while (NULL != dpMethodsArgsTmp);
1668
}
1669
}
1670
1671
_throwException:
1672
vmFuncs->freeStackWalkCaches(vmThread, &walkState);
1673
_walkStateUninitialized:
1674
vmFuncs->internalExitVMToJNI(vmThread);
1675
/* Trc_JCL_java_security_AccessController_getAccSnapshot_Exit(vmThread, result); */
1676
return result;
1677
}
1678
1679
/**
1680
* PrivilegedFrameIterator method to perform stack walking and find the caller specified by startingFrame
1681
*
1682
* @param currentThread the VM Thread
1683
* @param walkState the stack walk state
1684
*
1685
* @return J9_STACKWALK_STOP_ITERATING, J9_STACKWALK_KEEP_ITERATING
1686
*/
1687
static UDATA
1688
isPrivilegedFrameIteratorGetCallerPD(J9VMThread * currentThread, J9StackWalkState * walkState)
1689
{
1690
if (J9_ARE_ALL_BITS_SET(J9_ROM_METHOD_FROM_RAM_METHOD(walkState->method)->modifiers, J9AccMethodFrameIteratorSkip)) {
1691
/* Skip methods with java.lang.invoke.FrameIteratorSkip / jdk.internal.vm.annotation.Hidden / java.lang.invoke.LambdaForm$Hidden annotation */
1692
return J9_STACKWALK_KEEP_ITERATING;
1693
}
1694
1695
J9JavaVM *vm = currentThread->javaVM;
1696
J9Class * currentClass = J9_CLASS_FROM_CP(walkState->constantPool);
1697
if ((walkState->method == vm->jlrMethodInvoke)
1698
#if JAVA_SPEC_VERSION >= 18
1699
|| (walkState->method == vm->jlrMethodInvokeMH)
1700
#endif /* JAVA_SPEC_VERSION >= 18 */
1701
|| (walkState->method == vm->jliMethodHandleInvokeWithArgs)
1702
|| (walkState->method == vm->jliMethodHandleInvokeWithArgsList)
1703
|| (vm->srMethodAccessor && VM_VMHelpers::isSameOrSuperclass(J9VM_J9CLASS_FROM_JCLASS(currentThread, vm->srMethodAccessor), currentClass))
1704
/* there is no need to check srConstructorAccessor because doPrivilegedXX are method calls and not affected by Constructor reflection */
1705
) {
1706
/* skip reflection/MethodHandleInvoke frames */
1707
return J9_STACKWALK_KEEP_ITERATING;
1708
} else {
1709
/* find the caller */
1710
return J9_STACKWALK_STOP_ITERATING;
1711
}
1712
}
1713
1714
/**
1715
* This native retrieves the ProtectionDomain object of the non-reflection/MethodHandleInvoke caller as per the startingFrame specified.
1716
1717
* @param env The current thread.
1718
* @param jsAccessController The receiver class
1719
* @param startingFrame The frame to start stack walking
1720
*
1721
* @return a ProtectionDomain object as per description above
1722
*/
1723
jobject JNICALL
1724
Java_java_security_AccessController_getCallerPD(JNIEnv* env, jclass jsAccessController, jint startingFrame)
1725
{
1726
J9VMThread *vmThread = (J9VMThread *) env;
1727
J9JavaVM *vm = vmThread->javaVM;
1728
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
1729
J9StackWalkState walkState = {0};
1730
j9object_t pd = NULL;
1731
jobject result = NULL;
1732
UDATA *cachePtr = NULL;
1733
1734
vmFuncs->internalEnterVMFromJNI(vmThread);
1735
1736
walkState.skipCount = startingFrame + 1; /* skip this JNI frame as well */
1737
walkState.frameWalkFunction = isPrivilegedFrameIteratorGetCallerPD;
1738
walkState.flags = J9_STACKWALK_CACHE_CPS | J9_STACKWALK_VISIBLE_ONLY | J9_STACKWALK_INCLUDE_NATIVES | J9_STACKWALK_ITERATE_FRAMES;
1739
walkState.walkThread = vmThread;
1740
if (vm->walkStackFrames(vmThread, &walkState) != J9_STACKWALK_RC_NONE) {
1741
vmFuncs->setNativeOutOfMemoryError(vmThread, 0, 0);
1742
goto _throwException;
1743
}
1744
Assert_JCL_true(walkState.framesWalked > 0);
1745
cachePtr = walkState.cache + (walkState.framesWalked - 1);
1746
pd = J9VMJAVALANGCLASS_PROTECTIONDOMAIN(vmThread, J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_CP(*cachePtr)));
1747
if (NULL != pd) {
1748
result = vmFuncs->j9jni_createLocalRef(env, pd);
1749
}
1750
1751
_throwException:
1752
vmFuncs->freeStackWalkCaches(vmThread, &walkState);
1753
vmFuncs->internalExitVMToJNI(vmThread);
1754
1755
return result;
1756
}
1757
1758
/**
1759
* Helper method to store PD object discovered during stack walking
1760
*
1761
* @param vmThread[in] the current J9VMThread
1762
* @param arrayClass[in] the Object[] class
1763
* @param walkState[in] the stack walk state
1764
* @param contextObject[in] the AccessControlContext object
1765
* @param arraySize[in] the size of array object to be allocated
1766
* @param framesWalked[in] the frames walked
1767
* @param startPos[in] the start index of the actual ProtectionDomain object excluding acc & dup
1768
* @param dupCallerPD[in] the flag to indicate if the caller ProtectionDomain object is to be duplicated at index 1
1769
*
1770
* @returns an object array with AccessControlContext object at index 0 followed by ProtectionDomain objects
1771
*/
1772
static j9object_t
1773
storePDobjectsHelper(J9VMThread* vmThread, J9Class* arrayClass, J9StackWalkState* walkState, j9object_t contextObject, U_32 arraySize, UDATA framesWalked, I_32 startPos, BOOLEAN dupCallerPD)
1774
{
1775
j9object_t arrayObject = NULL;
1776
1777
PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, contextObject);
1778
arrayObject = vmThread->javaVM->memoryManagerFunctions->J9AllocateIndexableObject(vmThread, arrayClass, arraySize, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
1779
contextObject = POP_OBJECT_IN_SPECIAL_FRAME(vmThread);
1780
if (NULL == arrayObject) {
1781
vmThread->javaVM->internalVMFunctions->setHeapOutOfMemoryError(vmThread);
1782
return NULL;
1783
}
1784
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, 0, contextObject);
1785
/* Fill in the array. */
1786
if (0 < framesWalked) {
1787
UDATA i = 0;
1788
j9object_t lastPD = NULL;
1789
I_32 resultIndex = startPos;
1790
UDATA *cachePtr = walkState->cache;
1791
j9object_t pd = NULL;
1792
for (i = framesWalked; i > 0; i--) {
1793
pd = J9VMJAVALANGCLASS_PROTECTIONDOMAIN(vmThread, J9VM_J9CLASS_TO_HEAPCLASS(J9_CLASS_FROM_CP(*cachePtr)));
1794
cachePtr += 1;
1795
if ((NULL != pd) && (pd != lastPD)) {
1796
I_32 scanIndex = startPos;
1797
BOOLEAN duplicate = FALSE;
1798
while (scanIndex < resultIndex) {
1799
/* Scanning over objects that were already read in this function, so no exception can occur */
1800
if (pd == J9JAVAARRAYOFOBJECT_LOAD(vmThread, arrayObject, scanIndex)) {
1801
duplicate = TRUE;
1802
break;
1803
}
1804
scanIndex++;
1805
}
1806
if (!duplicate) {
1807
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, resultIndex, pd);
1808
resultIndex++;
1809
}
1810
lastPD = pd;
1811
}
1812
}
1813
if (dupCallerPD && NULL != pd) {
1814
J9JAVAARRAYOFOBJECT_STORE(vmThread, arrayObject, 1, pd);
1815
}
1816
}
1817
return arrayObject;
1818
}
1819
1820
1821
jobject JNICALL
1822
Java_java_lang_Class_getNestHostImpl(JNIEnv *env, jobject recv)
1823
{
1824
#if JAVA_SPEC_VERSION >= 11
1825
J9VMThread *currentThread = (J9VMThread*)env;
1826
J9InternalVMFunctions *vmFuncs = currentThread->javaVM->internalVMFunctions;
1827
vmFuncs->internalEnterVMFromJNI(currentThread);
1828
1829
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
1830
J9Class *nestHost = clazz->nestHost;
1831
1832
if (NULL == nestHost) {
1833
if (J9_VISIBILITY_ALLOWED == vmFuncs->loadAndVerifyNestHost(currentThread, clazz, J9_LOOK_NO_THROW)) {
1834
nestHost = clazz->nestHost;
1835
} else {
1836
/* If there is a failure loading or accessing the nest host, or if this class or interface does
1837
* not specify a nest, then it is considered to belong to its own nest and this is returned as
1838
* the host */
1839
nestHost = clazz;
1840
}
1841
}
1842
j9object_t resultObject = J9VM_J9CLASS_TO_HEAPCLASS(nestHost);
1843
jobject result = vmFuncs->j9jni_createLocalRef(env, resultObject);
1844
1845
if (NULL == result) {
1846
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
1847
}
1848
1849
vmFuncs->internalExitVMToJNI(currentThread);
1850
return result;
1851
#else /* JAVA_SPEC_VERSION >= 11 */
1852
Assert_JCL_unimplemented();
1853
return NULL;
1854
#endif /* JAVA_SPEC_VERSION >= 11 */
1855
}
1856
1857
jobject JNICALL
1858
Java_java_lang_Class_getNestMembersImpl(JNIEnv *env, jobject recv)
1859
{
1860
#if JAVA_SPEC_VERSION >= 11
1861
J9VMThread *currentThread = (J9VMThread*)env;
1862
J9JavaVM *vm = currentThread->javaVM;
1863
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
1864
J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;
1865
1866
j9object_t resultObject = NULL;
1867
jobject result = NULL;
1868
J9ROMClass *romHostClass = NULL;
1869
U_16 nestMemberCount = 0;
1870
J9Class *jlClass = NULL;
1871
J9Class *arrayClass = NULL;
1872
1873
vmFuncs->internalEnterVMFromJNI(currentThread);
1874
1875
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
1876
J9Class *nestHost = clazz->nestHost;
1877
1878
if (NULL == nestHost) {
1879
if (J9_VISIBILITY_ALLOWED != vmFuncs->loadAndVerifyNestHost(currentThread, clazz, 0)) {
1880
goto _done;
1881
}
1882
nestHost = clazz->nestHost;
1883
}
1884
romHostClass = nestHost->romClass;
1885
nestMemberCount = romHostClass->nestMemberCount;
1886
1887
/* Grab java.lang.Class class for result object size */
1888
jlClass = J9VMJAVALANGCLASS_OR_NULL(vm);
1889
Assert_JCL_notNull(jlClass);
1890
arrayClass = fetchArrayClass(currentThread, jlClass);
1891
if (NULL != currentThread->currentException) {
1892
goto _done;
1893
}
1894
1895
resultObject = mmFuncs->J9AllocateIndexableObject(currentThread, arrayClass, 1 + nestMemberCount, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
1896
if (NULL == resultObject) {
1897
vmFuncs->setHeapOutOfMemoryError(currentThread);
1898
goto _done;
1899
}
1900
1901
/* Host class is always in zeroeth index */
1902
J9JAVAARRAYOFOBJECT_STORE(currentThread, resultObject, 0, J9VM_J9CLASS_TO_HEAPCLASS(nestHost));
1903
1904
/* If host class claims nest members, they should be placed in second index onwards */
1905
if (0 != nestMemberCount) {
1906
J9SRP *nestMembers = J9ROMCLASS_NESTMEMBERS(romHostClass);
1907
U_16 i = 0;
1908
/* Classes in nest are in same runtime package & therefore have same classloader */
1909
J9ClassLoader *classLoader = clazz->classLoader;
1910
1911
for (i = 0; i < nestMemberCount; i++) {
1912
J9UTF8 *nestMemberName = NNSRP_GET(nestMembers[i], J9UTF8 *);
1913
1914
PUSH_OBJECT_IN_SPECIAL_FRAME(currentThread, resultObject);
1915
J9Class *nestMember = vmFuncs->internalFindClassUTF8(currentThread, J9UTF8_DATA(nestMemberName), J9UTF8_LENGTH(nestMemberName), classLoader, J9_FINDCLASS_FLAG_THROW_ON_FAIL);
1916
resultObject = POP_OBJECT_IN_SPECIAL_FRAME(currentThread);
1917
1918
if (NULL == nestMember) {
1919
/* If internalFindClassUTF8 fails to find the nest member, it sets
1920
* a NoClassDefFoundError
1921
*/
1922
goto _done;
1923
} else if (NULL == nestMember->nestHost) {
1924
if (J9_VISIBILITY_ALLOWED != vmFuncs->loadAndVerifyNestHost(currentThread, nestMember, 0)) {
1925
goto _done;
1926
}
1927
}
1928
if (nestMember->nestHost != nestHost) {
1929
vmFuncs->setNestmatesError(currentThread, nestMember, nestHost, J9_VISIBILITY_NEST_MEMBER_NOT_CLAIMED_ERROR);
1930
goto _done;
1931
}
1932
J9JAVAARRAYOFOBJECT_STORE(currentThread, resultObject, i + 1, J9VM_J9CLASS_TO_HEAPCLASS(nestMember));
1933
}
1934
}
1935
1936
result = vmFuncs->j9jni_createLocalRef(env, resultObject);
1937
1938
_done:
1939
vmFuncs->internalExitVMToJNI(currentThread);
1940
return result;
1941
#else /* JAVA_SPEC_VERSION >= 11 */
1942
Assert_JCL_unimplemented();
1943
return NULL;
1944
#endif /* JAVA_SPEC_VERSION >= 11 */
1945
}
1946
1947
jboolean JNICALL
1948
Java_java_lang_Class_isHiddenImpl(JNIEnv *env, jobject recv)
1949
{
1950
#if JAVA_SPEC_VERSION >= 15
1951
jboolean result = JNI_FALSE;
1952
J9VMThread *currentThread = (J9VMThread*)env;
1953
J9InternalVMFunctions *vmFuncs = currentThread->javaVM->internalVMFunctions;
1954
vmFuncs->internalEnterVMFromJNI(currentThread);
1955
J9Class *clazz = J9VM_J9CLASS_FROM_HEAPCLASS(currentThread, J9_JNI_UNWRAP_REFERENCE(recv));
1956
result = J9ROMCLASS_IS_HIDDEN(clazz->romClass);
1957
vmFuncs->internalExitVMToJNI(currentThread);
1958
return result;
1959
#else /* JAVA_SPEC_VERSION >= 15 */
1960
Assert_JCL_unimplemented();
1961
return JNI_FALSE;
1962
#endif /* JAVA_SPEC_VERSION >= 15 */
1963
}
1964
1965
} /* extern "C" */
1966
1967