< prev index next >

src/jdk.jdwp.agent/share/native/libjdwp/commonRef.c

Print this page

  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 
< prev index next >