jvmpi.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 1,650 行 · 第 1/5 页
C
1,650 行
/* * @(#)jvmpi.c 1.33 06/10/10 * * Portions Copyright 2000-2008 Sun Microsystems, Inc. All Rights * Reserved. Use is subject to license terms. * 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. *//* * Copyright 2005 Intel Corporation. All rights reserved. */#ifdef CVM_JVMPI#include "javavm/include/porting/time.h"#include "javavm/include/objects.h"#include "javavm/include/classes.h"#include "javavm/include/defs.h"#include "javavm/include/directmem.h"#include "javavm/include/gc_common.h"#include "javavm/include/globalroots.h"#include "javavm/include/globals.h"#include "javavm/include/interpreter.h"#include "javavm/include/jvmpi_impl.h"#include "javavm/include/localroots.h"#include "javavm/include/named_sys_monitor.h"#include "javavm/include/preloader.h"#include "javavm/include/stackmaps.h"#include "javavm/include/stackwalk.h"#include "javavm/include/sync.h"#include "javavm/include/utils.h"#include "javavm/export/jvm.h"#include "javavm/include/gc/gc_impl.h"#include "javavm/include/porting/doubleword.h"#include "javavm/include/porting/endianness.h"#include "javavm/include/opcodes.h"#include "generated/offsets/java_lang_Thread.h"#include "generated/offsets/java_lang_ThreadGroup.h"#ifdef CVM_INSPECTOR#include "javavm/include/inspector.h"#endif/* IAI-07: Notify JVMPI of compilations and decompilations. */#ifdef CVM_JIT#include "javavm/include/jit/jitcodebuffer.h"#endif/* NOTE: Calling from VM code to the profiler agent: ========================================== This implementation of JVMPI tries to only invoke the profiler agent when the thread is in a GC safe state before. This is done to minimize the chance of the profiler locking up any thread which wants to run a GC cycle. In addition, JVMPI also provides a means to disable GC through the use of the CVMGCLocker mechanism. This mechanism only prevents the GC cycle from actually starting. Unlike having a GC unsafe state, it does not block the thread wanting to run a GC cycle. When GC is disabled, a request for a synchronous GC will end up doing nothing in the call to the GC. Reason for why JVMPI sometimes uses its own CVMjvmpiGetICellDirect(): ==================================================================== GC need to post events (JVMPI_EVENT_OBJECT_FREE and JVMPI_EVENT_OBJECT_MOVE) while in a consistent state. Under such circumstances, the JVMPI implementation is not allowed to become GC unsafe in order to call CVMID_icellDirect(). CVMjvmpiGetICellDirect() is created to bypass the assertion that the thread is GC unsafe. It is OK to use CVMjvmpiGetICellDirect() instead of CVMID_icellDirect() in the following cases: 1. The current thread is the GC thread (assumming GC runs in a single thread) and a GC cycle is in progress. Since the current thread is the GC thread, there won't be any other thread changing the addresses of objects. Hence it is safe to dereference the ICell without becoming GC unsafe first. Of course, if GC becomes multi-threaded in the future, the code will have to be revised to deal with this. 2. GC has already been disabled by call a call to CVMjvmpiDisableGC() previously. Hence, GC won't be running in another thread and changing the addresses of objects. As a result, it is safe to dereference the ICell without becoming GC unsafe first. 3. The current thread is already in a GC unsafe state. 4. The current thread is holding the heapLock. This ensures that GC cannot start up in another thread. Usually, this condition is true when the current thread is in the process of allocating an object. The condition necessary for safe direct access comprising the above 4 criteria can be tested by using the CVMjvmpiIsSafeToAccessDirectObject() macro. Reason for why JVMPI always become GC safe before calling the agent: =================================================================== When the VM is not in a GC cycle, the profiling agent may choose to call JNI functions. This means that we must ensure that the profiling agent is operating in a GC safe state at that point. Hence, in every case where JVMPI calls across to the profiling agent, it will have to ensure the current thread is in a GC safe state if the VM is not in the midst of a GC cycle. When in the midst of a GC cycle, JVMPI is not allowed to change the GC safety state of the current thread. GC Safety and Deadlock Issues: ============================= If the current thread is in the midst of a GC cycle, the profiling agent is not allowed to become GC unsafe (e.g. by invoking JNI APIs). There is currently no way to enforce this. Fortunately, the JVMPI specs give us a little help here. According to the JVMPI specs: "Usage Note: It is not safe to invoke JNI functions in arbirtrary JVMPI event handlers. JVMPI events may be issued in virtual machine states that are not suitable for executing JNI functions. The profiler agent may only invoke JNI functions in multithreaded mode (as defined by the JVMPI specification) and must take extremely care under these circumstances to avoid race conditions, dead locks, and infinite recursions." Also according to the JVMPI specs, the VM is deemed to be in thread suspended (i.e. single-threaded) mode when issuing GC events. Hence, we can have a little faith that a well-behaved profiler won't make any JNI calls when processing received GC events. ========================================================================== Assumptions: 1. Availability of a CVMExecEnv: =============================== It is assumed that the profiler agent won't call into the VM from a thread that wasn't created by the VM (this is after all probably why JVMPI provides a thread creation mechanism). In order for the VM to do anything useful for the profiler, it will need a CVMExecEnv. If the profiler agent calls upon a JVMPI function from a thread not created by the VM, the VM will almost never be able to satisfy the functionality requested anyway. Hence, this JVMPI implementation will assume that a CVMExecEnv will always be available. ==========================================================================*//*============================================================================= Prototype of methods which make up the JVMPI Interface:*/static void CVMjvmpi_NotifyEvent(JVMPI_Event *event);static jint CVMjvmpi_EnableEvent(jint event_type, void *arg);static jint CVMjvmpi_DisableEvent(jint event_type, void *arg);static jint CVMjvmpi_RequestEvent(jint event_type, void *arg);static void CVMjvmpi_GetCallTrace(JVMPI_CallTrace *trace, jint depth);static void CVMjvmpi_ProfilerExit(jint exit_code);static JVMPI_RawMonitor CVMjvmpi_RawMonitorCreate(char *lock_name);static void CVMjvmpi_RawMonitorEnter(JVMPI_RawMonitor lock_id);static void CVMjvmpi_RawMonitorExit(JVMPI_RawMonitor lock_id);static void CVMjvmpi_RawMonitorWait(JVMPI_RawMonitor lock_id, jlong ms);static void CVMjvmpi_RawMonitorNotifyAll(JVMPI_RawMonitor lock_id);static void CVMjvmpi_RawMonitorDestroy(JVMPI_RawMonitor lock_id);static jlong CVMjvmpi_GetCurrentThreadCpuTime(void);static void CVMjvmpi_SuspendThread(JNIEnv *env);static void CVMjvmpi_ResumeThread(JNIEnv *env);static jint CVMjvmpi_GetThreadStatus(JNIEnv *env);static jboolean CVMjvmpi_ThreadHasRun(JNIEnv *env);static jint CVMjvmpi_CreateSystemThread(char *name, jint priority, jvmpi_void_function_of_void f);static void CVMjvmpi_SetThreadLocalStorage(JNIEnv *env, void *ptr);static void *CVMjvmpi_GetThreadLocalStorage(JNIEnv *env);static void CVMjvmpi_DisableGC(void);static void CVMjvmpi_EnableGC(void);static void CVMjvmpi_RunGC(void);static jobjectID CVMjvmpi_GetThreadObject(JNIEnv *env);static jobjectID CVMjvmpi_GetMethodClass(jmethodID mid);static jobject CVMjvmpi_jobjectID2jobject(jobjectID obj);static jobjectID CVMjvmpi_jobject2jobjectID(jobject ref);/*============================================================================= Prototype of other PRIVATE methods of the JVMPI implementation:*/static jint CVMjvmpiPostHeapDumpEvent(CVMExecEnv *ee, int dumpLevel);static jint CVMjvmpiPostMonitorDumpEvent(CVMExecEnv *ee);static jint CVMjvmpiPostObjectDumpEvent(CVMObject *obj);static void CVMjvmpiPostMonitorContendedExitEvent2(CVMExecEnv *ee, CVMProfiledMonitor *mon);static const CVMClassBlock *CVMjvmpiClassInstance2ClassBlock(CVMExecEnv *ee, CVMObject *obj);static void CVMjvmpiDisableAllNotification(CVMExecEnv *ee);static void CVMjvmpiDisableGC(CVMExecEnv *ee);static void CVMjvmpiDoCleanup(void);static void CVMjvmpiEnableGC(CVMExecEnv *ee);static CVMUint8 CVMjvmpiGetClassType(const CVMClassBlock *cb);static CVMInt32 CVMjvmpiGetLineNumber(CVMMethodBlock *mb, CVMFrame *frame);static CVMUint16 CVMjvmpiGetThreadStatus(CVMExecEnv *ee);static jintCVMjvmpiPostClassLoadEvent2(CVMExecEnv *ee, const CVMClassBlock *cb, CVMBool isRequestedEvent);static voidCVMjvmpiPostObjectAllocEvent2(CVMExecEnv *ee, CVMObject *obj, CVMBool isRequestedEvent);static jintCVMjvmpiPostThreadStartEvent2(CVMExecEnv *ee, CVMObject *threadObj, CVMBool isRequestedEvent);/* Purpose: Gets the global JVMPI_Interface. */#define CVMjvmpiInterface() (&CVMjvmpiRec()->interfaceX)/* Purpose: Calls the NotifyEvent() in the JVMPI_Interface. */#define CVMjvmpiNotifyEvent(/* JVMPI_Event * */event) { \ CVMjvmpiInterface()->NotifyEvent(event); \}/* Purpose: Checks to see if GC is disabled. */#define CVMjvmpiGCIsDisabled() \ (CVMgcLockerIsActive(&CVMjvmpiRec()->gcLocker))/* Purpose: Checks to see if it is safe to access object pointers directly. */#define CVMjvmpiIsSafeToAccessDirectObject(ee_) \ (CVMD_isgcUnsafe(ee_) || CVMgcIsGCThread(ee_) || \ CVMjvmpiGCIsDisabled() || CVMsysMutexIAmOwner(ee_, &CVMglobals.heapLock))/* Purpose: Gets the direct object pointer for the specified ICell. *//* NOTE: It is only safe to use this when we are in a GC unsafe state, or GC has been disabled using CVMjvmpi_disableGC(), or the current thread is the GC thread. */#define CVMjvmpiGetICellDirect(ee_, icellPtr_) \ CVMID_icellGetDirectWithAssertion(CVMjvmpiIsSafeToAccessDirectObject(ee_), \ icellPtr_)/* Purpose: Sets the direct object pointer in the specified ICell. *//* NOTE: It is only safe to use this when we are in a GC unsafe state, or GC has been disabled using CVMjvmpi_disableGC(), or the current thread is the GC thread. */#define CVMjvmpiSetICellDirect(ee_, icellPtr_, directObj_) \ CVMID_icellSetDirectWithAssertion(CVMjvmpiIsSafeToAccessDirectObject(ee_), \ icellPtr_, directObj_)/*============================================================================= Prototype of CVMJvmpiEventInfo methods:*/static void CVMjvmpiEventInfoInit(CVMJvmpiEventInfo *self, CVMExecEnv *ee);static void CVMjvmpiEventInfoDisable(CVMJvmpiEventInfo *self, CVMExecEnv *ee, CVMInt32 event);static void CVMjvmpiEventInfoDisableAll(CVMJvmpiEventInfo *self, CVMExecEnv *ee);static void CVMjvmpiEventInfoEnable(CVMJvmpiEventInfo *self, CVMExecEnv *ee, CVMInt32 event);/* static CVMBoolCVMjvmpiEventInfoIsNotAvailable(CVMJvmpiEventInfo *self, CVMInt32 event); */#define CVMjvmpiEventInfoIsNotAvailable(self, event) \ ((self)->eventInfoX[event] == CVMJvmpiEventInfo_NOT_AVAILABLE)/*============================================================================= CVMJvmpiEventInfo methods:*//* Purpose: Initializer. */static void CVMjvmpiEventInfoInit(CVMJvmpiEventInfo *self, CVMExecEnv *ee){ CVMsysMicroLock(ee, CVM_TOOLS_MICROLOCK); /* Fill in default event info for enabling/disabling event notification: */ /* Because CVMJvmpiEventInfo_DISABLED is defined to be 0, the following can be done more efficiently with a memset: int i; for (i = 0; i <= JVMPI_MAX_EVENT_TYPE_VAL; i++) { info->eventInfoX[i] = CVMJvmpiEventInfo_NOT_APPLICABLE; } */ memset(self->eventInfoX, CVMJvmpiEventInfo_NOT_AVAILABLE, JVMPI_MAX_EVENT_TYPE_VAL + 1);#undef CVMjvmpiEventInfoDisableX#define CVMjvmpiEventInfoDisableX(event) \ self->eventInfoX[event] = CVMJvmpiEventInfo_DISABLED; CVMjvmpiEventInfoDisableX(JVMPI_EVENT_CLASS_LOAD); CVMjvmpiEventInfoDisableX(JVMPI_EVENT_CLASS_UNLOAD); CVMjvmpiEventInfoDisableX(JVMPI_EVENT_CLASS_LOAD_HOOK);#ifdef CVM_JVMPI_TRACE_INSTRUCTION CVMjvmpiEventInfoDisableX(JVMPI_EVENT_INSTRUCTION_START);#endif CVMjvmpiEventInfoDisableX(JVMPI_EVENT_OBJ_ALLOC); CVMjvmpiEventInfoDisableX(JVMPI_EVENT_OBJ_FREE); CVMjvmpiEventInfoDisableX(JVMPI_EVENT_THREAD_START); CVMjvmpiEventInfoDisableX(JVMPI_EVENT_THREAD_END); CVMjvmpiEventInfoDisableX(JVMPI_EVENT_JNI_GLOBALREF_ALLOC);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?