michael@0: /* michael@0: This file is provided under a dual BSD/GPLv2 license. When using or michael@0: redistributing this file, you may do so under either license. michael@0: michael@0: GPL LICENSE SUMMARY michael@0: michael@0: Copyright (c) 2005-2012 Intel Corporation. All rights reserved. michael@0: michael@0: This program is free software; you can redistribute it and/or modify michael@0: it under the terms of version 2 of the GNU General Public License as michael@0: published by the Free Software Foundation. michael@0: michael@0: This program is distributed in the hope that it will be useful, but michael@0: WITHOUT ANY WARRANTY; without even the implied warranty of michael@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU michael@0: General Public License for more details. michael@0: michael@0: You should have received a copy of the GNU General Public License michael@0: along with this program; if not, write to the Free Software michael@0: Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. michael@0: The full GNU General Public License is included in this distribution michael@0: in the file called LICENSE.GPL. michael@0: michael@0: Contact Information: michael@0: http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ michael@0: michael@0: BSD LICENSE michael@0: michael@0: Copyright (c) 2005-2012 Intel Corporation. All rights reserved. michael@0: All rights reserved. michael@0: michael@0: Redistribution and use in source and binary forms, with or without michael@0: modification, are permitted provided that the following conditions michael@0: are met: michael@0: michael@0: * Redistributions of source code must retain the above copyright michael@0: notice, this list of conditions and the following disclaimer. michael@0: * Redistributions in binary form must reproduce the above copyright michael@0: notice, this list of conditions and the following disclaimer in michael@0: the documentation and/or other materials provided with the michael@0: distribution. michael@0: * Neither the name of Intel Corporation nor the names of its michael@0: contributors may be used to endorse or promote products derived michael@0: from this software without specific prior written permission. michael@0: michael@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: #include "vtune/ittnotify_config.h" michael@0: michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: #include michael@0: #pragma optimize("", off) michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: #include michael@0: #include michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: #include michael@0: #include michael@0: michael@0: #include "vtune/jitprofiling.h" michael@0: michael@0: static const char rcsid[] = "\n@(#) $Revision: 294150 $\n"; michael@0: michael@0: #define DLL_ENVIRONMENT_VAR "VS_PROFILER" michael@0: michael@0: #ifndef NEW_DLL_ENVIRONMENT_VAR michael@0: #if ITT_ARCH==ITT_ARCH_IA32 michael@0: #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32" michael@0: #else michael@0: #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64" michael@0: #endif michael@0: #endif /* NEW_DLL_ENVIRONMENT_VAR */ michael@0: michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: #define DEFAULT_DLLNAME "JitPI.dll" michael@0: HINSTANCE m_libHandle = NULL; michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: #define DEFAULT_DLLNAME "libJitPI.so" michael@0: void* m_libHandle = NULL; michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: michael@0: /* default location of JIT profiling agent on Android */ michael@0: #define ANDROID_JIT_AGENT_PATH "/data/intel/libittnotify.so" michael@0: michael@0: /* the function pointers */ michael@0: typedef unsigned int(*TPInitialize)(void); michael@0: static TPInitialize FUNC_Initialize=NULL; michael@0: michael@0: typedef unsigned int(*TPNotify)(unsigned int, void*); michael@0: static TPNotify FUNC_NotifyEvent=NULL; michael@0: michael@0: static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING; michael@0: michael@0: /* end collector dll part. */ michael@0: michael@0: /* loadiJIT_Funcs() : this function is called just in the beginning michael@0: * and is responsible to load the functions from BistroJavaCollector.dll michael@0: * result: michael@0: * on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1 michael@0: * on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0 michael@0: */ michael@0: static int loadiJIT_Funcs(void); michael@0: michael@0: /* global representing whether the BistroJavaCollector can't be loaded */ michael@0: static int iJIT_DLL_is_missing = 0; michael@0: michael@0: /* Virtual stack - the struct is used as a virtual stack for each thread. michael@0: * Every thread initializes with a stack of size INIT_TOP_STACK. michael@0: * Every method entry decreases from the current stack point, michael@0: * and when a thread stack reaches its top of stack (return from the global michael@0: * function), the top of stack and the current stack increase. Notice that michael@0: * when returning from a function the stack pointer is the address of michael@0: * the function return. michael@0: */ michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: static DWORD threadLocalStorageHandle = 0; michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0; michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: michael@0: #define INIT_TOP_Stack 10000 michael@0: michael@0: typedef struct michael@0: { michael@0: unsigned int TopStack; michael@0: unsigned int CurrentStack; michael@0: } ThreadStack, *pThreadStack; michael@0: michael@0: /* end of virtual stack. */ michael@0: michael@0: /* michael@0: * The function for reporting virtual-machine related events to VTune. michael@0: * Note: when reporting iJVM_EVENT_TYPE_ENTER_NIDS, there is no need to fill michael@0: * in the stack_id field in the iJIT_Method_NIDS structure, as VTune fills it. michael@0: * The return value in iJVM_EVENT_TYPE_ENTER_NIDS && michael@0: * iJVM_EVENT_TYPE_LEAVE_NIDS events will be 0 in case of failure. michael@0: * in iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event michael@0: * it will be -1 if EventSpecificData == 0 otherwise it will be 0. michael@0: */ michael@0: michael@0: ITT_EXTERN_C int JITAPI michael@0: iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData) michael@0: { michael@0: int ReturnValue; michael@0: michael@0: /* michael@0: * This section is for debugging outside of VTune. michael@0: * It creates the environment variables that indicates call graph mode. michael@0: * If running outside of VTune remove the remark. michael@0: * michael@0: * michael@0: * static int firstTime = 1; michael@0: * char DoCallGraph[12] = "DoCallGraph"; michael@0: * if (firstTime) michael@0: * { michael@0: * firstTime = 0; michael@0: * SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph); michael@0: * } michael@0: * michael@0: * end of section. michael@0: */ michael@0: michael@0: /* initialization part - the functions have not been loaded yet. This part michael@0: * will load the functions, and check if we are in Call Graph mode. michael@0: * (for special treatment). michael@0: */ michael@0: if (!FUNC_NotifyEvent) michael@0: { michael@0: if (iJIT_DLL_is_missing) michael@0: return 0; michael@0: michael@0: /* load the Function from the DLL */ michael@0: if (!loadiJIT_Funcs()) michael@0: return 0; michael@0: michael@0: /* Call Graph initialization. */ michael@0: } michael@0: michael@0: /* If the event is method entry/exit, check that in the current mode michael@0: * VTune is allowed to receive it michael@0: */ michael@0: if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS || michael@0: event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) && michael@0: (executionMode != iJIT_CALLGRAPH_ON)) michael@0: { michael@0: return 0; michael@0: } michael@0: /* This section is performed when method enter event occurs. michael@0: * It updates the virtual stack, or creates it if this is the first michael@0: * method entry in the thread. The stack pointer is decreased. michael@0: */ michael@0: if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS) michael@0: { michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: pThreadStack threadStack = michael@0: (pThreadStack)TlsGetValue (threadLocalStorageHandle); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: pThreadStack threadStack = michael@0: (pThreadStack)pthread_getspecific(threadLocalStorageHandle); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: michael@0: /* check for use of reserved method IDs */ michael@0: if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 ) michael@0: return 0; michael@0: michael@0: if (!threadStack) michael@0: { michael@0: /* initialize the stack. */ michael@0: threadStack = (pThreadStack) calloc (sizeof(ThreadStack), 1); michael@0: if (!threadStack) michael@0: return 0; michael@0: threadStack->TopStack = INIT_TOP_Stack; michael@0: threadStack->CurrentStack = INIT_TOP_Stack; michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: TlsSetValue(threadLocalStorageHandle,(void*)threadStack); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: pthread_setspecific(threadLocalStorageHandle,(void*)threadStack); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: } michael@0: michael@0: /* decrease the stack. */ michael@0: ((piJIT_Method_NIDS) EventSpecificData)->stack_id = michael@0: (threadStack->CurrentStack)--; michael@0: } michael@0: michael@0: /* This section is performed when method leave event occurs michael@0: * It updates the virtual stack. michael@0: * Increases the stack pointer. michael@0: * If the stack pointer reached the top (left the global function) michael@0: * increase the pointer and the top pointer. michael@0: */ michael@0: if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) michael@0: { michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: pThreadStack threadStack = michael@0: (pThreadStack)TlsGetValue (threadLocalStorageHandle); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: pThreadStack threadStack = michael@0: (pThreadStack)pthread_getspecific(threadLocalStorageHandle); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: michael@0: /* check for use of reserved method IDs */ michael@0: if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 ) michael@0: return 0; michael@0: michael@0: if (!threadStack) michael@0: { michael@0: /* Error: first report in this thread is method exit */ michael@0: exit (1); michael@0: } michael@0: michael@0: ((piJIT_Method_NIDS) EventSpecificData)->stack_id = michael@0: ++(threadStack->CurrentStack) + 1; michael@0: michael@0: if (((piJIT_Method_NIDS) EventSpecificData)->stack_id michael@0: > threadStack->TopStack) michael@0: ((piJIT_Method_NIDS) EventSpecificData)->stack_id = michael@0: (unsigned int)-1; michael@0: } michael@0: michael@0: if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED) michael@0: { michael@0: /* check for use of reserved method IDs */ michael@0: if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 ) michael@0: return 0; michael@0: } michael@0: else if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2) michael@0: { michael@0: /* check for use of reserved method IDs */ michael@0: if ( ((piJIT_Method_Load_V2) EventSpecificData)->method_id <= 999 ) michael@0: return 0; michael@0: } michael@0: michael@0: ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData); michael@0: michael@0: return ReturnValue; michael@0: } michael@0: michael@0: /* The new mode call back routine */ michael@0: ITT_EXTERN_C void JITAPI michael@0: iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx michael@0: NewModeCallBackFuncEx) michael@0: { michael@0: /* is it already missing... or the load of functions from the DLL failed */ michael@0: if (iJIT_DLL_is_missing || !loadiJIT_Funcs()) michael@0: { michael@0: /* then do not bother with notifications */ michael@0: NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS); michael@0: /* Error: could not load JIT functions. */ michael@0: return; michael@0: } michael@0: /* nothing to do with the callback */ michael@0: } michael@0: michael@0: /* michael@0: * This function allows the user to query in which mode, if at all, michael@0: *VTune is running michael@0: */ michael@0: ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive() michael@0: { michael@0: if (!iJIT_DLL_is_missing) michael@0: { michael@0: loadiJIT_Funcs(); michael@0: } michael@0: michael@0: return executionMode; michael@0: } michael@0: michael@0: /* this function loads the collector dll (BistroJavaCollector) michael@0: * and the relevant functions. michael@0: * on success: all functions load, iJIT_DLL_is_missing = 0, return value = 1 michael@0: * on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0 michael@0: */ michael@0: static int loadiJIT_Funcs() michael@0: { michael@0: static int bDllWasLoaded = 0; michael@0: char *dllName = (char*)rcsid; /* !! Just to avoid unused code elimination */ michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: DWORD dNameLength = 0; michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: michael@0: if(bDllWasLoaded) michael@0: { michael@0: /* dll was already loaded, no need to do it for the second time */ michael@0: return 1; michael@0: } michael@0: michael@0: /* Assumes that the DLL will not be found */ michael@0: iJIT_DLL_is_missing = 1; michael@0: FUNC_NotifyEvent = NULL; michael@0: michael@0: if (m_libHandle) michael@0: { michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: FreeLibrary(m_libHandle); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: dlclose(m_libHandle); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: m_libHandle = NULL; michael@0: } michael@0: michael@0: /* Try to get the dll name from the environment */ michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0); michael@0: if (dNameLength) michael@0: { michael@0: DWORD envret = 0; michael@0: dllName = (char*)malloc(sizeof(char) * (dNameLength + 1)); michael@0: envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, michael@0: dllName, dNameLength); michael@0: if (envret) michael@0: { michael@0: /* Try to load the dll from the PATH... */ michael@0: m_libHandle = LoadLibraryExA(dllName, michael@0: NULL, LOAD_WITH_ALTERED_SEARCH_PATH); michael@0: } michael@0: free(dllName); michael@0: } else { michael@0: /* Try to use old VS_PROFILER variable */ michael@0: dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0); michael@0: if (dNameLength) michael@0: { michael@0: DWORD envret = 0; michael@0: dllName = (char*)malloc(sizeof(char) * (dNameLength + 1)); michael@0: envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, michael@0: dllName, dNameLength); michael@0: if (envret) michael@0: { michael@0: /* Try to load the dll from the PATH... */ michael@0: m_libHandle = LoadLibraryA(dllName); michael@0: } michael@0: free(dllName); michael@0: } michael@0: } michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: dllName = getenv(NEW_DLL_ENVIRONMENT_VAR); michael@0: if (!dllName) michael@0: dllName = getenv(DLL_ENVIRONMENT_VAR); michael@0: #ifdef ANDROID michael@0: if (!dllName) michael@0: dllName = ANDROID_JIT_AGENT_PATH; michael@0: #endif michael@0: if (dllName) michael@0: { michael@0: /* Try to load the dll from the PATH... */ michael@0: m_libHandle = dlopen(dllName, RTLD_LAZY); michael@0: } michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: michael@0: if (!m_libHandle) michael@0: { michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: m_libHandle = LoadLibraryA(DEFAULT_DLLNAME); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: } michael@0: michael@0: /* if the dll wasn't loaded - exit. */ michael@0: if (!m_libHandle) michael@0: { michael@0: iJIT_DLL_is_missing = 1; /* don't try to initialize michael@0: * JIT agent the second time michael@0: */ michael@0: return 0; michael@0: } michael@0: michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent"); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: FUNC_NotifyEvent = (TPNotify)dlsym(m_libHandle, "NotifyEvent"); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: if (!FUNC_NotifyEvent) michael@0: { michael@0: FUNC_Initialize = NULL; michael@0: return 0; michael@0: } michael@0: michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize"); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: FUNC_Initialize = (TPInitialize)dlsym(m_libHandle, "Initialize"); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: if (!FUNC_Initialize) michael@0: { michael@0: FUNC_NotifyEvent = NULL; michael@0: return 0; michael@0: } michael@0: michael@0: executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize(); michael@0: michael@0: bDllWasLoaded = 1; michael@0: iJIT_DLL_is_missing = 0; /* DLL is ok. */ michael@0: michael@0: /* michael@0: * Call Graph mode: init the thread local storage michael@0: * (need to store the virtual stack there). michael@0: */ michael@0: if ( executionMode == iJIT_CALLGRAPH_ON ) michael@0: { michael@0: /* Allocate a thread local storage slot for the thread "stack" */ michael@0: if (!threadLocalStorageHandle) michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: threadLocalStorageHandle = TlsAlloc(); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: pthread_key_create(&threadLocalStorageHandle, NULL); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: } michael@0: michael@0: return 1; michael@0: } michael@0: michael@0: /* michael@0: * This function should be called by the user whenever a thread ends, michael@0: * to free the thread "virtual stack" storage michael@0: */ michael@0: ITT_EXTERN_C void JITAPI FinalizeThread() michael@0: { michael@0: if (threadLocalStorageHandle) michael@0: { michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: pThreadStack threadStack = michael@0: (pThreadStack)TlsGetValue (threadLocalStorageHandle); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: pThreadStack threadStack = michael@0: (pThreadStack)pthread_getspecific(threadLocalStorageHandle); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: if (threadStack) michael@0: { michael@0: free (threadStack); michael@0: threadStack = NULL; michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: TlsSetValue (threadLocalStorageHandle, threadStack); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: pthread_setspecific(threadLocalStorageHandle, threadStack); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * This function should be called by the user when the process ends, michael@0: * to free the local storage index michael@0: */ michael@0: ITT_EXTERN_C void JITAPI FinalizeProcess() michael@0: { michael@0: if (m_libHandle) michael@0: { michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: FreeLibrary(m_libHandle); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: dlclose(m_libHandle); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: m_libHandle = NULL; michael@0: } michael@0: michael@0: if (threadLocalStorageHandle) michael@0: #if ITT_PLATFORM==ITT_PLATFORM_WIN michael@0: TlsFree (threadLocalStorageHandle); michael@0: #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: pthread_key_delete(threadLocalStorageHandle); michael@0: #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ michael@0: } michael@0: michael@0: /* michael@0: * This function should be called by the user for any method once. michael@0: * The function will return a unique method ID, the user should maintain michael@0: * the ID for each method michael@0: */ michael@0: ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID() michael@0: { michael@0: static unsigned int methodID = 0x100000; michael@0: michael@0: if (methodID == 0) michael@0: return 0; /* ERROR : this is not a valid value */ michael@0: michael@0: return methodID++; michael@0: }