diff options
Diffstat (limited to 'tests/nbody-java/xmlvm.c')
-rw-r--r-- | tests/nbody-java/xmlvm.c | 565 |
1 files changed, 565 insertions, 0 deletions
diff --git a/tests/nbody-java/xmlvm.c b/tests/nbody-java/xmlvm.c new file mode 100644 index 00000000..35e04d16 --- /dev/null +++ b/tests/nbody-java/xmlvm.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2002-2011 by XMLVM.org + * + * Project Info: http://www.xmlvm.org + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include "xmlvm.h" +#include "xmlvm-util.h" +#include "java_lang_System.h" +#include "java_lang_Class.h" +#include "java_lang_String.h" +#include "java_lang_Throwable.h" +#include "org_xmlvm_runtime_FinalizerNotifier.h" +#include "org_xmlvm_runtime_XMLVMUtil.h" +#include <stdio.h> +#include <string.h> + + +XMLVM_STATIC_INITIALIZER_CONTROLLER* staticInitializerController; + +// This exception value is only used for the main thread. +// Since a call to Thread.currentThread() contains try-catch blocks, this must +// be defined before the "main" java.lang.Thread is defined. +XMLVM_JMP_BUF xmlvm_exception_env_main_thread; + + +#ifdef XMLVM_ENABLE_STACK_TRACES + + +#include "uthash.h" + +#define HASH_ADD_JAVA_LONG(head,javalongfield,add) \ + HASH_ADD(hh,head,javalongfield,sizeof(JAVA_LONG),add) +#define HASH_FIND_JAVA_LONG(head,findjavalong,out) \ + HASH_FIND(hh,head,findjavalong,sizeof(JAVA_LONG),out) + +// A map of type UTHash with a key of JAVA_LONG and value of JAVA_OBJECT +struct hash_struct { + JAVA_LONG key; + JAVA_OBJECT value; + UT_hash_handle hh; // makes this structure hashable +}; + + +// Map of thread id to its stack trace +struct hash_struct** threadToStackTraceMapPtr; + + +#endif + + +void xmlvm_init() +{ +#ifdef XMLVM_ENABLE_STACK_TRACES + threadToStackTraceMapPtr = malloc(sizeof(struct hash_struct**)); + struct hash_struct* map = NULL; // This must be set to NULL according to the UTHash documentation + *threadToStackTraceMapPtr = map; + + JAVA_LONG nativeThreadId = (JAVA_LONG) pthread_self(); + createStackForNewThread(nativeThreadId); +#endif + +#ifndef XMLVM_NO_GC +//#ifdef DEBUG +// setenv("GC_PRINT_STATS", "1", 1); +//#endif + GC_INIT(); + GC_enable_incremental(); +#endif + + staticInitializerController = XMLVM_MALLOC(sizeof(XMLVM_STATIC_INITIALIZER_CONTROLLER)); + staticInitializerController->initMutex = XMLVM_MALLOC(sizeof(pthread_mutex_t)); + if (0 != pthread_mutex_init(staticInitializerController->initMutex, NULL)) { + XMLVM_ERROR("Error initializing static initializer mutex", __FILE__, __FUNCTION__, __LINE__); + } + + __INIT_org_xmlvm_runtime_XMLVMArray(); + java_lang_Class_initNativeLayer__(); + __INIT_java_lang_System(); + org_xmlvm_runtime_XMLVMUtil_init__(); + /* + * The implementation of the constant pool makes use of cross-compiled Java data structures. + * During initialization of the VM done up to this point there are some circular dependencies + * between class initializers of various classes and the constant pool that lead to some + * inconsistencies. The easiest way to fix this is to clear the constant pool cache. + */ + xmlvm_clear_constant_pool_cache(); + +#ifndef XMLVM_NO_GC +#ifndef EMSCRIPTEN + GC_finalize_on_demand = 1; + GC_java_finalization = 1; + java_lang_Thread* finalizerThread = (java_lang_Thread*) org_xmlvm_runtime_FinalizerNotifier_startFinalizerThread__(); + GC_finalizer_notifier = org_xmlvm_runtime_FinalizerNotifier_finalizerNotifier__; +#endif +#endif + + reference_array = XMLVMUtil_NEW_ArrayList(); +} + +void xmlvm_destroy(java_lang_Thread* mainThread) +{ +#ifdef EMSCRIPTEN + return; // Let the JS engine handle clean up +#endif + + java_lang_Thread_threadTerminating__(mainThread); + +#ifdef XMLVM_ENABLE_STACK_TRACES + JAVA_LONG nativeThreadId = (JAVA_LONG) pthread_self(); + destroyStackForExitingThread(nativeThreadId); +#endif + + // Unregister the current thread. Only an explicitly registered + // thread (i.e. for which GC_register_my_thread() returns GC_SUCCESS) + // is allowed (and required) to call this function. (As a special + // exception, it is also allowed to once unregister the main thread.) +#ifndef XMLVM_NO_GC + GC_unregister_my_thread(); +#endif + + // Call pthread_exit(0) so that the main thread does not terminate until + // the other threads have finished + pthread_exit(0); +} + +/** + * Lock a mutex. If an error occurs, terminate the program. + */ +static void lockOrExit(char* className, pthread_mutex_t* mut) +{ + int result = pthread_mutex_lock(mut); + if (0 != result) { + printf("Error locking mutex in %s: %i\n", className, result); + exit(1); + } +// else { printf("SUCCESSFUL mutex lock in %s\n", className); } +} + +/** + * Unlock a mutex. If an error occurs, terminate the program. + */ +static void unlockOrExit(char* className, pthread_mutex_t* mut) +{ + int result = pthread_mutex_unlock(mut); + if (0 != result) { + printf("Error unlocking mutex in %s: %i\n", className, result); + exit(1); + } +// else { printf("SUCCESSFUL mutex unlock in %s\n", className); } +} + +/** + * Lock the static initializer mutex. + */ +void staticInitializerLock(void* tibDefinition) +{ + char* className = ((struct __TIB_DEFINITION_TEMPLATE*)tibDefinition)->className; + lockOrExit(className, staticInitializerController->initMutex); +} + +/** + * Unlock the static initializer mutex. + */ +void staticInitializerUnlock(void* tibDefinition) +{ + char* className = ((struct __TIB_DEFINITION_TEMPLATE*)tibDefinition)->className; + unlockOrExit(className, staticInitializerController->initMutex); +} + +int xmlvm_java_string_cmp(JAVA_OBJECT s1, const char* s2) +{ + java_lang_String* str = (java_lang_String*) s1; + JAVA_INT len = str->fields.java_lang_String.count_; + if (len != strlen(s2)) { + return 0; + } + JAVA_INT offset = str->fields.java_lang_String.offset_; + org_xmlvm_runtime_XMLVMArray* value = (org_xmlvm_runtime_XMLVMArray*) str->fields.java_lang_String.value_; + JAVA_ARRAY_CHAR* valueArray = (JAVA_ARRAY_CHAR*) value->fields.org_xmlvm_runtime_XMLVMArray.array_; + for (int i = 0; i < len; i++) { + if (valueArray[i + offset] != s2[i]) { + return 0; + } + } + return 1; +} + +const char* xmlvm_java_string_to_const_char(JAVA_OBJECT s) +{ + if (s == JAVA_NULL) { + return "null"; + } + java_lang_String* str = (java_lang_String*) s; + JAVA_INT len = str->fields.java_lang_String.count_; + char* cs = XMLVM_ATOMIC_MALLOC(len + 1); + JAVA_INT offset = str->fields.java_lang_String.offset_; + org_xmlvm_runtime_XMLVMArray* value = (org_xmlvm_runtime_XMLVMArray*) str->fields.java_lang_String.value_; + JAVA_ARRAY_CHAR* valueArray = (JAVA_ARRAY_CHAR*) value->fields.org_xmlvm_runtime_XMLVMArray.array_; + int i = 0; + for (i = 0; i < len; i++) { + cs[i] = valueArray[i + offset]; + } + cs[i] = '\0'; + return cs; +} + +JAVA_OBJECT xmlvm_create_java_string(const char* s) +{ + java_lang_String* str = __NEW_java_lang_String(); + org_xmlvm_runtime_XMLVMArray* charArray = XMLVMArray_createFromString(s); + java_lang_String___INIT____char_1ARRAY(str, charArray); + return XMLVMUtil_getFromStringPool(str); +} + +JAVA_OBJECT xmlvm_create_java_string_array(int count, const char **s) +{ + JAVA_OBJECT javaStrings[count]; + for (int i = 0; i < count; i++) { + javaStrings[i] = xmlvm_create_java_string(s[i]); + } + JAVA_OBJECT javaStringArray = XMLVMArray_createSingleDimension(__CLASS_java_lang_String, count); + XMLVMArray_fillArray(javaStringArray, javaStrings); + return javaStringArray; +} + +static JAVA_OBJECT* stringConstants = JAVA_NULL; + +JAVA_OBJECT xmlvm_create_java_string_from_pool(int pool_id) +{ + if (stringConstants == JAVA_NULL) { + // TODO: use XMLVM_ATOMIC_MALLOC? + stringConstants = XMLVM_MALLOC(xmlvm_constant_pool_size * sizeof(JAVA_OBJECT)); + XMLVM_BZERO(stringConstants, xmlvm_constant_pool_size * sizeof(JAVA_OBJECT)); + } + if (stringConstants[pool_id] != JAVA_NULL) { + return stringConstants[pool_id]; + } + java_lang_String* str = __NEW_java_lang_String(); + org_xmlvm_runtime_XMLVMArray* charArray = XMLVMArray_createSingleDimensionWithData(__CLASS_char, + xmlvm_constant_pool_length[pool_id], + (JAVA_OBJECT) xmlvm_constant_pool_data[pool_id]); + java_lang_String___INIT____char_1ARRAY(str, charArray); + JAVA_OBJECT poolStr = XMLVMUtil_getFromStringPool(str); + stringConstants[pool_id] = poolStr; + return poolStr; +} + +void xmlvm_clear_constant_pool_cache() +{ + XMLVM_BZERO(stringConstants, xmlvm_constant_pool_size * sizeof(JAVA_OBJECT)); +} + + +//--------------------------------------------------------------------------------------------- +// XMLVMClass + +JAVA_OBJECT XMLVM_CREATE_CLASS_OBJECT(void* tib) +{ + JAVA_OBJECT clazz = __NEW_java_lang_Class(); + java_lang_Class___INIT____java_lang_Object(clazz, tib); + return clazz; +} + + +JAVA_OBJECT XMLVM_CREATE_ARRAY_CLASS_OBJECT(JAVA_OBJECT baseType) +{ + __TIB_DEFINITION_org_xmlvm_runtime_XMLVMArray* tib = XMLVM_MALLOC(sizeof(__TIB_DEFINITION_org_xmlvm_runtime_XMLVMArray)); + XMLVM_MEMCPY(tib, &__TIB_org_xmlvm_runtime_XMLVMArray, sizeof(__TIB_DEFINITION_org_xmlvm_runtime_XMLVMArray)); + tib->flags = XMLVM_TYPE_ARRAY; + tib->baseType = baseType; + tib->arrayType = JAVA_NULL; + JAVA_OBJECT clazz = __NEW_java_lang_Class(); + java_lang_Class___INIT____java_lang_Object(clazz, tib); + tib->clazz = clazz; + // Set the arrayType in in baseType to this newly created array type class + java_lang_Class* baseTypeClass = (java_lang_Class*) baseType; + __TIB_DEFINITION_TEMPLATE* baseTypeTIB = (__TIB_DEFINITION_TEMPLATE*) baseTypeClass->fields.java_lang_Class.tib_; + baseTypeTIB->arrayType = clazz; + return clazz; +} + + +int XMLVM_ISA(JAVA_OBJECT obj, JAVA_OBJECT clazz) +{ + if (obj == JAVA_NULL) { + return 0; + } + + int dimension_tib1 = 0; + int dimension_tib2 = 0; + __TIB_DEFINITION_TEMPLATE* tib1 = (__TIB_DEFINITION_TEMPLATE*) ((java_lang_Object*) obj)->tib; + __TIB_DEFINITION_TEMPLATE* tib2 = (__TIB_DEFINITION_TEMPLATE*) ((java_lang_Class*) clazz)->fields.java_lang_Class.tib_; + + if (tib1 == &__TIB_org_xmlvm_runtime_XMLVMArray) { + java_lang_Class* clazz = ((org_xmlvm_runtime_XMLVMArray*) obj)->fields.org_xmlvm_runtime_XMLVMArray.type_; + tib1 = clazz->fields.java_lang_Class.tib_; + } + + while (tib1->baseType != JAVA_NULL) { + tib1 = ((java_lang_Class*) tib1->baseType)->fields.java_lang_Class.tib_; + dimension_tib1++; + } + + while (tib2->baseType != JAVA_NULL) { + tib2 = ((java_lang_Class*) tib2->baseType)->fields.java_lang_Class.tib_; + dimension_tib2++; + } + + if (dimension_tib1 < dimension_tib2) { + return 0; + } + + while (tib1 != JAVA_NULL) { + if (tib1 == tib2) { + return 1; + } + // Check all implemented interfaces + int i; + for (i = 0; i < tib1->numImplementedInterfaces; i++) { + if (tib1->implementedInterfaces[0][i] == tib2) { + return 1; + } + } + tib1 = tib1->extends; + } + return 0; +} + +//--------------------------------------------------------------------------------------------- +// Stack traces + +#ifdef XMLVM_ENABLE_STACK_TRACES + +void createStackForNewThread(JAVA_LONG threadId) +{ + struct hash_struct *s = malloc(sizeof(struct hash_struct)); + s->key = threadId; + + XMLVM_STACK_TRACE_CURRENT* newStack = malloc(sizeof(XMLVM_STACK_TRACE_CURRENT)); + newStack->stackSize = 0; + newStack->topOfStack = NULL; + + s->value = newStack; + HASH_ADD_JAVA_LONG((struct hash_struct *)*threadToStackTraceMapPtr, key, s); +} + +void destroyStackForExitingThread(JAVA_LONG threadId) +{ + struct hash_struct *s; + HASH_FIND_JAVA_LONG((struct hash_struct *)*threadToStackTraceMapPtr, &threadId, s); + if (s == NULL) { + printf("ERROR: Unable to destroy stack trace for exiting thread!\n"); + exit(-1); + } else { + HASH_DEL((struct hash_struct *)*threadToStackTraceMapPtr, s); + free(s->value); + free(s); + } +} + +XMLVM_STACK_TRACE_CURRENT* getCurrentStackTrace() +{ + JAVA_LONG currentThreadId = (JAVA_LONG)pthread_self(); + struct hash_struct *s; + HASH_FIND_JAVA_LONG((struct hash_struct *)*threadToStackTraceMapPtr, ¤tThreadId, s); + if (s == NULL) { + printf("ERROR: Unable to find stack trace for current thread!\n"); + exit(-1); + } + return (XMLVM_STACK_TRACE_CURRENT*)s->value; +} + +void xmlvmEnterMethod(XMLVM_STACK_TRACE_CURRENT* threadStack, const char* className, const char* methodName, const char* fileName) +{ + //printf("Entering method %s\n", className); + + XMLVM_STACK_TRACE_ELEMENT* newLocationElement = malloc(sizeof(XMLVM_STACK_TRACE_ELEMENT)); + newLocationElement->className = className; + newLocationElement->methodName = methodName; + newLocationElement->fileName = fileName; + newLocationElement->lineNumber = -2; + + XMLVM_STACK_TRACE_LINK* link = malloc(sizeof(XMLVM_STACK_TRACE_LINK)); + link->nextLink = threadStack->topOfStack; + if (threadStack->topOfStack != NULL) { + link->element = threadStack->topOfStack->currentLocation; + } + link->currentLocation = newLocationElement; + + // Push what was the current location onto the stack and set the new current location + threadStack->stackSize++; + threadStack->topOfStack = link; +} + +void xmlvmSourcePosition(XMLVM_STACK_TRACE_CURRENT* threadStack, const char* fileName, int lineNumber) +{ + //printf("Source position update %i\n", lineNumber); + + threadStack->topOfStack->currentLocation->fileName = fileName; + threadStack->topOfStack->currentLocation->lineNumber = lineNumber; +} + +void xmlvmExitMethod(XMLVM_STACK_TRACE_CURRENT* threadStack) +{ + //printf("Exiting method\n"); + + XMLVM_STACK_TRACE_LINK* linkToDestroy = threadStack->topOfStack; + threadStack->topOfStack = linkToDestroy->nextLink; + threadStack->stackSize--; + + free(linkToDestroy->currentLocation); + free(linkToDestroy); +} + +void xmlvmUnwindException(XMLVM_STACK_TRACE_CURRENT* threadStack, int unwindToStackSize) +{ + while (unwindToStackSize + 1 < threadStack->stackSize) { + //printf("Unwinding stack after catching an exception: %i > %i\n", unwindToStackSize, threadStack->stackSize); + xmlvmExitMethod(threadStack); + } +} + +#endif + + +#ifdef XMLVM_ENABLE_CLASS_LOGGING +//--------------------------------------------------------------------------------------------- +// Reflection/Class Usage logging + +FILE *logFile = 0; +int useLogging = 1; + +void xmlvmClassUsed(const char *prefix, const char *className) { + if (useLogging && (logFile == 0)) { + logFile = fopen("touched_classes.txt", "w"); + } + if (useLogging && (logFile != 0)) { + fprintf(logFile, "%s:%s\n", prefix, className); + } else { + useLogging = 0; // Failed to open file, so stop + } +} + +#endif + +//--------------------------------------------------------------------------------------------- +// XMLVMArray + + +JAVA_OBJECT XMLVMArray_createSingleDimension(JAVA_OBJECT type, JAVA_INT size) +{ + return org_xmlvm_runtime_XMLVMArray_createSingleDimension___java_lang_Class_int(type, size); +} + +JAVA_OBJECT XMLVMArray_createSingleDimensionWithData(JAVA_OBJECT type, JAVA_INT size, JAVA_OBJECT data) +{ + return org_xmlvm_runtime_XMLVMArray_createSingleDimensionWithData___java_lang_Class_int_java_lang_Object(type, size, data); +} + + +JAVA_OBJECT XMLVMArray_createMultiDimensions(JAVA_OBJECT type, JAVA_OBJECT dimensions) +{ + return org_xmlvm_runtime_XMLVMArray_createMultiDimensions___java_lang_Class_org_xmlvm_runtime_XMLVMArray(type, dimensions); +} + +JAVA_OBJECT XMLVMArray_createFromString(const char* str) +{ + int len = strlen(str); + int size = len * sizeof(JAVA_ARRAY_CHAR); + int i; + JAVA_ARRAY_CHAR* data = XMLVM_ATOMIC_MALLOC(size); + for (i = 0; i < len; i++) { + data[i] = *str++; + } + return XMLVMArray_createSingleDimensionWithData(__CLASS_char, len, data); +} + +void XMLVMArray_fillArray(JAVA_OBJECT array, void* data) +{ + org_xmlvm_runtime_XMLVMArray_fillArray___org_xmlvm_runtime_XMLVMArray_java_lang_Object(array, data); +} + +int XMLVMArray_count(JAVA_OBJECT array) +{ + org_xmlvm_runtime_XMLVMArray* a = (org_xmlvm_runtime_XMLVMArray*) array; + return a->fields.org_xmlvm_runtime_XMLVMArray.length_; +} + +void xmlvm_unhandled_exception() +{ + java_lang_Thread* curThread; + curThread = (java_lang_Thread*) java_lang_Thread_currentThread__(); + JAVA_OBJECT exception = curThread->fields.java_lang_Thread.xmlvmException_; + + JAVA_OBJECT thread_name; +#ifdef XMLVM_VTABLE_IDX_java_lang_Thread_getName__ + thread_name = ((Func_OO) ((java_lang_Thread*) curThread)->tib->vtable[XMLVM_VTABLE_IDX_java_lang_Thread_getName__])(curThread); +#else + thread_name = java_lang_Thread_getName__(curThread); +#endif + +#ifdef XMLVM_ENABLE_STACK_TRACES + + printf("Exception in thread \"%s\" ", + xmlvm_java_string_to_const_char(thread_name)); + java_lang_Throwable_printStackTrace__(exception); + +#else + + JAVA_OBJECT message; +#ifdef XMLVM_VTABLE_IDX_java_lang_Throwable_getMessage__ + message = ((Func_OO) ((java_lang_Throwable*) exception)->tib->vtable[XMLVM_VTABLE_IDX_java_lang_Throwable_getMessage__])(exception); +#else + message = java_lang_Throwable_getMessage__(exception); +#endif + + JAVA_OBJECT exception_class; +#ifdef XMLVM_VTABLE_IDX_java_lang_Object_getClass__ + exception_class = ((Func_OO) ((java_lang_Object*) exception)->tib->vtable[XMLVM_VTABLE_IDX_java_lang_Object_getClass__])(exception); +#else + exception_class = java_lang_Object_getClass__(exception); +#endif + + JAVA_OBJECT class_name; +#ifdef XMLVM_VTABLE_IDX_java_lang_Class_getName__ + class_name = ((Func_OO) ((java_lang_Class*) exception_class)->tib->vtable[XMLVM_VTABLE_IDX_java_lang_Class_getName__])(exception_class); +#else + class_name = java_lang_Class_getName__(exception_class); +#endif + + printf("Exception in thread \"%s\" %s: %s\n", + xmlvm_java_string_to_const_char(thread_name), + xmlvm_java_string_to_const_char(class_name), + xmlvm_java_string_to_const_char(message)); + +#endif +} + +void xmlvm_unimplemented_native_method() +{ + XMLVM_ERROR("Unimplemented native method", __FILE__, __FUNCTION__, __LINE__); +} + +void XMLVM_ERROR(const char* msg, const char* file, const char* function, int line) +{ + printf("XMLVM Error: %s: (%s):%s:%d\n", msg, function, file, line); + exit(-1); +} + |