commonref.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 610 行 · 第 1/2 页
C
610 行
/* * @(#)commonRef.c 1.24 06/10/25 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */#include "util.h"#include "commonRef.h"#define ALL_REFS -1/* * Each object sent to the front end is tracked with the RefNode struct * (see util.h). * External to this module, objects are identified by a jlong id which is * simply the sequence number. A weak reference is usually used so that * the presence of a debugger-tracked object will not prevent * its collection. Once an object is collected, its RefNode may be * deleted and the weak ref inside may be reused (these may happen in * either order). Using the sequence number * as the object id prevents ambiguity in the object id when the weak ref * is reused. The RefNode* is stored with the object as it's JVMTI Tag. * * The ref member is changed from weak to strong when * gc of the object is to be prevented. * Whether or not it is strong, it is never exported from this module. * * A reference count of each jobject is also maintained here. It tracks * the number times an object has been referenced through * commonRef_refToID. A RefNode is freed once the reference * count is decremented to 0 (with commonRef_release*), even if the * correspoding object has not been collected. * * One hash table is maintained. The mapping of ID to jobject (or RefNode*) * is handled with one hash table that will re-size itself as the number * of RefNode's grow. *//* Initial hash table size (must be power of 2) */#define HASH_INIT_SIZE 512/* If element count exceeds HASH_EXPAND_SCALE*hash_size we expand & re-hash */#define HASH_EXPAND_SCALE 8/* Maximum hash table size (must be power of 2) */#define HASH_MAX_SIZE (1024*HASH_INIT_SIZE)/* Map a key (ID) to a hash bucket */static jint hashBucket(jlong key) { /* Size should always be a power of 2, use mask instead of mod operator */ /*LINTED*/ return ((jint)key) & (gdata->objectsByIDsize-1);}/* Generate a new ID */static jlong newSeqNum(void){ return gdata->nextSeqNum++;}/* Create a fresh RefNode structure, create a weak ref and tag the object */static RefNode *createNode(JNIEnv *env, jobject ref) { RefNode *node; jobject weakRef; jvmtiError error; /* Could allocate RefNode's in blocks, not sure it would help much */ node = (RefNode*)jvmtiAllocate((int)sizeof(RefNode)); if (node == NULL) { return NULL; } /* Create weak reference to make sure we have a reference */ weakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, ref); if (weakRef == NULL) { jvmtiDeallocate(node); return NULL; } /* Set tag on weakRef */ error = JVMTI_FUNC_PTR(gdata->jvmti, SetTag) (gdata->jvmti, weakRef, (jlong)((jint)node)); if ( error != JVMTI_ERROR_NONE ) { JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, weakRef); jvmtiDeallocate(node); return NULL; } /* Fill in RefNode */ node->ref = weakRef; node->isStrong = JNI_FALSE; node->count = 1; node->seqNum = newSeqNum(); /* Count RefNode's created */ gdata->objectsByIDcount++; return node;}/* Delete a RefNode allocation, delete weak/global ref and clear tag */static void deleteNode(JNIEnv *env, RefNode *node){ LOG_MISC(("Freeing %d (%x)\n", (int)node->seqNum, node->ref)); if ( node->ref != NULL ) { /* Clear tag */ (void)JVMTI_FUNC_PTR(gdata->jvmti,SetTag) (gdata->jvmti, node->ref, NULL_OBJECT_ID); if (node->isStrong) { JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref); } else { JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref); } } gdata->objectsByIDcount--; jvmtiDeallocate(node);}/* Change a RefNode to have a strong reference */static jobjectstrengthenNode(JNIEnv *env, RefNode *node) { if (!node->isStrong) { jobject strongRef; strongRef = JNI_FUNC_PTR(env,NewGlobalRef)(env, node->ref); /* * NewGlobalRef on a weak ref will return NULL if the weak * reference has been collected or if out of memory. * We need to distinguish those two occurrences. */ if ((strongRef == NULL) && !isSameObject(env, node->ref, NULL)) { EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"NewGlobalRef"); } if (strongRef != NULL) { JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref); node->ref = strongRef; node->isStrong = JNI_TRUE; } return strongRef; } else { return node->ref; }}/* Change a RefNode to have a weak reference */static jweakweakenNode(JNIEnv *env, RefNode *node) { if (node->isStrong) { jweak weakRef; weakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, node->ref); if (weakRef != NULL) { JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref); node->ref = weakRef; node->isStrong = JNI_FALSE; } return weakRef; } else { return node->ref; }}/* * Returns the node which contains the common reference for the * given object. The passed reference should not be a weak reference * managed in the object hash table (i.e. returned by commonRef_idToRef) * because no sequence number checking is done. */static RefNode *findNodeByRef(JNIEnv *env, jobject ref) { jvmtiError error; jlong tag; tag = NULL_OBJECT_ID; error = JVMTI_FUNC_PTR(gdata->jvmti,GetTag)(gdata->jvmti, ref, &tag); if ( error == JVMTI_ERROR_NONE ) { RefNode *node; node = (RefNode*)((jint)tag); return node; } return NULL;}/* Locate and delete a node based on ID */static void deleteNodeByID(JNIEnv *env, jlong id, jint refCount) { jint slot; RefNode *node; RefNode *prev; slot = hashBucket(id); node = gdata->objectsByID[slot]; prev = NULL; while (node != NULL) { if (id == node->seqNum) { if (refCount != ALL_REFS) { node->count -= refCount; } else { node->count = 0; } if (node->count <= 0) { if ( node->count < 0 ) { EXIT_ERROR(AGENT_ERROR_INTERNAL,"RefNode count < 0"); } /* Detach from id hash table */ if (prev == NULL) { gdata->objectsByID[slot] = node->next; } else { prev->next = node->next; } deleteNode(env, node); } break; } prev = node; node = node->next; }}/* * Returns the node stored in the object hash table for the given object * id. The id should be a value previously returned by * commonRef_refToID. * * NOTE: It is possible that a match is found here, but that the object * is garbage collected by the time the caller inspects node->ref. * Callers should take care using the node->ref object returned here. * */static RefNode *findNodeByID(JNIEnv *env, jlong id) { jint slot; RefNode *node; RefNode *prev; slot = hashBucket(id); node = gdata->objectsByID[slot]; prev = NULL; while (node != NULL) { if ( id == node->seqNum ) { if ( prev != NULL ) { /* Re-order hash list so this one is up front */ prev->next = node->next; node->next = gdata->objectsByID[slot]; gdata->objectsByID[slot] = node; } break; } node = node->next; } return node;}/* Initialize the hash table stored in gdata area */static void initializeObjectsByID(int size) { /* Size should always be a power of 2 */ if ( size > HASH_MAX_SIZE ) size = HASH_MAX_SIZE; gdata->objectsByIDsize = size; gdata->objectsByIDcount = 0; gdata->objectsByID = (RefNode**)jvmtiAllocate((int)sizeof(RefNode*)*size); (void)memset(gdata->objectsByID, 0, (int)sizeof(RefNode*)*size);}/* hash in a RefNode */static voidhashIn(RefNode *node){ jint slot; /* Add to id hashtable */ slot = hashBucket(node->seqNum);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?