#include "toolbox/logging.h"
+#include "vm/array.h"
#include "vm/builtin.h"
#include "vm/cycles-stats.h"
#include "vm/exceptions.h"
#include "vm/jit/asmpart.h"
#include "vm/jit/codegen-common.h"
+#include "vm/jit/linenumbertable.h"
#include "vm/jit/methodheader.h"
#include "vmcore/class.h"
/* global variables ***********************************************************/
#if !defined(ENABLE_THREADS)
-stackframeinfo *_no_threads_stackframeinfo = NULL;
+stackframeinfo_t *_no_threads_stackframeinfo = NULL;
#endif
CYCLES_STATS_DECLARE(stacktrace_overhead ,100,1)
CYCLES_STATS_DECLARE(stacktrace_getStack ,40,10000)
-/* stacktrace_create_stackframeinfo ********************************************
+/* stacktrace_stackframeinfo_add ***********************************************
- Creates an stackframe info structure for inline code in the
- interpreter.
+ Fills a stackframe info structure with the given or calculated
+ values and adds it to the chain.
*******************************************************************************/
-#if defined(ENABLE_INTRP)
-void stacktrace_create_stackframeinfo(stackframeinfo *sfi, u1 *pv, u1 *sp,
- u1 *ra)
-{
- stackframeinfo **psfi;
- methodinfo *m;
- codeinfo *code;
-
- /* 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_get_pv_from_pc(ra);
- else
-#endif
- {
-#if defined(ENABLE_JIT)
- pv = md_codegen_get_pv_from_pc(ra);
-#endif
- }
- }
-
- /* get codeinfo pointer from data segment */
-
- code = *((codeinfo **) (pv + CodeinfoPointer));
-
- /* For asm_vm_call_method the codeinfo pointer is NULL. */
-
- m = (code == NULL) ? NULL : code->m;
-
- /* fill new stackframe info structure */
-
- 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 stacktrace_create */
-
- sfi->xpc = ra;
-
- /* store new stackframe info pointer */
-
- *psfi = sfi;
-}
-#endif /* defined(ENABLE_INTRP) */
-
-
-/* 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)
+void stacktrace_stackframeinfo_add(stackframeinfo_t *sfi, u1 *pv, u1 *sp, u1 *ra, u1 *xpc)
{
- stackframeinfo **psfi;
- methodinfo *m;
+ stackframeinfo_t **psfi;
+ codeinfo *code;
#if !defined(__I386__) && !defined(__X86_64__) && !defined(__S390__) && !defined(__M68K__)
- bool isleafmethod;
+ bool isleafmethod;
#endif
#if defined(ENABLE_JIT)
- s4 framesize;
+ s4 framesize;
#endif
/* get current stackframe info pointer */
}
}
- /* Get methodinfo pointer for the parent Java method. */
+ /* Get codeinfo pointer for the parent Java method. */
- m = code_get_methodinfo_for_pv(pv);
+ code = code_get_codeinfo_for_pv(pv);
/* XXX */
/* assert(m != NULL); */
/* Fill new stackframeinfo structure. */
- sfi->prev = *psfi;
- sfi->method = m;
- sfi->pv = pv;
- sfi->sp = sp;
- sfi->ra = ra;
- sfi->xpc = xpc;
+ 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 stackframeinfo pointer. */
}
-/* stacktrace_remove_stackframeinfo ********************************************
+/* stacktrace_stackframeinfo_remove ********************************************
- Remove the topmost stackframeinfo in the current thread.
+ Remove the given stackframeinfo from the chain in the current
+ thread.
*******************************************************************************/
-void stacktrace_remove_stackframeinfo(stackframeinfo *sfi)
+void stacktrace_stackframeinfo_remove(stackframeinfo_t *sfi)
{
- stackframeinfo **psfi;
+ stackframeinfo_t **psfi;
/* clear the native world flag for the current thread */
/* ATTENTION: Clear this flag _before_ removing the stackframe info */
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 */
*psfi = sfi->prev;
*******************************************************************************/
-static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo *sfi)
+static inline stacktracebuffer *stacktrace_method_add(stacktracebuffer *stb, stackframeinfo_t *sfi)
{
- methodinfo *m;
+ codeinfo *code;
void *pv;
void *xpc;
+ methodinfo *m;
int32_t linenumber;
/* Get values from the stackframeinfo. */
- m = sfi->method;
- pv = sfi->pv;
- xpc = sfi->xpc;
+ code = sfi->code;
+ pv = sfi->pv;
+ xpc = sfi->xpc;
+
+ m = code->m;
/* Skip builtin methods. */
/* Search the line number table. */
- linenumber = dseg_get_linenumber_from_pc(&m, pv, xpc);
+ linenumber = linenumbertable_linenumber_for_pc(&m, code, xpc);
/* Add a new entry to the staktrace. */
Walk the stack (or the stackframeinfo-chain) to the next method.
IN:
- sfi....stackframeinfo of current method
+ tmpsfi ... stackframeinfo of current method
+
+ RETURN:
+ true .... the sfi is filled with the new values
+ false ... we reached the top of the stacktrace
*******************************************************************************/
-static inline void stacktrace_stack_walk(stackframeinfo *sfi)
+static inline bool stacktrace_stack_walk(stackframeinfo_t *tmpsfi)
{
- methodinfo *m;
- void *pv;
- void *sp;
- void *ra;
- void *xpc;
- uint32_t framesize;
+ codeinfo *code;
+ void *pv;
+ void *sp;
+ void *ra;
+ void *xpc;
+ uint32_t framesize;
+ stackframeinfo_t *prevsfi;
/* Get values from the stackframeinfo. */
- m = sfi->method;
- pv = sfi->pv;
- sp = sfi->sp;
- ra = sfi->ra;
- xpc = sfi->xpc;
+ code = tmpsfi->code;
+ pv = tmpsfi->pv;
+ sp = tmpsfi->sp;
+ ra = tmpsfi->ra;
+ xpc = tmpsfi->xpc;
/* Get the current stack frame size. */
framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize));
/* Get the RA of the current stack frame (RA to the parent Java
- method). */
+ method) if the current method is a non-leaf method. Otherwise
+ the value in the stackframeinfo is correct (from the signal
+ handler). */
#if defined(ENABLE_JIT)
# if defined(ENABLE_INTRP)
ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
else
# endif
- ra = md_stacktrace_get_returnaddress(sp, framesize);
+ {
+ if (!code_is_leafmethod(code))
+ ra = md_stacktrace_get_returnaddress(sp, framesize);
+ }
#else
ra = intrp_md_stacktrace_get_returnaddress(sp, framesize);
#endif
#endif
}
- /* Get the methodinfo pointer for the parent Java method. */
+ /* Get the codeinfo pointer for the parent Java method. */
- m = code_get_methodinfo_for_pv(pv);
+ code = code_get_codeinfo_for_pv(pv);
/* Calculate the SP for the parent Java method. */
#endif
}
- /* 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. */
+ /* 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. */
+
+ if (code == NULL) {
+ prevsfi = tmpsfi->prev;
- sfi->method = m;
- sfi->pv = pv;
- sfi->sp = sp;
- sfi->ra = ra;
- sfi->xpc = (void *) (((intptr_t) ra) - 1);
+ /* If the previous stackframeinfo in the chain is NULL we
+ reached the top of the stacktrace and return false. */
+
+ if (prevsfi == NULL)
+ return false;
+
+ /* Fill the temporary stackframeinfo with the new values. */
+
+ tmpsfi->code = prevsfi->code;
+ tmpsfi->pv = prevsfi->pv;
+ tmpsfi->sp = prevsfi->sp;
+ tmpsfi->ra = prevsfi->ra;
+ tmpsfi->xpc = prevsfi->xpc;
+
+ /* Set the previous stackframe info of the temporary one to
+ the next in the chain. */
+
+ tmpsfi->prev = prevsfi->prev;
+ }
+ else {
+ /* 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. */
+
+ tmpsfi->code = code;
+ tmpsfi->pv = pv;
+ tmpsfi->sp = sp;
+ tmpsfi->ra = ra;
+ tmpsfi->xpc = (void *) (((intptr_t) ra) - 1);
+ }
+
+ return true;
}
*******************************************************************************/
-stacktracebuffer *stacktrace_create(stackframeinfo *sfi)
+stacktracebuffer *stacktrace_create(stackframeinfo_t *sfi)
{
stacktracebuffer *stb;
- stackframeinfo tmpsfi;
+ stackframeinfo_t tmpsfi;
+ bool skip_fillInStackTrace;
+ bool skip_init;
+
+ skip_fillInStackTrace = true;
+ skip_init = true;
/* Create a stacktracebuffer in dump memory. */
if (sfi == NULL)
return NULL;
- tmpsfi.method = sfi->method;
- tmpsfi.pv = sfi->pv;
- tmpsfi.sp = sfi->sp;
- tmpsfi.ra = sfi->ra;
- tmpsfi.xpc = sfi->xpc;
+ tmpsfi.code = sfi->code;
+ tmpsfi.pv = sfi->pv;
+ tmpsfi.sp = sfi->sp;
+ tmpsfi.ra = sfi->ra;
+ tmpsfi.xpc = sfi->xpc;
+
+ /* Initially set the previous stackframe info of the temporary one
+ to the next in the chain. */
+
+ tmpsfi.prev = sfi->prev;
/* Iterate till we're done. */
- for (;;) {
+ do {
#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.method, tmpsfi.pv, tmpsfi.sp, tmpsfi.ra,
+ tmpsfi.code->m, tmpsfi.pv, tmpsfi.sp, tmpsfi.ra,
tmpsfi.xpc);
- method_print(tmpsfi.method);
+ method_print(tmpsfi.code->m);
log_print("]");
log_finish();
}
#endif
- /* Check for Throwable.fillInStackTrace(). */
+ /* This logic is taken from
+ hotspot/src/share/vm/classfile/javaClasses.cpp
+ (java_lang_Throwable::fill_in_stack_trace). */
-/* if (tmpsfi.method->name != utf_fillInStackTrace) { */
-
- /* Add this method to the stacktrace. */
+ if (skip_fillInStackTrace == true) {
+ /* Check "fillInStackTrace" only once, so we negate the
+ flag after the first time check. */
- stb = stacktrace_method_add(stb, &tmpsfi);
-/* } */
+#if defined(WITH_CLASSPATH_GNU)
+ /* For GNU Classpath we also need to skip
+ VMThrowable.fillInStackTrace(). */
- /* Walk the stack (or the stackframeinfo chain) and get the
- next method. */
+ if ((tmpsfi.code->m->class == class_java_lang_VMThrowable) &&
+ (tmpsfi.code->m->name == utf_fillInStackTrace))
+ continue;
+#endif
- stacktrace_stack_walk(&tmpsfi);
+ skip_fillInStackTrace = false;
- /* If the new methodinfo 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. */
+ if (tmpsfi.code->m->name == utf_fillInStackTrace)
+ continue;
+ }
- if (tmpsfi.method == NULL) {
- sfi = sfi->prev;
+ /* Skip <init> methods of the exceptions klass. If there is
+ <init> methods that belongs to a superclass of the
+ exception we are going to skipping them in stack trace. */
- /* If the previous stackframeinfo in the chain is NULL we
- reached the top of the stacktrace and leave the
- loop. */
+ if (skip_init == true) {
+ if (tmpsfi.code->m->name == utf_init) {
+/* throwable->is_a(method->method_holder())) { */
+ continue;
+ }
+ else {
+ /* If no "Throwable.init()" method found, we stop
+ checking it next time. */
- if (sfi == NULL)
- break;
+ skip_init = false;
+ }
+ }
- /* Fill the temporary stackframeinfo with the new
- values. */
+ /* Add this method to the stacktrace. */
- tmpsfi.method = sfi->method;
- tmpsfi.pv = sfi->pv;
- tmpsfi.sp = sfi->sp;
- tmpsfi.ra = sfi->ra;
- tmpsfi.xpc = sfi->xpc;
- }
- }
+ stb = stacktrace_method_add(stb, &tmpsfi);
+ } while (stacktrace_stack_walk(&tmpsfi) == true);
#if !defined(NDEBUG)
if (opt_DebugStackTrace) {
/* set up the 2-dimensional array */
- LLNI_objectarray_element_set(oa, 0, classes);
- LLNI_objectarray_element_set(oa, 1, methodnames);
+ array_objectarray_element_set(oa, 0, (java_handle_t *) classes);
+ array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames);
/* iterate over all stacktrace entries */
if (string == NULL)
goto return_NULL;
- LLNI_objectarray_element_set(methodnames, i, string);
+ array_objectarray_element_set(methodnames, i, string);
}
/* return the 2-dimensional array */