annotate src/share/back/commonRef.c @ 0:37a05a11f281

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