jvmtiexport.c

来自「This is a resource based on j2me embedde」· C语言 代码 · 共 2,241 行 · 第 1/5 页

C
2,241
字号
/* * @(#)jvmtiExport.c	1.7 06/10/31 * * 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.  * *//* * Breakpoints, single-stepping and debugger event notification. * Debugger event notification/handling includes breakpoint, single-step * and exceptions. *//* * This file is derived from the original CVM jvmdi.c file.  In addition * the 'jvmti' components of this file are derived from the J2SE * jvmtiExport.cpp class.  The primary purpose of this file is to * export VM events to external libraries. */#ifdef CVM_JVMTI#include "javavm/include/porting/ansi/stdarg.h"#include "javavm/include/defs.h"#include "javavm/include/indirectmem.h"#include "javavm/include/globalroots.h"#include "javavm/include/localroots.h"#include "javavm/include/interpreter.h"#include "javavm/include/basictypes.h"#include "javavm/include/signature.h"#include "javavm/include/globals.h"#include "javavm/include/bag.h"#include "javavm/include/common_exceptions.h"#include "javavm/include/named_sys_monitor.h"#include "javavm/include/opcodes.h"#include "generated/offsets/java_lang_Thread.h"#include "generated/jni/java_lang_reflect_Modifier.h"#include "javavm/export/jvm.h"#include "javavm/export/jni.h"#include "javavm/include/jvmtiExport.h"#include "javavm/include/jvmtiDumper.h"#include "javavm/include/jvmtiCapabilities.h"#include "javavm/include/jvmti_jni.h"#ifdef CVM_JIT#include "javavm/include/jit/jitcodebuffer.h"#endif/* %comment: k001 *//* (This is unused in CVM -- only used in unimplemented GetBytecodes) *//* Defined in inline.c thru an include of "opcodes.length". This is dangerous   as is. There should be a header file with this extern shared by both .c   files *//* extern const short opcode_length[256]; *//* Convenience macros *//* Count of lockinfo structs to allocate if freelist is empty */#define JVMTI_LOCKINFO_ALLOC_COUNT 4#define CVM_THREAD_LOCK(ee)	  CVMsysMutexLock(ee, &CVMglobals.threadLock)#define CVM_THREAD_UNLOCK(ee) CVMsysMutexUnlock(ee, &CVMglobals.threadLock)/* NOTE: "Frame pop sentinels" removed in CVM version of JVMTI   because we don't have two return PC slots and mangling the only   available one is incorrect if an exception is thrown. See   CVMjvmtiNotifyDebuggerOfFramePop and jvmti_NotifyFramePop below. *//* #define FRAME_POP_SENTINEL ((unsigned char *)1) */#define GLOBAL_ENV CVMglobals.jvmti.statics.context#define INITIAL_BAG_SIZE 4/* additional local frames to push to cover usage by client debugger */#define LOCAL_FRAME_SLOP 10#define JVMTI_EVENT_GLOBAL_MASK 0xf0000000#define JVMTI_EVENT_THREAD_MASK 0x7fffffffstatic jint methodHash(CVMUint32 mid) {    return ((mid) % HASH_SLOT_COUNT);}static CVMJvmtiMethodNode *getNode(CVMMethodBlock *mb){    CVMJvmtiMethodNode *node;    jint slot;    slot = methodHash((CVMUint32)mb);    node = CVMglobals.jvmti.statics.nodeByMB[slot];    while (node != NULL) {	if (node->mb == mb) {		break;	    }	node = node->next;    }    return node;}/* FIXME: This function is called from the interpreter loop for each method   invocation even when JVMTI is not being used.  This is very heavy overhead   and need to be fixed.  One option is to use some sort of bit marker on the   mb itself to indicate that it is obsolete so as to not have to do this   look up.  In the least, the bit can indicate if a look is necessary. */CVMBoolCVMjvmtiMbIsObsoleteX(CVMMethodBlock *mb){    CVMJvmtiMethodNode *node;    node = getNode(mb);    if (node == NULL) {	return CVM_FALSE;    }    return node->isObsolete;}CVMConstantPool *CVMjvmtiMbConstantPool(CVMMethodBlock *mb) {    CVMJvmtiMethodNode *node;    jint slot;    slot = methodHash((CVMUint32)mb);    node = getNode(mb);    if (node == NULL) {	return NULL;    }    CVMassert(node->isObsolete);    return node->cp;}voidCVMjvmtiMarkAsObsolete(CVMMethodBlock *oldmb, CVMConstantPool *cp){    CVMJvmtiMethodNode *node;    CVMExecEnv *ee = CVMgetEE();    jint slot;    JVMTI_LOCK(ee);    node = getNode(oldmb);    if (node == NULL) {	slot = methodHash((CVMUint32)oldmb);	if (CVMjvmtiAllocate(sizeof(CVMJvmtiMethodNode),			     (unsigned char **)&node) != JVMTI_ERROR_NONE) {	    JVMTI_UNLOCK(ee);	    return;	}	node->next = CVMglobals.jvmti.statics.nodeByMB[slot];	CVMglobals.jvmti.statics.nodeByMB[slot] = node;    }    node->cp = cp;    node->mb = oldmb;    node->isObsolete = CVM_TRUE;    JVMTI_UNLOCK(ee);}/* Purpose: Gets the ClassBlock from the specified java.lang.Class object.   See also CVMjvmtiClassObject2ClassBlock() in jvmtiEnv.h.   CVMjvmtiClassObject2ClassBlock() takes a direct class object as input while   CVMjvmtiClassRef2ClassBlock() takes a class ref i.e.  jclass.*/CVMClassBlock *CVMjvmtiClassObject2ClassBlock(CVMExecEnv *ee, CVMObject *obj){    CVMJavaInt cbAddr;    CVMClassBlock *cb;    /* The following condition will have to be true to guarantee that the       CVMObject *obj that is passed in remains valid for the duration of this       function, and that we can access the       CVMoffsetOfjava_lang_Class_classBlockPointer directly below: */    CVMassert(CVMjvmtiIsSafeToAccessDirectObject(ee));    /* The object must be an instance of java.lang.Class: */    CVMassert(CVMobjectGetClass(obj) == CVMsystemClass(java_lang_Class));    CVMD_fieldReadInt(obj,        CVMoffsetOfjava_lang_Class_classBlockPointer, cbAddr);    cb = (CVMClassBlock*) cbAddr;    CVMassert(cb != NULL);    return cb;}/* * This macro is used in notify_debugger_* to determine whether a JVMTI  * event should be generated. */#define MUST_NOTIFY(ee, eventType)		\    (CVMjvmtiEnvEventEnabled(ee, eventType))#define MUST_NOTIFY_THREAD(ee, eventType)				\    (CVMjvmtiThreadEventEnabled(ee, eventType))/* forward defs */#ifdef JDK12static voidhandleExit(void);#endifstatic voidjvmtiDeleteObjsByRef(){    CVMJvmtiTagNode *node, *next;    int i;    for (i = 0; i < HASH_SLOT_COUNT; i++) {	node = CVMglobals.jvmti.statics.objectsByRef[i];        CVMglobals.jvmti.statics.objectsByRef[i] = NULL;	while (node != NULL) {	    next = node->next;            CVMjvmtiDeallocate((unsigned char *)node);	    node = next;	}    }}static voidjvmtiDeleteMethodNodes(){    CVMJvmtiMethodNode *node, *next;    int i;    for (i = 0; i < HASH_SLOT_COUNT; i++) {	node = CVMglobals.jvmti.statics.nodeByMB[i];        CVMglobals.jvmti.statics.nodeByMB[i] = NULL;	while (node != NULL) {	    next = node->next;            CVMjvmtiDeallocate((unsigned char *)node);	    node = next;	}    }}/* * Initialize JVMTI - if and only if it hasn't been initialized. * Must be called before anything that accesses event structures. * This function is called from CVMjvmtiGetInterface() which triggers the * enabling of JVMTI functionality in the VM. * Complements: CVMjvmtiDestroy(). */jvmtiErrorCVMjvmtiInitialize(JavaVM *vm) {    CVMJvmtiGlobals *globals = &CVMglobals.jvmti;    CVMExecEnv *ee = CVMgetEE();    CVMBool haveFailure = CVM_FALSE;    /* %comment: k003 */    if (CVMjvmtiIsEnabled()) {	/* Success, we're aleady initialized.  Nothing to do. */	return JVMTI_ERROR_NONE;    }#ifdef JDK12    CVMatExit(handleExit);#endif    globals->statics.vm = vm;    globals->statics.breakpoints = 	CVMbagCreateBag(sizeof(struct bkpt), INITIAL_BAG_SIZE);    globals->statics.framePops =        CVMbagCreateBag(sizeof(struct fpop), INITIAL_BAG_SIZE);    globals->statics.watchedFieldModifications = 	CVMbagCreateBag(sizeof(struct fieldWatch), INITIAL_BAG_SIZE);    globals->statics.watchedFieldAccesses = 	CVMbagCreateBag(sizeof(struct fieldWatch), INITIAL_BAG_SIZE);    if (globals->statics.breakpoints == NULL || 	globals->statics.framePops == NULL || 	globals->statics.watchedFieldModifications == NULL || 	globals->statics.watchedFieldAccesses == NULL) {	return JVMTI_ERROR_OUT_OF_MEMORY;    }    /* NOTE: We must not trigger a GC while holding the thread lock.       We are safe here because insertThread() can allocate global roots       which can cause expansion of the global root stack, but not cause       a GC. */    CVM_THREAD_LOCK(ee);    /* Log all thread that were created prior to JVMTI's initialization: */    /* NOTE: We are only logging the pre-existing threads into the JVMTI       threads list.  We don't send currently send JVMTI_EVENT_THREAD_START       for these threads that started before JVMTI was initialized. */    CVM_WALK_ALL_THREADS(ee, currentEE, {	    jthread thread = CVMcurrentThreadICell(currentEE);	    if (!haveFailure && !CVMID_icellIsNull(thread)) {		CVMJvmtiThreadNode *node = CVMjvmtiFindThread(ee, thread);		if (node == NULL) {		    node = CVMjvmtiInsertThread(ee, thread);		    if (node == NULL) {			haveFailure = CVM_TRUE;		    }		}	    }	});    CVM_THREAD_UNLOCK(ee);    /* Abort if we detected a failure while trying to log threads: */    if (haveFailure) {	return JVMTI_ERROR_OUT_OF_MEMORY;    }    /* isEnabled and debugOptionSet flags need to be in the proper     * state before calling CVMjvmtiInitializeCapabilities.     */    CVMjvmtiSetIsInDebugMode(CVMjvmtiHasDebugOptionSet());    CVMjvmtiSetIsEnabled(CVM_TRUE);    CVMjvmtiInitializeCapabilities();    /*    clks_per_sec = CVMgetClockTicks(); */    CVMjvmtiInstrumentJNINativeInterface();    return JVMTI_ERROR_NONE;}/* Shuts down JVMTI.  JVMTI facilities cannot be used after this.    Complements: CVMjvmtiInitialize().*/voidCVMjvmtiDestroy(CVMJvmtiGlobals *globals){    CVMExecEnv *ee = CVMgetEE();    CVMjvmtiUninstrumentJNINativeInterface();    CVMjvmtiDestroyCapabilities();    CVM_THREAD_LOCK(ee);    /* Remove all threadNodes that may be left behind.  For the most part,       this should only be for threads that the VM hasn't shut down yet       like the main thread: */    CVM_WALK_ALL_THREADS(ee, currentEE, {	    jthread thread = CVMcurrentThreadICell(currentEE);            CVMjvmtiDestroyLockInfo(currentEE);	    if (!CVMID_icellIsNull(thread)) {		CVMjvmtiRemoveThread(ee, thread);	    }	});    /* Once we're done with that, there should be no more threadNodes left: */    CVMassert(globals->statics.threadList == NULL);    CVM_THREAD_UNLOCK(ee);    CVMjvmtiSetIsEnabled(CVM_FALSE);    /* Free up the bags of debugging info: */    if (globals->statics.breakpoints != NULL) {	CVMbagDestroyBag(globals->statics.breakpoints);	CVMwithAssertsOnly(globals->statics.breakpoints = NULL);    }    if (globals->statics.framePops != NULL) {	CVMbagDestroyBag(globals->statics.framePops);	CVMwithAssertsOnly(globals->statics.framePops = NULL);    }    if (globals->statics.watchedFieldModifications != NULL) {	CVMbagDestroyBag(globals->statics.watchedFieldModifications);	CVMwithAssertsOnly(globals->statics.watchedFieldModifications = NULL);    }    if (globals->statics.watchedFieldAccesses != NULL) {	CVMbagDestroyBag(globals->statics.watchedFieldAccesses);	CVMwithAssertsOnly(globals->statics.watchedFieldAccesses = NULL);    }#ifdef CVM_DEBUG_ASSERTS    globals->statics.vm = NULL;#endif    jvmtiDeleteObjsByRef();    jvmtiDeleteMethodNodes();    CVMjvmtiDestroyContext(CVMglobals.jvmti.statics.context);    /* Note: CVMjvmtiDestroy() can be called long before the VM shutsdown if       the agentLib calls jvmti_DisposeEnvironment().  Hence, we can't always       expect the global to be NULL the next time we use JVMTI (which may be       before another VM launch) when we support multiple agentLibs, that is.       Hence, we need to reset these globals to 0 ourselves here. */    memset(&CVMglobals.jvmti, 0, sizeof(*globals));}/* Initialize any JVMTI state needed during VM start up. */voidCVMjvmtiInitializeGlobals(CVMJvmtiGlobals *globals){    /* The CVMJvmtiGlobals record is part of CVMglobals and should contain       NULLs by default.  Hence, there's no need to set them to NULL.  We       add some asserts here to make sure that this hasn't changed: */    CVMassert(globals->statics.vm == NULL);    CVMassert(globals->statics.breakpoints == NULL);    CVMassert(globals->statics.framePops == NULL);    CVMassert(globals->statics.watchedFieldModifications == NULL);    CVMassert(globals->statics.watchedFieldAccesses == NULL);    CVMassert(globals->statics.threadList == NULL);    CVMassert(globals->statics.context == NULL);}/* Destroys any JVMTI state for VM shutdown. */voidCVMjvmtiDestroyGlobals(CVMJvmtiGlobals *globals){    /* Shutdown JVMTI: */    CVMjvmtiDestroy(globals);    CVMassert(globals->statics.breakpoints == NULL);    CVMassert(globals->statics.framePops == NULL);    CVMassert(globals->statics.watchedFieldModifications == NULL);    CVMassert(globals->statics.watchedFieldAccesses == NULL);    /* The following should also have been cleaned-up.  If not, we need to       add clean up code for them before this: */    CVMassert(globals->statics.vm == NULL);    /* All thread nodes should have been removed from the threadList before we       get here.  Hence, this should be NULL: */    CVMassert(globals->statics.threadList == NULL);    CVMassert(globals->statics.context == NULL);}CVMClassBlock* CVMjvmtiGetCurrentRedefinedClass(CVMExecEnv *ee){    CVMJvmtiThreadNode *node;    node = CVMjvmtiFindThread(ee, CVMcurrentThreadICell(ee));    CVMassert(node != NULL);    return node->oldCb;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?