jvmtienv.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 2,229 行 · 第 1/5 页
C
2,229 行
/* * @(#)jvmtiEnv.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. * *//* * This file is derived from the original CVM jvmdi.c file. In addition * the 'jvmti' components of this file are derived from the J2SE * jvmtiEnv.cpp class. The primary purpose of this file is to * instantiate the JVMTI API to external libraries. */ #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/stacks.h"#include "javavm/include/bag.h"#include "javavm/include/porting/time.h"#include "javavm/include/path_md.h"#include "javavm/include/common_exceptions.h"#include "javavm/include/named_sys_monitor.h"#include "javavm/include/constantpool.h"#include "javavm/include/stackmaps.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/export/jvmti.h"#include "javavm/include/jvmtiEnv.h"#include "javavm/include/jvmtiDumper.h"#include "javavm/include/jvmtiCapabilities.h"#include "javavm/include/verify.h"#ifdef CVM_HW#include "include/hw.h"#endif/* CVM JVMTI Implementation Presuppositions: ========================================= 1. Stack traces will include reflection frames. This is reflected in the frame count and all other stack related inspection functions as well. *//* TODO: Review JVMTI functions for all the error conditions that the spec says that can be checked for. *//* TODO: Review interplay of CVMglobals.jvmtiLock and CVM_CODE_LOCK for race conditions. Currently, jvmtiLock replaces CODE_LOCK in some cases but not in JIT cases. Need to be consistent with this. - Not critical yet because JIT is not used wit breakpoints currently.*//* Convenience macros *//* TODO: #undef this before final release: */#define DO_PARANOID_ASSERTS#ifdef DO_PARANOID_ASSERTS#define CVMextraAssert(x) CVMassert(x)#else#define CVMextraAssert(x) #endif/* differences in flags from java class version */#define CVM_CLASS_FLAG_DIFFS (CVM_CLASS_ACC_SUPER | \ CVM_CLASS_ACC_REFERENCE | \ CVM_CLASS_ACC_FINALIZABLE)#define INITIAL_BAG_SIZE 4#define VALID_CLASS(cb) \ { \ if ((cb)==NULL) { \ return JVMTI_ERROR_INVALID_CLASS; \ } \ }#define VALID_OBJECT(o) \ { \ if ((o)==NULL) { \ return JVMTI_ERROR_INVALID_OBJECT; \ } \ }#define JVMTI_ENABLED() \ { \ if (!CVMjvmtiIsEnabled()) { \ return JVMTI_ERROR_ACCESS_DENIED; \ } \ }#define NULL_CHECK(Ptr, Error) \ { \ if ((Ptr) == NULL) { \ return (Error); \ } \ }#define NOT_NULL(ptr) \ { \ if (ptr == NULL) { \ return JVMTI_ERROR_NULL_POINTER; \ } \ }#define NOT_NULL2(ptr1,ptr2) \ { \ if (ptr1 == NULL || ptr2 == NULL) { \ return JVMTI_ERROR_NULL_POINTER; \ } \ }#define ASSERT_NOT_NULL_ELSE_EXIT_WITH_ERROR(ptr, errorCode) \ { \ if (NULL == (ptr)) { \ return (errorCode); \ } \ }#define ASSERT_NOT_NULL2_ELSE_EXIT_WITH_ERROR(ptr1, ptr2, errorCode) \ { \ if (NULL == (ptr1) || NULL == (ptr2)) { \ return (errorCode); \ } \ }#define METHOD_ID_OK(mb) \ { \ if (mb == NULL) { \ return JVMTI_ERROR_INVALID_METHODID; \ } \ }#define THREAD_OK(ee) \ { \ if (ee == NULL) { \ return JVMTI_ERROR_INVALID_THREAD; \ } \ }#define ALLOC(env, size, where) \ { \ jvmtiError allocErr = \ jvmti_Allocate(env, size, (unsigned char**)where); \ if (allocErr != JVMTI_ERROR_NONE) { \ return allocErr; \ } \ }#define ALLOC_WITH_CLEANUP_IF_FAILED(env, size, where, cleanup) \ { \ jvmtiError allocErr = \ jvmti_Allocate(env, size, (unsigned char**)where); \ if (allocErr != JVMTI_ERROR_NONE) { \ cleanup; \ return allocErr; \ } \ }#define CHECK_JVMTI_ENV \ CVMJvmtiContext *context = CVMjvmtiEnv2Context(jvmtienv); \ if (!context->isValid) { \ return JVMTI_ERROR_INVALID_ENVIRONMENT; \ } \#define CVM_THREAD_LOCK(ee) CVMsysMutexLock(ee, &CVMglobals.threadLock)#define CVM_THREAD_UNLOCK(ee) CVMsysMutexUnlock(ee, &CVMglobals.threadLock)#ifdef CVM_JIT#define CVM_JIT_LOCK(ee) CVMsysMutexLock(ee, &CVMglobals.jitLock)#define CVM_JIT_UNLOCK(ee) CVMsysMutexUnlock(ee, &CVMglobals.jitLock)#else#define CVM_JIT_LOCK(ee)#define CVM_JIT_UNLOCK(ee)#endif#define CHECK_CAP(cap_) \ if (getCapabilities(context)->cap_ != 1) { \ return JVMTI_ERROR_MUST_POSSESS_CAPABILITY; \ }/* StackMutationStopped ==================== Before inspecting the stack of a thread, we must ensure that the stack won't be changing while we're in the midst of inspecting it. Otherwise, the data we collect may contain some inconsistencies. There are 4 ways to guarantee that stack frames won't be mutating: 1. The thread is in a GC Safe state ================================ Stack frames can only be pushed and popped in a GC unsafe state. JIT code execution can only occur in a GC unsafe state. Hence, if the thread is in a GC safe state, we know that it will not be pushing/popping frames, nor entering and exiting inlined methods in the case of JIT compiled code. Hence, stack mutation has stopped. 2. The thread is suspended ======================= Obviously, if the thread is suspended, it won't be mutating. 3. The thread is the current thread ================================ While we're executing in our current function, the Java interpreter and JIT compiled code cannot be running in this thread at the same time. Hence, we know that stack mutation has stopped. 4. All threads are in a GC safe state ================================== This state is basically an overkill approach to achieve condition 1 above. If all threads are GC safe, then it necessarily follows that the target of interest is also in a GC safe state. Therefore, one technique for stopping mutation on another thread is to request a GC safe all state from the current thread. Note: The term stackMutationStopped would be more accurate if it were called stackFrameMutationStopped. The actual ceasing of mutation that we are ensuring here is that of stack "frame"s being pushed or popped. The thread can still be mutating the stack in terms modifying local variables stored on it. However, for all useful purposes here, we need not be concerned with those kinds of stack mutations. Hence, we use the term stackMutationStopped just for brevity. Why CVMgcIsInSafeAllState()?? You may roll all threads to safe points in the context of thread A and then test for safety using the ee of thread B which may hit an assertion since A called for safety and B is doing a test. Or you may roll all threads to safety in thread A and then try it again in some deeper routine in JVMTI which will assert. So we check this flag. Using the CVMjvmti...ICellDirect() macros ========================================= Note: When handling direct object pointers from icells/refs, we need to use the CVMjvmti...ICellDirect macros (defined further down below) if the current thread is excuting with a code region protected by the STOP/RESUME_STACK_MUTATION pair. This is because a GC safe all state may be used to stop stack mutation. In a GC safe all state, the current thread is not allowed to become GC unsafe (which is needed by the indirectmem.h macros). Hence, we'll need to use these macros instead. Note, however, that the stack mutation stopped state is not necessarily the equivalent of a "safe to access direct object" state (as captured by the CVMjvmtiIsSafeToAccessDirectObject() macro). Both states are similar in that they can both be achieved by requesting a GC safe all VM state. However, the current thread is already in a stack mutation stopped state without doing any extra work, but it certainly is not in a "safe to access direct object" state. This is because without anything extra, there is nothing to prevent another thread from triggering a GC. Since the STOP/RESUME_STACK_MUTATION macro pair requires the use of the ICellDirect macros (assuming we will be manipulating direct object pointers), we need to ensure that the current thread is also in the "safe to access direct object" state. We can achieve this by first acquiring the heapLock before entering the STOP/RESUME region. Again, the current thread is not allowed to become GC unsafe because the region may be operating under a GC safe all condition. Allocating JNI local refs in the STOP/RESUME ============================================ If you want to allocate a JNI local ref to store results, DON'T do the allocation inside the STOP/RESUME region. This is because the allocation may become GC unsafe. The solution is to allocate the local ref using the CVM internal API CVMjniCreateLocalRef() before entering the region. After exiting the region, if the local ref was not used, then release it with CVMjniDeleteLocalRef(). Calling JNI functions inside the STOP/RESUME region =================================================== In general, make sure that any functions you call within the STOP/RESUME region will not cause the current thread to become GC unsafe.*//* Checks if mutation is stopped on the stack of the specified thread. */#define stackMutationStopped(ee) \ (CVMgcIsInSafeAllState() || CVMD_isgcSafe(ee) || \ CVMeeThreadIsSuspended(ee) || (ee == CVMgetEE()))/* Stops mutation on the specified thread if necessary. */#define STOP_STACK_MUTATION_ACTION(ee, targetEE, lockAction) \ { \ /* ts and bits used for assertion testing */ \ CVMThreadState ts = targetEE->threadState; \ CVMThreadState bits = CVM_THREAD_SUSPENDED | \ CVM_THREAD_STACK_MUTATOR_LOCK; \ (void)bits; \ /* If the target thread is not the self thread, then the only \ way to stop its mutation is to force it so a GC safe point. \ It is not safe to suspend that thread as an alternative. \ \ If the target thread is the self thread then there's nothing \ to do. \ */ \ if (CVMeeThreadIsSuspended(targetEE)) { \ targetEE->threadState |= CVM_THREAD_STACK_MUTATOR_LOCK; \ ts |= CVM_THREAD_STACK_MUTATOR_LOCK; \ } \ CVMassert((ts & bits) == bits || (ts & bits) == 0); \ if (targetEE != ee && !CVMeeThreadIsSuspended(targetEE)) { \ CVMExecEnv *refetchedEE; \ \ lockAction; \ CVMD_gcBecomeSafeAll(ee); \ /* Since the target thread is not the self thread, then \ there's a chance that it could have died before we can \ get the stack trace. While the jthread keeps the object \ alive, we don't have anything to keep it's ee and stack \ alive too. \ \ Hence, after forcing it to a GC safe point, we need to \ refetch and recheck the threadEE from the jthread. The \ GC safe point prevents Java code from running, and \ consequently the thread from exiting. \ */ \ refetchedEE = getThreadEETopField(ee, thread); \ if (refetchedEE == NULL) { \ err = JVMTI_ERROR_THREAD_NOT_ALIVE; \ goto _cleanUpAndReturn; \ } \ CVMassert(refetchedEE == targetEE); \ } \ }/* Resumes mutation on the specified thread if previously stopped. */#define RESUME_STACK_MUTATION_ACTION(ee, targetEE, unlockAction) \ _cleanUpAndReturn: \ if (targetEE->threadState & CVM_THREAD_STACK_MUTATOR_LOCK) { \ targetEE->threadState &= ~CVM_THREAD_STACK_MUTATOR_LOCK; \ } \ if (targetEE != ee && !CVMeeThreadIsSuspended(targetEE)) { \ CVMD_gcAllowUnsafeAll(ee); \ unlockAction; \ }#define STOP_STACK_MUTATION(ee, targetEE) \ STOP_STACK_MUTATION_ACTION(ee, targetEE, { CVM_THREAD_LOCK(ee); })#define RESUME_STACK_MUTATION(ee, targetEE) \ RESUME_STACK_MUTATION_ACTION(ee, targetEE, { CVM_THREAD_UNLOCK(ee); })#define STOP_STACK_MUTATION_JIT(ee, targetEE) \ STOP_STACK_MUTATION_ACTION(ee, targetEE, { \ CVM_JIT_LOCK(ee); \ CVM_THREAD_LOCK(ee); \ })#define RESUME_STACK_MUTATION_JIT(ee, targetEE) \ RESUME_STACK_MUTATION_ACTION(ee, targetEE, { \ CVM_THREAD_UNLOCK(ee); \ CVM_JIT_UNLOCK(ee); \ })typedef struct { CVMSysMutex* mutex;} jvmtiSysMutexes;static const jvmtiSysMutexes jvmtiMutexes[] = {#ifdef CVM_CLASSLOADING {&CVMglobals.nullClassLoaderLock},#endif#ifdef CVM_JIT {&CVMglobals.jitLock},#endif {&CVMglobals.heapLock}, {&CVMglobals.threadLock}};#define NUM_JVMTI_SYSMUTEXES \ (sizeof(jvmtiMutexes) / sizeof(jvmtiSysMutexes))#define ACQUIRE_SYS_MUTEXES \ { \ int i; \ for (i = 0; i < NUM_JVMTI_SYSMUTEXES; i++) { \ CVMsysMutexLock(ee, jvmtiMutexes[i].mutex); \ } \ }#define RELEASE_SYS_MUTEXES \ { \ int i; \ for (i = NUM_JVMTI_SYSMUTEXES - 1; i >= 0; i--) { \ CVMsysMutexUnlock(ee, jvmtiMutexes[i].mutex); \ } \ }/* Error names */static const char* const jvmtiErrorNames[] ={ "JVMTI_ERROR_NONE", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "JVMTI_ERROR_INVALID_THREAD", "JVMTI_ERROR_INVALID_THREAD_GROUP", "JVMTI_ERROR_INVALID_PRIORITY", "JVMTI_ERROR_THREAD_NOT_SUSPENDED", "JVMTI_ERROR_THREAD_SUSPENDED", "JVMTI_ERROR_THREAD_NOT_ALIVE", NULL, NULL, NULL, NULL, "JVMTI_ERROR_INVALID_OBJECT", "JVMTI_ERROR_INVALID_CLASS", "JVMTI_ERROR_CLASS_NOT_PREPARED", "JVMTI_ERROR_INVALID_METHODID", "JVMTI_ERROR_INVALID_LOCATION", "JVMTI_ERROR_INVALID_FIELDID", NULL, NULL, NULL, NULL, NULL,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?