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 + -
显示快捷键?