Copyright (C) 1996-2005, 2006, 2007, 2008
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+ Copyright (C) 2009 Theobroma Systems Ltd.
This file is part of CACAO.
#include "md.h"
#include "mm/gc.hpp"
-#include "mm/memory.h"
+#include "mm/memory.hpp"
#include "vm/jit/stacktrace.hpp"
#include "threads/thread.hpp"
-#include "toolbox/logging.h"
+#include "toolbox/logging.hpp"
-#include "vm/array.h"
+#include "vm/array.hpp"
#include "vm/jit/builtin.hpp"
-#include "vm/class.h"
+#include "vm/class.hpp"
#include "vm/cycles-stats.h"
#include "vm/exceptions.hpp"
#include "vm/globals.hpp"
#include "vm/javaobjects.hpp"
#include "vm/loader.hpp"
-#include "vm/method.h"
+#include "vm/method.hpp"
#include "vm/options.h"
#include "vm/string.hpp"
#include "vm/vm.hpp"
#include "vm/jit/asmpart.h"
#include "vm/jit/codegen-common.hpp"
-#include "vm/jit/linenumbertable.h"
+#include "vm/jit/linenumbertable.hpp"
#include "vm/jit/methodheader.h"
#include "vm/jit/methodtree.h"
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
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. */
LLNI_CRITICAL_START;
- st = (stacktrace_t *) LLNI_array_data(ba);
+ st = (stacktrace_t *) ba.get_raw_data_ptr();
ste = st->entries;
CYCLES_STATS_END_WITH_OVERHEAD(stacktrace_fillInStackTrace,
stacktrace_overhead)
- return ba;
+ return ba.get_handle();
return_NULL:
/* dump_release(dumpsize); */
}
+/**
+ * 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
#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;
}
+/**
+ * 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.
stackframeinfo_t *sfi;
stackframeinfo_t tmpsfi;
int depth;
- java_handle_objectarray_t *oa;
- java_object_t **data;
int i;
methodinfo *m;
/* 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;
/* Store the class in the array. */
- data[i] = (java_object_t *) m->clazz;
+ ca.set_element(i, m->clazz);
i++;
}
CYCLES_STATS_END(stacktrace_getClassContext)
- return oa;
+ return ca.get_handle();
}
#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
/* 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
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. */
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)
/* Get the line number. */
- linenumber = linenumbertable_linenumber_for_pc(&m, ste->code, ste->pc);
+ linenumber = ste->code->linenumbertable->find(&m, ste->pc);
stacktrace_print_entry(m, linenumber);
}
code = tmpsfi.code;
m = code->m;
- /* Get the line number. */
-
- linenumber = linenumbertable_linenumber_for_pc(&m, code, tmpsfi.xpc);
+ // Get the line number.
+ linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
stacktrace_print_entry(m, linenumber);
}
}
+/**
+ * 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.
code = tmpsfi.code;
m = code->m;
- /* Get the line number. */
-
- linenumber = linenumbertable_linenumber_for_pc(&m, code, tmpsfi.xpc);
+ // Get the line number.
+ linenumber = code->linenumbertable->find(&m, tmpsfi.xpc);
stacktrace_print_entry(m, linenumber);
}
#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
// 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);