AC_CHECK_HEADERS([time.h])
AC_CHECK_HEADERS([ucontext.h])
AC_CHECK_HEADERS([unistd.h])
+AC_CHECK_HEADERS([mach/mach.h])
AC_CHECK_HEADERS([sys/ioctl.h])
+AC_CHECK_HEADERS([sys/loadavg.h])
AC_CHECK_HEADERS([sys/mman.h])
AC_CHECK_HEADERS([sys/resource.h])
AC_CHECK_HEADERS([sys/select.h])
AC_CHECK_HEADERS([sys/stat.h])
AC_CHECK_HEADERS([sys/time.h])
AC_CHECK_HEADERS([sys/types.h])
+AC_CHECK_HEADERS([sys/utsname.h])
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_CHECK_FUNCS([getenv])
AC_CHECK_FUNCS([gethostbyname])
AC_CHECK_FUNCS([gethostname])
+AC_CHECK_FUNCS([getloadavg])
AC_CHECK_FUNCS([getpagesize])
+AC_CHECK_FUNCS([getpid])
AC_CHECK_FUNCS([getrusage])
AC_CHECK_FUNCS([getsockname])
AC_CHECK_FUNCS([getsockopt])
AC_CHECK_WITH_JNI_MD_H
AC_CHECK_WITH_JNI_H
+dnl The jvmti.h header is only required if JVMTI is enabled.
+if test x"${ENABLE_JVMTI}" = "xyes"; then
+ AC_CHECK_WITH_JVMTI_H
+fi
+
dnl JVM, HPI, and JMM is only required for OpenJDK.
case "${WITH_JAVA_RUNTIME_LIBRARY}" in
openjdk)
AZ_PYTHON_CSPEC
AZ_PYTHON_LSPEC
-
-dnl define some stuff required for --fullversion
-AC_DEFINE_UNQUOTED(VERSION_CONFIGURE_ARGS, "$ac_configure_args", [configure arguments])
-AC_DEFINE_UNQUOTED(VERSION_CC, "$CC", [CC used])
-AC_DEFINE_UNQUOTED(VERSION_CXX, "$CXX", [CXX used])
-AC_DEFINE_UNQUOTED(VERSION_CFLAGS, "$OPT_CFLAGS $ARCH_CFLAGS $CC_FLAGS $CPPFLAGS", [CFLAGS used])
-AC_DEFINE_UNQUOTED(VERSION_CXXFLAGS, "$OPT_CXXFLAGS $ARCH_CXXFLAGS $CXX_FLAGS $CPPFLAGS", [CXXFLAGS used])
-
+dnl Define version numbers.
+AC_VERSION_DETAIL
+AC_VERSION_CONFIG
dnl Finally pass flags to Makefiles.
CFLAGS="$OPT_CFLAGS"
dnl m4/jvmti.m4
dnl
-dnl Copyright (C) 2008
+dnl Copyright (C) 2008, 2009
dnl CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
dnl
dnl This file is part of CACAO.
AC_DEFINE([ENABLE_JVMTI], 1, [use JVMTI])
fi
])
+
+
+dnl where jvmti.h is installed
+
+AC_DEFUN([AC_CHECK_WITH_JVMTI_H],[
+AC_MSG_CHECKING(where jvmti.h is installed)
+AC_ARG_WITH([jvmti_h],
+ [AS_HELP_STRING(--with-jvmti_h=<dir>,path to jvmti.h (only with --enable-jvmti) [[default=(openjdk:${JAVA_RUNTIME_LIBRARY_PREFIX}/jdk/src/share/javavm/export,*:${JAVA_RUNTIME_LIBRARY_PREFIX}/include)]])],
+ [WITH_JVMTI_H=${withval}],
+ [case "${WITH_JAVA_RUNTIME_LIBRARY}" in
+ openjdk)
+ WITH_JVMTI_H=${JAVA_RUNTIME_LIBRARY_PREFIX}/jdk/src/share/javavm/export
+ ;;
+ *)
+ WITH_JVMTI_H=${JAVA_RUNTIME_LIBRARY_PREFIX}/include
+ ;;
+ esac])
+AC_MSG_RESULT(${WITH_JVMTI_H})
+
+AC_CHECK_HEADER([${WITH_JVMTI_H}/jvmti.h],
+ [AC_DEFINE_UNQUOTED([INCLUDE_JVMTI_H], "${WITH_JVMTI_H}/jvmti.h", [Java runtime library jvmti.h header])],
+ [AC_MSG_ERROR(cannot find jvmti.h)])
+])
--- /dev/null
+dnl m4/version.m4
+dnl
+dnl Copyright (C) 2009
+dnl CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+dnl
+dnl This file is part of CACAO.
+dnl
+dnl This program is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU General Public License as
+dnl published by the Free Software Foundation; either version 2, or (at
+dnl your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+dnl 02110-1301, USA.
+
+
+dnl define detailed version numbers
+
+AC_DEFUN([AC_VERSION_DETAIL],[
+version="$PACKAGE_VERSION"
+if test x`echo "$version" | $SED -e 's/[[0-9a-z+]]*//g'` = "x..";
+then
+ major=`echo "$version" | $SED -e 's/\.[[0-9a-z.+]]*$//'`
+ minor=`echo "$version" | $SED -e 's/^[[0-9]]*\.//' -e 's/\.[[0-9a-z.+]]*$//'`
+ micro=`echo "$version" | $SED -e 's/^[[0-9]]*\.[[0-9]]*\.//' -e 's/[[a-z.+]]*$//'`
+ extra=`echo "$version" | $SED -e 's/^[[0-9]]*\.[[0-9]]*\.[[0-9]]*//'`
+else
+ major=`echo "$version" | $SED -e 's/\.[[0-9a-z.+]]*$//'`
+ minor=`echo "$version" | $SED -e 's/^[[0-9]]*\.//' -e 's/[[a-z.+]]*$//'`
+ micro=0
+ extra=`echo "$version" | $SED -e 's/^[[0-9]]*\.[[0-9]]*//'`
+fi
+
+AC_DEFINE_UNQUOTED(VERSION_MAJOR, $major, [major version number])
+AC_DEFINE_UNQUOTED(VERSION_MINOR, $minor, [minor version number])
+AC_DEFINE_UNQUOTED(VERSION_MICRO, $micro, [micro version number])
+AC_DEFINE_UNQUOTED(VERSION_EXTRA, "$extra", [extra version info])
+])
+
+
+dnl define some stuff required for -XX:+PrintConfig
+
+AC_DEFUN([AC_VERSION_CONFIG],[
+AC_DEFINE_UNQUOTED(VERSION_CONFIGURE_ARGS, "$ac_configure_args", [configure arguments])
+AC_DEFINE_UNQUOTED(VERSION_CC, "$CC", [CC used])
+AC_DEFINE_UNQUOTED(VERSION_CXX, "$CXX", [CXX used])
+AC_DEFINE_UNQUOTED(VERSION_CFLAGS, "$OPT_CFLAGS $ARCH_CFLAGS $CC_FLAGS $CPPFLAGS", [CFLAGS used])
+AC_DEFINE_UNQUOTED(VERSION_CXXFLAGS, "$OPT_CXXFLAGS $ARCH_CXXFLAGS $CXX_FLAGS $CPPFLAGS", [CXXFLAGS used])
+])
#include "native/jni.hpp"
#include "native/native.hpp"
-#if defined(ENABLE_JVMTI)
-# include "native/jvmti/jvmti.h"
-# include "native/jvmti/cacaodbg.h"
-#endif
-
#include "vm/os.hpp"
#include "vm/vm.hpp"
(void) VM_create(&vm, &env, vm_args);
-#if defined(ENABLE_JVMTI)
-# error This should be a JVMTI function.
- Mutex_init(&dbgcomlock);
- if (jvmti) jvmti_set_phase(JVMTI_PHASE_START);
-#endif
-
#if defined(ENABLE_LIBJVM)
libjvm_vm_run = os::dlsym(libjvm_handle, "vm_run");
#include <stdint.h>
#include <stdlib.h>
-#include <sys/mman.h> /* REMOVEME */
#include "threads/mutex.hpp"
#include "threads/thread.hpp"
#include <stdlib.h>
-#if defined(HAVE_SYS_MMAN_H)
-# include <sys/mman.h>
-#endif
-
#include "vm/types.h"
#include "boehm-gc/include/gc.h"
#include "vm/global.h"
#include "vm/loader.hpp"
#include "vm/options.h"
+#include "vm/os.hpp"
#include "vm/vm.hpp"
#include "mm/tlh.h"
#include "vm/global.h"
+#include "vm/os.hpp"
#include <assert.h>
-#include <sys/mman.h>
static const int TLH_MAX_SIZE = (20 * 1024 * 1024);
}
JNI_RELEASE_ARRAY_ELEMENTS(Boolean, jboolean, boolean, u1)
-JNI_RELEASE_ARRAY_ELEMENTS(Byte, jbyte, byte, int8_t)
+JNI_RELEASE_ARRAY_ELEMENTS(Byte, jbyte, byte, s1)
JNI_RELEASE_ARRAY_ELEMENTS(Char, jchar, char, u2)
JNI_RELEASE_ARRAY_ELEMENTS(Short, jshort, short, s2)
JNI_RELEASE_ARRAY_ELEMENTS(Int, jint, int, s4)
}
JNI_GET_ARRAY_REGION(Boolean, jboolean, boolean, u1)
-JNI_GET_ARRAY_REGION(Byte, jbyte, byte, int8_t)
+JNI_GET_ARRAY_REGION(Byte, jbyte, byte, s1)
JNI_GET_ARRAY_REGION(Char, jchar, char, u2)
JNI_GET_ARRAY_REGION(Short, jshort, short, s2)
JNI_GET_ARRAY_REGION(Int, jint, int, s4)
}
JNI_SET_ARRAY_REGION(Boolean, jboolean, boolean, u1)
-JNI_SET_ARRAY_REGION(Byte, jbyte, byte, int8_t)
+JNI_SET_ARRAY_REGION(Byte, jbyte, byte, s1)
JNI_SET_ARRAY_REGION(Char, jchar, char, u2)
JNI_SET_ARRAY_REGION(Short, jshort, short, s2)
JNI_SET_ARRAY_REGION(Int, jint, int, s4)
classinfo* c = LLNI_classinfo_unwrap(clazz);
- /* XXX: if implemented this needs a call to jvmti_NativeMethodBind
- if (jvmti) jvmti_NativeMethodBind(method, address, new_address_ptr);
- */
-
NativeMethods& nm = VM::get_current()->get_nativemethods();
nm.register_methods(c->name, methods, nMethods);
- return 0;
+ return 0;
}
#include "vm/exceptions.hpp"
#include "vm/global.h"
#include "vm/globals.hpp"
+#include "vm/hook.hpp"
#include "vm/loader.hpp"
#include "vm/options.h"
#include "vm/os.hpp"
exceptions_throw_unsatisfiedlinkerror(m->name);
}
+ // Hook point just after method resolving finished.
+ Hook::native_resolved(m, symbol, &symbol);
+
return symbol;
}
if (opt_verbosejni)
printf("failed ]\n");
- if (opt_verbose) {
- log_start();
- log_print("NativeLibrary::open: os::dlopen failed: ");
- log_print(os::dlerror());
- log_finish();
- }
+ if (opt_PrintWarnings)
+ log_println("NativeLibrary::open: os::dlopen failed: %s", os::dlerror());
return NULL;
}
if (opt_verbosejni)
printf("failed ]\n");
- if (opt_verbose) {
- log_start();
- log_print("NativeLibrary::close: os::dlclose failed: ");
- log_print(os::dlerror());
- log_finish();
- }
+ if (opt_PrintWarnings)
+ log_println("NativeLibrary::close: os::dlclose failed: %s", os::dlerror());
}
if (opt_verbosejni)
#include "config.h"
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <fcntl.h>
#include <errno.h>
#include <zlib.h>
#include "vm/array.hpp"
#include "vm/exceptions.hpp"
#include "vm/javaobjects.hpp"
+#include "vm/os.hpp"
#include "vm/string.hpp"
#include "vm/types.h"
#include "vm/vm.hpp" /* REMOVE ME: temporarily */
#include <netdb.h>
#include <unistd.h>
#include <sys/types.h>
-#include <sys/socket.h>
#include "vm/types.h"
*/
JNIEXPORT void JNICALL Java_java_lang_Object_wait(JNIEnv *env, jobject _this, jlong timeout)
{
-#if defined(ENABLE_JVMTI)
- /* Monitor Wait */
- if (jvmti) jvmti_MonitorWaiting(true, _this, timeout);
-#endif
-
#if defined(ENABLE_THREADS)
lock_wait_for_object((java_handle_t *) _this, timeout, 0);
#endif
-
-#if defined(ENABLE_JVMTI)
- /* Monitor Waited */
- /* XXX: How do you know if wait timed out ?*/
- if (jvmti) jvmti_MonitorWaiting(false, _this, 0);
-#endif
}
} // extern "C"
#include "toolbox/logging.hpp"
#include "vm/classcache.hpp"
+#include "vm/options.h"
#include "vm/utf8.h"
#include "vm/vm.hpp"
*/
JNIEXPORT jlong JNICALL Java_gnu_java_lang_management_VMClassLoadingMXBeanImpl_getUnloadedClassCount(JNIEnv *env, jclass clazz)
{
- log_println("Java_gnu_java_lang_management_VMClassLoadingMXBeanImpl_getUnloadedClassCount: IMPLEMENT ME!");
+ int32_t count;
+
+ // XXX Fix this once we support class unloading!
+ count = 0;
- return 0;
+ return count;
}
*/
JNIEXPORT jboolean JNICALL Java_gnu_java_lang_management_VMClassLoadingMXBeanImpl_isVerbose(JNIEnv *env, jclass clazz)
{
-/* return _Jv_jvm->Java_gnu_java_lang_management_VMClassLoadingMXBeanImpl_verbose; */
-#warning Move to C++
- log_println("Java_gnu_java_lang_management_VMClassLoadingMXBeanImpl_isVerbose: MOVE TO C++!");
- return 0;
+ return opt_verboseclass;
}
*/
JNIEXPORT void JNICALL Java_gnu_java_lang_management_VMClassLoadingMXBeanImpl_setVerbose(JNIEnv *env, jclass clazz, jboolean verbose)
{
-/* _Jv_jvm->Java_gnu_java_lang_management_VMClassLoadingMXBeanImpl_verbose = verbose; */
-#warning Move to C++
- log_println("Java_gnu_java_lang_management_VMClassLoadingMXBeanImpl_setVerbose: MOVE TO C++!");
+ opt_verboseclass = verbose;
}
} // extern "C"
# include "native/vm/include/gnu_java_lang_management_VMMemoryMXBeanImpl.h"
#endif
-#include "vm/jit/builtin.hpp"
#include "vm/class.hpp"
#include "vm/global.h"
-#include "vm/loader.hpp" /* XXX only for load_class_bootstrap */
+#include "vm/javaobjects.hpp"
#include "vm/options.h"
#include "vm/vm.hpp"
*/
JNIEXPORT jobject JNICALL Java_gnu_java_lang_management_VMMemoryMXBeanImpl_getHeapMemoryUsage(JNIEnv *env, jclass clazz)
{
- classinfo *class_java_lang_management_MemoryUsage;
- java_handle_t *o;
- methodinfo *m;
- int64_t init;
- int64_t used;
- int64_t commited;
- int64_t maximum;
+ // Get values from the VM.
+ // XXX If we ever support more than one VM, change this.
+ int64_t init = opt_heapstartsize;
+ int64_t used = gc_get_total_bytes();
+ int64_t commited = gc_get_heap_size();
+ int64_t maximum = gc_get_max_heap_size();
- /* get the class */
- /* XXX optimize me! sometime... */
+ // Construct a new java.lang.management.MemoryUsage object.
+ java_lang_management_MemoryUsage jlmmu(init, used, commited, maximum);
- if (!(class_java_lang_management_MemoryUsage = load_class_bootstrap(utf_new_char("java/lang/management/MemoryUsage"))))
- return false;
-
- /* create the object */
-
- o = builtin_new(class_java_lang_management_MemoryUsage);
-
- if (o == NULL)
- return NULL;
-
- /* find initializer */
-
- m = class_findmethod(class_java_lang_management_MemoryUsage,
- utf_init, utf_new_char("(JJJJ)V"));
-
- /* initializer not found */
-
- if (m == NULL)
- return NULL;
-
- /* get values from the VM */
- /* XXX if we ever support more than one VM, change this */
-
- init = opt_heapstartsize;
- used = gc_get_total_bytes();
- commited = gc_get_heap_size();
- maximum = gc_get_max_heap_size();
-
- /* call initializer */
-
- (void) vm_call_method(m, o, init, used, commited, maximum);
-
- return (jobject) o;
+ return jlmmu.get_handle();
}
*/
JNIEXPORT jboolean JNICALL Java_gnu_java_lang_management_VMMemoryMXBeanImpl_isVerbose(JNIEnv *env, jclass clazz)
{
-/* return _Jv_jvm->Java_gnu_java_lang_management_VMMemoryMXBeanImpl_verbose; */
-#warning Move to C++
- log_println("Java_gnu_java_lang_management_VMMemoryMXBeanImpl_isVerbose: MOVE TO C++!");
- return 0;
+ return opt_verbosegc;
}
*/
JNIEXPORT void JNICALL Java_gnu_java_lang_management_VMMemoryMXBeanImpl_setVerbose(JNIEnv *env, jclass clazz, jboolean verbose)
{
-/* _Jv_jvm->Java_gnu_java_lang_management_VMMemoryMXBeanImpl_verbose = verbose; */
-#warning Move to C++
- log_println("Java_gnu_java_lang_management_VMMemoryMXBeanImpl_setVerbose: MOVE TO C++!");
+ opt_verbosegc = verbose;
}
} // extern "C"
# include "native/vm/include/gnu_java_lang_management_VMThreadMXBeanImpl.h"
#endif
+#include "threads/threadlist.hpp"
+
#include "toolbox/logging.hpp"
#include "vm/classcache.hpp"
*/
JNIEXPORT jint JNICALL Java_gnu_java_lang_management_VMThreadMXBeanImpl_getPeakThreadCount(JNIEnv *env, jclass clazz)
{
-/* return _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount; */
-#warning Move to C++
- log_println("Java_gnu_java_lang_management_ThreadMXBean_getPeakThreadCount: MOVE TO C++!");
- return 0;
+ return ThreadList::get_peak_of_active_java_threads();
}
*/
JNIEXPORT jlong JNICALL Java_gnu_java_lang_management_VMThreadMXBeanImpl_getTotalStartedThreadCount(JNIEnv *env, jclass clazz)
{
-/* return _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount; */
-#warning Move to C++
- log_println("Java_gnu_java_lang_management_ThreadMXBean_getTotalStartedThreadCount: MOVE TO C++!");
- return 0;
+ return ThreadList::get_number_of_started_java_threads();
}
*/
JNIEXPORT void JNICALL Java_gnu_java_lang_management_VMThreadMXBeanImpl_resetPeakThreadCount(JNIEnv *env, jclass clazz)
{
-/* _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount = */
-/* _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount; */
-#warning Move to C++
- log_println("Java_gnu_java_lang_management_VMThreadMXBeanImpl_resetPeakThreadCount: MOVE TO C++!");
+ return ThreadList::reset_peak_of_active_java_threads();
}
} // extern "C"
#include <assert.h>
#include <stdint.h>
-#include <sys/stat.h>
#include "mm/memory.hpp"
#include "vm/linker.hpp"
#include "vm/loader.hpp"
#include "vm/options.h"
+#include "vm/os.hpp"
#include "vm/primitive.hpp"
#include "vm/statistics.h"
#include "vm/string.hpp"
*/
JNIEXPORT void JNICALL Java_java_lang_VMObject_wait(JNIEnv* env, jclass clazz, jobject o, jlong ms, jint ns)
{
-#if defined(ENABLE_JVMTI)
- /* Monitor Wait */
- if (jvmti) jvmti_MonitorWaiting(true, o, ms);
-#endif
-
#if defined(ENABLE_THREADS)
lock_wait_for_object(o, ms, ns);
#endif
-
-#if defined(ENABLE_JVMTI)
- /* Monitor Waited */
- /* XXX: How do you know if wait timed out ?*/
- if (jvmti) jvmti_MonitorWaiting(false, o, 0);
-#endif
}
} // extern "C"
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
-#include <sys/utsname.h>
-
-#if defined(__DARWIN__)
-# if defined(__POWERPC__)
-# define OS_INLINE /* required for <libkern/ppc/OSByteOrder.h> */
-# endif
-# include <mach/mach.h>
-#endif
#include "mm/memory.hpp"
#include "mm/gc.hpp"
HPI& hpi = vm->get_hpi();
hpi.initialize();
+ _Jv_sun_misc_Perf_init();
_Jv_sun_misc_Unsafe_init();
+# if !defined(NDEBUG)
+ // Sanity check current time in milliseconds, because negative values
+ // might confuse OpenJDKs sanity checks.
+ if (opt_PrintWarnings && (builtin_currenttimemillis() < 0))
+ log_println("nativevm_preinit: Current time in milliseconds is negative, please check your time!");
+# endif
+
# else
# error unknown classpath configuration
# endif
# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+void _Jv_sun_misc_Perf_init();
void _Jv_sun_misc_Unsafe_init();
# else
## src/native/vm/openjdk/Makefile.am
##
-## Copyright (C) 2007, 2008
+## Copyright (C) 2007, 2008, 2009
## CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
##
## This file is part of CACAO.
hpi.hpp \
jvm.cpp \
management.cpp \
- management.hpp
+ management.hpp \
+ sun_misc_Perf.cpp
## Local variables:
/* src/native/vm/openjdk/jvm.cpp - HotSpot VM interface functions
- Copyright (C) 2007, 2008
+ Copyright (C) 2007, 2008, 2009
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
Copyright (C) 2009 Theobroma Systems Ltd.
#include <sys/ioctl.h>
#endif
-#include <sys/socket.h>
-#include <sys/stat.h>
#include <sys/types.h>
// Include our JNI header before the JVM headers, because the JVM
void JVM_SuspendThread(JNIEnv* env, jobject jthread)
{
- log_println("JVM_SuspendThread: Deprecated. Not implemented.");
+ java_handle_t *h;
+ threadobject *t;
+
+ TRACEJVMCALLS(("JVM_SuspendThread(env=%p, jthread=%p)", env, jthread));
+
+ if (opt_PrintWarnings)
+ log_println("JVM_SuspendThread: Deprecated, do not use!");
+
+ h = (java_handle_t *) jthread;
+ t = thread_get_thread(h);
+
+ /* The threadobject is null when a thread is created in Java. */
+
+ if (t == NULL)
+ return;
+
+ threads_suspend_thread(t, SUSPEND_REASON_JAVA);
}
void JVM_ResumeThread(JNIEnv* env, jobject jthread)
{
- log_println("JVM_ResumeThread: Deprecated. Not implemented.");
+ java_handle_t *h;
+ threadobject *t;
+
+ TRACEJVMCALLS(("JVM_ResumeThread(env=%p, jthread=%p)", env, jthread));
+
+ if (opt_PrintWarnings)
+ log_println("JVM_ResumeThread: Deprecated, do not use!");
+
+ h = (java_handle_t *) jthread;
+ t = thread_get_thread(h);
+
+ /* The threadobject is null when a thread is created in Java. */
+
+ if (t == NULL)
+ return;
+
+ threads_resume_thread(t, SUSPEND_REASON_JAVA);
}
{
// Get a list of all active threads.
List<threadobject*> active_threads;
- ThreadList::get_active_threads(active_threads);
+ ThreadList::get_active_java_threads(active_threads);
// Allocate array to hold the java.lang.Thread objects.
int32_t length = active_threads.size();
void JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t info_size)
{
- log_println("JVM_GetVersionInfo: IMPLEMENT ME!");
+ TRACEJVMCALLS(("JVM_GetVersionInfo(env=%p, info=%p, info_size=%zd)", env, info, info_size));
+
+ memset(info, 0, info_size);
+
+ info->jvm_version = ((VERSION_MAJOR & 0xff) << 24) | ((VERSION_MINOR & 0xff) << 16) | (VERSION_MICRO & 0xff);
+ info->update_version = 0;
+ info->special_update_version = 0;
+ info->is_attach_supported = 0;
+ info->is_kernel_jvm = 0;
}
/* src/native/vm/openjdk/management.cpp - HotSpot management interface functions
- Copyright (C) 2008 Theobroma Systems Ltd.
+ Copyright (C) 2009
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+ Copyright (C) 2008, 2009 Theobroma Systems Ltd.
This file is part of CACAO.
#include "native/vm/openjdk/management.hpp"
+#include "threads/threadlist.hpp"
+
#include "toolbox/logging.hpp"
+#include "vm/array.hpp"
+#include "vm/classcache.hpp"
+#include "vm/globals.hpp" // XXX Remove!!!
+#include "vm/options.h"
#include "vm/os.hpp"
#include "vm/vm.hpp"
+/* debugging macros ***********************************************************/
+
+#if !defined(NDEBUG)
+
+# define TRACEJMMCALLS(x) \
+ do { \
+ if (opt_TraceJMMCalls) { \
+ log_println x; \
+ } \
+ } while (0)
+
+#else
+
+# define TRACEJMMCALLS(x)
+
+#endif
+
+
/**
* Initialize the Management subsystem.
*/
// Interface functions are exported as C functions.
extern "C" {
-// Returns a version string and sets major and minor version if the
-// input parameters are non-null.
jint jmm_GetVersion(JNIEnv* env)
{
return JMM_VERSION;
}
-// Gets the list of VM monitoring and management optional supports
-// Returns 0 if succeeded; otherwise returns non-zero.
jint jmm_GetOptionalSupport(JNIEnv* env, jmmOptionalSupport* support)
{
if (support == NULL) {
jobjectArray jmm_GetMemoryPools(JNIEnv* env, jobject obj)
{
- log_println("jmm_GetMemoryPools: IMPLEMENT ME!");
- return NULL;
+ TRACEJMMCALLS(("jmm_GetMemoryPools(env=%p, obj=%p)", env, obj));
+
+ // XXX This should be an array of java/lang/management/MemoryPoolMXBean.
+ log_println("jmm_GetMemoryPools: FIX ME!");
+ ObjectArray oa(0, class_java_lang_String);
+
+ return oa.get_handle();
}
jobjectArray jmm_GetMemoryManagers(JNIEnv* env, jobject obj)
{
- log_println("jmm_GetMemoryManagers: IMPLEMENT ME!");
- return NULL;
+ TRACEJMMCALLS(("jmm_GetMemoryManagers(env=%p, obj=%p)", env, obj));
+
+ // XXX This should be an array of java/lang/management/MemoryManagerMXBean.
+ log_println("jmm_GetMemoryManagers: FIX ME!");
+ ObjectArray oa(0, class_java_lang_String);
+
+ return oa.get_handle();
}
jboolean jmm_GetBoolAttribute(JNIEnv* env, jmmBoolAttribute att)
{
- log_println("jmm_GetBoolAttribute: IMPLEMENT ME!");
- return 0;
+ TRACEJMMCALLS(("jmm_GetBoolAttribute(env=%p, att=%d)", env, att));
+
+ jboolean result;
+
+ switch (att) {
+ case JMM_VERBOSE_GC:
+ result = opt_verbosegc;
+ break;
+ case JMM_VERBOSE_CLASS:
+ result = opt_verboseclass;
+ break;
+ default:
+ log_println("jmm_GetBoolAttribute: Unknown attribute %d", att);
+ return false;
+ }
+
+ return result;
}
jboolean jmm_SetBoolAttribute(JNIEnv* env, jmmBoolAttribute att, jboolean flag)
{
- log_println("jmm_SetBoolAttribute: IMPLEMENT ME!");
- return 0;
+ TRACEJMMCALLS(("jmm_SetBoolAttribute(env=%p, att=%d, flag=%d)", env, att, flag));
+
+ switch (att) {
+ case JMM_VERBOSE_GC:
+ opt_verbosegc = flag;
+ break;
+ case JMM_VERBOSE_CLASS:
+ opt_verboseclass = flag;
+ break;
+ default:
+ log_println("jmm_SetBoolAttribute: Unknown attribute %d", att);
+ return false;
+ }
+
+ return true;
}
jlong jmm_GetLongAttribute(JNIEnv* env, jobject obj, jmmLongAttribute att)
{
- log_println("jmm_GetLongAttribute: IMPLEMENT ME!");
- return 0;
+ TRACEJMMCALLS(("jmm_GetLongAttribute(env=%p, obj=%p, att=%d)", env, obj, att));
+
+ jlong result;
+
+ switch (att) {
+ case JMM_CLASS_LOADED_COUNT:
+ result = classcache_get_loaded_class_count();
+ break;
+ case JMM_CLASS_UNLOADED_COUNT:
+ // XXX Fix this once we support class unloading!
+ result = 0;
+ break;
+ case JMM_THREAD_TOTAL_COUNT:
+ result = ThreadList::get_number_of_started_java_threads();
+ break;
+ case JMM_THREAD_LIVE_COUNT:
+ result = ThreadList::get_number_of_active_java_threads();
+ break;
+ case JMM_THREAD_PEAK_COUNT:
+ result = ThreadList::get_peak_of_active_java_threads();
+ break;
+ case JMM_THREAD_DAEMON_COUNT:
+ result = ThreadList::get_number_of_daemon_java_threads();
+ break;
+ case JMM_JVM_INIT_DONE_TIME_MS:
+ result = VM::get_current()->get_inittime();
+ break;
+ case JMM_OS_PROCESS_ID:
+ result = os::getpid();
+ break;
+ default:
+ log_println("jmm_GetLongAttribute: Unknown attribute %d", att);
+ return -1;
+ }
+
+ return result;
}
jboolean jmm_ResetStatistic(JNIEnv* env, jvalue obj, jmmStatisticType type)
{
- log_println("jmm_ResetStatistic: IMPLEMENT ME!");
- return 0;
+ TRACEJMMCALLS(("jmm_ResetStatistic(env=%p, obj=%p, type=%d)", env, obj, type));
+
+ switch (type) {
+ case JMM_STAT_PEAK_THREAD_COUNT:
+ ThreadList::reset_peak_of_active_java_threads();
+ break;
+ default:
+ log_println("jmm_ResetStatistic: Unknown statistic type %d", type);
+ return false;
+ }
+
+ return true;
}
--- /dev/null
+/* src/native/vm/openjdk/sun_misc_Perf.cpp - sun/misc/Perf
+
+ Copyright (C) 2009
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+ Copyright (C) 2009 Theobroma Systems Ltd.
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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 for more details.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+
+#include "native/jni.hpp"
+#include "native/native.hpp"
+
+#include "vm/utf8.h"
+#include "vm/vm.hpp"
+
+
+// Native functions are exported as C functions.
+extern "C" {
+
+/*
+ * Class: sun/misc/Perf
+ * Method: registerNatives
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_misc_Perf_registerNatives(JNIEnv *env, jclass clazz)
+{
+ /* The native methods of this function are already registered in
+ _Jv_sun_misc_Perf_init() which is called during VM
+ startup. */
+}
+
+
+/*
+ * Class: sun/misc/Perf
+ * Method: attach
+ * Signature: (Ljava/lang/String;II)Ljava/nio/ByteBuffer;
+ */
+JNIEXPORT jobject JNICALL Java_sun_misc_Perf_attach(JNIEnv *env, jobject _this, jstring user, jint lvmid, jint mode)
+{
+ log_println("Java_sun_misc_Perf_attach: Not supported!");
+ return NULL;
+}
+
+
+/*
+ * Class: sun/misc/Perf
+ * Method: createByteArray
+ * Signature: (Ljava/lang/String;II[BI)Ljava/nio/ByteBuffer;
+ */
+JNIEXPORT jobject JNICALL Java_sun_misc_Perf_createByteArray(JNIEnv *env, jobject _this, jstring name, jint variability, jint units, jbyteArray value, jint max_length)
+{
+ log_println("Java_sun_misc_Perf_createByteArray: Not supported!");
+ return NULL;
+}
+
+
+/*
+ * Class: sun/misc/Perf
+ * Method: createLong
+ * Signature: (Ljava/lang/String;IIJ)Ljava/nio/ByteBuffer;
+ */
+JNIEXPORT jobject JNICALL Java_sun_misc_Perf_createLong(JNIEnv *env, jobject _this, jstring name, jint variability, jint units, jlong value)
+{
+ log_println("Java_sun_misc_Perf_createLong: Not supported!");
+ return NULL;
+}
+
+
+/*
+ * Class: sun/misc/Perf
+ * Method: detach
+ * Signature: (Ljava/nio/ByteBuffer;)V
+ */
+JNIEXPORT void JNICALL Java_sun_misc_Perf_detach(JNIEnv *env, jobject _this, jobject bb)
+{
+ log_println("Java_sun_misc_Perf_detach: Not supported!");
+}
+
+
+/*
+ * Class: sun/misc/Perf
+ * Method: highResCounter
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_sun_misc_Perf_highResCounter(JNIEnv *env, jobject _this)
+{
+ log_println("Java_sun_misc_Perf_highResCounter: IMPLEMENT ME!");
+ return 0;
+}
+
+
+/*
+ * Class: sun/misc/Perf
+ * Method: highResFrequency
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_sun_misc_Perf_highResFrequency(JNIEnv *env, jobject _this)
+{
+ log_println("Java_sun_misc_Perf_highResFrequency: IMPLEMENT ME!");
+ return 0;
+}
+
+} // extern "C"
+
+
+/* native methods implemented by this file ************************************/
+
+static JNINativeMethod methods[] = {
+ { (char*) "registerNatives", (char*) "()V", (void*) (uintptr_t) &Java_sun_misc_Perf_registerNatives },
+ { (char*) "attach", (char*) "(Ljava/lang/String;II)Ljava/nio/ByteBuffer;", (void*) (uintptr_t) &Java_sun_misc_Perf_attach },
+ { (char*) "createByteArray", (char*) "(Ljava/lang/String;II[BI)Ljava/nio/ByteBuffer;", (void*) (uintptr_t) &Java_sun_misc_Perf_createByteArray },
+ { (char*) "createLong", (char*) "(Ljava/lang/String;IIJ)Ljava/nio/ByteBuffer;", (void*) (uintptr_t) &Java_sun_misc_Perf_createLong },
+ { (char*) "detach", (char*) "(Ljava/nio/ByteBuffer;)V", (void*) (uintptr_t) &Java_sun_misc_Perf_detach },
+ { (char*) "highResCounter", (char*) "()J", (void*) (uintptr_t) &Java_sun_misc_Perf_highResCounter },
+ { (char*) "highResFrequency", (char*) "()J", (void*) (uintptr_t) &Java_sun_misc_Perf_highResFrequency },
+};
+
+
+/* _Jv_sun_misc_Perf_init ******************************************************
+
+ Register native functions.
+
+*******************************************************************************/
+
+void _Jv_sun_misc_Perf_init(void)
+{
+ utf* u = utf_new_char("sun/misc/Perf");
+
+ NativeMethods& nm = VM::get_current()->get_nativemethods();
+ nm.register_methods(u, methods, NATIVE_METHODS_COUNT);
+}
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c++
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
threads_park(isAbsolute, time);
}
+
+/*
+ * Class: sun/misc/Unsafe
+ * Method: getLoadAverage
+ * Signature: ([DI)I
+ */
+JNIEXPORT jint JNICALL Java_sun_misc_Unsafe_getLoadAverage(JNIEnv *env, jobject _this, jdoubleArray loadavg, jint nelem)
+{
+ DoubleArray da(loadavg);
+
+#define MAX_SAMPLES 3
+
+ // Check the passed number of samples.
+ if ((nelem < 0) || (nelem > da.get_length()) || nelem > MAX_SAMPLES) {
+ exceptions_throw_arrayindexoutofboundsexception();
+ return -1;
+ }
+
+ // Actually retrieve samples.
+ double values[MAX_SAMPLES];
+ int result = os::getloadavg(values, nelem);
+
+ // Save samples into the given array.
+ for (int i = 0; i < result; i++) {
+ da.set_element(i, values[i]);
+ }
+
+ return result;
+}
+
} // extern "C"
{ (char*) "putOrderedLong", (char*) "(Ljava/lang/Object;JJ)V", (void*) (uintptr_t) &Java_sun_misc_Unsafe_putOrderedLong },
{ (char*) "unpark", (char*) "(Ljava/lang/Object;)V", (void*) (uintptr_t) &Java_sun_misc_Unsafe_unpark },
{ (char*) "park", (char*) "(ZJ)V", (void*) (uintptr_t) &Java_sun_misc_Unsafe_park },
+ { (char*) "getLoadAverage", (char*) "([DI)I", (void*) (uintptr_t) &Java_sun_misc_Unsafe_getLoadAverage },
};
# include "threads/posix/mutex-posix.hpp"
#endif
+#if __cplusplus
+
+/**
+ * Helper class used to implicitly acquire and release a mutex
+ * within a method scope.
+ */
+class MutexLocker {
+private:
+ Mutex& _mutex;
+
+public:
+ MutexLocker(Mutex& mutex) : _mutex(mutex) { _mutex.lock(); }
+ ~MutexLocker() { _mutex.unlock(); }
+};
+
+#endif
+
#endif /* _MUTEX_HPP */
#include "vm/exceptions.hpp"
#include "vm/global.h"
#include "vm/globals.hpp"
+#include "vm/hook.hpp"
#include "vm/javaobjects.hpp"
#include "vm/options.h"
#include "vm/os.hpp"
#include "vm/jit/asmpart.h"
-#if !defined(__DARWIN__)
+#if defined(__DARWIN__)
+
+typedef struct {
+ Mutex* mutex;
+ Condition* cond;
+ int value;
+} sem_t;
+
+#else
# include <semaphore.h>
#endif
# include "mm/boehm-gc/include/gc.h"
#endif
-#if defined(ENABLE_JVMTI)
-#include "native/jvmti/cacaodbg.h"
-#endif
-
#if defined(__DARWIN__)
/* Darwin has no working semaphore implementation. This one is taken
thread->_global_sp = (Cell *) (intrp_thread_stack + opt_stacksize);
#endif
-#if defined(ENABLE_JVMTI)
- /* fire thread start event */
-
- if (jvmti)
- jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_START);
-#endif
+ // Hook point just before the threads initial method is executed.
+ Hook::thread_start(t);
DEBUGTHREADS("starting", t);
if (m == NULL)
vm_abort("threads_startup_thread: run() method not found in class");
- /* set ThreadMXBean variables */
-
-/* _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++; */
-/* _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++; */
-
-/* if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount > */
-/* _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount) */
-/* _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount = */
-/* _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount; */
-#warning Move to C++
-
#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
// We need to start the run method of java.lang.VMThread.
(void) vm_call_method(m, h);
}
else {
- /* set ThreadMXBean variables */
-
-/* _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++; */
-/* _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++; */
-
-/* if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount > */
-/* _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount) */
-/* _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount = */
-/* _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount; */
-#warning Move to C++
-
/* call passed function, e.g. finalizer_thread */
(function)();
DEBUGTHREADS("stopping", t);
-#if defined(ENABLE_JVMTI)
- /* fire thread end event */
-
- if (jvmti)
- jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_END);
-#endif
+ // Hook point just after the threads initial method returned.
+ Hook::thread_end(t);
/* We ignore the return value. */
(void) thread_detach_current_thread();
- /* set ThreadMXBean variables */
-
-/* _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount--; */
-#warning Move to C++
-
return NULL;
}
}
-/* threads_suspend_thread ******************************************************
-
- Suspend the passed thread. Execution stops until the thread
- is explicitly resumend again.
-
- IN:
- reason.....Reason for suspending this thread.
-
-*******************************************************************************/
-
-bool threads_suspend_thread(threadobject *thread, s4 reason)
+/**
+ * Internal helper function which suspends the current thread. This is
+ * the core method of the suspension mechanism actually blocking the
+ * execution until the suspension reason is cleared again. Note that
+ * the current thread needs to hold the suspension mutex while calling
+ * this function.
+ */
+static void threads_suspend_self()
{
- /* acquire the suspendmutex */
- thread->suspendmutex->lock();
-
- if (thread->suspended) {
- thread->suspendmutex->unlock();
- return false;
- }
+ threadobject* thread = THREADOBJECT;
- /* set the reason for the suspension */
- thread->suspend_reason = reason;
+ DEBUGTHREADS("suspending", thread);
- /* send the suspend signal to the thread */
- assert(thread != THREADOBJECT);
- if (pthread_kill(thread->tid, SIGUSR1) != 0)
- vm_abort("threads_suspend_thread: pthread_kill failed: %s",
- strerror(errno));
+ // Mark thread as suspended.
+ assert(!thread->suspended);
+ assert(thread->suspend_reason != SUSPEND_REASON_NONE);
+ thread->suspended = true;
- /* REMEMBER: do not release the suspendmutex, this is done
- by the thread itself in threads_suspend_ack(). */
+ // Acknowledge the suspension.
+ thread->suspendcond->broadcast();
- return true;
-}
+#if defined(ENABLE_GC_CACAO)
+ // If we are stopping the world, we should send a global ack.
+ if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD)
+ threads_sem_post(&suspend_ack);
+#endif
+ // Release the suspension mutex and wait till we are resumed.
+ thread->suspendcond->wait(thread->suspendmutex);
-/* threads_suspend_ack *********************************************************
+#if defined(ENABLE_GC_CACAO)
+ // XXX This is propably not ok!
+ // If we are starting the world, we should send a global ack.
+ if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD)
+ threads_sem_post(&suspend_ack);
+#endif
- Acknowledges the suspension of the current thread.
+ // Mark thread as not suspended.
+ assert(thread->suspended);
+ assert(thread->suspend_reason == SUSPEND_REASON_NONE);
+ thread->suspended = false;
- IN:
- pc.....The PC where the thread suspended its execution.
- sp.....The SP before the thread suspended its execution.
+ DEBUGTHREADS("resuming", thread);
+}
-*******************************************************************************/
-#if defined(ENABLE_GC_CACAO)
-void threads_suspend_ack(u1* pc, u1* sp)
+/**
+ * Suspend the passed thread. Execution of that thread stops until the thread
+ * is explicitly resumend again.
+ *
+ * @param thread The thread to be suspended.
+ * @param reason Reason for suspending the given thread.
+ * @return True of operation was successful, false otherwise.
+ */
+bool threads_suspend_thread(threadobject *thread, int32_t reason)
{
- threadobject *thread;
+ // Sanity check.
+ assert(reason != SUSPEND_REASON_NONE);
- thread = THREADOBJECT;
+ // Guard this with the suspension mutex.
+ MutexLocker ml(*thread->suspendmutex);
- assert(thread->suspend_reason != 0);
-
- /* TODO: remember dump memory size */
-
- /* inform the GC about the suspension */
- if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD && gc_pending) {
+ // Check if thread is already suspended.
+ if (thread->suspended)
+ return false;
- /* check if the GC wants to leave the thread running */
- if (!gc_suspend(thread, pc, sp)) {
+ // Check if thread is in the process of suspending.
+ if (thread->suspend_reason != SUSPEND_REASON_NONE)
+ return false;
- /* REMEMBER: we do not unlock the suspendmutex because the thread
- will suspend itself again at a later time */
- return;
+ // Set the reason for suspending the thread.
+ thread->suspend_reason = reason;
- }
+ if (thread == THREADOBJECT) {
+ // We already hold the suspension mutex and can suspend ourselves
+ // immediately without using signals at all.
+ threads_suspend_self();
}
-
- /* mark this thread as suspended and remember the PC */
- thread->pc = pc;
- thread->suspended = true;
-
- /* if we are stopping the world, we should send a global ack */
- if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
- threads_sem_post(&suspend_ack);
+ else {
+ // Send the suspend signal to the other thread.
+ if (pthread_kill(thread->tid, SIGUSR1) != 0)
+ os::abort_errno("threads_suspend_thread: pthread_kill failed");
+
+ // Wait for the thread to acknowledge the suspension.
+ // XXX A possible optimization would be to not wait here, but you
+ // better think this through twice before trying it!
+ thread->suspendcond->wait(thread->suspendmutex);
}
- DEBUGTHREADS("suspending", thread);
+ return true;
+}
- /* release the suspension mutex and wait till we are resumed */
- thread->suspendcond->wait(thread->suspendmutex);
- DEBUGTHREADS("resuming", thread);
+/**
+ * Resumes execution of the passed thread.
+ *
+ * @param thread The thread to be resumed.
+ * @param reason Reason for suspending the given thread.
+ * @return True of operation was successful, false otherwise.
+ */
+bool threads_resume_thread(threadobject *thread, int32_t reason)
+{
+ // Sanity check.
+ assert(thread != THREADOBJECT);
+ assert(reason != SUSPEND_REASON_NONE);
- /* if we are stopping the world, we should send a global ack */
- if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
- threads_sem_post(&suspend_ack);
- }
+ // Guard this with the suspension mutex.
+ MutexLocker ml(*thread->suspendmutex);
- /* TODO: free dump memory */
+ // Check if thread really is suspended.
+ if (!thread->suspended)
+ return false;
- /* release the suspendmutex */
- thread->suspendmutex->unlock();
-}
-#endif
+ // Threads can only be resumed for the same reason they were suspended.
+ if (thread->suspend_reason != reason)
+ return false;
+ // Clear the reason for suspending the thread.
+ thread->suspend_reason = SUSPEND_REASON_NONE;
-/* threads_resume_thread *******************************************************
+ // Tell everyone that the thread should resume.
+ thread->suspendcond->broadcast();
- Resumes the execution of the passed thread.
+ return true;
+}
-*******************************************************************************/
-#if defined(ENABLE_GC_CACAO)
-bool threads_resume_thread(threadobject *thread)
+/**
+ * Acknowledges the suspension of the current thread.
+ */
+void threads_suspend_ack()
{
- /* acquire the suspendmutex */
- thread->suspendmutex->lock();
-
- if (!thread->suspended) {
- thread->suspendmutex->unlock();
- return false;
- }
-
- thread->suspended = false;
-
- /* tell everyone that the thread should resume */
- assert(thread != THREADOBJECT);
- thread->suspendcond->broadcast();
+ threadobject* thread = THREADOBJECT;
- /* release the suspendmutex */
- thread->suspendmutex->unlock();
+ // Guard this with the suspension mutex.
+ MutexLocker ml(*thread->suspendmutex);
- return true;
+ // Suspend ourselves while holding the suspension mutex.
+ threads_suspend_self();
}
-#endif
/* threads_join_all_threads ****************************************************
#define THREAD_FLAG_DAEMON 0x04 /* daemon thread */
#define THREAD_FLAG_IN_NATIVE 0x08 /* currently executing native code */
-#define SUSPEND_REASON_JNI 1 /* suspended from JNI */
-#define SUSPEND_REASON_STOPWORLD 2 /* suspended from stop-thw-world */
+#define SUSPEND_REASON_NONE 0 /* no reason to suspend */
+#define SUSPEND_REASON_JAVA 1 /* suspended from java.lang.Thread */
+#define SUSPEND_REASON_STOPWORLD 2 /* suspended from stop-the-world */
+#define SUSPEND_REASON_DUMP 3 /* suspended from threadlist dumping */
+#define SUSPEND_REASON_JVMTI 4 /* suspended from JVMTI agent */
typedef struct threadobject threadobject;
#include "vm/jit/intrp/intrp.h"
#endif
-#if defined(__DARWIN__)
-# include <mach/mach.h>
-
-typedef struct {
- Mutex* mutex;
- Condition* cond;
- int value;
-} sem_t;
-
-#else
-# include <semaphore.h>
-#endif
-
// FIXME
#ifdef __cplusplus
/* functions ******************************************************************/
-void threads_sem_init(sem_t *sem, bool shared, int value);
-void threads_sem_wait(sem_t *sem);
-void threads_sem_post(sem_t *sem);
-
void threads_start_thread(threadobject *thread, functionptr function);
void threads_set_thread_priority(pthread_t tid, int priority);
-#if defined(ENABLE_GC_CACAO)
-bool threads_suspend_thread(threadobject *thread, s4 reason);
-void threads_suspend_ack(u1* pc, u1* sp);
-bool threads_resume_thread(threadobject *thread);
-#endif
+bool threads_suspend_thread(threadobject *thread, int32_t reason);
+bool threads_resume_thread(threadobject *thread, int32_t reason);
+void threads_suspend_ack();
void threads_join_all_threads(void);
static void thread_create_initial_threadgroups(void);
static void thread_create_initial_thread(void);
-static threadobject *thread_new(void);
+static threadobject *thread_new(int32_t flags);
/* threads_preinit *************************************************************
/* Create internal thread data-structure for the main thread. */
- mainthread = thread_new();
+ mainthread = thread_new(THREAD_FLAG_JAVA);
/* The main thread should always have index 1. */
vm_abort("threads_preinit: main thread index not 1: %d != 1",
mainthread->index);
- /* thread is a Java thread and running */
+ /* Thread is already running. */
- mainthread->flags |= THREAD_FLAG_JAVA;
mainthread->state = THREAD_STATE_RUNNABLE;
/* Store the internal thread data-structure in the TSD. */
*******************************************************************************/
-static threadobject *thread_new(void)
+static threadobject *thread_new(int32_t flags)
{
int32_t index;
threadobject *t;
t->index = index;
t->thinlock = Lockword::pre_compute_thinlock(t->index);
- t->flags = 0;
+ t->flags = flags;
t->state = THREAD_STATE_NEW;
#if defined(ENABLE_GC_CACAO)
/* Create internal thread data-structure. */
- t = thread_new();
-
- t->flags |= THREAD_FLAG_INTERNAL | THREAD_FLAG_DAEMON;
+ t = thread_new(THREAD_FLAG_INTERNAL | THREAD_FLAG_DAEMON);
/* The thread is flagged as (non-)daemon thread, we can leave the
mutex. */
/* Create internal thread data-structure. */
- threadobject* t = thread_new();
-
- /* this is a normal Java thread */
-
- t->flags |= THREAD_FLAG_JAVA;
+ threadobject* t = thread_new(THREAD_FLAG_JAVA);
#if defined(ENABLE_JAVASE)
/* Is this a daemon thread? */
/* Create internal thread data structure. */
- t = thread_new();
-
- /* Thread is a Java thread and running. */
-
- t->flags = THREAD_FLAG_JAVA;
+ t = thread_new(THREAD_FLAG_JAVA);
if (isdaemon)
t->flags |= THREAD_FLAG_DAEMON;
/* src/threads/threadlist.cpp - thread list
- Copyright (C) 2008
+ Copyright (C) 2008, 2009
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
List<threadobject*> ThreadList::_free_thread_list; // list of free threads
List<int32_t> ThreadList::_free_index_list; // list of free thread indexes
+int32_t ThreadList::_number_of_started_java_threads;
+int32_t ThreadList::_number_of_active_java_threads;
+int32_t ThreadList::_peak_of_active_java_threads;
int32_t ThreadList::_number_of_non_daemon_threads;
*/
void ThreadList::dump_threads()
{
- // XXX we should stop the world here
+ // XXX we should stop the world here and remove explicit
+ // thread suspension from the loop below.
// Lock the thread lists.
lock();
printf("Full thread dump CACAO "VERSION":\n");
// Iterate over all started threads.
+ threadobject* self = THREADOBJECT;
for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
threadobject* t = *it;
if (t->state == THREAD_STATE_NEW)
continue;
-#if defined(ENABLE_GC_CACAO)
- /* Suspend the thread. */
- /* XXX Is the suspend reason correct? */
+ /* Suspend the thread (and ignore return value). */
- if (threads_suspend_thread(t, SUSPEND_REASON_JNI) == false)
- vm_abort("threads_dump: threads_suspend_thread failed");
-#endif
+ if (t != self)
+ (void) threads_suspend_thread(t, SUSPEND_REASON_DUMP);
/* Print thread info. */
stacktrace_print_of_thread(t);
-#if defined(ENABLE_GC_CACAO)
- /* Resume the thread. */
+ /* Resume the thread (and ignore return value). */
- if (threads_resume_thread(t) == false)
- vm_abort("threads_dump: threads_resume_thread failed");
-#endif
+ if (t != self)
+ (void) threads_resume_thread(t, SUSPEND_REASON_DUMP);
}
// Unlock the thread lists.
}
+/**
+ * Fills the passed list with all currently active threads which should be
+ * visible to Java. Creating a copy of the thread list here, is the only way
+ * to ensure we do not end up in a dead-lock when iterating over the list.
+ *
+ * @param list list class to be filled
+ */
+void ThreadList::get_active_java_threads(List<threadobject*> &list)
+{
+ // Lock the thread lists.
+ lock();
+
+ // Iterate over all active threads.
+ for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
+ threadobject* t = *it;
+
+ // We skip internal threads.
+ if (t->flags & THREAD_FLAG_INTERNAL)
+ continue;
+
+ list.push_back(t);
+ }
+
+ // Unlock the thread lists.
+ unlock();
+}
+
+
/**
* Return a free thread object.
*
}
+/**
+ * Return the number of daemon threads visible to Java.
+ *
+ * NOTE: This function does a linear-search over the threads list,
+ * because it is only used by the management interface.
+ *
+ * @return number of daemon threads
+ */
+int32_t ThreadList::get_number_of_daemon_java_threads(void)
+{
+ int number = 0;
+
+ // Lock the thread lists.
+ lock();
+
+ // Iterate over all active threads.
+ for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
+ threadobject* t = *it;
+
+ // We skip internal threads.
+ if (t->flags & THREAD_FLAG_INTERNAL)
+ continue;
+
+ if (thread_is_daemon(t))
+ number++;
+ }
+
+ // Unlock the thread lists.
+ unlock();
+
+ return number;
+}
+
+
/**
* Return the number of non-daemon threads.
*
/* src/threads/threadlist.hpp - different thread-lists
- Copyright (C) 2008
+ Copyright (C) 2008, 2009
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
#include "toolbox/list.hpp"
+#include "vm/global.h"
+
/* ThreadList *****************************************************************/
static List<threadobject*> _free_thread_list; // list of free threads
static List<int32_t> _free_index_list; // list of free thread indexes
+ // Thread counters visible to Java.
+ static int32_t _number_of_started_java_threads;
+ static int32_t _number_of_active_java_threads;
+ static int32_t _peak_of_active_java_threads;
+
+ // Thread counters for internal usage.
static int32_t _number_of_non_daemon_threads;
static void remove_from_active_thread_list(threadobject* t);
// TODO make private
static void add_to_active_thread_list(threadobject* t);
- static void dump_threads();
- static void get_active_threads(List<threadobject*> &list);
+ // Thread management methods.
static threadobject* get_main_thread();
static threadobject* get_free_thread();
static int32_t get_free_thread_index();
- static int32_t get_number_of_non_daemon_threads();
static threadobject* get_thread_by_index(int32_t index);
static threadobject* get_thread_from_java_object(java_handle_t* h);
static void release_thread(threadobject* t);
+
+ // Thread listing methods.
+ static void get_active_threads(List<threadobject*> &list);
+ static void get_active_java_threads(List<threadobject*> &list);
+
+ // Thread counting methods visible to Java.
+ static int32_t get_number_of_started_java_threads();
+ static int32_t get_number_of_active_java_threads();
+ static int32_t get_number_of_daemon_java_threads();
+ static int32_t get_peak_of_active_java_threads();
+ static void reset_peak_of_active_java_threads();
+
+ // Thread counting methods for internal use.
+ static int32_t get_number_of_active_threads();
+ static int32_t get_number_of_non_daemon_threads();
+
+ // Debugging methods.
+ static void dump_threads();
};
struct ThreadListLocker {
inline void ThreadList::add_to_active_thread_list(threadobject* t)
{
_active_thread_list.push_back(t);
+
+ // Update counter variables.
+ if ((t->flags & THREAD_FLAG_INTERNAL) == 0) {
+ _number_of_started_java_threads++;
+ _number_of_active_java_threads++;
+ _peak_of_active_java_threads = MAX(_peak_of_active_java_threads, _number_of_active_java_threads);
+ }
}
inline void ThreadList::remove_from_active_thread_list(threadobject* t)
{
_active_thread_list.remove(t);
+
+ // Update counter variables.
+ if ((t->flags & THREAD_FLAG_INTERNAL) == 0) {
+ _number_of_active_java_threads--;
+ }
}
inline void ThreadList::add_to_free_thread_list(threadobject* t)
return _active_thread_list.front();
}
+inline int32_t ThreadList::get_number_of_active_threads()
+{
+ return _active_thread_list.size();
+}
+
+inline int32_t ThreadList::get_number_of_started_java_threads()
+{
+ return _number_of_started_java_threads;
+}
+
+inline int32_t ThreadList::get_number_of_active_java_threads()
+{
+ return _number_of_active_java_threads;
+}
+
+inline int32_t ThreadList::get_peak_of_active_java_threads()
+{
+ return _peak_of_active_java_threads;
+}
+
+inline void ThreadList::reset_peak_of_active_java_threads()
+{
+ _peak_of_active_java_threads = _number_of_active_java_threads;
+}
+
#else
typedef struct ThreadList ThreadList;
--- /dev/null
+/* src/toolbox/hashtable.hpp - hashtable classes
+
+ Copyright (C) 2009
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+ Copyright (C) 2009 Theobroma Systems Ltd.
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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 for more details.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#ifndef _HASHTABLE_HPP
+#define _HASHTABLE_HPP
+
+#include "config.h"
+
+#if __cplusplus
+
+// XXX This is a TR1 header and not (yet) part of the C++ standard, so we
+// should not use it. The solution is to implement the below stuff
+// ourselves. This will be done, sometimes, soon, I hope ...
+#include <tr1/unordered_map>
+
+
+/**
+ * Default hashing function for hashtable implementation.
+ */
+template<class T> class Hasher {
+ // XXX Implement me!
+};
+
+
+/**
+ * Hashtable implementation.
+ */
+template<class Key, class T,
+ class Hash = Hasher<Key>,
+ class Pred = std::equal_to<Key> >
+class Hashtable :
+ protected std::tr1::unordered_map<Key,T,Hash,Pred> {
+public:
+ // Constructor.
+ Hashtable(size_t n) : std::tr1::unordered_map<Key,T,Hash,Pred>(n) {}
+
+ // Make iterator of TR1 unordered map visible.
+ using std::tr1::unordered_map<Key,T,Hash,Pred>::iterator;
+
+ // Make functions of TR1 unordered map visible.
+ using std::tr1::unordered_map<Key,T,Hash,Pred>::end;
+ using std::tr1::unordered_map<Key,T,Hash,Pred>::find;
+ using std::tr1::unordered_map<Key,T,Hash,Pred>::insert;
+};
+
+
+// Required by LockableHashtable.
+#include "threads/mutex.hpp"
+
+
+/**
+ * Hashtable implementation with a Mutex.
+ */
+template<class Key, class T,
+ class Hash = Hasher<Key>,
+ class Pred = std::equal_to<Key> >
+class LockableHashtable :
+ public Hashtable<Key,T,Hash,Pred>,
+ public Mutex {
+public:
+ // Constructor.
+ LockableHashtable(size_t n) : Hashtable<Key,T,Hash,Pred>(n) {}
+};
+
+#endif
+
+#endif /* _HASHTABLE_HPP */
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c++
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
#include "vm/vm.hpp"
-/* _Jv_getcwd ******************************************************************
-
- Return the current working directory.
-
- RETURN VALUE:
- pointer to a char array allocated by MNEW, or
- NULL if memory could not be allocated.
-
-*******************************************************************************/
-
-char *_Jv_getcwd(void)
-{
- char *buf;
- s4 size;
-
- size = 1024;
-
- buf = MNEW(char, size);
-
- while (buf) {
- if (getcwd(buf, size) != NULL)
- return buf;
-
- MFREE(buf, char, size);
-
- /* too small buffer or a more serious problem */
-
- if (errno != ERANGE)
- vm_abort("getcwd failed: %s", strerror(errno));
-
- /* double the buffer size */
-
- size *= 2;
-
- buf = MNEW(char, size);
- }
-
- return NULL;
-}
-
-
/* get_variable_message_length *************************************************
This function simluates the print of a variable message and
extern "C" {
#endif
-char *_Jv_getcwd(void);
int get_variable_message_length(const char *fmt, va_list ap);
#ifdef __cplusplus
finalizer.hpp \
globals.cpp \
globals.hpp \
+ hook.hpp \
initialize.cpp \
initialize.hpp \
javaobjects.cpp \
}
-/* classcache_get_loaded_classes ***********************************************
-
- Returns an array of all loaded classes as array. The array is
- allocaed on the Java heap.
-
-*******************************************************************************/
-
-#if defined(ENABLE_JVMTI)
-void classcache_get_loaded_classes(s4 *class_count_ptr,
- classinfo ***classes_ptr)
-{
- classinfo **classes;
- s4 class_count;
- classcache_name_entry *en;
- classcache_class_entry *clsen;
- s4 i;
- s4 j;
-
- CLASSCACHE_LOCK();
-
- /* get the number of loaded classes and allocate the array */
-
- class_count = classcache_number_of_loaded_classes();
-
- classes = GCMNEW(classinfo*, class_count);
-
- /* look in every slot of the hashtable */
-
- for (i = 0, j = 0; i < hashtable_classcache.size; i++) {
- /* iterate over hashlink */
-
- for (en = hashtable_classcache.ptr[i]; en != NULL; en = en->hashlink) {
- /* filter pseudo classes $NEW$, $NULL$, $ARRAYSTUB$ out */
-
- if (en->name->text[0] == '$')
- continue;
-
- /* iterate over classes with same name */
-
- for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
- /* get only loaded classes */
-
- if (clsen->classobj != NULL) {
- classes[j] = clsen->classobj;
- j++;
- }
- }
- }
- }
-
- /* pass the return values */
-
- *class_count_ptr = class_count;
- *classes_ptr = classes;
-
- CLASSCACHE_UNLOCK();
-}
-#endif /* defined(ENABLE_JVMTI) */
-
-
/* classcache_foreach_loaded_class *********************************************
Calls the given function for each loaded class.
void classcache_foreach_loaded_class(classcache_foreach_functionptr_t func,
void *data);
-#if defined(ENABLE_JVMTI)
-void classcache_get_loaded_classes(s4 *class_count_ptr,
- classinfo ***classes_ptr);
-#endif
-
#ifndef NDEBUG
void classcache_debug_dump(FILE *file,utf *only);
#endif
/* src/vm/cycles-stats.h - macros for cycle count statistics
- Copyright (C) 1996-2005, 2006 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, 2009
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Contact: cacao@cacaojvm.org
-
- Authors: Edwin Steiner
-
- Changes:
-
*/
#ifndef _CYCLES_STATS_H
#include <stdio.h>
+#include "md.h"
+
#define CYCLES_STATS_DECLARE(name,nbins,divisor) \
static const int CYCLES_STATS_##name##_MAX = (nbins); \
static const int CYCLES_STATS_##name##_DIV = (divisor); \
static u8 cycles_stats_##name##_min = 1000000000;
#define CYCLES_STATS_GET(var) \
- (var) = asm_get_cycle_count() \
+ (var) = md_get_cycle_count() \
#define CYCLES_STATS_COUNT(name,cyclesexpr) \
do { \
} while (0)
#define CYCLES_STATS_DECLARE_AND_START \
- u8 cycles_start = asm_get_cycle_count(); \
+ u8 cycles_start = md_get_cycle_count(); \
u8 cycles_end;
#define CYCLES_STATS_DECLARE_AND_START_WITH_OVERHEAD \
- u8 cycles_start = asm_get_cycle_count(); \
- u8 cycles_overhead = asm_get_cycle_count(); \
+ u8 cycles_start = md_get_cycle_count(); \
+ u8 cycles_overhead = md_get_cycle_count(); \
u8 cycles_end;
#define CYCLES_STATS_END(name) \
- cycles_end = asm_get_cycle_count(); \
+ cycles_end = md_get_cycle_count(); \
CYCLES_STATS_COUNT(name, cycles_end - cycles_start);
#define CYCLES_STATS_END_WITH_OVERHEAD(name,ovname) \
- cycles_end = asm_get_cycle_count(); \
+ cycles_end = md_get_cycle_count(); \
CYCLES_STATS_COUNT(ovname, cycles_overhead - cycles_start); \
CYCLES_STATS_COUNT(name, cycles_end - cycles_overhead);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void cycles_stats_print(FILE *file,
const char *name, int nbins, int div,
u4 *bins, u8 count, u8 total, u8 min, u8 max,
int overhead);
+#ifdef __cplusplus
+}
+#endif
+
#else /* !defined(ENABLE_CYCLES_STATS) */
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
-#include <sys/mman.h>
#include "vm/types.h"
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
+#ifndef MAX
+# define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
/* forward typedefs ***********************************************************/
--- /dev/null
+/* src/vm/hook.hpp - hook points inside the VM
+
+ Copyright (C) 2009
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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 for more details.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+#ifndef _HOOK_HPP
+#define _HOOK_HPP
+
+#include "config.h"
+
+#if defined(ENABLE_OPAGENT)
+#include "vm/jit/oprofile-agent.hpp"
+#endif
+
+
+/**
+ * Hook points are inline functions acting as probes scattered throughout
+ * several VM subsystems. They can be used to implement event generation
+ * or statistics gathering without polluting the source code. Hence all
+ * compiler macro and runtime checks should be done in this file. One
+ * example of where hooks are useful is JVMTI event firing.
+ */
+namespace Hook {
+ void breakpoint (Breakpoint *bp);
+ void class_linked (classinfo *c);
+ void class_loaded (classinfo *c);
+ void jit_generated (methodinfo *m, codeinfo *code);
+ void jit_recycled (methodinfo *m, codeinfo *code);
+ void method_enter (methodinfo *m);
+ void method_exit (methodinfo *m);
+ void method_unwind (methodinfo *m);
+ void native_resolved(methodinfo *m, void *symbol, void **symbolptr);
+ void thread_start (threadobject *t);
+ void thread_end (threadobject *t);
+ void vm_init ();
+ void vm_preinit ();
+ void vm_shutdown ();
+}
+
+
+inline void Hook::breakpoint(Breakpoint *bp)
+{
+#if defined(ENABLE_JVMTI)
+ methodinfo* m = bp->method;
+ int32_t l = bp->location;
+
+ log_message_method("JVMTI: Reached breakpoint in method ", m);
+ log_println("JVMTI: Reached breakpoint at location %d", l);
+#endif
+}
+
+inline void Hook::class_linked(classinfo *c)
+{
+ /* nop */
+}
+
+inline void Hook::class_loaded(classinfo *c)
+{
+ /* nop */
+}
+
+/**
+ * Hook point just after code was generated. Note that one method can have
+ * multiple code realizations, the hook is fired for each of them. The code
+ * was not yet executed.
+ *
+ * @param m The method for which code was generated.
+ * @param code The fully initialized codeinfo for the generated code.
+ */
+inline void Hook::jit_generated(methodinfo *m, codeinfo *code)
+{
+#if defined(ENABLE_OPAGENT)
+ if (opt_EnableOpagent)
+ OprofileAgent::newmethod(m);
+#endif
+}
+
+inline void Hook::method_enter(methodinfo *m)
+{
+ /* nop */
+}
+
+inline void Hook::method_exit(methodinfo *m)
+{
+ /* nop */
+}
+
+inline void Hook::method_unwind(methodinfo *m)
+{
+ /* nop */
+}
+
+inline void Hook::native_resolved(methodinfo *m, void *symbol, void **symbolptr)
+{
+ /* nop */
+}
+
+inline void Hook::thread_start(threadobject *t)
+{
+ /* nop */
+}
+
+inline void Hook::thread_end(threadobject *t)
+{
+ /* nop */
+}
+
+/**
+ * Hook point after the VM is initialized. At this point the VM is fully
+ * operating and ready to execute Java code. Final intializations and thread
+ * startup should be done here.
+ */
+inline void Hook::vm_init()
+{
+ /* nop */
+}
+
+/**
+ * Hook point before the VM is initialized. At this point the VM can not
+ * yet execute Java code but some central native subsystems are initialized.
+ * Only basic initialization steps should be done here.
+ */
+inline void Hook::vm_preinit()
+{
+#if defined(ENABLE_OPAGENT)
+ if (opt_EnableOpagent)
+ OprofileAgent::initialize();
+#endif
+}
+
+/**
+ * Hook point before the VM is actually destroyed. At this point the VM is
+ * still running, but all non-daemon threads have terminated and resources
+ * are ready to be reclaimed. Final cleanup tasks should be done here.
+ */
+inline void Hook::vm_shutdown()
+{
+#if defined(ENABLE_OPAGENT)
+ if (opt_EnableOpagent)
+ OprofileAgent::close();
+#endif
+}
+
+
+#endif /* _HOOK_HPP */
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c++
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
}
+/**
+ * Constructs a new instance of the class by calling the
+ * appropriate Java initializer.
+ */
+java_lang_management_MemoryUsage::java_lang_management_MemoryUsage(int64_t init, int64_t used, int64_t commited, int64_t maximum)
+{
+ // Load the class.
+ // XXX Maybe this should be made global at some points.
+ classinfo* class_java_lang_management_MemoryUsage;
+ if (!(class_java_lang_management_MemoryUsage = load_class_bootstrap(utf_new_char("java/lang/management/MemoryUsage"))))
+ return;
+
+ // Find the appropriate initializer.
+ // XXX Maybe this should be made global at some points.
+ methodinfo* m = class_findmethod(class_java_lang_management_MemoryUsage,
+ utf_init,
+ utf_new_char("(JJJJ)V"));
+
+ if (m == NULL)
+ return;
+
+ // Instantiate a new object.
+ _handle = builtin_new(class_java_lang_management_MemoryUsage);
+
+ if (is_null())
+ return;
+
+ // Call initializer.
+ (void) vm_call_method(m, _handle, init, used, commited, maximum);
+}
+
+
/**
* Constructs a Java object with the given
* java.lang.reflect.Constructor.
#if defined(ENABLE_JAVASE)
+/**
+ * java/lang/management/MemoryUsage
+ *
+ * Object layout:
+ *
+ * 0. object header
+ * [other fields are not used]
+ */
+class java_lang_management_MemoryUsage : public java_lang_Object, private FieldAccess {
+public:
+ java_lang_management_MemoryUsage(java_handle_t* h) : java_lang_Object(h) {}
+ java_lang_management_MemoryUsage(int64_t init, int64_t used, int64_t commited, int64_t maximum);
+};
+
+
# if defined(ENABLE_ANNOTATIONS)
/**
* OpenJDK sun/reflect/ConstantPool
#define STACKFRMAE_RA_BETWEEN_FRAMES 0
#define STACKFRAME_RA_TOP_OF_FRAME 1
+#define STACKFRAME_RA_LINKAGE_AREA 0
#define STACKFRAME_LEAFMETHODS_RA_REGISTER 1
#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 0
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->sc_pc;
- sp = (u1 *) _mc->sc_regs[REG_SP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
#define STACKFRMAE_RA_BETWEEN_FRAMES 0
#define STACKFRAME_RA_TOP_OF_FRAME 1
+#define STACKFRAME_RA_LINKAGE_AREA 0
#define STACKFRAME_LEAFMETHODS_RA_REGISTER 1
#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 0
/* calculate stackframe size */
cd->stackframesize =
- 4 + /* return address */
- sizeof(stackframeinfo_t) + /* stackframeinfo */
- sizeof(localref_table) + /* localref_table */
- nmd->memuse * 4; /* stack arguments */
+ 1 + /* return address */
+ sizeof(stackframeinfo_t) / SIZEOF_VOID_P + /* stackframeinfo */
+ sizeof(localref_table) / SIZEOF_VOID_P + /* localref_table */
+ nmd->memuse; /* stack arguments */
/* align stack to 8-byte */
- cd->stackframesize = (cd->stackframesize + 4) & ~4;
+ cd->stackframesize = (cd->stackframesize + 1) & ~1;
/* create method header */
/* generate stub code */
M_STMFD(1<<REG_LR, REG_SP);
- M_SUB_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize / 4 - 1);
-
-#if !defined(NDEBUG)
- if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
- emit_verbosecall_enter(jd);
-#endif
+ M_SUB_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize * 2 - 1);
#if defined(ENABLE_GC_CACAO)
/* Save callee saved integer registers in stackframeinfo (GC may
}
}
else {
- s1 = md->params[i].regoff + cd->stackframesize;
+ s1 = md->params[i].regoff + cd->stackframesize * 8;
s2 = nmd->params[j].regoff;
if (IS_2_WORD_TYPE(t)) {
}
#endif
-#if !defined(NDEBUG)
- if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
- emit_verbosecall_exit(jd);
-#endif
-
/* remove native stackframe info */
/* TODO: improve this store/load */
/* finish stub code, but do not yet return to caller */
- M_ADD_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize / 4 - 1);
+ M_ADD_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize * 2 - 1);
M_LDMFD(1<<REG_LR, REG_SP);
/* check for exception */
#define M_STR(d, base, offset) \
do { \
- assert((d) != REG_ITMP3); \
CHECK_OFFSET(offset, 0x0fffff); \
if (IS_OFFSET(offset, 0x000fff)) { \
M_STR_INTERN(d, base, offset); \
} else { \
+ assert((d) != REG_ITMP3); \
if ((offset) > 0) { \
M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
M_STR_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
#define M_STRD(d, base, offset) \
do { \
- assert(GET_LOW_REG(d) != REG_ITMP3); \
- assert(GET_HIGH_REG(d) != REG_ITMP3); \
CHECK_OFFSET(offset, 0x0fffff - 4); \
if (IS_OFFSET(offset, 0x000fff - 4)) { \
M_STRD_INTERN(d,base,offset); \
dolog("M_STRD: this offset seems to be complicated (%d)", offset); \
assert(0); \
} else { \
+ assert(GET_LOW_REG(d) != REG_ITMP3); \
+ assert(GET_HIGH_REG(d) != REG_ITMP3); \
if ((offset) > 0) { \
M_ADD_IMM(REG_ITMP3, base, IMM_ROTL((offset) >> 12, 6)); \
M_STRD_INTERN(d, REG_ITMP3, (offset) & 0x000fff); \
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- scontext_t *_sc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _sc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _sc->arm_pc;
- sp = (u1 *) _sc->arm_sp;
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
/* cache flush function */
void asm_cacheflush(void* addr, int nbytes);
-u8 asm_get_cycle_count(void);
-
void *md_asm_codegen_get_pv_from_pc(void *ra);
#if defined(ENABLE_ESCAPE_CHECK)
case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */
/* sx.val.i = constant */
+ case ICMD_IMULPOW2: /* ..., value ==> ..., value * (2 ^ constant) */
+ /* sx.val.i = constant */
case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */
/* sx.val.l = constant */
+ case ICMD_LMULPOW2: /* ..., value ==> ..., value * (2 ^ constant) */
+ /* sx.val.l = constant */
case ICMD_IDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
case ICMD_IREM: /* ..., val1, val2 ==> ..., val1 % val2 */
case ICMD_IDIVPOW2: /* ..., value ==> ..., value >> constant */
/* This approach is much faster than moving the field
address inline into a register. */
- // XXX ARM: M_DSEG_LOAD(REG_ITMP3, disp);
M_ALD_DSEG(REG_ITMP1, disp);
switch (fieldtype) {
/* This approach is much faster than moving the field
address inline into a register. */
- // XXX ARM: M_DSEG_LOAD(REG_ITMP3, disp);
M_ALD_DSEG(REG_ITMP1, disp);
switch (fieldtype) {
REPLACEMENT_POINT_RETURN(cd, iptr);
s1 = emit_load_s1(jd, iptr, REG_FRESULT);
- // XXX ARM: Here this was M_CAST_F2I(s1, REG_RESULT);
+#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
emit_fmove(cd, s1, REG_FRESULT);
+#else
+ M_CAST_F2I(s1, REG_RESULT);
+#endif
goto nowperformreturn;
case ICMD_DRETURN: /* ..., retvalue ==> ... */
REPLACEMENT_POINT_RETURN(cd, iptr);
s1 = emit_load_s1(jd, iptr, REG_FRESULT);
- // XXX ARM: Here this was M_CAST_D2L(s1, REG_RESULT_PACKED);
+#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
emit_dmove(cd, s1, REG_FRESULT);
+#else
+ M_CAST_D2L(s1, REG_LRESULT);
+#endif
goto nowperformreturn;
nowperformreturn:
continue;
if (!md->params[i].inmemory) {
- assert(ARG_CNT > 0);
- s1 = emit_load(jd, iptr, var, d);
-
switch (var->type) {
case TYPE_ADR:
case TYPE_INT:
- assert(INT_ARG_CNT > 0);
+ s1 = emit_load(jd, iptr, var, d);
emit_imove(cd, s1, d);
break;
-#if 0 //XXX For ARM:
-if (!md->params[s3].inmemory) {
- s1 = emit_load(jd, iptr, var, REG_FTMP1);
- if (IS_2_WORD_TYPE(var->type))
- M_CAST_D2L(s1, d);
- else
- M_CAST_F2I(s1, d);
-}
-#endif //XXX End of ARM!
-
case TYPE_LNG:
+ s1 = emit_load(jd, iptr, var, d);
emit_lmove(cd, s1, d);
break;
case TYPE_FLT:
+#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
+ s1 = emit_load(jd, iptr, var, d);
emit_fmove(cd, s1, d);
+#else
+ s1 = emit_load(jd, iptr, var, REG_FTMP1);
+ M_CAST_F2I(s1, d);
+#endif
break;
case TYPE_DBL:
+#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
+ s1 = emit_load(jd, iptr, var, d);
emit_dmove(cd, s1, d);
+#else
+ s1 = emit_load(jd, iptr, var, REG_FTMP1);
+ M_CAST_D2L(s1, d);
+#endif
break;
}
}
emit_store_dst(jd, iptr, s1);
break;
-#if 0 //XXX For ARM!!!
-#if !defined(ENABLE_SOFTFLOAT)
- } else {
- s1 = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
- if (IS_2_WORD_TYPE(d))
- M_CAST_L2D(REG_RESULT_PACKED, s1);
- else
- M_CAST_I2F(REG_RESULT, s1);
- }
-#endif /* !defined(ENABLE_SOFTFLOAT) */
-#endif //XXX End of ARM
-
case TYPE_FLT:
+#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT);
emit_fmove(cd, REG_FRESULT, s1);
+#else
+ s1 = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ M_CAST_I2F(REG_RESULT, s1);
+#endif
emit_store_dst(jd, iptr, s1);
break;
case TYPE_DBL:
+#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT);
emit_dmove(cd, REG_FRESULT, s1);
+#else
+ s1 = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+ M_CAST_L2D(REG_LRESULT, s1);
+#endif
emit_store_dst(jd, iptr, s1);
break;
/* src/vm/jit/executionstate.c - execution-state handling
- Copyright (C) 2007, 2008
+ Copyright (C) 2007, 2008, 2009
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
#include <stdint.h>
#include <stdio.h>
+#include "arch.h"
+#include "md.h"
#include "md-abi.h"
#include "vm/descriptor.hpp"
#include "vm/jit/executionstate.h"
+/**
+ * Restore callee-saved registers (including the RA register),
+ * set the stack pointer to the next stackframe,
+ * set the PC to the return address of the popped frame.
+ *
+ * *** This function imitates the effects of the method epilog ***
+ * *** and returning from the method call. ***
+ *
+ * @param es Execution state to be modified.
+ * NOTE: es->code and es->pv are NOT updated.
+ */
+void executionstate_pop_stackframe(executionstate_t *es)
+{
+ int32_t reg;
+ int32_t i;
+
+ // Sanity checks.
+ assert(es->code != NULL);
+
+ // Calculate the size of the stackframe.
+ int32_t framesize = md_stacktrace_get_framesize(es->code);
+
+ // Read the return address.
+ uint8_t* ra;
+#if STACKFRAME_LEAFMETHODS_RA_REGISTER
+ if (code_is_leafmethod(es->code))
+ ra = es->ra;
+ else
+#endif
+ ra = (u1*) md_stacktrace_get_returnaddress(es->sp, framesize);
+
+ // Calculate the base of the stack frame.
+ uintptr_t sp = (uintptr_t) es->sp;
+ uintptr_t basesp = sp + es->code->stackframesize * SIZE_OF_STACKSLOT;
+
+ // Restore return address, if part of frame.
+#if STACKFRAME_RA_TOP_OF_FRAME
+# if STACKFRAME_LEAFMETHODS_RA_REGISTER
+ if (!code_is_leafmethod(es->code)) {
+# endif
+ basesp -= 1 * SIZE_OF_STACKSLOT;
+ es->ra = *((uint8_t**) basesp);
+# if STACKFRAME_LEAFMETHODS_RA_REGISTER
+ }
+# endif
+#endif /* STACKFRAME_RA_TOP_OF_FRAME */
+
+ // Restore return address, if inside linkage area.
+#if STACKFRAME_RA_LINKAGE_AREA
+# if STACKFRAME_LEAFMETHODS_RA_REGISTER
+ if (!code_is_leafmethod(es->code))
+# endif
+ es->ra = *((uint8_t**) (basesp + LA_LR_OFFSET));
+#endif /* STACKFRAME_RA_LINKAGE_AREA */
+
+ // Restore saved int registers.
+ reg = INT_REG_CNT;
+ for (i=0; i<es->code->savedintcount; ++i) {
+ while (nregdescint[--reg] != REG_SAV)
+ ;
+ basesp -= 1 * SIZE_OF_STACKSLOT;
+ es->intregs[reg] = *((uintptr_t*) basesp);
+ }
+
+ // Restore saved flt registers.
+ // XXX align?
+ reg = FLT_REG_CNT;
+ for (i=0; i<es->code->savedfltcount; ++i) {
+ while (nregdescfloat[--reg] != REG_SAV)
+ ;
+ basesp -= STACK_SLOTS_PER_FLOAT * SIZE_OF_STACKSLOT;
+ es->fltregs[reg] = *((double*) basesp);
+ }
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+ // Restore saved adr registers.
+ reg = ADR_REG_CNT;
+ for (i=0; i<es->code->savedadrcount; ++i) {
+ while (nregdescadr[--reg] != REG_SAV)
+ ;
+ basesp -= 1 * SIZE_OF_STACKSLOT;
+ es->adrregs[reg] = *((uintptr_t*) basesp);
+ }
+#endif
+
+ // Adjust the stackpointer.
+ es->sp += framesize;
+#if STACKFRMAE_RA_BETWEEN_FRAMES
+ es->sp += SIZEOF_VOID_P; /* skip return address */
+#endif
+
+ // Set the program counter to the return address.
+ es->pc = ra;
+
+ // In debugging mode clobber non-saved registers.
+#if !defined(NDEBUG)
+ for (i=0; i<INT_REG_CNT; ++i)
+ if (nregdescint[i] != REG_SAV)
+ es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
+ for (i=0; i<FLT_REG_CNT; ++i)
+ if (nregdescfloat[i] != REG_SAV)
+ *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
+# if defined(HAS_ADDRESS_REGISTER_FILE)
+ for (i=0; i<ADR_REG_CNT; ++i)
+ if (nregdescadr[i] != REG_SAV)
+ es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
+# endif
+#endif /* !defined(NDEBUG) */
+}
+
+
+// XXX Move this prototype somewhere else!
+void *exceptions_handle_exception(java_object_t *xptro, void *xpc, void *pv, void *sp);
+
+
+/**
+ * Performs stack unwinding in case of an exception. This is done by
+ * popping frames off the given execution state until a frame is reached
+ * for which there is a handler. Execution will continue at the handler
+ * site once the execution state is written back to the machine.
+ *
+ * @param es Execution state to be modified.
+ * @param e The thrown exception object.
+ *
+ * This is specified in:
+ * The Java(TM) Virtual Machine Specification, Second Edition
+ * Section 3.6.5: Abrupt Method Invocation Completion
+ */
+void executionstate_unwind_exception(executionstate_t* es, java_handle_t* e)
+{
+ void* handler = NULL;
+
+ // Iterate until we find an exception handler.
+ while (handler == NULL) {
+
+ // Search an exception handler in the current frame.
+ handler = exceptions_handle_exception(e, es->pc, es->pv, es->sp);
+
+ // Jump directly into the handler in case we found one.
+ if (handler != NULL)
+ break;
+
+ // Find the codeinfo structure for the current frame.
+ es->code = code_get_codeinfo_for_pv(es->pv);
+
+ // Pop one frame off the stack.
+ executionstate_pop_stackframe(es);
+
+ // Get the PV for the parent Java method.
+ es->pv = md_codegen_get_pv_from_pc(es->pc);
+
+ // After popping the frame the PC points to the instruction just after
+ // the invocation. To get the XPC we need to correct the PC to point
+ // just before the invocation. But we do not know how big the
+ // invocation site actually is, so we subtract one, which should be
+ // sufficient for our purposes.
+ es->pc -= 1;
+ }
+
+ // Update the execution state to continue at the handler site.
+ es->pc = (uint8_t*) handler;
+}
+
+
/* executionstate_sanity_check *************************************************
Perform some sanity checks for the md_executionstate_read and
/* src/vm/jit/executionstate.h - execution-state handling
- Copyright (C) 2007, 2008
+ Copyright (C) 2007, 2008, 2009
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
#include "vm/jit/code.hpp"
+/* configuration of native stack slot size ************************************/
+
+#define SIZE_OF_STACKSLOT 8
+#define STACK_SLOTS_PER_FLOAT 1
+typedef uint64_t stackslot_t;
+
+
/* executionstate_t ************************************************************
An execution-state represents the state of a thread containing all
extern "C" {
#endif
+void executionstate_pop_stackframe(executionstate_t *es);
+
+void executionstate_unwind_exception(executionstate_t* es, java_handle_t* e);
+
#if !defined(NDEBUG)
void executionstate_sanity_check(void *context);
void executionstate_println(executionstate_t *es);
#define STACKFRMAE_RA_BETWEEN_FRAMES 1
#define STACKFRAME_RA_TOP_OF_FRAME 0
+#define STACKFRAME_RA_LINKAGE_AREA 0
#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0
#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 0
.globl asm_compare_and_swap
.globl asm_memory_barrier
- .globl asm_get_cycle_count
-
#if defined(ENABLE_ESCAPE_CHECK)
.globl asm_escape_check
#endif
lock; add $0,0(sp)
ret
-
-/* asm_get_cycle_count *********************************************************
-
- Get the current time-stamp counter from the CPU.
-
-*******************************************************************************/
-
-asm_get_cycle_count:
- rdtsc
- ret
#if defined(ENABLE_ESCAPE_CHECK)
asm_escape_check:
#define builtin_d2i _builtin_d2i
#define builtin_d2l _builtin_d2l
-#define asm_get_cycle_count _asm_get_cycle_count
-
#endif /* _MD_ASM_H */
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->mc_eip;
- sp = (u1 *) _mc->mc_esp;
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->gregs[REG_EIP];
- sp = (u1 *) _mc->gregs[REG_ESP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
__asm__ __volatile__ ("" : : : "memory");
}
+
+/* md_get_cycle_count **********************************************************
+
+ Get the current time-stamp counter from the CPU.
+
+*******************************************************************************/
+
+inline static uint64_t md_get_cycle_count()
+{
+ uint64_t cycles;
+
+ // Get current cycles count from the CPU.
+ __asm__ __volatile__ ("rdtsc" : "=A" (cycles));
+
+ return cycles;
+}
+
#endif /* _VM_JIT_I386_MD_H */
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->gregs[EIP];
- sp = (u1 *) _mc->gregs[UESP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
#include "vm/class.hpp"
#include "vm/global.h"
#include "vm/globals.hpp"
+#include "vm/hook.hpp"
#include "vm/initialize.hpp"
#include "vm/loader.hpp"
#include "vm/method.hpp"
#include "vm/jit/stack.h"
#include "vm/jit/stubs.hpp"
-#if defined(ENABLE_OPAGENT)
-#include "vm/jit/oprofile-agent.hpp"
-#endif
-
#include "vm/jit/allocator/simplereg.h"
#if defined(ENABLE_LSRA) && !defined(ENABLE_SSA)
# include "vm/jit/allocator/lsra.h"
#else
intrp_md_init();
#endif
-
-#if defined(ENABLE_OPAGENT)
- if (opt_EnableOpagent)
- OprofileAgent::initialize();
-#endif
}
void jit_close(void)
{
-#if defined(ENABLE_OPAGENT)
- if (opt_EnableOpagent)
- OprofileAgent::close();
-#endif
+ /* nop */
}
compilingtime_stop();
#endif
-#if defined(ENABLE_OPAGENT)
- if (opt_EnableOpagent)
- OprofileAgent::newmethod(m);
-#endif
+ // Hook point just after code was generated.
+ Hook::jit_generated(m, m->code);
/* leave the monitor */
compilingtime_stop();
#endif
-#if defined(ENABLE_OPAGENT)
- if (opt_EnableOpagent)
- OprofileAgent::newmethod(m);
-#endif
+ // Hook point just after code was generated.
+ Hook::jit_generated(m, m->code);
DEBUG_JIT_COMPILEVERBOSE("Recompiling done: ");
#define STACKFRMAE_RA_BETWEEN_FRAMES 1
#define STACKFRAME_RA_TOP_OF_FRAME 0
+#define STACKFRAME_RA_LINKAGE_AREA 0
#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0
#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 1
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->gregs[R_PC];
- sp = (u1 *) _mc->gregs[R_SP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where
#define STACKFRMAE_RA_BETWEEN_FRAMES 0
#define STACKFRAME_RA_TOP_OF_FRAME 1
+#define STACKFRAME_RA_LINKAGE_AREA 0
#define STACKFRAME_LEAFMETHODS_RA_REGISTER 1
#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 1
M_IADD(GET_HIGH_REG(s1), REG_ITMP3, GET_HIGH_REG(d));
}
else if ((iptr->sx.val.l >= (-32768 + 1)) && (iptr->sx.val.l < 0)) {
- s1 = emit_load_s1_low(jd, iptr, REG_ITMP2);
+ s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
M_ISUB_IMM(s1, -(iptr->sx.val.l), GET_LOW_REG(d));
M_CMPULT_IMM(GET_LOW_REG(d), iptr->sx.val.l, REG_ITMP3);
- s1 = emit_load_s1_high(jd, iptr, REG_ITMP2);
+ s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
M_ISUB_IMM(s1, 1, GET_HIGH_REG(d));
M_IADD(GET_HIGH_REG(d), REG_ITMP3, GET_HIGH_REG(d));
}
else {
- ICONST(REG_ITMP2, iptr->sx.val.l & 0xffffffff);
+ ICONST(REG_ITMP1, iptr->sx.val.l & 0xffffffff);
s1 = emit_load_s1_low(jd, iptr, REG_ITMP3);
- M_IADD(s1, REG_ITMP2, GET_LOW_REG(d));
+ M_IADD(s1, REG_ITMP1, GET_LOW_REG(d));
M_CMPULT(GET_LOW_REG(d), s1, REG_ITMP3);
- s1 = emit_load_s1_high(jd, iptr, REG_ITMP2);
+ s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
M_IADD(s1, REG_ITMP3, GET_HIGH_REG(d));
ICONST(REG_ITMP3, iptr->sx.val.l >> 32);
M_IADD(GET_HIGH_REG(d), REG_ITMP3, GET_HIGH_REG(d));
d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
M_ISUB(s1, s2, GET_HIGH_REG(d));
s1 = emit_load_s1_low(jd, iptr, REG_ITMP3);
- s2 = emit_load_s2_low(jd, iptr, REG_ITMP1);
+ s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
M_CMPULT(s1, s2, REG_ITMP3);
M_ISUB(GET_HIGH_REG(d), REG_ITMP3, GET_HIGH_REG(d));
/* if s1 is equal to REG_ITMP3 we have to reload it, since
#else
d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
if ((iptr->sx.val.l >= 0) && (iptr->sx.val.l <= 32768)) {
- s1 = emit_load_s1_low(jd, iptr, REG_ITMP2);
+ s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
M_ISUB_IMM(s1, iptr->sx.val.l, GET_LOW_REG(d));
M_CMPULT_IMM(GET_LOW_REG(d), -(iptr->sx.val.l), REG_ITMP3);
- s1 = emit_load_s1_high(jd, iptr, REG_ITMP2);
+ s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
M_ISUB_IMM(s1, 1, GET_HIGH_REG(d));
M_IADD(GET_HIGH_REG(d), REG_ITMP3, GET_HIGH_REG(d));
}
M_IADD(GET_HIGH_REG(s1), REG_ITMP3, GET_HIGH_REG(d));
}
else {
- ICONST(REG_ITMP2, iptr->sx.val.l & 0xffffffff);
+ ICONST(REG_ITMP1, iptr->sx.val.l & 0xffffffff);
s1 = emit_load_s1_low(jd, iptr, REG_ITMP3);
- M_ISUB(s1, REG_ITMP2, GET_LOW_REG(d));
- M_CMPULT(s1, REG_ITMP2, REG_ITMP3);
- s1 = emit_load_s1_high(jd, iptr, REG_ITMP2);
+ M_ISUB(s1, REG_ITMP1, GET_LOW_REG(d));
+ M_CMPULT(s1, REG_ITMP1, REG_ITMP3);
+ s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
M_ISUB(s1, REG_ITMP3, GET_HIGH_REG(d));
ICONST(REG_ITMP3, iptr->sx.val.l >> 32);
M_ISUB(GET_HIGH_REG(d), REG_ITMP3, GET_HIGH_REG(d));
M_AND_IMM(d, iptr->sx.val.i, d);
}
else {
- ICONST(REG_ITMP2, iptr->sx.val.i);
- M_AND(s1, REG_ITMP2, d);
+ ICONST(REG_ITMP3, iptr->sx.val.i);
+ M_AND(s1, REG_ITMP3, d);
M_BGEZ(s1, 4);
M_NOP;
M_ISUB(REG_ZERO, s1, d);
- M_AND(d, REG_ITMP2, d);
+ M_AND(d, REG_ITMP3, d);
}
M_ISUB(REG_ZERO, d, d);
emit_store_dst(jd, iptr, d);
s2 = emit_load_s2_low(jd, iptr, REG_ITMP3);
d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
M_AND(s1, s2, GET_LOW_REG(d));
- s1 = emit_load_s1_high(jd, iptr, REG_ITMP2);
+ s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
s2 = emit_load_s2_high(jd, iptr, REG_ITMP3);
M_AND(s1, s2, GET_HIGH_REG(d));
#endif
s2 = emit_load_s2_low(jd, iptr, REG_ITMP3);
d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
M_OR(s1, s2, GET_LOW_REG(d));
- s1 = emit_load_s1_high(jd, iptr, REG_ITMP2);
+ s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
s2 = emit_load_s2_high(jd, iptr, REG_ITMP3);
M_OR(s1, s2, GET_HIGH_REG(d));
#endif
s2 = emit_load_s2_low(jd, iptr, REG_ITMP3);
d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
M_XOR(s1, s2, GET_LOW_REG(d));
- s1 = emit_load_s1_high(jd, iptr, REG_ITMP2);
+ s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
s2 = emit_load_s2_high(jd, iptr, REG_ITMP3);
M_XOR(s1, s2, GET_HIGH_REG(d));
#endif
*/
void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
{
+ int disp = 0;
+ int cause;
ucontext_t* _uc = (struct ucontext *) _p;
mcontext_t* _mc = &_uc->uc_mcontext;
+ void *xpc;
- void* xpc = (void*) (_mc->pc - 4);
+#if !defined(__UCLIBC__)
+# if ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 5))
+ /* NOTE: We only need this for pre glibc-2.5. */
+
+ /* get the cause of this exception */
+
+ cause = _mc->cause;
+
+ /* check the cause to find the faulting instruction */
+
+ /* TODO: use defines for that stuff */
+
+ switch (cause & 0x0000003c) {
+ case 0x00000008:
+ /* TLBL: XPC is ok */
+ break;
+
+ case 0x00000010:
+ /* AdEL: XPC is of the following instruction */
+ disp -= 4;
+ break;
+ }
+ xpc = (void*) (_mc->pc + disp);
+# else
+ xpc = (void*) _mc->pc;
+# endif
+#else
+ xpc = (void*) _gregs[CTX_EPC];
+#endif
// Handle the trap.
trap_handle(TRAP_SIGSEGV, xpc, _p);
ucontext_t* _uc = (struct ucontext *) _p;
mcontext_t* _mc = &_uc->uc_mcontext;
- void* xpc = (void*) (_mc->pc - 4);
+#if !defined(__UCLIBC__)
+ void* xpc = (void*) _mc->pc;
+#else
+ void* xpc = (void*) _gregs[CTX_EPC];
+#endif
// Handle the trap.
trap_handle(TRAP_SIGILL, xpc, _p);
{
_handle = op_open_agent();
if (!_handle)
- os::abort_errno("unable to open opagent handle:");
+ os::abort_errno("unable to open opagent handle");
}
/**
#include "vm/breakpoint.hpp"
#include "vm/exceptions.hpp"
+#include "vm/hook.hpp"
#include "vm/initialize.hpp"
#include "vm/options.h"
#include "vm/os.hpp"
#define TRACE_PATCHER_INDENT for (i=0; i<patcher_depth; i++) printf("\t")
#endif /* !defined(NDEBUG) */
-java_handle_t *patcher_handler(u1 *pc)
+bool patcher_handler(u1 *pc)
{
codeinfo *code;
patchref_t *pr;
}
#endif
code->patchers->unlock();
- return NULL;
+ return true;
}
#if !defined(NDEBUG)
}
#endif
- // Check for return value and exit accordingly.
- if (result == false) {
- // Mangle the pending exception.
+ // Check return value and mangle the pending exception.
+ if (result == false)
resolve_handle_pending_exception(true);
- // Get the exception and return it.
- java_handle_t* e = exceptions_get_and_clear_exception();
-
- code->patchers->unlock();
-
- return e;
- }
-
- pr->done = true; /* XXX this is only preliminary to prevent double-patching */
+ // XXX This is only preliminary to prevent double-patching.
+ else
+ pr->done = true;
code->patchers->unlock();
- return NULL;
+ return result;
}
// Get stuff from the patcher reference.
Breakpoint* breakp = (Breakpoint*) pr->ref;
-#if defined(ENABLE_JVMTI)
- methodinfo* m = breakp->method;
- int32_t l = breakp->location;
-
- log_message_method("JVMTI: Reached breakpoint in method ", m);
- log_println("JVMTI: Reached breakpoint at location %d", l);
-#endif
+ // Hook point when a breakpoint was triggered.
+ Hook::breakpoint(breakp);
// In case the breakpoint wants to be kept active, we simply
// fail to "patch" at this point.
// MD function.
bool patcher_is_valid_trap_instruction_at(void* pc);
-java_handle_t *patcher_handler(u1 *pc);
+bool patcher_handler(u1 *pc);
/* empty patcher (just patches back original mcode) ***************************/
#define STACKFRMAE_RA_BETWEEN_FRAMES 0
#define STACKFRAME_RA_TOP_OF_FRAME 0
-#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0
+#define STACKFRAME_RA_LINKAGE_AREA 1
+#define STACKFRAME_LEAFMETHODS_RA_REGISTER 1
#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 1
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- unsigned long *_gregs;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
-
-#if defined(__UCLIBC__)
- _mc = &(_uc->uc_mcontext);
- _gregs = _mc->regs->gpr;
-#else
- _mc = _uc->uc_mcontext.uc_regs;
- _gregs = _mc->gregs;
-#endif
-
- /* get the PC and SP for this thread */
-
- pc = (u1 *) _gregs[PT_NIP];
- sp = (u1 *) _gregs[REG_SP];
-
- /* now suspend the current thread */
-
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
/* save the current machine code */
*(u4*)(savedmcode) = *(u4*)(pc);
- /* build the machine code for the patch */
- assert(0); /* XXX build trap instruction below */
+ // Build the machine code for the patch. On PowerPC we use
+ // an illegal instruction which really is just 0, believe me!
mcode = 0;
/* write the new machine code */
#define STACKFRMAE_RA_BETWEEN_FRAMES 0
#define STACKFRAME_RA_TOP_OF_FRAME 0
+#define STACKFRAME_RA_LINKAGE_AREA 1
#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0
#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 1
/* src/vm/jit/replace.cpp - on-stack replacement of methods
- Copyright (C) 1996-2005, 2006, 2007, 2008
+ Copyright (C) 1996-2005, 2006, 2007, 2008, 2009
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
#include <vmlog_cacao.h>
#endif
-/*** architecture-dependent configuration *************************************/
-
-/* first unset the macros (default) */
-#undef REPLACE_RA_LINKAGE_AREA
-
-/* powerpc */
-#if defined(__POWERPC__)
-# define REPLACE_RA_LINKAGE_AREA
-#endif
-
-
-/*** configuration of native stack slot size **********************************/
-
-/* XXX this should be in md-abi.h files, probably */
-
-#define SIZE_OF_STACKSLOT 8
-#define STACK_SLOTS_PER_FLOAT 1
-typedef u8 stackslot_t;
-
/*** debugging ****************************************************************/
}
-/* md_pop_stackframe ***********************************************************
-
- Restore callee-saved registers (including the RA register),
- set the stack pointer to the next stackframe,
- set the PC to the return address of the popped frame.
-
- *** This function imitates the effects of the method epilog ***
- *** and returning from the method call. ***
-
- IN:
- es...............execution state
-
- OUT:
- *es..............the execution state after popping the stack frame
- NOTE: es->code and es->pv are NOT updated.
-
-*******************************************************************************/
-
-void md_pop_stackframe(executionstate_t *es)
-{
- u1 *ra;
- s4 framesize;
- s4 reg;
- s4 i;
- stackslot_t *basesp;
- stackslot_t *sp;
-
- assert(es->code);
-
- /* calculate the size of the stackframe */
-
- framesize = md_stacktrace_get_framesize(es->code);
-
- /* read the return address */
-
-#if STACKFRAME_LEAFMETHODS_RA_REGISTER
- if (code_is_leafmethod(es->code))
- ra = es->ra;
- else
-#endif
- ra = (u1*) md_stacktrace_get_returnaddress(es->sp, framesize);
-
- /* calculate the base of the stack frame */
-
- sp = (stackslot_t *) es->sp;
- basesp = sp + es->code->stackframesize;
-
- /* restore return address, if part of frame */
-
-#if STACKFRAME_RA_TOP_OF_FRAME
-# if STACKFRAME_LEAFMETHODS_RA_REGISTER
- if (!code_is_leafmethod(es->code))
-# endif
- es->ra = (u1*) (ptrint) *--basesp;
-#endif /* STACKFRAME_RA_TOP_OF_FRAME */
-
-#if defined(REPLACE_RA_LINKAGE_AREA)
-# if STACKFRAME_LEAFMETHODS_RA_REGISTER
- if (!code_is_leafmethod(es->code))
-# endif
- es->ra = (u1*) (ptrint) basesp[LA_LR_OFFSET / sizeof(stackslot_t)];
-#endif /* REPLACE_RA_LINKAGE_AREA */
-
- /* restore saved int registers */
-
- reg = INT_REG_CNT;
- for (i=0; i<es->code->savedintcount; ++i) {
- while (nregdescint[--reg] != REG_SAV)
- ;
- es->intregs[reg] = *--basesp;
- }
-
- /* restore saved flt registers */
-
- /* XXX align? */
- reg = FLT_REG_CNT;
- for (i=0; i<es->code->savedfltcount; ++i) {
- while (nregdescfloat[--reg] != REG_SAV)
- ;
- basesp -= STACK_SLOTS_PER_FLOAT;
- es->fltregs[reg] = *(double*)basesp;
- }
-
-#if defined(HAS_ADDRESS_REGISTER_FILE)
- /* restore saved adr registers */
-
- reg = ADR_REG_CNT;
- for (i=0; i<es->code->savedadrcount; ++i) {
- while (nregdescadr[--reg] != REG_SAV)
- ;
- es->adrregs[reg] = *--basesp;
- }
-#endif
-
- /* adjust the stackpointer */
-
- es->sp += framesize;
-#if STACKFRMAE_RA_BETWEEN_FRAMES
- es->sp += SIZEOF_VOID_P; /* skip return address */
-#endif
-
- /* set the program counter to the return address */
-
- es->pc = ra;
-
- /* in debugging mode clobber non-saved registers */
-
-#if !defined(NDEBUG)
- /* for debugging */
- for (i=0; i<INT_REG_CNT; ++i)
- if (nregdescint[i] != REG_SAV)
- es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
- for (i=0; i<FLT_REG_CNT; ++i)
- if (nregdescfloat[i] != REG_SAV)
- *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
-# if defined(HAS_ADDRESS_REGISTER_FILE)
- for (i=0; i<ADR_REG_CNT; ++i)
- if (nregdescadr[i] != REG_SAV)
- es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
-# endif
-#endif /* !defined(NDEBUG) */
-}
-
-
/* md_push_stackframe **********************************************************
Save the given return address, build the new stackframe,
*--basesp = (ptrint) ra;
#endif /* STACKFRAME_RA_TOP_OF_FRAME */
-#if defined(REPLACE_RA_LINKAGE_AREA)
+#if STACKFRAME_RA_LINKAGE_AREA
# if STACKFRAME_LEAFMETHODS_RA_REGISTER
if (!code_is_leafmethod(calleecode))
# endif
- basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
-#endif /* REPLACE_RA_LINKAGE_AREA */
+ *((uint8_t**) ((intptr_t) basesp + LA_LR_OFFSET)) = ra;
+#endif /* STACKFRAME_RA_LINKAGE_AREA */
/* save int registers */
for (i=0; i<calleecode->savedintcount; ++i) {
while (nregdescint[--reg] != REG_SAV)
;
- *--basesp = es->intregs[reg];
+ basesp -= 1;
+ *((uintptr_t*) basesp) = es->intregs[reg];
/* XXX may not clobber saved regs used by native code! */
#if !defined(NDEBUG) && 0
while (nregdescfloat[--reg] != REG_SAV)
;
basesp -= STACK_SLOTS_PER_FLOAT;
- *(double*)basesp = es->fltregs[reg];
+ *((double*) basesp) = es->fltregs[reg];
/* XXX may not clobber saved regs used by native code! */
#if !defined(NDEBUG) && 0
for (i=0; i<calleecode->savedadrcount; ++i) {
while (nregdescadr[--reg] != REG_SAV)
;
- *--basesp = es->adrregs[reg];
+ basesp -= 1;
+ *((uintptr_t*) basesp) = es->adrregs[reg];
/* XXX may not clobber saved regs used by native code! */
#if !defined(NDEBUG) && 0
frame->syncslotcount = count;
frame->syncslots = (replace_val_t*) DumpMemory::allocate(sizeof(replace_val_t) * count);
for (i=0; i<count; ++i) {
- frame->syncslots[i].p = sp[es->code->memuse + i]; /* XXX md_ function */
+ frame->syncslots[i].p = *((intptr_t*) (sp + es->code->memuse + i)); /* XXX md_ function */
}
/* pop the stackframe */
- md_pop_stackframe(es);
+ executionstate_pop_stackframe(es);
ra = es->pc;
count = code_get_sync_slot_count(calleecode);
assert(count == calleeframe->syncslotcount);
for (i=0; i<count; ++i) {
- sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
+ *((intptr_t*) (sp + calleecode->memuse + i)) = calleeframe->syncslots[i].p;
}
/* redirect future invocations */
}
-/* replace_me_wrapper **********************************************************
+/* replace_handler *************************************************************
This function is called by the signal handler. It determines if there
is an active replacement point pending at the given PC and returns
IN:
pc...............the program counter that triggered the replacement.
- context..........the context (machine state) to which the
+ es...............the execution state (machine state) to which the
replacement should be applied.
OUT:
- context..........the context after replacement finished.
+ es...............the execution state after replacement finished.
RETURN VALUE:
true.............replacement done, everything went ok
- false............no replacement done, context unchanged
+ false............no replacement done, execution state unchanged
*******************************************************************************/
-bool replace_me_wrapper(u1 *pc, void *context)
+bool replace_handler(u1 *pc, executionstate_t *es)
{
codeinfo *code;
rplpoint *rp;
- executionstate_t es;
#if defined(ENABLE_RT_TIMING)
struct timespec time_start, time_end;
#endif
DOLOG( printf("valid replacement point\n"); );
-#if !defined(NDEBUG)
- executionstate_sanity_check(context);
-#endif
-
/* set codeinfo pointer in execution state */
- es.code = code;
-
- /* read execution state from current context */
-
- md_executionstate_read(&es, context);
-
- DOLOG( printf("REPLACEMENT READ: ");
- executionstate_println(&es); );
+ es->code = code;
/* do the actual replacement */
RT_TIMING_GET_TIME(time_start);
#endif
- replace_me(rp, &es);
+ replace_me(rp, es);
#if defined(ENABLE_RT_TIMING)
RT_TIMING_GET_TIME(time_end);
RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_REPLACE);
#endif
- /* write execution state to current context */
-
- md_executionstate_write(&es, context);
-
- DOLOG( printf("REPLACEMENT WRITE: ");
- executionstate_println(&es); );
-
/* new code is entered after returning */
DOLOG( printf("JUMPING IN!\n"); fflush(stdout); );
#include "vm/method.hpp"
+#include "vm/jit/executionstate.h"
#include "vm/jit/reg.h"
#include "vm/jit/stacktrace.hpp"
void replace_activate_replacement_points(codeinfo *code, bool mappable);
void replace_deactivate_replacement_points(codeinfo *code);
-bool replace_me_wrapper(u1 *pc, void *context);
+bool replace_handler(u1 *pc, executionstate_t *es);
#if !defined(NDEBUG)
void replace_show_replacement_points(codeinfo *code);
#define STACKFRMAE_RA_BETWEEN_FRAMES 0
#define STACKFRAME_RA_TOP_OF_FRAME 1
+#define STACKFRAME_RA_LINKAGE_AREA 0
#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0
#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 1
#error Set the values below correctly!!!
#define STACKFRMAE_RA_BETWEEN_FRAMES 0
#define STACKFRAME_RA_TOP_OF_FRAME 0
+#define STACKFRAME_RA_LINKAGE_AREA 0
#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0
#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 0
}
-// Legacy C interface.
-
-extern "C" {
- void* CompilerStub_generate(methodinfo* m) { return CompilerStub::generate(m); }
- void CompilerStub_remove(void* stub) { CompilerStub::remove(stub); }
-
- void BuiltinStub_generate(methodinfo* m, builtintable_entry* bte) { BuiltinStub::generate(m, bte); }
-
- void NativeStub_remove(void* stub) { NativeStub::remove(stub); }
-}
-
-
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where
// Include machine dependent implementation.
#include "md-stubs.hpp"
-#else
-
-// Legacy C interface.
-
-void* CompilerStub_generate(methodinfo* m);
-void* CompilerStub_remove(void* stub);
-void BuiltinStub_generate(methodinfo* m, builtintable_entry* bte);
-void NativeStub_remove(void* stub);
-
#endif
#endif // _STUBS_HPP
#include "vm/array.hpp"
#include "vm/global.h"
#include "vm/globals.hpp"
+#include "vm/hook.hpp"
#include "vm/javaobjects.hpp"
#include "vm/options.h"
#include "vm/string.hpp"
return;
#endif
+ // Hook point on entry into Java method.
+ Hook::method_enter(m);
+
md = m->parseddesc;
/* calculate message length */
return;
#endif
+ // Hook point upon exit from Java method.
+ Hook::method_exit(m);
+
md = m->parseddesc;
/* outdent the log message */
stackframeinfo_t sfi;
trapinfo_t trp;
- // Prevent compiler warnings.
- java_handle_t* o = NULL;
- methodinfo* m = NULL;
-
#if !defined(NDEBUG)
// Sanity checking the XPC.
if (xpc == NULL)
/* Do some preparations before we enter the nativeworld. */
/* BEFORE: creating stackframeinfo */
+ // Prevent compiler warnings.
+ int32_t index = 0;
+ java_handle_t* o = NULL;
+ methodinfo* m = NULL;
+
switch (type) {
+ case TRAP_ArrayIndexOutOfBoundsException:
+ /* Get the index into the array causing the exception. */
+
+ index = (int32_t) val;
+ break;
+
case TRAP_ClassCastException:
/* Wrap the value into a handle, as it is a reference. */
/* Get resulting exception (or pointer to compiled method). */
- int32_t index;
java_handle_t* p;
void* entry;
+ bool was_patched;
+#if defined(ENABLE_REPLACEMENT)
+ bool was_replaced;
+#endif
switch (type) {
case TRAP_NullPointerException:
break;
case TRAP_ArrayIndexOutOfBoundsException:
- index = (int32_t) val;
p = exceptions_new_arrayindexoutofboundsexception(index);
break;
break;
case TRAP_PATCHER:
+ p = NULL;
#if defined(ENABLE_REPLACEMENT)
- if (replace_me_wrapper((uint8_t*) xpc, context)) {
- p = NULL;
+ was_replaced = replace_handler((uint8_t*) xpc, &es);
+ if (was_replaced)
break;
- }
#endif
- p = patcher_handler((uint8_t*) xpc);
+ was_patched = patcher_handler((uint8_t*) xpc);
break;
case TRAP_COMPILER:
- entry = jit_compile_handle(m, sfi.pv, ra, (void*) val);
p = NULL;
+ entry = jit_compile_handle(m, sfi.pv, ra, (void*) val);
break;
-#if defined(ENABLE_REPLACEMENT)
+#if defined(__I386__) && defined(ENABLE_REPLACEMENT)
+# warning Port the below stuff to use the patching subsystem.
case TRAP_COUNTDOWN:
-# if defined(__I386__)
- replace_me_wrapper((uint8_t*) xpc - 13, context);
-# endif
p = NULL;
+ (void) replace_handler((uint8_t*) xpc - 13, &es);
break;
#endif
goto trap_handle_exception;
case TRAP_PATCHER:
+#if defined(ENABLE_REPLACEMENT)
+ // If on-stack-replacement suceeded, we are not allowed to touch
+ // the execution state. We assume that there was no exception.
+
+ if (was_replaced) {
+ assert(exceptions_get_exception() == NULL);
+ break;
+ }
+#endif
+
// The normal case for a patcher trap is to continue execution at
// the trap instruction. On some archs the PC may point after the
// trap instruction, so we reset it here.
+ if (was_patched) {
+ assert(exceptions_get_exception() == NULL);
+ es.pc = (uint8_t *) (uintptr_t) xpc;
+ break;
+ }
+
+ // In case patching was not successful, we try to fetch the pending
+ // exception here.
+
+ p = exceptions_get_and_clear_exception();
+
+ // If there is no pending exception, we continue execution behind
+ // the position still in need of patching. Normally this would
+ // indicate an error in the patching subsystem, but others might
+ // want to piggyback patchers and we want to be able to provide
+ // "reusable trap points" and avoid inifinite loops here. This is
+ // especially useful to implement breakpoints or profiling points
+ // of any kind. So before changing the trap logic, think about
+ // utilizing the patching subsystem on your quest. :)
+
if (p == NULL) {
+#if !defined(NDEBUG)
+ if (opt_PrintWarnings)
+ log_println("trap_handle: Detected reusable trap at %p", xpc);
+#endif
es.pc = (uint8_t *) (uintptr_t) xpc;
+ es.pc += REPLACEMENT_PATCH_SIZE;
break;
}
trap_handle_exception:
default:
if (p != NULL) {
+#if defined(__ALPHA__) || defined(__I386__) || defined(__X86_64__)
+ // Perform stack unwinding for exceptions on execution state.
+ es.pc = (uint8_t *) (uintptr_t) xpc;
+ es.pv = (uint8_t *) (uintptr_t) sfi.pv;
+ executionstate_unwind_exception(&es, p);
+
+ // Pass the exception object to the exception handler.
+ es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
+#else
es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
es.intregs[REG_ITMP2_XPC] = (uintptr_t) xpc;
es.pc = (uint8_t *) (uintptr_t) asm_handle_exception;
+#endif
}
}
#define STACKFRMAE_RA_BETWEEN_FRAMES 1
#define STACKFRAME_RA_TOP_OF_FRAME 0
+#define STACKFRAME_RA_LINKAGE_AREA 0
#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0
#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 0
.globl asm_builtin_d2i
.globl asm_builtin_d2l
- .globl asm_get_cycle_count
-
/********************* function asm_calljavafunction ***************************
* *
ret
-/* asm_get_cycle_count *********************************************************
-
- Get the current time-stamp counter from the CPU.
-
-*******************************************************************************/
-
-asm_get_cycle_count:
- rdtsc
- shl $0x20, %rdx
- mov %eax, %eax
- or %rdx, %rax
- ret
-
-
/* disable exec-stacks ********************************************************/
#if defined(__linux__) && defined(__ELF__)
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
- different to the ones in <ucontext.h>. */
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->gregs[REG_RIP];
- sp = (u1 *) _mc->gregs[REG_RSP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
/* src/vm/jit/x86_64/md.h - machine dependent x86_64 functions
- Copyright (C) 1996-2005, 2006, 2007, 2008
+ Copyright (C) 1996-2005, 2006, 2007, 2008, 2009
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
__asm__ __volatile__ ("" : : : "memory");
}
+
+/* md_get_cycle_count **********************************************************
+
+ Get the current time-stamp counter from the CPU.
+
+*******************************************************************************/
+
+inline static uint64_t md_get_cycle_count()
+{
+ uint64_t cycles;
+
+ // Get current cycles count from the CPU.
+ __asm__ __volatile__ ("rdtsc" : "=A" (cycles));
+
+ return cycles;
+}
+
#endif /* _VM_JIT_X86_64_MD_H */
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
- different to the ones in <ucontext.h>. */
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->gregs[REG_RIP];
- sp = (u1 *) _mc->gregs[REG_RSP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
#include "vm/classcache.hpp"
#include "vm/exceptions.hpp"
#include "vm/globals.hpp"
+#include "vm/hook.hpp"
#include "vm/loader.hpp"
#include "vm/options.h"
#include "vm/primitive.hpp"
RT_TIMING_TIME_DIFF(time_start,time_end,RT_TIMING_LINK_TOTAL);
+ // Hook point just after a class was linked.
+ Hook::class_linked(r);
+
return r;
}
#include "vm/field.hpp"
#include "vm/global.h"
#include "vm/globals.hpp"
+#include "vm/hook.hpp"
#include "vm/javaobjects.hpp"
#include "vm/linker.hpp"
#include "vm/loader.hpp"
#include "vm/jit/stubs.hpp"
-#if defined(ENABLE_JVMTI)
-# include "native/jvmti/cacaodbg.h"
-#endif
-
/* global variables ***********************************************************/
printf("]\n");
}
-#if defined(ENABLE_JVMTI)
- /* fire Class Load JVMTI event */
- if (jvmti) jvmti_ClassLoadPrepare(false, c);
-#endif
-
-
return c;
}
c->state = (c->state & ~CLASS_LOADING) | CLASS_LOADED;
-#if defined(ENABLE_JVMTI)
- /* fire Class Prepare JVMTI event */
-
- if (jvmti)
- jvmti_ClassLoadPrepare(true, c);
-#endif
-
#if !defined(NDEBUG)
if (loadverbose)
log_message_class("Loading done class: ", c);
#endif
+ // Hook point just after a class was loaded.
+ Hook::class_loaded(c);
+
return c;
}
} line_number_table[line_number_table_length];
}
+ LocalVariableTable_attribute {
+ u2 attribute_name_index;
+ u4 attribute_length;
+ u2 local_variable_table_length;
+ {
+ u2 start_pc;
+ u2 length;
+ u2 name_index;
+ u2 descriptor_index;
+ u2 index;
+ } local_variable_table[local_variable_table_length];
+ }
+
*******************************************************************************/
bool method_load(classbuffer *cb, methodinfo *m, descriptor_pool *descpool)
if (!stackmap_load_attribute_stackmaptable(cb, m))
return false;
}
-#endif
+# if defined(ENABLE_JVMTI)
+ else if (code_attribute_name == utf_LocalVariableTable) {
+ /* LocalVariableTable */
+
+ if (m->localvars != NULL) {
+ exceptions_throw_classformaterror(c, "Multiple LocalVariableTable attributes");
+ return false;
+ }
+
+ if (!suck_check_classbuffer_size(cb, 4 + 2))
+ return false;
+
+ // Attribute length.
+ (void) suck_u4(cb);
+
+ m->localvarcount = suck_u2(cb);
+
+ if (!suck_check_classbuffer_size(cb, 10 * m->localvarcount))
+ return false;
+
+ m->localvars = MNEW(localvarinfo, m->localvarcount);
+
+ for (l = 0; l < m->localvarcount; l++) {
+ m->localvars[l].start_pc = suck_u2(cb);
+ m->localvars[l].length = suck_u2(cb);
+
+ uint16_t name_index = suck_u2(cb);
+ if (!(m->localvars[l].name = (utf*) class_getconstant(c, name_index, CONSTANT_Utf8)))
+ return false;
+
+ uint16_t descriptor_index = suck_u2(cb);
+ if (!(m->localvars[l].descriptor = (utf*) class_getconstant(c, descriptor_index, CONSTANT_Utf8)))
+ return false;
+
+ m->localvars[l].index = suck_u2(cb);
+
+ // XXX Check if index is in range.
+ // XXX Check if index already taken.
+ }
+ }
+# endif /* defined(ENABLE_JVMTI) */
+#endif /* defined(ENABLE_JAVASE) */
else {
/* unknown code attribute */
return false;
}
-#if defined(ENABLE_ANNOTATIONS)
+# if defined(ENABLE_ANNOTATIONS)
else if (attribute_name == utf_RuntimeVisibleAnnotations) {
/* RuntimeVisibleAnnotations */
if (!annotation_load_method_attribute_runtimevisibleannotations(cb, m))
if (!annotation_load_method_attribute_annotationdefault(cb, m))
return false;
}
-#endif
+# endif
#endif
else {
/* unknown attribute */
typedef struct methodinfo methodinfo;
typedef struct raw_exception_entry raw_exception_entry;
-typedef struct lineinfo lineinfo;
+typedef struct lineinfo lineinfo;
+typedef struct localvarinfo localvarinfo;
typedef struct method_assumption method_assumption;
typedef struct method_worklist method_worklist;
typedef struct codeinfo codeinfo;
#endif
methoddesc *parseddesc; /* parsed descriptor */
-
+
classinfo *clazz; /* class, the method belongs to */
s4 vftblindex; /* index of method in virtual function */
/* table (if it is a virtual method) */
u2 linenumbercount; /* number of linenumber attributes */
lineinfo *linenumbers; /* array of lineinfo items */
+#if defined(ENABLE_JAVASE) && defined(ENABLE_JVMTI)
+ uint16_t localvarcount; /* number of local variable attributes */
+ localvarinfo* localvars; /* array of localvarinfo items */
+#endif
+
u1 *stubroutine; /* stub for compiling or calling natives */
codeinfo *code; /* current code of this method */
};
+/* localvarinfo ***************************************************************/
+
+struct localvarinfo {
+ uint16_t start_pc;
+ uint16_t length;
+ utf* name;
+ utf* descriptor;
+ uint16_t index;
+};
+
+
/* global variables ***********************************************************/
extern methodinfo *method_java_lang_reflect_Method_invoke;
int opt_TraceInlining = 0;
#endif
int opt_TraceJavaCalls = 0;
+bool opt_TraceJMMCalls = false;
int opt_TraceJNICalls = 0;
int opt_TraceJVMCalls = 0;
int opt_TraceJVMCallsVerbose = 0;
+#if defined(ENABLE_JVMTI)
+int opt_TraceJVMTICalls = 0;
+#endif
int opt_TraceLinkClass = 0;
#if defined(ENABLE_REPLACEMENT)
int opt_TraceReplacement = 0;
OPT_TraceHPI,
OPT_TraceInlining,
OPT_TraceJavaCalls,
+ OPT_TraceJMMCalls,
OPT_TraceJNICalls,
OPT_TraceJVMCalls,
OPT_TraceJVMCallsVerbose,
+ OPT_TraceJVMTICalls,
OPT_TraceLinkClass,
OPT_TraceReplacement,
OPT_TraceSubsystemInitialization,
#if !defined(ENABLE_VMLOG)
{ "TraceJavaCalls", OPT_TraceJavaCalls, OPT_TYPE_BOOLEAN, "trace Java method calls" },
#endif
+ { "TraceJMMCalls", OPT_TraceJMMCalls, OPT_TYPE_BOOLEAN, "trace JMM method calls" },
{ "TraceJNICalls", OPT_TraceJNICalls, OPT_TYPE_BOOLEAN, "trace JNI method calls" },
{ "TraceJVMCalls", OPT_TraceJVMCalls, OPT_TYPE_BOOLEAN, "trace JVM method calls but omit very frequent ones" },
{ "TraceJVMCallsVerbose", OPT_TraceJVMCallsVerbose, OPT_TYPE_BOOLEAN, "trace all JVM method calls" },
+#if defined(ENABLE_JVMTI)
+ { "TraceJVMTICalls", OPT_TraceJVMTICalls, OPT_TYPE_BOOLEAN, "trace JVMTI method calls" },
+#endif
{ "TraceLinkClass", OPT_TraceLinkClass, OPT_TYPE_BOOLEAN, "trace class linking" },
#if defined(ENABLE_REPLACEMENT)
{ "TraceReplacement", OPT_TraceReplacement, OPT_TYPE_VALUE, "trace on-stack replacement with the given verbosity level (default: 1)" },
opt_TraceJavaCalls = enable;
break;
+ case OPT_TraceJMMCalls:
+ opt_TraceJMMCalls = enable;
+ break;
+
case OPT_TraceJNICalls:
opt_TraceJNICalls = enable;
break;
opt_TraceJVMCallsVerbose = enable;
break;
+#if defined(ENABLE_JVMTI)
+ case OPT_TraceJVMTICalls:
+ opt_TraceJVMTICalls = enable;
+ break;
+#endif
+
case OPT_TraceLinkClass:
opt_TraceLinkClass = enable;
break;
extern int opt_TraceInlining;
#endif
extern int opt_TraceJavaCalls;
+extern bool opt_TraceJMMCalls;
extern int opt_TraceJNICalls;
extern int opt_TraceJVMCalls;
extern int opt_TraceJVMCallsVerbose;
+#if defined(ENABLE_JVMTI)
+extern int opt_TraceJVMTICalls;
+#endif
extern int opt_TraceLinkClass;
#if defined(ENABLE_REPLACEMENT)
extern int opt_TraceReplacement;
#include "config.h"
-/* NOTE: In this file we check for all system headers, because we wrap
- all system calls into functions for better portability. */
-
-#if defined(HAVE_ERRNO_H)
-# include <errno.h>
-#endif
-
-#if defined(HAVE_STDINT_H)
-# include <stdint.h>
-#endif
-
-#if defined(HAVE_STRING_H)
-# include <string.h>
-#endif
-
-#if defined(HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#if defined(HAVE_SYS_MMAN_H)
-# include <sys/mman.h>
-#endif
-
#if defined(__DARWIN__)
# include <mach/mach.h>
# include <mach/mach_host.h>
/* this should work on BSD */
/* #include <sys/sysctl.h> */
+#include "mm/memory.hpp"
+
+#include "vm/os.hpp"
#include "vm/vm.hpp"
}
+/**
+ * Return the current working directory.
+ *
+ * @return Pointer to a char array allocated by MNEW, or
+ * NULL if memory could not be allocated.
+ */
+char* os::getcwd(void)
+{
+ int32_t size = 1024;
+
+ char* buf = MNEW(char, size);
+
+ while (buf != NULL) {
+ if (getcwd(buf, size) != NULL)
+ return buf;
+
+ MFREE(buf, char, size);
+
+ /* too small buffer or a more serious problem */
+
+ if (errno != ERANGE)
+ abort_errno("os::getcwd: getcwd failed");
+
+ /* double the buffer size */
+
+ size *= 2;
+
+ buf = MNEW(char, size);
+ }
+
+ return NULL;
+}
+
+
/**
* Maps anonymous memory, even on systems not defining
* MAP_ANON(YMOUS).
extern "C" {
void* os_mmap_anonymous(void *addr, size_t len, int prot, int flags) { return os::mmap_anonymous(addr, len, prot, flags); }
- void os_abort(void) { os::abort(); }
- int os_access(const char* pathname, int mode) { return os::access(pathname, mode); }
int os_atoi(const char* nptr) { return os::atoi(nptr); }
- void* os_calloc(size_t nmemb, size_t size) { return os::calloc(nmemb, size); }
-#if defined(ENABLE_JRE_LAYOUT)
- char* os_dirname(char* path) { return os::dirname(path); }
-#endif
- char* os_dlerror(void) { return os::dlerror(); }
- void* os_dlsym(void* handle, const char* symbol) { return os::dlsym(handle, symbol); }
- int os_fclose(FILE* fp) { return os::fclose(fp); }
- FILE* os_fopen(const char* path, const char* mode) { return os::fopen(path, mode); }
- size_t os_fread(void* ptr, size_t size, size_t nmemb, FILE* stream) { return os::fread(ptr, size, nmemb, stream); }
- void os_free(void* ptr) { os::free(ptr); }
int os_getpagesize(void) { return os::getpagesize(); }
void* os_memcpy(void* dest, const void* src, size_t n) { return os::memcpy(dest, src, n); }
void* os_memset(void* s, int c, size_t n) { return os::memset(s, c, n); }
- int os_mprotect(void* addr, size_t len, int prot) { return os::mprotect(addr, len, prot); }
- int os_scandir(const char* dir, struct dirent*** namelist, int(*filter)(const struct dirent*), int(*compar)(const void*, const void*)) { return os::scandir(dir, namelist, filter, compar); }
- int os_stat(const char* path, struct stat* buf) { return os::stat(path, buf); }
- char* os_strcat(char* dest, const char* src) { return os::strcat(dest, src); }
- char* os_strcpy(char* dest, const char* src) { return os::strcpy(dest, src); }
char* os_strdup(const char* s) { return os::strdup(s); }
int os_strlen(const char* s) { return os::strlen(s); }
# include <unistd.h>
#endif
+#if defined(__DARWIN__)
+# if defined(HAVE_MACH_MACH_H)
+# include <mach/mach.h>
+# endif
+#endif
+
+#if defined(HAVE_SYS_LOADAVG_H)
+# include <sys/loadavg.h>
+#endif
+
#if defined(HAVE_SYS_MMAN_H)
# include <sys/mman.h>
#endif
# include <sys/types.h>
#endif
+#if defined(HAVE_SYS_UTSNAME_H)
+# include <sys/utsname.h>
+#endif
+
#ifdef __cplusplus
static inline int fprintf(FILE* stream, const char* format, ...);
static inline size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream);
static inline void free(void* ptr);
+ static inline char* getcwd(char* buf, size_t size);
static inline char* getenv(const char* name);
static inline int gethostname(char* name, size_t len);
+ static inline int getloadavg(double loadavg[], int nelem);
static inline int getpagesize(void);
+ static inline pid_t getpid(void);
static inline int getsockname(int s, struct sockaddr* name, socklen_t* namelen);
static inline int getsockopt(int s, int level, int optname, void* optval, socklen_t* optlen);
static inline int listen(int sockfd, int backlog);
static void abort(const char* text, ...);
static void abort_errnum(int errnum, const char* text, ...);
static void abort_errno(const char* text, ...);
+ static char* getcwd(void);
static void* mmap_anonymous(void *addr, size_t len, int prot, int flags);
static void print_backtrace();
static int processors_online();
#endif
}
+inline char* os::getcwd(char* buf, size_t size)
+{
+#if defined(HAVE_GETCWD)
+ return ::getcwd(buf, size);
+#else
+# error getcwd not available
+#endif
+}
+
inline char* os::getenv(const char* name)
{
#if defined(HAVE_GETENV)
#endif
}
+inline int os::getloadavg(double loadavg[], int nelem)
+{
+#if defined(HAVE_GETLOADAVG)
+ return ::getloadavg(loadavg, nelem);
+#else
+# error getloadavg not available
+#endif
+}
+
inline int os::getpagesize(void)
{
#if defined(HAVE_GETPAGESIZE)
#endif
}
+inline pid_t os::getpid(void)
+{
+#if defined(HAVE_GETPID)
+ return ::getpid();
+#else
+# error getpid not available
+#endif
+}
+
inline int os::getsockname(int s, struct sockaddr* name, socklen_t* namelen)
{
#if defined(HAVE_GETSOCKNAME)
void* os_mmap_anonymous(void *addr, size_t len, int prot, int flags);
-void os_abort(void);
-int os_access(const char* pathname, int mode);
int os_atoi(const char* nptr);
-void* os_calloc(size_t nmemb, size_t size);
-char* os_dirname(char* path);
-char* os_dlerror(void);
-void* os_dlsym(void* handle, const char* symbol);
-int os_fclose(FILE* fp);
-FILE* os_fopen(const char* path, const char* mode);
-size_t os_fread(void* ptr, size_t size, size_t nmemb, FILE* stream);
-void os_free(void* ptr);
int os_getpagesize(void);
void* os_memcpy(void* dest, const void* src, size_t n);
void* os_memset(void* s, int c, size_t n);
-int os_mprotect(void* addr, size_t len, int prot);
-int os_scandir(const char* dir, struct dirent*** namelist, int(*filter)(const struct dirent*), int(*compar)(const void*, const void*));
-int os_stat(const char* path, struct stat* buf);
-char* os_strcat(char* dest, const char* src);
-char* os_strcpy(char* dest, const char* src);
char* os_strdup(const char* s);
int os_strlen(const char* s);
}
+/**
+ * Returns the primitive type of the given primitive-class.
+ *
+ * @param c Class structure.
+ *
+ * @return Integer type of the class.
+ */
+int Primitive::get_type_by_primitiveclass(classinfo *c)
+{
+ /* Search primitive table. */
+
+ for (int i = 0; i < PRIMITIVETYPE_COUNT; i++)
+ if (primitivetype_table[i].class_primitive == c)
+ return i;
+
+ /* Invalid primitive class. */
+
+ return -1;
+}
+
+
/**
* Box a primitive of the given type. If the type is an object,
* simply return it.
static classinfo* get_arrayclass_by_type(int type);
static int get_type_by_wrapperclass(classinfo *c);
+ static int get_type_by_primitiveclass(classinfo *c);
static java_handle_t* box(int type, imm_union value);
#include <string.h>
#include <time.h>
#include <unistd.h>
-#include <sys/utsname.h>
#include "mm/memory.hpp"
#include "native/llni.h"
-#include "toolbox/util.h"
-
#include "vm/class.hpp"
#include "vm/global.h"
#include "vm/method.hpp"
/* Get properties from system. */
- char* cwd = _Jv_getcwd();
+ char* cwd = os::getcwd();
char* env_user = os::getenv("USER");
char* env_home = os::getenv("HOME");
#include <stdint.h>
#include <stdlib.h>
-#if defined(__DARWIN__)
-/* If we compile with -ansi on darwin, <sys/types.h> is not
- included. So let's do it here. */
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-
#include "arch.h"
#if defined(ENABLE_GC_BOEHM)
/* function prototypes ********************************************************/
void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p);
+void signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p);
/* signal_init *****************************************************************
signal_register_signal(Signal_INTERRUPT_SYSTEM_CALL, (functionptr) signal_handler_sighup, 0);
#endif
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
- /* SIGUSR1 handler for the exact GC to suspend threads */
+#if defined(ENABLE_THREADS)
+ /* SIGUSR1 handler for thread suspension */
- signal_register_signal(SIGUSR1, (functionptr) md_signal_handler_sigusr1,
+ signal_register_signal(SIGUSR1, (functionptr) signal_handler_sigusr1,
SA_SIGINFO);
#endif
#endif
+/* signal_handler_sigusr1 ******************************************************
+
+ Signal handler for suspending threads.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+void signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
+{
+ // Really suspend ourselves by acknowledging the suspension.
+ threads_suspend_ack();
+}
+#endif
+
+
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where
void md_signal_handler_sigtrap(int sig, siginfo_t *siginfo, void *_p);
#endif
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p);
-
void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p);
#ifdef __cplusplus
#include "toolbox/list.hpp"
#include "toolbox/logging.hpp"
-#include "toolbox/util.h"
#include "vm/exceptions.hpp"
#include "vm/loader.hpp"
cwdlen = 0;
if (*start != '/') { /* XXX fix me for win32 */
- cwd = _Jv_getcwd();
+ cwd = os::getcwd();
cwdlen = strlen(cwd) + strlen("/");
}
/* src/vm/types.h - type definitions for CACAO's internal types
- Copyright (C) 1996-2005, 2006 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, 2008, 2009
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Contact: cacao@cacaojvm.org
-
- Authors: Reinhard Grafl
- Andreas Krall
-
- Changes: Christian Thalinger
-
*/
#include "config.h"
+#include <stdint.h>
+
/* In this file we check for unknown pointersizes, so we don't have to
do this somewhere else. */
/* Define the sizes of the integer types used internally by CACAO. ************/
-typedef signed char s1;
-typedef unsigned char u1;
-
-typedef signed short int s2;
-typedef unsigned short int u2;
+typedef int8_t s1;
+typedef uint8_t u1;
+
+typedef int16_t s2;
+typedef uint16_t u2;
-typedef signed int s4;
-typedef unsigned int u4;
+typedef int32_t s4;
+typedef uint32_t u4;
-#if SIZEOF_VOID_P == 8
-typedef signed long int s8;
-typedef unsigned long int u8;
-#elif SIZEOF_VOID_P == 4
-typedef signed long long int s8;
-typedef unsigned long long int u8;
-#else
-#error unknown pointer size
-#endif
+typedef int64_t s8;
+typedef uint64_t u8;
/* Define the size of a function pointer used in function pointer casts. ******/
-#if SIZEOF_VOID_P == 8
-typedef u8 ptrint;
-#else
-typedef u4 ptrint;
-#endif
+typedef uintptr_t ptrint;
#endif /* _CACAO_TYPES_H */
utf *utf_Signature;
utf *utf_StackMapTable;
-#if defined(ENABLE_ANNOTATIONS)
+# if defined(ENABLE_JVMTI)
+utf *utf_LocalVariableTable;
+# endif
+
+# if defined(ENABLE_ANNOTATIONS)
utf *utf_RuntimeVisibleAnnotations; /* RuntimeVisibleAnnotations */
utf *utf_RuntimeInvisibleAnnotations; /* RuntimeInvisibleAnnotations */
utf *utf_RuntimeVisibleParameterAnnotations; /* RuntimeVisibleParameterAnnotations */
utf *utf_RuntimeInvisibleParameterAnnotations; /* RuntimeInvisibleParameterAnnotations */
utf *utf_AnnotationDefault; /* AnnotationDefault */
-#endif
+# endif
#endif
utf *utf_init; /* <init> */
utf_Signature = utf_new_char("Signature");
utf_StackMapTable = utf_new_char("StackMapTable");
+# if defined(ENABLE_JVMTI)
+ utf_LocalVariableTable = utf_new_char("LocalVariableTable");
+# endif
+
# if defined(ENABLE_ANNOTATIONS)
utf_RuntimeVisibleAnnotations = utf_new_char("RuntimeVisibleAnnotations");
utf_RuntimeInvisibleAnnotations = utf_new_char("RuntimeInvisibleAnnotations");
extern utf *utf_Signature;
extern utf *utf_StackMapTable;
-#if defined(ENABLE_ANNOTATIONS)
+# if defined(ENABLE_JVMTI)
+extern utf *utf_LocalVariableTable;
+# endif
+
+# if defined(ENABLE_ANNOTATIONS)
extern utf *utf_RuntimeVisibleAnnotations;
extern utf *utf_RuntimeInvisibleAnnotations;
extern utf *utf_RuntimeVisibleParameterAnnotations;
extern utf *utf_RuntimeInvisibleParameterAnnotations;
extern utf *utf_AnnotationDefault;
-#endif
+# endif
#endif
extern utf *utf_init;
/* src/vm/vm.cpp - VM startup and shutdown functions
- Copyright (C) 1996-2005, 2006, 2007, 2008
+ Copyright (C) 1996-2005, 2006, 2007, 2008, 2009
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
#include "vm/finalizer.hpp"
#include "vm/global.h"
#include "vm/globals.hpp"
+#include "vm/hook.hpp"
#include "vm/initialize.hpp"
#include "vm/options.h"
#include "vm/os.hpp"
*******************************************************************************/
-void usage(void)
+static void usage(void)
{
puts("Usage: cacao [-options] classname [arguments]");
puts(" (to run a class file)");
puts("java version \""JAVA_VERSION"\"");
puts("CACAO version "VERSION"\n");
- puts("Copyright (C) 1996-2005, 2006, 2007, 2008");
+ puts("Copyright (C) 1996-2005, 2006, 2007, 2008, 2009");
puts("CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO");
puts("This is free software; see the source for copying conditions. There is NO");
puts("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
utf8_init();
+ // Hook point before the VM is initialized.
+ Hook::vm_preinit();
+
#if defined(ENABLE_JVMTI)
// AFTER: utf8_init
if (!_nativeagents.load_agents())
// Initialization is done, VM is created.
_created = true;
_initializing = false;
-
+
+ // Set the VM inittime.
+ _inittime = builtin_currenttimemillis();
+
+ // Hook point after the VM is initialized.
+ Hook::vm_init();
+
// Print the run-time VM configuration after all stuff is set and
// the VM is initialized.
if (opt_PrintConfig)
print_run_time_config();
+
+ // Start runtime agents after the VM is created.
+ if (!start_runtime_agents())
+ os::abort("vm_create: start_runtime_agents failed");
}
}
+/**
+ * Start runtime agents which are provided by the JRE but need to be
+ * started explicitly by the VM.
+ */
+bool VM::start_runtime_agents()
+{
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+
+ // Nothing to do.
+
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+
+ // Check whether the management agent should be loaded.
+ if ((_properties.get("com.sun.management.jmxremote") != NULL) ||
+ (_properties.get("com.sun.management.snmp") != NULL))
+ {
+
+ // Load the management agent class.
+ classinfo* class_sun_management_Agent;
+ if (!(class_sun_management_Agent = load_class_from_sysloader(utf_new_char("sun/management/Agent"))))
+ return false;
+
+ // Link the management agent class.
+ if (!link_class(class_sun_management_Agent))
+ return false;
+
+ // Actually start the management agent.
+ methodinfo* m = class_resolveclassmethod(class_sun_management_Agent,
+ utf_new_char("startAgent"),
+ utf_void__void,
+ class_java_lang_Object,
+ false);
+
+ if (m == NULL)
+ return false;
+
+ (void) vm_call_method(m, NULL);
+
+ if (exceptions_get_exception() != NULL)
+ return false;
+ }
+
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
+
+ // Nothing to do.
+
+#else
+# error unknown classpath configuration
+#endif
+
+ return true;
+}
+
+
/* vm_run **********************************************************************
Runs the main-method of the passed class.
typeinfo_test();
#endif
- /* set ThreadMXBean variables */
-
-// _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++;
-// _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++;
-
-// if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount >
-// _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount)
-// _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount =
-// _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount;
-#warning Move to C++
-
/* start the main thread */
(void) vm_call_method(m, NULL, oa.get_handle());
threads_join_all_threads();
#endif
+ // Hook point before the VM is actually destroyed.
+ Hook::vm_shutdown();
+
/* VM is gone. */
// _created = false;
extern "C" {
-JavaVM* VM_get_javavm() { return VM::get_current()->get_javavm(); }
JNIEnv* VM_get_jnienv() { return VM::get_current()->get_jnienv(); }
-bool VM_is_initializing() { return VM::get_current()->is_initializing(); }
-bool VM_is_created() { return VM::get_current()->is_created(); }
-int64_t VM_get_starttime() { return VM::get_current()->get_starttime(); }
void vm_abort(const char* text, ...)
{
bool _created;
bool _exiting;
int64_t _starttime;
+ int64_t _inittime;
// Subsystems.
Properties _properties; ///< Commandline properties.
bool is_created() { return _created; }
bool is_exiting() { return _exiting; }
int64_t get_starttime() { return _starttime; }
+ int64_t get_inittime() { return _inittime; }
Properties& get_properties () { return _properties; }
Recompiler& get_recompiler () { return _recompiler; } // REMOVEME
NativeLibraries& get_nativelibraries() { return _nativelibraries; }
NativeMethods& get_nativemethods () { return _nativemethods; }
SuckClasspath& get_suckclasspath () { return _suckclasspath; }
+
+private:
+ // Internal helper methods.
+ bool start_runtime_agents();
};
#else
-JavaVM* VM_get_javavm();
JNIEnv* VM_get_jnienv();
-bool VM_is_initializing();
-bool VM_is_created();
-int64_t VM_get_starttime();
#endif
extern "C" {
#endif
-void usage(void);
-
-bool vm_create(JavaVMInitArgs *vm_args);
void vm_run(JavaVM *vm, JavaVMInitArgs *vm_args);
int32_t vm_destroy(JavaVM *vm);
void vm_exit(int32_t status);
#include <assert.h>
#include <errno.h>
-#include <fcntl.h>
#include <unistd.h>
#include <zlib.h>
-#include <sys/mman.h>
#include "vm/types.h"
#include "mm/memory.hpp"
#include "vm/global.h"
+#include "vm/os.hpp"
#include "vm/suck.hpp"
#include "vm/utf8.h"
#include "vm/vm.hpp"
@RunWith(Suite.class)
@Suite.SuiteClasses({
+TestAbstractMethodError.class,
TestArrayClasses.class,
TestCloning.class,
TestExceptionInStaticClassInitializer.class,
--- /dev/null
+/* tests/regression/base/TestAbstractMethodError.java
+
+ Copyright (C) 2009
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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 for more details.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class TestAbstractMethodError extends ClassLoader {
+ @Test
+ public void test() throws InstantiationException, IllegalAccessException {
+ Class cls = super.defineClass(null, bytecode, 0, bytecode.length);
+ Base obj = (Base) cls.newInstance();
+ try {
+ obj.foo();
+ fail();
+ } catch (AbstractMethodError e) {
+ StackTraceElement[] st = e.getStackTrace();
+ assertNotNull("stack trace available", st);
+ assertTrue("stack trace size", st.length > 1);
+ assertEquals("stack trace element",
+ "TestAbstractMethodError.test(TestAbstractMethodError.java:35)",
+ st[0].toString());
+ }
+ }
+
+ public static abstract class Base {
+ abstract void foo();
+ };
+
+ /*
+ * The following Bytecode was derived from a class like this:
+ * public class Foo extends TestAbstractMethodError.Base {
+ * // empty.
+ * }
+ *
+ * This class is not abstract but it misses to implement the
+ * abstract method "void foo()" of the base class.
+ */
+ static byte[] bytecode = {
+ (byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x2e,
+ (byte)0x00, (byte)0x0e, (byte)0x07, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x03,
+ (byte)0x46, (byte)0x6f, (byte)0x6f, (byte)0x07, (byte)0x00, (byte)0x04, (byte)0x01, (byte)0x00,
+ (byte)0x1c, (byte)0x54, (byte)0x65, (byte)0x73, (byte)0x74, (byte)0x41, (byte)0x62, (byte)0x73,
+ (byte)0x74, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x74, (byte)0x4d, (byte)0x65, (byte)0x74,
+ (byte)0x68, (byte)0x6f, (byte)0x64, (byte)0x45, (byte)0x72, (byte)0x72, (byte)0x6f, (byte)0x72,
+ (byte)0x24, (byte)0x42, (byte)0x61, (byte)0x73, (byte)0x65, (byte)0x01, (byte)0x00, (byte)0x06,
+ (byte)0x3c, (byte)0x69, (byte)0x6e, (byte)0x69, (byte)0x74, (byte)0x3e, (byte)0x01, (byte)0x00,
+ (byte)0x03, (byte)0x28, (byte)0x29, (byte)0x56, (byte)0x01, (byte)0x00, (byte)0x04, (byte)0x43,
+ (byte)0x6f, (byte)0x64, (byte)0x65, (byte)0x0a, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x09,
+ (byte)0x0c, (byte)0x00, (byte)0x05, (byte)0x00, (byte)0x06, (byte)0x01, (byte)0x00, (byte)0x0c,
+ (byte)0x49, (byte)0x6e, (byte)0x6e, (byte)0x65, (byte)0x72, (byte)0x43, (byte)0x6c, (byte)0x61,
+ (byte)0x73, (byte)0x73, (byte)0x65, (byte)0x73, (byte)0x07, (byte)0x00, (byte)0x0c, (byte)0x01,
+ (byte)0x00, (byte)0x17, (byte)0x54, (byte)0x65, (byte)0x73, (byte)0x74, (byte)0x41, (byte)0x62,
+ (byte)0x73, (byte)0x74, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x74, (byte)0x4d, (byte)0x65,
+ (byte)0x74, (byte)0x68, (byte)0x6f, (byte)0x64, (byte)0x45, (byte)0x72, (byte)0x72, (byte)0x6f,
+ (byte)0x72, (byte)0x01, (byte)0x00, (byte)0x04, (byte)0x42, (byte)0x61, (byte)0x73, (byte)0x65,
+ (byte)0x00, (byte)0x21, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x05,
+ (byte)0x00, (byte)0x06, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x07, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x11, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x05, (byte)0x2a, (byte)0xb7, (byte)0x00, (byte)0x08, (byte)0xb1, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x0a, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x03, (byte)0x00,
+ (byte)0x0b, (byte)0x00, (byte)0x0d, (byte)0x04, (byte)0x09,
+ };
+}