X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fstacktrace.cpp;h=c59d05ac1bf7299add8422432dbd1cc7041da8ba;hb=4a6cefba48d8720b9e33f2e89823b8ed7fa0b78d;hp=514c2fd08ae38809c1052e6f5b7baf8458bb8971;hpb=c378b6dabad51760ac3d9fae8ca8bcab7cca1364;p=cacao.git diff --git a/src/vm/jit/stacktrace.cpp b/src/vm/jit/stacktrace.cpp index 514c2fd08..c59d05ac1 100644 --- a/src/vm/jit/stacktrace.cpp +++ b/src/vm/jit/stacktrace.cpp @@ -1,7 +1,8 @@ /* src/vm/jit/stacktrace.cpp - machine independent stacktrace system - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2011 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + Copyright (C) 2009 Theobroma Systems Ltd. This file is part of CACAO. @@ -32,6 +33,7 @@ #include "vm/types.h" +#include "arch.h" #include "md.h" #include "mm/gc.hpp" @@ -137,7 +139,7 @@ void stacktrace_stackframeinfo_add(stackframeinfo_t* sfi, void* pv, void* sp, vo /* On S390 we use REG_RA as REG_ITMP3, so we have always to get the RA from stack. */ - framesize = *((u4 *) (((uintptr_t) pv) + FrameSize)); + framesize = md_stacktrace_get_framesize(code); ra = md_stacktrace_get_returnaddress(sp, framesize); # else @@ -148,7 +150,7 @@ void stacktrace_stackframeinfo_add(stackframeinfo_t* sfi, void* pv, void* sp, vo the asm_vm_call_method special case. */ if ((code == NULL) || !code_is_leafmethod(code)) { - framesize = *((u4 *) (((uintptr_t) pv) + FrameSize)); + framesize = md_stacktrace_get_framesize(code); ra = md_stacktrace_get_returnaddress(sp, framesize); } @@ -305,7 +307,7 @@ static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi) /* Get the current stack frame size. */ - framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize)); + framesize = md_stacktrace_get_framesize(code); /* Get the RA of the current stack frame (RA to the parent Java method) if the current method is a non-leaf method. Otherwise @@ -356,7 +358,7 @@ static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi) else #endif { -#if defined(__I386__) || defined (__X86_64__) || defined (__M68K__) +#if STACKFRMAE_RA_BETWEEN_FRAMES sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P); #elif defined(__SPARC_64__) /* already has the new sp */ @@ -516,15 +518,14 @@ static int stacktrace_depth(stackframeinfo_t *sfi) java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi) { - stackframeinfo_t tmpsfi; - int depth; - java_handle_bytearray_t *ba; - int32_t ba_size; - stacktrace_t *st; - stacktrace_entry_t *ste; - methodinfo *m; - bool skip_fillInStackTrace; - bool skip_init; + stackframeinfo_t tmpsfi; + int depth; + int32_t ba_size; + stacktrace_t *st; + stacktrace_entry_t *ste; + methodinfo *m; + bool skip_fillInStackTrace; + bool skip_init; CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD @@ -550,9 +551,9 @@ java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi) ba_size = sizeof(stacktrace_t) + sizeof(stacktrace_entry_t) * depth; - ba = builtin_newarray_byte(ba_size); + ByteArray ba(ba_size); - if (ba == NULL) + if (ba.is_null()) goto return_NULL; /* Get a stacktrace entry pointer. */ @@ -561,7 +562,7 @@ java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi) LLNI_CRITICAL_START; - st = (stacktrace_t *) LLNI_array_data(ba); + st = (stacktrace_t *) ba.get_raw_data_ptr(); ste = st->entries; @@ -639,7 +640,7 @@ java_handle_bytearray_t *stacktrace_get(stackframeinfo_t *sfi) CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace, stacktrace_overhead) - return ba; + return ba.get_handle(); return_NULL: /* dump_release(dumpsize); */ @@ -674,6 +675,129 @@ java_handle_bytearray_t *stacktrace_get_current(void) } +/** + * Creates a java.lang.StackTraceElement for one element of the given + * stacktrace. + * + * @param st Given stacktrace. + * @param index Index of element inside stacktrace. + * @return The filled StackTraceElement object. + */ +#if defined(ENABLE_JAVASE) +java_handle_t* stacktrace_get_StackTraceElement(stacktrace_t* st, int32_t index) +{ + assert(st != NULL); + + if ((index < 0) || (index >= st->length)) { + /* XXX This should be an IndexOutOfBoundsException (check this + again). */ + exceptions_throw_arrayindexoutofboundsexception(); + return NULL; + } + + // Get the stacktrace entry. + stacktrace_entry_t* ste = &(st->entries[index]); + + // Get the codeinfo, methodinfo and classinfo. + codeinfo* code = ste->code; + methodinfo* m = code->m; + classinfo* c = m->clazz; + + // Get filename. + java_handle_t* filename; + + if (!(m->flags & ACC_NATIVE)) { + if (c->sourcefile != NULL) + filename = javastring_new(c->sourcefile); + else + filename = NULL; + } + else + filename = NULL; + + // Get line number. + int32_t linenumber; + + if (m->flags & ACC_NATIVE) { +#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) + linenumber = -1; +#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) + linenumber = -2; +#else +# error unknown classpath configuration +#endif + } + else { + // FIXME linenumbertable->find could change the methodinfo + // pointer when hitting an inlined method. + linenumber = code->linenumbertable->find(&m, ste->pc); + linenumber = (linenumber == 0) ? -1 : linenumber; + } + + // Get declaring class name. + java_handle_t* declaringclass = class_get_classname(c); + +#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) + // Allocate a new StackTraceElement object. + java_handle_t* h = builtin_new(class_java_lang_StackTraceElement); + + if (h == NULL) + return NULL; + + java_lang_StackTraceElement jlste(h, filename, linenumber, declaringclass, javastring_new(m->name), ((m->flags & ACC_NATIVE) ? 1 : 0)); +#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) + // Allocate a new StackTraceElement object. + java_lang_StackTraceElement jlste(declaringclass, javastring_new(m->name), filename, linenumber); + + if (jlste.is_null()) + return NULL; +#else +# error unknown classpath configuration +#endif + + return jlste.get_handle(); +} +#endif + + +/** + * Creates a complete array of java.lang.StackTraceElement objects + * for the given stacktrace. + * + * @param st Given stacktrace. + * @return Array of filled StackTraceElement objects. + */ +#if defined(ENABLE_JAVASE) +java_handle_objectarray_t* stacktrace_get_StackTraceElements(stacktrace_t* st) +{ + // Get length of stacktrace. If stacktrace is not available + // an empty array should be returned. + int32_t length = (st != NULL) ? st->length : 0; + + // Create the stacktrace element array. + ObjectArray oa(length, class_java_lang_StackTraceElement); + + if (oa.is_null()) + return NULL; + + // Iterate over all stacktrace elements. + for (int i = 0; i < length; i++) { + + // Get stacktrace element at current index. + java_handle_t* h = stacktrace_get_StackTraceElement(st, i); + + if (h == NULL) + return NULL; + + // Store stacktrace element in array. + oa.set_element(i, h); + } + + return oa.get_handle(); +} +#endif + + /* stacktrace_get_caller_class ************************************************* Get the class on the stack at the given depth. This function skips @@ -750,17 +874,12 @@ classinfo *stacktrace_get_caller_class(int depth) #endif -/* stacktrace_first_nonnull_classloader **************************************** - - Returns the first non-null (user-defined) classloader on the stack. - If none is found NULL is returned. - - RETURN: - classloader - -*******************************************************************************/ - -classloader_t *stacktrace_first_nonnull_classloader(void) +/** + * Returns the first non-null (user-defined) classloader on the stack. + * + * @return The first non-null classloader or NULL if none is found. + */ +classloader_t* stacktrace_first_nonnull_classloader(void) { stackframeinfo_t *sfi; stackframeinfo_t tmpsfi; @@ -785,6 +904,14 @@ classloader_t *stacktrace_first_nonnull_classloader(void) m = tmpsfi.code->m; cl = class_get_classloader(m->clazz); +#if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) + /* NOTE: See hotspot/src/share/vm/runtime/vframe.cpp + (vframeStreamCommon::skip_reflection_related_frames). */ + if (class_issubclass(m->clazz, class_sun_reflect_MethodAccessorImpl) || + class_issubclass(m->clazz, class_sun_reflect_ConstructorAccessorImpl)) + continue; +#endif + if (cl != NULL) return cl; } @@ -793,6 +920,82 @@ classloader_t *stacktrace_first_nonnull_classloader(void) } +/** + * Checks if a given classloader is equal to the the second classloader + * or one of its ancestors (parents). + * + * XXX: This helper method should be moved to java_lang_Classloader. + */ +#if defined(ENABLE_JAVASE) +static bool is_ancestor_of(classloader_t* loader, classloader_t* parent) +{ + // Iterate over chain of possible parents. + while (parent != NULL) { + + // Check if given loader is parent. + if (loader == parent) + return true; + + // Jump to next parent. + java_lang_ClassLoader jlcl(parent); + parent = jlcl.get_parent(); + } + + return false; +} +#endif /* defined(ENABLE_JAVASE) */ + + +/** + * Returns the first non-system (user-defined) classloader on the stack. + * A non-system classloader is a non-null classloader being not equal to + * the system classloader (or one of its ancestors). + * + * @return The first non-system classloader or NULL if none is found. + */ +#if defined(ENABLE_JAVASE) +classloader_t* stacktrace_first_nonsystem_classloader(void) +{ + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + methodinfo *m; + classloader_t *cl; + classloader_t *syscl; + +#if !defined(NDEBUG) + if (opt_DebugStackTrace) + log_println("[stacktrace_first_nonsystem_classloader]"); +#endif + + // Get the stackframeinfo of the current thread. + sfi = threads_get_current_stackframeinfo(); + + // Get the system class class loader. + syscl = java_lang_ClassLoader::invoke_getSystemClassLoader(); + + // Iterate over the whole stack. + for (stacktrace_stackframeinfo_fill(&tmpsfi, sfi); + stacktrace_stackframeinfo_end_check(&tmpsfi) == false; + stacktrace_stackframeinfo_next(&tmpsfi)) { + + m = tmpsfi.code->m; + cl = class_get_classloader(m->clazz); + + if (cl == NULL) + continue; + + // XXX if a method in a class in a trusted loader is in a + // doPrivileged, return NULL (or break) here. + + if (!is_ancestor_of(cl, syscl)) + return cl; + } + + return NULL; +} +#endif /* defined(ENABLE_JAVASE) */ + + /* stacktrace_getClassContext ************************************************** Creates a Class context array. @@ -808,8 +1011,6 @@ java_handle_objectarray_t *stacktrace_getClassContext(void) stackframeinfo_t *sfi; stackframeinfo_t tmpsfi; int depth; - java_handle_objectarray_t *oa; - java_object_t **data; int i; methodinfo *m; @@ -836,20 +1037,15 @@ java_handle_objectarray_t *stacktrace_getClassContext(void) /* Allocate the Class array. */ - oa = builtin_anewarray(depth, class_java_lang_Class); + ClassArray ca(depth); - if (oa == NULL) { + if (ca.is_null()) { CYCLES_STATS_END(stacktrace_getClassContext); return NULL; } /* Fill the Class array from the stacktrace list. */ - - LLNI_CRITICAL_START; - - data = LLNI_array_data(oa); - /* Iterate over the whole stack. */ i = 0; @@ -868,7 +1064,7 @@ java_handle_objectarray_t *stacktrace_getClassContext(void) /* Store the class in the array. */ - data[i] = (java_object_t *) m->clazz; + ca.set_element(i, m->clazz); i++; } @@ -877,7 +1073,7 @@ java_handle_objectarray_t *stacktrace_getClassContext(void) CYCLES_STATS_END(stacktrace_getClassContext) - return oa; + return ca.get_handle(); } @@ -969,15 +1165,12 @@ classinfo *stacktrace_get_current_class(void) #if defined(ENABLE_JAVASE) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) java_handle_objectarray_t *stacktrace_get_stack(void) { - stackframeinfo_t *sfi; - stackframeinfo_t tmpsfi; - int depth; - java_handle_objectarray_t *oa; - java_handle_objectarray_t *classes; - java_handle_objectarray_t *methodnames; - methodinfo *m; - java_handle_t *string; - int i; + stackframeinfo_t *sfi; + stackframeinfo_t tmpsfi; + int depth; + methodinfo *m; + java_handle_t *string; + int i; CYCLES_STATS_DECLARE_AND_START @@ -999,25 +1192,23 @@ java_handle_objectarray_t *stacktrace_get_stack(void) /* Allocate the required arrays. */ - oa = builtin_anewarray(2, arrayclass_java_lang_Object); + ObjectArray oa(2, arrayclass_java_lang_Object); + ClassArray classes(depth); + ObjectArray methodnames(depth, class_java_lang_String); - if (oa == NULL) + if (oa.is_null()) goto return_NULL; - classes = builtin_anewarray(depth, class_java_lang_Class); - - if (classes == NULL) + if (classes.is_null()) goto return_NULL; - methodnames = builtin_anewarray(depth, class_java_lang_String); - - if (methodnames == NULL) + if (methodnames.is_null()) goto return_NULL; /* Set up the 2-dimensional array. */ - array_objectarray_element_set(oa, 0, (java_handle_t *) classes); - array_objectarray_element_set(oa, 1, (java_handle_t *) methodnames); + oa.set_element(0, (java_handle_t *) classes.get_handle()); + oa.set_element(1, (java_handle_t *) methodnames.get_handle()); /* Iterate over the whole stack. */ /* TODO We should use a critical section here to speed things @@ -1038,10 +1229,8 @@ java_handle_objectarray_t *stacktrace_get_stack(void) continue; /* Store the class in the array. */ - /* NOTE: We use a LLNI-macro here, because a classinfo is not - a handle. */ - LLNI_array_direct(classes, i) = (java_object_t *) m->clazz; + classes.set_element(i, m->clazz); /* Store the name in the array. */ @@ -1050,14 +1239,14 @@ java_handle_objectarray_t *stacktrace_get_stack(void) if (string == NULL) goto return_NULL; - array_objectarray_element_set(methodnames, i, string); + methodnames.set_element(i, string); i++; } CYCLES_STATS_END(stacktrace_get_stack) - return oa; + return oa.get_handle(); return_NULL: CYCLES_STATS_END(stacktrace_get_stack) @@ -1187,9 +1376,42 @@ void stacktrace_print_current(void) } +/** + * Creates a stacktrace for the given thread. + * + * @param t Given thread. + * @return Current stacktrace of the given thread. + * + * XXX: Creation of the stacktrace starts at the most recent + * stackframeinfo block. If the thread is not inside the native + * world, the created stacktrace is not complete! + */ +#if defined(ENABLE_THREADS) +stacktrace_t* stacktrace_get_of_thread(threadobject* t) +{ + stackframeinfo_t* sfi; + java_handle_bytearray_t* stba; + stacktrace_t* st; + + sfi = t->_stackframeinfo; + stba = stacktrace_get(sfi); + + ByteArray ba(stba); + + if (ba.is_null()) + return NULL; + + st = (stacktrace_t*) ba.get_raw_data_ptr(); + + return st; +} +#endif + + /* stacktrace_print_of_thread ************************************************** - Print the current stacktrace of the given thread. + Print the current stacktrace of the given thread. It will only work + for suspended threads. ARGUMENTS: t ... thread @@ -1209,7 +1431,7 @@ void stacktrace_print_of_thread(threadobject *t) sfi = t->_stackframeinfo; - if (sfi == NULL) { + if (!t->suspended || sfi == NULL) { puts("\t<>"); fflush(stdout); return; @@ -1254,11 +1476,11 @@ void stacktrace_print_exception(java_handle_t *h) #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) java_lang_VMThrowable vmt(t.get_vmState()); - java_handle_bytearray_t* backtrace = vmt.get_vmdata(); + ByteArray backtrace(vmt.get_vmdata()); #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1) - java_handle_bytearray_t* backtrace = t.get_backtrace(); + ByteArray backtrace(t.get_backtrace()); #else # error unknown classpath configuration @@ -1266,14 +1488,14 @@ void stacktrace_print_exception(java_handle_t *h) // Sanity check. - assert(backtrace != NULL); + assert(backtrace.is_non_null()); /* We need a critical section here as we use the byte-array data pointer directly. */ LLNI_CRITICAL_START; - stacktrace_t* st = (stacktrace_t*) LLNI_array_data(backtrace); + stacktrace_t* st = (stacktrace_t*) backtrace.get_raw_data_ptr(); stacktrace_print(st);