Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/back/commonRef.c
38765 views
1
/*
2
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
#if defined(_ALLBSD_SOURCE)
27
#include <stdint.h> /* for uintptr_t */
28
#endif
29
30
#include "util.h"
31
#include "commonRef.h"
32
33
#define ALL_REFS -1
34
35
/*
36
* Each object sent to the front end is tracked with the RefNode struct
37
* (see util.h).
38
* External to this module, objects are identified by a jlong id which is
39
* simply the sequence number. A weak reference is usually used so that
40
* the presence of a debugger-tracked object will not prevent
41
* its collection. Once an object is collected, its RefNode may be
42
* deleted and the weak ref inside may be reused (these may happen in
43
* either order). Using the sequence number
44
* as the object id prevents ambiguity in the object id when the weak ref
45
* is reused. The RefNode* is stored with the object as it's JVMTI Tag.
46
*
47
* The ref member is changed from weak to strong when
48
* gc of the object is to be prevented.
49
* Whether or not it is strong, it is never exported from this module.
50
*
51
* A reference count of each jobject is also maintained here. It tracks
52
* the number times an object has been referenced through
53
* commonRef_refToID. A RefNode is freed once the reference
54
* count is decremented to 0 (with commonRef_release*), even if the
55
* corresponding object has not been collected.
56
*
57
* One hash table is maintained. The mapping of ID to jobject (or RefNode*)
58
* is handled with one hash table that will re-size itself as the number
59
* of RefNode's grow.
60
*/
61
62
/* Initial hash table size (must be power of 2) */
63
#define HASH_INIT_SIZE 512
64
/* If element count exceeds HASH_EXPAND_SCALE*hash_size we expand & re-hash */
65
#define HASH_EXPAND_SCALE 8
66
/* Maximum hash table size (must be power of 2) */
67
#define HASH_MAX_SIZE (1024*HASH_INIT_SIZE)
68
69
/* Map a key (ID) to a hash bucket */
70
static jint
71
hashBucket(jlong key)
72
{
73
/* Size should always be a power of 2, use mask instead of mod operator */
74
/*LINTED*/
75
return ((jint)key) & (gdata->objectsByIDsize-1);
76
}
77
78
/* Generate a new ID */
79
static jlong
80
newSeqNum(void)
81
{
82
return gdata->nextSeqNum++;
83
}
84
85
/* Create a fresh RefNode structure, create a weak ref and tag the object */
86
static RefNode *
87
createNode(JNIEnv *env, jobject ref)
88
{
89
RefNode *node;
90
jobject weakRef;
91
jvmtiError error;
92
93
/* Could allocate RefNode's in blocks, not sure it would help much */
94
node = (RefNode*)jvmtiAllocate((int)sizeof(RefNode));
95
if (node == NULL) {
96
return NULL;
97
}
98
99
/* Create weak reference to make sure we have a reference */
100
weakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, ref);
101
if (weakRef == NULL) {
102
jvmtiDeallocate(node);
103
return NULL;
104
}
105
106
/* Set tag on weakRef */
107
error = JVMTI_FUNC_PTR(gdata->jvmti, SetTag)
108
(gdata->jvmti, weakRef, ptr_to_jlong(node));
109
if ( error != JVMTI_ERROR_NONE ) {
110
JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, weakRef);
111
jvmtiDeallocate(node);
112
return NULL;
113
}
114
115
/* Fill in RefNode */
116
node->ref = weakRef;
117
node->isStrong = JNI_FALSE;
118
node->count = 1;
119
node->seqNum = newSeqNum();
120
121
/* Count RefNode's created */
122
gdata->objectsByIDcount++;
123
return node;
124
}
125
126
/* Delete a RefNode allocation, delete weak/global ref and clear tag */
127
static void
128
deleteNode(JNIEnv *env, RefNode *node)
129
{
130
LOG_MISC(("Freeing %d (%x)\n", (int)node->seqNum, node->ref));
131
132
if ( node->ref != NULL ) {
133
/* Clear tag */
134
(void)JVMTI_FUNC_PTR(gdata->jvmti,SetTag)
135
(gdata->jvmti, node->ref, NULL_OBJECT_ID);
136
if (node->isStrong) {
137
JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref);
138
} else {
139
JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref);
140
}
141
}
142
gdata->objectsByIDcount--;
143
jvmtiDeallocate(node);
144
}
145
146
/* Change a RefNode to have a strong reference */
147
static jobject
148
strengthenNode(JNIEnv *env, RefNode *node)
149
{
150
if (!node->isStrong) {
151
jobject strongRef;
152
153
strongRef = JNI_FUNC_PTR(env,NewGlobalRef)(env, node->ref);
154
/*
155
* NewGlobalRef on a weak ref will return NULL if the weak
156
* reference has been collected or if out of memory.
157
* We need to distinguish those two occurrences.
158
*/
159
if ((strongRef == NULL) && !isSameObject(env, node->ref, NULL)) {
160
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"NewGlobalRef");
161
}
162
if (strongRef != NULL) {
163
JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref);
164
node->ref = strongRef;
165
node->isStrong = JNI_TRUE;
166
}
167
return strongRef;
168
} else {
169
return node->ref;
170
}
171
}
172
173
/* Change a RefNode to have a weak reference */
174
static jweak
175
weakenNode(JNIEnv *env, RefNode *node)
176
{
177
if (node->isStrong) {
178
jweak weakRef;
179
180
weakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, node->ref);
181
if (weakRef != NULL) {
182
JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref);
183
node->ref = weakRef;
184
node->isStrong = JNI_FALSE;
185
}
186
return weakRef;
187
} else {
188
return node->ref;
189
}
190
}
191
192
/*
193
* Returns the node which contains the common reference for the
194
* given object. The passed reference should not be a weak reference
195
* managed in the object hash table (i.e. returned by commonRef_idToRef)
196
* because no sequence number checking is done.
197
*/
198
static RefNode *
199
findNodeByRef(JNIEnv *env, jobject ref)
200
{
201
jvmtiError error;
202
jlong tag;
203
204
tag = NULL_OBJECT_ID;
205
error = JVMTI_FUNC_PTR(gdata->jvmti,GetTag)(gdata->jvmti, ref, &tag);
206
if ( error == JVMTI_ERROR_NONE ) {
207
RefNode *node;
208
209
node = (RefNode*)jlong_to_ptr(tag);
210
return node;
211
}
212
return NULL;
213
}
214
215
/* Locate and delete a node based on ID */
216
static void
217
deleteNodeByID(JNIEnv *env, jlong id, jint refCount)
218
{
219
jint slot;
220
RefNode *node;
221
RefNode *prev;
222
223
slot = hashBucket(id);
224
node = gdata->objectsByID[slot];
225
prev = NULL;
226
227
while (node != NULL) {
228
if (id == node->seqNum) {
229
if (refCount != ALL_REFS) {
230
node->count -= refCount;
231
} else {
232
node->count = 0;
233
}
234
if (node->count <= 0) {
235
if ( node->count < 0 ) {
236
EXIT_ERROR(AGENT_ERROR_INTERNAL,"RefNode count < 0");
237
}
238
/* Detach from id hash table */
239
if (prev == NULL) {
240
gdata->objectsByID[slot] = node->next;
241
} else {
242
prev->next = node->next;
243
}
244
deleteNode(env, node);
245
}
246
break;
247
}
248
prev = node;
249
node = node->next;
250
}
251
}
252
253
/*
254
* Returns the node stored in the object hash table for the given object
255
* id. The id should be a value previously returned by
256
* commonRef_refToID.
257
*
258
* NOTE: It is possible that a match is found here, but that the object
259
* is garbage collected by the time the caller inspects node->ref.
260
* Callers should take care using the node->ref object returned here.
261
*
262
*/
263
static RefNode *
264
findNodeByID(JNIEnv *env, jlong id)
265
{
266
jint slot;
267
RefNode *node;
268
RefNode *prev;
269
270
slot = hashBucket(id);
271
node = gdata->objectsByID[slot];
272
prev = NULL;
273
274
while (node != NULL) {
275
if ( id == node->seqNum ) {
276
if ( prev != NULL ) {
277
/* Re-order hash list so this one is up front */
278
prev->next = node->next;
279
node->next = gdata->objectsByID[slot];
280
gdata->objectsByID[slot] = node;
281
}
282
break;
283
}
284
node = node->next;
285
}
286
return node;
287
}
288
289
/* Initialize the hash table stored in gdata area */
290
static void
291
initializeObjectsByID(int size)
292
{
293
/* Size should always be a power of 2 */
294
if ( size > HASH_MAX_SIZE ) size = HASH_MAX_SIZE;
295
gdata->objectsByIDsize = size;
296
gdata->objectsByIDcount = 0;
297
gdata->objectsByID = (RefNode**)jvmtiAllocate((int)sizeof(RefNode*)*size);
298
(void)memset(gdata->objectsByID, 0, (int)sizeof(RefNode*)*size);
299
}
300
301
/* hash in a RefNode */
302
static void
303
hashIn(RefNode *node)
304
{
305
jint slot;
306
307
/* Add to id hashtable */
308
slot = hashBucket(node->seqNum);
309
node->next = gdata->objectsByID[slot];
310
gdata->objectsByID[slot] = node;
311
}
312
313
/* Allocate and add RefNode to hash table */
314
static RefNode *
315
newCommonRef(JNIEnv *env, jobject ref)
316
{
317
RefNode *node;
318
319
/* Allocate the node and set it up */
320
node = createNode(env, ref);
321
if ( node == NULL ) {
322
return NULL;
323
}
324
325
/* See if hash table needs expansion */
326
if ( gdata->objectsByIDcount > gdata->objectsByIDsize*HASH_EXPAND_SCALE &&
327
gdata->objectsByIDsize < HASH_MAX_SIZE ) {
328
RefNode **old;
329
int oldsize;
330
int newsize;
331
int i;
332
333
/* Save old information */
334
old = gdata->objectsByID;
335
oldsize = gdata->objectsByIDsize;
336
/* Allocate new hash table */
337
gdata->objectsByID = NULL;
338
newsize = oldsize*HASH_EXPAND_SCALE;
339
if ( newsize > HASH_MAX_SIZE ) newsize = HASH_MAX_SIZE;
340
initializeObjectsByID(newsize);
341
/* Walk over old one and hash in all the RefNodes */
342
for ( i = 0 ; i < oldsize ; i++ ) {
343
RefNode *onode;
344
345
onode = old[i];
346
while (onode != NULL) {
347
RefNode *next;
348
349
next = onode->next;
350
hashIn(onode);
351
onode = next;
352
}
353
}
354
jvmtiDeallocate(old);
355
}
356
357
/* Add to id hashtable */
358
hashIn(node);
359
return node;
360
}
361
362
/* Initialize the commonRefs usage */
363
void
364
commonRef_initialize(void)
365
{
366
gdata->refLock = debugMonitorCreate("JDWP Reference Table Monitor");
367
gdata->nextSeqNum = 1; /* 0 used for error indication */
368
initializeObjectsByID(HASH_INIT_SIZE);
369
}
370
371
/* Reset the commonRefs usage */
372
void
373
commonRef_reset(JNIEnv *env)
374
{
375
debugMonitorEnter(gdata->refLock); {
376
int i;
377
378
for (i = 0; i < gdata->objectsByIDsize; i++) {
379
RefNode *node;
380
381
node = gdata->objectsByID[i];
382
while (node != NULL) {
383
RefNode *next;
384
385
next = node->next;
386
deleteNode(env, node);
387
node = next;
388
}
389
gdata->objectsByID[i] = NULL;
390
}
391
392
/* Toss entire hash table and re-create a new one */
393
jvmtiDeallocate(gdata->objectsByID);
394
gdata->objectsByID = NULL;
395
gdata->nextSeqNum = 1; /* 0 used for error indication */
396
initializeObjectsByID(HASH_INIT_SIZE);
397
398
} debugMonitorExit(gdata->refLock);
399
}
400
401
/*
402
* Given a reference obtained from JNI or JVMTI, return an object
403
* id suitable for sending to the debugger front end.
404
*/
405
jlong
406
commonRef_refToID(JNIEnv *env, jobject ref)
407
{
408
jlong id;
409
410
if (ref == NULL) {
411
return NULL_OBJECT_ID;
412
}
413
414
id = NULL_OBJECT_ID;
415
debugMonitorEnter(gdata->refLock); {
416
RefNode *node;
417
418
node = findNodeByRef(env, ref);
419
if (node == NULL) {
420
node = newCommonRef(env, ref);
421
if ( node != NULL ) {
422
id = node->seqNum;
423
}
424
} else {
425
id = node->seqNum;
426
node->count++;
427
}
428
} debugMonitorExit(gdata->refLock);
429
return id;
430
}
431
432
/*
433
* Given an object ID obtained from the debugger front end, return a
434
* strong, global reference to that object (or NULL if the object
435
* has been collected). The reference can then be used for JNI and
436
* JVMTI calls. Caller is resposible for deleting the returned reference.
437
*/
438
jobject
439
commonRef_idToRef(JNIEnv *env, jlong id)
440
{
441
jobject ref;
442
443
ref = NULL;
444
debugMonitorEnter(gdata->refLock); {
445
RefNode *node;
446
447
node = findNodeByID(env, id);
448
if (node != NULL) {
449
if (node->isStrong) {
450
saveGlobalRef(env, node->ref, &ref);
451
} else {
452
jobject lref;
453
454
lref = JNI_FUNC_PTR(env,NewLocalRef)(env, node->ref);
455
if ( lref == NULL ) {
456
/* Object was GC'd shortly after we found the node */
457
deleteNodeByID(env, node->seqNum, ALL_REFS);
458
} else {
459
saveGlobalRef(env, node->ref, &ref);
460
JNI_FUNC_PTR(env,DeleteLocalRef)(env, lref);
461
}
462
}
463
}
464
} debugMonitorExit(gdata->refLock);
465
return ref;
466
}
467
468
/* Deletes the global reference that commonRef_idToRef() created */
469
void
470
commonRef_idToRef_delete(JNIEnv *env, jobject ref)
471
{
472
if ( ref==NULL ) {
473
return;
474
}
475
tossGlobalRef(env, &ref);
476
}
477
478
479
/* Prevent garbage collection of an object */
480
jvmtiError
481
commonRef_pin(jlong id)
482
{
483
jvmtiError error;
484
485
error = JVMTI_ERROR_NONE;
486
if (id == NULL_OBJECT_ID) {
487
return error;
488
}
489
debugMonitorEnter(gdata->refLock); {
490
JNIEnv *env;
491
RefNode *node;
492
493
env = getEnv();
494
node = findNodeByID(env, id);
495
if (node == NULL) {
496
error = AGENT_ERROR_INVALID_OBJECT;
497
} else {
498
jobject strongRef;
499
500
strongRef = strengthenNode(env, node);
501
if (strongRef == NULL) {
502
/*
503
* Referent has been collected, clean up now.
504
*/
505
error = AGENT_ERROR_INVALID_OBJECT;
506
deleteNodeByID(env, id, ALL_REFS);
507
}
508
}
509
} debugMonitorExit(gdata->refLock);
510
return error;
511
}
512
513
/* Permit garbage collection of an object */
514
jvmtiError
515
commonRef_unpin(jlong id)
516
{
517
jvmtiError error;
518
519
error = JVMTI_ERROR_NONE;
520
debugMonitorEnter(gdata->refLock); {
521
JNIEnv *env;
522
RefNode *node;
523
524
env = getEnv();
525
node = findNodeByID(env, id);
526
if (node != NULL) {
527
jweak weakRef;
528
529
weakRef = weakenNode(env, node);
530
if (weakRef == NULL) {
531
error = AGENT_ERROR_OUT_OF_MEMORY;
532
}
533
}
534
} debugMonitorExit(gdata->refLock);
535
return error;
536
}
537
538
/* Release tracking of an object by ID */
539
void
540
commonRef_release(JNIEnv *env, jlong id)
541
{
542
debugMonitorEnter(gdata->refLock); {
543
deleteNodeByID(env, id, 1);
544
} debugMonitorExit(gdata->refLock);
545
}
546
547
void
548
commonRef_releaseMultiple(JNIEnv *env, jlong id, jint refCount)
549
{
550
debugMonitorEnter(gdata->refLock); {
551
deleteNodeByID(env, id, refCount);
552
} debugMonitorExit(gdata->refLock);
553
}
554
555
/* Get rid of RefNodes for objects that no longer exist */
556
void
557
commonRef_compact(void)
558
{
559
JNIEnv *env;
560
RefNode *node;
561
RefNode *prev;
562
int i;
563
564
env = getEnv();
565
debugMonitorEnter(gdata->refLock); {
566
if ( gdata->objectsByIDsize > 0 ) {
567
/*
568
* Walk through the id-based hash table. Detach any nodes
569
* for which the ref has been collected.
570
*/
571
for (i = 0; i < gdata->objectsByIDsize; i++) {
572
node = gdata->objectsByID[i];
573
prev = NULL;
574
while (node != NULL) {
575
/* Has the object been collected? */
576
if ( (!node->isStrong) &&
577
isSameObject(env, node->ref, NULL)) {
578
RefNode *freed;
579
580
/* Detach from the ID list */
581
if (prev == NULL) {
582
gdata->objectsByID[i] = node->next;
583
} else {
584
prev->next = node->next;
585
}
586
freed = node;
587
node = node->next;
588
deleteNode(env, freed);
589
} else {
590
prev = node;
591
node = node->next;
592
}
593
}
594
}
595
}
596
} debugMonitorExit(gdata->refLock);
597
}
598
599
/* Lock the commonRef tables */
600
void
601
commonRef_lock(void)
602
{
603
debugMonitorEnter(gdata->refLock);
604
}
605
606
/* Unlock the commonRef tables */
607
void
608
commonRef_unlock(void)
609
{
610
debugMonitorExit(gdata->refLock);
611
}
612
613