OpenJDK / jdk / jdk12
changeset 26201:40a873d21081
8043936: Drop HPROF as demo, keep as HPROF agent shipped with JDK
Reviewed-by: erikj, alanb
line wrap: on
line diff
--- a/jdk/make/CompileDemos.gmk Mon Aug 25 09:20:49 2014 +0100 +++ b/jdk/make/CompileDemos.gmk Tue Aug 26 07:55:08 2014 +0200 @@ -314,19 +314,6 @@ $(eval $(call SetupJVMTIDemo,gctest, agent_util)) $(eval $(call SetupJVMTIDemo,heapTracker, agent_util java_crw_demo)) $(eval $(call SetupJVMTIDemo,heapViewer, agent_util)) - -# On AIX, hprof requires 'dladdr' from src/aix/porting/porting_aix.cpp -BUILD_LIBHPROF_AIX_EXTRA_SRC := -BUILD_LIBHPROF_AIX_EXTRA_CFLAGS := -ifeq ($(OPENJDK_TARGET_OS), aix) - BUILD_LIBHPROF_AIX_EXTRA_SRC += $(JDK_TOPDIR)/src/aix/porting - BUILD_LIBHPROF_AIX_EXTRA_CFLAGS += -I$(JDK_TOPDIR)/src/aix/porting -endif - -$(eval $(call SetupJVMTIDemo,hprof, java_crw_demo, \ - $(BUILD_LIBHPROF_AIX_EXTRA_CFLAGS), C, \ - -ldl, ws2_32.lib winmm.lib, -lsocket -lnsl, -lpthread, $(BUILD_LIBHPROF_AIX_EXTRA_SRC))) - $(eval $(call SetupJVMTIDemo,minst, agent_util java_crw_demo)) $(eval $(call SetupJVMTIDemo,mtrace, agent_util java_crw_demo)) $(eval $(call SetupJVMTIDemo,waiters, agent_util, , C++))
--- a/jdk/make/copy/Copy-jdk.hprof.agent.gmk Mon Aug 25 09:20:49 2014 +0100 +++ b/jdk/make/copy/Copy-jdk.hprof.agent.gmk Tue Aug 26 07:55:08 2014 +0200 @@ -27,7 +27,7 @@ ################################################################################ -HPROF_SRC := $(JDK_TOPDIR)/src/demo/share/jvmti/hprof/jvm.hprof.txt +HPROF_SRC := $(JDK_TOPDIR)/src/jdk.hprof.agent/share/native/libhprof/jvm.hprof.txt $(LIB_DST_DIR)/jvm.hprof.txt: $(HPROF_SRC) $(call install-file)
--- a/jdk/make/lib/Lib-jdk.hprof.agent.gmk Mon Aug 25 09:20:49 2014 +0100 +++ b/jdk/make/lib/Lib-jdk.hprof.agent.gmk Tue Aug 26 07:55:08 2014 +0200 @@ -27,11 +27,11 @@ ################################################################################ -BUILD_LIBHPROF_SRC := $(JDK_TOPDIR)/src/demo/share/jvmti/hprof \ - $(JDK_TOPDIR)/src/demo/$(OPENJDK_TARGET_OS_API_DIR)/jvmti/hprof +BUILD_LIBHPROF_SRC := $(call FindSrcDirsForLib, jdk.hprof.agent, hprof) + BUILD_LIBHPROF_CFLAGS := $(addprefix -I, $(BUILD_LIBHPROF_SRC)) \ -I$(JDK_TOPDIR)/src/demo/share/jvmti/java_crw_demo - + BUILD_LIBHPROF_LDFLAGS := LIBHPROF_OPTIMIZATION := HIGHEST
--- a/jdk/src/demo/aix/jvmti/hprof/porting_aix.c Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * Copyright 2012, 2013 SAP AG. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code 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 code 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 in the LICENSE file that - * accompanied this code). - * - * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include <stdio.h> -#include <sys/ldr.h> -#include <errno.h> - -#include "porting_aix.h" - -static unsigned char dladdr_buffer[0x4000]; - -static void fill_dll_info(void) { - int rc = loadquery(L_GETINFO,dladdr_buffer, sizeof(dladdr_buffer)); - if (rc == -1) { - fprintf(stderr, "loadquery failed (%d %s)", errno, strerror(errno)); - fflush(stderr); - } -} - -static int dladdr_dont_reload(void* addr, Dl_info* info) { - const struct ld_info* p = (struct ld_info*) dladdr_buffer; - info->dli_fbase = 0; info->dli_fname = 0; - info->dli_sname = 0; info->dli_saddr = 0; - for (;;) { - if (addr >= p->ldinfo_textorg && - addr < (((char*)p->ldinfo_textorg) + p->ldinfo_textsize)) { - info->dli_fname = p->ldinfo_filename; - info->dli_fbase = p->ldinfo_textorg; - return 1; /* [sic] */ - } - if (!p->ldinfo_next) { - break; - } - p = (struct ld_info*)(((char*)p) + p->ldinfo_next); - } - return 0; /* [sic] */ -} - -#ifdef __cplusplus -extern "C" -#endif -int dladdr(void *addr, Dl_info *info) { - static int loaded = 0; - if (!loaded) { - fill_dll_info(); - loaded = 1; - } - if (!addr) { - return 0; /* [sic] */ - } - /* Address could be AIX function descriptor? */ - void* const addr0 = *( (void**) addr ); - int rc = dladdr_dont_reload(addr, info); - if (rc == 0) { - rc = dladdr_dont_reload(addr0, info); - if (rc == 0) { /* [sic] */ - fill_dll_info(); /* refill, maybe loadquery info is outdated */ - rc = dladdr_dont_reload(addr, info); - if (rc == 0) { - rc = dladdr_dont_reload(addr0, info); - } - } - } - return rc; -}
--- a/jdk/src/demo/aix/jvmti/hprof/porting_aix.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright 2012, 2013 SAP AG. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code 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 code 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 in the LICENSE file that - * accompanied this code). - * - * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -/* - * Header file to contain porting-relevant code which does not have a - * home anywhere else. - * This is intially based on hotspot/src/os/aix/vm/{loadlib,porting}_aix.{hpp,cpp} - */ - -/* - * Aix' own version of dladdr(). - * This function tries to mimick dladdr(3) on Linux - * (see http://linux.die.net/man/3/dladdr) - * dladdr(3) is not POSIX but a GNU extension, and is not available on AIX. - * - * Differences between AIX dladdr and Linux dladdr: - * - * 1) Dl_info.dli_fbase: can never work, is disabled. - * A loaded image on AIX is divided in multiple segments, at least two - * (text and data) but potentially also far more. This is because the loader may - * load each member into an own segment, as for instance happens with the libC.a - * 2) Dl_info.dli_sname: This only works for code symbols (functions); for data, a - * zero-length string is returned (""). - * 3) Dl_info.dli_saddr: For code, this will return the entry point of the function, - * not the function descriptor. - */ - -typedef struct { - const char *dli_fname; /* file path of loaded library */ - void *dli_fbase; /* doesn't make sence on AIX */ - const char *dli_sname; /* symbol name; "" if not known */ - void *dli_saddr; /* address of *entry* of function; not function descriptor; */ -} Dl_info; - -#ifdef __cplusplus -extern "C" -#endif -int dladdr(void *addr, Dl_info *info);
--- a/jdk/src/demo/share/jvmti/hprof/README.txt Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -README ------- - -Design and Implementation: - - * The Tracker Class (Tracker.java & hprof_tracker.c) - It was added to the sun.tools.hprof.Tracker in JDK 5.0 FCS, then - moved to a package that didn't cause classload errors due to - the security manager not liking the sun.* package name. - 5091195 detected that this class needs to be in com.sun.demo.jvmti.hprof. - The BCI code will call these static methods, which will in turn - (if engaged) call matching native methods in the hprof library, - with the additional current Thread argument (Thread.currentThread()). - Doing the currentThread call on the Java side was necessary due - to the difficulty of getting the current thread while inside one - of these Tracker native methods. This class lives in rt.jar. - - * Byte Code Instrumentation (BCI) - Using the ClassFileLoadHook feature and a C language - implementation of a byte code injection transformer, the following - bytecodes get injections: - - On entry to the java.lang.Object <init> method, - a invokestatic call to - Tracker.ObjectInit(this); - is injected. - - On any newarray type opcode, immediately following it, - the array object is duplicated on the stack and an - invokestatic call to - Tracker.NewArray(obj); - is injected. - - On entry to all methods, a invokestatic call to - Tracker.CallSite(cnum,mnum); - is injected. The hprof agent can map the two integers - (cnum,mnum) to a method in a class. This is the BCI based - "method entry" event. - - On return from any method (any return opcode), - a invokestatic call to - Tracker.ReturnSite(cnum,mnum); - is injected. - All classes found via ClassFileLoadHook are injected with the - exception of some system class methods "<init>" and "finalize" - whose length is 1 and system class methods with name "<clinit>", - and also java.lang.Thread.currentThread() which is used in the - class Tracker (preventing nasty recursion issue). - System classes are currently defined as any class seen by the - ClassFileLoadHook prior to VM_INIT. This does mean that - objects created in the system classes inside <clinit> might not - get tracked initially. - See the java_crw_demo source and documentation for more info. - The injections are based on what the hprof options - are requesting, e.g. if heap=sites or heap=all is requested, the - newarray and Object.<init> method injections happen. - If cpu=times is requested, all methods get their entries and - returns tracked. Options like cpu=samples or monitor=y - do not require BCI. - - * BCI Allocation Tags (hprof_tag.c) - The current jlong tag being used on allocated objects - is an ObjectIndex, or an index into the object table inside - the hprof code. Depending on whether heap=sites or heap=dump - was asked for, these ObjectIndex's might represent unique - objects, or unique allocation sites for types of objects. - The heap=dump option requires considerable more space - due to the one jobject per ObjectIndex mapping. - - * BCI Performance - The cpu=times seems to have the most negative affect on - performance, this could be improved by not having the - Tracker class methods call native code directly, but accumulate - the data in a file or memory somehow and letting it buffer down - to the agent. The cpu=samples is probably a better way to - measure cpu usage, varying the interval as needed. - The heap=dump seems to use memory like crazy, but that's - partially the way it has always been. - - * Sources in the JDK workspace - The sources and Makefiles live in: - src/share/classes/com/sun/demo/jvmti/hprof/* - src/share/demo/jvmti/hprof/* - src/share/demo/jvmti/java_crw_demo/* - src/solaris/demo/jvmti/hprof/* - src/windows/demo/jvmti/hprof/* - make/java/java_hprof_demo/* - make/java/java_crw_demo/* - ---------
--- a/jdk/src/demo/share/jvmti/hprof/debug_malloc.c Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,769 +0,0 @@ -/* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -/* ************************************************************************** - * - * Set of malloc/realloc/calloc/strdup/free replacement macros that - * insert some extra words around each allocation for debugging purposes - * and also attempt to detect invalid uses of the malloc heap through - * various tricks like inserting clobber words at the head and tail of - * the user's area, delayed free() calls, and setting the memory to - * a fixed pattern on allocation and when freed. The allocations also - * can include warrants so that when an area is clobbered, this - * package can report where the allocation took place. - * The macros included are: - * malloc(size) - * realloc(ptr,size) - * calloc(nelem,elsize) - * strdup(s1) - * free(ptr) - * malloc_police() <--- Not a system function - * The above macros match the standard behavior of the system functions. - * - * They should be used through the include file "debug_malloc.h". - * - * IMPORTANT: All source files that call any of these macros - * should include debug_malloc.h. This package will - * not work if the memory isn't allocated and freed - * by the macros in debug_malloc.h. The important issue - * is that any malloc() from debug_malloc.h must be - * freed by the free() in debug_malloc.h. - * - * The macros in debug_malloc.h will override the normal use of - * malloc, realloc, calloc, strdup, and free with the functions below. - * - * These functions include: - * void *debug_malloc(size_t, void*, int); - * void *debug_realloc(void*, size_t, void*, int); - * void *debug_calloc(size_t, size_t, void*, int); - * void debug_free(void *, void*, int); - * - * In addition the function debug_malloc_police() can be called to - * tell you what memory has not been freed. - * void debug_malloc_police(void*, int); - * The function debug_malloc_police() is available through the macro - * malloc_police(). Normally you would want to call this at exit() - * time to find out what memory is still allocated. - * - * The variable malloc_watch determines if the warrants are generated. - * warrants are structures that include the filename and line number - * of the caller who allocated the memory. This structure is stored - * at the tail of the malloc space, which is allocated large enough - * to hold some clobber words at the head and tail, the user's request - * and the warrant record (if malloc_watch is non-zero). - * - * The macro LEFT_OVER_CHAR is what the trailing bytes of an allocation - * are set to (when the allocation is not a multiple of 8) on allocation. - * At free(0 time, these bytes are double checked to make sure they were - * not clobbered. To remove this feature #undef LEFT_OVER_CHAR. - * - * The memory freed will have the FREED_CHAR put into it. To remove this - * feature #undef FREED_CHAR. - * - * The memory allocated (not calloc'd) will have the ALLOC_CHAR put into it - * at the time of allocation. To remove this feature #undef ALLOC_CHAR. - * - * The macro MAX_FREE_DELAY_COUNT controls how many free blocks will - * be kept around before being freed. This creates a delayed affect - * so that free space that gets clobbered just might get detected. - * The free() call will immediately set the user space to the FREED_CHAR, - * leaving the clobber words and warrant in place (making sure they - * haven't been clobbered). Then the free() pointer is added to a - * queue of MAX_FREE_DELAY_COUNT long, and if the queue was full, the - * oldest free()'d memory is actually freed, getting it's entire - * memory length set to the FREED_CHAR. - * - * WARNING: This can significantly slow down an application, depending - * on how many allocations are made. Also the additional memory - * needed for the clobber words and the warrants can be significant - * again, depending on how many allocations are made. - * In addition, the delayed free calls can create situations - * where you might run out of memory prematurely. - * - * ************************************************************************** - */ - -#ifdef DEBUG - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <stdarg.h> -#include "hprof.h" - -/* *************************************************************************** - * Space normally looks like (clobber Word is 64 bits and aligned to 8 bytes): - * - * ----------------- - * malloc/free get->| clobber Word | ---> contains -size requested by user - * ----------------- - * User gets --->| user space | - * | | - * | | left_over | ---> left_over bytes will be <= 7 - * ----------------- - * | clobber Word | ---> contains -size requested by user - * ----------------- - * | Warrant | ---> Optional (malloc_watch!=0) - * | | Contains filename and line number - * | | where allocation happened - * | | - * ----------------- - ***************************************************************************/ - -/* - * Flag that tells debug_malloc/debug_free/debug_realloc to police - * heap space usage. (This is a dynamic flag that can be turned on/off) - */ -static int malloc_watch = 1; - -/* Character to stuff into freed space */ -#define FREED_CHAR 'F' - -/* Character to stuff into allocated space */ -#define ALLOC_CHAR 'A' - -/* Character to stuff into left over trailing bytes */ -#define LEFT_OVER_CHAR 'Z' - -/* Number of 'free' calls that will be delayed until the end */ -#define MAX_FREE_DELAY_COUNT 1 -#undef MAX_FREE_DELAY_COUNT - -/* Maximum name of __FILE_ stored in each malloc'd area */ -#define WARRANT_NAME_MAX (32-1) /* 1 less than multiple of 8 is best */ - -/* Macro to convert a user pointer to the malloc pointer */ -#define user2malloc_(uptr) (((char*)(void*)uptr)-sizeof(Word)) - -/* Macro to convert a macro pointer to the user pointer */ -#define malloc2user_(mptr) (((char*)(void*)(mptr))+sizeof(Word)) - -/* Size of the warrant record (this is dynamic) */ -#define warrant_space ( malloc_watch?sizeof(Warrant_Record):0 ) - -/* Macro to round up a number of bytes to a multiple of sizeof(Word) bytes */ -#define round_up_(n) \ - ((n)==0?0:(sizeof(Word)+(((n)-1)/sizeof(Word))*sizeof(Word))) - -/* Macro to calculate the needed malloc bytes from the user's request. */ -#define rbytes_(nbytes) \ - (size_t)( sizeof(Word) + round_up_(nbytes) + sizeof(Word) + warrant_space ) - -/* Macro to get the -size stored in space through the malloc pointer */ -#define nsize1_(mptr) (((Word*)(void*)(mptr))->nsize1) -#define nsize2_(mptr) (((Word*)(void*)(mptr))->nsize2) - -/* Macro to get the -size stored in the tail of the space through */ -/* the malloc pointer */ -#define tail_nsize1_(mptr) \ - nsize1_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word)) -#define tail_nsize2_(mptr) \ - nsize2_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word)) - -/* Macro to get the -size stored in space through the user pointer */ -#define user_nsize1_(uptr) nsize1_(user2malloc_(uptr)) -#define user_nsize2_(uptr) nsize2_(user2malloc_(uptr)) - -/* Macro to get the -size stored in the tail of the space through */ -/* the user pointer */ -#define user_tail_nsize1_(uptr) tail_nsize1_(user2malloc_(uptr)) -#define user_tail_nsize2_(uptr) tail_nsize2_(user2malloc_(uptr)) - -/* Macro to get the int* of the last 32bit word of user space */ -#define last_user_word_(mptr) \ - ((int*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr)))) - -/* Macros to get at the warrant contents from the malloc pointer */ -#define warrant_(mptr) \ - (*((Warrant_Record*)(void*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word)*2))) - -/* This struct is allocated after the tail clobber word if malloc_watch */ -/* is true. */ -typedef struct { - void *link; /* Next mptr in list */ - char name[WARRANT_NAME_MAX + 1]; /* Name of allocator */ - int line; /* Line number where allocated */ - int id; /* Nth allocation */ -} Warrant_Record; -#define warrant_link_(mptr) warrant_(mptr).link -#define warrant_name_(mptr) warrant_(mptr).name -#define warrant_line_(mptr) warrant_(mptr).line -#define warrant_id_(mptr) warrant_(mptr).id -#define MFILE(mptr) (malloc_watch?warrant_name_(mptr):"?") -#define MLINE(mptr) (malloc_watch?warrant_line_(mptr):0) -#define MID(mptr) (malloc_watch?warrant_id_(mptr):0) - -/* This should be one machine word and is also the clobber word struct */ -typedef struct { - int nsize1; - int nsize2; -} Word; /* Largest basic type , sizeof(double)? */ - -/* The first malloc pointer for the warrants */ -static void *first_warrant_mptr = NULL; - -/* Counter of allocations */ -static int id_counter = 0; -static int largest_size = 0; -static void * largest_addr = NULL; -static void * smallest_addr = NULL; - -/* Used to isolate what the error is */ -static char *debug_check; -static void *clobbered_ptr; - -/* Minimum macro */ -#define minimum(a,b) ((a)<(b)?(a):(b)) - -/* Message routine */ -static void -error_message(const char * format, ...) -{ - FILE *error_fp = stderr; /* All debug_malloc.c messages */ - va_list ap; - va_start(ap, format); - (void)fprintf(error_fp, "debug_malloc: "); - (void)vfprintf(error_fp, format, ap); - (void)fprintf(error_fp, "\n"); - (void)fflush(error_fp); - va_end(ap); -} - -/* This function prints out a memory error for the memory function - * 'name' which was called in file 'file' at line number 'line'. The malloc - * pointer with the error is in 'mptr'. - */ -static void -memory_error(void *mptr, const char *name, int mid, const char *mfile, int mline, const char *file, int line) -{ - char nice_words[512]; - char temp[256]; - int len; - void *mptr_walk; - - if (name == NULL) - name = "UNKNOWN_NAME"; - if (file == NULL) - file = "UNKNOWN_FILE"; - md_system_error(temp, (int)sizeof(temp)); - (void)strcpy(nice_words, temp); - if ( debug_check!=NULL ) { - (void)md_snprintf(nice_words, sizeof(nice_words), - "%s The %s at %p appears to have been hit.", - temp, debug_check, clobbered_ptr); - } - len = -nsize1_(mptr); - error_message("Error: " - "%s The malloc space #%d is at %p [user size=%d(0x%x)]," - " and was allocated from file \"%s\" at line %d." - " [The debug function %s() detected this error " - "in file \"%s\" at line %d.]", - nice_words, mid, mptr, len, len, mfile, mline, - name, file, line); - - /* Print out contents of this allocation */ - { - int i; - void *uptr = malloc2user_(mptr); - char *pmess; - pmess = temp; - for(i=0;i<(int)sizeof(temp);i++) { - int ch = ((unsigned char*)uptr)[i]; - if ( isprint(ch) ) { - *pmess++ = ch; - } else { - *pmess++ = '\\'; - *pmess++ = 'x'; - (void)sprintf(pmess,"%02x",ch); - pmess+=2; - } - } - *pmess = 0; - error_message("Error: %p contains user data: %s", uptr, temp); - } - - /* Try and print out table */ - if (!malloc_watch) { - return; - } - mptr_walk = first_warrant_mptr; - if (mptr_walk != NULL) { - error_message("Active allocations: " - "count=%d, largest_size=%d, address range (%p,%p)", - id_counter, largest_size, smallest_addr, largest_addr); - do { - int size1; - int size2; - char *mfile_walk; - - if ( mptr_walk > largest_addr || mptr_walk < smallest_addr ) { - error_message("Terminating list due to pointer corruption"); - break; - } - size1 = -nsize1_(mptr_walk); - size2 = -nsize2_(mptr_walk); - mfile_walk = MFILE(mptr_walk); - error_message("#%d: addr=%p size1=%d size2=%d file=\"%.*s\" line=%d", - MID(mptr_walk), mptr_walk, size1, size2, - WARRANT_NAME_MAX, mfile_walk, MLINE(mptr_walk)); - if ( size1 != size2 || size1 > largest_size || size1 < 0 ) { - error_message("Terminating list due to size corruption"); - break; - } - mptr_walk = warrant_link_(mptr_walk); - } while (mptr_walk != NULL); - } - abort(); -} - -/* This function sets the clobber word and sets up the warrant for the input - * malloc pointer "mptr". - */ -static void -setup_space_and_issue_warrant(void *mptr, size_t size, const char *file, int line) -{ - register int nbytes; - - /*LINTED*/ - nbytes = (int)size; - if ( nbytes > largest_size || largest_addr == NULL ) largest_size = nbytes; - /*LINTED*/ - if ( mptr > largest_addr ) largest_addr = mptr; - /*LINTED*/ - if ( mptr < smallest_addr || smallest_addr == NULL ) smallest_addr = mptr; - - /* Must be done first: */ - nsize1_(mptr) = -nbytes; - nsize2_(mptr) = -nbytes; - tail_nsize1_(mptr) = -nbytes; - tail_nsize2_(mptr) = -nbytes; - -#ifdef LEFT_OVER_CHAR - /* Fill in those few extra bytes just before the tail Word structure */ - { - register int trailing_extra_bytes; - /* LINTED */ - trailing_extra_bytes = (int) (round_up_(nbytes) - nbytes); - if ( trailing_extra_bytes > 0 ) { - register char *p; - register int i; - p = ((char *) mptr) + sizeof(Word) + nbytes; - for (i = 0; i < trailing_extra_bytes; i++) - p[i] = LEFT_OVER_CHAR; - } - } -#endif - - /* Fill out warrant */ - if (malloc_watch) { - static Warrant_Record zero_warrant; - register void *p1, - *p2; - size_t len; - int start_pos = 0; - warrant_(mptr) = zero_warrant; - p1 = warrant_name_(mptr); - len = strlen(file); - if ( len > WARRANT_NAME_MAX ) { - /*LINTED*/ - start_pos = (int)len - WARRANT_NAME_MAX; - } - p2 = ((char*)file) + start_pos; - /*LINTED*/ - (void) memcpy(p1, p2, minimum(((int)len), WARRANT_NAME_MAX)); - warrant_line_(mptr) = line; - warrant_id_(mptr) = ++id_counter; - warrant_link_(mptr) = first_warrant_mptr; - first_warrant_mptr = mptr; - } -} - -/* This function checks the clobber words at the beginning and end of the - * allocated space. - */ -static void -memory_check(void *uptr, int mid, const char *mfile, int mline, const char *file, int line) -{ - int neg_nbytes; - int nbytes; - - debug_check = "pointer value itself"; - clobbered_ptr = uptr; - if (uptr == NULL) - memory_error((void *) NULL, "memory_check", mid, mfile, mline, file, line); - - /* Check both Word structures */ - - debug_check = "first beginning clobber word"; - clobbered_ptr = (char*)&user_nsize1_(uptr); - neg_nbytes = user_nsize1_(uptr); - if (neg_nbytes >= 0) - memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line); - - debug_check = "second beginning clobber word"; - clobbered_ptr = (char*)&user_nsize2_(uptr); - if (neg_nbytes != user_nsize2_(uptr)) - memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line); - - debug_check = "first ending clobber word"; - clobbered_ptr = (char*)&user_tail_nsize1_(uptr); - if (neg_nbytes != user_tail_nsize1_(uptr)) - memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line); - - debug_check = "second ending clobber word"; - clobbered_ptr = (char*)&user_tail_nsize2_(uptr); - if (neg_nbytes != user_tail_nsize2_(uptr)) - memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line); - - /* Get a positive count of bytes */ - nbytes = -neg_nbytes; - -#ifdef LEFT_OVER_CHAR - { - /* Check those few extra bytes just before the tail Word structure */ - register int trailing_extra_bytes; - register int i; - register char *p; - /* LINTED */ - trailing_extra_bytes = (int) (round_up_(nbytes) - nbytes); - p = ((char *) (uptr)) + nbytes; - debug_check = "trailing left over area"; - for (i = 0; i < trailing_extra_bytes; i++) { - clobbered_ptr = p+1; - if (p[i] != LEFT_OVER_CHAR) { - memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line); - } - } - } -#endif - - /* Make sure debug_check is cleared */ - debug_check = NULL; -} - -/* This function looks for the given malloc pointer in the police line up - * and removes it from the warrant list. - * mptr The pointer to the malloc space being removed - */ -static int -remove_warrant(void *mptr) -{ - void *mptr1, - *last_mptr1; - - /* Free it up from the list */ - if (malloc_watch && mptr != NULL) { - int found; - - found = 0; - last_mptr1 = NULL; - mptr1 = first_warrant_mptr; - while (mptr1 != NULL) { - if (mptr1 == mptr) { - if (last_mptr1 == NULL) - first_warrant_mptr = warrant_link_(mptr1); - else - warrant_link_(last_mptr1) = warrant_link_(mptr1); - found = 1; - break; - } - last_mptr1 = mptr1; - mptr1 = warrant_link_(mptr1); - } - return found; - } - return 1; -} - -static void -actual_free(void *uptr, const char *file, int line) -{ - void *mptr; - const char *mfile; - int mline; - int mid; - if ( uptr == NULL ) - return; - mptr = user2malloc_(uptr); - memory_check(uptr, (mid=MID(mptr)), (mfile=MFILE(mptr)), (mline=MLINE(mptr)), file, line); - if (malloc_watch && remove_warrant(mptr)==0 ) - memory_check(uptr, mid, mfile, mline, file, line); -#ifdef FREED_CHAR - if ( mptr!=NULL ) { - size_t nbytes = -nsize1_(mptr); - /* LINTED */ - (void)memset(mptr, FREED_CHAR, rbytes_(nbytes)); - } -#endif - free(mptr); -} - -#ifdef MAX_FREE_DELAY_COUNT - -static void *free_delay[MAX_FREE_DELAY_COUNT]; -static int free_delay_pos = 0; - -static void -delayed_free(void *uptr, const char* file, int line) -{ - void *mptr; - void *olduptr = free_delay[free_delay_pos]; - size_t nbytes; - if ( uptr==NULL ) - return; - mptr = user2malloc_(uptr); - memory_check(uptr, MID(mptr), MFILE(mptr), MLINE(mptr), file, line); - if ( olduptr!=NULL ) { - actual_free(olduptr, file, line); - } - free_delay[free_delay_pos] = uptr; - free_delay_pos++; - free_delay_pos = free_delay_pos % MAX_FREE_DELAY_COUNT; - nbytes = -user_nsize1_(uptr); -#ifdef FREED_CHAR - (void)memset(uptr, FREED_CHAR, (size_t)nbytes); -#endif -} - -static void -delayed_free_all(const char *file, int line) -{ - int i; - for ( i=0; i< MAX_FREE_DELAY_COUNT; i++) { - void *olduptr = free_delay[i]; - free_delay[i] = NULL; - if ( olduptr!=NULL ) { - actual_free(olduptr, file, line); - } - } -} - -#endif - -void -debug_free(void *uptr, const char *file, int line) -{ - int mid = 0; - - if (uptr == NULL) - memory_error((void *) NULL, "debug_free", mid, file, line, file, line); -#ifdef MAX_FREE_DELAY_COUNT - delayed_free(uptr, file, line); -#else - actual_free(uptr, file, line); -#endif -} - -/* This function calls malloc(). */ -void * -debug_malloc(size_t nbytes, const char *file, int line) -{ - void *mptr; - void *uptr; - int mid = id_counter; - - /*LINTED*/ - if ((int)nbytes <= 0) - memory_error((void *) NULL, "debug_malloc", mid, file, line, file, line); - /* LINTED */ - mptr = malloc(rbytes_(nbytes)); - if (mptr == NULL) - memory_error((void *) NULL, "debug_malloc", mid, file, line, file, line); - setup_space_and_issue_warrant(mptr, nbytes, file, line); - uptr = malloc2user_(mptr); -#ifdef ALLOC_CHAR - (void)memset(uptr, ALLOC_CHAR, (size_t)nbytes); -#endif - return uptr; -} - -void * -debug_realloc(void *uptr, size_t nbytes, const char *file, int line) -{ - void *mptr; - void *oldmptr; - void *newuptr; - size_t oldnbytes; - int mid = id_counter; - - oldmptr = user2malloc_(uptr); - oldnbytes = 0; - if ((int)nbytes <= 0) - memory_error(oldmptr, "debug_realloc", mid, file, line, file, line); - if (uptr != NULL) { - memory_check(uptr, MID(oldmptr), MFILE(oldmptr), MLINE(oldmptr), file, line); - oldnbytes = -user_nsize1_(uptr); - if ( malloc_watch && remove_warrant(oldmptr)==0 ) - memory_check(uptr, MID(oldmptr), MFILE(oldmptr), MLINE(oldmptr), file, line); - } - if (uptr == NULL) { - /* LINTED */ - mptr = malloc(rbytes_(nbytes)); - } else { - /* LINTED */ - mptr = realloc(oldmptr, rbytes_(nbytes)); - } - if (mptr == NULL) - memory_error(oldmptr, "debug_realloc", mid, file, line, file, line); - setup_space_and_issue_warrant(mptr, nbytes, file, line); - newuptr = malloc2user_(mptr); -#ifdef ALLOC_CHAR - if (uptr == NULL) - (void)memset(newuptr, ALLOC_CHAR, (size_t)nbytes); - else if ( nbytes > oldnbytes ) - (void)memset(((char*)newuptr)+oldnbytes, ALLOC_CHAR, (size_t)nbytes-oldnbytes); -#endif - return newuptr; -} - -/* This function calls calloc(). */ -void * -debug_calloc(size_t nelem, size_t elsize, const char *file, int line) -{ - void *mptr; - size_t nbytes; - int mid = id_counter; - - nbytes = nelem*elsize; - /*LINTED*/ - if ((int)nbytes <= 0) - memory_error((void *) NULL, "debug_calloc", mid, file, line, file, line); - /* LINTED */ - mptr = calloc(rbytes_(nbytes),1); - if (mptr == NULL) - memory_error((void *) NULL, "debug_calloc", mid, file, line, file, line); - setup_space_and_issue_warrant(mptr, nbytes, file, line); - return malloc2user_(mptr); -} - -/* This function replaces strdup(). */ -char * -debug_strdup(const char *s1, const char *file, int line) -{ - void *mptr; - void *uptr; - size_t nbytes; - int mid = id_counter; - - if (s1 == NULL) - memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line); - nbytes = strlen(s1)+1; - /*LINTED*/ - if ((int)nbytes < 0) - memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line); - /* LINTED */ - mptr = malloc(rbytes_(nbytes)); - if (mptr == NULL) - memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line); - setup_space_and_issue_warrant(mptr, nbytes, file, line); - uptr = malloc2user_(mptr); - (void)strcpy((char*)uptr, s1); - return (char*)uptr; -} - -void -debug_malloc_verify(const char *file, int line) -{ - void *mptr; - -#ifdef MAX_FREE_DELAY_COUNT - delayed_free_all(file,line); -#endif - - if (!malloc_watch) { - return; - } - mptr = first_warrant_mptr; - if (mptr != NULL) { - /* Check all this memory first */ - do { - memory_check(malloc2user_(mptr), MID(mptr), MFILE(mptr), MLINE(mptr), file, line); - mptr = warrant_link_(mptr); - } while (mptr != NULL); - } -} - -/* Report outstanding space warrants to console. */ -void -debug_malloc_police(const char *file, int line) -{ - void *mptr; - -#ifdef MAX_FREE_DELAY_COUNT - delayed_free_all(file,line); -#endif - - if (!malloc_watch) { - return; - } - - mptr = first_warrant_mptr; - if (mptr != NULL) { - debug_malloc_verify(file, line); - /* Now issue warrants */ - mptr = first_warrant_mptr; - do { - error_message("Outstanding space warrant: %p (%d bytes) allocated by %s at line %d, allocation #%d", - mptr, -nsize1_(mptr), warrant_name_(mptr), - warrant_line_(mptr), warrant_id_(mptr)); - - mptr = warrant_link_(mptr); - } while (mptr != NULL); - } -} - -#else - -void -debug_malloc_verify(const char *file, int line) -{ - file = file; - line = line; -} - -void -debug_malloc_police(const char *file, int line) -{ - file = file; - line = line; -} - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/debug_malloc.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -/* *********************************************************************** - * - * The source file debug_malloc.c should be included with your sources. - * - * The object file debug_malloc.o should be included with your object files. - * - * WARNING: Any memory allocattion from things like memalign(), valloc(), - * or any memory not coming from these macros (malloc, realloc, - * calloc, and strdup) will fail miserably. - * - * *********************************************************************** - */ - -#ifndef _DEBUG_MALLOC_H -#define _DEBUG_MALLOC_H - -#ifdef DEBUG - -#include <stdlib.h> -#include <string.h> - -/* Use THIS_FILE when it is available. */ -#ifndef THIS_FILE - #define THIS_FILE __FILE__ -#endif - -/* The real functions behind the macro curtains. */ - -void *debug_malloc(size_t, const char *, int); -void *debug_realloc(void *, size_t, const char *, int); -void *debug_calloc(size_t, size_t, const char *, int); -char *debug_strdup(const char *, const char *, int); -void debug_free(void *, const char *, int); - -#endif - -void debug_malloc_verify(const char*, int); -#undef malloc_verify -#define malloc_verify() debug_malloc_verify(THIS_FILE, __LINE__) - -void debug_malloc_police(const char*, int); -#undef malloc_police -#define malloc_police() debug_malloc_police(THIS_FILE, __LINE__) - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/hprof.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,401 +0,0 @@ -/* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -/* Primary hprof #include file, should be included by most if not - * all hprof source files. Gives access to the global data structure - * and all global macros, and everything declared in the #include - * files of each of the source files. - */ - -#ifndef HPROF_H -#define HPROF_H - -/* Standard C functions used throughout. */ - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <string.h> -#include <stddef.h> -#include <stdarg.h> -#include <limits.h> -#include <time.h> -#include <errno.h> - -/* General JVM/Java functions, types and macros. */ - -#include <sys/types.h> -#include "jni.h" -#include "jvmti.h" -#include "classfile_constants.h" -#include "jvm_md.h" - -/* Macros to extract the upper and lower 32 bits of a jlong */ - -#define jlong_high(a) ((jint)((a)>>32)) -#define jlong_low(a) ((jint)(a)) -#define jlong_to_jint(a) ((jint)(a)) -#define jint_to_jlong(a) ((jlong)(a)) - -#define jlong_add(a, b) ((a) + (b)) - - -/* The type used to contain a generic 32bit "serial number". */ - -typedef unsigned SerialNumber; - -/* How the options get to OnLoad: */ - -#define AGENTNAME "hprof" -#define XRUN "-Xrun" AGENTNAME -#define AGENTLIB "-agentlib:" AGENTNAME - -/* Name of prelude file, found at runtime relative to java binary location */ - -#define PRELUDE_FILE "jvm.hprof.txt" - -/* File I/O buffer size to be used with any file i/o operation */ - -#define FILE_IO_BUFFER_SIZE (1024*64) - -/* Machine dependent functions. */ - -#include "hprof_md.h" - -/* Table index types */ - -typedef unsigned TableIndex; -typedef TableIndex ClassIndex; -typedef TableIndex FrameIndex; -typedef TableIndex IoNameIndex; -typedef TableIndex MonitorIndex; -typedef TableIndex ObjectIndex; -typedef TableIndex LoaderIndex; -typedef TableIndex RefIndex; -typedef TableIndex SiteIndex; -typedef TableIndex StringIndex; -typedef TableIndex TlsIndex; -typedef TableIndex TraceIndex; - -/* Index for method tables in classes */ - -typedef int MethodIndex; - -/* The different kinds of class status bits. */ - -enum ClassStatus { - CLASS_PREPARED = 0x00000001, - CLASS_LOADED = 0x00000002, - CLASS_UNLOADED = 0x00000004, - CLASS_SPECIAL = 0x00000008, - CLASS_IN_LOAD_LIST = 0x00000010, - CLASS_SYSTEM = 0x00000020, - CLASS_DUMPED = 0x00000040 -}; -typedef jint ClassStatus; - -/* The different kind of objects we track with heap=dump */ - -typedef unsigned char ObjectKind; -enum { - OBJECT_NORMAL = 1, - OBJECT_CLASS = 2, - OBJECT_SYSTEM = 3, - OBJECT_HPROF = 4, - OBJECT_LOADER = 5 -}; - -/* Used by site_write() when writing out the heap=sites data. */ - -enum { - SITE_DUMP_INCREMENTAL = 0x01, - SITE_SORT_BY_ALLOC = 0x02, - SITE_FORCE_GC = 0x04 -}; - -/* Used to hold information about a field, and potentially a value too. */ - -typedef struct FieldInfo { - ClassIndex cnum; - StringIndex name_index; - StringIndex sig_index; - unsigned short modifiers; - unsigned char primType; - unsigned char primSize; -} FieldInfo; - -/* Used to hold information about a constant pool entry value for a class. */ - -typedef struct ConstantPoolValue { - unsigned constant_pool_index; - StringIndex sig_index; - jvalue value; -} ConstantPoolValue; - -/* All machine independent functions */ - -#include "hprof_error.h" -#include "hprof_util.h" -#include "hprof_blocks.h" -#include "hprof_stack.h" -#include "hprof_init.h" -#include "hprof_table.h" -#include "hprof_string.h" -#include "hprof_class.h" -#include "hprof_tracker.h" -#include "hprof_frame.h" -#include "hprof_monitor.h" -#include "hprof_trace.h" -#include "hprof_site.h" -#include "hprof_event.h" -#include "hprof_reference.h" -#include "hprof_object.h" -#include "hprof_loader.h" -#include "hprof_tls.h" -#include "hprof_check.h" -#include "hprof_io.h" -#include "hprof_listener.h" -#include "hprof_cpu.h" -#include "hprof_tag.h" - -/* Global data structure */ - -struct LineTable; - -typedef struct { - - jvmtiEnv *jvmti; /* JVMTI env for this session */ - JavaVM *jvm; /* JavaVM* for this session */ - jint cachedJvmtiVersion; /* JVMTI version number */ - - char *header; /* "JAVA PROFILE 1.0.[12]" */ - jboolean segmented; /* JNI_TRUE if 1.0.2 */ - jlong maxHeapSegment; - jlong maxMemory; - - /* Option settings */ - char * options; /* option string copy */ - char * utf8_output_filename;/* file=filename */ - int net_port; /* net=hostname:port */ - char * net_hostname; /* net=hostname:port */ - char output_format; /* format=a|b */ - int max_trace_depth; /* depth=max_trace_depth */ - int prof_trace_depth; /* max_trace_depth or 2 (old) */ - int sample_interval; /* interval=sample_interval (ms) */ - double cutoff_point; /* cutoff=cutoff_point */ - jboolean cpu_sampling; /* cpu=samples|y */ - jboolean cpu_timing; /* cpu=times */ - jboolean old_timing_format; /* cpu=old (old) output format */ - jboolean heap_dump; /* heap=dump|all */ - jboolean alloc_sites; /* heap=sites|all */ - jboolean thread_in_traces; /* thread=y|n */ - jboolean lineno_in_traces; /* lineno=y|n */ - jboolean dump_on_exit; /* doe=y|n */ - jboolean micro_state_accounting; /* msa=y|n */ - jboolean force_output; /* force=y|n */ - jboolean monitor_tracing; /* monitor=y|n */ - jboolean gc_okay; /* gc_okay=y|n (Not used) */ - - unsigned logflags; /* logflags=bitmask */ - - #define DEBUGFLAG_UNPREPARED_CLASSES 0x001 - unsigned debugflags; /* debugflags=bitmask */ - - jboolean coredump; /* coredump=y|n */ - jboolean errorexit; /* errorexit=y|n */ - jboolean pause; /* pause=y|n */ - jboolean debug; /* debug=y|n */ - jboolean verbose; /* verbose=y|n */ - jboolean primfields; /* primfields=y|n */ - jboolean primarrays; /* primarrays=y|n */ - jint experiment; /* X=NUMBER */ - - int fd; /* file or socket (net=addr). */ - jboolean socket; /* True if fd is a socket (net=addr). */ - jboolean bci; /* True if any kind of BCI being done */ - jboolean obj_watch; /* True if bci and watching allocs */ - - int bci_counter; /* Class BCI counter */ - - int heap_fd; - char *output_filename; /* file=filename */ - char *heapfilename; - - int check_fd; - char *checkfilename; - - volatile jboolean dump_in_process; /* Dump in process */ - volatile jboolean jvm_initializing; /* VMInit happening */ - volatile jboolean jvm_initialized; /* VMInit happened */ - volatile jboolean jvm_shut_down; /* VMDeath happened */ - jboolean vm_death_callback_active; /* VMDeath happening */ - - /* Stack of objects freed during GC */ - Stack * object_free_stack; - jrawMonitorID object_free_lock; - - /* Lock for debug_malloc() */ - jrawMonitorID debug_malloc_lock; - - /* Count of classes that JVMTI thinks are active */ - jint class_count; - - /* Used to track callbacks for VM_DEATH */ - jrawMonitorID callbackBlock; - jrawMonitorID callbackLock; - jint active_callbacks; - - /* Running totals on all bytes allocated */ - jlong total_alloced_bytes; - jlong total_alloced_instances; - jint total_live_bytes; - jint total_live_instances; - - /* Running total on all time spent in GC (very rough estimate) */ - jlong gc_start_time; - jlong time_in_gc; - - /* Global Data access Lock */ - jrawMonitorID data_access_lock; - - /* Global Dump lock */ - jrawMonitorID dump_lock; - - /* Milli-second clock when hprof onload started */ - jlong micro_sec_ticks; - - /* Thread class (for starting agent threads) */ - ClassIndex thread_cnum; - - /* Agent threads started information */ - jboolean listener_loop_running; - jrawMonitorID listener_loop_lock; - jboolean cpu_loop_running; - jrawMonitorID cpu_loop_lock; - jrawMonitorID cpu_sample_lock; /* cpu=samples loop */ - jint gc_finish; /* Count of GC finish events */ - jboolean gc_finish_active; /* True if thread active */ - jboolean gc_finish_stop_request; /* True if we want it to stop */ - jrawMonitorID gc_finish_lock; - - jboolean pause_cpu_sampling; /* temp pause in cpu sampling */ - - /* Output buffer, position, size, and position in dump if reading */ - char * write_buffer; - int write_buffer_index; - int write_buffer_size; - char * heap_buffer; - int heap_buffer_index; - int heap_buffer_size; - jlong heap_last_tag_position; - jlong heap_write_count; - char * check_buffer; - int check_buffer_index; - int check_buffer_size; - - /* Serial number counters for tables (see hprof_table.c), classes, - * tls (thread local storage), and traces. - */ - SerialNumber table_serial_number_start; - SerialNumber class_serial_number_start; - SerialNumber thread_serial_number_start; - SerialNumber trace_serial_number_start; - SerialNumber object_serial_number_start; - SerialNumber frame_serial_number_start; - SerialNumber gref_serial_number_start; - - SerialNumber table_serial_number_counter; - SerialNumber class_serial_number_counter; - SerialNumber thread_serial_number_counter; - SerialNumber trace_serial_number_counter; - SerialNumber object_serial_number_counter; - SerialNumber frame_serial_number_counter; - SerialNumber gref_serial_number_counter; - - /* The methodID for the Object <init> method. */ - jmethodID object_init_method; - - /* Keeping track of the tracker class and it's methods */ - volatile jint tracking_engaged; /* !=0 means it's on */ - ClassIndex tracker_cnum; - int tracker_method_count; - struct { - StringIndex name; /* String index for name */ - StringIndex sig; /* String index for signature */ - jmethodID method; /* Method ID */ - } tracker_methods[12]; /* MAX 12 Tracker class methods */ - - /* Index to some common items */ - LoaderIndex system_loader; - SerialNumber unknown_thread_serial_num; - TraceIndex system_trace_index; - SiteIndex system_object_site_index; - jint system_class_size; - TraceIndex hprof_trace_index; - SiteIndex hprof_site_index; - - /* Tables for strings, classes, sites, etc. */ - struct LookupTable * string_table; - struct LookupTable * ioname_table; - struct LookupTable * class_table; - struct LookupTable * site_table; - struct LookupTable * object_table; - struct LookupTable * reference_table; - struct LookupTable * frame_table; - struct LookupTable * trace_table; - struct LookupTable * monitor_table; - struct LookupTable * tls_table; - struct LookupTable * loader_table; - - /* Handles to java_crw_demo library */ - void * java_crw_demo_library; - void * java_crw_demo_function; - void * java_crw_demo_classname_function; - - /* Indication that the agent has been loaded */ - jboolean isLoaded; - -} GlobalData; - -/* This should be the only 'extern' in the library (not exported). */ - -extern GlobalData * gdata; - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/hprof_b_spec.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef HPROF_B_SPEC_H -#define HPROF_B_SPEC_H - -/* Hprof binary format enums and spec. */ - -/* Need to #define or typedef HprofId before including this file. - * hprof used ObjectIndex or 4 bytes, but it can be 4 or 8 byte type. - */ - -/* -------------------------------------------------------------------- */ -/* -------------------------------------------------------------------- */ -/* -------------------------------------------------------------------- */ - -/* - * hprof binary format: (result either written to a file or sent over - * the network). - * - * WARNING: This format is still under development, and is subject to - * change without notice. - * - * header "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2" (0-terminated) - * u4 size of identifiers. Identifiers are used to represent - * UTF8 strings, objects, stack traces, etc. They usually - * have the same size as host pointers. For example, on - * Solaris and Win32, the size is 4. - * u4 high word - * u4 low word number of milliseconds since 0:00 GMT, 1/1/70 - * [record]* a sequence of records. - */ - -/* - * Record format: - * - * u1 a TAG denoting the type of the record - * u4 number of *microseconds* since the time stamp in the - * header. (wraps around in a little more than an hour) - * u4 number of bytes *remaining* in the record. Note that - * this number excludes the tag and the length field itself. - * [u1]* BODY of the record (a sequence of bytes) - */ - -/* - * The following TAGs are supported: - * - * TAG BODY notes - *---------------------------------------------------------- - * HPROF_UTF8 a UTF8-encoded name - * - * id name ID - * [u1]* UTF8 characters (no trailing zero) - * - * HPROF_LOAD_CLASS a newly loaded class - * - * u4 class serial number (> 0) - * id class object ID - * u4 stack trace serial number - * id class name ID - * - * HPROF_UNLOAD_CLASS an unloading class - * - * u4 class serial_number - * - * HPROF_FRAME a Java stack frame - * - * id stack frame ID - * id method name ID - * id method signature ID - * id source file name ID - * u4 class serial number - * i4 line number. >0: normal - * -1: unknown - * -2: compiled method - * -3: native method - * - * HPROF_TRACE a Java stack trace - * - * u4 stack trace serial number - * u4 thread serial number - * u4 number of frames - * [id]* stack frame IDs - * - * - * HPROF_ALLOC_SITES a set of heap allocation sites, obtained after GC - * - * u2 flags 0x0001: incremental vs. complete - * 0x0002: sorted by allocation vs. live - * 0x0004: whether to force a GC - * u4 cutoff ratio - * u4 total live bytes - * u4 total live instances - * u8 total bytes allocated - * u8 total instances allocated - * u4 number of sites that follow - * [u1 is_array: 0: normal object - * 2: object array - * 4: boolean array - * 5: char array - * 6: float array - * 7: double array - * 8: byte array - * 9: short array - * 10: int array - * 11: long array - * u4 class serial number (may be zero during startup) - * u4 stack trace serial number - * u4 number of bytes alive - * u4 number of instances alive - * u4 number of bytes allocated - * u4]* number of instance allocated - * - * HPROF_START_THREAD a newly started thread. - * - * u4 thread serial number (> 0) - * id thread object ID - * u4 stack trace serial number - * id thread name ID - * id thread group name ID - * id thread group parent name ID - * - * HPROF_END_THREAD a terminating thread. - * - * u4 thread serial number - * - * HPROF_HEAP_SUMMARY heap summary - * - * u4 total live bytes - * u4 total live instances - * u8 total bytes allocated - * u8 total instances allocated - * - * HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT denote a heap dump - * - * [heap dump sub-records]* - * - * There are four kinds of heap dump sub-records: - * - * u1 sub-record type - * - * HPROF_GC_ROOT_UNKNOWN unknown root - * - * id object ID - * - * HPROF_GC_ROOT_THREAD_OBJ thread object - * - * id thread object ID (may be 0 for a - * thread newly attached through JNI) - * u4 thread sequence number - * u4 stack trace sequence number - * - * HPROF_GC_ROOT_JNI_GLOBAL JNI global ref root - * - * id object ID - * id JNI global ref ID - * - * HPROF_GC_ROOT_JNI_LOCAL JNI local ref - * - * id object ID - * u4 thread serial number - * u4 frame # in stack trace (-1 for empty) - * - * HPROF_GC_ROOT_JAVA_FRAME Java stack frame - * - * id object ID - * u4 thread serial number - * u4 frame # in stack trace (-1 for empty) - * - * HPROF_GC_ROOT_NATIVE_STACK Native stack - * - * id object ID - * u4 thread serial number - * - * HPROF_GC_ROOT_STICKY_CLASS System class - * - * id object ID - * - * HPROF_GC_ROOT_THREAD_BLOCK Reference from thread block - * - * id object ID - * u4 thread serial number - * - * HPROF_GC_ROOT_MONITOR_USED Busy monitor - * - * id object ID - * - * HPROF_GC_CLASS_DUMP dump of a class object - * - * id class object ID - * u4 stack trace serial number - * id super class object ID - * id class loader object ID - * id signers object ID - * id protection domain object ID - * id reserved - * id reserved - * - * u4 instance size (in bytes) - * - * u2 size of constant pool - * [u2, constant pool index, - * ty, type - * 2: object - * 4: boolean - * 5: char - * 6: float - * 7: double - * 8: byte - * 9: short - * 10: int - * 11: long - * vl]* and value - * - * u2 number of static fields - * [id, static field name, - * ty, type, - * vl]* and value - * - * u2 number of inst. fields (not inc. super) - * [id, instance field name, - * ty]* type - * - * HPROF_GC_INSTANCE_DUMP dump of a normal object - * - * id object ID - * u4 stack trace serial number - * id class object ID - * u4 number of bytes that follow - * [vl]* instance field values (class, followed - * by super, super's super ...) - * - * HPROF_GC_OBJ_ARRAY_DUMP dump of an object array - * - * id array object ID - * u4 stack trace serial number - * u4 number of elements - * id array class ID - * [id]* elements - * - * HPROF_GC_PRIM_ARRAY_DUMP dump of a primitive array - * - * id array object ID - * u4 stack trace serial number - * u4 number of elements - * u1 element type - * 4: boolean array - * 5: char array - * 6: float array - * 7: double array - * 8: byte array - * 9: short array - * 10: int array - * 11: long array - * [u1]* elements - * - * HPROF_HEAP_DUMP_END terminates series of heap dump segments - * - * HPROF_CPU_SAMPLES a set of sample traces of running threads - * - * u4 total number of samples - * u4 # of traces - * [u4 # of samples - * u4]* stack trace serial number - * - * HPROF_CONTROL_SETTINGS the settings of on/off switches - * - * u4 0x00000001: alloc traces on/off - * 0x00000002: cpu sampling on/off - * u2 stack trace depth - * - */ - -typedef enum HprofTag { - HPROF_UTF8 = 0x01, - HPROF_LOAD_CLASS = 0x02, - HPROF_UNLOAD_CLASS = 0x03, - HPROF_FRAME = 0x04, - HPROF_TRACE = 0x05, - HPROF_ALLOC_SITES = 0x06, - HPROF_HEAP_SUMMARY = 0x07, - HPROF_START_THREAD = 0x0A, - HPROF_END_THREAD = 0x0B, - HPROF_HEAP_DUMP = 0x0C, - HPROF_HEAP_DUMP_SEGMENT = 0x1C, /* 1.0.2 only */ - HPROF_HEAP_DUMP_END = 0x2C, /* 1.0.2 only */ - HPROF_CPU_SAMPLES = 0x0D, - HPROF_CONTROL_SETTINGS = 0x0E -} HprofTag; - -/* - * Heap dump constants - */ - -typedef enum HprofGcTag { - HPROF_GC_ROOT_UNKNOWN = 0xFF, - HPROF_GC_ROOT_JNI_GLOBAL = 0x01, - HPROF_GC_ROOT_JNI_LOCAL = 0x02, - HPROF_GC_ROOT_JAVA_FRAME = 0x03, - HPROF_GC_ROOT_NATIVE_STACK = 0x04, - HPROF_GC_ROOT_STICKY_CLASS = 0x05, - HPROF_GC_ROOT_THREAD_BLOCK = 0x06, - HPROF_GC_ROOT_MONITOR_USED = 0x07, - HPROF_GC_ROOT_THREAD_OBJ = 0x08, - HPROF_GC_CLASS_DUMP = 0x20, - HPROF_GC_INSTANCE_DUMP = 0x21, - HPROF_GC_OBJ_ARRAY_DUMP = 0x22, - HPROF_GC_PRIM_ARRAY_DUMP = 0x23 -} HprofGcTag; - -enum HprofType { - HPROF_ARRAY_OBJECT = 1, - HPROF_NORMAL_OBJECT = 2, - HPROF_BOOLEAN = 4, - HPROF_CHAR = 5, - HPROF_FLOAT = 6, - HPROF_DOUBLE = 7, - HPROF_BYTE = 8, - HPROF_SHORT = 9, - HPROF_INT = 10, - HPROF_LONG = 11 -}; -typedef unsigned char HprofType; - -#define HPROF_TYPE_SIZES \ - { \ - /*Object?*/ sizeof(HprofId), \ - /*Object?*/ sizeof(HprofId), \ - /*Array*/ sizeof(HprofId), \ - /*Object?*/ sizeof(HprofId), \ - /*jboolean*/ 1, \ - /*jchar*/ 2, \ - /*jfloat*/ 4, \ - /*jdouble*/ 8, \ - /*jbyte*/ 1, \ - /*jshort*/ 2, \ - /*jint*/ 4, \ - /*jlong*/ 8 \ - } - -#define HPROF_TYPE_IS_PRIMITIVE(ty) ((ty)>=HPROF_BOOLEAN) - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/hprof_blocks.c Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -/* Allocations from large blocks, no individual free's */ - -#include "hprof.h" - -/* - * This file contains some allocation code that allows you - * to have space allocated via larger blocks of space. - * The only free allowed is of all the blocks and all the elements. - * Elements can be of different alignments and fixed or variable sized. - * The space allocated never moves. - * - */ - -/* Get the real size allocated based on alignment and bytes needed */ -static int -real_size(int alignment, int nbytes) -{ - if ( alignment > 1 ) { - int wasted; - - wasted = alignment - ( nbytes % alignment ); - if ( wasted != alignment ) { - nbytes += wasted; - } - } - return nbytes; -} - -/* Add a new current_block to the Blocks* chain, adjust size if nbytes big. */ -static void -add_block(Blocks *blocks, int nbytes) -{ - int header_size; - int block_size; - BlockHeader *block_header; - - HPROF_ASSERT(blocks!=NULL); - HPROF_ASSERT(nbytes>0); - - header_size = real_size(blocks->alignment, sizeof(BlockHeader)); - block_size = blocks->elem_size*blocks->population; - if ( nbytes > block_size ) { - block_size = real_size(blocks->alignment, nbytes); - } - block_header = (BlockHeader*)HPROF_MALLOC(block_size+header_size); - block_header->next = NULL; - block_header->bytes_left = block_size; - block_header->next_pos = header_size; - - /* Link in new block */ - if ( blocks->current_block != NULL ) { - blocks->current_block->next = block_header; - } - blocks->current_block = block_header; - if ( blocks->first_block == NULL ) { - blocks->first_block = block_header; - } -} - -/* Initialize a new Blocks */ -Blocks * -blocks_init(int alignment, int elem_size, int population) -{ - Blocks *blocks; - - HPROF_ASSERT(alignment>0); - HPROF_ASSERT(elem_size>0); - HPROF_ASSERT(population>0); - - blocks = (Blocks*)HPROF_MALLOC(sizeof(Blocks)); - blocks->alignment = alignment; - blocks->elem_size = elem_size; - blocks->population = population; - blocks->first_block = NULL; - blocks->current_block = NULL; - return blocks; -} - -/* Allocate bytes from a Blocks area. */ -void * -blocks_alloc(Blocks *blocks, int nbytes) -{ - BlockHeader *block; - int pos; - void *ptr; - - HPROF_ASSERT(blocks!=NULL); - HPROF_ASSERT(nbytes>=0); - if ( nbytes == 0 ) { - return NULL; - } - - block = blocks->current_block; - nbytes = real_size(blocks->alignment, nbytes); - if ( block == NULL || block->bytes_left < nbytes ) { - add_block(blocks, nbytes); - block = blocks->current_block; - } - pos = block->next_pos; - ptr = (void*)(((char*)block)+pos); - block->next_pos += nbytes; - block->bytes_left -= nbytes; - return ptr; -} - -/* Terminate the Blocks */ -void -blocks_term(Blocks *blocks) -{ - BlockHeader *block; - - HPROF_ASSERT(blocks!=NULL); - - block = blocks->first_block; - while ( block != NULL ) { - BlockHeader *next_block; - - next_block = block->next; - HPROF_FREE(block); - block = next_block; - } - HPROF_FREE(blocks); -}
--- a/jdk/src/demo/share/jvmti/hprof/hprof_blocks.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -#ifndef HPROF_BLOCKS_H -#define HPROF_BLOCKS_H - -typedef struct BlockHeader { - struct BlockHeader *next; - int bytes_left; - int next_pos; -} BlockHeader; - -typedef struct Blocks { - BlockHeader *first_block; /* Pointer to first BlockHeader */ - BlockHeader *current_block; /* Pointer to current BlockHeader */ - int alignment; /* Data alignment, 1, 2, 4, 8, 16 */ - int elem_size; /* Size in bytes, ==1 means variable sizes */ - int population; /* Number of elements to allow for per Block */ -} Blocks; - -Blocks * blocks_init(int alignment, int elem_size, int population); -void * blocks_alloc(Blocks *blocks, int nbytes); -void blocks_term(Blocks *blocks); - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/hprof_check.c Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1152 +0,0 @@ -/* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -/* Functionality for checking hprof format=b output. */ - -/* ONLY used with logflags=4. */ - -/* Verifies and write a verbose textual version of a format=b file. - * Textual output file is gdata->checkfilename, fd is gdata->check_fd. - * Buffer is in gdata too, see gdata->check* variables. - * Could probably be isolated to a separate library or utility. - */ - -#include "hprof.h" - -typedef TableIndex HprofId; - -#include "hprof_b_spec.h" - -static int type_size[ /*HprofType*/ ] = HPROF_TYPE_SIZES; - -/* For map from HPROF_UTF8 to a string */ -typedef struct UmapInfo { - char *str; -} UmapInfo; - -/* Field information */ -typedef struct Finfo { - HprofId id; - HprofType ty; -} Finfo; - -/* Class information map from class ID (ClassIndex) to class information */ -typedef struct CmapInfo { - int max_finfo; - int n_finfo; - Finfo *finfo; - int inst_size; - HprofId sup; -} CmapInfo; - -/* Read raw bytes from the file image, update the pointer */ -static void -read_raw(unsigned char **pp, unsigned char *buf, int len) -{ - while ( len > 0 ) { - *buf = **pp; - buf++; - (*pp)++; - len--; - } -} - -/* Read various sized elements, properly converted from big to right endian. - * File will contain big endian format. - */ -static unsigned -read_u1(unsigned char **pp) -{ - unsigned char b; - - read_raw(pp, &b, 1); - return b; -} -static unsigned -read_u2(unsigned char **pp) -{ - unsigned short s; - - read_raw(pp, (void*)&s, 2); - return md_htons(s); -} -static unsigned -read_u4(unsigned char **pp) -{ - unsigned int u; - - read_raw(pp, (void*)&u, 4); - return md_htonl(u); -} -static jlong -read_u8(unsigned char **pp) -{ - unsigned int high; - unsigned int low; - jlong x; - - high = read_u4(pp); - low = read_u4(pp); - x = high; - x = (x << 32) | low; - return x; -} -static HprofId -read_id(unsigned char **pp) -{ - return (HprofId)read_u4(pp); -} - -/* System error routine */ -static void -system_error(const char *system_call, int rc, int errnum) -{ - char buf[256]; - char details[256]; - - details[0] = 0; - if ( errnum != 0 ) { - md_system_error(details, (int)sizeof(details)); - } else if ( rc >= 0 ) { - (void)strcpy(details,"Only part of buffer processed"); - } - if ( details[0] == 0 ) { - (void)strcpy(details,"Unknown system error condition"); - } - (void)md_snprintf(buf, sizeof(buf), "System %s failed: %s\n", - system_call, details); - HPROF_ERROR(JNI_TRUE, buf); -} - -/* Write to a fd */ -static void -system_write(int fd, void *buf, int len) -{ - int res; - - HPROF_ASSERT(fd>=0); - res = md_write(fd, buf, len); - if (res < 0 || res!=len) { - system_error("write", res, errno); - } -} - -/* Flush check buffer */ -static void -check_flush(void) -{ - if ( gdata->check_fd < 0 ) { - return; - } - if (gdata->check_buffer_index) { - system_write(gdata->check_fd, gdata->check_buffer, gdata->check_buffer_index); - gdata->check_buffer_index = 0; - } -} - -/* Read out a given typed element */ -static jvalue -read_val(unsigned char **pp, HprofType ty) -{ - jvalue val; - static jvalue empty_val; - - val = empty_val; - switch ( ty ) { - case 0: - case HPROF_ARRAY_OBJECT: - case HPROF_NORMAL_OBJECT: - val.i = read_id(pp); - break; - case HPROF_BYTE: - case HPROF_BOOLEAN: - val.b = read_u1(pp); - break; - case HPROF_CHAR: - case HPROF_SHORT: - val.s = read_u2(pp); - break; - case HPROF_FLOAT: - case HPROF_INT: - val.i = read_u4(pp); - break; - case HPROF_DOUBLE: - case HPROF_LONG: - val.j = read_u8(pp); - break; - default: - HPROF_ERROR(JNI_TRUE, "bad type number"); - break; - } - return val; -} - -/* Move arbitrary byte stream into gdata->check_fd */ -static void -check_raw(void *buf, int len) -{ - if ( gdata->check_fd < 0 ) { - return; - } - - if ( len <= 0 ) { - return; - } - - if (gdata->check_buffer_index + len > gdata->check_buffer_size) { - check_flush(); - if (len > gdata->check_buffer_size) { - system_write(gdata->check_fd, buf, len); - return; - } - } - (void)memcpy(gdata->check_buffer + gdata->check_buffer_index, buf, len); - gdata->check_buffer_index += len; -} - -/* Printf for gdata->check_fd */ -static void -check_printf(char *fmt, ...) -{ - char buf[1024]; - va_list args; - - if ( gdata->check_fd < 0 ) { - return; - } - - va_start(args, fmt); - (void)md_vsnprintf(buf, sizeof(buf), fmt, args); - buf[sizeof(buf)-1] = 0; - check_raw(buf, (int)strlen(buf)); - va_end(args); -} - -/* Printf of an element for gdata->check_fd */ -static void -check_printf_val(HprofType ty, jvalue val, int long_form) -{ - jint low; - jint high; - - switch ( ty ) { - case HPROF_ARRAY_OBJECT: - check_printf("0x%08x", val.i); - break; - case HPROF_NORMAL_OBJECT: - check_printf("0x%08x", val.i); - break; - case HPROF_BOOLEAN: - check_printf("0x%02x", val.b); - break; - case HPROF_CHAR: - if ( long_form ) { - if ( val.s < 0 || val.s > 0x7f || !isprint(val.s) ) { - check_printf("0x%04x", val.s); - } else { - check_printf("0x%04x(%c)", val.s, val.s); - } - } else { - if ( val.s < 0 || val.s > 0x7f || !isprint(val.s) ) { - check_printf("\\u%04x", val.s); - } else { - check_printf("%c", val.s); - } - } - break; - case HPROF_FLOAT: - low = jlong_low(val.j); - check_printf("0x%08x(%f)", low, (double)val.f); - break; - case HPROF_DOUBLE: - high = jlong_high(val.j); - low = jlong_low(val.j); - check_printf("0x%08x%08x(%f)", high, low, val.d); - break; - case HPROF_BYTE: - check_printf("0x%02x", val.b); - break; - case HPROF_SHORT: - check_printf("0x%04x", val.s); - break; - case HPROF_INT: - check_printf("0x%08x", val.i); - break; - case HPROF_LONG: - high = jlong_high(val.j); - low = jlong_low(val.j); - check_printf("0x%08x%08x", high, low); - break; - } -} - -/* Printf of a string for gdata->check_fd */ -static void -check_printf_str(char *str) -{ - int len; - int i; - - if ( str == NULL ) { - check_printf("<null>"); - } - check_printf("\""); - len = (int)strlen(str); - for (i = 0; i < len; i++) { - unsigned char c; - c = str[i]; - if ( isprint(c) ) { - check_printf("%c", c); - } else { - check_printf("\\x%02x", c); - } - } - check_printf("\""); -} - -/* Printf of a utf8 id for gdata->check_fd */ -static void -check_print_utf8(struct LookupTable *utab, char *prefix, HprofId id) -{ - TableIndex uindex; - - if ( id == 0 ) { - check_printf("%s0x%x", prefix, id); - } else { - uindex = table_find_entry(utab, &id, sizeof(id)); - if ( uindex == 0 ) { - check_printf("%s0x%x", prefix, id); - } else { - UmapInfo *umap; - - umap = (UmapInfo*)table_get_info(utab, uindex); - HPROF_ASSERT(umap!=NULL); - HPROF_ASSERT(umap->str!=NULL); - check_printf("%s0x%x->", prefix, id); - check_printf_str(umap->str); - } - } -} - -/* Add a instance field information to this cmap. */ -static void -add_inst_field_to_cmap(CmapInfo *cmap, HprofId id, HprofType ty) -{ - int i; - - HPROF_ASSERT(cmap!=NULL); - i = cmap->n_finfo++; - if ( i+1 >= cmap->max_finfo ) { - int osize; - Finfo *new_finfo; - - osize = cmap->max_finfo; - cmap->max_finfo += 12; - new_finfo = (Finfo*)HPROF_MALLOC(cmap->max_finfo*(int)sizeof(Finfo)); - (void)memset(new_finfo,0,cmap->max_finfo*(int)sizeof(Finfo)); - if ( i == 0 ) { - cmap->finfo = new_finfo; - } else { - (void)memcpy(new_finfo,cmap->finfo,osize*(int)sizeof(Finfo)); - HPROF_FREE(cmap->finfo); - cmap->finfo = new_finfo; - } - } - cmap->finfo[i].id = id; - cmap->finfo[i].ty = ty; -} - -/* LookupTable callback for cmap entry cleanup */ -static void -cmap_cleanup(TableIndex i, void *key_ptr, int key_len, void*info, void*data) -{ - CmapInfo *cmap = info; - - if ( cmap == NULL ) { - return; - } - if ( cmap->finfo != NULL ) { - HPROF_FREE(cmap->finfo); - cmap->finfo = NULL; - } -} - -/* Case label for a switch on hprof heap dump elements */ -#define CASE_HEAP(name) case name: label = #name; - -/* Given the heap dump data and the utf8 map, check/write the heap dump. */ -static int -check_heap_tags(struct LookupTable *utab, unsigned char *pstart, int nbytes) -{ - int nrecords; - unsigned char *p; - unsigned char *psave; - struct LookupTable *ctab; - CmapInfo cmap; - char *label; - unsigned tag; - HprofType ty; - HprofId id, id2, fr, sup; - int num_elements; - int num_bytes; - SerialNumber trace_serial_num; - SerialNumber thread_serial_num; - int npos; - int i; - int inst_size; - - ctab = table_initialize("temp ctab", 64, 64, 512, sizeof(CmapInfo)); - - /* First pass over heap records just fills in the CmapInfo table */ - nrecords = 0; - p = pstart; - while ( p < (pstart+nbytes) ) { - nrecords++; - /*LINTED*/ - npos = (int)(p - pstart); - tag = read_u1(&p); - switch ( tag ) { - CASE_HEAP(HPROF_GC_ROOT_UNKNOWN) - id = read_id(&p); - break; - CASE_HEAP(HPROF_GC_ROOT_JNI_GLOBAL) - id = read_id(&p); - id2 = read_id(&p); - break; - CASE_HEAP(HPROF_GC_ROOT_JNI_LOCAL) - id = read_id(&p); - thread_serial_num = read_u4(&p); - fr = read_u4(&p); - break; - CASE_HEAP(HPROF_GC_ROOT_JAVA_FRAME) - id = read_id(&p); - thread_serial_num = read_u4(&p); - fr = read_u4(&p); - break; - CASE_HEAP(HPROF_GC_ROOT_NATIVE_STACK) - id = read_id(&p); - thread_serial_num = read_u4(&p); - break; - CASE_HEAP(HPROF_GC_ROOT_STICKY_CLASS) - id = read_id(&p); - break; - CASE_HEAP(HPROF_GC_ROOT_THREAD_BLOCK) - id = read_id(&p); - thread_serial_num = read_u4(&p); - break; - CASE_HEAP(HPROF_GC_ROOT_MONITOR_USED) - id = read_id(&p); - break; - CASE_HEAP(HPROF_GC_ROOT_THREAD_OBJ) - id = read_id(&p); - thread_serial_num = read_u4(&p); - trace_serial_num = read_u4(&p); - break; - CASE_HEAP(HPROF_GC_CLASS_DUMP) - (void)memset((void*)&cmap, 0, sizeof(cmap)); - id = read_id(&p); - trace_serial_num = read_u4(&p); - { - HprofId ld, si, pr, re1, re2; - - sup = read_id(&p); - ld = read_id(&p); - si = read_id(&p); - pr = read_id(&p); - re1 = read_id(&p); - re2 = read_id(&p); - cmap.sup = sup; - } - inst_size = read_u4(&p); - cmap.inst_size = inst_size; - num_elements = read_u2(&p); - for(i=0; i<num_elements; i++) { - (void)read_u2(&p); - ty = read_u1(&p); - (void)read_val(&p, ty); - } - num_elements = read_u2(&p); - for(i=0; i<num_elements; i++) { - (void)read_id(&p); - ty = read_u1(&p); - (void)read_val(&p, ty); - } - num_elements = read_u2(&p); - for(i=0; i<num_elements; i++) { - HprofType ty; - HprofId id; - - id = read_id(&p); - ty = read_u1(&p); - add_inst_field_to_cmap(&cmap, id, ty); - } - (void)table_create_entry(ctab, &id, sizeof(id), &cmap); - break; - CASE_HEAP(HPROF_GC_INSTANCE_DUMP) - id = read_id(&p); - trace_serial_num = read_u4(&p); - id2 = read_id(&p); /* class id */ - num_bytes = read_u4(&p); - p += num_bytes; - break; - CASE_HEAP(HPROF_GC_OBJ_ARRAY_DUMP) - id = read_id(&p); - trace_serial_num = read_u4(&p); - num_elements = read_u4(&p); - id2 = read_id(&p); - p += num_elements*(int)sizeof(HprofId); - break; - CASE_HEAP(HPROF_GC_PRIM_ARRAY_DUMP) - id = read_id(&p); - trace_serial_num = read_u4(&p); - num_elements = read_u4(&p); - ty = read_u1(&p); - p += type_size[ty]*num_elements; - break; - default: - label = "UNKNOWN"; - check_printf("H#%d@%d %s: ERROR!\n", - nrecords, npos, label); - HPROF_ERROR(JNI_TRUE, "unknown heap record type"); - break; - } - } - CHECK_FOR_ERROR(p==pstart+nbytes); - - /* Scan again once we have our cmap */ - nrecords = 0; - p = pstart; - while ( p < (pstart+nbytes) ) { - nrecords++; - /*LINTED*/ - npos = (int)(p - pstart); - tag = read_u1(&p); - switch ( tag ) { - CASE_HEAP(HPROF_GC_ROOT_UNKNOWN) - id = read_id(&p); - check_printf("H#%d@%d %s: id=0x%x\n", - nrecords, npos, label, id); - break; - CASE_HEAP(HPROF_GC_ROOT_JNI_GLOBAL) - id = read_id(&p); - id2 = read_id(&p); - check_printf("H#%d@%d %s: id=0x%x, id2=0x%x\n", - nrecords, npos, label, id, id2); - break; - CASE_HEAP(HPROF_GC_ROOT_JNI_LOCAL) - id = read_id(&p); - thread_serial_num = read_u4(&p); - fr = read_u4(&p); - check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u, fr=0x%x\n", - nrecords, npos, label, id, thread_serial_num, fr); - break; - CASE_HEAP(HPROF_GC_ROOT_JAVA_FRAME) - id = read_id(&p); - thread_serial_num = read_u4(&p); - fr = read_u4(&p); - check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u, fr=0x%x\n", - nrecords, npos, label, id, thread_serial_num, fr); - break; - CASE_HEAP(HPROF_GC_ROOT_NATIVE_STACK) - id = read_id(&p); - thread_serial_num = read_u4(&p); - check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u\n", - nrecords, npos, label, id, thread_serial_num); - break; - CASE_HEAP(HPROF_GC_ROOT_STICKY_CLASS) - id = read_id(&p); - check_printf("H#%d@%d %s: id=0x%x\n", - nrecords, npos, label, id); - break; - CASE_HEAP(HPROF_GC_ROOT_THREAD_BLOCK) - id = read_id(&p); - thread_serial_num = read_u4(&p); - check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u\n", - nrecords, npos, label, id, thread_serial_num); - break; - CASE_HEAP(HPROF_GC_ROOT_MONITOR_USED) - id = read_id(&p); - check_printf("H#%d@%d %s: id=0x%x\n", - nrecords, npos, label, id); - break; - CASE_HEAP(HPROF_GC_ROOT_THREAD_OBJ) - id = read_id(&p); - thread_serial_num = read_u4(&p); - trace_serial_num = read_u4(&p); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u," - " trace_serial_num=%u\n", - nrecords, npos, label, id, thread_serial_num, - trace_serial_num); - break; - CASE_HEAP(HPROF_GC_CLASS_DUMP) - id = read_id(&p); - trace_serial_num = read_u4(&p); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u\n", - nrecords, npos, label, id, trace_serial_num); - { - HprofId ld, si, pr, re1, re2; - - sup = read_id(&p); - ld = read_id(&p); - si = read_id(&p); - pr = read_id(&p); - re1 = read_id(&p); - re2 = read_id(&p); - check_printf(" su=0x%x, ld=0x%x, si=0x%x," - " pr=0x%x, re1=0x%x, re2=0x%x\n", - sup, ld, si, pr, re1, re2); - } - inst_size = read_u4(&p); - check_printf(" instance_size=%d\n", inst_size); - - num_elements = read_u2(&p); - for(i=0; i<num_elements; i++) { - HprofType ty; - unsigned cpi; - jvalue val; - - cpi = read_u2(&p); - ty = read_u1(&p); - val = read_val(&p, ty); - check_printf(" constant_pool %d: cpi=%d, ty=%d, val=", - i, cpi, ty); - check_printf_val(ty, val, 1); - check_printf("\n"); - } - - num_elements = read_u2(&p); - check_printf(" static_field_count=%d\n", num_elements); - for(i=0; i<num_elements; i++) { - HprofType ty; - HprofId id; - jvalue val; - - id = read_id(&p); - ty = read_u1(&p); - val = read_val(&p, ty); - check_printf(" static field %d: ", i); - check_print_utf8(utab, "id=", id); - check_printf(", ty=%d, val=", ty); - check_printf_val(ty, val, 1); - check_printf("\n"); - } - - num_elements = read_u2(&p); - check_printf(" instance_field_count=%d\n", num_elements); - for(i=0; i<num_elements; i++) { - HprofType ty; - HprofId id; - - id = read_id(&p); - ty = read_u1(&p); - check_printf(" instance_field %d: ", i); - check_print_utf8(utab, "id=", id); - check_printf(", ty=%d\n", ty); - } - break; - CASE_HEAP(HPROF_GC_INSTANCE_DUMP) - id = read_id(&p); - trace_serial_num = read_u4(&p); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - id2 = read_id(&p); /* class id */ - num_bytes = read_u4(&p); - check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u," - " cid=0x%x, nbytes=%d\n", - nrecords, npos, label, id, trace_serial_num, - id2, num_bytes); - /* This is a packed set of bytes for the instance fields */ - if ( num_bytes > 0 ) { - TableIndex cindex; - int ifield; - CmapInfo *map; - - cindex = table_find_entry(ctab, &id2, sizeof(id2)); - HPROF_ASSERT(cindex!=0); - map = (CmapInfo*)table_get_info(ctab, cindex); - HPROF_ASSERT(map!=NULL); - HPROF_ASSERT(num_bytes==map->inst_size); - - psave = p; - ifield = 0; - - do { - for(i=0;i<map->n_finfo;i++) { - HprofType ty; - HprofId id; - jvalue val; - - ty = map->finfo[i].ty; - id = map->finfo[i].id; - HPROF_ASSERT(ty!=0); - HPROF_ASSERT(id!=0); - val = read_val(&p, ty); - check_printf(" field %d: ", ifield); - check_print_utf8(utab, "id=", id); - check_printf(", ty=%d, val=", ty); - check_printf_val(ty, val, 1); - check_printf("\n"); - ifield++; - } - id2 = map->sup; - map = NULL; - cindex = 0; - if ( id2 != 0 ) { - cindex = table_find_entry(ctab, &id2, sizeof(id2)); - HPROF_ASSERT(cindex!=0); - map = (CmapInfo*)table_get_info(ctab, cindex); - HPROF_ASSERT(map!=NULL); - } - } while ( map != NULL ); - HPROF_ASSERT(num_bytes==(p-psave)); - } - break; - CASE_HEAP(HPROF_GC_OBJ_ARRAY_DUMP) - id = read_id(&p); - trace_serial_num = read_u4(&p); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - num_elements = read_u4(&p); - id2 = read_id(&p); - check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u, nelems=%d, eid=0x%x\n", - nrecords, npos, label, id, trace_serial_num, num_elements, id2); - for(i=0; i<num_elements; i++) { - HprofId id; - - id = read_id(&p); - check_printf(" [%d]: id=0x%x\n", i, id); - } - break; - CASE_HEAP(HPROF_GC_PRIM_ARRAY_DUMP) - id = read_id(&p); - trace_serial_num = read_u4(&p); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - num_elements = read_u4(&p); - ty = read_u1(&p); - psave = p; - check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u, " - "nelems=%d, ty=%d\n", - nrecords, npos, label, id, trace_serial_num, num_elements, ty); - HPROF_ASSERT(HPROF_TYPE_IS_PRIMITIVE(ty)); - if ( num_elements > 0 ) { - int count; - int long_form; - int max_count; - char *quote; - - quote = ""; - long_form = 1; - max_count = 8; - count = 0; - switch ( ty ) { - case HPROF_CHAR: - long_form = 0; - max_count = 72; - quote = "\""; - /*FALLTHRU*/ - case HPROF_INT: - case HPROF_DOUBLE: - case HPROF_LONG: - case HPROF_BYTE: - case HPROF_BOOLEAN: - case HPROF_SHORT: - case HPROF_FLOAT: - check_printf(" val=%s", quote); - for(i=0; i<num_elements; i++) { - jvalue val; - - if ( i > 0 && count == 0 ) { - check_printf(" %s", quote); - } - val = read_val(&p, ty); - check_printf_val(ty, val, long_form); - count += 1; - if ( count >= max_count ) { - check_printf("\"\n"); - count = 0; - } - } - if ( count != 0 ) { - check_printf("%s\n", quote); - } - break; - } - } - HPROF_ASSERT(type_size[ty]*num_elements==(p-psave)); - break; - default: - label = "UNKNOWN"; - check_printf("H#%d@%d %s: ERROR!\n", - nrecords, npos, label); - HPROF_ERROR(JNI_TRUE, "unknown heap record type"); - break; - } - } - CHECK_FOR_ERROR(p==pstart+nbytes); - - table_cleanup(ctab, &cmap_cleanup, NULL); - - return nrecords; -} - -/* LookupTable cleanup callback for utab */ -static void -utab_cleanup(TableIndex i, void *key_ptr, int key_len, void*info, void*data) -{ - UmapInfo *umap = info; - - if ( umap == NULL ) { - return; - } - if ( umap->str != NULL ) { - HPROF_FREE(umap->str); - umap->str = NULL; - } -} - -/* Check all the heap tags in a heap dump */ -static int -check_tags(unsigned char *pstart, int nbytes) -{ - unsigned char *p; - int nrecord; - struct LookupTable *utab; - UmapInfo umap; - - check_printf("\nCHECK TAGS: starting\n"); - - utab = table_initialize("temp utf8 map", 64, 64, 512, sizeof(UmapInfo)); - - /* Walk the tags, assumes UTF8 tags are defined before used */ - p = pstart; - nrecord = 0; - while ( p < (pstart+nbytes) ) { - unsigned tag; - unsigned size; - int nheap_records; - int npos; - char *label; - HprofId id, nm, sg, so, gr, gn; - int i, li, num_elements; - HprofType ty; - SerialNumber trace_serial_num; - SerialNumber thread_serial_num; - SerialNumber class_serial_num; - unsigned flags; - unsigned depth; - float cutoff; - unsigned temp; - jint nblive; - jint nilive; - jlong tbytes; - jlong tinsts; - jint total_samples; - jint trace_count; - - nrecord++; - /*LINTED*/ - npos = (int)(p - pstart); - tag = read_u1(&p); - (void)read_u4(&p); /* microsecs */ - size = read_u4(&p); - #define CASE_TAG(name) case name: label = #name; - switch ( tag ) { - CASE_TAG(HPROF_UTF8) - CHECK_FOR_ERROR(size>=(int)sizeof(HprofId)); - id = read_id(&p); - check_printf("#%d@%d: %s, sz=%d, name_id=0x%x, \"", - nrecord, npos, label, size, id); - num_elements = size-(int)sizeof(HprofId); - check_raw(p, num_elements); - check_printf("\"\n"); - /* Create entry in umap */ - umap.str = HPROF_MALLOC(num_elements+1); - (void)strncpy(umap.str, (char*)p, (size_t)num_elements); - umap.str[num_elements] = 0; - (void)table_create_entry(utab, &id, sizeof(id), &umap); - p += num_elements; - break; - CASE_TAG(HPROF_LOAD_CLASS) - CHECK_FOR_ERROR(size==2*4+2*(int)sizeof(HprofId)); - class_serial_num = read_u4(&p); - CHECK_CLASS_SERIAL_NO(class_serial_num); - id = read_id(&p); - trace_serial_num = read_u4(&p); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - nm = read_id(&p); - check_printf("#%d@%d: %s, sz=%d, class_serial_num=%u," - " id=0x%x, trace_serial_num=%u, name_id=0x%x\n", - nrecord, npos, label, size, class_serial_num, - id, trace_serial_num, nm); - break; - CASE_TAG(HPROF_UNLOAD_CLASS) - CHECK_FOR_ERROR(size==4); - class_serial_num = read_u4(&p); - CHECK_CLASS_SERIAL_NO(class_serial_num); - check_printf("#%d@%d: %s, sz=%d, class_serial_num=%u\n", - nrecord, npos, label, size, class_serial_num); - break; - CASE_TAG(HPROF_FRAME) - CHECK_FOR_ERROR(size==2*4+4*(int)sizeof(HprofId)); - id = read_id(&p); - nm = read_id(&p); - sg = read_id(&p); - so = read_id(&p); - class_serial_num = read_u4(&p); - CHECK_CLASS_SERIAL_NO(class_serial_num); - li = read_u4(&p); - check_printf("#%d@%d: %s, sz=%d, ", nrecord, npos, label, size); - check_print_utf8(utab, "id=", id); - check_printf(" name_id=0x%x, sig_id=0x%x, source_id=0x%x," - " class_serial_num=%u, lineno=%d\n", - nm, sg, so, class_serial_num, li); - break; - CASE_TAG(HPROF_TRACE) - CHECK_FOR_ERROR(size>=3*4); - trace_serial_num = read_u4(&p); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - thread_serial_num = read_u4(&p); /* Can be 0 */ - num_elements = read_u4(&p); - check_printf("#%d@%d: %s, sz=%d, trace_serial_num=%u," - " thread_serial_num=%u, nelems=%d [", - nrecord, npos, label, size, - trace_serial_num, thread_serial_num, num_elements); - for(i=0; i< num_elements; i++) { - check_printf("0x%x,", read_id(&p)); - } - check_printf("]\n"); - break; - CASE_TAG(HPROF_ALLOC_SITES) - CHECK_FOR_ERROR(size>=2+4*4+2*8); - flags = read_u2(&p); - temp = read_u4(&p); - cutoff = *((float*)&temp); - nblive = read_u4(&p); - nilive = read_u4(&p); - tbytes = read_u8(&p); - tinsts = read_u8(&p); - num_elements = read_u4(&p); - check_printf("#%d@%d: %s, sz=%d, flags=0x%x, cutoff=%g," - " nblive=%d, nilive=%d, tbytes=(%d,%d)," - " tinsts=(%d,%d), num_elements=%d\n", - nrecord, npos, label, size, - flags, cutoff, nblive, nilive, - jlong_high(tbytes), jlong_low(tbytes), - jlong_high(tinsts), jlong_low(tinsts), - num_elements); - for(i=0; i< num_elements; i++) { - ty = read_u1(&p); - class_serial_num = read_u4(&p); - CHECK_CLASS_SERIAL_NO(class_serial_num); - trace_serial_num = read_u4(&p); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - nblive = read_u4(&p); - nilive = read_u4(&p); - tbytes = read_u4(&p); - tinsts = read_u4(&p); - check_printf("\t %d: ty=%d, class_serial_num=%u," - " trace_serial_num=%u, nblive=%d, nilive=%d," - " tbytes=%d, tinsts=%d\n", - i, ty, class_serial_num, trace_serial_num, - nblive, nilive, (jint)tbytes, (jint)tinsts); - } - break; - CASE_TAG(HPROF_HEAP_SUMMARY) - CHECK_FOR_ERROR(size==2*4+2*8); - nblive = read_u4(&p); - nilive = read_u4(&p); - tbytes = read_u8(&p); - tinsts = read_u8(&p); - check_printf("#%d@%d: %s, sz=%d," - " nblive=%d, nilive=%d, tbytes=(%d,%d)," - " tinsts=(%d,%d)\n", - nrecord, npos, label, size, - nblive, nilive, - jlong_high(tbytes), jlong_low(tbytes), - jlong_high(tinsts), jlong_low(tinsts)); - break; - CASE_TAG(HPROF_START_THREAD) - CHECK_FOR_ERROR(size==2*4+4*(int)sizeof(HprofId)); - thread_serial_num = read_u4(&p); - CHECK_THREAD_SERIAL_NO(thread_serial_num); - id = read_id(&p); - trace_serial_num = read_u4(&p); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - nm = read_id(&p); - gr = read_id(&p); - gn = read_id(&p); - check_printf("#%d@%d: %s, sz=%d, thread_serial_num=%u," - " id=0x%x, trace_serial_num=%u, ", - nrecord, npos, label, size, - thread_serial_num, id, trace_serial_num); - check_print_utf8(utab, "nm=", id); - check_printf(" trace_serial_num=%u, nm=0x%x," - " gr=0x%x, gn=0x%x\n", - trace_serial_num, nm, gr, gn); - break; - CASE_TAG(HPROF_END_THREAD) - CHECK_FOR_ERROR(size==4); - thread_serial_num = read_u4(&p); - CHECK_THREAD_SERIAL_NO(thread_serial_num); - check_printf("#%d@%d: %s, sz=%d, thread_serial_num=%u\n", - nrecord, npos, label, size, thread_serial_num); - break; - CASE_TAG(HPROF_HEAP_DUMP) - check_printf("#%d@%d: BEGIN: %s, sz=%d\n", - nrecord, npos, label, size); - nheap_records = check_heap_tags(utab, p, size); - check_printf("#%d@%d: END: %s, sz=%d, nheap_recs=%d\n", - nrecord, npos, label, size, nheap_records); - p += size; - break; - CASE_TAG(HPROF_HEAP_DUMP_SEGMENT) /* 1.0.2 */ - check_printf("#%d@%d: BEGIN SEGMENT: %s, sz=%d\n", - nrecord, npos, label, size); - nheap_records = check_heap_tags(utab, p, size); - check_printf("#%d@%d: END SEGMENT: %s, sz=%d, nheap_recs=%d\n", - nrecord, npos, label, size, nheap_records); - p += size; - break; - CASE_TAG(HPROF_HEAP_DUMP_END) /* 1.0.2 */ - check_printf("#%d@%d: SEGMENT END: %s, sz=%d\n", - nrecord, npos, label, size); - break; - CASE_TAG(HPROF_CPU_SAMPLES) - CHECK_FOR_ERROR(size>=2*4); - total_samples = read_u4(&p); - trace_count = read_u4(&p); - check_printf("#%d@%d: %s, sz=%d, total_samples=%d," - " trace_count=%d\n", - nrecord, npos, label, size, - total_samples, trace_count); - for(i=0; i< trace_count; i++) { - num_elements = read_u4(&p); - trace_serial_num = read_u4(&p); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - check_printf("\t %d: samples=%d, trace_serial_num=%u\n", - trace_serial_num, num_elements); - } - break; - CASE_TAG(HPROF_CONTROL_SETTINGS) - CHECK_FOR_ERROR(size==4+2); - flags = read_u4(&p); - depth = read_u2(&p); - check_printf("#%d@%d: %s, sz=%d, flags=0x%x, depth=%d\n", - nrecord, npos, label, size, flags, depth); - break; - default: - label = "UNKNOWN"; - check_printf("#%d@%d: %s, sz=%d\n", - nrecord, npos, label, size); - HPROF_ERROR(JNI_TRUE, "unknown record type"); - p += size; - break; - } - CHECK_FOR_ERROR(p<=(pstart+nbytes)); - } - check_flush(); - CHECK_FOR_ERROR(p==(pstart+nbytes)); - table_cleanup(utab, &utab_cleanup, NULL); - return nrecord; -} - -/* Read the entire file into memory */ -static void * -get_binary_file_image(char *filename, int *pnbytes) -{ - unsigned char *image; - int fd; - jlong nbytes; - int nread; - - *pnbytes = 0; - fd = md_open_binary(filename); - CHECK_FOR_ERROR(fd>=0); - if ( (nbytes = md_seek(fd, (jlong)-1)) == (jlong)-1 ) { - HPROF_ERROR(JNI_TRUE, "Cannot md_seek() to end of file"); - } - CHECK_FOR_ERROR(((jint)nbytes)>512); - if ( md_seek(fd, (jlong)0) != (jlong)0 ) { - HPROF_ERROR(JNI_TRUE, "Cannot md_seek() to start of file"); - } - image = HPROF_MALLOC(((jint)nbytes)+1); - CHECK_FOR_ERROR(image!=NULL); - - /* Read the entire file image into memory */ - nread = md_read(fd, image, (jint)nbytes); - if ( nread <= 0 ) { - HPROF_ERROR(JNI_TRUE, "System read failed."); - } - CHECK_FOR_ERROR(((jint)nbytes)==nread); - md_close(fd); - *pnbytes = (jint)nbytes; - return image; -} - -/* ------------------------------------------------------------------ */ - -void -check_binary_file(char *filename) -{ - unsigned char *image; - unsigned char *p; - unsigned idsize; - int nbytes; - int nrecords; - - image = get_binary_file_image(filename, &nbytes); - if ( image == NULL ) { - check_printf("No file image: %s\n", filename); - return; - } - p = image; - CHECK_FOR_ERROR(strcmp((char*)p, gdata->header)==0); - check_printf("Filename=%s, nbytes=%d, header=\"%s\"\n", - filename, nbytes, p); - p+=((int)strlen((char*)p)+1); - idsize = read_u4(&p); - CHECK_FOR_ERROR(idsize==sizeof(HprofId)); - (void)read_u4(&p); - (void)read_u4(&p); - /* LINTED */ - nrecords = check_tags(p, nbytes - (int)( p - image ) ); - check_printf("#%d total records found in %d bytes\n", nrecords, nbytes); - HPROF_FREE(image); -}
--- a/jdk/src/demo/share/jvmti/hprof/hprof_check.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -#ifndef HPROF_CHECK_H -#define HPROF_CHECK_H - -#define CHECK_FOR_ERROR(condition) \ - ( (condition) ? \ - (void)0 : \ - HPROF_ERROR(JNI_TRUE, #condition) ) -#define CHECK_SERIAL_NO(name, sno) \ - CHECK_FOR_ERROR( (sno) >= gdata->name##_serial_number_start && \ - (sno) < gdata->name##_serial_number_counter) -#define CHECK_CLASS_SERIAL_NO(sno) CHECK_SERIAL_NO(class,sno) -#define CHECK_THREAD_SERIAL_NO(sno) CHECK_SERIAL_NO(thread,sno) -#define CHECK_TRACE_SERIAL_NO(sno) CHECK_SERIAL_NO(trace,sno) -#define CHECK_OBJECT_SERIAL_NO(sno) CHECK_SERIAL_NO(object,sno) - -void check_binary_file(char *filename); - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/hprof_class.c Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,686 +0,0 @@ -/* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -/* Table of class information. - * - * Each element in this table is identified with a ClassIndex. - * Each element is uniquely identified by it's signature and loader. - * Every class load has a unique class serial number. - * While loaded, each element will have a cache of a global reference - * to it's jclass object, plus jmethodID's as needed. - * Method signatures and names are obtained via BCI. - * Methods can be identified with a ClassIndex and MethodIndex pair, - * where the MethodIndex matches the index of the method name and - * signature arrays obtained from the BCI pass. - * Strings are stored in the string table and a StringIndex is used. - * Class Loaders are stored in the loader table and a LoaderIndex is used. - * Since the jclass object is an object, at some point an object table - * entry may be allocated for the jclass as an ObjectIndex. - */ - -#include "hprof.h" - -/* Effectively represents a jclass object. */ - -/* These table elements are made unique by and sorted by signature name. */ - -typedef struct ClassKey { - StringIndex sig_string_index; /* Signature of class */ - LoaderIndex loader_index; /* Index for class loader */ -} ClassKey; - -/* Each class could contain method information, gotten from BCI callback */ - -typedef struct MethodInfo { - StringIndex name_index; /* Method name, index into string table */ - StringIndex sig_index; /* Method signature, index into string table */ - jmethodID method_id; /* Method ID, possibly NULL at first */ -} MethodInfo; - -/* The basic class information we save */ - -typedef struct ClassInfo { - jclass classref; /* Global ref to jclass */ - MethodInfo *method; /* Array of method data */ - int method_count; /* Count of methods */ - ObjectIndex object_index; /* Optional object index for jclass */ - SerialNumber serial_num; /* Unique to the actual class load */ - ClassStatus status; /* Current class status (bit mask) */ - ClassIndex super; /* Super class in this table */ - StringIndex name; /* Name of class */ - jint inst_size; /* #bytes needed for instance fields */ - jint field_count; /* Number of all fields */ - FieldInfo *field; /* Pointer to all FieldInfo's */ -} ClassInfo; - -/* Private interfaces */ - -static ClassKey* -get_pkey(ClassIndex index) -{ - void *key_ptr; - int key_len; - - table_get_key(gdata->class_table, index, (void*)&key_ptr, &key_len); - HPROF_ASSERT(key_len==sizeof(ClassKey)); - HPROF_ASSERT(key_ptr!=NULL); - return (ClassKey*)key_ptr; -} - -static void -fillin_pkey(const char *sig, LoaderIndex loader_index, ClassKey *pkey) -{ - static ClassKey empty_key; - - HPROF_ASSERT(loader_index!=0); - *pkey = empty_key; - pkey->sig_string_index = string_find_or_create(sig); - pkey->loader_index = loader_index; -} - -static ClassInfo * -get_info(ClassIndex index) -{ - ClassInfo *info; - - info = (ClassInfo*)table_get_info(gdata->class_table, index); - return info; -} - -static void -fill_info(TableIndex index, ClassKey *pkey) -{ - ClassInfo *info; - char *sig; - - info = get_info(index); - info->serial_num = gdata->class_serial_number_counter++; - info->method_count = 0; - info->inst_size = -1; - info->field_count = -1; - info->field = NULL; - sig = string_get(pkey->sig_string_index); - if ( sig[0] != JVM_SIGNATURE_CLASS ) { - info->name = pkey->sig_string_index; - } else { - int len; - - len = string_get_len(pkey->sig_string_index); - if ( len > 2 ) { - char *name; - - /* Class signature looks like "Lname;", we want "name" here. */ - name = HPROF_MALLOC(len-1); - (void)memcpy(name, sig+1, len-2); - name[len-2] = 0; - info->name = string_find_or_create(name); - HPROF_FREE(name); - } else { - /* This would be strange, a class signature not in "Lname;" form? */ - info->name = pkey->sig_string_index; - } - } -} - -static ClassIndex -find_entry(ClassKey *pkey) -{ - ClassIndex index; - - index = table_find_entry(gdata->class_table, - (void*)pkey, (int)sizeof(ClassKey)); - return index; -} - -static ClassIndex -create_entry(ClassKey *pkey) -{ - ClassIndex index; - - index = table_create_entry(gdata->class_table, - (void*)pkey, (int)sizeof(ClassKey), NULL); - fill_info(index, pkey); - return index; -} - -static ClassIndex -find_or_create_entry(ClassKey *pkey) -{ - ClassIndex index; - - HPROF_ASSERT(pkey!=NULL); - HPROF_ASSERT(pkey->loader_index!=0); - index = find_entry(pkey); - if ( index == 0 ) { - index = create_entry(pkey); - } - return index; -} - -static void -delete_classref(JNIEnv *env, ClassInfo *info, jclass klass) -{ - jclass ref; - int i; - - HPROF_ASSERT(env!=NULL); - HPROF_ASSERT(info!=NULL); - - for ( i = 0 ; i < info->method_count ; i++ ) { - info->method[i].method_id = NULL; - } - ref = info->classref; - if ( klass != NULL ) { - info->classref = newGlobalReference(env, klass); - } else { - info->classref = NULL; - } - if ( ref != NULL ) { - deleteGlobalReference(env, ref); - } -} - -static void -cleanup_item(TableIndex index, void *key_ptr, int key_len, - void *info_ptr, void *arg) -{ - ClassInfo *info; - - /* Cleanup any information in this ClassInfo structure. */ - HPROF_ASSERT(key_ptr!=NULL); - HPROF_ASSERT(key_len==sizeof(ClassKey)); - HPROF_ASSERT(info_ptr!=NULL); - info = (ClassInfo *)info_ptr; - if ( info->method_count > 0 ) { - HPROF_FREE((void*)info->method); - info->method_count = 0; - info->method = NULL; - } - if ( info->field != NULL ) { - HPROF_FREE((void*)info->field); - info->field_count = 0; - info->field = NULL; - } -} - -static void -delete_ref_item(TableIndex index, void *key_ptr, int key_len, - void *info_ptr, void *arg) -{ - delete_classref((JNIEnv*)arg, (ClassInfo*)info_ptr, NULL); -} - -static void -list_item(TableIndex index, void *key_ptr, int key_len, - void *info_ptr, void *arg) -{ - ClassInfo *info; - ClassKey key; - char *sig; - int i; - - HPROF_ASSERT(key_ptr!=NULL); - HPROF_ASSERT(key_len==sizeof(ClassKey)); - HPROF_ASSERT(info_ptr!=NULL); - key = *((ClassKey*)key_ptr); - sig = string_get(key.sig_string_index); - info = (ClassInfo *)info_ptr; - debug_message( - "0x%08x: Class %s, SN=%u, status=0x%08x, ref=%p," - " method_count=%d\n", - index, - (const char *)sig, - info->serial_num, - info->status, - (void*)info->classref, - info->method_count); - if ( info->method_count > 0 ) { - for ( i = 0 ; i < info->method_count ; i++ ) { - debug_message( - " Method %d: \"%s\", sig=\"%s\", method=%p\n", - i, - string_get(info->method[i].name_index), - string_get(info->method[i].sig_index), - (void*)info->method[i].method_id); - } - } -} - -static void -all_status_remove(TableIndex index, void *key_ptr, int key_len, - void *info_ptr, void *arg) -{ - ClassInfo *info; - ClassStatus status; - - HPROF_ASSERT(info_ptr!=NULL); - /*LINTED*/ - status = (ClassStatus)(long)(ptrdiff_t)arg; - info = (ClassInfo *)info_ptr; - info->status &= (~status); -} - -static void -unload_walker(TableIndex index, void *key_ptr, int key_len, - void *info_ptr, void *arg) -{ - ClassInfo *info; - - HPROF_ASSERT(info_ptr!=NULL); - info = (ClassInfo *)info_ptr; - if ( ! ( info->status & CLASS_IN_LOAD_LIST ) ) { - if ( ! (info->status & (CLASS_SPECIAL|CLASS_SYSTEM|CLASS_UNLOADED)) ) { - io_write_class_unload(info->serial_num, info->object_index); - info->status |= CLASS_UNLOADED; - delete_classref((JNIEnv*)arg, info, NULL); - } - } -} - -/* External interfaces */ - -void -class_init(void) -{ - HPROF_ASSERT(gdata->class_table==NULL); - gdata->class_table = table_initialize("Class", 512, 512, 511, - (int)sizeof(ClassInfo)); -} - -ClassIndex -class_find_or_create(const char *sig, LoaderIndex loader_index) -{ - ClassKey key; - - fillin_pkey(sig, loader_index, &key); - return find_or_create_entry(&key); -} - -ClassIndex -class_create(const char *sig, LoaderIndex loader_index) -{ - ClassKey key; - - fillin_pkey(sig, loader_index, &key); - return create_entry(&key); -} - -void -class_prime_system_classes(void) -{ - /* Prime System classes? Anything before VM_START is System class. - * Or classes loaded before env arg is non-NULL. - * Or any of the classes listed below. - */ - static const char * signatures[] = - { - "Ljava/lang/Object;", - "Ljava/io/Serializable;", - "Ljava/lang/String;", - "Ljava/lang/Class;", - "Ljava/lang/ClassLoader;", - "Ljava/lang/System;", - "Ljava/lang/Thread;", - "Ljava/lang/ThreadGroup;", - }; - int n_signatures; - int i; - LoaderIndex loader_index; - - n_signatures = (int)sizeof(signatures)/(int)sizeof(signatures[0]); - loader_index = loader_find_or_create(NULL, NULL); - for ( i = 0 ; i < n_signatures ; i++ ) { - ClassInfo *info; - ClassIndex index; - ClassKey key; - - fillin_pkey(signatures[i], loader_index, &key); - index = find_or_create_entry(&key); - info = get_info(index); - info->status |= CLASS_SYSTEM; - } -} - -void -class_add_status(ClassIndex index, ClassStatus status) -{ - ClassInfo *info; - - info = get_info(index); - info->status |= status; -} - -ClassStatus -class_get_status(ClassIndex index) -{ - ClassInfo *info; - - info = get_info(index); - return info->status; -} - -StringIndex -class_get_signature(ClassIndex index) -{ - ClassKey *pkey; - - pkey = get_pkey(index); - return pkey->sig_string_index; -} - -SerialNumber -class_get_serial_number(ClassIndex index) -{ - ClassInfo *info; - - if ( index == 0 ) { - return 0; - } - info = get_info(index); - return info->serial_num; -} - -void -class_all_status_remove(ClassStatus status) -{ - table_walk_items(gdata->class_table, &all_status_remove, - (void*)(ptrdiff_t)(long)status); -} - -void -class_do_unloads(JNIEnv *env) -{ - table_walk_items(gdata->class_table, &unload_walker, (void*)env); -} - -void -class_list(void) -{ - debug_message( - "--------------------- Class Table ------------------------\n"); - table_walk_items(gdata->class_table, &list_item, NULL); - debug_message( - "----------------------------------------------------------\n"); -} - -void -class_cleanup(void) -{ - table_cleanup(gdata->class_table, &cleanup_item, NULL); - gdata->class_table = NULL; -} - -void -class_delete_global_references(JNIEnv* env) -{ - table_walk_items(gdata->class_table, &delete_ref_item, (void*)env); -} - -void -class_set_methods(ClassIndex index, const char **name, const char **sig, - int count) -{ - ClassInfo *info; - int i; - - info = get_info(index); - if ( info->method_count > 0 ) { - HPROF_FREE((void*)info->method); - info->method_count = 0; - info->method = NULL; - } - info->method_count = count; - if ( count > 0 ) { - info->method = (MethodInfo *)HPROF_MALLOC(count*(int)sizeof(MethodInfo)); - for ( i = 0 ; i < count ; i++ ) { - info->method[i].name_index = string_find_or_create(name[i]); - info->method[i].sig_index = string_find_or_create(sig[i]); - info->method[i].method_id = NULL; - } - } -} - -jclass -class_new_classref(JNIEnv *env, ClassIndex index, jclass classref) -{ - ClassInfo *info; - - HPROF_ASSERT(classref!=NULL); - info = get_info(index); - if ( ! isSameObject(env, classref, info->classref) ) { - delete_classref(env, info, classref); - } - return info->classref; -} - -jclass -class_get_class(JNIEnv *env, ClassIndex index) -{ - ClassInfo *info; - jclass clazz; - - info = get_info(index); - clazz = info->classref; - if ( env != NULL && clazz == NULL ) { - WITH_LOCAL_REFS(env, 1) { - jclass new_clazz; - char *class_name; - - class_name = string_get(info->name); - /* This really only makes sense for the bootclass classes, - * since FindClass doesn't provide a way to load a class in - * a specific class loader. - */ - new_clazz = findClass(env, class_name); - if ( new_clazz == NULL ) { - HPROF_ERROR(JNI_TRUE, "Cannot load class with findClass"); - } - HPROF_ASSERT(new_clazz!=NULL); - clazz = class_new_classref(env, index, new_clazz); - } END_WITH_LOCAL_REFS; - HPROF_ASSERT(clazz!=NULL); - } - return clazz; -} - -jmethodID -class_get_methodID(JNIEnv *env, ClassIndex index, MethodIndex mnum) -{ - ClassInfo *info; - jmethodID method; - - info = get_info(index); - if (mnum >= info->method_count) { - jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); - (*env)->ThrowNew(env, newExcCls, "Illegal mnum"); - - return NULL; - } - method = info->method[mnum].method_id; - if ( method == NULL ) { - char * name; - char * sig; - jclass clazz; - - name = (char *)string_get(info->method[mnum].name_index); - if (name==NULL) { - jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); - (*env)->ThrowNew(env, newExcCls, "Name not found"); - - return NULL; - } - sig = (char *)string_get(info->method[mnum].sig_index); - HPROF_ASSERT(sig!=NULL); - clazz = class_get_class(env, index); - if ( clazz != NULL ) { - method = getMethodID(env, clazz, name, sig); - HPROF_ASSERT(method!=NULL); - info = get_info(index); - info->method[mnum].method_id = method; - } - } - return method; -} - -void -class_set_inst_size(ClassIndex index, jint inst_size) -{ - ClassInfo *info; - - info = get_info(index); - info->inst_size = inst_size; -} - -jint -class_get_inst_size(ClassIndex index) -{ - ClassInfo *info; - - info = get_info(index); - return info->inst_size; -} - -void -class_set_object_index(ClassIndex index, ObjectIndex object_index) -{ - ClassInfo *info; - - info = get_info(index); - info->object_index = object_index; -} - -ObjectIndex -class_get_object_index(ClassIndex index) -{ - ClassInfo *info; - - info = get_info(index); - return info->object_index; -} - -ClassIndex -class_get_super(ClassIndex index) -{ - ClassInfo *info; - - info = get_info(index); - return info->super; -} - -void -class_set_super(ClassIndex index, ClassIndex super) -{ - ClassInfo *info; - - info = get_info(index); - info->super = super; -} - -LoaderIndex -class_get_loader(ClassIndex index) -{ - ClassKey *pkey; - - pkey = get_pkey(index); - HPROF_ASSERT(pkey->loader_index!=0); - return pkey->loader_index; -} - -/* Get ALL class fields (supers too), return 1 on error, 0 if ok */ -jint -class_get_all_fields(JNIEnv *env, ClassIndex index, - jint *pfield_count, FieldInfo **pfield) -{ - ClassInfo *info; - FieldInfo *finfo; - jint count; - jint ret; - - count = 0; - finfo = NULL; - ret = 1; /* Default is to return an error condition */ - - info = get_info(index); - if ( info != NULL ) { - if ( info->field_count >= 0 ) { - /* Get cache */ - count = info->field_count; - finfo = info->field; - ret = 0; /* Return of cache data, no error */ - } else { - jclass klass; - - klass = info->classref; - if ( klass == NULL || isSameObject(env, klass, NULL) ) { - /* This is probably an error because this will cause the field - * index values to be off, but I'm hesitant to generate a - * fatal error here, so I will issue something and continue. - * I should have been holding a global reference to all the - * jclass, so I'm not sure how this could happen. - * Issuing a FindClass() here is just asking for trouble - * because if the class went away, we aren't even sure - * what ClassLoader to use. - */ - HPROF_ERROR(JNI_FALSE, "Missing jclass when fields needed"); - } else { - jint status; - - status = getClassStatus(klass); - if ( status & - (JVMTI_CLASS_STATUS_PRIMITIVE|JVMTI_CLASS_STATUS_ARRAY) ) { - /* Set cache */ - info->field_count = count; - info->field = finfo; - ret = 0; /* Primitive or array ok */ - } else if ( status & JVMTI_CLASS_STATUS_PREPARED ) { - /* Call JVMTI to get them */ - getAllClassFieldInfo(env, klass, &count, &finfo); - /* Set cache */ - info->field_count = count; - info->field = finfo; - ret = 0; - } - } - } - } - *pfield_count = count; - *pfield = finfo; - return ret; -}
--- a/jdk/src/demo/share/jvmti/hprof/hprof_class.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -#ifndef HPROF_CLASS_H -#define HPROF_CLASS_H - -void class_init(void); -ClassIndex class_find_or_create(const char *sig, LoaderIndex loader); -ClassIndex class_create(const char *sig, LoaderIndex loader); -SerialNumber class_get_serial_number(ClassIndex index); -StringIndex class_get_signature(ClassIndex index); -ClassStatus class_get_status(ClassIndex index); -void class_add_status(ClassIndex index, ClassStatus status); -void class_all_status_remove(ClassStatus status); -void class_do_unloads(JNIEnv *env); -void class_list(void); -void class_delete_global_references(JNIEnv* env); -void class_cleanup(void); -void class_set_methods(ClassIndex index, const char**name, - const char**descr, int count); -jmethodID class_get_methodID(JNIEnv *env, ClassIndex index, - MethodIndex mnum); -jclass class_new_classref(JNIEnv *env, ClassIndex index, - jclass classref); -void class_delete_classref(JNIEnv *env, ClassIndex index); -jclass class_get_class(JNIEnv *env, ClassIndex index); -void class_set_inst_size(ClassIndex index, jint inst_size); -jint class_get_inst_size(ClassIndex index); -void class_set_object_index(ClassIndex index, - ObjectIndex object_index); -ObjectIndex class_get_object_index(ClassIndex index); -ClassIndex class_get_super(ClassIndex index); -void class_set_super(ClassIndex index, ClassIndex super); -void class_set_loader(ClassIndex index, LoaderIndex loader); -LoaderIndex class_get_loader(ClassIndex index); -void class_prime_system_classes(void); -jint class_get_all_fields(JNIEnv *env, ClassIndex cnum, - jint *pfield_count, FieldInfo **pfield); - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/hprof_cpu.c Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -#include "hprof.h" - -/* This file contains the cpu loop for the option cpu=samples */ - -/* The cpu_loop thread basically waits for gdata->sample_interval millisecs - * then wakes up, and for each running thread it gets their stack trace, - * and updates the traces with 'hits'. - * - * No threads are suspended or resumed, and the thread sampling is in the - * file hprof_tls.c, which manages all active threads. The sampling - * technique (what is sampled) is also in hprof_tls.c. - * - * No adjustments are made to the pause time or sample interval except - * by the user via the interval=n option (default is 10ms). - * - * This thread can cause havoc when started prematurely or not terminated - * properly, see cpu_sample_init() and cpu_term(), and their calls in hprof_init.c. - * - * The listener loop (hprof_listener.c) can dynamically turn on or off the - * sampling of all or selected threads. - * - */ - -/* Private functions */ - -static void JNICALL -cpu_loop_function(jvmtiEnv *jvmti, JNIEnv *env, void *p) -{ - int loop_trip_counter; - jboolean cpu_loop_running; - - loop_trip_counter = 0; - - rawMonitorEnter(gdata->cpu_loop_lock); { - gdata->cpu_loop_running = JNI_TRUE; - cpu_loop_running = gdata->cpu_loop_running; - /* Notify cpu_sample_init() that we have started */ - rawMonitorNotifyAll(gdata->cpu_loop_lock); - } rawMonitorExit(gdata->cpu_loop_lock); - - rawMonitorEnter(gdata->cpu_sample_lock); /* Only waits inside loop let go */ - - while ( cpu_loop_running ) { - - ++loop_trip_counter; - - LOG3("cpu_loop()", "iteration", loop_trip_counter); - - /* If a dump is in progress, we pause sampling. */ - rawMonitorEnter(gdata->dump_lock); { - if (gdata->dump_in_process) { - gdata->pause_cpu_sampling = JNI_TRUE; - } - } rawMonitorExit(gdata->dump_lock); - - /* Check to see if we need to pause sampling (listener_loop command) */ - if (gdata->pause_cpu_sampling) { - - /* - * Pause sampling for now. Reset sample controls if - * sampling is resumed again. - */ - - rawMonitorWait(gdata->cpu_sample_lock, 0); - - rawMonitorEnter(gdata->cpu_loop_lock); { - cpu_loop_running = gdata->cpu_loop_running; - } rawMonitorExit(gdata->cpu_loop_lock); - - /* Continue the while loop, which will terminate if done. */ - continue; - } - - /* This is the normal short timed wait before getting a sample */ - rawMonitorWait(gdata->cpu_sample_lock, (jlong)gdata->sample_interval); - - /* Make sure we really want to continue */ - rawMonitorEnter(gdata->cpu_loop_lock); { - cpu_loop_running = gdata->cpu_loop_running; - } rawMonitorExit(gdata->cpu_loop_lock); - - /* Break out if we are done */ - if ( !cpu_loop_running ) { - break; - } - - /* - * If a dump request came in after we checked at the top of - * the while loop, then we catch that fact here. We - * don't want to perturb the data that is being dumped so - * we just ignore the data from this sampling loop. - */ - rawMonitorEnter(gdata->dump_lock); { - if (gdata->dump_in_process) { - gdata->pause_cpu_sampling = JNI_TRUE; - } - } rawMonitorExit(gdata->dump_lock); - - /* Sample all the threads and update trace costs */ - if ( !gdata->pause_cpu_sampling) { - tls_sample_all_threads(env); - } - - /* Check to see if we need to finish */ - rawMonitorEnter(gdata->cpu_loop_lock); { - cpu_loop_running = gdata->cpu_loop_running; - } rawMonitorExit(gdata->cpu_loop_lock); - - } - rawMonitorExit(gdata->cpu_sample_lock); - - rawMonitorEnter(gdata->cpu_loop_lock); { - /* Notify cpu_sample_term() that we are done. */ - rawMonitorNotifyAll(gdata->cpu_loop_lock); - } rawMonitorExit(gdata->cpu_loop_lock); - - LOG2("cpu_loop()", "clean termination"); -} - -/* External functions */ - -void -cpu_sample_init(JNIEnv *env) -{ - gdata->cpu_sampling = JNI_TRUE; - - /* Create the raw monitors needed */ - gdata->cpu_loop_lock = createRawMonitor("HPROF cpu loop lock"); - gdata->cpu_sample_lock = createRawMonitor("HPROF cpu sample lock"); - - rawMonitorEnter(gdata->cpu_loop_lock); { - createAgentThread(env, "HPROF cpu sampling thread", - &cpu_loop_function); - /* Wait for cpu_loop_function() to notify us it has started. */ - rawMonitorWait(gdata->cpu_loop_lock, 0); - } rawMonitorExit(gdata->cpu_loop_lock); -} - -void -cpu_sample_off(JNIEnv *env, ObjectIndex object_index) -{ - jint count; - - count = 1; - if (object_index != 0) { - tls_set_sample_status(object_index, 0); - count = tls_sum_sample_status(); - } - if ( count == 0 ) { - gdata->pause_cpu_sampling = JNI_TRUE; - } else { - gdata->pause_cpu_sampling = JNI_FALSE; - } -} - -void -cpu_sample_on(JNIEnv *env, ObjectIndex object_index) -{ - if ( gdata->cpu_loop_lock == NULL ) { - cpu_sample_init(env); - } - - if (object_index == 0) { - gdata->cpu_sampling = JNI_TRUE; - gdata->pause_cpu_sampling = JNI_FALSE; - } else { - jint count; - - tls_set_sample_status(object_index, 1); - count = tls_sum_sample_status(); - if ( count > 0 ) { - gdata->pause_cpu_sampling = JNI_FALSE; - } - } - - /* Notify the CPU sampling thread that sampling is on */ - rawMonitorEnter(gdata->cpu_sample_lock); { - rawMonitorNotifyAll(gdata->cpu_sample_lock); - } rawMonitorExit(gdata->cpu_sample_lock); - -} - -void -cpu_sample_term(JNIEnv *env) -{ - gdata->pause_cpu_sampling = JNI_FALSE; - rawMonitorEnter(gdata->cpu_sample_lock); { - /* Notify the CPU sampling thread to get out of any sampling Wait */ - rawMonitorNotifyAll(gdata->cpu_sample_lock); - } rawMonitorExit(gdata->cpu_sample_lock); - rawMonitorEnter(gdata->cpu_loop_lock); { - if ( gdata->cpu_loop_running ) { - gdata->cpu_loop_running = JNI_FALSE; - /* Wait for cpu_loop_function() thread to tell us it completed. */ - rawMonitorWait(gdata->cpu_loop_lock, 0); - } - } rawMonitorExit(gdata->cpu_loop_lock); -}
--- a/jdk/src/demo/share/jvmti/hprof/hprof_cpu.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -#ifndef HPROF_CPU_H -#define HPROF_CPU_H - -void cpu_sample_off(JNIEnv *env, ObjectIndex object_index); -void cpu_sample_on(JNIEnv *env, ObjectIndex object_index); - -void cpu_sample_init(JNIEnv *env); -void cpu_sample_term(JNIEnv *env); - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/hprof_error.c Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -#include "hprof.h" - -/* The error handling logic. */ - -/* - * Most hprof error processing and error functions are kept here, along with - * termination functions and signal handling (used in debug version only). - * - */ - -#include <signal.h> - -static int p = 1; /* Used with pause=y|n option */ - -/* Private functions */ - -static void -error_message(const char * format, ...) -{ - va_list ap; - - va_start(ap, format); - (void)vfprintf(stderr, format, ap); - va_end(ap); -} - -static void -error_abort(void) -{ - /* Important to remove existing signal handler */ - (void)signal(SIGABRT, NULL); - error_message("HPROF DUMPING CORE\n"); - abort(); /* Sends SIGABRT signal, usually also caught by libjvm */ -} - -static void -signal_handler(int sig) -{ - /* Caught a signal, most likely a SIGABRT */ - error_message("HPROF SIGNAL %d TERMINATED PROCESS\n", sig); - error_abort(); -} - -static void -setup_signal_handler(int sig) -{ - /* Only if debug version or debug=y */ - if ( gdata->debug ) { - (void)signal(sig, (void(*)(int))(void*)&signal_handler); - } -} - -static void -terminate_everything(jint exit_code) -{ - if ( exit_code > 0 ) { - /* Could be a fatal error or assert error or a sanity error */ - error_message("HPROF TERMINATED PROCESS\n"); - if ( gdata->coredump || gdata->debug ) { - /* Core dump here by request */ - error_abort(); - } - } - /* Terminate the process */ - error_exit_process(exit_code); -} - -/* External functions */ - -void -error_setup(void) -{ - setup_signal_handler(SIGABRT); -} - -void -error_do_pause(void) -{ - int pid = md_getpid(); - int timeleft = 600; /* 10 minutes max */ - int interval = 10; /* 10 second message check */ - - /*LINTED*/ - error_message("\nHPROF pause for PID %d\n", (int)pid); - while ( p && timeleft > 0 ) { - md_sleep(interval); /* 'assign p=0' to stop pause loop */ - timeleft -= interval; - } - if ( timeleft <= 0 ) { - error_message("\n HPROF pause got tired of waiting and gave up.\n"); - } -} - -void -error_exit_process(int exit_code) -{ - exit(exit_code); -} - -static const char * -source_basename(const char *file) -{ - const char *p; - - if ( file == NULL ) { - return "UnknownSourceFile"; - } - p = strrchr(file, '/'); - if ( p == NULL ) { - p = strrchr(file, '\\'); - } - if ( p == NULL ) { - p = file; - } else { - p++; /* go past / */ - } - return p; -} - -void -error_assert(const char *condition, const char *file, int line) -{ - error_message("ASSERTION FAILURE: %s [%s:%d]\n", condition, - source_basename(file), line); - error_abort(); -} - -void -error_handler(jboolean fatal, jvmtiError error, - const char *message, const char *file, int line) -{ - char *error_name; - - if ( message==NULL ) { - message = ""; - } - if ( error != JVMTI_ERROR_NONE ) { - error_name = getErrorName(error); - if ( error_name == NULL ) { - error_name = "?"; - } - error_message("HPROF ERROR: %s (JVMTI Error %s(%d)) [%s:%d]\n", - message, error_name, error, - source_basename(file), line); - } else { - error_message("HPROF ERROR: %s [%s:%d]\n", message, - source_basename(file), line); - } - if ( fatal || gdata->errorexit ) { - /* If it's fatal, or the user wants termination on any error, die */ - terminate_everything(9); - } -} - -void -debug_message(const char * format, ...) -{ - va_list ap; - - va_start(ap, format); - (void)vfprintf(stderr, format, ap); - va_end(ap); -} - -void -verbose_message(const char * format, ...) -{ - if ( gdata->verbose ) { - va_list ap; - - va_start(ap, format); - (void)vfprintf(stderr, format, ap); - va_end(ap); - } -}
--- a/jdk/src/demo/share/jvmti/hprof/hprof_error.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -#ifndef HPROF_ERROR_H -#define HPROF_ERROR_H - -/* Use THIS_FILE when it is available. */ -#ifndef THIS_FILE - #define THIS_FILE __FILE__ -#endif - -/* Macros over assert and error functions so we can capture the source loc. */ - -#define HPROF_BOOL(x) ((jboolean)((x)==0?JNI_FALSE:JNI_TRUE)) - -#define HPROF_ERROR(fatal,msg) \ - error_handler(HPROF_BOOL(fatal), JVMTI_ERROR_NONE, msg, THIS_FILE, __LINE__) - -#define HPROF_JVMTI_ERROR(error,msg) \ - error_handler(HPROF_BOOL(error!=JVMTI_ERROR_NONE), \ - error, msg, THIS_FILE, __LINE__) - -#if defined(DEBUG) || !defined(NDEBUG) - #define HPROF_ASSERT(cond) \ - (((int)(cond))?(void)0:error_assert(#cond, THIS_FILE, __LINE__)) -#else - #define HPROF_ASSERT(cond) -#endif - -#define LOG_DUMP_MISC 0x1 /* Misc. logging info */ -#define LOG_DUMP_LISTS 0x2 /* Dump tables at vm init and death */ -#define LOG_CHECK_BINARY 0x4 /* If format=b, verify binary format */ - -#ifdef HPROF_LOGGING - #define LOG_STDERR(args) \ - { \ - if ( gdata != NULL && (gdata->logflags & LOG_DUMP_MISC) ) { \ - (void)fprintf args ; \ - } \ - } -#else - #define LOG_STDERR(args) -#endif - -#define LOG_FORMAT(format) "HPROF LOG: " format " [%s:%d]\n" - -#define LOG1(str1) LOG_STDERR((stderr, LOG_FORMAT("%s"), \ - str1, THIS_FILE, __LINE__ )) -#define LOG2(str1,str2) LOG_STDERR((stderr, LOG_FORMAT("%s %s"), \ - str1, str2, THIS_FILE, __LINE__ )) -#define LOG3(str1,str2,num) LOG_STDERR((stderr, LOG_FORMAT("%s %s 0x%x"), \ - str1, str2, num, THIS_FILE, __LINE__ )) - -#define LOG(str) LOG1(str) - -void error_handler(jboolean fatal, jvmtiError error, - const char *message, const char *file, int line); -void error_assert(const char *condition, const char *file, int line); -void error_exit_process(int exit_code); -void error_do_pause(void); -void error_setup(void); -void debug_message(const char * format, ...); -void verbose_message(const char * format, ...); - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/hprof_event.c Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,450 +0,0 @@ -/* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -/* This file contains all class, method and allocation event support functions, - * both JVMTI and BCI events. - * (See hprof_monitor.c for the monitor event handlers). - */ - -#include "hprof.h" - -/* Private internal functions. */ - -/* Return a TraceIndex for the given thread. */ -static TraceIndex -get_current(TlsIndex tls_index, JNIEnv *env, jboolean skip_init) -{ - TraceIndex trace_index; - - trace_index = tls_get_trace(tls_index, env, gdata->max_trace_depth, skip_init); - return trace_index; -} - -/* Return a ClassIndex for the given jclass, loader supplied or looked up. */ -static ClassIndex -find_cnum(JNIEnv *env, jclass klass, jobject loader) -{ - LoaderIndex loader_index; - ClassIndex cnum; - char * signature; - - HPROF_ASSERT(klass!=NULL); - - /* Get the loader index */ - loader_index = loader_find_or_create(env, loader); - - /* Get the signature for this class */ - getClassSignature(klass, &signature, NULL); - - /* Find the ClassIndex for this class */ - cnum = class_find_or_create(signature, loader_index); - - /* Free the signature space */ - jvmtiDeallocate(signature); - - /* Make sure we save a global reference to this class in the table */ - HPROF_ASSERT(cnum!=0); - (void)class_new_classref(env, cnum, klass); - return cnum; -} - -/* Get the ClassIndex for the superClass of this jclass. */ -static ClassIndex -get_super(JNIEnv *env, jclass klass) -{ - ClassIndex super_cnum; - - super_cnum = 0; - WITH_LOCAL_REFS(env, 1) { - jclass super_klass; - - super_klass = getSuperclass(env, klass); - if ( super_klass != NULL ) { - super_cnum = find_cnum(env, super_klass, - getClassLoader(super_klass)); - } - } END_WITH_LOCAL_REFS; - return super_cnum; -} - -/* Record an allocation. Could be jobject, jclass, jarray or primitive type. */ -static void -any_allocation(JNIEnv *env, SerialNumber thread_serial_num, - TraceIndex trace_index, jobject object) -{ - SiteIndex site_index; - ClassIndex cnum; - jint size; - jclass klass; - - /* NOTE: Normally the getObjectClass() and getClassLoader() - * would require a - * WITH_LOCAL_REFS(env, 1) { - * } END_WITH_LOCAL_REFS; - * but for performance reasons we skip it here. - */ - - /* Get and tag the klass */ - klass = getObjectClass(env, object); - cnum = find_cnum(env, klass, getClassLoader(klass)); - site_index = site_find_or_create(cnum, trace_index); - tag_class(env, klass, cnum, thread_serial_num, site_index); - - /* Tag the object */ - size = (jint)getObjectSize(object); - tag_new_object(object, OBJECT_NORMAL, thread_serial_num, size, site_index); -} - -/* Handle a java.lang.Object.<init> object allocation. */ -void -event_object_init(JNIEnv *env, jthread thread, jobject object) -{ - /* Called via BCI Tracker class */ - - /* Be very careful what is called here, watch out for recursion. */ - - jint *pstatus; - TraceIndex trace_index; - SerialNumber thread_serial_num; - - HPROF_ASSERT(env!=NULL); - HPROF_ASSERT(thread!=NULL); - HPROF_ASSERT(object!=NULL); - - /* Prevent recursion into any BCI function for this thread (pstatus). */ - if ( tls_get_tracker_status(env, thread, JNI_TRUE, - &pstatus, NULL, &thread_serial_num, &trace_index) == 0 ) { - (*pstatus) = 1; - any_allocation(env, thread_serial_num, trace_index, object); - (*pstatus) = 0; - } -} - -/* Handle any newarray opcode allocation. */ -void -event_newarray(JNIEnv *env, jthread thread, jobject object) -{ - /* Called via BCI Tracker class */ - - /* Be very careful what is called here, watch out for recursion. */ - - jint *pstatus; - TraceIndex trace_index; - SerialNumber thread_serial_num; - - HPROF_ASSERT(env!=NULL); - HPROF_ASSERT(thread!=NULL); - HPROF_ASSERT(object!=NULL); - - /* Prevent recursion into any BCI function for this thread (pstatus). */ - if ( tls_get_tracker_status(env, thread, JNI_FALSE, - &pstatus, NULL, &thread_serial_num, &trace_index) == 0 ) { - (*pstatus) = 1; - any_allocation(env, thread_serial_num, trace_index, object); - (*pstatus) = 0; - } -} - -/* Handle tracking of a method call. */ -void -event_call(JNIEnv *env, jthread thread, ClassIndex cnum, MethodIndex mnum) -{ - /* Called via BCI Tracker class */ - - /* Be very careful what is called here, watch out for recursion. */ - - TlsIndex tls_index; - jint *pstatus; - - HPROF_ASSERT(env!=NULL); - HPROF_ASSERT(thread!=NULL); - if (cnum == 0 || cnum == gdata->tracker_cnum) { - jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); - (*env)->ThrowNew(env, newExcCls, "Illegal cnum."); - - return; - } - - /* Prevent recursion into any BCI function for this thread (pstatus). */ - if ( tls_get_tracker_status(env, thread, JNI_FALSE, - &pstatus, &tls_index, NULL, NULL) == 0 ) { - jmethodID method; - - (*pstatus) = 1; - method = class_get_methodID(env, cnum, mnum); - if (method != NULL) { - tls_push_method(tls_index, method); - } - - (*pstatus) = 0; - } -} - -/* Handle tracking of an exception catch */ -void -event_exception_catch(JNIEnv *env, jthread thread, jmethodID method, - jlocation location, jobject exception) -{ - /* Called via JVMTI_EVENT_EXCEPTION_CATCH callback */ - - /* Be very careful what is called here, watch out for recursion. */ - - TlsIndex tls_index; - jint *pstatus; - - HPROF_ASSERT(env!=NULL); - HPROF_ASSERT(thread!=NULL); - HPROF_ASSERT(method!=NULL); - - /* Prevent recursion into any BCI function for this thread (pstatus). */ - if ( tls_get_tracker_status(env, thread, JNI_FALSE, - &pstatus, &tls_index, NULL, NULL) == 0 ) { - (*pstatus) = 1; - tls_pop_exception_catch(tls_index, thread, method); - (*pstatus) = 0; - } -} - -/* Handle tracking of a method return pop one (maybe more) methods. */ -void -event_return(JNIEnv *env, jthread thread, ClassIndex cnum, MethodIndex mnum) -{ - /* Called via BCI Tracker class */ - - /* Be very careful what is called here, watch out for recursion. */ - - TlsIndex tls_index; - jint *pstatus; - - HPROF_ASSERT(env!=NULL); - HPROF_ASSERT(thread!=NULL); - - if (cnum == 0 || cnum == gdata->tracker_cnum) { - jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); - (*env)->ThrowNew(env, newExcCls, "Illegal cnum."); - - return; - } - - /* Prevent recursion into any BCI function for this thread (pstatus). */ - if ( tls_get_tracker_status(env, thread, JNI_FALSE, - &pstatus, &tls_index, NULL, NULL) == 0 ) { - jmethodID method; - - (*pstatus) = 1; - method = class_get_methodID(env, cnum, mnum); - if (method != NULL) { - tls_pop_method(tls_index, thread, method); - } - - (*pstatus) = 0; - } -} - -/* Handle a class prepare (should have been already loaded) */ -void -event_class_prepare(JNIEnv *env, jthread thread, jclass klass, jobject loader) -{ - /* Called via JVMTI_EVENT_CLASS_PREPARE event */ - - ClassIndex cnum; - - HPROF_ASSERT(env!=NULL); - HPROF_ASSERT(thread!=NULL); - HPROF_ASSERT(klass!=NULL); - - /* Find the ClassIndex for this class */ - cnum = find_cnum(env, klass, loader); - class_add_status(cnum, CLASS_PREPARED); - -} - -/* Handle a class load (could have been already loaded) */ -void -event_class_load(JNIEnv *env, jthread thread, jclass klass, jobject loader) -{ - /* Called via JVMTI_EVENT_CLASS_LOAD event or reset_class_load_status() */ - - ClassIndex cnum; - - HPROF_ASSERT(env!=NULL); - HPROF_ASSERT(klass!=NULL); - - /* Find the ClassIndex for this class */ - cnum = find_cnum(env, klass, loader); - - /* Always mark it as being in the load list */ - class_add_status(cnum, CLASS_IN_LOAD_LIST); - - /* If we are seeing this as a new loaded class, extra work */ - if ( ! ( class_get_status(cnum) & CLASS_LOADED ) ) { - TraceIndex trace_index; - SiteIndex site_index; - ClassIndex super; - SerialNumber class_serial_num; - SerialNumber trace_serial_num; - SerialNumber thread_serial_num; - ObjectIndex class_object_index; - char *signature; - - /* Get the TlsIndex and a TraceIndex for this location */ - if ( thread == NULL ) { - /* This should be very rare, but if this class load was simulated - * from hprof_init.c due to a reset of the class load status, - * and it originated from a pre-VM_INIT event, the jthread - * would be NULL, or it was a jclass created that didn't get - * reported to us, like an array class or a primitive class? - */ - trace_index = gdata->system_trace_index; - thread_serial_num = gdata->unknown_thread_serial_num; - } else { - TlsIndex tls_index; - - tls_index = tls_find_or_create(env, thread); - trace_index = get_current(tls_index, env, JNI_FALSE); - thread_serial_num = tls_get_thread_serial_number(tls_index); - } - - /* Get the SiteIndex for this location and a java.lang.Class object */ - /* Note that the target cnum, not the cnum for java.lang.Class. */ - site_index = site_find_or_create(cnum, trace_index); - - /* Tag this java.lang.Class object */ - tag_class(env, klass, cnum, thread_serial_num, site_index); - - class_add_status(cnum, CLASS_LOADED); - - class_serial_num = class_get_serial_number(cnum); - class_object_index = class_get_object_index(cnum); - trace_serial_num = trace_get_serial_number(trace_index); - signature = string_get(class_get_signature(cnum)); - - rawMonitorEnter(gdata->data_access_lock); { - io_write_class_load(class_serial_num, class_object_index, - trace_serial_num, signature); - } rawMonitorExit(gdata->data_access_lock); - - super = get_super(env, klass); - class_set_super(cnum, super); - } - -} - -/* Handle a thread start event */ -void -event_thread_start(JNIEnv *env, jthread thread) -{ - /* Called via JVMTI_EVENT_THREAD_START event */ - - TlsIndex tls_index; - ObjectIndex object_index; - TraceIndex trace_index; - jlong tag; - SerialNumber thread_serial_num; - - HPROF_ASSERT(env!=NULL); - HPROF_ASSERT(thread!=NULL); - - tls_index = tls_find_or_create(env, thread); - thread_serial_num = tls_get_thread_serial_number(tls_index); - trace_index = get_current(tls_index, env, JNI_FALSE); - - tag = getTag(thread); - if ( tag == (jlong)0 ) { - SiteIndex site_index; - jint size; - - size = (jint)getObjectSize(thread); - site_index = site_find_or_create(gdata->thread_cnum, trace_index); - /* We create a new object with this thread's serial number */ - object_index = object_new(site_index, size, OBJECT_NORMAL, - thread_serial_num); - } else { - object_index = tag_extract(tag); - /* Normally the Thread object is created and tagged before we get - * here, but the thread_serial_number on this object isn't what - * we want. So we update it to the serial number of this thread. - */ - object_set_thread_serial_number(object_index, thread_serial_num); - } - tls_set_thread_object_index(tls_index, object_index); - - WITH_LOCAL_REFS(env, 1) { - jvmtiThreadInfo threadInfo; - jvmtiThreadGroupInfo threadGroupInfo; - jvmtiThreadGroupInfo parentGroupInfo; - - getThreadInfo(thread, &threadInfo); - getThreadGroupInfo(threadInfo.thread_group, &threadGroupInfo); - if ( threadGroupInfo.parent != NULL ) { - getThreadGroupInfo(threadGroupInfo.parent, &parentGroupInfo); - } else { - (void)memset(&parentGroupInfo, 0, sizeof(parentGroupInfo)); - } - - rawMonitorEnter(gdata->data_access_lock); { - io_write_thread_start(thread_serial_num, - object_index, trace_get_serial_number(trace_index), - threadInfo.name, threadGroupInfo.name, parentGroupInfo.name); - } rawMonitorExit(gdata->data_access_lock); - - jvmtiDeallocate(threadInfo.name); - jvmtiDeallocate(threadGroupInfo.name); - jvmtiDeallocate(parentGroupInfo.name); - - } END_WITH_LOCAL_REFS; -} - -void -event_thread_end(JNIEnv *env, jthread thread) -{ - /* Called via JVMTI_EVENT_THREAD_END event */ - TlsIndex tls_index; - - HPROF_ASSERT(env!=NULL); - HPROF_ASSERT(thread!=NULL); - - tls_index = tls_find_or_create(env, thread); - rawMonitorEnter(gdata->data_access_lock); { - io_write_thread_end(tls_get_thread_serial_number(tls_index)); - } rawMonitorExit(gdata->data_access_lock); - tls_thread_ended(env, tls_index); - setThreadLocalStorage(thread, (void*)NULL); -}
--- a/jdk/src/demo/share/jvmti/hprof/hprof_event.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -#ifndef HPROF_EVENT_H -#define HPROF_EVENT_H - -/* From BCI: */ -void event_object_init(JNIEnv *env, jthread thread, jobject obj); -void event_newarray(JNIEnv *env, jthread thread, jobject obj); -void event_call(JNIEnv *env, jthread thread, - ClassIndex cnum, MethodIndex mnum); -void event_return(JNIEnv *env, jthread thread, - ClassIndex cnum, MethodIndex mnum); - -/* From JVMTI: */ -void event_class_load(JNIEnv *env, jthread thread, jclass klass, jobject loader); -void event_class_prepare(JNIEnv *env, jthread thread, jclass klass, jobject loader); -void event_thread_start(JNIEnv *env_id, jthread thread); -void event_thread_end(JNIEnv *env_id, jthread thread); -void event_exception_catch(JNIEnv *env, jthread thread, jmethodID method, - jlocation location, jobject exception); - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/hprof_frame.c Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -/* This file contains support for handling frames, or (method,location) pairs. */ - -#include "hprof.h" - -/* - * Frames map 1-to-1 to (methodID,location) pairs. - * When no line number is known, -1 should be used. - * - * Frames are mostly used in traces (see hprof_trace.c) and will be marked - * with their status flag as they are written out to the hprof output file. - * - */ - -enum LinenoState { - LINENUM_UNINITIALIZED = 0, - LINENUM_AVAILABLE = 1, - LINENUM_UNAVAILABLE = 2 -}; - -typedef struct FrameKey { - jmethodID method; - jlocation location; -} FrameKey; - -typedef struct FrameInfo { - unsigned short lineno; - unsigned char lineno_state; /* LinenoState */ - unsigned char status; - SerialNumber serial_num; -} FrameInfo; - -static FrameKey* -get_pkey(FrameIndex index) -{ - void *key_ptr; - int key_len; - - table_get_key(gdata->frame_table, index, &key_ptr, &key_len); - HPROF_ASSERT(key_len==sizeof(FrameKey)); - HPROF_ASSERT(key_ptr!=NULL); - return (FrameKey*)key_ptr; -} - -static FrameInfo * -get_info(FrameIndex index) -{ - FrameInfo *info; - - info = (FrameInfo*)table_get_info(gdata->frame_table, index); - return info; -} - -static void -list_item(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg) -{ - FrameKey key; - FrameInfo *info; - - HPROF_ASSERT(key_ptr!=NULL); - HPROF_ASSERT(key_len==sizeof(FrameKey)); - HPROF_ASSERT(info_ptr!=NULL); - - key = *((FrameKey*)key_ptr); - info = (FrameInfo*)info_ptr; - debug_message( - "Frame 0x%08x: method=%p, location=%d, lineno=%d(%d), status=%d \n", - i, (void*)key.method, (jint)key.location, - info->lineno, info->lineno_state, info->status); -} - -void -frame_init(void) -{ - gdata->frame_table = table_initialize("Frame", - 1024, 1024, 1023, (int)sizeof(FrameInfo)); -} - -FrameIndex -frame_find_or_create(jmethodID method, jlocation location) -{ - FrameIndex index; - static FrameKey empty_key; - FrameKey key; - jboolean new_one; - - key = empty_key; - key.method = method; - key.location = location; - new_one = JNI_FALSE; - index = table_find_or_create_entry(gdata->frame_table, - &key, (int)sizeof(key), &new_one, NULL); - if ( new_one ) { - FrameInfo *info; - - info = get_info(index); - info->lineno_state = LINENUM_UNINITIALIZED; - if ( location < 0 ) { - info->lineno_state = LINENUM_UNAVAILABLE; - } - info->serial_num = gdata->frame_serial_number_counter++; - } - return index; -} - -void -frame_list(void) -{ - debug_message( - "--------------------- Frame Table ------------------------\n"); - table_walk_items(gdata->frame_table, &list_item, NULL); - debug_message( - "----------------------------------------------------------\n"); -} - -void -frame_cleanup(void) -{ - table_cleanup(gdata->frame_table, NULL, NULL); - gdata->frame_table = NULL; -} - -void -frame_set_status(FrameIndex index, jint status) -{ - FrameInfo *info; - - info = get_info(index); - info->status = (unsigned char)status; -} - -void -frame_get_location(FrameIndex index, SerialNumber *pserial_num, - jmethodID *pmethod, jlocation *plocation, jint *plineno) -{ - FrameKey *pkey; - FrameInfo *info; - jint lineno; - - pkey = get_pkey(index); - *pmethod = pkey->method; - *plocation = pkey->location; - info = get_info(index); - lineno = (jint)info->lineno; - if ( info->lineno_state == LINENUM_UNINITIALIZED ) { - info->lineno_state = LINENUM_UNAVAILABLE; - if ( gdata->lineno_in_traces ) { - if ( pkey->location >= 0 && !isMethodNative(pkey->method) ) { - lineno = getLineNumber(pkey->method, pkey->location); - if ( lineno >= 0 ) { - info->lineno = (unsigned short)lineno; /* save it */ - info->lineno_state = LINENUM_AVAILABLE; - } - } - } - } - if ( info->lineno_state == LINENUM_UNAVAILABLE ) { - lineno = -1; - } - *plineno = lineno; - *pserial_num = info->serial_num; -} - -jint -frame_get_status(FrameIndex index) -{ - FrameInfo *info; - - info = get_info(index); - return (jint)info->status; -}
--- a/jdk/src/demo/share/jvmti/hprof/hprof_frame.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -#ifndef HPROF_FRAME_H -#define HPROF_FRAME_H - -void frame_init(void); -FrameIndex frame_find_or_create(jmethodID method, jlocation location); -void frame_list(void); -void frame_cleanup(void); -void frame_get_location(FrameIndex frame_num, SerialNumber *serial_num, - jmethodID *pmethod, - jlocation *plocation, jint *plineno); -void frame_set_status(FrameIndex frame_num, jint status); -jint frame_get_status(FrameIndex frame_num); - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/hprof_init.c Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2145 +0,0 @@ -/* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -/* Main source file, the basic JVMTI connection/startup code. */ - -#include "hprof.h" - -#include "java_crw_demo.h" - -/* - * This file contains all the startup logic (Agent_Onload) and - * connection to the JVMTI interface. - * All JVMTI Event callbacks are in this file. - * All setting of global data (gdata) is done here. - * Options are parsed here. - * Option help messages are here. - * Termination handled here (VM_DEATH) and shutdown (Agent_OnUnload). - * Spawning of the cpu sample loop thread and listener thread is done here. - * - * Use of private 'static' data has been limited, most shared static data - * should be found in the GlobalData structure pointed to by gdata - * (see hprof.h). - * - */ - -/* The default output filenames. */ - -#define DEFAULT_TXT_SUFFIX ".txt" -#define DEFAULT_OUTPUTFILE "java.hprof" -#define DEFAULT_OUTPUTTEMP "java.hprof.temp" - -/* The only global variable, defined by this library */ -GlobalData *gdata; - -/* Experimental options */ -#define EXPERIMENT_NO_EARLY_HOOK 0x1 - -/* Default trace depth */ -#define DEFAULT_TRACE_DEPTH 4 - -/* Default sample interval */ -#define DEFAULT_SAMPLE_INTERVAL 10 - -/* Default cutoff */ -#define DEFAULT_CUTOFF_POINT 0.0001 - -/* Stringize macros for help. */ -#define _TO_STR(a) #a -#define TO_STR(a) _TO_STR(a) - -/* Macros to surround callback code (non-VM_DEATH callbacks). - * Note that this just keeps a count of the non-VM_DEATH callbacks that - * are currently active, it does not prevent these callbacks from - * operating in parallel. It's the VM_DEATH callback that will wait - * for all these callbacks to either complete and block, or just block. - * We need to hold back these threads so they don't die during the final - * VM_DEATH processing. - * If the VM_DEATH callback is active in the beginning, then this callback - * just blocks to prevent further execution of the thread. - * If the VM_DEATH callback is active at the end, then this callback - * will notify the VM_DEATH callback if it's the last one. - * In all cases, the last thing they do is Enter/Exit the monitor - * gdata->callbackBlock, which will block this callback if VM_DEATH - * is running. - * - * WARNING: No not 'return' or 'goto' out of the BEGIN_CALLBACK/END_CALLBACK - * block, this will mess up the count. - */ - -#define BEGIN_CALLBACK() \ -{ /* BEGIN OF CALLBACK */ \ - jboolean bypass; \ - rawMonitorEnter(gdata->callbackLock); \ - if (gdata->vm_death_callback_active) { \ - /* VM_DEATH is active, we will bypass the CALLBACK CODE */ \ - bypass = JNI_TRUE; \ - rawMonitorExit(gdata->callbackLock); \ - /* Bypassed CALLBACKS block here until VM_DEATH done */ \ - rawMonitorEnter(gdata->callbackBlock); \ - rawMonitorExit(gdata->callbackBlock); \ - } else { \ - /* We will be executing the CALLBACK CODE in this case */ \ - gdata->active_callbacks++; \ - bypass = JNI_FALSE; \ - rawMonitorExit(gdata->callbackLock); \ - } \ - if ( !bypass ) { \ - /* BODY OF CALLBACK CODE (with no callback locks held) */ - -#define END_CALLBACK() /* Part of bypass if body */ \ - rawMonitorEnter(gdata->callbackLock); \ - gdata->active_callbacks--; \ - /* If VM_DEATH is active, and last one, send notify. */ \ - if (gdata->vm_death_callback_active) { \ - if (gdata->active_callbacks == 0) { \ - rawMonitorNotifyAll(gdata->callbackLock); \ - } \ - } \ - rawMonitorExit(gdata->callbackLock); \ - /* Non-Bypassed CALLBACKS block here until VM_DEATH done */ \ - rawMonitorEnter(gdata->callbackBlock); \ - rawMonitorExit(gdata->callbackBlock); \ - } \ -} /* END OF CALLBACK */ - -/* Forward declarations */ -static void set_callbacks(jboolean on); - -/* ------------------------------------------------------------------- */ -/* Global data initialization */ - -/* Get initialized global data area */ -static GlobalData * -get_gdata(void) -{ - static GlobalData data; - - /* Create initial default values */ - (void)memset(&data, 0, sizeof(GlobalData)); - - data.fd = -1; /* Non-zero file or socket. */ - data.heap_fd = -1; /* For heap=dump, see hprof_io */ - data.check_fd = -1; /* For heap=dump, see hprof_io */ - data.max_trace_depth = DEFAULT_TRACE_DEPTH; - data.prof_trace_depth = DEFAULT_TRACE_DEPTH; - data.sample_interval = DEFAULT_SAMPLE_INTERVAL; - data.lineno_in_traces = JNI_TRUE; - data.output_format = 'a'; /* 'b' for binary */ - data.cutoff_point = DEFAULT_CUTOFF_POINT; - data.dump_on_exit = JNI_TRUE; - data.gc_start_time = -1L; -#ifdef DEBUG - data.debug = JNI_TRUE; - data.coredump = JNI_TRUE; -#endif - data.micro_state_accounting = JNI_FALSE; - data.force_output = JNI_TRUE; - data.verbose = JNI_TRUE; - data.primfields = JNI_TRUE; - data.primarrays = JNI_TRUE; - - data.table_serial_number_start = 1; - data.class_serial_number_start = 100000; - data.thread_serial_number_start = 200000; - data.trace_serial_number_start = 300000; - data.object_serial_number_start = 400000; - data.frame_serial_number_start = 500000; - data.gref_serial_number_start = 1; - - data.table_serial_number_counter = data.table_serial_number_start; - data.class_serial_number_counter = data.class_serial_number_start; - data.thread_serial_number_counter = data.thread_serial_number_start; - data.trace_serial_number_counter = data.trace_serial_number_start; - data.object_serial_number_counter = data.object_serial_number_start; - data.frame_serial_number_counter = data.frame_serial_number_start; - data.gref_serial_number_counter = data.gref_serial_number_start; - - data.unknown_thread_serial_num = data.thread_serial_number_counter++; - return &data; -} - -/* ------------------------------------------------------------------- */ -/* Error handler callback for the java_crw_demo (classfile read write) functions. */ - -static void -my_crw_fatal_error_handler(const char * msg, const char *file, int line) -{ - char errmsg[256]; - - (void)md_snprintf(errmsg, sizeof(errmsg), - "%s [%s:%d]", msg, file, line); - errmsg[sizeof(errmsg)-1] = 0; - HPROF_ERROR(JNI_TRUE, errmsg); -} - -static void -list_all_tables(void) -{ - string_list(); - class_list(); - frame_list(); - site_list(); - object_list(); - trace_list(); - monitor_list(); - tls_list(); - loader_list(); -} - -/* ------------------------------------------------------------------- */ -/* Option Parsing support */ - -/** - * Socket connection - */ - -/* - * Return a socket connect()ed to a "hostname" that is - * accept()ing heap profile data on "port." Return a value <= 0 if - * such a connection can't be made. - */ -static int -connect_to_socket(char *hostname, int port) -{ - int fd; - - if (port == 0 || port > 65535) { - HPROF_ERROR(JNI_FALSE, "invalid port number"); - return -1; - } - if (hostname == NULL) { - HPROF_ERROR(JNI_FALSE, "hostname is NULL"); - return -1; - } - - /* create a socket */ - fd = md_connect(hostname, (unsigned short)port); - return fd; -} - -/* Accept a filename, and adjust the name so that it is unique for this PID */ -static void -make_unique_filename(char **filename) -{ - int fd; - - /* Find a file that doesn't exist */ - fd = md_open(*filename); - if ( fd >= 0 ) { - int pid; - char *new_name; - char *old_name; - char *prefix; - char suffix[5]; - int new_len; - - /* Close the file. */ - md_close(fd); - - /* Make filename name.PID[.txt] */ - pid = md_getpid(); - old_name = *filename; - new_len = (int)strlen(old_name)+64; - new_name = HPROF_MALLOC(new_len); - prefix = old_name; - suffix[0] = 0; - - /* Look for .txt suffix if not binary output */ - if (gdata->output_format != 'b') { - char *dot; - char *format_suffix; - - format_suffix = DEFAULT_TXT_SUFFIX; - - (void)strcpy(suffix, format_suffix); - - dot = strrchr(old_name, '.'); - if ( dot != NULL ) { - int i; - int slen; - int match; - - slen = (int)strlen(format_suffix); - match = 1; - for ( i = 0; i < slen; i++ ) { - if ( dot[i]==0 || - tolower(format_suffix[i]) != tolower(dot[i]) ) { - match = 0; - break; - } - } - if ( match ) { - (void)strcpy(suffix, dot); - *dot = 0; /* truncates prefix and old_name */ - } - } - } - - /* Construct the name */ - (void)md_snprintf(new_name, new_len, - "%s.%d%s", prefix, pid, suffix); - *filename = new_name; - HPROF_FREE(old_name); - - /* Odds are with Windows, this file may not be so unique. */ - (void)remove(gdata->output_filename); - } -} - -static int -get_tok(char **src, char *buf, int buflen, int sep) -{ - int len; - char *p; - - buf[0] = 0; - if ( **src == 0 ) { - return 0; - } - p = strchr(*src, sep); - if ( p==NULL ) { - len = (int)strlen(*src); - p = (*src) + len; - } else { - /*LINTED*/ - len = (int)(p - (*src)); - } - if ( (len+1) > buflen ) { - return 0; - } - (void)memcpy(buf, *src, len); - buf[len] = 0; - if ( *p != 0 && *p == sep ) { - (*src) = p+1; - } else { - (*src) = p; - } - return len; -} - -static jboolean -setBinarySwitch(char **src, jboolean *ptr) -{ - char buf[80]; - - if (!get_tok(src, buf, (int)sizeof(buf), ',')) { - return JNI_FALSE; - } - if (strcmp(buf, "y") == 0) { - *ptr = JNI_TRUE; - } else if (strcmp(buf, "n") == 0) { - *ptr = JNI_FALSE; - } else { - return JNI_FALSE; - } - return JNI_TRUE; -} - -static void -print_usage(void) -{ - - (void)fprintf(stdout, -"\n" -" HPROF: Heap and CPU Profiling Agent (JVMTI Demonstration Code)\n" -"\n" -AGENTNAME " usage: java " AGENTLIB "=[help]|[<option>=<value>, ...]\n" -"\n" -"Option Name and Value Description Default\n" -"--------------------- ----------- -------\n" -"heap=dump|sites|all heap profiling all\n" -"cpu=samples|times|old CPU usage off\n" -"monitor=y|n monitor contention n\n" -"format=a|b text(txt) or binary output a\n" -"file=<file> write data to file " DEFAULT_OUTPUTFILE "[{" DEFAULT_TXT_SUFFIX "}]\n" -"net=<host>:<port> send data over a socket off\n" -"depth=<size> stack trace depth " TO_STR(DEFAULT_TRACE_DEPTH) "\n" -"interval=<ms> sample interval in ms " TO_STR(DEFAULT_SAMPLE_INTERVAL) "\n" -"cutoff=<value> output cutoff point " TO_STR(DEFAULT_CUTOFF_POINT) "\n" -"lineno=y|n line number in traces? y\n" -"thread=y|n thread in traces? n\n" -"doe=y|n dump on exit? y\n" -"msa=y|n Solaris micro state accounting n\n" -"force=y|n force output to <file> y\n" -"verbose=y|n print messages about dumps y\n" -"\n" -"Obsolete Options\n" -"----------------\n" -"gc_okay=y|n\n" - -#ifdef DEBUG -"\n" -"DEBUG Option Description Default\n" -"------------ ----------- -------\n" -"primfields=y|n include primitive field values y\n" -"primarrays=y|n include primitive array values y\n" -"debugflags=MASK Various debug flags 0\n" -" 0x01 Report refs in and of unprepared classes\n" -"logflags=MASK Logging to stderr 0\n" -" " TO_STR(LOG_DUMP_MISC) " Misc logging\n" -" " TO_STR(LOG_DUMP_LISTS) " Dump out the tables\n" -" " TO_STR(LOG_CHECK_BINARY) " Verify & dump format=b\n" -"coredump=y|n Core dump on fatal n\n" -"errorexit=y|n Exit on any error n\n" -"pause=y|n Pause on onload & echo PID n\n" -"debug=y|n Turn on all debug checking n\n" -"X=MASK Internal use only 0\n" - -"\n" -"Environment Variables\n" -"---------------------\n" -"_JAVA_HPROF_OPTIONS\n" -" Options can be added externally via this environment variable.\n" -" Anything contained in it will get a comma prepended to it (if needed),\n" -" then it will be added to the end of the options supplied via the\n" -" " XRUN " or " AGENTLIB " command line option.\n" - -#endif - -"\n" -"Examples\n" -"--------\n" -" - Get sample cpu information every 20 millisec, with a stack depth of 3:\n" -" java " AGENTLIB "=cpu=samples,interval=20,depth=3 classname\n" -" - Get heap usage information based on the allocation sites:\n" -" java " AGENTLIB "=heap=sites classname\n" - -#ifdef DEBUG -" - Using the external option addition with csh, log details on all runs:\n" -" setenv _JAVA_HPROF_OPTIONS \"logflags=0xC\"\n" -" java " AGENTLIB "=cpu=samples classname\n" -" is the same as:\n" -" java " AGENTLIB "=cpu=samples,logflags=0xC classname\n" -#endif - -"\n" -"Notes\n" -"-----\n" -" - The option format=b cannot be used with monitor=y.\n" -" - The option format=b cannot be used with cpu=old|times.\n" -" - Use of the " XRUN " interface can still be used, e.g.\n" -" java " XRUN ":[help]|[<option>=<value>, ...]\n" -" will behave exactly the same as:\n" -" java " AGENTLIB "=[help]|[<option>=<value>, ...]\n" - -#ifdef DEBUG -" - The debug options and environment variables are available with both java\n" -" and java_g versions.\n" -#endif - -"\n" -"Warnings\n" -"--------\n" -" - This is demonstration code for the JVMTI interface and use of BCI,\n" -" it is not an official product or formal part of the JDK.\n" -" - The " XRUN " interface will be removed in a future release.\n" -" - The option format=b is considered experimental, this format may change\n" -" in a future release.\n" - -#ifdef DEBUG -" - The obsolete options may be completely removed in a future release.\n" -" - The debug options and environment variables are not considered public\n" -" interfaces and can change or be removed with any type of update of\n" -" " AGENTNAME ", including patches.\n" -#endif - - ); -} - -static void -option_error(char *description) -{ - char errmsg[FILENAME_MAX+80]; - - (void)md_snprintf(errmsg, sizeof(errmsg), - "%s option error: %s (%s)", AGENTNAME, description, gdata->options); - errmsg[sizeof(errmsg)-1] = 0; - HPROF_ERROR(JNI_FALSE, errmsg); - error_exit_process(1); -} - -static void -parse_options(char *command_line_options) -{ - int file_or_net_option_seen = JNI_FALSE; - char *all_options; - char *extra_options; - char *options; - char *default_filename; - int ulen; - - if (command_line_options == 0) - command_line_options = ""; - - if ((strcmp(command_line_options, "help")) == 0) { - print_usage(); - error_exit_process(0); - } - - extra_options = getenv("_JAVA_HPROF_OPTIONS"); - if ( extra_options == NULL ) { - extra_options = ""; - } - - all_options = HPROF_MALLOC((int)strlen(command_line_options) + - (int)strlen(extra_options) + 2); - gdata->options = all_options; - (void)strcpy(all_options, command_line_options); - if ( extra_options[0] != 0 ) { - if ( all_options[0] != 0 ) { - (void)strcat(all_options, ","); - } - (void)strcat(all_options, extra_options); - } - options = all_options; - - LOG2("parse_options()", all_options); - - while (*options) { - char option[16]; - char suboption[FILENAME_MAX+1]; - char *endptr; - - if (!get_tok(&options, option, (int)sizeof(option), '=')) { - option_error("general syntax error parsing options"); - } - if (strcmp(option, "file") == 0) { - if ( file_or_net_option_seen ) { - option_error("file or net options should only appear once"); - } - if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) { - option_error("syntax error parsing file=filename"); - } - gdata->utf8_output_filename = HPROF_MALLOC((int)strlen(suboption)+1); - (void)strcpy(gdata->utf8_output_filename, suboption); - file_or_net_option_seen = JNI_TRUE; - } else if (strcmp(option, "net") == 0) { - char port_number[16]; - if (file_or_net_option_seen ) { - option_error("file or net options should only appear once"); - } - if (!get_tok(&options, suboption, (int)sizeof(suboption), ':')) { - option_error("net option missing ':'"); - } - if (!get_tok(&options, port_number, (int)sizeof(port_number), ',')) { - option_error("net option missing port"); - } - gdata->net_hostname = HPROF_MALLOC((int)strlen(suboption)+1); - (void)strcpy(gdata->net_hostname, suboption); - gdata->net_port = (int)strtol(port_number, NULL, 10); - file_or_net_option_seen = JNI_TRUE; - } else if (strcmp(option, "format") == 0) { - if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) { - option_error("syntax error parsing format=a|b"); - } - if (strcmp(suboption, "a") == 0) { - gdata->output_format = 'a'; - } else if (strcmp(suboption, "b") == 0) { - gdata->output_format = 'b'; - } else { - option_error("format option value must be a|b"); - } - } else if (strcmp(option, "depth") == 0) { - if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) { - option_error("syntax error parsing depth=DECIMAL"); - } - gdata->max_trace_depth = (int)strtol(suboption, &endptr, 10); - if ((endptr != NULL && *endptr != 0) || gdata->max_trace_depth < 0) { - option_error("depth option value must be decimal and >= 0"); - } - gdata->prof_trace_depth = gdata->max_trace_depth; - } else if (strcmp(option, "interval") == 0) { - if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) { - option_error("syntax error parsing interval=DECIMAL"); - } - gdata->sample_interval = (int)strtol(suboption, &endptr, 10); - if ((endptr != NULL && *endptr != 0) || gdata->sample_interval <= 0) { - option_error("interval option value must be decimal and > 0"); - } - } else if (strcmp(option, "cutoff") == 0) { - if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) { - option_error("syntax error parsing cutoff=DOUBLE"); - } - gdata->cutoff_point = strtod(suboption, &endptr); - if ((endptr != NULL && *endptr != 0) || gdata->cutoff_point < 0) { - option_error("cutoff option value must be floating point and >= 0"); - } - } else if (strcmp(option, "cpu") == 0) { - if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) { - option_error("syntax error parsing cpu=y|samples|times|old"); - } - if ((strcmp(suboption, "samples") == 0) || - (strcmp(suboption, "y") == 0)) { - gdata->cpu_sampling = JNI_TRUE; - } else if (strcmp(suboption, "times") == 0) { - gdata->cpu_timing = JNI_TRUE; - gdata->old_timing_format = JNI_FALSE; - } else if (strcmp(suboption, "old") == 0) { - gdata->cpu_timing = JNI_TRUE; - gdata->old_timing_format = JNI_TRUE; - } else { - option_error("cpu option value must be y|samples|times|old"); - } - } else if (strcmp(option, "heap") == 0) { - if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) { - option_error("syntax error parsing heap=dump|sites|all"); - } - if (strcmp(suboption, "dump") == 0) { - gdata->heap_dump = JNI_TRUE; - } else if (strcmp(suboption, "sites") == 0) { - gdata->alloc_sites = JNI_TRUE; - } else if (strcmp(suboption, "all") == 0) { - gdata->heap_dump = JNI_TRUE; - gdata->alloc_sites = JNI_TRUE; - } else { - option_error("heap option value must be dump|sites|all"); - } - } else if( strcmp(option,"lineno") == 0) { - if ( !setBinarySwitch(&options, &(gdata->lineno_in_traces)) ) { - option_error("lineno option value must be y|n"); - } - } else if( strcmp(option,"thread") == 0) { - if ( !setBinarySwitch(&options, &(gdata->thread_in_traces)) ) { - option_error("thread option value must be y|n"); - } - } else if( strcmp(option,"doe") == 0) { - if ( !setBinarySwitch(&options, &(gdata->dump_on_exit)) ) { - option_error("doe option value must be y|n"); - } - } else if( strcmp(option,"msa") == 0) { - if ( !setBinarySwitch(&options, &(gdata->micro_state_accounting)) ) { - option_error("msa option value must be y|n"); - } - } else if( strcmp(option,"force") == 0) { - if ( !setBinarySwitch(&options, &(gdata->force_output)) ) { - option_error("force option value must be y|n"); - } - } else if( strcmp(option,"verbose") == 0) { - if ( !setBinarySwitch(&options, &(gdata->verbose)) ) { - option_error("verbose option value must be y|n"); - } - } else if( strcmp(option,"primfields") == 0) { - if ( !setBinarySwitch(&options, &(gdata->primfields)) ) { - option_error("primfields option value must be y|n"); - } - } else if( strcmp(option,"primarrays") == 0) { - if ( !setBinarySwitch(&options, &(gdata->primarrays)) ) { - option_error("primarrays option value must be y|n"); - } - } else if( strcmp(option,"monitor") == 0) { - if ( !setBinarySwitch(&options, &(gdata->monitor_tracing)) ) { - option_error("monitor option value must be y|n"); - } - } else if( strcmp(option,"gc_okay") == 0) { - if ( !setBinarySwitch(&options, &(gdata->gc_okay)) ) { - option_error("gc_okay option value must be y|n"); - } - } else if (strcmp(option, "logflags") == 0) { - if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) { - option_error("logflags option value must be numeric"); - } - gdata->logflags = (int)strtol(suboption, NULL, 0); - } else if (strcmp(option, "debugflags") == 0) { - if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) { - option_error("debugflags option value must be numeric"); - } - gdata->debugflags = (int)strtol(suboption, NULL, 0); - } else if (strcmp(option, "coredump") == 0) { - if ( !setBinarySwitch(&options, &(gdata->coredump)) ) { - option_error("coredump option value must be y|n"); - } - } else if (strcmp(option, "exitpause") == 0) { - option_error("The exitpause option was removed, use -XX:OnError='cmd %%p'"); - } else if (strcmp(option, "errorexit") == 0) { - if ( !setBinarySwitch(&options, &(gdata->errorexit)) ) { - option_error("errorexit option value must be y|n"); - } - } else if (strcmp(option, "pause") == 0) { - if ( !setBinarySwitch(&options, &(gdata->pause)) ) { - option_error("pause option value must be y|n"); - } - } else if (strcmp(option, "debug") == 0) { - if ( !setBinarySwitch(&options, &(gdata->debug)) ) { - option_error("debug option value must be y|n"); - } - } else if (strcmp(option, "precrash") == 0) { - option_error("The precrash option was removed, use -XX:OnError='precrash -p %%p'"); - } else if (strcmp(option, "X") == 0) { - if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) { - option_error("X option value must be numeric"); - } - gdata->experiment = (int)strtol(suboption, NULL, 0); - } else { - char errmsg[80]; - (void)strcpy(errmsg, "Unknown option: "); - (void)strcat(errmsg, option); - option_error(errmsg); - } - } - - if (gdata->output_format == 'b') { - if (gdata->cpu_timing) { - option_error("cpu=times|old is not supported with format=b"); - } - if (gdata->monitor_tracing) { - option_error("monitor=y is not supported with format=b"); - } - } - - if (gdata->old_timing_format) { - gdata->prof_trace_depth = 2; - } - - if (gdata->output_format == 'b') { - default_filename = DEFAULT_OUTPUTFILE; - } else { - default_filename = DEFAULT_OUTPUTFILE DEFAULT_TXT_SUFFIX; - } - - if (!file_or_net_option_seen) { - gdata->utf8_output_filename = HPROF_MALLOC((int)strlen(default_filename)+1); - (void)strcpy(gdata->utf8_output_filename, default_filename); - } - - if ( gdata->utf8_output_filename != NULL ) { - // Don't attempt to convert output filename. - // If fileystem uses the same encoding as the rest of the OS it will work as is. - ulen = (int)strlen(gdata->utf8_output_filename); - gdata->output_filename = (char*)HPROF_MALLOC(ulen*3+3); - (void)strcpy(gdata->output_filename, gdata->utf8_output_filename); - } - - /* By default we turn on gdata->alloc_sites and gdata->heap_dump */ - if ( !gdata->cpu_timing && - !gdata->cpu_sampling && - !gdata->monitor_tracing && - !gdata->alloc_sites && - !gdata->heap_dump) { - gdata->heap_dump = JNI_TRUE; - gdata->alloc_sites = JNI_TRUE; - } - - if ( gdata->alloc_sites || gdata->heap_dump ) { - gdata->obj_watch = JNI_TRUE; - } - if ( gdata->obj_watch || gdata->cpu_timing ) { - gdata->bci = JNI_TRUE; - } - - /* Create files & sockets needed */ - if (gdata->heap_dump) { - char *base; - int len; - - /* Get a fast tempfile for the heap information */ - base = gdata->output_filename; - if ( base==NULL ) { - base = default_filename; - } - len = (int)strlen(base); - gdata->heapfilename = HPROF_MALLOC(len + 5); - (void)strcpy(gdata->heapfilename, base); - (void)strcat(gdata->heapfilename, ".TMP"); - make_unique_filename(&(gdata->heapfilename)); - (void)remove(gdata->heapfilename); - if (gdata->output_format == 'b') { - if ( gdata->logflags & LOG_CHECK_BINARY ) { - char * check_suffix; - - check_suffix = ".check" DEFAULT_TXT_SUFFIX; - gdata->checkfilename = - HPROF_MALLOC((int)strlen(default_filename)+ - (int)strlen(check_suffix)+1); - (void)strcpy(gdata->checkfilename, default_filename); - (void)strcat(gdata->checkfilename, check_suffix); - (void)remove(gdata->checkfilename); - gdata->check_fd = md_creat(gdata->checkfilename); - } - if ( gdata->debug ) { - gdata->logflags |= LOG_CHECK_BINARY; - } - gdata->heap_fd = md_creat_binary(gdata->heapfilename); - } else { - gdata->heap_fd = md_creat(gdata->heapfilename); - } - if ( gdata->heap_fd < 0 ) { - char errmsg[FILENAME_MAX+80]; - - (void)md_snprintf(errmsg, sizeof(errmsg), - "can't create temp heap file: %s", gdata->heapfilename); - errmsg[sizeof(errmsg)-1] = 0; - HPROF_ERROR(JNI_TRUE, errmsg); - } - } - - if ( gdata->net_port > 0 ) { - LOG2("Agent_OnLoad", "Connecting to socket"); - gdata->fd = connect_to_socket(gdata->net_hostname, gdata->net_port); - if (gdata->fd <= 0) { - char errmsg[120]; - - (void)md_snprintf(errmsg, sizeof(errmsg), - "can't connect to %s:%u", gdata->net_hostname, gdata->net_port); - errmsg[sizeof(errmsg)-1] = 0; - HPROF_ERROR(JNI_FALSE, errmsg); - error_exit_process(1); - } - gdata->socket = JNI_TRUE; - } else { - /* If going out to a file, obey the force=y|n option */ - if ( !gdata->force_output ) { - make_unique_filename(&(gdata->output_filename)); - } - /* Make doubly sure this file does NOT exist */ - (void)remove(gdata->output_filename); - /* Create the file */ - if (gdata->output_format == 'b') { - gdata->fd = md_creat_binary(gdata->output_filename); - } else { - gdata->fd = md_creat(gdata->output_filename); - } - if (gdata->fd < 0) { - char errmsg[FILENAME_MAX+80]; - - (void)md_snprintf(errmsg, sizeof(errmsg), - "can't create profile file: %s", gdata->output_filename); - errmsg[sizeof(errmsg)-1] = 0; - HPROF_ERROR(JNI_FALSE, errmsg); - error_exit_process(1); - } - } - -} - -/* ------------------------------------------------------------------- */ -/* Data reset and dump functions */ - -static void -reset_all_data(void) -{ - if (gdata->cpu_sampling || gdata->cpu_timing || gdata->monitor_tracing) { - rawMonitorEnter(gdata->data_access_lock); - } - - if (gdata->cpu_sampling || gdata->cpu_timing) { - trace_clear_cost(); - } - if (gdata->monitor_tracing) { - monitor_clear(); - } - - if (gdata->cpu_sampling || gdata->cpu_timing || gdata->monitor_tracing) { - rawMonitorExit(gdata->data_access_lock); - } -} - -static void reset_class_load_status(JNIEnv *env, jthread thread); - -static void -dump_all_data(JNIEnv *env) -{ - verbose_message("Dumping"); - if (gdata->monitor_tracing) { - verbose_message(" contended monitor usage ..."); - tls_dump_monitor_state(env); - monitor_write_contended_time(env, gdata->cutoff_point); - } - if (gdata->heap_dump) { - verbose_message(" Java heap ..."); - /* Update the class table */ - reset_class_load_status(env, NULL); - site_heapdump(env); - } - if (gdata->alloc_sites) { - verbose_message(" allocation sites ..."); - site_write(env, 0, gdata->cutoff_point); - } - if (gdata->cpu_sampling) { - verbose_message(" CPU usage by sampling running threads ..."); - trace_output_cost(env, gdata->cutoff_point); - } - if (gdata->cpu_timing) { - if (!gdata->old_timing_format) { - verbose_message(" CPU usage by timing methods ..."); - trace_output_cost(env, gdata->cutoff_point); - } else { - verbose_message(" CPU usage in old prof format ..."); - trace_output_cost_in_prof_format(env); - } - } - reset_all_data(); - io_flush(); - verbose_message(" done.\n"); -} - -/* ------------------------------------------------------------------- */ -/* Dealing with class load and unload status */ - -static void -reset_class_load_status(JNIEnv *env, jthread thread) -{ - - WITH_LOCAL_REFS(env, 1) { - jint class_count; - jclass *classes; - jint i; - - /* Get all classes from JVMTI, make sure they are in the class table. */ - getLoadedClasses(&classes, &class_count); - - /* We don't know if the class list has changed really, so we - * guess by the class count changing. Don't want to do - * a bunch of work on classes when it's unnecessary. - * I assume that even though we have global references on the - * jclass object that the class is still considered unloaded. - * (e.g. GC of jclass isn't required for it to be included - * in the unloaded list, or not in the load list) - * [Note: Use of Weak references was a performance problem.] - */ - if ( class_count != gdata->class_count ) { - - rawMonitorEnter(gdata->data_access_lock); { - - /* Unmark the classes in the load list */ - class_all_status_remove(CLASS_IN_LOAD_LIST); - - /* Pretend like it was a class load event */ - for ( i = 0 ; i < class_count ; i++ ) { - jobject loader; - - loader = getClassLoader(classes[i]); - event_class_load(env, thread, classes[i], loader); - } - - /* Process the classes that have been unloaded */ - class_do_unloads(env); - - } rawMonitorExit(gdata->data_access_lock); - - } - - /* Free the space and save the count. */ - jvmtiDeallocate(classes); - gdata->class_count = class_count; - - } END_WITH_LOCAL_REFS; - -} - -/* A GC or Death event has happened, so do some cleanup */ -static void -object_free_cleanup(JNIEnv *env, jboolean force_class_table_reset) -{ - Stack *stack; - - /* Then we process the ObjectFreeStack */ - rawMonitorEnter(gdata->object_free_lock); { - stack = gdata->object_free_stack; - gdata->object_free_stack = NULL; /* Will trigger new stack */ - } rawMonitorExit(gdata->object_free_lock); - - /* Notice we just grabbed the stack of freed objects so - * any object free events will create a new stack. - */ - if ( stack != NULL ) { - int count; - int i; - - count = stack_depth(stack); - - /* If we saw something freed in this GC */ - if ( count > 0 ) { - - for ( i = 0 ; i < count ; i++ ) { - ObjectIndex object_index; - jlong tag; - - tag = *(jlong*)stack_element(stack,i); - object_index = tag_extract(tag); - - (void)object_free(object_index); - } - - /* We reset the class load status (only do this once) */ - reset_class_load_status(env, NULL); - force_class_table_reset = JNI_FALSE; - - } - - /* Just terminate this stack object */ - stack_term(stack); - } - - /* We reset the class load status if we haven't and need to */ - if ( force_class_table_reset ) { - reset_class_load_status(env, NULL); - } - -} - -/* Main function for thread that watches for GC finish events */ -static void JNICALL -gc_finish_watcher(jvmtiEnv *jvmti, JNIEnv *env, void *p) -{ - jboolean active; - - active = JNI_TRUE; - - /* Indicate the watcher thread is active */ - rawMonitorEnter(gdata->gc_finish_lock); { - gdata->gc_finish_active = JNI_TRUE; - } rawMonitorExit(gdata->gc_finish_lock); - - /* Loop while active */ - while ( active ) { - jboolean do_cleanup; - - do_cleanup = JNI_FALSE; - rawMonitorEnter(gdata->gc_finish_lock); { - /* Don't wait if VM_DEATH wants us to quit */ - if ( gdata->gc_finish_stop_request ) { - /* Time to terminate */ - active = JNI_FALSE; - } else { - /* Wait for notification to do cleanup, or terminate */ - rawMonitorWait(gdata->gc_finish_lock, 0); - /* After wait, check to see if VM_DEATH wants us to quit */ - if ( gdata->gc_finish_stop_request ) { - /* Time to terminate */ - active = JNI_FALSE; - } - } - if ( active && gdata->gc_finish > 0 ) { - /* Time to cleanup, reset count and prepare for cleanup */ - gdata->gc_finish = 0; - do_cleanup = JNI_TRUE; - } - } rawMonitorExit(gdata->gc_finish_lock); - - /* Do the cleanup if requested outside gc_finish_lock */ - if ( do_cleanup ) { - /* Free up all freed objects, don't force class table reset - * We cannot let the VM_DEATH complete while we are doing - * this cleanup. So if during this, VM_DEATH happens, - * the VM_DEATH callback should block waiting for this - * loop to terminate, and send a notification to the - * VM_DEATH thread. - */ - object_free_cleanup(env, JNI_FALSE); - - /* Cleanup the tls table where the Thread objects were GC'd */ - tls_garbage_collect(env); - } - - } - - /* Falling out means VM_DEATH is happening, we need to notify VM_DEATH - * that we are done doing the cleanup. VM_DEATH is waiting on this - * notify. - */ - rawMonitorEnter(gdata->gc_finish_lock); { - gdata->gc_finish_active = JNI_FALSE; - rawMonitorNotifyAll(gdata->gc_finish_lock); - } rawMonitorExit(gdata->gc_finish_lock); -} - -/* ------------------------------------------------------------------- */ -/* JVMTI Event callback functions */ - -static void -setup_event_mode(jboolean onload_set_only, jvmtiEventMode state) -{ - if ( onload_set_only ) { - setEventNotificationMode(state, - JVMTI_EVENT_VM_INIT, NULL); - setEventNotificationMode(state, - JVMTI_EVENT_VM_DEATH, NULL); - if (gdata->bci) { - setEventNotificationMode(state, - JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); - } - } else { - /* Enable all other JVMTI events of interest now. */ - setEventNotificationMode(state, - JVMTI_EVENT_THREAD_START, NULL); - setEventNotificationMode(state, - JVMTI_EVENT_THREAD_END, NULL); - setEventNotificationMode(state, - JVMTI_EVENT_CLASS_LOAD, NULL); - setEventNotificationMode(state, - JVMTI_EVENT_CLASS_PREPARE, NULL); - setEventNotificationMode(state, - JVMTI_EVENT_DATA_DUMP_REQUEST, NULL); - if (gdata->cpu_timing) { - setEventNotificationMode(state, - JVMTI_EVENT_EXCEPTION_CATCH, NULL); - } - if (gdata->monitor_tracing) { - setEventNotificationMode(state, - JVMTI_EVENT_MONITOR_WAIT, NULL); - setEventNotificationMode(state, - JVMTI_EVENT_MONITOR_WAITED, NULL); - setEventNotificationMode(state, - JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL); - setEventNotificationMode(state, - JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL); - } - if (gdata->obj_watch) { - setEventNotificationMode(state, - JVMTI_EVENT_OBJECT_FREE, NULL); - } - setEventNotificationMode(state, - JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL); - setEventNotificationMode(state, - JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL); - } -} - -/* JVMTI_EVENT_VM_INIT */ -static void JNICALL -cbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) -{ - rawMonitorEnter(gdata->data_access_lock); { - - LoaderIndex loader_index; - ClassIndex cnum; - TlsIndex tls_index; - - gdata->jvm_initializing = JNI_TRUE; - - /* Header to use in heap dumps */ - gdata->header = "JAVA PROFILE 1.0.1"; - gdata->segmented = JNI_FALSE; - if (gdata->output_format == 'b') { - /* We need JNI here to call in and get the current maximum memory */ - gdata->maxMemory = getMaxMemory(env); - gdata->maxHeapSegment = (jlong)2000000000; - /* More than 2Gig triggers segments and 1.0.2 */ - if ( gdata->maxMemory >= gdata->maxHeapSegment ) { - gdata->header = "JAVA PROFILE 1.0.2"; - gdata->segmented = JNI_TRUE; /* 1.0.2 */ - } - } - - /* We write the initial header after the VM initializes now - * because we needed to use JNI to get maxMemory and determine if - * a 1.0.1 or a 1.0.2 header will be used. - * This used to be done in Agent_OnLoad. - */ - io_write_file_header(); - - LOG("cbVMInit begin"); - - /* Create a system loader entry first */ - loader_index = loader_find_or_create(NULL,NULL); - - /* Find the thread jclass (does JNI calls) */ - gdata->thread_cnum = class_find_or_create("Ljava/lang/Thread;", - loader_index); - class_add_status(gdata->thread_cnum, CLASS_SYSTEM); - - /* Issue fake system thread start */ - tls_index = tls_find_or_create(env, thread); - - /* Setup the Tracker class (should be first class in table) */ - tracker_setup_class(); - - /* Find selected system classes to keep track of */ - gdata->system_class_size = 0; - cnum = class_find_or_create("Ljava/lang/Object;", loader_index); - - gdata->system_trace_index = tls_get_trace(tls_index, env, - gdata->max_trace_depth, JNI_FALSE); - gdata->system_object_site_index = site_find_or_create( - cnum, gdata->system_trace_index); - - /* Used to ID HPROF generated items */ - gdata->hprof_trace_index = tls_get_trace(tls_index, env, - gdata->max_trace_depth, JNI_FALSE); - gdata->hprof_site_index = site_find_or_create( - cnum, gdata->hprof_trace_index); - - if ( gdata->logflags & LOG_DUMP_LISTS ) { - list_all_tables(); - } - - /* Prime the class table */ - reset_class_load_status(env, thread); - - /* Find the tracker jclass and jmethodID's (does JNI calls) */ - if ( gdata->bci ) { - tracker_setup_methods(env); - } - - /* Start any agent threads (does JNI, JVMTI, and Java calls) */ - - /* Thread to watch for gc_finish events */ - rawMonitorEnter(gdata->gc_finish_lock); { - createAgentThread(env, "HPROF gc_finish watcher", - &gc_finish_watcher); - } rawMonitorExit(gdata->gc_finish_lock); - - /* Start up listener thread if we need it */ - if ( gdata->socket ) { - listener_init(env); - } - - /* Start up cpu sampling thread if we need it */ - if ( gdata->cpu_sampling ) { - /* Note: this could also get started later (see cpu) */ - cpu_sample_init(env); - } - - /* Setup event modes */ - setup_event_mode(JNI_FALSE, JVMTI_ENABLE); - - /* Engage tracking (sets Java Tracker field so injections call into - * agent library). - */ - if ( gdata->bci ) { - tracker_engage(env); - } - - /* Indicate the VM is initialized now */ - gdata->jvm_initialized = JNI_TRUE; - gdata->jvm_initializing = JNI_FALSE; - - LOG("cbVMInit end"); - - } rawMonitorExit(gdata->data_access_lock); -} - -/* JVMTI_EVENT_VM_DEATH */ -static void JNICALL -cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env) -{ - /* - * Use local flag to minimize gdata->dump_lock hold time. - */ - jboolean need_to_dump = JNI_FALSE; - - LOG("cbVMDeath"); - - /* Shutdown thread watching gc_finish, outside CALLBACK locks. - * We need to make sure the watcher thread is done doing any cleanup - * work before we continue here. - */ - rawMonitorEnter(gdata->gc_finish_lock); { - /* Notify watcher thread to finish up, it will send - * another notify when done. If the watcher thread is busy - * cleaning up, it will detect gc_finish_stop_request when it's done. - * Then it sets gc_finish_active to JNI_FALSE and will notify us. - * If the watcher thread is waiting to be notified, then the - * notification wakes it up. - * We do not want to do the VM_DEATH while the gc_finish - * watcher thread is in the middle of a cleanup. - */ - gdata->gc_finish_stop_request = JNI_TRUE; - rawMonitorNotifyAll(gdata->gc_finish_lock); - /* Wait for the gc_finish watcher thread to notify us it's done */ - while ( gdata->gc_finish_active ) { - rawMonitorWait(gdata->gc_finish_lock,0); - } - } rawMonitorExit(gdata->gc_finish_lock); - - /* The gc_finish watcher thread should be done now, or done shortly. */ - - - /* BEGIN_CALLBACK/END_CALLBACK handling. */ - - /* The callbackBlock prevents any active callbacks from returning - * back to the VM, and also blocks all new callbacks. - * We want to prevent any threads from premature death, so - * that we don't have worry about that during thread queries - * in this final dump process. - */ - rawMonitorEnter(gdata->callbackBlock); { - - /* We need to wait for all callbacks actively executing to block - * on exit, and new ones will block on entry. - * The BEGIN_CALLBACK/END_CALLBACK macros keep track of callbacks - * that are active. - * Once the last active callback is done, it will notify this - * thread and block. - */ - - rawMonitorEnter(gdata->callbackLock); { - /* Turn off native calls */ - if ( gdata->bci ) { - tracker_disengage(env); - } - gdata->vm_death_callback_active = JNI_TRUE; - while (gdata->active_callbacks > 0) { - rawMonitorWait(gdata->callbackLock, 0); - } - } rawMonitorExit(gdata->callbackLock); - - /* Now we know that no threads will die on us, being blocked - * on some event callback, at a minimum ThreadEnd. - */ - - /* Make some basic checks. */ - rawMonitorEnter(gdata->data_access_lock); { - if ( gdata->jvm_initializing ) { - HPROF_ERROR(JNI_TRUE, "VM Death during VM Init"); - return; - } - if ( !gdata->jvm_initialized ) { - HPROF_ERROR(JNI_TRUE, "VM Death before VM Init"); - return; - } - if (gdata->jvm_shut_down) { - HPROF_ERROR(JNI_TRUE, "VM Death more than once?"); - return; - } - } rawMonitorExit(gdata->data_access_lock); - - /* Shutdown the cpu loop thread */ - if ( gdata->cpu_sampling ) { - cpu_sample_term(env); - } - - /* Time to dump the final data */ - rawMonitorEnter(gdata->dump_lock); { - - gdata->jvm_shut_down = JNI_TRUE; - - if (!gdata->dump_in_process) { - need_to_dump = JNI_TRUE; - gdata->dump_in_process = JNI_TRUE; - /* - * Setting gdata->dump_in_process will cause cpu sampling to pause - * (if we are sampling). We don't resume sampling after the - * dump_all_data() call below because the VM is shutting - * down. - */ - } - - } rawMonitorExit(gdata->dump_lock); - - /* Dump everything if we need to */ - if (gdata->dump_on_exit && need_to_dump) { - - dump_all_data(env); - } - - /* Disable all events and callbacks now, all of them. - * NOTE: It's important that this be done after the dump - * it prevents other threads from messing up the data - * because they will block on ThreadStart and ThreadEnd - * events due to the CALLBACK block. - */ - set_callbacks(JNI_FALSE); - setup_event_mode(JNI_FALSE, JVMTI_DISABLE); - setup_event_mode(JNI_TRUE, JVMTI_DISABLE); - - /* Write tail of file */ - io_write_file_footer(); - - } rawMonitorExit(gdata->callbackBlock); - - /* Shutdown the listener thread and socket, or flush I/O buffers */ - if (gdata->socket) { - listener_term(env); - } else { - io_flush(); - } - - /* Close the file descriptors down */ - if ( gdata->fd >= 0 ) { - (void)md_close(gdata->fd); - gdata->fd = -1; - if ( gdata->logflags & LOG_CHECK_BINARY ) { - if (gdata->output_format == 'b' && gdata->output_filename != NULL) { - check_binary_file(gdata->output_filename); - } - } - } - if ( gdata->heap_fd >= 0 ) { - (void)md_close(gdata->heap_fd); - gdata->heap_fd = -1; - } - - if ( gdata->check_fd >= 0 ) { - (void)md_close(gdata->check_fd); - gdata->check_fd = -1; - } - - /* Remove the temporary heap file */ - if (gdata->heap_dump) { - (void)remove(gdata->heapfilename); - } - - /* If logging, dump the tables */ - if ( gdata->logflags & LOG_DUMP_LISTS ) { - list_all_tables(); - } - - /* Make sure all global references are deleted */ - class_delete_global_references(env); - loader_delete_global_references(env); - tls_delete_global_references(env); - -} - -/* JVMTI_EVENT_THREAD_START */ -static void JNICALL -cbThreadStart(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) -{ - LOG3("cbThreadStart", "thread is", (int)(long)(ptrdiff_t)thread); - - BEGIN_CALLBACK() { - event_thread_start(env, thread); - } END_CALLBACK(); -} - -/* JVMTI_EVENT_THREAD_END */ -static void JNICALL -cbThreadEnd(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) -{ - LOG3("cbThreadEnd", "thread is", (int)(long)(ptrdiff_t)thread); - - BEGIN_CALLBACK() { - event_thread_end(env, thread); - } END_CALLBACK(); -} - -/* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */ -static void JNICALL -cbClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv* env, - jclass class_being_redefined, jobject loader, - const char* name, jobject protection_domain, - jint class_data_len, const unsigned char* class_data, - jint* new_class_data_len, unsigned char** new_class_data) -{ - - /* WARNING: This will be called before VM_INIT. */ - - LOG2("cbClassFileLoadHook:",(name==NULL?"Unknown":name)); - - if (!gdata->bci) { - return; - } - - BEGIN_CALLBACK() { - rawMonitorEnter(gdata->data_access_lock); { - const char *classname; - - if ( gdata->bci_counter == 0 ) { - /* Prime the system classes */ - class_prime_system_classes(); - } - - gdata->bci_counter++; - - *new_class_data_len = 0; - *new_class_data = NULL; - - /* Name could be NULL */ - if ( name == NULL ) { - classname = ((JavaCrwDemoClassname) - (gdata->java_crw_demo_classname_function)) - (class_data, class_data_len, &my_crw_fatal_error_handler); - if ( classname == NULL ) { - HPROF_ERROR(JNI_TRUE, "No classname in classfile"); - } - } else { - classname = strdup(name); - if ( classname == NULL ) { - HPROF_ERROR(JNI_TRUE, "Ran out of malloc() space"); - } - } - - /* The tracker class itself? */ - if ( strcmp(classname, TRACKER_CLASS_NAME) != 0 ) { - ClassIndex cnum; - int system_class; - unsigned char * new_image; - long new_length; - int len; - char *signature; - LoaderIndex loader_index; - - LOG2("cbClassFileLoadHook injecting class" , classname); - - /* Define a unique class number for this class */ - len = (int)strlen(classname); - signature = HPROF_MALLOC(len+3); - signature[0] = JVM_SIGNATURE_CLASS; - (void)memcpy(signature+1, classname, len); - signature[len+1] = JVM_SIGNATURE_ENDCLASS; - signature[len+2] = 0; - loader_index = loader_find_or_create(env,loader); - if ( class_being_redefined != NULL ) { - cnum = class_find_or_create(signature, loader_index); - } else { - cnum = class_create(signature, loader_index); - } - HPROF_FREE(signature); - signature = NULL; - - /* Make sure class doesn't get unloaded by accident */ - class_add_status(cnum, CLASS_IN_LOAD_LIST); - - /* Is it a system class? */ - system_class = 0; - if ( (!gdata->jvm_initialized) - && (!gdata->jvm_initializing) - && ( ( class_get_status(cnum) & CLASS_SYSTEM) != 0 - || gdata->bci_counter < 8 ) ) { - system_class = 1; - LOG2(classname, " is a system class"); - } - - new_image = NULL; - new_length = 0; - - /* Call the class file reader/write demo code */ - ((JavaCrwDemo)(gdata->java_crw_demo_function))( - cnum, - classname, - class_data, - class_data_len, - system_class, - TRACKER_CLASS_NAME, - TRACKER_CLASS_SIG, - (gdata->cpu_timing)?TRACKER_CALL_NAME:NULL, - (gdata->cpu_timing)?TRACKER_CALL_SIG:NULL, - (gdata->cpu_timing)?TRACKER_RETURN_NAME:NULL, - (gdata->cpu_timing)?TRACKER_RETURN_SIG:NULL, - (gdata->obj_watch)?TRACKER_OBJECT_INIT_NAME:NULL, - (gdata->obj_watch)?TRACKER_OBJECT_INIT_SIG:NULL, - (gdata->obj_watch)?TRACKER_NEWARRAY_NAME:NULL, - (gdata->obj_watch)?TRACKER_NEWARRAY_SIG:NULL, - &new_image, - &new_length, - &my_crw_fatal_error_handler, - &class_set_methods); - - if ( new_length > 0 ) { - unsigned char *jvmti_space; - - LOG2("cbClassFileLoadHook DID inject this class", classname); - jvmti_space = (unsigned char *)jvmtiAllocate((jint)new_length); - (void)memcpy((void*)jvmti_space, (void*)new_image, (int)new_length); - *new_class_data_len = (jint)new_length; - *new_class_data = jvmti_space; /* VM will deallocate */ - } else { - LOG2("cbClassFileLoadHook DID NOT inject this class", classname); - *new_class_data_len = 0; - *new_class_data = NULL; - } - if ( new_image != NULL ) { - (void)free((void*)new_image); /* Free malloc() space with free() */ - } - } - (void)free((void*)classname); - } rawMonitorExit(gdata->data_access_lock); - } END_CALLBACK(); -} - -/* JVMTI_EVENT_CLASS_LOAD */ -static void JNICALL -cbClassLoad(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) -{ - - /* WARNING: This MAY be called before VM_INIT. */ - - LOG("cbClassLoad"); - - BEGIN_CALLBACK() { - rawMonitorEnter(gdata->data_access_lock); { - - WITH_LOCAL_REFS(env, 1) { - jobject loader; - - loader = getClassLoader(klass); - event_class_load(env, thread, klass, loader); - } END_WITH_LOCAL_REFS; - - } rawMonitorExit(gdata->data_access_lock); - } END_CALLBACK(); -} - -/* JVMTI_EVENT_CLASS_PREPARE */ -static void JNICALL -cbClassPrepare(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) -{ - - /* WARNING: This will be called before VM_INIT. */ - - LOG("cbClassPrepare"); - - BEGIN_CALLBACK() { - rawMonitorEnter(gdata->data_access_lock); { - - WITH_LOCAL_REFS(env, 1) { - jobject loader; - - loader = NULL; - loader = getClassLoader(klass); - event_class_prepare(env, thread, klass, loader); - } END_WITH_LOCAL_REFS; - - } rawMonitorExit(gdata->data_access_lock); - } END_CALLBACK(); - -} - -/* JVMTI_EVENT_DATA_DUMP_REQUEST */ -static void JNICALL -cbDataDumpRequest(jvmtiEnv *jvmti) -{ - jboolean need_to_dump; - - LOG("cbDataDumpRequest"); - - BEGIN_CALLBACK() { - need_to_dump = JNI_FALSE; - rawMonitorEnter(gdata->dump_lock); { - if (!gdata->dump_in_process) { - need_to_dump = JNI_TRUE; - gdata->dump_in_process = JNI_TRUE; - } - } rawMonitorExit(gdata->dump_lock); - - if (need_to_dump) { - dump_all_data(getEnv()); - - rawMonitorEnter(gdata->dump_lock); { - gdata->dump_in_process = JNI_FALSE; - } rawMonitorExit(gdata->dump_lock); - - if (gdata->cpu_sampling && !gdata->jvm_shut_down) { - cpu_sample_on(NULL, 0); /* resume sampling */ - } - } - } END_CALLBACK(); - -} - -/* JVMTI_EVENT_EXCEPTION_CATCH */ -static void JNICALL -cbExceptionCatch(jvmtiEnv *jvmti, JNIEnv* env, - jthread thread, jmethodID method, jlocation location, - jobject exception) -{ - LOG("cbExceptionCatch"); - - BEGIN_CALLBACK() { - event_exception_catch(env, thread, method, location, exception); - } END_CALLBACK(); -} - -/* JVMTI_EVENT_MONITOR_WAIT */ -static void JNICALL -cbMonitorWait(jvmtiEnv *jvmti, JNIEnv* env, - jthread thread, jobject object, jlong timeout) -{ - LOG("cbMonitorWait"); - - BEGIN_CALLBACK() { - monitor_wait_event(env, thread, object, timeout); - } END_CALLBACK(); -} - -/* JVMTI_EVENT_MONITOR_WAITED */ -static void JNICALL -cbMonitorWaited(jvmtiEnv *jvmti, JNIEnv* env, - jthread thread, jobject object, jboolean timed_out) -{ - LOG("cbMonitorWaited"); - - BEGIN_CALLBACK() { - monitor_waited_event(env, thread, object, timed_out); - } END_CALLBACK(); -} - -/* JVMTI_EVENT_MONITOR_CONTENDED_ENTER */ -static void JNICALL -cbMonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv* env, - jthread thread, jobject object) -{ - LOG("cbMonitorContendedEnter"); - - BEGIN_CALLBACK() { - monitor_contended_enter_event(env, thread, object); - } END_CALLBACK(); -} - -/* JVMTI_EVENT_MONITOR_CONTENDED_ENTERED */ -static void JNICALL -cbMonitorContendedEntered(jvmtiEnv *jvmti, JNIEnv* env, - jthread thread, jobject object) -{ - LOG("cbMonitorContendedEntered"); - - BEGIN_CALLBACK() { - monitor_contended_entered_event(env, thread, object); - } END_CALLBACK(); -} - -/* JVMTI_EVENT_GARBAGE_COLLECTION_START */ -static void JNICALL -cbGarbageCollectionStart(jvmtiEnv *jvmti) -{ - LOG("cbGarbageCollectionStart"); - - /* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit - * are allowed here (see the JVMTI Spec). - */ - - gdata->gc_start_time = md_get_timemillis(); -} - -/* JVMTI_EVENT_GARBAGE_COLLECTION_FINISH */ -static void JNICALL -cbGarbageCollectionFinish(jvmtiEnv *jvmti) -{ - LOG("cbGarbageCollectionFinish"); - - /* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit - * are allowed here (see the JVMTI Spec). - */ - - if ( gdata->gc_start_time != -1L ) { - gdata->time_in_gc += (md_get_timemillis() - gdata->gc_start_time); - gdata->gc_start_time = -1L; - } - - /* Increment gc_finish counter, notify watcher thread */ - rawMonitorEnter(gdata->gc_finish_lock); { - /* If VM_DEATH is trying to shut it down, don't do anything at all. - * Never send notify if VM_DEATH wants the watcher thread to quit. - */ - if ( gdata->gc_finish_active ) { - gdata->gc_finish++; - rawMonitorNotifyAll(gdata->gc_finish_lock); - } - } rawMonitorExit(gdata->gc_finish_lock); -} - -/* JVMTI_EVENT_OBJECT_FREE */ -static void JNICALL -cbObjectFree(jvmtiEnv *jvmti, jlong tag) -{ - LOG3("cbObjectFree", "tag", (int)tag); - - /* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit - * are allowed here (see the JVMTI Spec). - */ - - HPROF_ASSERT(tag!=(jlong)0); - rawMonitorEnter(gdata->object_free_lock); { - if ( !gdata->jvm_shut_down ) { - Stack *stack; - - stack = gdata->object_free_stack; - if ( stack == NULL ) { - gdata->object_free_stack = stack_init(512, 512, sizeof(jlong)); - stack = gdata->object_free_stack; - } - stack_push(stack, (void*)&tag); - } - } rawMonitorExit(gdata->object_free_lock); -} - -static void -set_callbacks(jboolean on) -{ - jvmtiEventCallbacks callbacks; - - (void)memset(&callbacks,0,sizeof(callbacks)); - if ( ! on ) { - setEventCallbacks(&callbacks); - return; - } - - /* JVMTI_EVENT_VM_INIT */ - callbacks.VMInit = &cbVMInit; - /* JVMTI_EVENT_VM_DEATH */ - callbacks.VMDeath = &cbVMDeath; - /* JVMTI_EVENT_THREAD_START */ - callbacks.ThreadStart = &cbThreadStart; - /* JVMTI_EVENT_THREAD_END */ - callbacks.ThreadEnd = &cbThreadEnd; - /* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */ - callbacks.ClassFileLoadHook = &cbClassFileLoadHook; - /* JVMTI_EVENT_CLASS_LOAD */ - callbacks.ClassLoad = &cbClassLoad; - /* JVMTI_EVENT_CLASS_PREPARE */ - callbacks.ClassPrepare = &cbClassPrepare; - /* JVMTI_EVENT_DATA_DUMP_REQUEST */ - callbacks.DataDumpRequest = &cbDataDumpRequest; - /* JVMTI_EVENT_EXCEPTION_CATCH */ - callbacks.ExceptionCatch = &cbExceptionCatch; - /* JVMTI_EVENT_MONITOR_WAIT */ - callbacks.MonitorWait = &cbMonitorWait; - /* JVMTI_EVENT_MONITOR_WAITED */ - callbacks.MonitorWaited = &cbMonitorWaited; - /* JVMTI_EVENT_MONITOR_CONTENDED_ENTER */ - callbacks.MonitorContendedEnter = &cbMonitorContendedEnter; - /* JVMTI_EVENT_MONITOR_CONTENDED_ENTERED */ - callbacks.MonitorContendedEntered = &cbMonitorContendedEntered; - /* JVMTI_EVENT_GARBAGE_COLLECTION_START */ - callbacks.GarbageCollectionStart = &cbGarbageCollectionStart; - /* JVMTI_EVENT_GARBAGE_COLLECTION_FINISH */ - callbacks.GarbageCollectionFinish = &cbGarbageCollectionFinish; - /* JVMTI_EVENT_OBJECT_FREE */ - callbacks.ObjectFree = &cbObjectFree; - - setEventCallbacks(&callbacks); - -} - -static void -getCapabilities(void) -{ - jvmtiCapabilities needed_capabilities; - jvmtiCapabilities potential_capabilities; - - /* Fill in ones that we must have */ - (void)memset(&needed_capabilities,0,sizeof(needed_capabilities)); - needed_capabilities.can_generate_garbage_collection_events = 1; - needed_capabilities.can_tag_objects = 1; - if (gdata->bci) { - needed_capabilities.can_generate_all_class_hook_events = 1; - } - if (gdata->obj_watch) { - needed_capabilities.can_generate_object_free_events = 1; - } - if (gdata->cpu_timing || gdata->cpu_sampling) { - #if 0 /* Not needed until we call JVMTI for CpuTime */ - needed_capabilities.can_get_thread_cpu_time = 1; - needed_capabilities.can_get_current_thread_cpu_time = 1; - #endif - needed_capabilities.can_generate_exception_events = 1; - } - if (gdata->monitor_tracing) { - #if 0 /* Not needed until we call JVMTI for CpuTime */ - needed_capabilities.can_get_thread_cpu_time = 1; - needed_capabilities.can_get_current_thread_cpu_time = 1; - #endif - needed_capabilities.can_get_owned_monitor_info = 1; - needed_capabilities.can_get_current_contended_monitor = 1; - needed_capabilities.can_get_monitor_info = 1; - needed_capabilities.can_generate_monitor_events = 1; - } - - /* Get potential capabilities */ - getPotentialCapabilities(&potential_capabilities); - - /* Some capabilities would be nicer to have */ - needed_capabilities.can_get_source_file_name = - potential_capabilities.can_get_source_file_name; - needed_capabilities.can_get_line_numbers = - potential_capabilities.can_get_line_numbers; - - /* Add the capabilities */ - addCapabilities(&needed_capabilities); - -} - -/* Dynamic library loading */ -static void * -load_library(char *name) -{ - char lname[FILENAME_MAX+1]; - char err_buf[256+FILENAME_MAX+1]; - char *boot_path; - void *handle; - - handle = NULL; - - /* The library may be located in different ways, try both, but - * if it comes from outside the SDK/jre it isn't ours. - */ - getSystemProperty("sun.boot.library.path", &boot_path); - md_build_library_name(lname, FILENAME_MAX, boot_path, name); - if ( strlen(lname) == 0 ) { - HPROF_ERROR(JNI_TRUE, "Could not find library"); - } - jvmtiDeallocate(boot_path); - handle = md_load_library(lname, err_buf, (int)sizeof(err_buf)); - if ( handle == NULL ) { - /* This may be necessary on Windows. */ - md_build_library_name(lname, FILENAME_MAX, "", name); - if ( strlen(lname) == 0 ) { - HPROF_ERROR(JNI_TRUE, "Could not find library"); - } - handle = md_load_library(lname, err_buf, (int)sizeof(err_buf)); - if ( handle == NULL ) { - HPROF_ERROR(JNI_TRUE, err_buf); - } - } - return handle; -} - -/* Lookup dynamic function pointer in shared library */ -static void * -lookup_library_symbol(void *library, char **symbols, int nsymbols) -{ - void *addr; - int i; - - addr = NULL; - for( i = 0 ; i < nsymbols; i++ ) { - addr = md_find_library_entry(library, symbols[i]); - if ( addr != NULL ) { - break; - } - } - if ( addr == NULL ) { - char errmsg[256]; - - (void)md_snprintf(errmsg, sizeof(errmsg), - "Cannot find library symbol '%s'", symbols[0]); - HPROF_ERROR(JNI_TRUE, errmsg); - } - return addr; -} - -/* ------------------------------------------------------------------- */ -/* The OnLoad interface */ - -JNIEXPORT jint JNICALL -Agent_OnLoad(JavaVM *vm, char *options, void *reserved) -{ - char *boot_path = NULL; - - /* See if it's already loaded */ - if ( gdata!=NULL && gdata->isLoaded==JNI_TRUE ) { - HPROF_ERROR(JNI_TRUE, "Cannot load this JVM TI agent twice, check your java command line for duplicate hprof options."); - return JNI_ERR; - } - - gdata = get_gdata(); - - gdata->isLoaded = JNI_TRUE; - - error_setup(); - - LOG2("Agent_OnLoad", "gdata setup"); - - gdata->jvm = vm; - - /* Get the JVMTI environment */ - getJvmti(); - - /* Lock needed to protect debug_malloc() code, which is not MT safe */ - #ifdef DEBUG - gdata->debug_malloc_lock = createRawMonitor("HPROF debug_malloc lock"); - #endif - - parse_options(options); - - LOG2("Agent_OnLoad", "Has jvmtiEnv and options parsed"); - - /* Initialize machine dependent code (micro state accounting) */ - md_init(); - - string_init(); /* Table index values look like: 0x10000000 */ - - class_init(); /* Table index values look like: 0x20000000 */ - tls_init(); /* Table index values look like: 0x30000000 */ - trace_init(); /* Table index values look like: 0x40000000 */ - object_init(); /* Table index values look like: 0x50000000 */ - - site_init(); /* Table index values look like: 0x60000000 */ - frame_init(); /* Table index values look like: 0x70000000 */ - monitor_init(); /* Table index values look like: 0x80000000 */ - loader_init(); /* Table index values look like: 0x90000000 */ - - LOG2("Agent_OnLoad", "Tables initialized"); - - if ( gdata->pause ) { - error_do_pause(); - } - - getCapabilities(); - - /* Set the JVMTI callback functions (do this only once)*/ - set_callbacks(JNI_TRUE); - - /* Create basic locks */ - gdata->dump_lock = createRawMonitor("HPROF dump lock"); - gdata->data_access_lock = createRawMonitor("HPROF data access lock"); - gdata->callbackLock = createRawMonitor("HPROF callback lock"); - gdata->callbackBlock = createRawMonitor("HPROF callback block"); - gdata->object_free_lock = createRawMonitor("HPROF object free lock"); - gdata->gc_finish_lock = createRawMonitor("HPROF gc_finish lock"); - - /* Set Onload events mode. */ - setup_event_mode(JNI_TRUE, JVMTI_ENABLE); - - LOG2("Agent_OnLoad", "JVMTI capabilities, callbacks and initial notifications setup"); - - /* Used in VM_DEATH to wait for callbacks to complete */ - gdata->jvm_initializing = JNI_FALSE; - gdata->jvm_initialized = JNI_FALSE; - gdata->vm_death_callback_active = JNI_FALSE; - gdata->active_callbacks = 0; - - /* Write the header information */ - io_setup(); - - /* We sample the start time now so that the time increments can be - * placed in the various heap dump segments in micro seconds. - */ - gdata->micro_sec_ticks = md_get_microsecs(); - - /* Load java_crw_demo library and find function "java_crw_demo" */ - if ( gdata->bci ) { - - /* Load the library or get the handle to it */ - gdata->java_crw_demo_library = load_library("java_crw_demo"); - - { /* "java_crw_demo" */ - static char *symbols[] = JAVA_CRW_DEMO_SYMBOLS; - gdata->java_crw_demo_function = - lookup_library_symbol(gdata->java_crw_demo_library, - symbols, (int)(sizeof(symbols)/sizeof(char*))); - } - { /* "java_crw_demo_classname" */ - static char *symbols[] = JAVA_CRW_DEMO_CLASSNAME_SYMBOLS; - gdata->java_crw_demo_classname_function = - lookup_library_symbol(gdata->java_crw_demo_library, - symbols, (int)(sizeof(symbols)/sizeof(char*))); - } - } - - return JNI_OK; -} - -JNIEXPORT void JNICALL -Agent_OnUnload(JavaVM *vm) -{ - Stack *stack; - - LOG("Agent_OnUnload"); - - gdata->isLoaded = JNI_FALSE; - - stack = gdata->object_free_stack; - gdata->object_free_stack = NULL; - if ( stack != NULL ) { - stack_term(stack); - } - - io_cleanup(); - loader_cleanup(); - tls_cleanup(); - monitor_cleanup(); - trace_cleanup(); - site_cleanup(); - object_cleanup(); - frame_cleanup(); - class_cleanup(); - string_cleanup(); - - /* Deallocate any memory in gdata */ - if ( gdata->net_hostname != NULL ) { - HPROF_FREE(gdata->net_hostname); - } - if ( gdata->utf8_output_filename != NULL ) { - HPROF_FREE(gdata->utf8_output_filename); - } - if ( gdata->output_filename != NULL ) { - HPROF_FREE(gdata->output_filename); - } - if ( gdata->heapfilename != NULL ) { - HPROF_FREE(gdata->heapfilename); - } - if ( gdata->checkfilename != NULL ) { - HPROF_FREE(gdata->checkfilename); - } - if ( gdata->options != NULL ) { - HPROF_FREE(gdata->options); - } - - /* Verify all allocated memory has been taken care of. */ - malloc_police(); - - /* Cleanup is hard to do when other threads might still be running - * so we skip destroying some raw monitors which still might be in use - * and we skip disposal of the jvmtiEnv* which might still be needed. - * Only raw monitors that could be held by other threads are left - * alone. So we explicitly do NOT do this: - * destroyRawMonitor(gdata->callbackLock); - * destroyRawMonitor(gdata->callbackBlock); - * destroyRawMonitor(gdata->gc_finish_lock); - * destroyRawMonitor(gdata->object_free_lock); - * destroyRawMonitor(gdata->listener_loop_lock); - * destroyRawMonitor(gdata->cpu_loop_lock); - * disposeEnvironment(); - * gdata->jvmti = NULL; - */ - - /* Destroy basic locks */ - destroyRawMonitor(gdata->dump_lock); - gdata->dump_lock = NULL; - destroyRawMonitor(gdata->data_access_lock); - gdata->data_access_lock = NULL; - if ( gdata->cpu_sample_lock != NULL ) { - destroyRawMonitor(gdata->cpu_sample_lock); - gdata->cpu_sample_lock = NULL; - } - #ifdef DEBUG - destroyRawMonitor(gdata->debug_malloc_lock); - gdata->debug_malloc_lock = NULL; - #endif - - /* Unload java_crw_demo library */ - if ( gdata->bci && gdata->java_crw_demo_library != NULL ) { - md_unload_library(gdata->java_crw_demo_library); - gdata->java_crw_demo_library = NULL; - } - - /* You would think you could clear out gdata and set it to NULL, but - * turns out that isn't a good idea. Some of the threads could be - * blocked inside the CALLBACK*() macros, where they got blocked up - * waiting for the VM_DEATH callback to complete. They only have - * some raw monitor actions to do, but they need access to gdata to do it. - * So do not do this: - * (void)memset(gdata, 0, sizeof(GlobalData)); - * gdata = NULL; - */ -}
--- a/jdk/src/demo/share/jvmti/hprof/hprof_init.h Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -#ifndef HPROF_INIT_H -#define HPROF_INIT_H - -JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved); -JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm); - -#endif
--- a/jdk/src/demo/share/jvmti/hprof/hprof_io.c Mon Aug 25 09:20:49 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1980 +0,0 @@ -/* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -/* All I/O functionality for hprof. */ - -/* - * The hprof agent has many forms of output: - * - * format=b gdata->output_format=='b' - * Binary format. Defined below. This is used by HAT. - * This is NOT the same format as emitted by JVMPI. - * - * format=a gdata->output_format=='a' - * Ascii format. Not exactly an ascii representation of the binary format. - * - * And many forms of dumps: - * - * heap=dump - * A large dump that in this implementation is written to a separate - * file first before being placed in the output file. Several reasons, - * the binary form needs a byte count of the length in the header, and - * references in this dump to other items need to be emitted first. - * So it's two pass, or use a temp file and copy. - * heap=sites - * Dumps the sites in the order of most allocations. - * cpu=samples - * Dumps the traces in order of most hits - * cpu=times - * Dumps the traces in the order of most time spent there. - * cpu=old (format=a only) - * Dumps out an older form of cpu output (old -prof format) - * monitor=y (format=a only) - * Dumps out a list of monitors in order of most contended. - * - * This file also includes a binary format check function that will read - * back in the hprof binary format and verify the syntax looks correct. - * - * WARNING: Besides the comments below, there is little format spec on this, - * however see: - * http://java.sun.com/j2se/1.4.2/docs/guide/jvmpi/jvmpi.html#hprof - */ - -#include "hprof.h" - -typedef TableIndex HprofId; - -#include "hprof_ioname.h" -#include "hprof_b_spec.h" - -static int type_size[ /*HprofType*/ ] = HPROF_TYPE_SIZES; - -static void dump_heap_segment_and_reset(jlong segment_size); - -static void -not_implemented(void) -{ -} - -static IoNameIndex -get_name_index(char *name) -{ - if (name != NULL && gdata->output_format == 'b') { - return ioname_find_or_create(name, NULL); - } - return 0; -} - -static char * -signature_to_name(char *sig) -{ - char *ptr; - char *basename; - char *name; - int i; - int len; - int name_len; - - if ( sig != NULL ) { - switch ( sig[0] ) { - case JVM_SIGNATURE_CLASS: - ptr = strchr(sig+1, JVM_SIGNATURE_ENDCLASS); - if ( ptr == NULL ) { - basename = "Unknown_class"; - break; - } - /*LINTED*/ - name_len = (jint)(ptr - (sig+1)); - name = HPROF_MALLOC(name_len+1); - (void)memcpy(name, sig+1, name_len); - name[name_len] = 0; - for ( i = 0 ; i < name_len ; i++ ) { - if ( name[i] == '/' ) name[i] = '.'; - } - return name; - case JVM_SIGNATURE_ARRAY: - basename = signature_to_name(sig+1); - len = (int)strlen(basename); - name_len = len+2; - name = HPROF_MALLOC(name_len+1); - (void)memcpy(name, basename, len); - (void)memcpy(name+len, "[]", 2); - name[name_len] = 0; - HPROF_FREE(basename); - return name; - case JVM_SIGNATURE_FUNC: - ptr = strchr(sig+1, JVM_SIGNATURE_ENDFUNC); - if ( ptr == NULL ) { - basename = "Unknown_method"; - break; - } - basename = "()"; /* Someday deal with method signatures */ - break; - case JVM_SIGNATURE_BYTE: - basename = "byte"; - break; - case JVM_SIGNATURE_CHAR: - basename = "char"; - break; - case JVM_SIGNATURE_ENUM: - basename = "enum"; - break; - case JVM_SIGNATURE_FLOAT: - basename = "float"; - break; - case JVM_SIGNATURE_DOUBLE: - basename = "double"; - break; - case JVM_SIGNATURE_INT: - basename = "int"; - break; - case JVM_SIGNATURE_LONG: - basename = "long"; - break; - case JVM_SIGNATURE_SHORT: - basename = "short"; - break; - case JVM_SIGNATURE_VOID: - basename = "void"; - break; - case JVM_SIGNATURE_BOOLEAN: - basename = "boolean"; - break; - default: - basename = "Unknown_class"; - break; - } - } else { - basename = "Unknown_class"; - } - - /* Simple basename */ - name_len = (int)strlen(basename); - name = HPROF_MALLOC(name_len+1); - (void)strcpy(name, basename); - return name; -} - -static int -size_from_field_info(int size) -{ - if ( size == 0 ) { - size = (int)sizeof(HprofId); - } - return size; -} - -static void -type_from_signature(const char *sig, HprofType *kind, jint *size) -{ - *kind = HPROF_NORMAL_OBJECT; - *size = 0; - switch ( sig[0] ) { - case JVM_SIGNATURE_ENUM: - case JVM_SIGNATURE_CLASS: - case JVM_SIGNATURE_ARRAY: - *kind = HPROF_NORMAL_OBJECT; - break; - case JVM_SIGNATURE_BOOLEAN: - *kind = HPROF_BOOLEAN; - break; - case JVM_SIGNATURE_CHAR: - *kind = HPROF_CHAR; - break; - case JVM_SIGNATURE_FLOAT: - *kind = HPROF_FLOAT; - break; - case JVM_SIGNATURE_DOUBLE: - *kind = HPROF_DOUBLE; - break; - case JVM_SIGNATURE_BYTE: - *kind = HPROF_BYTE; - break; - case JVM_SIGNATURE_SHORT: - *kind = HPROF_SHORT; - break; - case JVM_SIGNATURE_INT: - *kind = HPROF_INT; - break; - case JVM_SIGNATURE_LONG: - *kind = HPROF_LONG; - break; - default: - HPROF_ASSERT(0); - break; - } - *size = type_size[*kind]; -} - -static void -type_array(const char *sig, HprofType *kind, jint *elem_size) -{ - *kind = 0; - *elem_size = 0; - switch ( sig[0] ) { - case JVM_SIGNATURE_ARRAY: - type_from_signature(sig+1, kind, elem_size); - break; - } -} - -static void -system_error(const char *system_call, int rc, int errnum) -{ - char buf[256]; - char details[256]; - - details[0] = 0; - if ( errnum != 0 ) { - md_system_error(details, (int)sizeof(details)); - } else if ( rc >= 0 ) { - (void)strcpy(details,"Only part of buffer processed"); - } - if ( details[0] == 0 ) { - (void)strcpy(details,"Unknown system error condition"); - } - (void)md_snprintf(buf, sizeof(buf), "System %s failed: %s\n", - system_call, details); - HPROF_ERROR(JNI_TRUE, buf); -} - -static void -system_write(int fd, void *buf, int len, jboolean socket) -{ - int res; - - HPROF_ASSERT(fd>=0); - if (socket) { - res = md_send(fd, buf, len, 0); - if (res < 0 || res!=len) { - system_error("send", res, errno); - } - } else { - res = md_write(fd, buf, len); - if (res < 0 || res!=len) { - system_error("write", res, errno); - } - } -} - -static void -write_flush(void) -{ - HPROF_ASSERT(gdata->fd >= 0); - if (gdata->write_buffer_index) { - system_write(gdata->fd, gdata->write_buffer, gdata->write_buffer_index, - gdata->socket); - gdata->write_buffer_index = 0; - } -} - -static void -heap_flush(void) -{ - HPROF_ASSERT(gdata->heap_fd >= 0); - if (gdata->heap_buffer_index) { - gdata->heap_write_count += (jlong)gdata->heap_buffer_index; - system_write(gdata->heap_fd, gdata->heap_buffer, gdata->heap_buffer_index, - JNI_FALSE); - gdata->heap_buffer_index = 0; - } -} - -static void -write_raw(void *buf, int len) -{ - HPROF_ASSERT(gdata->fd >= 0); - if (gdata->write_buffer_index + len > gdata->write_buffer_size) { - write_flush(); - if (len > gdata->write_buffer_size) { - system_write(gdata->fd, buf, len, gdata->socket); - return; - } - } - (void)memcpy(gdata->write_buffer + gdata->write_buffer_index, buf, len); - gdata->write_buffer_index += len; -} - -static void -write_u4(unsigned i) -{ - i = md_htonl(i); - write_raw(&i, (jint)sizeof(unsigned)); -} - -static void -write_u8(jlong t) -{ - write_u4((jint)jlong_high(t)); - write_u4((jint)jlong_low(t)); -} - -static void -write_u2(unsigned short i) -{ - i = md_htons(i); - write_raw(&i, (jint)sizeof(unsigned short)); -} - -static void -write_u1(unsigned char i) -{ - write_raw(&i, (jint)sizeof(unsigned char)); -} - -static void -write_id(HprofId i) -{ - write_u4(i); -} - -static void -write_current_ticks(void) -{ - write_u4((jint)(md_get_microsecs() - gdata->micro_sec_ticks)); -} - -static void -write_header(unsigned char type, jint length) -{ - write_u1(type); - write_current_ticks(); - write_u4(length); -} - -static void -write_index_id(HprofId index) -{ - write_id(index); -} - -static IoNameIndex -write_name_first(char *name) -{ - if ( name == NULL ) { - return 0; - } - if (gdata->output_format == 'b') { - IoNameIndex name_index; - jboolean new_one; - - new_one = JNI_FALSE; - name_index = ioname_find_or_create(name, &new_one); - if ( new_one ) { - int len; - - len = (int)strlen(name); - write_header(HPROF_UTF8, len + (jint)sizeof(HprofId)); - write_index_id(name_index); - write_raw(name, len); - - } - return name_index; - } - return 0; -} - -static void -write_printf(char *fmt, ...) -{ - char buf[1024]; - va_list args; - va_start(args, fmt); - (void)md_vsnprintf(buf, sizeof(buf), fmt, args); - buf[sizeof(buf)-1] = 0; - write_raw(buf, (int)strlen(buf)); - va_end(args); -} - -static void -write_thread_serial_number(SerialNumber thread_serial_num, int with_comma) -{ - if ( thread_serial_num != 0 ) { - CHECK_THREAD_SERIAL_NO(thread_serial_num); - if ( with_comma ) { - write_printf(" thread %d,", thread_serial_num); - } else { - write_printf(" thread %d", thread_serial_num); - } - } else { - if ( with_comma ) { - write_printf(" <unknown thread>,"); - } else { - write_printf(" <unknown thread>"); - } - } -} - -static void -heap_raw(void *buf, int len) -{ - HPROF_ASSERT(gdata->heap_fd >= 0); - if (gdata->heap_buffer_index + len > gdata->heap_buffer_size) { - heap_flush(); - if (len > gdata->heap_buffer_size) { - gdata->heap_write_count += (jlong)len; - system_write(gdata->heap_fd, buf, len, JNI_FALSE); - return; - } - } - (void)memcpy(gdata->heap_buffer + gdata->heap_buffer_index, buf, len); - gdata->heap_buffer_index += len; -} - -static void -heap_u4(unsigned i) -{ - i = md_htonl(i); - heap_raw(&i, (jint)sizeof(unsigned)); -} - -static void -heap_u8(jlong i) -{ - heap_u4((jint)jlong_high(i)); - heap_u4((jint)jlong_low(i)); -} - -static void -heap_u2(unsigned short i) -{ - i = md_htons(i); - heap_raw(&i, (jint)sizeof(unsigned short)); -} - -static void -heap_u1(unsigned char i) -{ - heap_raw(&i, (jint)sizeof(unsigned char)); -} - -/* Write out the first byte of a heap tag */ -static void -heap_tag(unsigned char tag) -{ - jlong pos; - - /* Current position in virtual heap dump file */ - pos = gdata->heap_write_count + (jlong)gdata->heap_buffer_index; - if ( gdata->segmented == JNI_TRUE ) { /* 1.0.2 */ - if ( pos >= gdata->maxHeapSegment ) { - /* Flush all bytes to the heap dump file */ - heap_flush(); - - /* Send out segment (up to last tag written out) */ - dump_heap_segment_and_reset(gdata->heap_last_tag_position); - - /* Get new current position */ - pos = gdata->heap_write_count + (jlong)gdata->heap_buffer_index; - } - } - /* Save position of this tag */ - gdata->heap_last_tag_position = pos; - /* Write out this tag */ - heap_u1(tag); -} - -static void -heap_id(HprofId i) -{ - heap_u4(i); -} - -static void -heap_index_id(HprofId index) -{ - heap_id(index); -} - -static void -heap_name(char *name) -{ - heap_index_id(get_name_index(name)); -} - -static void -heap_printf(char *fmt, ...) -{ - char buf[1024]; - va_list args; - va_start(args, fmt); - (void)md_vsnprintf(buf, sizeof(buf), fmt, args); - buf[sizeof(buf)-1] = 0; - heap_raw(buf, (int)strlen(buf)); - va_end(args); -} - -static void -heap_element(HprofType kind, jint size, jvalue value) -{ - if ( !HPROF_TYPE_IS_PRIMITIVE(kind) ) { - HPROF_ASSERT(size==4); - heap_id((HprofId)value.i); - } else { - switch ( size ) { - case 8: - HPROF_ASSERT(size==8); - HPROF_ASSERT(kind==HPROF_LONG || kind==HPROF_DOUBLE); - heap_u8(value.j); - break; - case 4: - HPROF_ASSERT(size==4); - HPROF_ASSERT(kind==HPROF_INT || kind==HPROF_FLOAT); - heap_u4(value.i); - break; - case 2: - HPROF_ASSERT(size==2); - HPROF_ASSERT(kind==HPROF_SHORT || kind==HPROF_CHAR); - heap_u2(value.s); - break; - case 1: - HPROF_ASSERT(size==1); - HPROF_ASSERT(kind==HPROF_BOOLEAN || kind==HPROF_BYTE); - HPROF_ASSERT(kind==HPROF_BOOLEAN?(value.b==0 || value.b==1):1); - heap_u1(value.b); - break; - default: - HPROF_ASSERT(0); - break; - } - } -} - -/* Dump out all elements of an array, objects in jvalues, prims packed */ -static void -heap_elements(HprofType kind, jint num_elements, jint elem_size, void *elements) -{ - int i; - jvalue val; - static jvalue empty_val; - - if ( num_elements == 0 ) { - return; - } - - switch ( kind ) { - case 0: - case HPROF_ARRAY_OBJECT: - case HPROF_NORMAL_OBJECT: - for (i = 0; i < num_elements; i++) { - val = empty_val; - val.i = ((ObjectIndex*)elements)[i]; - heap_element(kind, elem_size, val); - } - break; - case HPROF_BYTE: - case HPROF_BOOLEAN: - HPROF_ASSERT(elem_size==1); - for (i = 0; i < num_elements; i++) { - val = empty_val; - val.b = ((jboolean*)elements)[i]; - heap_element(kind, elem_size, val); - } - break; - case HPROF_CHAR: - case HPROF_SHORT: - HPROF_ASSERT(elem_size==2); - for (i = 0; i < num_elements; i++) { - val = empty_val; - val.s = ((jshort*)elements)[i]; - heap_element(kind, elem_size, val); - } - break; - case HPROF_FLOAT: - case HPROF_INT: - HPROF_ASSERT(elem_size==4); - for (i = 0; i < num_elements; i++) { - val = empty_val; - val.i = ((jint*)elements)[i]; - heap_element(kind, elem_size, val); - } - break; - case HPROF_DOUBLE: - case HPROF_LONG: - HPROF_ASSERT(elem_size==8); - for (i = 0; i < num_elements; i++) { - val = empty_val; - val.j = ((jlong*)elements)[i]; - heap_element(kind, elem_size, val); - } - break; - } -} - -/* ------------------------------------------------------------------ */ - -void -io_flush(void) -{ - HPROF_ASSERT(gdata->header!=NULL); - write_flush(); -} - -void -io_setup(void) -{ - gdata->write_buffer_size = FILE_IO_BUFFER_SIZE; - gdata->write_buffer = HPROF_MALLOC(gdata->write_buffer_size); - gdata->write_buffer_index = 0; - - gdata->heap_write_count = (jlong)0; - gdata->heap_last_tag_position = (jlong)0; - gdata->heap_buffer_size = FILE_IO_BUFFER_SIZE; - gdata->heap_buffer = HPROF_MALLOC(gdata->heap_buffer_size); - gdata->heap_buffer_index = 0; - - if ( gdata->logflags & LOG_CHECK_BINARY ) { - gdata->check_buffer_size = FILE_IO_BUFFER_SIZE; - gdata->check_buffer = HPROF_MALLOC(gdata->check_buffer_size); - gdata->check_buffer_index = 0; - } - - ioname_init(); -} - -void -io_cleanup(void) -{ - if ( gdata->write_buffer != NULL ) { - HPROF_FREE(gdata->write_buffer); - } - gdata->write_buffer_size = 0; - gdata->write_buffer = NULL; - gdata->write_buffer_index = 0; - - if ( gdata->heap_buffer != NULL ) { - HPROF_FREE(gdata->heap_buffer); - } - gdata->heap_write_count = (jlong)0; - gdata->heap_last_tag_position = (jlong)0; - gdata->heap_buffer_size = 0; - gdata->heap_buffer = NULL; - gdata->heap_buffer_index = 0; - - if ( gdata->logflags & LOG_CHECK_BINARY ) { - if ( gdata->check_buffer != NULL ) { - HPROF_FREE(gdata->check_buffer); - } - gdata->check_buffer_size = 0; - gdata->check_buffer = NULL; - gdata->check_buffer_index = 0; - } - - ioname_cleanup(); -} - -void -io_write_file_header(void) -{ - HPROF_ASSERT(gdata->header!=NULL); - if (gdata->output_format == 'b') { - jint settings; - jlong t; - - settings = 0; - if (gdata->heap_dump || gdata->alloc_sites) { - settings |= 1; - } - if (gdata->cpu_sampling) { - settings |= 2; - } - t = md_get_timemillis(); - - write_raw(gdata->header, (int)strlen(gdata->header) + 1); - write_u4((jint)sizeof(HprofId)); - write_u8(t); - - write_header(HPROF_CONTROL_SETTINGS, 4 + 2); - write_u4(settings); - write_u2((unsigned short)gdata->max_trace_depth); - - } else if ((!gdata->cpu_timing) || (!gdata->old_timing_format)) { - /* We don't want the prelude file for the old prof output format */ - time_t t; - char prelude_file[FILENAME_MAX]; - int prelude_fd; - int nbytes; - - t = time(0); - - md_get_prelude_path(prelude_file, sizeof(prelude_file), PRELUDE_FILE); - - prelude_fd = md_open(prelude_file); - if (prelude_fd < 0) { - char buf[FILENAME_MAX+80]; - - (void)md_snprintf(buf, sizeof(buf), "Can't open %s", prelude_file); - buf[sizeof(buf)-1] = 0; - HPROF_ERROR(JNI_TRUE, buf); - } - - write_printf("%s, created %s\n", gdata->header, ctime(&t)); - - do { - char buf[1024]; /* File is small, small buffer ok here */ - - nbytes = md_read(prelude_fd, buf, sizeof(buf)); - if ( nbytes < 0 ) { - system_error("read", nbytes, errno); - break; - } - if (nbytes == 0) { - break; - } - write_raw(buf, nbytes); - } while ( nbytes > 0 ); - - md_close(prelude_fd); - - write_printf("\n--------\n\n"); - - write_flush(); - } -} - -void -io_write_file_footer(void) -{ - HPROF_ASSERT(gdata->header!=NULL); -} - -void -io_write_class_load(SerialNumber class_serial_num, ObjectIndex index, - SerialNumber trace_serial_num, char *sig) -{ - CHECK_CLASS_SERIAL_NO(class_serial_num); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - if (gdata->output_format == 'b') { - IoNameIndex name_index; - char *class_name; - - class_name = signature_to_name(sig); - name_index = write_name_first(class_name); - write_header(HPROF_LOAD_CLASS, (2 * (jint)sizeof(HprofId)) + (4 * 2)); - write_u4(class_serial_num); - write_index_id(index); - write_u4(trace_serial_num); - write_index_id(name_index); - HPROF_FREE(class_name); - } -} - -void -io_write_class_unload(SerialNumber class_serial_num, ObjectIndex index) -{ - CHECK_CLASS_SERIAL_NO(class_serial_num); - if (gdata->output_format == 'b') { - write_header(HPROF_UNLOAD_CLASS, 4); - write_u4(class_serial_num); - } -} - -void -io_write_sites_header(const char * comment_str, jint flags, double cutoff, - jint total_live_bytes, jint total_live_instances, - jlong total_alloced_bytes, jlong total_alloced_instances, - jint count) -{ - if ( gdata->output_format == 'b') { - write_header(HPROF_ALLOC_SITES, 2 + (8 * 4) + (count * (4 * 6 + 1))); - write_u2((unsigned short)flags); - write_u4(*(int *)(&cutoff)); - write_u4(total_live_bytes); - write_u4(total_live_instances); - write_u8(total_alloced_bytes); - write_u8(total_alloced_instances); - write_u4(count); - } else { - time_t t; - - t = time(0); - write_printf("SITES BEGIN (ordered by %s) %s", comment_str, ctime(&t)); - write_printf( - " percent live alloc'ed stack class\n"); - write_printf( - " rank self accum bytes objs bytes objs trace name\n"); - } -} - -void -io_write_sites_elem(jint index, double ratio, double accum_percent, - char *sig, SerialNumber class_serial_num, - SerialNumber trace_serial_num, jint n_live_bytes, - jint n_live_instances, jint n_alloced_bytes, - jint n_alloced_instances) -{ - CHECK_CLASS_SERIAL_NO(class_serial_num); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - if ( gdata->output_format == 'b') { - HprofType kind; - jint size; - - type_array(sig, &kind, &size); - write_u1(kind); - write_u4(class_serial_num); - write_u4(trace_serial_num); - write_u4(n_live_bytes); - write_u4(n_live_instances); - write_u4(n_alloced_bytes); - write_u4(n_alloced_instances); - } else { - char *class_name; - - class_name = signature_to_name(sig); - write_printf("%5u %5.2f%% %5.2f%% %9u %4u %9u %5u %5u %s\n", - index, - ratio * 100.0, - accum_percent * 100.0, - n_live_bytes, - n_live_instances, - n_alloced_bytes, - n_alloced_instances, - trace_serial_num, - class_name); - HPROF_FREE(class_name); - } -} - -void -io_write_sites_footer(void) -{ - if (gdata->output_format == 'b') { - not_implemented(); - } else { - write_printf("SITES END\n"); - } -} - -void -io_write_thread_start(SerialNumber thread_serial_num, - ObjectIndex thread_obj_id, - SerialNumber trace_serial_num, char *thread_name, - char *thread_group_name, char *thread_parent_name) -{ - CHECK_THREAD_SERIAL_NO(thread_serial_num); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - if (gdata->output_format == 'b') { - IoNameIndex tname_index; - IoNameIndex gname_index; - IoNameIndex pname_index; - - tname_index = write_name_first(thread_name); - gname_index = write_name_first(thread_group_name); - pname_index = write_name_first(thread_parent_name); - write_header(HPROF_START_THREAD, ((jint)sizeof(HprofId) * 4) + (4 * 2)); - write_u4(thread_serial_num); - write_index_id(thread_obj_id); - write_u4(trace_serial_num); - write_index_id(tname_index); - write_index_id(gname_index); - write_index_id(pname_index); - - } else if ( (!gdata->cpu_timing) || (!gdata->old_timing_format)) { - /* We don't want thread info for the old prof output format */ - write_printf("THREAD START " - "(obj=%x, id = %d, name=\"%s\", group=\"%s\")\n", - thread_obj_id, thread_serial_num, - (thread_name==NULL?"":thread_name), - (thread_group_name==NULL?"":thread_group_name)); - } -} - -void -io_write_thread_end(SerialNumber thread_serial_num) -{ - CHECK_THREAD_SERIAL_NO(thread_serial_num); - if (gdata->output_format == 'b') { - write_header(HPROF_END_THREAD, 4); - write_u4(thread_serial_num); - - } else if ( (!gdata->cpu_timing) || (!gdata->old_timing_format)) { - /* we don't want thread info for the old prof output format */ - write_printf("THREAD END (id = %d)\n", thread_serial_num); - } -} - -void -io_write_frame(FrameIndex index, SerialNumber frame_serial_num, - char *mname, char *msig, char *sname, - SerialNumber class_serial_num, jint lineno) -{ - CHECK_CLASS_SERIAL_NO(class_serial_num); - if (gdata->output_format == 'b') { - IoNameIndex mname_index; - IoNameIndex msig_index; - IoNameIndex sname_index; - - mname_index = write_name_first(mname); - msig_index = write_name_first(msig); - sname_index = write_name_first(sname); - - write_header(HPROF_FRAME, ((jint)sizeof(HprofId) * 4) + (4 * 2)); - write_index_id(index); - write_index_id(mname_index); - write_index_id(msig_index); - write_index_id(sname_index); - write_u4(class_serial_num); - write_u4(lineno); - } -} - -void -io_write_trace_header(SerialNumber trace_serial_num, - SerialNumber thread_serial_num, jint n_frames, char *phase_str) -{ - CHECK_TRACE_SERIAL_NO(trace_serial_num); - if (gdata->output_format == 'b') { - write_header(HPROF_TRACE, ((jint)sizeof(HprofId) * n_frames) + (4 * 3)); - write_u4(trace_serial_num); - write_u4(thread_serial_num); - write_u4(n_frames); - } else { - write_printf("TRACE %u:", trace_serial_num); - if (thread_serial_num) { - write_printf(" (thread=%d)", thread_serial_num); - } - if ( phase_str != NULL ) { - write_printf(" (from %s phase of JVM)", phase_str); - } - write_printf("\n"); - if (n_frames == 0) { - write_printf("\t<empty>\n"); - } - } -} - -void -io_write_trace_elem(SerialNumber trace_serial_num, FrameIndex frame_index, - SerialNumber frame_serial_num, - char *csig, char *mname, char *sname, jint lineno) -{ - if (gdata->output_format == 'b') { - write_index_id(frame_index); - } else { - char *class_name; - char linebuf[32]; - - if (lineno == -2) { - (void)md_snprintf(linebuf, sizeof(linebuf), "Compiled method"); - } else if (lineno == -3) { - (void)md_snprintf(linebuf, sizeof(linebuf), "Native method"); - } else if (lineno == -1) { - (void)md_snprintf(linebuf, sizeof(linebuf), "Unknown line"); - } else { - (void)md_snprintf(linebuf, sizeof(linebuf), "%d", lineno); - } - linebuf[sizeof(linebuf)-1] = 0; - class_name = signature_to_name(csig); - if ( mname == NULL ) { - mname = "<Unknown Method>"; - } - if ( sname == NULL ) { - sname = "<Unknown Source>"; - } - write_printf("\t%s.%s(%s:%s)\n", class_name, mname, sname, linebuf); - HPROF_FREE(class_name); - } -} - -void -io_write_trace_footer(SerialNumber trace_serial_num, - SerialNumber thread_serial_num, jint n_frames) -{ -} - -#define CPU_SAMPLES_RECORD_NAME ("CPU SAMPLES") -#define CPU_TIMES_RECORD_NAME ("CPU TIME (ms)") - -void -io_write_cpu_samples_header(jlong total_cost, jint n_items) -{ - - if (gdata->output_format == 'b') { - write_header(HPROF_CPU_SAMPLES, (n_items * (4 * 2)) + (4 * 2)); - write_u4((jint)total_cost); - write_u4(n_items); - } else { - time_t t; - char *record_name; - - if ( gdata->cpu_sampling ) { - record_name = CPU_SAMPLES_RECORD_NAME; - } else { - record_name = CPU_TIMES_RECORD_NAME; - } - t = time(0); - write_printf("%s BEGIN (total = %d) %s", record_name, - /*jlong*/(int)total_cost, ctime(&t)); - if ( n_items > 0 ) { - write_printf("rank self accum count trace method\n"); - } - } -} - -void -io_write_cpu_samples_elem(jint index, double percent, double accum, - jint num_hits, jlong cost, SerialNumber trace_serial_num, - jint n_frames, char *csig, char *mname) -{ - CHECK_TRACE_SERIAL_NO(trace_serial_num); - if (gdata->output_format == 'b') { - write_u4((jint)cost); - write_u4(trace_serial_num); - } else { - write_printf("%4u %5.2f%% %5.2f%% %7u %5u", - index, percent, accum, num_hits, - trace_serial_num); - if (n_frames > 0) { - char * class_name; - - class_name = signature_to_name(csig); - write_printf(" %s.%s\n", class_name, mname); - HPROF_FREE(class_name); - } else { - write_printf(" <empty trace>\n"); - } - } -} - -void -io_write_cpu_samples_footer(void) -{ - if (gdata->output_format == 'b') { - not_implemented(); - } else { - char *record_name; - - if ( gdata->cpu_sampling ) { - record_name = CPU_SAMPLES_RECORD_NAME; - } else { - record_name = CPU_TIMES_RECORD_NAME; - } - write_printf("%s END\n", record_name); - } -} - -void -io_write_heap_summary(jlong total_live_bytes, jlong total_live_instances, - jlong total_alloced_bytes, jlong total_alloced_instances) -{ - if (gdata->output_format == 'b') { - write_header(HPROF_HEAP_SUMMARY, 4 * 6); - write_u4((jint)total_live_bytes); - write_u4((jint)total_live_instances); - write_u8(total_alloced_bytes); - write_u8(total_alloced_instances); - } -} - -void -io_write_oldprof_header(void) -{ - if ( gdata->old_timing_format ) { - write_printf("count callee caller time\n"); - } -} - -void -io_write_oldprof_elem(jint num_hits, jint num_frames, char *csig_callee, - char *mname_callee, char *msig_callee, char *csig_caller, - char *mname_caller, char *msig_caller, jlong cost) -{ - if ( gdata->old_timing_format ) { - char * class_name_callee; - char * class_name_caller; - - class_name_callee = signature_to_name(csig_callee); - class_name_caller = signature_to_name(csig_caller); - write_printf("%d ", num_hits); - if (num_frames >= 1) { - write_printf("%s.%s%s ", class_name_callee, - mname_callee, msig_callee); - } else { - write_printf("%s ", "<unknown callee>"); - } - if (num_frames > 1) { - write_printf("%s.%s%s ", class_name_caller, - mname_caller, msig_caller); - } else { - write_printf("%s ", "<unknown caller>"); - } - write_printf("%d\n", (int)cost); - HPROF_FREE(class_name_callee); - HPROF_FREE(class_name_caller); - } -} - -void -io_write_oldprof_footer(void) -{ -} - -void -io_write_monitor_header(jlong total_time) -{ - if (gdata->output_format == 'b') { - not_implemented(); - } else { - time_t t = time(0); - - t = time(0); - write_printf("MONITOR TIME BEGIN (total = %u ms) %s", - (int)total_time, ctime(&t)); - if (total_time > 0) { - write_printf("rank self accum count trace monitor\n"); - } - } -} - -void -io_write_monitor_elem(jint index, double percent, double accum, - jint num_hits, SerialNumber trace_serial_num, char *sig) -{ - CHECK_TRACE_SERIAL_NO(trace_serial_num); - if (gdata->output_format == 'b') { - not_implemented(); - } else { - char *class_name; - - class_name = signature_to_name(sig); - write_printf("%4u %5.2f%% %5.2f%% %7u %5u %s (Java)\n", - index, percent, accum, num_hits, - trace_serial_num, class_name); - HPROF_FREE(class_name); - } -} - -void -io_write_monitor_footer(void) -{ - if (gdata->output_format == 'b') { - not_implemented(); - } else { - write_printf("MONITOR TIME END\n"); - } -} - -void -io_write_monitor_sleep(jlong timeout, SerialNumber thread_serial_num) -{ - if (gdata->output_format == 'b') { - not_implemented(); - } else { - if ( thread_serial_num == 0 ) { - write_printf("SLEEP: timeout=%d, <unknown thread>\n", - (int)timeout); - } else { - CHECK_THREAD_SERIAL_NO(thread_serial_num); - write_printf("SLEEP: timeout=%d, thread %d\n", - (int)timeout, thread_serial_num); - } - } -} - -void -io_write_monitor_wait(char *sig, jlong timeout, - SerialNumber thread_serial_num) -{ - if (gdata->output_format == 'b') { - not_implemented(); - } else { - if ( thread_serial_num == 0 ) { - write_printf("WAIT: MONITOR %s, timeout=%d, <unknown thread>\n", - sig, (int)timeout); - } else { - CHECK_THREAD_SERIAL_NO(thread_serial_num); - write_printf("WAIT: MONITOR %s, timeout=%d, thread %d\n", - sig, (int)timeout, thread_serial_num); - } - } -} - -void -io_write_monitor_waited(char *sig, jlong time_waited, - SerialNumber thread_serial_num) -{ - if (gdata->output_format == 'b') { - not_implemented(); - } else { - if ( thread_serial_num == 0 ) { - write_printf("WAITED: MONITOR %s, time_waited=%d, <unknown thread>\n", - sig, (int)time_waited); - } else { - CHECK_THREAD_SERIAL_NO(thread_serial_num); - write_printf("WAITED: MONITOR %s, time_waited=%d, thread %d\n", - sig, (int)time_waited, thread_serial_num); - } - } -} - -void -io_write_monitor_exit(char *sig, SerialNumber thread_serial_num) -{ - if (gdata->output_format == 'b') { - not_implemented(); - } else { - if ( thread_serial_num == 0 ) { - write_printf("EXIT: MONITOR %s, <unknown thread>\n", sig); - } else { - CHECK_THREAD_SERIAL_NO(thread_serial_num); - write_printf("EXIT: MONITOR %s, thread %d\n", - sig, thread_serial_num); - } - } -} - -void -io_write_monitor_dump_header(void) -{ - if (gdata->output_format == 'b') { - not_implemented(); - } else { - write_printf("MONITOR DUMP BEGIN\n"); - } -} - -void -io_write_monitor_dump_thread_state(SerialNumber thread_serial_num, - SerialNumber trace_serial_num, - jint threadState) -{ - CHECK_THREAD_SERIAL_NO(thread_serial_num); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - if (gdata->output_format == 'b') { - not_implemented(); - } else { - char tstate[20]; - - tstate[0] = 0; - - if (threadState & JVMTI_THREAD_STATE_SUSPENDED) { - (void)strcat(tstate,"S|"); - } - if (threadState & JVMTI_THREAD_STATE_INTERRUPTED) { - (void)strcat(tstate,"intr|"); - } - if (threadState & JVMTI_THREAD_STATE_IN_NATIVE) { - (void)strcat(tstate,"native|"); - } - if ( ! ( threadState & JVMTI_THREAD_STATE_ALIVE ) ) { - if ( threadState & JVMTI_THREAD_STATE_TERMINATED ) { - (void)strcat(tstate,"ZO"); - } else { - (void)strcat(tstate,"NS"); - } - } else { - if ( threadState & JVMTI_THREAD_STATE_SLEEPING ) { - (void)strcat(tstate,"SL"); - } else if ( threadState & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER ) { - (void)strcat(tstate,"MW"); - } else if ( threadState & JVMTI_THREAD_STATE_WAITING ) { - (void)strcat(tstate,"CW"); - } else if ( threadState & JVMTI_THREAD_STATE_RUNNABLE ) { - (void)strcat(tstate,"R"); - } else { - (void)strcat(tstate,"UN"); - } - } - write_printf(" THREAD %d, trace %d, status: %s\n", - thread_serial_num, trace_serial_num, tstate); - } -} - -void -io_write_monitor_dump_state(char *sig, SerialNumber thread_serial_num, - jint entry_count, - SerialNumber *waiters, jint waiter_count, - SerialNumber *notify_waiters, jint notify_waiter_count) -{ - if (gdata->output_format == 'b') { - not_implemented(); - } else { - int i; - - if ( thread_serial_num != 0 ) { - CHECK_THREAD_SERIAL_NO(thread_serial_num); - write_printf(" MONITOR %s\n", sig); - write_printf("\towner: thread %d, entry count: %d\n", - thread_serial_num, entry_count); - } else { - write_printf(" MONITOR %s unowned\n", sig); - } - write_printf("\twaiting to enter:"); - for (i = 0; i < waiter_count; i++) { - write_thread_serial_number(waiters[i], - (i != (waiter_count-1))); - } - write_printf("\n"); - write_printf("\twaiting to be notified:"); - for (i = 0; i < notify_waiter_count; i++) { - write_thread_serial_number(notify_waiters[i], - (i != (notify_waiter_count-1))); - } - write_printf("\n"); - } -} - -void -io_write_monitor_dump_footer(void) -{ - if (gdata->output_format == 'b') { - not_implemented(); - } else { - write_printf("MONITOR DUMP END\n"); - } -} - -/* ----------------------------------------------------------------- */ -/* These functions write to a separate file */ - -void -io_heap_header(jlong total_live_instances, jlong total_live_bytes) -{ - if (gdata->output_format != 'b') { - time_t t; - - t = time(0); - heap_printf("HEAP DUMP BEGIN (%u objects, %u bytes) %s", - /*jlong*/(int)total_live_instances, - /*jlong*/(int)total_live_bytes, ctime(&t)); - } -} - -void -io_heap_root_thread_object(ObjectIndex thread_obj_id, - SerialNumber thread_serial_num, SerialNumber trace_serial_num) -{ - CHECK_THREAD_SERIAL_NO(thread_serial_num); - CHECK_TRACE_SERIAL_NO(trace_serial_num); - if (gdata->output_format == 'b') { - heap_tag(HPROF_GC_ROOT_THREAD_OBJ); - heap_id(thread_obj_id); - heap_u4(thread_serial_num); - heap_u4(trace_serial_num); - } else { - heap_printf("ROOT %x (kind=<thread>, id=%u, trace=%u)\n", - thread_obj_id, thread_serial_num, trace_serial_num); - } -} - -void -io_heap_root_unknown(ObjectIndex obj_id) -{ - if (gdata->output_format == 'b') { - heap_tag(HPROF_GC_ROOT_UNKNOWN); - heap_id(obj_id); - } else { - heap_printf("ROOT %x (kind=<unknown>)\n", obj_id); - } -} - -void -io_heap_root_jni_global(ObjectIndex obj_id, SerialNumber gref_serial_num, - SerialNumber trace_serial_num) -{ - CHECK_TRACE_SERIAL_NO(trace_serial_num); - if (gdata->output_format == 'b') { - heap_tag(HPROF_GC_ROOT_JNI_GLOBAL); - heap_id(obj_id); - heap_id(gref_serial_num); - } else { - heap_printf("ROOT %x (kind=<JNI global ref>, " - "id=%x, trace=%u)\n", - obj_id, gref_serial_num, trace_serial_num); - } -} - -void -io_heap_root_jni_local(ObjectIndex obj_id, SerialNumber thread_serial_num, - jint frame_depth) -{ - CHECK_THREAD_SERIAL_NO(thread_serial_num); - if (gdata->output_format == 'b') { - heap_tag(HPROF_GC_ROOT_JNI_LOCAL); - heap_id(obj_id); - heap_u4(thread_serial_num); - heap_u4(frame_depth); - } else { - heap_printf("ROOT %x (kind=<JNI local ref>, " - "thread=%u, frame=%d)\n", - obj_id, thread_serial_num, frame_depth); - } -} - -void -io_heap_root_system_class(ObjectIndex obj_id, char *sig, SerialNumber class_serial_num) -{ - if (gdata->output_format == 'b') { - heap_tag(HPROF_GC_ROOT_STICKY_CLASS); - heap_id(obj_id); - } else { - char *class_name; - - class_name = signature_to_name(sig); - heap_printf("ROOT %x (kind=<system class>, name=%s)\n", - obj_id, class_name); - HPROF_FREE(class_name); - } -} - -void -io_heap_root_monitor(ObjectIndex obj_id) -{ - if (gdata->output_format == 'b') { - heap_tag(HPROF_GC_ROOT_MONITOR_USED); - heap_id(obj_id); - } else { - heap_printf("ROOT %x (kind=<busy monitor>)\n", obj_id); - } -} - -void -io_heap_root_thread(ObjectIndex obj_id, SerialNumber thread_serial_num) -{ - CHECK_THREAD_SERIAL_NO(thread_serial_num); - if (gdata->output_format == 'b') { - heap_tag(HPROF_GC_ROOT_THREAD_BLOCK); - heap_id(obj_id); - heap_u4(thread_serial_num); - } else { - heap_printf("ROOT %x (kind=<thread block>, thread=%u)\n", - obj_id, thread_serial_num); - } -} - -void -io_heap_root_java_frame(ObjectIndex obj_id, SerialNumber thread_serial_num, - jint frame_depth) -{ - CHECK_THREAD_SERIAL_NO(thread_serial_num); - if (gdata->output_format == 'b') { - heap_tag(HPROF_GC_ROOT_JAVA_FRAME); - heap_id(obj_id); - heap_u4(thread_serial_num); - heap_u4(frame_depth); - } else { - heap_printf("ROOT %x (kind=<Java stack>, " - "thread=%u, frame=%d)\n", - obj_id, thread_serial_num, frame_depth); - } -} - -void -io_heap_root_native_stack(ObjectIndex obj_id, SerialNumber thread_serial_num) -{ - CHECK_THREAD_SERIAL_NO(thread_serial_num); - if (gdata->output_format == 'b') { - heap_tag(HPROF_GC_ROOT_NATIVE_STACK); - heap_id(obj_id); - heap_u4(thread_serial_num); - } else { - heap_printf("ROOT %x (kind=<native stack>, thread=%u)\n", - obj_id, thread_serial_num); - } -} - -static jboolean -is_static_field(jint modifiers) -{ - if ( modifiers & JVM_ACC_STATIC ) { - return JNI_TRUE; - } - return JNI_FALSE; -} - -static jboolean -is_inst_field(jint modifiers) -{ - if ( modifiers & JVM_ACC_STATIC ) { - return JNI_FALSE; - } - return JNI_TRUE; -} - -void -io_heap_class_dump(ClassIndex cnum, char *sig, ObjectIndex class_id, - SerialNumber trace_serial_num, - ObjectIndex super_id, ObjectIndex loader_id, - ObjectIndex signers_id, ObjectIndex domain_id, - jint size, - jint n_cpool, ConstantPoolValue *cpool, - jint n_fields, FieldInfo *fields, jvalue *fvalues) -{ - CHECK_TRACE_SERIAL_NO(trace_serial_num); - if (gdata->output_format == 'b') { - int i; - jint n_static_fields; - jint n_inst_fields; - jint inst_size; - jint saved_inst_size; - - n_static_fields = 0; - n_inst_fields = 0; - inst_size = 0; - - /* These do NOT go into the heap output */ - for ( i = 0 ; i < n_fields ; i++ ) { - if ( fields[i].cnum == cnum && - is_static_field(fields[i].modifiers) ) { - char *field_name; - - field_name = string_get(fields[i].name_index); - (void)write_name_first(field_name); - n_static_fields++; - } - if ( is_inst_field(fields[i].modifiers) ) { - inst_size += size_from_field_info(fields[i].primSize); - if ( fields[i].cnum == cnum ) { - char *field_name; - - field_name = string_get(fields[i].name_index); - (void)write_name_first(field_name); - n_inst_fields++; - } - } - } - - /* Verify that the instance size we have calculated as we went - * through the fields, matches what is saved away with this - * class. - */ - if ( size >= 0 ) { - saved_inst_size = class_get_inst_size(cnum); - if ( saved_inst_size == -1 ) { - class_set_inst_size(cnum, inst_size); - } else if ( saved_inst_size != inst_size ) { - HPROF_ERROR(JNI_TRUE, "Mis-match on instance size in class dump"); - } - } - - heap_tag(HPROF_GC_CLASS_DUMP); - heap_id(class_id); - heap_u4(trace_serial_num); - heap_id(super_id); - heap_id(loader_id); - heap_id(signers_id); - heap_id(domain_id); - heap_id(0); - heap_id(0); - heap_u4(inst_size); /* Must match inst_size in instance dump */ - - heap_u2((unsigned short)n_cpool); - for ( i = 0 ; i < n_cpool ; i++ ) { - HprofType kind; - jint size; - - type_from_signature(string_get(cpool[i].sig_index), - &kind, &size); - heap_u2((unsigned short)(cpool[i].constant_pool_index)); - heap_u1(kind); - HPROF_ASSERT(!HPROF_TYPE_IS_PRIMITIVE(kind)); - heap_element(kind, size, cpool[i].value); - } - - heap_u2((unsigned short)n_static_fields); - for ( i = 0 ; i < n_fields ; i++ ) { - if ( fields[i].cnum == cnum && - is_static_field(fields[i].modifiers) ) { - char *field_name; - HprofType kind; - jint size; - - type_from_signature(string_get(fields[i].sig_index), - &kind, &size); - field_name = string_get(fields[i].name_index); - heap_name(field_name); - heap_u1(kind); - heap_element(kind, size, fvalues[i]); - } - } - - heap_u2((unsigned short)n_inst_fields); /* Does not include super class */ - for ( i = 0 ; i < n_fields ; i++ ) { - if ( fields[i].cnum == cnum && - is_inst_field(fields[i].modifiers) ) { - HprofType kind; - jint size; - char *field_name; - - field_name = string_get(fields[i].name_index); - type_from_signature(string_get(fields[i].sig_index), - &kind, &size); - heap_name(field_name); - heap_u1(kind); - } - } - } else { - char * class_name; - int i; - - class_name = signature_to_name(sig); - heap_printf("CLS %x (name=%s, trace=%u)\n", - class_id, class_name, trace_serial_num); - HPROF_FREE(class_name); - if (super_id) { - heap_printf("\tsuper\t\t%x\n", super_id); - } - if (loader_id) { - heap_printf("\tloader\t\t%x\n", loader_id); - } - if (signers_id) { - heap_printf("\tsigners\t\t%x\n", signers_id); - } - if (domain_id) { - heap_printf("\tdomain\t\t%x\n", domain_id); - } - for ( i = 0 ; i < n_fields ; i++ ) { - if ( fields[i].cnum == cnum && - is_static_field(fields[i].modifiers) ) { - HprofType kind; - jint size; - - type_from_signature(string_get(fields[i].sig_index), - &kind, &size); - if ( !HPROF_TYPE_IS_PRIMITIVE(kind) ) { - if (fvalues[i].i != 0 ) { - char *field_name; - - field_name = string_get(fields[i].name_index); - heap_printf("\tstatic %s\t%x\n", field_name, - fvalues[i].i); - } - } - } - } - for ( i = 0 ; i < n_cpool ; i++ ) { - HprofType kind; - jint size; - - type_from_signature(string_get(cpool[i].sig_index), &kind, &size); - if ( !HPROF_TYPE_IS_PRIMITIVE(kind) ) { - if (cpool[i].value.i != 0 ) { - heap_printf("\tconstant pool entry %d\t%x\n", - cpool[i].constant_pool_index, cpool[i].value.i); - } - } - } - } -} - -/* Dump the instance fields in the right order. */ -static int -dump_instance_fields(ClassIndex cnum, - FieldInfo *fields, jvalue *fvalues, jint n_fields) -{ - ClassIndex super_cnum; - int i; - int nbytes; - - HPROF_ASSERT(cnum!=0); - - nbytes = 0; - for (i = 0; i < n_fields; i++) { - if ( fields[i].cnum == cnum && - is_inst_field(fields[i].modifiers) ) { - HprofType kind; - int size; - - type_from_signature(string_get(fields[i].sig_index), - &kind, &size); - heap_element(kind, size, fvalues[i]); - nbytes += size; - } - } - - super_cnum = class_get_super(cnum); - if ( super_cnum != 0 ) { - nbytes += dump_instance_fields(super_cnum, fields, fvalues, n_fields); - } - return nbytes; -} - -void -io_heap_instance_dump(ClassIndex cnum, ObjectIndex obj_id, - SerialNumber trace_serial_num, - ObjectIndex class_id, jint size, char *sig, - FieldInfo *fields, jvalue *fvalues, jint n_fields) -{ - CHECK_TRACE_SERIAL_NO(trace_serial_num); - if (gdata->output_format == 'b') { - jint inst_size; - jint saved_inst_size; - int i; - int nbytes; - - inst_size = 0; - for (i = 0; i < n_fields; i++) { - if ( is_inst_field(fields[i].modifiers) ) { - inst_size += size_from_field_info(fields[i].primSize); - } - } - - /* Verify that the instance size we have calculated as we went - * through the fields, matches what is saved away with this - * class. - */ - saved_inst_size = class_get_inst_size(cnum); - if ( saved_inst_size == -1 ) { - class_set_inst_size(cnum, inst_size); - } else if ( saved_inst_size != inst_size ) { - HPROF_ERROR(JNI_TRUE, "Mis-match on instance size in instance dump"); - } - - heap_tag(HPROF_GC_INSTANCE_DUMP); - heap_id(obj_id); - heap_u4(trace_serial_num); - heap_id(class_id); - heap_u4(inst_size); /* Must match inst_size in class dump */ - - /* Order must be class, super, super's super, ... */ - nbytes = dump_instance_fields(cnum, fields, fvalues, n_fields);