1 /*
2 * Copyright (c) 1998, 2022, 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
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) */
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 /* Returns true if this is a strong reference, meaning that either or both of
86 isPinAll and isCommonPin are true. */
87 static jboolean
88 isStrong(RefNode* node)
89 {
90 return node->isPinAll || node->isCommonPin;
91 }
92
93 /* Create a fresh RefNode structure, create a weak ref and tag the object */
94 static RefNode *
95 createNode(JNIEnv *env, jobject ref)
96 {
97 RefNode *node;
98 jobject strongOrWeakRef;
99 jvmtiError error;
100 jboolean pinAll = gdata->pinAllCount != 0;
101
102 /* Could allocate RefNode's in blocks, not sure it would help much */
103 node = (RefNode*)jvmtiAllocate((int)sizeof(RefNode));
104 if (node == NULL) {
105 return NULL;
106 }
107
108 if (pinAll) {
109 /* Create strong reference to make sure we have a reference */
110 strongOrWeakRef = JNI_FUNC_PTR(env,NewGlobalRef)(env, ref);
111 } else {
112 /* Create weak reference to make sure we have a reference */
113 strongOrWeakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, ref);
114
115 // NewWeakGlobalRef can throw OOM, clear exception here.
116 if ((*env)->ExceptionCheck(env)) {
117 (*env)->ExceptionClear(env);
118 jvmtiDeallocate(node);
119 return NULL;
120 }
121 }
122
123 /* Set tag on strongOrWeakRef */
124 error = JVMTI_FUNC_PTR(gdata->jvmti, SetTag)
125 (gdata->jvmti, strongOrWeakRef, ptr_to_jlong(node));
126 if ( error != JVMTI_ERROR_NONE ) {
127 if (pinAll) {
128 JNI_FUNC_PTR(env,DeleteGlobalRef)(env, strongOrWeakRef);
129 } else {
130 JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, strongOrWeakRef);
131 }
132 jvmtiDeallocate(node);
133 return NULL;
134 }
135
136 /* Fill in RefNode */
137 node->ref = strongOrWeakRef;
138 node->count = 1;
139 node->isPinAll = pinAll;
140 node->isCommonPin = JNI_FALSE;
141 node->seqNum = newSeqNum();
142
143 /* Count RefNode's created */
144 gdata->objectsByIDcount++;
145 return node;
146 }
147
148 /* Delete a RefNode allocation, delete weak/global ref and clear tag */
149 static void
150 deleteNode(JNIEnv *env, RefNode *node)
151 {
152 LOG_MISC(("Freeing %d (%x)\n", (int)node->seqNum, node->ref));
153
154 if ( node->ref != NULL ) {
155 /* Clear tag */
156 (void)JVMTI_FUNC_PTR(gdata->jvmti,SetTag)
157 (gdata->jvmti, node->ref, NULL_OBJECT_ID);
158 if (isStrong(node)) {
184 }
185 if (strongRef != NULL) {
186 JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref);
187 node->ref = strongRef;
188 } else {
189 return NULL;
190 }
191 }
192 if (isPinAll) {
193 node->isPinAll = JNI_TRUE;
194 } else {
195 node->isCommonPin = JNI_TRUE;
196 }
197 return node->ref;
198 }
199
200 /* Change a RefNode to have a weak reference */
201 static jweak
202 weakenNode(JNIEnv *env, RefNode *node, jboolean isUnpinAll)
203 {
204 jboolean willStillBeStrong = (node->isPinAll && !isUnpinAll) || (node->isCommonPin && isUnpinAll);
205
206 // If the node is strong, but the reason(s) for it being strong
207 // will no longer exist, then weaken it.
208 if (isStrong(node) && !willStillBeStrong) {
209 jweak weakRef;
210
211 weakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, node->ref);
212 // NewWeakGlobalRef can throw OOM, clear exception here.
213 if ((*env)->ExceptionCheck(env)) {
214 (*env)->ExceptionClear(env);
215 }
216
217 if (weakRef != NULL) {
218 JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref);
219 node->ref = weakRef;
220 } else {
221 return NULL;
222 }
223 }
224
|
1 /*
2 * Copyright (c) 1998, 2026, 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
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 * References to value objects are always strong.
48 *
49 * The ref member is changed from weak to strong when
50 * gc of the object is to be prevented.
51 * Whether or not it is strong, it is never exported from this module.
52 *
53 * A reference count of each jobject is also maintained here. It tracks
54 * the number times an object has been referenced through
55 * commonRef_refToID. A RefNode is freed once the reference
56 * count is decremented to 0 (with commonRef_release*), even if the
57 * corresponding object has not been collected.
58 *
59 * One hash table is maintained. The mapping of ID to jobject (or RefNode*)
60 * is handled with one hash table that will re-size itself as the number
61 * of RefNode's grow.
62 */
63
64 /* Initial hash table size (must be power of 2) */
65 #define HASH_INIT_SIZE 512
66 /* If element count exceeds HASH_EXPAND_SCALE*hash_size we expand & re-hash */
67 #define HASH_EXPAND_SCALE 8
68 /* Maximum hash table size (must be power of 2) */
72 static jint
73 hashBucket(jlong key)
74 {
75 /* Size should always be a power of 2, use mask instead of mod operator */
76 /*LINTED*/
77 return ((jint)key) & (gdata->objectsByIDsize-1);
78 }
79
80 /* Generate a new ID */
81 static jlong
82 newSeqNum(void)
83 {
84 return gdata->nextSeqNum++;
85 }
86
87 /* Returns true if this is a strong reference, meaning that either or both of
88 isPinAll and isCommonPin are true. */
89 static jboolean
90 isStrong(RefNode* node)
91 {
92 return node->isValueObject || node->isPinAll || node->isCommonPin;
93 }
94
95 /* Create a fresh RefNode structure, create a weak ref and tag the object */
96 static RefNode *
97 createNode(JNIEnv *env, jobject ref)
98 {
99 RefNode *node;
100 jobject strongOrWeakRef;
101 jvmtiError error;
102 jboolean pinAll = gdata->pinAllCount != 0;
103 jboolean isValueObject;
104
105 /* Could allocate RefNode's in blocks, not sure it would help much */
106 node = (RefNode*)jvmtiAllocate((int)sizeof(RefNode));
107 if (node == NULL) {
108 return NULL;
109 }
110
111 isValueObject = JNI_FUNC_PTR(env,IsValueObject)(env, ref);
112
113 if (pinAll || isValueObject) {
114 /* Create strong reference to make sure we have a reference */
115 strongOrWeakRef = JNI_FUNC_PTR(env,NewGlobalRef)(env, ref);
116 } else {
117 /* Create weak reference to make sure we have a reference */
118 strongOrWeakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, ref);
119
120 // NewWeakGlobalRef can throw OOM, clear exception here.
121 if ((*env)->ExceptionCheck(env)) {
122 (*env)->ExceptionClear(env);
123 jvmtiDeallocate(node);
124 return NULL;
125 }
126 }
127
128 /* Set tag on strongOrWeakRef */
129 error = JVMTI_FUNC_PTR(gdata->jvmti, SetTag)
130 (gdata->jvmti, strongOrWeakRef, ptr_to_jlong(node));
131 if ( error != JVMTI_ERROR_NONE ) {
132 if (pinAll) {
133 JNI_FUNC_PTR(env,DeleteGlobalRef)(env, strongOrWeakRef);
134 } else {
135 JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, strongOrWeakRef);
136 }
137 jvmtiDeallocate(node);
138 return NULL;
139 }
140
141 /* Fill in RefNode */
142 node->ref = strongOrWeakRef;
143 node->count = 1;
144 node->isValueObject = isValueObject;
145 node->isPinAll = pinAll;
146 node->isCommonPin = JNI_FALSE;
147 node->seqNum = newSeqNum();
148
149 /* Count RefNode's created */
150 gdata->objectsByIDcount++;
151 return node;
152 }
153
154 /* Delete a RefNode allocation, delete weak/global ref and clear tag */
155 static void
156 deleteNode(JNIEnv *env, RefNode *node)
157 {
158 LOG_MISC(("Freeing %d (%x)\n", (int)node->seqNum, node->ref));
159
160 if ( node->ref != NULL ) {
161 /* Clear tag */
162 (void)JVMTI_FUNC_PTR(gdata->jvmti,SetTag)
163 (gdata->jvmti, node->ref, NULL_OBJECT_ID);
164 if (isStrong(node)) {
190 }
191 if (strongRef != NULL) {
192 JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref);
193 node->ref = strongRef;
194 } else {
195 return NULL;
196 }
197 }
198 if (isPinAll) {
199 node->isPinAll = JNI_TRUE;
200 } else {
201 node->isCommonPin = JNI_TRUE;
202 }
203 return node->ref;
204 }
205
206 /* Change a RefNode to have a weak reference */
207 static jweak
208 weakenNode(JNIEnv *env, RefNode *node, jboolean isUnpinAll)
209 {
210 jboolean willStillBeStrong = node->isValueObject || (node->isPinAll && !isUnpinAll) || (node->isCommonPin && isUnpinAll);
211
212 // If the node is strong, but the reason(s) for it being strong
213 // will no longer exist, then weaken it.
214 if (isStrong(node) && !willStillBeStrong) {
215 jweak weakRef;
216
217 weakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, node->ref);
218 // NewWeakGlobalRef can throw OOM, clear exception here.
219 if ((*env)->ExceptionCheck(env)) {
220 (*env)->ExceptionClear(env);
221 }
222
223 if (weakRef != NULL) {
224 JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref);
225 node->ref = weakRef;
226 } else {
227 return NULL;
228 }
229 }
230
|