inspector.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 1,888 行 · 第 1/5 页
C
1,888 行
/* * 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 "javavm/include/porting/doubleword.h"#include "javavm/include/porting/time.h"#include "javavm/include/objects.h"#include "javavm/include/classes.h"#include "javavm/include/gc_common.h"#include "javavm/include/inspector.h"#include "javavm/include/indirectmem.h"#include "javavm/include/jit_common.h"#include "native/common/jni_util.h"#include "generated/offsets/java_lang_String.h"#ifdef CVM_CLASSLOADING#include "generated/offsets/java_lang_ClassLoader.h"#endif/*===========================================================================*/#ifdef CVM_INSPECTOR/* Purpose: Disables GC. To be used for debugging purposes ONLY. *//* Returns: CVM_TRUE if successful. */CVMBool CVMgcDisableGC(void){ CVMExecEnv *ee = CVMgetEE(); CVMGCLocker *inspectorGCLocker = &CVMglobals.inspectorGCLocker; CVMBool success = CVM_TRUE; if (CVMgcLockerGetLockCount(inspectorGCLocker) > 0) { CVMconsolePrintf("GC is already disabled! No need to disable.\n"); } else { CVMinspectorGCLockerLock(inspectorGCLocker, ee); } return success;}/* Purpose: Enables GC. To be used for debugging purposes ONLY. *//* Returns: CVM_TRUE if successful. */CVMBool CVMgcEnableGC(void){ CVMExecEnv *ee = CVMgetEE(); CVMBool success = CVM_TRUE; CVMGCLocker *inspectorGCLocker = &CVMglobals.inspectorGCLocker; if (CVMgcLockerGetLockCount(inspectorGCLocker) == 0) { CVMconsolePrintf("GC was not disabled! No need to enable.\n"); } else { CVMinspectorGCLockerUnlock(inspectorGCLocker, ee); } return success;}/* Purpose: Checks to see if GC is disabled. To be used for debugging purposes ONLY. *//* Returns: CVM_TRUE if GC is disabled. */CVMBool CVMgcIsDisabled(void){ CVMGCLocker *inspectorGCLocker = &CVMglobals.inspectorGCLocker; return CVMgcLockerIsActive(inspectorGCLocker);}/* Purpose: Forces the GC to keep all objects alive or not. To be used for debugging purposes ONLY. */void CVMgcKeepAllObjectsAlive(CVMBool keepAlive){ CVMglobals.inspector.keepAllObjectsAlive = keepAlive;}/*================================================= Inspector GC Locker ==*//* Purpose: Deactivates the debug GC lock. *//* NOTE: Calls to CVMinspectorGCLockerLock() & CVMinspectorGCLockerUnlock() can be nested. Can be called while GC safe or unsafe. Based on CVMgcLockerUnlock() with the addition of the cv notification. */void CVMinspectorGCLockerUnlock(CVMGCLocker *self, CVMExecEnv *current_ee){ if (CVMD_isgcSafe(current_ee)) { CVMsysMutexLock (current_ee, &CVMglobals.gcLockerLock); } CVMsysMicroLock(current_ee, CVM_GC_LOCKER_MICROLOCK); if (self->lockCount > 0) { self->lockCount--; /* The following notification is for waking up those threads that were waiting using CVMgcLockerWait(). However, CVMgcLockerWait() is only called after all threads are GC safe. If the current thread is still GC unsafe, then we know that there are no threads waiting using CVMgcLockerWait() and no notification is needed. */ if (CVMD_isgcSafe(current_ee)) { if (self->lockCount == 0 && self->wasContended) { CVMcondvarNotify(&CVMglobals.gcLockerCV); } } } CVMsysMicroUnlock(current_ee, CVM_GC_LOCKER_MICROLOCK); if (CVMD_isgcSafe(current_ee)) { CVMsysMutexUnlock (current_ee, &CVMglobals.gcLockerLock); }}/* Purpose: Wait for the debug GC lock to deactivate. *//* NOTE: This is only used by GC code to wait for the debug GCLocker to be deactivated. This function assumes that the current thread already holds the gcLockerLock. *//* NOTE: Called while all threads are GC safe. */void CVMinspectorGCLockerWait(CVMGCLocker *self, CVMExecEnv *current_ee){ CVMassert(CVMD_gcAllThreadsAreSafe()); CVMassert(CVMsysMutexOwner(&CVMglobals.gcLockerLock) == current_ee); while (self->lockCount > 0) { self->wasContended = CVM_TRUE; CVMsysMutexWait(current_ee, &CVMglobals.gcLockerLock, &CVMglobals.gcLockerCV, CVMlongConstZero()); }}/*================================================= ObjectValidityVerifier ==*//* Purpose: Call back function for CVMgcIsValidHeapObject(). *//* Returns: CVM_FALSE if the specified object is found (i.e. abort scan). Else returns CVM_TRUE. */static CVMBoolCVMgcIsValidHeapObjectCallBack(CVMObject *obj, CVMClassBlock *cb, CVMUint32 size, void *data){ if (obj == (CVMObject *)data) { return CVM_FALSE; /* Found match. Hence abort. */ } return CVM_TRUE;}/* Purpose: Checks to see if the specified pointer corresponds to a valid object in the heap. *//* Returns: CVM_TRUE if the specified object is valid. Else returns CVM_FALSE. */CVMBool CVMgcIsValidHeapObject(CVMExecEnv *ee, CVMObject *obj){ CVMBool status = CVMgcimplIterateHeap(ee, CVMgcIsValidHeapObjectCallBack, (void *) obj); return (status == CVM_FALSE);}/* Purpose: Checks to see if the specified pointer corresponds to a valid object. *//* Returns: CVM_TRUE if the specified object is valid. Else returns CVM_FALSE. */CVMBool CVMgcIsValidObject(CVMExecEnv *ee, CVMObject *obj){ /* Check if pointer is a valid heap object: */ if (CVMgcIsValidHeapObject(ee, obj)) { return CVM_TRUE; } /* If its not an object on the heap, check if pointer is a valid ROMized object: */ if (CVMpreloaderIsPreloadedObject(obj)) { return CVM_TRUE; } return CVM_FALSE;}/*================================================== ObjectReferenceFinder ==*//* * Reference Finder routines *//* Purpose: Call back function to process a non-null reference. */static voidCVMgcDumpReferencesCallBack(CVMObject **ref, void *data){ CVMGCProfilingInfo *info = (CVMGCProfilingInfo *) data; CVMObject *targetObj = (CVMObject *) info->data; if (*ref == targetObj) { const char *typestr = "INVALID"; switch (info->type) { case CVMGCRefType_GLOBAL_ROOT: { typestr = "GLOBAL ROOT"; break; } case CVMGCRefType_PRELOADER_STATICS: { typestr = "PRELOADER STATICS ROOT"; break; } case CVMGCRefType_CLASS_STATICS: { /* Check for the case where we came across the ICell in the classblock which points to the self class object. This is not a valid reference to the targetObj i.e. the class in this case: */ if (ref == (CVMObject **) CVMcbJavaInstance(info->u.clazz.cb)) { /* This is kept here for future reference: CVMconsolePrintf(" Ref 0x%x type: ICell inside classblock" " of %C pointing to itself\n", ref, info->u.clazz.cb); */ return; } CVMconsolePrintf(" Ref 0x%x type: STATIC FIELD of class %C\n", ref, info->u.clazz.cb); return; } case CVMGCRefType_LOCAL_ROOTS: { typestr = "LOCAL ROOT"; break; } case CVMGCRefType_UNKNOWN_STACK_FRAME: { typestr = "UNKNOWN STACK_FRAME ROOT"; break; } case CVMGCRefType_JAVA_FRAME: { CVMconsolePrintf(" Ref 0x%x type: JAVA FRAME ROOT ee 0x%x frame %d\n", ref, info->u.frame.ee, info->u.frame.frameNumber); return; } case CVMGCRefType_JNI_FRAME: { CVMconsolePrintf(" Ref 0x%x type: JNI FRAME ROOT ee 0x%x frame %d\n", ref, info->u.frame.ee, info->u.frame.frameNumber); return; } case CVMGCRefType_TRANSITION_FRAME: { typestr = "TRANSITION FRAME ROOT"; break; } default: CVMassert(CVM_FALSE); } CVMconsolePrintf(" Ref 0x%x type: %s\n", ref, typestr); }}/* Purpose: Dump references from the fields of an object. */static CVMBoolCVMgcDumpReferencesObjectCallback(CVMObject *obj, CVMClassBlock *cb, CVMUint32 size, void *data){ CVMExecEnv *ee = CVMgetEE(); CVMObject *targetObj = (CVMObject *) data; CVMGCOptions gcOpts = { /* isUpdatingObjectPointers */ CVM_FALSE, /* discoverWeakReferences */ CVM_FALSE, /* isProfilingPass */ CVM_TRUE }; CVMGCOptions *gcOptsPtr = &gcOpts; CVMobjectWalkRefsWithSpecialHandling(ee, gcOptsPtr, obj, CVMobjectGetClassWord(obj), { if (*refPtr == targetObj) { CVMconsolePrintf(" Ref 0x%x type: OBJECT_FIELD Addr: 0x%x Size:" " %d \tClass: %C\n", refPtr, obj, size, cb); } }, CVMgcDumpReferencesCallBack, data); return CVM_TRUE;}/* Purpose: Scans all roots and the heap for references to the specified object. *//* NOTE: Should only be called from a GC safe state with the HeapLock already acquired by the current thread to prevent GC from running. The current thread should already have called "stopped the world" (see CVMgcStopTheWorld() for details on how to stop the world). */static void CVMgcDumpReferences(CVMObject *obj){ CVMExecEnv *ee = CVMgetEE(); CVMGCOptions gcOpts = { /* isUpdatingObjectPointers */ CVM_FALSE, /* discoverWeakReferences */ CVM_FALSE, /* isProfilingPass */ CVM_TRUE }; CVMassert(CVMsysMutexOwner(&CVMglobals.heapLock) == ee); CVMassert(CVMD_isgcSafe(ee)); CVMconsolePrintf("List of references to object 0x%x (%C):\n", obj, CVMobjectGetClass(obj)); CVMgcClearClassMarks(ee, NULL); CVMgcScanRoots(ee, &gcOpts, CVMgcDumpReferencesCallBack, obj); CVMgcimplIterateHeap(ee, CVMgcDumpReferencesObjectCallback, obj);}#ifdef CVM_ROOT_FINDERstatic void CVMgcDumpGCRoots(CVMObject *obj){ CVMExecEnv *ee = CVMgetEE(); CVMGCOptions gcOpts = { /* isUpdatingObjectPointers */ CVM_FALSE, /* discoverWeakReferences */ CVM_FALSE, /* isProfilingPass */ CVM_TRUE }; CVMassert(CVMsysMutexOwner(&CVMglobals.heapLock) == ee); CVMassert(CVMD_isgcSafe(ee)); CVMconsolePrintf("List of references to object 0x%x (%C):\n", obj, CVMobjectGetClass(obj)); /* FIXME: this is where we have to set up data structures to track the references so that we can traverse each reverse reference. */ CVMgcClearClassMarks(ee, NULL); CVMgcScanRoots(ee, &gcOpts, CVMgcDumpReferencesCallBack, obj); CVMgcimplIterateHeap(ee, CVMgcDumpReferencesObjectCallback, obj);}#endif/* * Heap dump related routines *//* * Locks heap and dumps contents given a 'dumpFunc' */static voiddumper(CVMExecEnv* ee, void (*dumpFunc)(CVMExecEnv* ee, void *data), void *data){ CVMSysMutex* heapLock = &CVMglobals.heapLock;#ifdef CVM_JIT CVMSysMutex* jitLock = &CVMglobals.jitLock;#endif#ifdef CVM_JIT /* We need to become safe all to do the dump. So, we need to enter the * jitLock first without blocking. Refuse to dump heap if recursively * entering lock, or if another thread has already locked the lock. */ if (!CVMsysMutexTryLock(ee, jitLock)) { CVMconsolePrintf("Cannot acquire needed locks without blocking -- " "another thread already owns the heap lock!\n"); return; }#endif /* Try to enter the heap lock without blocking. Refuse to dump heap * if recursively entering lock, or if another thread has already locked * the lock. */ if (!CVMsysMutexTryLock(ee, heapLock)) { CVMconsolePrintf("Cannot acquire needed locks without blocking -- " "another thread already owns the heap lock!\n"); goto abort1; } /* We did obtain the lock without blocking. Now just make sure it's not a recursive entry. */ if (CVMsysMutexCount(heapLock) > 1) { CVMconsolePrintf("Cannot dump heap -- "
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?