-/* src/vm/jit/stacktrace.c - machine independet stacktrace system
+/* src/vm/jit/stacktrace.c - machine independent stacktrace system
- Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
- R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
- C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
- Institut f. Computersprachen - TU Wien
+ Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
+ C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+ E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+ J. Wenninger, Institut f. Computersprachen - TU Wien
This file is part of CACAO.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
-
- Contact: cacao@complang.tuwien.ac.at
-
- Authors: Joseph Wenninger
-
- Changes: Christian Thalinger
-
- $Id: stacktrace.c 4014 2005-12-30 14:20:25Z twisti $
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
*/
#include "config.h"
#include <assert.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "vm/types.h"
-#include "mm/boehm.h"
-#include "native/native.h"
+#include "mm/gc-common.h"
+#include "mm/memory.h"
+
+#include "vm/jit/stacktrace.h"
#include "vm/global.h" /* required here for native includes */
-#include "native/include/java_lang_ClassLoader.h"
+#include "native/jni.h"
+#include "native/llni.h"
#include "native/include/java_lang_Throwable.h"
-#include "native/include/java_lang_VMThrowable.h"
+
+#if defined(WITH_CLASSPATH_GNU)
+# include "native/include/java_lang_VMThrowable.h"
+#endif
+
+#if defined(ENABLE_THREADS)
+# include "threads/native/threads.h"
+#else
+# include "threads/none/threads.h"
+#endif
#include "toolbox/logging.h"
+
+#include "vm/array.h"
#include "vm/builtin.h"
-#include "vm/class.h"
+#include "vm/cycles-stats.h"
#include "vm/exceptions.h"
-#include "vm/loader.h"
-#include "vm/options.h"
#include "vm/stringlocal.h"
+#include "vm/vm.h"
+
#include "vm/jit/asmpart.h"
#include "vm/jit/codegen-common.h"
#include "vm/jit/methodheader.h"
-
-/* lineNumberTableEntry *******************************************************/
-
-/* Keep the type of line the same as the pointer type, otherwise we run into */
-/* alignment troubles (like on MIPS64). */
-
-typedef struct lineNumberTableEntry {
- ptrint line;
- u1 *pc;
-} lineNumberTableEntry;
-
-
-typedef struct lineNumberTableEntryInlineBegin {
- /* this should have the same layout and size as the lineNumberTableEntry */
- ptrint lineNrOuter;
- methodinfo *method;
-} lineNumberTableEntryInlineBegin;
-
-#ifndef ENABLE_JVMTI
-typedef bool(*CacaoStackTraceCollector)(void **, stackTraceBuffer*);
-#endif
-
-#define BLOCK_INITIALSIZE 40
-#define BLOCK_SIZEINCREMENT 40
+#include "vmcore/class.h"
+#include "vmcore/loader.h"
+#include "vmcore/options.h"
/* global variables ***********************************************************/
-
-#if !defined(USE_THREADS)
-stackframeinfo *_no_threads_stackframeinfo = NULL;
-#endif
-
-
-/* stacktrace_create_stackframeinfo ********************************************
-
- Creates an stackframe info structure for inline code in the
- interpreter.
-
-*******************************************************************************/
-
-#if defined(ENABLE_INTRP)
-void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
- u1 *ra)
-{
- stackframeinfo **psfi;
- methodinfo *m;
-
- /* get current stackframe info pointer */
-
- psfi = STACKFRAMEINFO;
-
- /* if we don't have pv handy */
-
- if (pv == NULL) {
-#if defined(ENABLE_INTRP)
- if (opt_intrp)
- pv = codegen_findmethod(ra);
- else
-#endif
- {
-#if defined(ENABLE_JIT)
- pv = md_codegen_findmethod(ra);
+#if !defined(ENABLE_THREADS)
+stackframeinfo_t *_no_threads_stackframeinfo = NULL;
#endif
- }
- }
- /* get methodinfo pointer from data segment */
+CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1)
+CYCLES_STATS_DECLARE(stacktrace_fillInStackTrace,40,5000)
+CYCLES_STATS_DECLARE(stacktrace_getClassContext ,40,5000)
+CYCLES_STATS_DECLARE(stacktrace_getCurrentClass ,40,5000)
+CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
- m = *((methodinfo **) (pv + MethodPointer));
- /* fill new stackframe info structure */
+/* stacktrace_stackframeinfo_add ***********************************************
- sfi->prev = *psfi;
- sfi->method = m;
- sfi->pv = pv;
- sfi->sp = sp;
- sfi->ra = ra;
-
- /* xpc is the same as ra, but is required in fillInStackTrace */
-
- sfi->xpc = ra;
-
- /* store new stackframe info pointer */
-
- *psfi = sfi;
-}
-#endif /* defined(ENABLE_INTRP) */
-
-/* stacktrace_create_inline_stackframeinfo *************************************
-
- Creates an stackframe info structure for an inline exception stub.
+ Fills a stackframe info structure with the given or calculated
+ values and adds it to the chain.
*******************************************************************************/
-void stacktrace_create_inline_stackframeinfo(stackframeinfo *sfi, u1 *pv,
- u1 *sp, u1 *ra, u1 *xpc)
+void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra, u1 *xpc)
{
- stackframeinfo **psfi;
-
- /* get current stackframe info pointer */
-
- psfi = STACKFRAMEINFO;
-
-#if defined(ENABLE_INTRP)
- if (opt_intrp) {
- /* if we don't have pv handy */
-
- if (pv == NULL)
- pv = codegen_findmethod(ra);
-
- }
+ stackframeinfo_t **psfi;
+ codeinfo *code;
+#if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
+ bool isleafmethod;
#endif
-
- /* fill new stackframe info structure */
-
- sfi->prev = *psfi;
- sfi->method = NULL;
- sfi->pv = pv;
- sfi->sp = sp;
- sfi->ra = ra;
- sfi->xpc = xpc;
-
- /* store new stackframe info pointer */
-
- *psfi = sfi;
-}
-
-
-/* stacktrace_create_extern_stackframeinfo *************************************
-
- Creates an stackframe info structure for an extern exception
- (hardware or assembler).
-
-*******************************************************************************/
-
-void stacktrace_create_extern_stackframeinfo(stackframeinfo *sfi, u1 *pv,
- u1 *sp, u1 *ra, u1 *xpc)
-{
- stackframeinfo **psfi;
-#if !defined(__I386__) && !defined(__X86_64__)
- bool isleafmethod;
+#if defined(ENABLE_JIT)
+ s4 framesize;
#endif
- s4 framesize;
/* get current stackframe info pointer */
- psfi = STACKFRAMEINFO;
+ psfi = &STACKFRAMEINFO;
/* sometimes we don't have pv handy (e.g. in asmpart.S:
L_asm_call_jit_compiler_exception or in the interpreter). */
if (pv == NULL) {
#if defined(ENABLE_INTRP)
if (opt_intrp)
- pv = codegen_findmethod(ra);
+ pv = codegen_get_pv_from_pc(ra);
else
#endif
{
#if defined(ENABLE_JIT)
- pv = md_codegen_findmethod(ra);
+# if defined(__SPARC_64__)
+ pv = md_get_pv_from_stackframe(sp);
+# else
+ pv = md_codegen_get_pv_from_pc(ra);
+# endif
#endif
}
}
-#if defined(ENABLE_INTRP)
+ /* Get codeinfo pointer for the parent Java method. */
+
+ code = code_get_codeinfo_for_pv(pv);
+
+ /* XXX */
+/* assert(m != NULL); */
+
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
/* When using the interpreter, we pass RA to the function. */
if (!opt_intrp) {
-#endif
-# if defined(__I386__) || defined(__X86_64__)
+# endif
+# if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__M68K__)
/* On i386 and x86_64 we always have to get the return address
from the stack. */
+ /* m68k has return address on stack always */
+ /* On S390 we use REG_RA as REG_ITMP3, so we have always to get
+ the RA from stack. */
framesize = *((u4 *) (pv + FrameSize));
ra = md_stacktrace_get_returnaddress(sp, framesize);
}
# endif
-#if defined(ENABLE_INTRP)
+# if defined(ENABLE_INTRP)
}
+# endif
#endif
- /* fill new stackframe info structure */
+ /* Calculate XPC when not given. The XPC is then the return
+ address of the current method minus 1 because the RA points to
+ the instruction after the call instruction. This is required
+ e.g. for method stubs. */
+
+ if (xpc == NULL) {
+ xpc = (void *) (((intptr_t) ra) - 1);
+ }
- sfi->prev = *psfi;
- sfi->method = NULL;
- sfi->pv = pv;
- sfi->sp = sp;
- sfi->ra = ra;
- sfi->xpc = xpc;
+ /* Fill new stackframeinfo structure. */
+
+ sfi->prev = *psfi;
+ sfi->code = code;
+ sfi->pv = pv;
+ sfi->sp = sp;
+ sfi->ra = ra;
+ sfi->xpc = xpc;
+
+#if !defined(NDEBUG)
+ if (opt_DebugStackFrameInfo) {
+ log_start();
+ log_print("[stackframeinfo add : sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
+ sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
+ method_print(sfi->code->m);
+ log_print("]");
+ log_finish();
+ }
+#endif
- /* store new stackframe info pointer */
+ /* Store new stackframeinfo pointer. */
*psfi = sfi;
+
+ /* set the native world flag for the current thread */
+ /* ATTENTION: This flag tells the GC how to treat this thread in case of
+ a collection. Set this flag _after_ a valid stackframe info was set. */
+
+ THREAD_NATIVEWORLD_ENTER;
}
-/* stacktrace_create_native_stackframeinfo *************************************
+/* stacktrace_stackframeinfo_remove ********************************************
- Creates a stackframe info structure for a native stub.
+ Remove the given stackframeinfo from the chain in the current
+ thread.
*******************************************************************************/
-void stacktrace_create_native_stackframeinfo(stackframeinfo *sfi, u1 *pv,
- u1 *sp, u1 *ra)
+void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
{
- stackframeinfo **psfi;
- methodinfo *m;
+ stackframeinfo_t **psfi;
- /* get methodinfo pointer from data segment */
+ /* clear the native world flag for the current thread */
+ /* ATTENTION: Clear this flag _before_ removing the stackframe info */
- m = *((methodinfo **) (pv + MethodPointer));
+ THREAD_NATIVEWORLD_EXIT;
/* get current stackframe info pointer */
- psfi = STACKFRAMEINFO;
-
- /* fill new stackframe info structure */
-
- sfi->prev = *psfi;
- sfi->method = m;
- sfi->pv = NULL;
- sfi->sp = sp;
- sfi->ra = ra;
- sfi->xpc = NULL;
-
- /* store new stackframe info pointer */
-
- *psfi = sfi;
-}
-
-
-/* stacktrace_remove_stackframeinfo ********************************************
+ psfi = &STACKFRAMEINFO;
- XXX
-
-*******************************************************************************/
-
-void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
-{
- stackframeinfo **psfi;
-
- /* get current stackframe info pointer */
-
- psfi = STACKFRAMEINFO;
+#if !defined(NDEBUG)
+ if (opt_DebugStackFrameInfo) {
+ log_start();
+ log_print("[stackframeinfo remove: sfi=%p, method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
+ sfi, sfi->code->m, sfi->pv, sfi->sp, sfi->ra, sfi->xpc);
+ method_print(sfi->code->m);
+ log_print("]");
+ log_finish();
+ }
+#endif
/* restore the old pointer */
}
-/* stacktrace_inline_arithmeticexception ***************************************
+/* stacktrace_entry_add ********************************************************
- Creates an ArithemticException for inline stub.
+ Adds a new entry to the stacktrace buffer.
*******************************************************************************/
-java_objectheader *stacktrace_inline_arithmeticexception(u1 *pv, u1 *sp,
- u1 *ra, u1 *xpc)
+static inline stacktracebuffer *stacktrace_entry_add(stacktracebuffer *stb, methodinfo *m, u2 line)
{
- stackframeinfo sfi;
- java_objectheader *o;
-
- /* create stackframeinfo */
+ stacktrace_entry *ste;
+ u4 stb_size_old;
+ u4 stb_size_new;
- stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+ /* check if we already reached the buffer capacity */
- /* create exception */
+ if (stb->used >= stb->capacity) {
+ /* calculate size of stacktracebuffer */
- o = new_arithmeticexception();
+ stb_size_old = sizeof(stacktracebuffer) +
+ sizeof(stacktrace_entry) * stb->capacity -
+ sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
- /* remove stackframeinfo */
-
- stacktrace_remove_stackframeinfo(&sfi);
-
- return o;
-}
+ stb_size_new = stb_size_old +
+ sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_INCREMENT;
+ /* reallocate new memory */
-/* stacktrace_inline_arrayindexoutofboundsexception ****************************
+ stb = DMREALLOC(stb, u1, stb_size_old, stb_size_new);
- Creates an ArrayIndexOutOfBoundsException for inline stub.
+ /* set new buffer capacity */
-*******************************************************************************/
-
-java_objectheader *stacktrace_inline_arrayindexoutofboundsexception(u1 *pv,
- u1 *sp,
- u1 *ra,
- u1 *xpc,
- s4 index)
-{
- stackframeinfo sfi;
- java_objectheader *o;
-
- /* create stackframeinfo */
+ stb->capacity = stb->capacity + STACKTRACE_CAPACITY_INCREMENT;
+ }
- stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+ /* insert the current entry */
- /* create exception */
+ ste = &(stb->entries[stb->used]);
- o = new_arrayindexoutofboundsexception(index);
+ ste->method = m;
+ ste->linenumber = line;
- /* remove stackframeinfo */
+ /* increase entries used count */
- stacktrace_remove_stackframeinfo(&sfi);
+ stb->used += 1;
- return o;
+ return stb;
}
-/* stacktrace_inline_arraystoreexception ***************************************
-
- Creates an ArrayStoreException for inline stub.
-
-*******************************************************************************/
-
-java_objectheader *stacktrace_inline_arraystoreexception(u1 *pv, u1 *sp, u1 *ra,
- u1 *xpc)
-{
- stackframeinfo sfi;
- java_objectheader *o;
-
- /* create stackframeinfo */
-
- stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+/* stacktrace_method_add *******************************************************
- /* create exception */
+ Add stacktrace entries[1] for the given method to the stacktrace
+ buffer.
- o = new_arraystoreexception();
+ IN:
+ stb....stacktracebuffer to fill
+ sfi....current stackframeinfo
+ OUT:
+ stacktracebuffer after possible reallocation.
- /* remove stackframeinfo */
-
- stacktrace_remove_stackframeinfo(&sfi);
-
- return o;
-}
-
-
-/* stacktrace_inline_classcastexception ****************************************
-
- Creates an ClassCastException for inline stub.
+ [1] In case of inlined methods there may be more than one stacktrace
+ entry for a codegen-level method. (see doc/inlining_stacktrace.txt)
*******************************************************************************/
-java_objectheader *stacktrace_inline_classcastexception(u1 *pv, u1 *sp, u1 *ra,
- u1 *xpc)
+static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo_t *sfi)
{
- stackframeinfo sfi;
- java_objectheader *o;
+ codeinfo *code;
+ void *pv;
+ void *xpc;
+ methodinfo *m;
+ int32_t linenumber;
- /* create stackframeinfo */
+ /* Get values from the stackframeinfo. */
- stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
+ code = sfi->code;
+ pv = sfi->pv;
+ xpc = sfi->xpc;
- /* create exception */
+ m = code->m;
- o = new_classcastexception();
+ /* Skip builtin methods. */
- /* remove stackframeinfo */
+ if (m->flags & ACC_METHOD_BUILTIN)
+ return stb;
- stacktrace_remove_stackframeinfo(&sfi);
+ /* Search the line number table. */
- return o;
-}
+ linenumber = dseg_get_linenumber_from_pc(&m, pv, xpc);
+ /* Add a new entry to the staktrace. */
-/* stacktrace_inline_nullpointerexception **************************************
-
- Creates an NullPointerException for inline stub.
-
-*******************************************************************************/
-
-java_objectheader *stacktrace_inline_nullpointerexception(u1 *pv, u1 *sp,
- u1 *ra, u1 *xpc)
-{
- stackframeinfo sfi;
- java_objectheader *o;
-
- /* create stackframeinfo */
+ stb = stacktrace_entry_add(stb, m, linenumber);
- stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
-
- /* create exception */
-
- o = new_nullpointerexception();
-
- /* remove stackframeinfo */
-
- stacktrace_remove_stackframeinfo(&sfi);
-
- return o;
+ return stb;
}
-/* stacktrace_hardware_arithmeticexception *************************************
-
- Creates an ArithemticException for inline stub.
-
-*******************************************************************************/
-
-java_objectheader *stacktrace_hardware_arithmeticexception(u1 *pv, u1 *sp,
- u1 *ra, u1 *xpc)
-{
- stackframeinfo sfi;
- java_objectheader *o;
-
- /* create stackframeinfo */
-
- stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
+/* stacktrace_stack_walk *******************************************************
- /* create exception */
+ Walk the stack (or the stackframeinfo-chain) to the next method.
- o = new_arithmeticexception();
-
- /* remove stackframeinfo */
-
- stacktrace_remove_stackframeinfo(&sfi);
-
- return o;
-}
-
-
-/* stacktrace_hardware_nullpointerexception ************************************
-
- Creates an NullPointerException for the SIGSEGV signal handler.
+ IN:
+ sfi....stackframeinfo of current method
*******************************************************************************/
-java_objectheader *stacktrace_hardware_nullpointerexception(u1 *pv, u1 *sp,
- u1 *ra, u1 *xpc)
+static inline void stacktrace_stack_walk(stackframeinfo_t *sfi)
{
- stackframeinfo sfi;
- java_objectheader *o;
+ codeinfo *code;
+ void *pv;
+ void *sp;
+ void *ra;
+ void *xpc;
+ uint32_t framesize;
- /* create stackframeinfo */
+ /* Get values from the stackframeinfo. */
- stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
-
- /* create exception */
-
- o = new_nullpointerexception();
-
- /* remove stackframeinfo */
-
- stacktrace_remove_stackframeinfo(&sfi);
-
- return o;
-}
+ code = sfi->code;
+ pv = sfi->pv;
+ sp = sfi->sp;
+ ra = sfi->ra;
+ xpc = sfi->xpc;
+ /* Get the current stack frame size. */
-/* stacktrace_inline_fillInStackTrace ******************************************
+ framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
- Fills in the correct stacktrace into an existing exception object
- (this one is for inline exception stubs).
+ /* Get the RA of the current stack frame (RA to the parent Java
+ method) if the current method is a non-leaf method. Otherwise
+ the value in the stackframeinfo is correct (from the signal
+ handler). */
-*******************************************************************************/
-
-java_objectheader *stacktrace_inline_fillInStackTrace(u1 *pv, u1 *sp, u1 *ra,
- u1 *xpc)
-{
- stackframeinfo sfi;
- java_objectheader *o;
- methodinfo *m;
-
- /* create stackframeinfo */
-
- stacktrace_create_inline_stackframeinfo(&sfi, pv, sp, ra, xpc);
-
- /* get exception */
-
- o = *exceptionptr;
-
- /* clear exception */
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+ if (opt_intrp)
+ ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
+ else
+# endif
+ {
+ if (!code_is_leafmethod(code))
+ ra = md_stacktrace_get_returnaddress(sp, framesize);
+ }
+#else
+ ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
+#endif
- *exceptionptr = NULL;
+ /* Get the PV for the parent Java method. */
- /* resolve methodinfo pointer from exception object */
+#if defined(ENABLE_INTRP)
+ if (opt_intrp)
+ pv = codegen_get_pv_from_pc(ra);
+ else
+#endif
+ {
+#if defined(ENABLE_JIT)
+# if defined(__SPARC_64__)
+ sp = md_get_framepointer(sp);
+ pv = md_get_pv_from_stackframe(sp);
+# else
+ pv = md_codegen_get_pv_from_pc(ra);
+# endif
+#endif
+ }
- m = class_resolvemethod(o->vftbl->class,
- utf_fillInStackTrace,
- utf_void__java_lang_Throwable);
+ /* Get the codeinfo pointer for the parent Java method. */
- /* call function */
+ code = code_get_codeinfo_for_pv(pv);
- asm_calljavafunction(m, o, NULL, NULL, NULL);
+ /* Calculate the SP for the parent Java method. */
- /* remove stackframeinfo */
+#if defined(ENABLE_INTRP)
+ if (opt_intrp)
+ sp = *(u1 **) (sp - framesize);
+ else
+#endif
+ {
+#if defined(__I386__) || defined (__X86_64__) || defined (__M68K__)
+ sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P);
+#elif defined(__SPARC_64__)
+ /* already has the new sp */
+#else
+ sp = (void *) (((intptr_t) sp) + framesize);
+#endif
+ }
- stacktrace_remove_stackframeinfo(&sfi);
+ /* Store the new values in the stackframeinfo. NOTE: We subtract
+ 1 from the RA to get the XPC, because the RA points to the
+ instruction after the call instruction. */
- return o;
+ sfi->code = code;
+ sfi->pv = pv;
+ sfi->sp = sp;
+ sfi->ra = ra;
+ sfi->xpc = (void *) (((intptr_t) ra) - 1);
}
-/* addEntry ********************************************************************
+/* stacktrace_create ***********************************************************
+
+ Generates a stacktrace from the thread passed into a
+ stacktracebuffer. The stacktracebuffer is allocated on the
+ dump memory.
+
+ NOTE: The first element in the stackframe chain must always be a
+ native stackframeinfo (e.g. VMThrowable.fillInStackTrace() is
+ a native function).
- XXX
+ RETURN VALUE:
+ pointer to the stacktracebuffer, or
+ NULL if there is no stacktrace available for the
+ given thread.
*******************************************************************************/
-static void addEntry(stackTraceBuffer *buffer, methodinfo *method, u2 line)
+stacktracebuffer *stacktrace_create(stackframeinfo_t *sfi)
{
- if (buffer->size > buffer->full) {
- stacktraceelement *tmp = &(buffer->start[buffer->full]);
+ stacktracebuffer *stb;
+ stackframeinfo_t tmpsfi;
- tmp->method = method;
- tmp->linenumber = line;
- buffer->full = buffer->full + 1;
+ /* Create a stacktracebuffer in dump memory. */
- } else {
- stacktraceelement *newBuffer;
+ stb = DNEW(stacktracebuffer);
- newBuffer =
- (stacktraceelement *) malloc((buffer->size + BLOCK_SIZEINCREMENT) *
- sizeof(stacktraceelement));
+ stb->capacity = STACKTRACE_CAPACITY_DEFAULT;
+ stb->used = 0;
- if (newBuffer == 0) {
- log_text("OOM during stacktrace creation");
- assert(0);
- }
-
- memcpy(newBuffer, buffer->start, buffer->size * sizeof(stacktraceelement));
- if (buffer->needsFree)
- free(buffer->start);
-
- buffer->start = newBuffer;
- buffer->size = buffer->size + BLOCK_SIZEINCREMENT;
- buffer->needsFree = 1;
-
- addEntry(buffer, method, line);
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace) {
+ printf("\n\n---> stacktrace creation start (fillInStackTrace):\n");
+ fflush(stdout);
}
-}
-
-
-/* stacktrace_fillInStackTrace_methodRecursive *********************************
-
- XXX
-
-*******************************************************************************/
-
-static bool stacktrace_fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,
- methodinfo *m,
- lineNumberTableEntry *lntentry,
- s4 lntsize,
- u1 *pc)
-{
-#if 0
- lineNumberTableEntryInlineBegin *lntinline;
#endif
- /* find the line number for the specified pc (going backwards) */
-
- for (; lntsize > 0; lntsize--, lntentry--) {
- /* did we reach the current line? */
-
- if (pc >= lntentry->pc) {
- /* check for special inline entries */
-
- switch (lntentry->line) {
-#if 0
- /* XXX TWISTI we have to think about this inline stuff again */
-
- case -1: /* begin of inlined method */
- lntinline = (lineNumberTableEntryInlineBegin *) (--lntentry);
- lntentry++;
- lntsize--; lntsize--;
- if (stacktrace_fillInStackTrace_methodRecursive(buffer,
- ilStart->method,
- ent,
- &ent,
- &ahead,
- pc)) {
- addEntry(buffer, m, ilStart->lineNrOuter);
-
- return true;
- }
- break;
+ /* Put the data from the stackframeinfo into a temporary one. */
- case -2: /* end of inlined method */
- *entry = ent;
- *entriesAhead = ahead;
- return false;
- break;
-#endif
+ /* XXX This is not correct, but a workaround for threads-dump for
+ now. */
+/* assert(sfi != NULL); */
+ if (sfi == NULL)
+ return NULL;
- default:
- addEntry(buffer, m, lntentry->line);
- return true;
- }
+ tmpsfi.code = sfi->code;
+ tmpsfi.pv = sfi->pv;
+ tmpsfi.sp = sfi->sp;
+ tmpsfi.ra = sfi->ra;
+ tmpsfi.xpc = sfi->xpc;
+
+ /* Iterate till we're done. */
+
+ for (;;) {
+#if !defined(NDEBUG)
+ /* Print current method information. */
+
+ if (opt_DebugStackTrace) {
+ log_start();
+ log_print("[stacktrace: method=%p, pv=%p, sp=%p, ra=%p, xpc=%p, method=",
+ tmpsfi.code->m, tmpsfi.pv, tmpsfi.sp, tmpsfi.ra,
+ tmpsfi.xpc);
+ method_print(tmpsfi.code->m);
+ log_print("]");
+ log_finish();
}
- }
-
- /* check if we are before the actual JIT code */
-
- if ((ptrint) pc < (ptrint) m->entrypoint) {
- dolog("Current pc before start of code: %p < %p", pc, m->entrypoint);
- assert(0);
- }
-
- /* otherwise just add line 0 */
-
- addEntry(buffer, m, 0);
-
- return true;
-}
+#endif
+ /* Check for Throwable.fillInStackTrace(). */
-/* stacktrace_fillInStackTrace_method ******************************************
+/* if (tmpsfi.method->name != utf_fillInStackTrace) { */
+
+ /* Add this method to the stacktrace. */
- XXX
+ stb = stacktrace_method_add(stb, &tmpsfi);
+/* } */
-*******************************************************************************/
+ /* Walk the stack (or the stackframeinfo chain) and get the
+ next method. */
-static void stacktrace_fillInStackTrace_method(stackTraceBuffer *buffer,
- methodinfo *method, u1 *pv,
- u1 *pc)
-{
- ptrint lntsize; /* size of line number table */
- u1 *lntstart; /* start of line number table */
- lineNumberTableEntry *lntentry; /* points to last entry in the table */
+ stacktrace_stack_walk(&tmpsfi);
- /* get size of line number table */
+ /* If the new codeinfo pointer is NULL we reached a
+ asm_vm_call_method function. In this case we get the next
+ values from the previous stackframeinfo in the chain.
+ Otherwise the new values have been calculated before. */
- lntsize = *((ptrint *) (pv + LineNumberTableSize));
- lntstart = *((u1 **) (pv + LineNumberTableStart));
-
- /* subtract the size of the line number entry of the structure, since the */
- /* line number table start points to the pc */
+ if (tmpsfi.code == NULL) {
+ sfi = sfi->prev;
- lntentry = (lineNumberTableEntry *) (lntstart - SIZEOF_VOID_P);
+ /* If the previous stackframeinfo in the chain is NULL we
+ reached the top of the stacktrace and leave the
+ loop. */
- if (lntsize == 0) {
- /* this happens when an exception is thrown in the native stub */
+ if (sfi == NULL)
+ break;
- addEntry(buffer, method, 0);
+ /* Fill the temporary stackframeinfo with the new
+ values. */
- } else {
- if (!stacktrace_fillInStackTrace_methodRecursive(buffer,
- method,
- lntentry,
- lntsize,
- pc)) {
- log_text("Trace point not found in suspected method");
- assert(0);
+ tmpsfi.code = sfi->code;
+ tmpsfi.pv = sfi->pv;
+ tmpsfi.sp = sfi->sp;
+ tmpsfi.ra = sfi->ra;
+ tmpsfi.xpc = sfi->xpc;
}
}
-}
-
-
-/* cacao_stacktrace_fillInStackTrace *******************************************
- XXX
-
-*******************************************************************************/
-#ifdef ENABLE_JVMTI
-bool cacao_stacktrace_fillInStackTrace(void **target,
- CacaoStackTraceCollector coll,
- threadobject* thread)
-#else
-static bool cacao_stacktrace_fillInStackTrace(void **target,
- CacaoStackTraceCollector coll)
+#if !defined(NDEBUG)
+ if (opt_DebugStackTrace) {
+ printf("---> stacktrace creation finished.\n\n");
+ fflush(stdout);
+ }
#endif
-{
- stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)];
- stackTraceBuffer buffer;
- stackframeinfo *sfi;
- methodinfo *m;
- u1 *pv;
- u1 *sp;
- u4 framesize;
- u1 *ra;
- u1 *xpc;
- bool result;
-
- /* prevent compiler warnings */
-
- pv = NULL;
- sp = NULL;
- ra = NULL;
+ /* return the stacktracebuffer */
- /* In most cases this should be enough -> one malloc less. I don't think */
- /* temporary data should be allocated with the GC, only the result. */
-
- buffer.needsFree = 0;
- buffer.start = primaryBlock;
- buffer.size = BLOCK_INITIALSIZE; /* *sizeof(stacktraceelement); */
- buffer.full = 0;
-
- /* the first element in the stackframe chain must always be a native */
- /* stackframeinfo (VMThrowable.fillInStackTrace is a native function) */
-
-#ifdef ENABLE_JVMTI
- if (thread == NULL)
- sfi = *STACKFRAMEINFO; /* invocation from Throwable */
+ if (stb->used == 0)
+ return NULL;
else
- sfi = thread->info._stackframeinfo; /* invocation from JVMTI */
-#else
- sfi = *STACKFRAMEINFO;
-#endif
+ return stb;
+}
- if (!sfi) {
- *target = NULL;
- return true;
- }
-#define PRINTMETHODS 0
+/* stacktrace_fillInStackTrace *************************************************
-#if PRINTMETHODS
- printf("\n\nfillInStackTrace start:\n");
- fflush(stdout);
-#endif
+ Generate a stacktrace from the current thread for
+ java.lang.VMThrowable.fillInStackTrace.
- /* loop while we have a method pointer (asm_calljavafunction has NULL) or */
- /* there is a stackframeinfo in the chain */
+*******************************************************************************/
- m = NULL;
+java_handle_bytearray_t *stacktrace_fillInStackTrace(void)
+{
+ stacktracebuffer *stb;
+ java_handle_bytearray_t *ba;
+ s4 ba_size;
+ s4 dumpsize;
+ CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD
- while (m || sfi) {
- /* m == NULL should only happen for the first time and inline */
- /* stackframe infos, like from the exception stubs or the patcher */
- /* wrapper */
+ /* mark start of dump memory area */
- if (m == NULL) {
- /* for native stub stackframe infos, pv is always NULL */
+ dumpsize = dump_size();
- if (sfi->pv == NULL) {
- /* get methodinfo, sp and ra from the current stackframe info */
+ /* create a stacktrace from the current thread */
- m = sfi->method;
- sp = sfi->sp; /* sp of parent Java function */
- ra = sfi->ra;
+ stb = stacktrace_create(STACKFRAMEINFO);
- if (m)
- addEntry(&buffer, m, 0);
+ if (stb == NULL)
+ goto return_NULL;
-#if PRINTMETHODS
- printf("ra=%p sp=%p, ", ra, sp);
- utf_display_classname(m->class->name);
- printf(".");
- utf_display(m->name);
- utf_display(m->descriptor);
- printf(": native stub\n");
- fflush(stdout);
-#endif
- /* this is an native stub stackframe info, so we can get the */
- /* parent pv from the return address (ICMD_INVOKE*) */
+ /* allocate memory from the GC heap and copy the stacktrace buffer */
+ /* ATTENTION: use a bytearray for this to not confuse the GC */
-#if defined(ENABLE_INTRP)
- if (opt_intrp)
- pv = codegen_findmethod(ra);
- else
-#endif
- {
-#if defined(ENABLE_JIT)
- pv = md_codegen_findmethod(ra);
-#endif
- }
+ ba_size = sizeof(stacktracebuffer) +
+ sizeof(stacktrace_entry) * stb->used -
+ sizeof(stacktrace_entry) * STACKTRACE_CAPACITY_DEFAULT;
+ ba = builtin_newarray_byte(ba_size);
- /* get methodinfo pointer from parent data segment */
+ if (ba == NULL)
+ goto return_NULL;
- m = *((methodinfo **) (pv + MethodPointer));
+ MCOPY(LLNI_array_data(ba), stb, u1, ba_size);
- } else {
- /* Inline stackframe infos are special: they have a xpc of */
- /* the actual exception position and the return address saved */
- /* since an inline stackframe info can also be in a leaf */
- /* method (no return address saved on stack!!!). */
- /* ATTENTION: This one is also for hardware exceptions!!! */
+ /* release dump memory */
- /* get methodinfo, sp and ra from the current stackframe info */
+ dump_release(dumpsize);
- m = sfi->method; /* m == NULL */
- pv = sfi->pv; /* pv of parent Java function */
- sp = sfi->sp; /* sp of parent Java function */
- ra = sfi->ra; /* ra of parent Java function */
- xpc = sfi->xpc; /* actual exception position */
+ CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
+ stacktrace_overhead)
+ return ba;
-#if PRINTMETHODS
- printf("ra=%p sp=%p, ", ra, sp);
- printf("NULL: inline stub\n");
- fflush(stdout);
-#endif
+return_NULL:
+ dump_release(dumpsize);
- /* get methodinfo from current Java method */
+ CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
+ stacktrace_overhead)
- m = *((methodinfo **) (pv + MethodPointer));
+ return NULL;
+}
- /* if m == NULL, this is a asm_calljavafunction call */
- if (m != NULL) {
-#if PRINTMETHODS
- printf("ra=%p sp=%p, ", ra, sp);
- utf_display_classname(m->class->name);
- printf(".");
- utf_display(m->name);
- utf_display(m->descriptor);
- printf(": inline stub parent");
- fflush(stdout);
-#endif
+/* stacktrace_getClassContext **************************************************
-#if defined(ENABLE_INTRP)
- if (!opt_intrp) {
-#endif
+ Creates a Class context array.
- /* add it to the stacktrace */
+ RETURN VALUE:
+ the array of java.lang.Class objects, or
+ NULL if an exception has been thrown
- stacktrace_fillInStackTrace_method(&buffer, m, pv,
- (u1 *) ((ptrint) xpc));
+*******************************************************************************/
- /* get the current stack frame size */
+java_handle_objectarray_t *stacktrace_getClassContext(void)
+{
+ stacktracebuffer *stb;
+ stacktrace_entry *ste;
+ java_handle_objectarray_t *oa;
+ s4 oalength;
+ s4 i;
+ s4 dumpsize;
+ CYCLES_STATS_DECLARE_AND_START
- framesize = *((u4 *) (pv + FrameSize));
+ /* mark start of dump memory area */
-#if PRINTMETHODS
- printf(", framsize=%d\n", framesize);
- fflush(stdout);
-#endif
+ dumpsize = dump_size();
- /* set stack pointer to stackframe of parent Java */
- /* function of the current Java function */
+ /* create a stacktrace for the current thread */
-#if defined(__I386__) || defined (__X86_64__)
- sp += framesize + SIZEOF_VOID_P;
-#else
- sp += framesize;
-#endif
+ stb = stacktrace_create(STACKFRAMEINFO);
- /* get data segment and methodinfo pointer from parent */
- /* method */
+ if (stb == NULL)
+ goto return_NULL;
-#if defined(ENABLE_JIT)
- pv = md_codegen_findmethod(ra);
-#endif
+ /* calculate the size of the Class array */
- m = *((methodinfo **) (pv + MethodPointer));
+ for (i = 0, oalength = 0; i < stb->used; i++)
+ if (stb->entries[i].method != NULL)
+ oalength++;
-#if defined(ENABLE_INTRP)
- }
-#endif
- }
-#if PRINTMETHODS
- else {
- printf("ra=%p sp=%p, ", ra, sp);
- printf("asm_calljavafunction\n");
- fflush(stdout);
- }
-#endif
- }
-
- /* get previous stackframeinfo in the chain */
+ /* The first entry corresponds to the method whose implementation */
+ /* calls stacktrace_getClassContext. We remove that entry. */
- sfi = sfi->prev;
-
- } else {
-#if PRINTMETHODS
- printf("ra=%p sp=%p, ", ra, sp);
- utf_display_classname(m->class->name);
- printf(".");
- utf_display(m->name);
- utf_display(m->descriptor);
- printf(": JIT");
- fflush(stdout);
-#endif
+ ste = &(stb->entries[0]);
+ ste++;
+ oalength--;
- /* JIT method found, add it to the stacktrace (we subtract 1 from */
- /* the return address since it points the the instruction after */
- /* call) */
+ /* allocate the Class array */
- stacktrace_fillInStackTrace_method(&buffer, m, pv,
- (u1 *) ((ptrint) ra) - 1);
+ oa = builtin_anewarray(oalength, class_java_lang_Class);
+ if (!oa)
+ goto return_NULL;
- /* get the current stack frame size */
+ /* fill the Class array from the stacktracebuffer */
- framesize = *((u4 *) (pv + FrameSize));
+ for(i = 0; i < oalength; i++, ste++) {
+ if (ste->method == NULL) {
+ i--;
+ continue;
+ }
-#if PRINTMETHODS
- printf(", framsize=%d\n", framesize);
- fflush(stdout);
-#endif
+ LLNI_array_direct(oa, i) = (java_object_t *) ste->method->class;
+ }
- /* get return address of current stack frame */
+ /* release dump memory */
- ra = md_stacktrace_get_returnaddress(sp, framesize);
+ dump_release(dumpsize);
- /* get data segment and methodinfo pointer from parent method */
+ CYCLES_STATS_END(stacktrace_getClassContext)
-#if defined(ENABLE_INTRP)
- if (opt_intrp)
- pv = codegen_findmethod(ra);
- else
-#endif
- {
-#if defined(ENABLE_JIT)
- pv = md_codegen_findmethod(ra);
-#endif
- }
+ return oa;
- m = *((methodinfo **) (pv + MethodPointer));
+return_NULL:
+ dump_release(dumpsize);
- /* walk the stack */
+ CYCLES_STATS_END(stacktrace_getClassContext)
-#if defined(ENABLE_INTRP)
- if (opt_intrp)
- sp = *(u1 **)(sp - framesize);
- else
-#endif
- {
-#if defined(__I386__) || defined (__X86_64__)
- sp += framesize + SIZEOF_VOID_P;
-#else
- sp += framesize;
-#endif
- }
- }
- }
-
- if (coll)
- result = coll(target, &buffer);
-
- if (buffer.needsFree)
- free(buffer.start);
-
- return result;
+ return NULL;
}
-/* stackTraceCollector *********************************************************
+/* stacktrace_getCurrentClass **************************************************
- XXX
+ Find the current class by walking the stack trace.
+
+ Quote from the JNI documentation:
+
+ In the Java 2 Platform, FindClass locates the class loader
+ associated with the current native method. If the native code
+ belongs to a system class, no class loader will be
+ involved. Otherwise, the proper class loader will be invoked to
+ load and link the named class. When FindClass is called through the
+ Invocation Interface, there is no current native method or its
+ associated class loader. In that case, the result of
+ ClassLoader.getBaseClassLoader is used."
*******************************************************************************/
-#ifdef ENABLE_JVMTI
-bool stackTraceCollector(void **target, stackTraceBuffer *buffer)
-#else
-static bool stackTraceCollector(void **target, stackTraceBuffer *buffer)
-#endif
+
+#if defined(ENABLE_JAVASE)
+classinfo *stacktrace_getCurrentClass(void)
{
- stackTraceBuffer *dest;
+ stacktracebuffer *stb;
+ stacktrace_entry *ste;
+ methodinfo *m;
+ s4 i;
+ s4 dumpsize;
+ CYCLES_STATS_DECLARE_AND_START
- dest = *target = heap_allocate(sizeof(stackTraceBuffer) + buffer->full * sizeof(stacktraceelement), true, 0);
+ /* mark start of dump memory area */
- if (!dest)
- return false;
+ dumpsize = dump_size();
- memcpy(*target, buffer, sizeof(stackTraceBuffer));
- memcpy(dest + 1, buffer->start, buffer->full * sizeof(stacktraceelement));
+ /* create a stacktrace for the current thread */
- dest->needsFree = 0;
- dest->size = dest->full;
- dest->start = (stacktraceelement *) (dest + 1);
+ stb = stacktrace_create(STACKFRAMEINFO);
- return true;
-}
+ if (stb == NULL)
+ goto return_NULL; /* XXX exception: how to distinguish from normal NULL return? */
+ /* iterate over all stacktrace entries and find the first suitable
+ class */
-bool cacao_stacktrace_NormalTrace(void **target)
-{
-#ifdef ENABLE_JVMTI
- return cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector, NULL);
-#else
- return cacao_stacktrace_fillInStackTrace(target, &stackTraceCollector);
-#endif
-
-}
-
+ for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
+ m = ste->method;
+ if (m == NULL)
+ continue;
-static bool classContextCollector(void **target, stackTraceBuffer *buffer)
-{
- java_objectarray *oa;
- stacktraceelement *current;
- stacktraceelement *start;
- size_t size;
- size_t targetSize;
- s4 i;
-
- size = buffer->full;
- targetSize = 0;
-
- for (i = 0; i < size; i++)
- if (buffer->start[i].method != 0)
- targetSize++;
-
- start = buffer->start;
- start++;
- targetSize--;
-
- if (targetSize > 0) {
- if (start->method &&
- (start->method->class == class_java_lang_SecurityManager)) {
- targetSize--;
- start++;
- }
- }
+ if (m->class == class_java_security_PrivilegedAction)
+ goto return_NULL;
- oa = builtin_anewarray(targetSize, class_java_lang_Class);
+ if (m->class != NULL) {
+ dump_release(dumpsize);
- if (!oa)
- return false;
+ CYCLES_STATS_END(stacktrace_getCurrentClass)
- for(i = 0, current = start; i < targetSize; i++, current++) {
- if (!current->method) {
- i--;
- continue;
+ return m->class;
}
-
- oa->data[i] = (java_objectheader *) current->method->class;
}
- *target = oa;
-
- return true;
-}
-
-
+ /* no Java method found on the stack */
-java_objectarray *cacao_createClassContextArray(void)
-{
- java_objectarray *array = NULL;
+return_NULL:
+ dump_release(dumpsize);
-#ifdef ENABLE_JVMTI
- if (!cacao_stacktrace_fillInStackTrace((void **) &array,
- &classContextCollector, NULL))
-#else
- if (!cacao_stacktrace_fillInStackTrace((void **) &array,
- &classContextCollector))
-#endif
- return NULL;
+ CYCLES_STATS_END(stacktrace_getCurrentClass)
- return array;
+ return NULL;
}
+#endif /* ENABLE_JAVASE */
-/* stacktrace_classLoaderCollector *********************************************
+/* stacktrace_getStack *********************************************************
- XXX
+ Create a 2-dimensional array for java.security.VMAccessControler.
+
+ RETURN VALUE:
+ the arrary, or
+ NULL if an exception has been thrown
*******************************************************************************/
-static bool stacktrace_classLoaderCollector(void **target,
- stackTraceBuffer *buffer)
+#if defined(ENABLE_JAVASE)
+java_handle_objectarray_t *stacktrace_getStack(void)
{
- stacktraceelement *current;
- stacktraceelement *start;
- methodinfo *m;
- ptrint size;
- s4 i;
-
- size = buffer->full;
- start = &(buffer->start[0]);
-
- for(i = 0, current = start; i < size; i++, current++) {
- m = current->method;
-
- if (!m)
- continue;
-
- if (m->class == class_java_security_PrivilegedAction) {
- *target = NULL;
- return true;
- }
-
- if (m->class->classloader) {
- *target = (java_lang_ClassLoader *) m->class->classloader;
- return true;
- }
- }
-
- *target = NULL;
-
- return true;
-}
+ stacktracebuffer *stb;
+ stacktrace_entry *ste;
+ java_handle_objectarray_t *oa;
+ java_handle_objectarray_t *classes;
+ java_handle_objectarray_t *methodnames;
+ classinfo *c;
+ java_handle_t *string;
+ s4 i;
+ s4 dumpsize;
+ CYCLES_STATS_DECLARE_AND_START
+ /* mark start of dump memory area */
-/* cacao_currentClassLoader ****************************************************
+ dumpsize = dump_size();
- XXX
+ /* create a stacktrace for the current thread */
-*******************************************************************************/
+ stb = stacktrace_create(STACKFRAMEINFO);
-java_objectheader *cacao_currentClassLoader(void)
-{
- java_objectheader *header = NULL;
+ if (stb == NULL)
+ goto return_NULL;
+ /* get the first stacktrace entry */
-#ifdef ENABLE_JVMTI
- if (!cacao_stacktrace_fillInStackTrace((void**)&header,
- &stacktrace_classLoaderCollector,
- NULL))
-#else
- if (!cacao_stacktrace_fillInStackTrace((void**)&header,
- &stacktrace_classLoaderCollector))
-#endif
- return NULL;
-
- return header;
-}
+ ste = &(stb->entries[0]);
+ /* allocate all required arrays */
-static bool getStackCollector(void **target, stackTraceBuffer *buffer)
-{
- java_objectarray *oa;
- java_objectarray *classes;
- java_objectarray *methodnames;
- java_lang_String *str;
- classinfo *c;
- stacktraceelement *current;
- s4 i, size;
+ oa = builtin_anewarray(2, arrayclass_java_lang_Object);
-/* *result = (java_objectarray **) target; */
+ if (oa == NULL)
+ goto return_NULL;
- size = buffer->full;
+ classes = builtin_anewarray(stb->used, class_java_lang_Class);
- oa = builtin_anewarray(2, arrayclass_java_lang_Object);
+ if (classes == NULL)
+ goto return_NULL;
- if (!oa)
- return false;
+ methodnames = builtin_anewarray(stb->used, class_java_lang_String);
- classes = builtin_anewarray(size, class_java_lang_Class);
+ if (methodnames == NULL)
+ goto return_NULL;
- if (!classes)
- return false;
+ /* set up the 2-dimensional array */
- methodnames = builtin_anewarray(size, class_java_lang_String);
+ array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
+ array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
- if (!methodnames)
- return false;
+ /* iterate over all stacktrace entries */
- oa->data[0] = (java_objectheader *) classes;
- oa->data[1] = (java_objectheader *) methodnames;
+ for (i = 0, ste = &(stb->entries[0]); i < stb->used; i++, ste++) {
+ c = ste->method->class;
- for (i = 0, current = &(buffer->start[0]); i < size; i++, current++) {
- c = current->method->class;
+ LLNI_array_direct(classes, i) = (java_object_t *) c;
- classes->data[i] = (java_objectheader *) c;
- str = javastring_new(current->method->name);
+ string = javastring_new(ste->method->name);
- if (!str)
- return false;
+ if (string == NULL)
+ goto return_NULL;
- methodnames->data[i] = (java_objectheader *) str;
+ array_objectarray_element_set(methodnames, i, string);
}
- *target = oa;
+ /* return the 2-dimensional array */
- return true;
-}
+ dump_release(dumpsize);
+ CYCLES_STATS_END(stacktrace_getStack)
-java_objectarray *cacao_getStackForVMAccessController(void)
-{
- java_objectarray *result = NULL;
+ return oa;
-#ifdef ENABLE_JVMTI
- if (!cacao_stacktrace_fillInStackTrace((void **) &result,
- &getStackCollector,NULL))
-#else
- if (!cacao_stacktrace_fillInStackTrace((void **) &result,
- &getStackCollector))
-#endif
- return NULL;
+return_NULL:
+ dump_release(dumpsize);
- return result;
+ CYCLES_STATS_END(stacktrace_getStack)
+
+ return NULL;
}
+#endif /* ENABLE_JAVASE */
/* stacktrace_print_trace_from_buffer ******************************************
- Print the stacktrace of a given stackTraceBuffer with CACAO intern
+ Print the stacktrace of a given stacktracebuffer with CACAO intern
methods (no Java help). This method is used by
stacktrace_dump_trace and builtin_trace_exception.
*******************************************************************************/
-static void stacktrace_print_trace_from_buffer(stackTraceBuffer *stb)
+void stacktrace_print_trace_from_buffer(stacktracebuffer *stb)
{
- stacktraceelement *ste;
- methodinfo *m;
- s4 i;
+ stacktrace_entry *ste;
+ methodinfo *m;
+ s4 i;
- ste = stb->start;
+ ste = &(stb->entries[0]);
- for (i = 0; i < stb->size; i++, ste++) {
+ for (i = 0; i < stb->used; i++, ste++) {
m = ste->method;
printf("\tat ");
- utf_display_classname(m->class->name);
+ utf_display_printable_ascii_classname(m->class->name);
printf(".");
- utf_display(m->name);
- utf_display(m->descriptor);
+ utf_display_printable_ascii(m->name);
+ utf_display_printable_ascii(m->descriptor);
if (m->flags & ACC_NATIVE) {
puts("(Native Method)");
} else {
printf("(");
- utf_display(m->class->sourcefile);
+ utf_display_printable_ascii(m->class->sourcefile);
printf(":%d)\n", (u4) ste->linenumber);
}
}
}
-/* stacktrace_dump_trace *******************************************************
+/* stacktrace_print_trace ******************************************************
- This method is call from signal_handler_sigusr1 to dump the
- stacktrace of the current thread to stdout.
+ Print the stacktrace of a given exception. More or less a wrapper
+ to stacktrace_print_trace_from_buffer.
*******************************************************************************/
-void stacktrace_dump_trace(void)
+void stacktrace_print_trace(java_handle_t *xptr)
{
- stackTraceBuffer *buffer;
-
-#if 0
- /* get thread stackframeinfo */
+ java_lang_Throwable *t;
+#if defined(WITH_CLASSPATH_GNU)
+ java_lang_VMThrowable *vmt;
+#endif
+ java_handle_bytearray_t *ba;
+ stacktracebuffer *stb;
- info = &THREADINFO->_stackframeinfo;
+ t = (java_lang_Throwable *) xptr;
- /* fill stackframeinfo structure */
+ if (t == NULL)
+ return;
- tmp.oldThreadspecificHeadValue = *info;
- tmp.addressOfThreadspecificHead = info;
- tmp.method = NULL;
- tmp.sp = NULL;
- tmp.ra = _mc->gregs[REG_RIP];
+ /* now print the stacktrace */
- *info = &tmp;
+#if defined(WITH_CLASSPATH_GNU)
+ LLNI_field_get_ref(t, vmState, vmt);
+ LLNI_field_get_ref(vmt, vmData, ba);
+#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
+ LLNI_field_get_ref(t, backtrace, ba);
+#else
+# error unknown classpath configuration
#endif
- /* generate stacktrace */
-
- cacao_stacktrace_NormalTrace((void **) &buffer);
-
- /* print stacktrace */
-
- if (buffer) {
- stacktrace_print_trace_from_buffer(buffer);
+ assert(ba);
+ stb = (stacktracebuffer *) LLNI_array_data(ba);
- } else {
- puts("\t<<No stacktrace available>>");
- fflush(stdout);
- }
+ stacktrace_print_trace_from_buffer(stb);
}
-/* stacktrace_print_trace ******************************************************
-
- Print the stacktrace of a given exception. More or less a wrapper
- to stacktrace_print_trace_from_buffer.
-
-*******************************************************************************/
-
-void stacktrace_print_trace(java_objectheader *xptr)
+#if defined(ENABLE_CYCLES_STATS)
+void stacktrace_print_cycles_stats(FILE *file)
{
- java_lang_Throwable *t;
- java_lang_VMThrowable *vmt;
- stackTraceBuffer *stb;
-
- t = (java_lang_Throwable *) xptr;
-
- /* now print the stacktrace */
-
- vmt = t->vmState;
- stb = (stackTraceBuffer *) vmt->vmData;
-
- stacktrace_print_trace_from_buffer(stb);
+ CYCLES_STATS_PRINT_OVERHEAD(stacktrace_overhead,file);
+ CYCLES_STATS_PRINT(stacktrace_fillInStackTrace,file);
+ CYCLES_STATS_PRINT(stacktrace_getClassContext ,file);
+ CYCLES_STATS_PRINT(stacktrace_getCurrentClass ,file);
+ CYCLES_STATS_PRINT(stacktrace_getStack ,file);
}
+#endif
/*
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/