Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/jcl/common/jclvm.c
6000 views
1
/*******************************************************************************
2
* Copyright (c) 1998, 2019 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 <stdlib.h>
24
#include <string.h>
25
26
#include "iohelp.h"
27
#include "j9.h"
28
#include "omrgcconsts.h"
29
#include "j9jclnls.h"
30
#include "j9port.h"
31
#include "j9protos.h"
32
#include "jclglob.h"
33
#include "jclprots.h"
34
#include "jni.h"
35
#include "ut_j9jcl.h"
36
37
/* require for new string merging primitives */
38
#include "stackwalk.h"
39
#include "omrlinkedlist.h"
40
#include "j9cp.h"
41
#include "rommeth.h"
42
#include "vmhook.h"
43
#include "HeapIteratorAPI.h"
44
45
46
typedef struct AllInstancesData {
47
J9Class *clazz; /* class being looked for */
48
J9VMThread *vmThread;
49
J9IndexableObject *target; /* the array */
50
UDATA size; /* size of the array */
51
UDATA storeIndex; /* current index being stored */
52
UDATA instanceCount; /* count of instances found regardless if they are being collected in the array or not */
53
} AllInstancesData;
54
55
typedef struct J9HeapStatisticsTableEntry {
56
J9Class *clazz; /* hash table key */
57
UDATA objectCount; /* number of instances of the class */
58
UDATA objectSize;
59
UDATA aggregateSize;
60
} J9HeapStatisticsTableEntry;
61
62
static UDATA hasConstructor(J9VMThread *vmThread, J9StackWalkState *state);
63
static jvmtiIterationControl collectInstances(J9JavaVM *vm, J9MM_IterateObjectDescriptor *objDesc, void *state);
64
static int hasActiveConstructor(J9VMThread *vmThread, J9Class *clazz);
65
static UDATA allInstances (JNIEnv * env, jclass clazz, jobjectArray target);
66
static J9HashTable *collectHeapStatistics(J9VMThread *vmThread);
67
static jvmtiIterationControl updateHeapStatistics(J9JavaVM *vm, J9MM_IterateObjectDescriptor *objDesc, void *state);
68
static UDATA heapStatisticsHashEqualFn(void *leftKey, void *rightKey, void *userData);
69
static UDATA heapStatisticsHashFn(void *key, void *userData);
70
static UDATA printHeapStatistics(JNIEnv *env,J9HeapStatisticsTableEntry **statsArray,
71
UDATA numClasses, char *stringBuffer, UDATA bufferSize);
72
static int compareByAggregateSize(const void *a, const void *b);
73
74
void JNICALL
75
Java_com_ibm_oti_vm_VM_localGC(JNIEnv *env, jclass clazz)
76
{
77
J9VMThread *currentThread = (J9VMThread*)env;
78
J9JavaVM *vm = currentThread->javaVM;
79
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
80
vmFuncs->internalEnterVMFromJNI(currentThread);
81
vm->memoryManagerFunctions->j9gc_modron_local_collect(currentThread);
82
vmFuncs->internalExitVMToJNI(currentThread);
83
}
84
85
86
void JNICALL
87
Java_com_ibm_oti_vm_VM_globalGC(JNIEnv *env, jclass clazz)
88
{
89
J9VMThread *currentThread = (J9VMThread*)env;
90
J9JavaVM *vm = currentThread->javaVM;
91
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
92
vmFuncs->internalEnterVMFromJNI(currentThread);
93
vm->memoryManagerFunctions->j9gc_modron_global_collect(currentThread);
94
vmFuncs->internalExitVMToJNI(currentThread);
95
}
96
97
98
jint JNICALL Java_com_ibm_oti_vm_VM_getClassPathCount(JNIEnv * env, jclass clazz)
99
{
100
#if defined(J9VM_OPT_DYNAMIC_LOAD_SUPPORT)
101
J9JavaVM *javaVM;
102
J9ClassLoader *classLoader;
103
104
javaVM = ((J9VMThread *) env)->javaVM;
105
classLoader = (J9ClassLoader*)javaVM->systemClassLoader;
106
return (jint)classLoader->classPathEntryCount;
107
#else
108
/* No dynamic loader. */
109
return 0;
110
#endif
111
}
112
113
114
115
116
117
/* Java_test_StringCompress_allInstances
118
* Fill in all the instances of clazz into target.
119
* return the count of the instances in the system
120
* if the count is > than the array size, there are more strings than fit.
121
* if count is <= the array size, the array may have null references.
122
* static void allInstances (Class, Object[])
123
*/
124
jint JNICALL
125
Java_com_ibm_oti_vm_VM_allInstances(JNIEnv * env, jclass unused, jclass clazz, jobjectArray target )
126
{
127
jint count = 0;
128
J9VMThread *vmThread = (J9VMThread *) env;
129
J9JavaVM *javaVM = vmThread->javaVM;
130
131
if (OMR_GC_ALLOCATION_TYPE_SEGREGATED != javaVM->gcAllocationType) {
132
UDATA savedGCFlags = 0;
133
134
/* enterVMFromJNI(vmThread); */
135
javaVM->internalVMFunctions->internalEnterVMFromJNI(vmThread);
136
javaVM->internalVMFunctions->acquireExclusiveVMAccess(vmThread);
137
138
savedGCFlags = vmThread->javaVM->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_ALLOW_USER_HEAP_WALK;
139
if (savedGCFlags == 0) { /* if the flags was not set, you set it */
140
vmThread->javaVM->requiredDebugAttributes |= J9VM_DEBUG_ATTRIBUTE_ALLOW_USER_HEAP_WALK;
141
}
142
javaVM->memoryManagerFunctions->j9gc_modron_global_collect(vmThread);
143
if (savedGCFlags == 0) { /* if you set it, you have to unset it */
144
vmThread->javaVM->requiredDebugAttributes &= ~J9VM_DEBUG_ATTRIBUTE_ALLOW_USER_HEAP_WALK;
145
}
146
count = (jint)allInstances(env, clazz, target);
147
148
javaVM->internalVMFunctions->releaseExclusiveVMAccess(vmThread);
149
javaVM->internalVMFunctions->internalExitVMToJNI(vmThread);
150
}
151
152
return count;
153
}
154
155
/**
156
* Return a String object containing a summary of the classes on the heap,
157
* the number of instances, and their aggregate size.
158
* This string inserts Unix-style line separators. The caller is responsible for translating them if necessary.
159
*/
160
jstring JNICALL
161
Java_openj9_internal_tools_attach_target_DiagnosticUtils_getHeapClassStatisticsImpl(JNIEnv * env, jclass unused)
162
{
163
J9VMThread *vmThread = (J9VMThread *) env;
164
J9JavaVM *vm = vmThread->javaVM;
165
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
166
J9HashTable *statsTable = NULL;
167
J9HashTableState hashTableState;
168
BOOLEAN outOfMemory = FALSE;
169
j9object_t stringObject = NULL;
170
J9HeapStatisticsTableEntry **statsArray = NULL;
171
jstring stringObjectRef = NULL;
172
UDATA numClasses = 0;
173
174
PORT_ACCESS_FROM_ENV(env);
175
176
vmFuncs->internalEnterVMFromJNI(vmThread);
177
178
vmFuncs->acquireExclusiveVMAccess(vmThread);
179
statsTable = collectHeapStatistics(vmThread);
180
vmFuncs->releaseExclusiveVMAccess(vmThread);
181
182
if (NULL != statsTable) {
183
numClasses = hashTableGetCount(statsTable);
184
statsArray = j9mem_allocate_memory(numClasses * sizeof(J9HeapStatisticsTableEntry*), J9MEM_CATEGORY_VM_JCL);
185
}
186
if (NULL == statsArray) {
187
outOfMemory = TRUE;
188
} else {
189
UDATA cursor = 0;
190
UDATA printedLength = 0;
191
UDATA bufferSize = 0;
192
J9HeapStatisticsTableEntry *entry = (J9HeapStatisticsTableEntry *) hashTableStartDo(statsTable, &hashTableState);
193
/* build a list of pointers to the hash table entries */
194
while (NULL != entry) {
195
entry->aggregateSize = entry->objectSize * entry->objectCount;
196
statsArray[cursor] = entry;
197
cursor += 1;
198
entry = (J9HeapStatisticsTableEntry *) hashTableNextDo(&hashTableState);
199
}
200
numClasses = cursor; /* adjust the length in case the hash table contained nulls */
201
qsort(statsArray, numClasses, sizeof(J9HeapStatisticsTableEntry*), compareByAggregateSize);
202
do {
203
char *stringBuffer = NULL;
204
bufferSize += numClasses * 80; /* try incrementally larger sizes */
205
stringBuffer = (char *) j9mem_allocate_memory(bufferSize, J9MEM_CATEGORY_VM_JCL);
206
if (NULL == stringBuffer) {
207
outOfMemory = TRUE;
208
break;
209
}
210
printedLength = printHeapStatistics(env, statsArray, numClasses, stringBuffer, bufferSize);
211
if (printedLength > 0) {
212
stringObject = vm->memoryManagerFunctions->j9gc_createJavaLangString(vmThread,
213
(U_8 *) stringBuffer, printedLength, J9_STR_XLAT);
214
stringObjectRef = vmFuncs->j9jni_createLocalRef(env, stringObject);
215
}
216
j9mem_free_memory(stringBuffer);
217
} while (0 == printedLength);
218
/* Need to keep the table until this point since statsArray contained pointer to its members. */
219
hashTableFree(statsTable);
220
j9mem_free_memory(statsArray);
221
}
222
223
if (outOfMemory) {
224
Trc_JCL_heapStatisticsOOM(vmThread);
225
vm->internalVMFunctions->setNativeOutOfMemoryError(vmThread, 0, 0);
226
}
227
vm->internalVMFunctions->internalExitVMToJNI(vmThread);
228
229
return stringObjectRef;
230
}
231
232
/**
233
* Arguments are pointers to entries in the statsArray,
234
* which are themselves pointers to entry in the hash table.
235
* Compare such that the list is sorted in descending order.
236
*/
237
static int
238
compareByAggregateSize(const void *a, const void *b)
239
{
240
const J9HeapStatisticsTableEntry *aEntry = *(const J9HeapStatisticsTableEntry* const *) a;
241
const J9HeapStatisticsTableEntry *bEntry = *(const J9HeapStatisticsTableEntry* const *) b;
242
int result = 0;
243
if (bEntry->aggregateSize < aEntry->aggregateSize) {
244
result = -1;
245
} else if (bEntry->aggregateSize > aEntry->aggregateSize) {
246
result = 1;
247
}
248
return result;
249
}
250
251
static UDATA
252
printHeapStatistics(JNIEnv *env,J9HeapStatisticsTableEntry **statsArray,
253
UDATA numClasses, char *stringBuffer, UDATA bufferSize)
254
{
255
char *bufferCursor = stringBuffer;
256
UDATA classCursor = 0;
257
UDATA cumulativeCount = 0;
258
UDATA cumulativeSize = 0;
259
UDATA result = 0;
260
261
PORT_ACCESS_FROM_ENV(env);
262
263
result = j9str_printf(PORTLIB, bufferCursor, bufferSize,
264
"%5s %14s %14s %s\n-------------------------------------------------\n",
265
"num", "object count", "total size", "class name"
266
);
267
bufferCursor += result;
268
bufferSize -= result;
269
for (classCursor = 0; (result > 0) && (classCursor < numClasses); ++classCursor) {
270
J9Class *currentClass = statsArray[classCursor]->clazz;
271
result = j9str_printf(PORTLIB, bufferCursor, bufferSize,
272
"%5d %14zu %14zu ",
273
classCursor + 1, statsArray[classCursor]->objectCount,
274
statsArray[classCursor]->aggregateSize
275
);
276
bufferCursor += result;
277
bufferSize -= result;
278
if (J9CLASS_IS_ARRAY(currentClass)) {
279
J9ArrayClass *arrayClazz = (J9ArrayClass*)currentClass;
280
UDATA arity = arrayClazz->arity;
281
J9Class *leafComponentType = arrayClazz->leafComponentType;
282
J9ROMClass *leafROMClass = leafComponentType->romClass;
283
J9UTF8 *leafName = J9ROMCLASS_CLASSNAME(leafROMClass);
284
UDATA isPrimitive = J9ROMCLASS_IS_PRIMITIVE_TYPE(leafROMClass);
285
UDATA i = 0;
286
for (i = 0; i < arity; ++i) {
287
result = j9str_printf(PORTLIB, bufferCursor, bufferSize, "[");
288
bufferCursor += result;
289
bufferSize -= result;
290
}
291
if (isPrimitive) {
292
result = j9str_printf(PORTLIB, bufferCursor, bufferSize, "%c\n",
293
J9UTF8_DATA(J9ROMCLASS_CLASSNAME(leafComponentType->arrayClass->romClass))[1]);
294
} else {
295
result = j9str_printf(PORTLIB, bufferCursor, bufferSize, "L%.*s;\n",
296
J9UTF8_LENGTH(leafName), J9UTF8_DATA(leafName));
297
}
298
} else {
299
J9UTF8 *className = J9ROMCLASS_CLASSNAME(currentClass->romClass);
300
result = j9str_printf(PORTLIB, bufferCursor, bufferSize, "%.*s\n",
301
J9UTF8_LENGTH(className), J9UTF8_DATA(className));
302
}
303
bufferCursor += result;
304
bufferSize -= result;
305
cumulativeCount += statsArray[classCursor]->objectCount;
306
cumulativeSize += statsArray[classCursor]->aggregateSize;
307
}
308
result = j9str_printf(PORTLIB, bufferCursor, bufferSize,
309
"%5s %14zd %14zd\n",
310
"Total", cumulativeCount, cumulativeSize
311
);
312
bufferCursor += result;
313
return (result > 0) ? (bufferCursor - stringBuffer) : 0;
314
}
315
316
/* The string that keeps its original bytes is string1.
317
* String2 has its bytes set to be string1-> bytes if the offsets already match and the bytes are not already set to the same value
318
* The bytes being set already could happen frequently as this primitive will be used repeatedly to remerge strings in the runtime
319
*/
320
jint JNICALL
321
Java_com_ibm_oti_vm_VM_setCommonData(JNIEnv * env, jclass unused, jobject string1, jobject string2 )
322
{
323
UDATA allowMerge = 0;
324
J9VMThread *vmThread = (J9VMThread *) env;
325
J9JavaVM *javaVM = vmThread->javaVM;
326
327
if (OMR_GC_ALLOCATION_TYPE_SEGREGATED != javaVM->gcAllocationType) {
328
if (string1 == NULL || string2 == NULL) {
329
allowMerge = 0;
330
} else {
331
j9object_t unwrappedString1 = NULL;
332
j9object_t unwrappedString2 = NULL;
333
j9object_t stringBytes1 = NULL;
334
j9object_t stringBytes2 = NULL;
335
336
allowMerge = 1;
337
javaVM->internalVMFunctions->internalEnterVMFromJNI(vmThread);
338
339
unwrappedString1 = J9_JNI_UNWRAP_REFERENCE(string1);
340
unwrappedString2 = J9_JNI_UNWRAP_REFERENCE(string2);
341
342
stringBytes1 = J9VMJAVALANGSTRING_VALUE(vmThread, unwrappedString1);
343
stringBytes2 = J9VMJAVALANGSTRING_VALUE(vmThread, unwrappedString2);
344
345
/* skip merging of bytes if they are already the same. As this primitive is called repeatedly, then its likely the character data will be the same
346
* on repeat calls.
347
*/
348
349
if (stringBytes1 == stringBytes2) {
350
allowMerge = 0;
351
}
352
353
if (allowMerge) {
354
/* set the duplicate string (string2) bytes to be (original) string1's bytes */
355
J9VMJAVALANGSTRING_SET_VALUE(vmThread, unwrappedString2, stringBytes1);
356
}
357
358
javaVM->internalVMFunctions->internalExitVMToJNI(vmThread);
359
}
360
}
361
362
363
return (jint)allowMerge;
364
}
365
366
367
static UDATA
368
allInstances (JNIEnv * env, jclass clazz, jobjectArray target)
369
{
370
J9VMThread *vmThread = (J9VMThread *) env;
371
AllInstancesData data;
372
373
J9Class *unwrappedObj = clazz ? J9VM_J9CLASS_FROM_JCLASS(vmThread, clazz) : NULL;
374
J9IndexableObject *unwrappedArray = target ? *(J9IndexableObject**)target : NULL;
375
376
if (unwrappedObj == NULL) {
377
return 0;
378
}
379
380
if (hasActiveConstructor (vmThread, unwrappedObj)) {
381
/* printf ("\nFOUND A CONSTRUCTOR for the class, allInstances aborted"); */
382
return 0;
383
}
384
385
data.clazz = unwrappedObj;
386
data.target = unwrappedArray;
387
data.vmThread = vmThread;
388
if (unwrappedArray != NULL) {
389
data.size = J9INDEXABLEOBJECT_SIZE (vmThread, unwrappedArray);
390
} else {
391
data.size = 0;
392
}
393
data.storeIndex = 0;
394
data.instanceCount = 0;
395
396
vmThread->javaVM->memoryManagerFunctions->j9mm_iterate_all_objects(vmThread->javaVM, vmThread->javaVM->portLibrary, 0, collectInstances, &data);
397
398
return data.instanceCount;
399
}
400
401
402
static jvmtiIterationControl
403
collectInstances (J9JavaVM *vm, J9MM_IterateObjectDescriptor *objDesc, void *state)
404
{
405
AllInstancesData *data = (AllInstancesData *) state;
406
j9object_t obj = objDesc->object;
407
408
if (J9OBJECT_CLAZZ_VM(vm, obj) == data->clazz) {
409
data->instanceCount++;
410
/* fill in the array only if one was passed in */
411
if (data->target != NULL) {
412
/* if no room, you can ignore the object and not store it */
413
if (data->storeIndex < data->size) {
414
J9JAVAARRAYOFOBJECT_STORE_VM(vm, data->target, (I_32)data->storeIndex, obj);
415
data->storeIndex++;
416
}
417
}
418
}
419
return JVMTI_ITERATION_CONTINUE;
420
}
421
422
423
static int
424
hasActiveConstructor(J9VMThread *vmThread, J9Class *clazz)
425
{
426
J9JavaVM *vm = vmThread->javaVM;
427
J9VMThread * walkThread;
428
429
walkThread = J9_LINKED_LIST_START_DO(vm->mainThread);
430
while (walkThread != NULL) {
431
J9StackWalkState walkState;
432
walkState.walkThread = walkThread;
433
walkState.flags = J9_STACKWALK_ITERATE_FRAMES;
434
walkState.skipCount = 0;
435
walkState.userData1 = (void*) clazz;
436
walkState.userData2 = (void*) 0;
437
walkState.frameWalkFunction = hasConstructor;
438
439
vm->walkStackFrames(vmThread, &walkState);
440
if (walkState.userData2 == (void*)1) {
441
return 1;
442
}
443
walkThread = J9_LINKED_LIST_NEXT_DO(vm->mainThread, walkThread);
444
}
445
return 0;
446
}
447
448
449
static UDATA
450
hasConstructor(J9VMThread *vmThread, J9StackWalkState *state)
451
{
452
J9Method *method = state->method;
453
J9Class *classToFind = (J9Class*) state->userData1;
454
455
if (method == NULL) {
456
return J9_STACKWALK_KEEP_ITERATING;
457
} else {
458
J9Class *methodClass = J9_CLASS_FROM_METHOD(method);
459
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);
460
J9UTF8 *methodName = J9ROMMETHOD_NAME(romMethod);
461
462
/* if the method is a constructor in the class we're looking for then quit looking for more
463
* a constructor is a non-static (to filter clinit) method which starts with '<'.
464
*/
465
if (methodClass == classToFind) {
466
if (!(romMethod->modifiers & J9AccStatic)) {
467
if (J9UTF8_DATA(methodName)[0] == '<') {
468
state->userData2 = (void*)1;
469
return J9_STACKWALK_STOP_ITERATING;
470
}
471
}
472
}
473
return J9_STACKWALK_KEEP_ITERATING;
474
}
475
}
476
477
static J9HashTable *
478
collectHeapStatistics(J9VMThread *vmThread)
479
{
480
J9JavaVM *vm = vmThread->javaVM;
481
J9HashTable *hashTable = hashTableNew(
482
OMRPORT_FROM_J9PORT(vm->portLibrary),
483
J9_GET_CALLSITE(),
484
0, /* let the system choose the initial size of table */
485
sizeof(J9HeapStatisticsTableEntry),
486
sizeof(U_8*),
487
0,
488
J9MEM_CATEGORY_CLASSES,
489
heapStatisticsHashFn,
490
heapStatisticsHashEqualFn,
491
NULL,
492
vm
493
);
494
495
if (NULL != hashTable) {
496
if (vm->memoryManagerFunctions->j9mm_iterate_all_objects(vmThread->javaVM,
497
vm->portLibrary, 0, updateHeapStatistics, hashTable)
498
!= JVMTI_ITERATION_CONTINUE) {
499
hashTableFree(hashTable);
500
hashTable = NULL;
501
}
502
}
503
return hashTable;
504
}
505
506
static jvmtiIterationControl
507
updateHeapStatistics(J9JavaVM *vm, J9MM_IterateObjectDescriptor *objDesc, void *state)
508
{
509
J9HashTable *hashTable = (J9HashTable *) state;
510
j9object_t obj = objDesc->object;
511
J9Class *clazz = J9OBJECT_CLAZZ_VM(vm, obj);
512
struct J9HeapStatisticsTableEntry query;
513
struct J9HeapStatisticsTableEntry *result = NULL;
514
jvmtiIterationControl status = JVMTI_ITERATION_CONTINUE;
515
516
query.clazz = clazz;
517
result = hashTableFind(hashTable, &query);
518
if (NULL == result) {
519
query.objectCount = 1;
520
query.objectSize = vm->memoryManagerFunctions->j9gc_get_object_size_in_bytes(vm, obj);
521
result = hashTableAdd(hashTable, &query);
522
if (NULL == result) {
523
J9VMThread *vmThread = vm->internalVMFunctions->currentVMThread(vm);
524
Trc_JCL_heapStatisticsOOM(vmThread);
525
vm->internalVMFunctions->setNativeOutOfMemoryError(vmThread, 0, 0);
526
status = JVMTI_ITERATION_ABORT;
527
}
528
} else {
529
result->objectCount += 1;
530
}
531
return status;
532
}
533
534
static UDATA
535
heapStatisticsHashEqualFn(void *leftKey, void *rightKey, void *userData)
536
{
537
J9HeapStatisticsTableEntry *entryA = leftKey;
538
J9HeapStatisticsTableEntry *entryB = rightKey;
539
return entryA->clazz == entryB->clazz;
540
}
541
542
static UDATA
543
heapStatisticsHashFn(void *key, void *userData)
544
{
545
J9HeapStatisticsTableEntry *entry = key;
546
return (UDATA) entry->clazz;
547
}
548
549
/*
550
* Dump a String to stderr using the port library.
551
*
552
* @param[in] str - a java.lang.String object
553
*/
554
void JNICALL
555
Java_com_ibm_oti_vm_VM_dumpString(JNIEnv * env, jclass clazz, jstring str)
556
{
557
PORT_ACCESS_FROM_ENV(env);
558
559
if (str == NULL) {
560
j9tty_printf(PORTLIB, "null");
561
} else {
562
/* Note: GetStringUTFChars nul-terminates the resulting chars, even though the spec does not say so */
563
const char * utfChars = (const char *) (*env)->GetStringUTFChars(env, str, NULL);
564
565
if (utfChars != NULL) {
566
Trc_JCL_com_ibm_oti_vm_VM_dumpString(env, utfChars);
567
j9tty_printf(PORTLIB, "%s", utfChars);
568
(*env)->ReleaseStringUTFChars(env, str, utfChars);
569
}
570
}
571
}
572
573