author | alanb |
Fri, 07 Apr 2017 08:05:54 +0000 | |
changeset 44545 | 83b611b88ac8 |
parent 29272 | 3363c00f4a4e |
permissions | -rw-r--r-- |
2 | 1 |
/* |
23010
6dadb192ad81
8029235: Update copyright year to match last edit in jdk8 jdk repository for 2013
lana
parents:
21278
diff
changeset
|
2 |
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 24 |
*/ |
25 |
||
12047
320a714614e9
7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
5506
diff
changeset
|
26 |
#if defined(_ALLBSD_SOURCE) |
320a714614e9
7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
5506
diff
changeset
|
27 |
#include <stdint.h> /* for uintptr_t */ |
320a714614e9
7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
5506
diff
changeset
|
28 |
#endif |
320a714614e9
7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
5506
diff
changeset
|
29 |
|
2 | 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 |
|
21278 | 55 |
* corresponding object has not been collected. |
2 | 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); |
|
29272
3363c00f4a4e
8030708: warnings from b119 for jdk/src/share/back: JNI exception pending
dsamersoff
parents:
25859
diff
changeset
|
101 |
// NewWeakGlobalRef can throw OOM, clear exception here. |
3363c00f4a4e
8030708: warnings from b119 for jdk/src/share/back: JNI exception pending
dsamersoff
parents:
25859
diff
changeset
|
102 |
if ((*env)->ExceptionCheck(env)) { |
3363c00f4a4e
8030708: warnings from b119 for jdk/src/share/back: JNI exception pending
dsamersoff
parents:
25859
diff
changeset
|
103 |
(*env)->ExceptionClear(env); |
2 | 104 |
jvmtiDeallocate(node); |
105 |
return NULL; |
|
106 |
} |
|
107 |
||
108 |
/* Set tag on weakRef */ |
|
109 |
error = JVMTI_FUNC_PTR(gdata->jvmti, SetTag) |
|
110 |
(gdata->jvmti, weakRef, ptr_to_jlong(node)); |
|
111 |
if ( error != JVMTI_ERROR_NONE ) { |
|
112 |
JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, weakRef); |
|
113 |
jvmtiDeallocate(node); |
|
114 |
return NULL; |
|
115 |
} |
|
116 |
||
117 |
/* Fill in RefNode */ |
|
118 |
node->ref = weakRef; |
|
119 |
node->isStrong = JNI_FALSE; |
|
120 |
node->count = 1; |
|
121 |
node->seqNum = newSeqNum(); |
|
122 |
||
123 |
/* Count RefNode's created */ |
|
124 |
gdata->objectsByIDcount++; |
|
125 |
return node; |
|
126 |
} |
|
127 |
||
128 |
/* Delete a RefNode allocation, delete weak/global ref and clear tag */ |
|
129 |
static void |
|
130 |
deleteNode(JNIEnv *env, RefNode *node) |
|
131 |
{ |
|
132 |
LOG_MISC(("Freeing %d (%x)\n", (int)node->seqNum, node->ref)); |
|
133 |
||
134 |
if ( node->ref != NULL ) { |
|
135 |
/* Clear tag */ |
|
136 |
(void)JVMTI_FUNC_PTR(gdata->jvmti,SetTag) |
|
137 |
(gdata->jvmti, node->ref, NULL_OBJECT_ID); |
|
138 |
if (node->isStrong) { |
|
139 |
JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref); |
|
140 |
} else { |
|
141 |
JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref); |
|
142 |
} |
|
143 |
} |
|
144 |
gdata->objectsByIDcount--; |
|
145 |
jvmtiDeallocate(node); |
|
146 |
} |
|
147 |
||
148 |
/* Change a RefNode to have a strong reference */ |
|
149 |
static jobject |
|
150 |
strengthenNode(JNIEnv *env, RefNode *node) |
|
151 |
{ |
|
152 |
if (!node->isStrong) { |
|
153 |
jobject strongRef; |
|
154 |
||
155 |
strongRef = JNI_FUNC_PTR(env,NewGlobalRef)(env, node->ref); |
|
156 |
/* |
|
157 |
* NewGlobalRef on a weak ref will return NULL if the weak |
|
158 |
* reference has been collected or if out of memory. |
|
29272
3363c00f4a4e
8030708: warnings from b119 for jdk/src/share/back: JNI exception pending
dsamersoff
parents:
25859
diff
changeset
|
159 |
* It never throws OOM. |
2 | 160 |
* We need to distinguish those two occurrences. |
161 |
*/ |
|
162 |
if ((strongRef == NULL) && !isSameObject(env, node->ref, NULL)) { |
|
163 |
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"NewGlobalRef"); |
|
164 |
} |
|
165 |
if (strongRef != NULL) { |
|
166 |
JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref); |
|
167 |
node->ref = strongRef; |
|
168 |
node->isStrong = JNI_TRUE; |
|
169 |
} |
|
170 |
return strongRef; |
|
171 |
} else { |
|
172 |
return node->ref; |
|
173 |
} |
|
174 |
} |
|
175 |
||
176 |
/* Change a RefNode to have a weak reference */ |
|
177 |
static jweak |
|
178 |
weakenNode(JNIEnv *env, RefNode *node) |
|
179 |
{ |
|
180 |
if (node->isStrong) { |
|
181 |
jweak weakRef; |
|
182 |
||
183 |
weakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, node->ref); |
|
29272
3363c00f4a4e
8030708: warnings from b119 for jdk/src/share/back: JNI exception pending
dsamersoff
parents:
25859
diff
changeset
|
184 |
// NewWeakGlobalRef can throw OOM, clear exception here. |
3363c00f4a4e
8030708: warnings from b119 for jdk/src/share/back: JNI exception pending
dsamersoff
parents:
25859
diff
changeset
|
185 |
if ((*env)->ExceptionCheck(env)) { |
3363c00f4a4e
8030708: warnings from b119 for jdk/src/share/back: JNI exception pending
dsamersoff
parents:
25859
diff
changeset
|
186 |
(*env)->ExceptionClear(env); |
3363c00f4a4e
8030708: warnings from b119 for jdk/src/share/back: JNI exception pending
dsamersoff
parents:
25859
diff
changeset
|
187 |
} |
3363c00f4a4e
8030708: warnings from b119 for jdk/src/share/back: JNI exception pending
dsamersoff
parents:
25859
diff
changeset
|
188 |
|
2 | 189 |
if (weakRef != NULL) { |
190 |
JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref); |
|
191 |
node->ref = weakRef; |
|
192 |
node->isStrong = JNI_FALSE; |
|
193 |
} |
|
194 |
return weakRef; |
|
195 |
} else { |
|
196 |
return node->ref; |
|
197 |
} |
|
198 |
} |
|
199 |
||
200 |
/* |
|
201 |
* Returns the node which contains the common reference for the |
|
202 |
* given object. The passed reference should not be a weak reference |
|
203 |
* managed in the object hash table (i.e. returned by commonRef_idToRef) |
|
204 |
* because no sequence number checking is done. |
|
205 |
*/ |
|
206 |
static RefNode * |
|
207 |
findNodeByRef(JNIEnv *env, jobject ref) |
|
208 |
{ |
|
209 |
jvmtiError error; |
|
210 |
jlong tag; |
|
211 |
||
212 |
tag = NULL_OBJECT_ID; |
|
213 |
error = JVMTI_FUNC_PTR(gdata->jvmti,GetTag)(gdata->jvmti, ref, &tag); |
|
214 |
if ( error == JVMTI_ERROR_NONE ) { |
|
215 |
RefNode *node; |
|
216 |
||
217 |
node = (RefNode*)jlong_to_ptr(tag); |
|
218 |
return node; |
|
219 |
} |
|
220 |
return NULL; |
|
221 |
} |
|
222 |
||
223 |
/* Locate and delete a node based on ID */ |
|
224 |
static void |
|
225 |
deleteNodeByID(JNIEnv *env, jlong id, jint refCount) |
|
226 |
{ |
|
227 |
jint slot; |
|
228 |
RefNode *node; |
|
229 |
RefNode *prev; |
|
230 |
||
231 |
slot = hashBucket(id); |
|
232 |
node = gdata->objectsByID[slot]; |
|
233 |
prev = NULL; |
|
234 |
||
235 |
while (node != NULL) { |
|
236 |
if (id == node->seqNum) { |
|
237 |
if (refCount != ALL_REFS) { |
|
238 |
node->count -= refCount; |
|
239 |
} else { |
|
240 |
node->count = 0; |
|
241 |
} |
|
242 |
if (node->count <= 0) { |
|
243 |
if ( node->count < 0 ) { |
|
244 |
EXIT_ERROR(AGENT_ERROR_INTERNAL,"RefNode count < 0"); |
|
245 |
} |
|
246 |
/* Detach from id hash table */ |
|
247 |
if (prev == NULL) { |
|
248 |
gdata->objectsByID[slot] = node->next; |
|
249 |
} else { |
|
250 |
prev->next = node->next; |
|
251 |
} |
|
252 |
deleteNode(env, node); |
|
253 |
} |
|
254 |
break; |
|
255 |
} |
|
256 |
prev = node; |
|
257 |
node = node->next; |
|
258 |
} |
|
259 |
} |
|
260 |
||
261 |
/* |
|
262 |
* Returns the node stored in the object hash table for the given object |
|
263 |
* id. The id should be a value previously returned by |
|
264 |
* commonRef_refToID. |
|
265 |
* |
|
266 |
* NOTE: It is possible that a match is found here, but that the object |
|
267 |
* is garbage collected by the time the caller inspects node->ref. |
|
268 |
* Callers should take care using the node->ref object returned here. |
|
269 |
* |
|
270 |
*/ |
|
271 |
static RefNode * |
|
272 |
findNodeByID(JNIEnv *env, jlong id) |
|
273 |
{ |
|
274 |
jint slot; |
|
275 |
RefNode *node; |
|
276 |
RefNode *prev; |
|
277 |
||
278 |
slot = hashBucket(id); |
|
279 |
node = gdata->objectsByID[slot]; |
|
280 |
prev = NULL; |
|
281 |
||
282 |
while (node != NULL) { |
|
283 |
if ( id == node->seqNum ) { |
|
284 |
if ( prev != NULL ) { |
|
285 |
/* Re-order hash list so this one is up front */ |
|
286 |
prev->next = node->next; |
|
287 |
node->next = gdata->objectsByID[slot]; |
|
288 |
gdata->objectsByID[slot] = node; |
|
289 |
} |
|
290 |
break; |
|
291 |
} |
|
292 |
node = node->next; |
|
293 |
} |
|
294 |
return node; |
|
295 |
} |
|
296 |
||
297 |
/* Initialize the hash table stored in gdata area */ |
|
298 |
static void |
|
299 |
initializeObjectsByID(int size) |
|
300 |
{ |
|
301 |
/* Size should always be a power of 2 */ |
|
302 |
if ( size > HASH_MAX_SIZE ) size = HASH_MAX_SIZE; |
|
303 |
gdata->objectsByIDsize = size; |
|
304 |
gdata->objectsByIDcount = 0; |
|
305 |
gdata->objectsByID = (RefNode**)jvmtiAllocate((int)sizeof(RefNode*)*size); |
|
306 |
(void)memset(gdata->objectsByID, 0, (int)sizeof(RefNode*)*size); |
|
307 |
} |
|
308 |
||
309 |
/* hash in a RefNode */ |
|
310 |
static void |
|
311 |
hashIn(RefNode *node) |
|
312 |
{ |
|
313 |
jint slot; |
|
314 |
||
315 |
/* Add to id hashtable */ |
|
316 |
slot = hashBucket(node->seqNum); |
|
317 |
node->next = gdata->objectsByID[slot]; |
|
318 |
gdata->objectsByID[slot] = node; |
|
319 |
} |
|
320 |
||
321 |
/* Allocate and add RefNode to hash table */ |
|
322 |
static RefNode * |
|
323 |
newCommonRef(JNIEnv *env, jobject ref) |
|
324 |
{ |
|
325 |
RefNode *node; |
|
326 |
||
327 |
/* Allocate the node and set it up */ |
|
328 |
node = createNode(env, ref); |
|
329 |
if ( node == NULL ) { |
|
330 |
return NULL; |
|
331 |
} |
|
332 |
||
333 |
/* See if hash table needs expansion */ |
|
334 |
if ( gdata->objectsByIDcount > gdata->objectsByIDsize*HASH_EXPAND_SCALE && |
|
335 |
gdata->objectsByIDsize < HASH_MAX_SIZE ) { |
|
336 |
RefNode **old; |
|
337 |
int oldsize; |
|
338 |
int newsize; |
|
339 |
int i; |
|
340 |
||
341 |
/* Save old information */ |
|
342 |
old = gdata->objectsByID; |
|
343 |
oldsize = gdata->objectsByIDsize; |
|
344 |
/* Allocate new hash table */ |
|
345 |
gdata->objectsByID = NULL; |
|
346 |
newsize = oldsize*HASH_EXPAND_SCALE; |
|
347 |
if ( newsize > HASH_MAX_SIZE ) newsize = HASH_MAX_SIZE; |
|
348 |
initializeObjectsByID(newsize); |
|
349 |
/* Walk over old one and hash in all the RefNodes */ |
|
350 |
for ( i = 0 ; i < oldsize ; i++ ) { |
|
351 |
RefNode *onode; |
|
352 |
||
353 |
onode = old[i]; |
|
354 |
while (onode != NULL) { |
|
355 |
RefNode *next; |
|
356 |
||
357 |
next = onode->next; |
|
358 |
hashIn(onode); |
|
359 |
onode = next; |
|
360 |
} |
|
361 |
} |
|
362 |
jvmtiDeallocate(old); |
|
363 |
} |
|
364 |
||
365 |
/* Add to id hashtable */ |
|
366 |
hashIn(node); |
|
367 |
return node; |
|
368 |
} |
|
369 |
||
370 |
/* Initialize the commonRefs usage */ |
|
371 |
void |
|
372 |
commonRef_initialize(void) |
|
373 |
{ |
|
374 |
gdata->refLock = debugMonitorCreate("JDWP Reference Table Monitor"); |
|
375 |
gdata->nextSeqNum = 1; /* 0 used for error indication */ |
|
376 |
initializeObjectsByID(HASH_INIT_SIZE); |
|
377 |
} |
|
378 |
||
379 |
/* Reset the commonRefs usage */ |
|
380 |
void |
|
381 |
commonRef_reset(JNIEnv *env) |
|
382 |
{ |
|
383 |
debugMonitorEnter(gdata->refLock); { |
|
384 |
int i; |
|
385 |
||
386 |
for (i = 0; i < gdata->objectsByIDsize; i++) { |
|
387 |
RefNode *node; |
|
388 |
||
389 |
node = gdata->objectsByID[i]; |
|
390 |
while (node != NULL) { |
|
391 |
RefNode *next; |
|
392 |
||
393 |
next = node->next; |
|
394 |
deleteNode(env, node); |
|
395 |
node = next; |
|
396 |
} |
|
397 |
gdata->objectsByID[i] = NULL; |
|
398 |
} |
|
399 |
||
400 |
/* Toss entire hash table and re-create a new one */ |
|
401 |
jvmtiDeallocate(gdata->objectsByID); |
|
402 |
gdata->objectsByID = NULL; |
|
403 |
gdata->nextSeqNum = 1; /* 0 used for error indication */ |
|
404 |
initializeObjectsByID(HASH_INIT_SIZE); |
|
405 |
||
406 |
} debugMonitorExit(gdata->refLock); |
|
407 |
} |
|
408 |
||
409 |
/* |
|
410 |
* Given a reference obtained from JNI or JVMTI, return an object |
|
411 |
* id suitable for sending to the debugger front end. |
|
412 |
*/ |
|
413 |
jlong |
|
414 |
commonRef_refToID(JNIEnv *env, jobject ref) |
|
415 |
{ |
|
416 |
jlong id; |
|
417 |
||
418 |
if (ref == NULL) { |
|
419 |
return NULL_OBJECT_ID; |
|
420 |
} |
|
421 |
||
422 |
id = NULL_OBJECT_ID; |
|
423 |
debugMonitorEnter(gdata->refLock); { |
|
424 |
RefNode *node; |
|
425 |
||
426 |
node = findNodeByRef(env, ref); |
|
427 |
if (node == NULL) { |
|
428 |
node = newCommonRef(env, ref); |
|
429 |
if ( node != NULL ) { |
|
430 |
id = node->seqNum; |
|
431 |
} |
|
432 |
} else { |
|
433 |
id = node->seqNum; |
|
434 |
node->count++; |
|
435 |
} |
|
436 |
} debugMonitorExit(gdata->refLock); |
|
437 |
return id; |
|
438 |
} |
|
439 |
||
440 |
/* |
|
441 |
* Given an object ID obtained from the debugger front end, return a |
|
442 |
* strong, global reference to that object (or NULL if the object |
|
443 |
* has been collected). The reference can then be used for JNI and |
|
444 |
* JVMTI calls. Caller is resposible for deleting the returned reference. |
|
445 |
*/ |
|
446 |
jobject |
|
447 |
commonRef_idToRef(JNIEnv *env, jlong id) |
|
448 |
{ |
|
449 |
jobject ref; |
|
450 |
||
451 |
ref = NULL; |
|
452 |
debugMonitorEnter(gdata->refLock); { |
|
453 |
RefNode *node; |
|
454 |
||
455 |
node = findNodeByID(env, id); |
|
456 |
if (node != NULL) { |
|
457 |
if (node->isStrong) { |
|
458 |
saveGlobalRef(env, node->ref, &ref); |
|
459 |
} else { |
|
460 |
jobject lref; |
|
461 |
||
462 |
lref = JNI_FUNC_PTR(env,NewLocalRef)(env, node->ref); |
|
29272
3363c00f4a4e
8030708: warnings from b119 for jdk/src/share/back: JNI exception pending
dsamersoff
parents:
25859
diff
changeset
|
463 |
// NewLocalRef never throws OOM. |
2 | 464 |
if ( lref == NULL ) { |
465 |
/* Object was GC'd shortly after we found the node */ |
|
466 |
deleteNodeByID(env, node->seqNum, ALL_REFS); |
|
467 |
} else { |
|
468 |
saveGlobalRef(env, node->ref, &ref); |
|
469 |
JNI_FUNC_PTR(env,DeleteLocalRef)(env, lref); |
|
470 |
} |
|
471 |
} |
|
472 |
} |
|
473 |
} debugMonitorExit(gdata->refLock); |
|
474 |
return ref; |
|
475 |
} |
|
476 |
||
477 |
/* Deletes the global reference that commonRef_idToRef() created */ |
|
478 |
void |
|
479 |
commonRef_idToRef_delete(JNIEnv *env, jobject ref) |
|
480 |
{ |
|
481 |
if ( ref==NULL ) { |
|
482 |
return; |
|
483 |
} |
|
484 |
tossGlobalRef(env, &ref); |
|
485 |
} |
|
486 |
||
487 |
||
488 |
/* Prevent garbage collection of an object */ |
|
489 |
jvmtiError |
|
490 |
commonRef_pin(jlong id) |
|
491 |
{ |
|
492 |
jvmtiError error; |
|
493 |
||
494 |
error = JVMTI_ERROR_NONE; |
|
495 |
if (id == NULL_OBJECT_ID) { |
|
496 |
return error; |
|
497 |
} |
|
498 |
debugMonitorEnter(gdata->refLock); { |
|
499 |
JNIEnv *env; |
|
500 |
RefNode *node; |
|
501 |
||
502 |
env = getEnv(); |
|
503 |
node = findNodeByID(env, id); |
|
504 |
if (node == NULL) { |
|
505 |
error = AGENT_ERROR_INVALID_OBJECT; |
|
506 |
} else { |
|
507 |
jobject strongRef; |
|
508 |
||
509 |
strongRef = strengthenNode(env, node); |
|
510 |
if (strongRef == NULL) { |
|
511 |
/* |
|
512 |
* Referent has been collected, clean up now. |
|
513 |
*/ |
|
514 |
error = AGENT_ERROR_INVALID_OBJECT; |
|
515 |
deleteNodeByID(env, id, ALL_REFS); |
|
516 |
} |
|
517 |
} |
|
518 |
} debugMonitorExit(gdata->refLock); |
|
519 |
return error; |
|
520 |
} |
|
521 |
||
522 |
/* Permit garbage collection of an object */ |
|
523 |
jvmtiError |
|
524 |
commonRef_unpin(jlong id) |
|
525 |
{ |
|
526 |
jvmtiError error; |
|
527 |
||
528 |
error = JVMTI_ERROR_NONE; |
|
529 |
debugMonitorEnter(gdata->refLock); { |
|
530 |
JNIEnv *env; |
|
531 |
RefNode *node; |
|
532 |
||
533 |
env = getEnv(); |
|
534 |
node = findNodeByID(env, id); |
|
535 |
if (node != NULL) { |
|
536 |
jweak weakRef; |
|
537 |
||
538 |
weakRef = weakenNode(env, node); |
|
539 |
if (weakRef == NULL) { |
|
540 |
error = AGENT_ERROR_OUT_OF_MEMORY; |
|
541 |
} |
|
542 |
} |
|
543 |
} debugMonitorExit(gdata->refLock); |
|
544 |
return error; |
|
545 |
} |
|
546 |
||
547 |
/* Release tracking of an object by ID */ |
|
548 |
void |
|
549 |
commonRef_release(JNIEnv *env, jlong id) |
|
550 |
{ |
|
551 |
debugMonitorEnter(gdata->refLock); { |
|
552 |
deleteNodeByID(env, id, 1); |
|
553 |
} debugMonitorExit(gdata->refLock); |
|
554 |
} |
|
555 |
||
556 |
void |
|
557 |
commonRef_releaseMultiple(JNIEnv *env, jlong id, jint refCount) |
|
558 |
{ |
|
559 |
debugMonitorEnter(gdata->refLock); { |
|
560 |
deleteNodeByID(env, id, refCount); |
|
561 |
} debugMonitorExit(gdata->refLock); |
|
562 |
} |
|
563 |
||
564 |
/* Get rid of RefNodes for objects that no longer exist */ |
|
565 |
void |
|
566 |
commonRef_compact(void) |
|
567 |
{ |
|
568 |
JNIEnv *env; |
|
569 |
RefNode *node; |
|
570 |
RefNode *prev; |
|
571 |
int i; |
|
572 |
||
573 |
env = getEnv(); |
|
574 |
debugMonitorEnter(gdata->refLock); { |
|
575 |
if ( gdata->objectsByIDsize > 0 ) { |
|
576 |
/* |
|
577 |
* Walk through the id-based hash table. Detach any nodes |
|
578 |
* for which the ref has been collected. |
|
579 |
*/ |
|
580 |
for (i = 0; i < gdata->objectsByIDsize; i++) { |
|
581 |
node = gdata->objectsByID[i]; |
|
582 |
prev = NULL; |
|
583 |
while (node != NULL) { |
|
584 |
/* Has the object been collected? */ |
|
585 |
if ( (!node->isStrong) && |
|
586 |
isSameObject(env, node->ref, NULL)) { |
|
587 |
RefNode *freed; |
|
588 |
||
589 |
/* Detach from the ID list */ |
|
590 |
if (prev == NULL) { |
|
591 |
gdata->objectsByID[i] = node->next; |
|
592 |
} else { |
|
593 |
prev->next = node->next; |
|
594 |
} |
|
595 |
freed = node; |
|
596 |
node = node->next; |
|
597 |
deleteNode(env, freed); |
|
598 |
} else { |
|
599 |
prev = node; |
|
600 |
node = node->next; |
|
601 |
} |
|
602 |
} |
|
603 |
} |
|
604 |
} |
|
605 |
} debugMonitorExit(gdata->refLock); |
|
606 |
} |
|
607 |
||
608 |
/* Lock the commonRef tables */ |
|
609 |
void |
|
610 |
commonRef_lock(void) |
|
611 |
{ |
|
612 |
debugMonitorEnter(gdata->refLock); |
|
613 |
} |
|
614 |
||
615 |
/* Unlock the commonRef tables */ |
|
616 |
void |
|
617 |
commonRef_unlock(void) |
|
618 |
{ |
|
619 |
debugMonitorExit(gdata->refLock); |
|
620 |
} |