1 /*
2  * Copyright (c) 2002-2011 by XMLVM.org
3  *
4  * Project Info:  http://www.xmlvm.org
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14  * License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
19  * USA.
20  */
21 
22 #include "xmlvm.h"
23 #include "xmlvm-util.h"
24 #include "java_lang_System.h"
25 #include "java_lang_Class.h"
26 #include "java_lang_String.h"
27 #include "java_lang_Throwable.h"
28 #include "org_xmlvm_runtime_FinalizerNotifier.h"
29 #include "org_xmlvm_runtime_XMLVMUtil.h"
30 #include <stdio.h>
31 #include <string.h>
32 
33 
34 XMLVM_STATIC_INITIALIZER_CONTROLLER* staticInitializerController;
35 
36 // This exception value is only used for the main thread.
37 // Since a call to Thread.currentThread() contains try-catch blocks, this must
38 // be defined before the "main" java.lang.Thread is defined.
39 XMLVM_JMP_BUF xmlvm_exception_env_main_thread;
40 
41 
42 #ifdef XMLVM_ENABLE_STACK_TRACES
43 
44 
45 #include "uthash.h"
46 
47 #define HASH_ADD_JAVA_LONG(head,javalongfield,add) \
48     HASH_ADD(hh,head,javalongfield,sizeof(JAVA_LONG),add)
49 #define HASH_FIND_JAVA_LONG(head,findjavalong,out) \
50     HASH_FIND(hh,head,findjavalong,sizeof(JAVA_LONG),out)
51 
52 // A map of type UTHash with a key of JAVA_LONG and value of JAVA_OBJECT
53 struct hash_struct {
54     JAVA_LONG key;
55     JAVA_OBJECT value;
56     UT_hash_handle hh; // makes this structure hashable
57 };
58 
59 
60 // Map of thread id to its stack trace
61 struct hash_struct** threadToStackTraceMapPtr;
62 
63 
64 #endif
65 
66 
xmlvm_init()67 void xmlvm_init()
68 {
69 #ifdef XMLVM_ENABLE_STACK_TRACES
70     threadToStackTraceMapPtr = malloc(sizeof(struct hash_struct**));
71     struct hash_struct* map = NULL; // This must be set to NULL according to the UTHash documentation
72     *threadToStackTraceMapPtr = map;
73 
74     JAVA_LONG nativeThreadId = (JAVA_LONG) pthread_self();
75     createStackForNewThread(nativeThreadId);
76 #endif
77 
78 #ifndef XMLVM_NO_GC
79 //#ifdef DEBUG
80 //    setenv("GC_PRINT_STATS", "1", 1);
81 //#endif
82     GC_INIT();
83     GC_enable_incremental();
84 #endif
85 
86     staticInitializerController = XMLVM_MALLOC(sizeof(XMLVM_STATIC_INITIALIZER_CONTROLLER));
87     staticInitializerController->initMutex = XMLVM_MALLOC(sizeof(pthread_mutex_t));
88     if (0 != pthread_mutex_init(staticInitializerController->initMutex, NULL)) {
89         XMLVM_ERROR("Error initializing static initializer mutex", __FILE__, __FUNCTION__, __LINE__);
90     }
91 
92     __INIT_org_xmlvm_runtime_XMLVMArray();
93     java_lang_Class_initNativeLayer__();
94     __INIT_java_lang_System();
95     org_xmlvm_runtime_XMLVMUtil_init__();
96     /*
97      * The implementation of the constant pool makes use of cross-compiled Java data structures.
98      * During initialization of the VM done up to this point there are some circular dependencies
99      * between class initializers of various classes and the constant pool that lead to some
100      * inconsistencies. The easiest way to fix this is to clear the constant pool cache.
101      */
102     xmlvm_clear_constant_pool_cache();
103 
104 #ifndef XMLVM_NO_GC
105 #ifndef __EMSCRIPTEN__
106     GC_finalize_on_demand = 1;
107     GC_java_finalization = 1;
108     java_lang_Thread* finalizerThread = (java_lang_Thread*) org_xmlvm_runtime_FinalizerNotifier_startFinalizerThread__();
109     GC_finalizer_notifier = org_xmlvm_runtime_FinalizerNotifier_finalizerNotifier__;
110 #endif
111 #endif
112 
113 	reference_array = XMLVMUtil_NEW_ArrayList();
114 }
115 
xmlvm_destroy(java_lang_Thread * mainThread)116 void xmlvm_destroy(java_lang_Thread* mainThread)
117 {
118 #ifdef __EMSCRIPTEN__
119 	return; // Let the JS engine handle clean up
120 #endif
121 
122     java_lang_Thread_threadTerminating__(mainThread);
123 
124 #ifdef XMLVM_ENABLE_STACK_TRACES
125     JAVA_LONG nativeThreadId = (JAVA_LONG) pthread_self();
126     destroyStackForExitingThread(nativeThreadId);
127 #endif
128 
129     // Unregister the current thread.  Only an explicitly registered
130     // thread (i.e. for which GC_register_my_thread() returns GC_SUCCESS)
131     // is allowed (and required) to call this function.  (As a special
132     // exception, it is also allowed to once unregister the main thread.)
133 #ifndef XMLVM_NO_GC
134     GC_unregister_my_thread();
135 #endif
136 
137     // Call pthread_exit(0) so that the main thread does not terminate until
138     // the other threads have finished
139     pthread_exit(0);
140 }
141 
142 /**
143  * Lock a mutex. If an error occurs, terminate the program.
144  */
lockOrExit(char * className,pthread_mutex_t * mut)145 static void lockOrExit(char* className, pthread_mutex_t* mut)
146 {
147     int result = pthread_mutex_lock(mut);
148     if (0 != result) {
149         printf("Error locking mutex in %s: %i\n", className, result);
150         exit(1);
151     }
152 //    else { printf("SUCCESSFUL mutex lock in %s\n", className); }
153 }
154 
155 /**
156  * Unlock a mutex. If an error occurs, terminate the program.
157  */
unlockOrExit(char * className,pthread_mutex_t * mut)158 static void unlockOrExit(char* className, pthread_mutex_t* mut)
159 {
160     int result = pthread_mutex_unlock(mut);
161     if (0 != result) {
162         printf("Error unlocking mutex in %s: %i\n", className, result);
163         exit(1);
164     }
165 //    else { printf("SUCCESSFUL mutex unlock in %s\n", className); }
166 }
167 
168 /**
169  * Lock the static initializer mutex.
170  */
staticInitializerLock(void * tibDefinition)171 void staticInitializerLock(void* tibDefinition)
172 {
173     char* className = ((struct __TIB_DEFINITION_TEMPLATE*)tibDefinition)->className;
174     lockOrExit(className, staticInitializerController->initMutex);
175 }
176 
177 /**
178  * Unlock the static initializer mutex.
179  */
staticInitializerUnlock(void * tibDefinition)180 void staticInitializerUnlock(void* tibDefinition)
181 {
182     char* className = ((struct __TIB_DEFINITION_TEMPLATE*)tibDefinition)->className;
183     unlockOrExit(className, staticInitializerController->initMutex);
184 }
185 
xmlvm_java_string_cmp(JAVA_OBJECT s1,const char * s2)186 int xmlvm_java_string_cmp(JAVA_OBJECT s1, const char* s2)
187 {
188     java_lang_String* str = (java_lang_String*) s1;
189     JAVA_INT len = str->fields.java_lang_String.count_;
190     if (len != strlen(s2)) {
191         return 0;
192     }
193     JAVA_INT offset = str->fields.java_lang_String.offset_;
194     org_xmlvm_runtime_XMLVMArray* value = (org_xmlvm_runtime_XMLVMArray*) str->fields.java_lang_String.value_;
195     JAVA_ARRAY_CHAR* valueArray = (JAVA_ARRAY_CHAR*) value->fields.org_xmlvm_runtime_XMLVMArray.array_;
196     for (int i = 0; i < len; i++) {
197         if (valueArray[i + offset] != s2[i]) {
198             return 0;
199         }
200     }
201     return 1;
202 }
203 
xmlvm_java_string_to_const_char(JAVA_OBJECT s)204 const char* xmlvm_java_string_to_const_char(JAVA_OBJECT s)
205 {
206     if (s == JAVA_NULL) {
207         return "null";
208     }
209     java_lang_String* str = (java_lang_String*) s;
210     JAVA_INT len = str->fields.java_lang_String.count_;
211     char* cs = XMLVM_ATOMIC_MALLOC(len + 1);
212     JAVA_INT offset = str->fields.java_lang_String.offset_;
213     org_xmlvm_runtime_XMLVMArray* value = (org_xmlvm_runtime_XMLVMArray*) str->fields.java_lang_String.value_;
214     JAVA_ARRAY_CHAR* valueArray = (JAVA_ARRAY_CHAR*) value->fields.org_xmlvm_runtime_XMLVMArray.array_;
215     int i = 0;
216     for (i = 0; i < len; i++) {
217         cs[i] = valueArray[i + offset];
218     }
219     cs[i] = '\0';
220     return cs;
221 }
222 
xmlvm_create_java_string(const char * s)223 JAVA_OBJECT xmlvm_create_java_string(const char* s)
224 {
225     java_lang_String* str = __NEW_java_lang_String();
226     org_xmlvm_runtime_XMLVMArray* charArray = XMLVMArray_createFromString(s);
227     java_lang_String___INIT____char_1ARRAY(str, charArray);
228     return XMLVMUtil_getFromStringPool(str);
229 }
230 
xmlvm_create_java_string_array(int count,const char ** s)231 JAVA_OBJECT xmlvm_create_java_string_array(int count, const char **s)
232 {
233     JAVA_OBJECT javaStrings[count];
234     for (int i = 0; i < count; i++) {
235         javaStrings[i] = xmlvm_create_java_string(s[i]);
236     }
237     JAVA_OBJECT javaStringArray = XMLVMArray_createSingleDimension(__CLASS_java_lang_String, count);
238     XMLVMArray_fillArray(javaStringArray, javaStrings);
239     return javaStringArray;
240 }
241 
242 static JAVA_OBJECT* stringConstants = JAVA_NULL;
243 
xmlvm_create_java_string_from_pool(int pool_id)244 JAVA_OBJECT xmlvm_create_java_string_from_pool(int pool_id)
245 {
246     if (stringConstants == JAVA_NULL) {
247         // TODO: use XMLVM_ATOMIC_MALLOC?
248         stringConstants = XMLVM_MALLOC(xmlvm_constant_pool_size * sizeof(JAVA_OBJECT));
249         XMLVM_BZERO(stringConstants, xmlvm_constant_pool_size * sizeof(JAVA_OBJECT));
250     }
251     if (stringConstants[pool_id] != JAVA_NULL) {
252         return stringConstants[pool_id];
253     }
254     java_lang_String* str = __NEW_java_lang_String();
255     org_xmlvm_runtime_XMLVMArray* charArray = XMLVMArray_createSingleDimensionWithData(__CLASS_char,
256                                                                                        xmlvm_constant_pool_length[pool_id],
257                                                                                        (JAVA_OBJECT) xmlvm_constant_pool_data[pool_id]);
258     java_lang_String___INIT____char_1ARRAY(str, charArray);
259     JAVA_OBJECT poolStr = XMLVMUtil_getFromStringPool(str);
260     stringConstants[pool_id] = poolStr;
261     return poolStr;
262 }
263 
xmlvm_clear_constant_pool_cache()264 void xmlvm_clear_constant_pool_cache()
265 {
266     XMLVM_BZERO(stringConstants, xmlvm_constant_pool_size * sizeof(JAVA_OBJECT));
267 }
268 
269 
270 //---------------------------------------------------------------------------------------------
271 // XMLVMClass
272 
XMLVM_CREATE_CLASS_OBJECT(void * tib)273 JAVA_OBJECT XMLVM_CREATE_CLASS_OBJECT(void* tib)
274 {
275     JAVA_OBJECT clazz = __NEW_java_lang_Class();
276     java_lang_Class___INIT____java_lang_Object(clazz, tib);
277     return clazz;
278 }
279 
280 
XMLVM_CREATE_ARRAY_CLASS_OBJECT(JAVA_OBJECT baseType)281 JAVA_OBJECT XMLVM_CREATE_ARRAY_CLASS_OBJECT(JAVA_OBJECT baseType)
282 {
283     __TIB_DEFINITION_org_xmlvm_runtime_XMLVMArray* tib = XMLVM_MALLOC(sizeof(__TIB_DEFINITION_org_xmlvm_runtime_XMLVMArray));
284     XMLVM_MEMCPY(tib, &__TIB_org_xmlvm_runtime_XMLVMArray, sizeof(__TIB_DEFINITION_org_xmlvm_runtime_XMLVMArray));
285     tib->flags = XMLVM_TYPE_ARRAY;
286     tib->baseType = baseType;
287     tib->arrayType = JAVA_NULL;
288     JAVA_OBJECT clazz = __NEW_java_lang_Class();
289     java_lang_Class___INIT____java_lang_Object(clazz, tib);
290     tib->clazz = clazz;
291     // Set the arrayType in in baseType to this newly created array type class
292     java_lang_Class* baseTypeClass = (java_lang_Class*) baseType;
293     __TIB_DEFINITION_TEMPLATE* baseTypeTIB = (__TIB_DEFINITION_TEMPLATE*) baseTypeClass->fields.java_lang_Class.tib_;
294     baseTypeTIB->arrayType = clazz;
295     return clazz;
296 }
297 
298 
XMLVM_ISA(JAVA_OBJECT obj,JAVA_OBJECT clazz)299 int XMLVM_ISA(JAVA_OBJECT obj, JAVA_OBJECT clazz)
300 {
301     if (obj == JAVA_NULL) {
302         return 0;
303     }
304 
305     int dimension_tib1 = 0;
306     int dimension_tib2 = 0;
307     __TIB_DEFINITION_TEMPLATE* tib1 = (__TIB_DEFINITION_TEMPLATE*) ((java_lang_Object*) obj)->tib;
308     __TIB_DEFINITION_TEMPLATE* tib2 = (__TIB_DEFINITION_TEMPLATE*) ((java_lang_Class*) clazz)->fields.java_lang_Class.tib_;
309 
310     if (tib1 == &__TIB_org_xmlvm_runtime_XMLVMArray) {
311         java_lang_Class* clazz = ((org_xmlvm_runtime_XMLVMArray*) obj)->fields.org_xmlvm_runtime_XMLVMArray.type_;
312         tib1 = clazz->fields.java_lang_Class.tib_;
313     }
314 
315     while (tib1->baseType != JAVA_NULL) {
316         tib1 = ((java_lang_Class*) tib1->baseType)->fields.java_lang_Class.tib_;
317         dimension_tib1++;
318     }
319 
320     while (tib2->baseType != JAVA_NULL) {
321         tib2 = ((java_lang_Class*) tib2->baseType)->fields.java_lang_Class.tib_;
322         dimension_tib2++;
323     }
324 
325     if (dimension_tib1 < dimension_tib2) {
326         return 0;
327     }
328 
329     while (tib1 != JAVA_NULL) {
330         if (tib1 == tib2) {
331             return 1;
332         }
333         // Check all implemented interfaces
334         int i;
335         for (i = 0; i < tib1->numImplementedInterfaces; i++) {
336             if (tib1->implementedInterfaces[0][i] == tib2) {
337                 return 1;
338             }
339         }
340         tib1 = tib1->extends;
341     }
342     return 0;
343 }
344 
345 //---------------------------------------------------------------------------------------------
346 // Stack traces
347 
348 #ifdef XMLVM_ENABLE_STACK_TRACES
349 
createStackForNewThread(JAVA_LONG threadId)350 void createStackForNewThread(JAVA_LONG threadId)
351 {
352     struct hash_struct *s = malloc(sizeof(struct hash_struct));
353     s->key = threadId;
354 
355     XMLVM_STACK_TRACE_CURRENT* newStack = malloc(sizeof(XMLVM_STACK_TRACE_CURRENT));
356     newStack->stackSize = 0;
357     newStack->topOfStack = NULL;
358 
359     s->value = newStack;
360     HASH_ADD_JAVA_LONG((struct hash_struct *)*threadToStackTraceMapPtr, key, s);
361 }
362 
destroyStackForExitingThread(JAVA_LONG threadId)363 void destroyStackForExitingThread(JAVA_LONG threadId)
364 {
365     struct hash_struct *s;
366     HASH_FIND_JAVA_LONG((struct hash_struct *)*threadToStackTraceMapPtr, &threadId, s);
367     if (s == NULL) {
368         printf("ERROR: Unable to destroy stack trace for exiting thread!\n");
369         exit(-1);
370     } else {
371         HASH_DEL((struct hash_struct *)*threadToStackTraceMapPtr, s);
372         free(s->value);
373         free(s);
374     }
375 }
376 
getCurrentStackTrace()377 XMLVM_STACK_TRACE_CURRENT* getCurrentStackTrace()
378 {
379 	JAVA_LONG currentThreadId = (JAVA_LONG)pthread_self();
380     struct hash_struct *s;
381     HASH_FIND_JAVA_LONG((struct hash_struct *)*threadToStackTraceMapPtr, &currentThreadId, s);
382     if (s == NULL) {
383         printf("ERROR: Unable to find stack trace for current thread!\n");
384         exit(-1);
385     }
386     return (XMLVM_STACK_TRACE_CURRENT*)s->value;
387 }
388 
xmlvmEnterMethod(XMLVM_STACK_TRACE_CURRENT * threadStack,const char * className,const char * methodName,const char * fileName)389 void xmlvmEnterMethod(XMLVM_STACK_TRACE_CURRENT* threadStack, const char* className, const char* methodName, const char* fileName)
390 {
391     //printf("Entering method %s\n", className);
392 
393     XMLVM_STACK_TRACE_ELEMENT* newLocationElement = malloc(sizeof(XMLVM_STACK_TRACE_ELEMENT));
394     newLocationElement->className = className;
395     newLocationElement->methodName = methodName;
396     newLocationElement->fileName = fileName;
397     newLocationElement->lineNumber = -2;
398 
399     XMLVM_STACK_TRACE_LINK* link = malloc(sizeof(XMLVM_STACK_TRACE_LINK));
400     link->nextLink = threadStack->topOfStack;
401     if (threadStack->topOfStack != NULL) {
402         link->element = threadStack->topOfStack->currentLocation;
403     }
404     link->currentLocation = newLocationElement;
405 
406     // Push what was the current location onto the stack and set the new current location
407     threadStack->stackSize++;
408     threadStack->topOfStack = link;
409 }
410 
xmlvmSourcePosition(XMLVM_STACK_TRACE_CURRENT * threadStack,const char * fileName,int lineNumber)411 void xmlvmSourcePosition(XMLVM_STACK_TRACE_CURRENT* threadStack, const char* fileName, int lineNumber)
412 {
413     //printf("Source position update %i\n", lineNumber);
414 
415     threadStack->topOfStack->currentLocation->fileName = fileName;
416     threadStack->topOfStack->currentLocation->lineNumber = lineNumber;
417 }
418 
xmlvmExitMethod(XMLVM_STACK_TRACE_CURRENT * threadStack)419 void xmlvmExitMethod(XMLVM_STACK_TRACE_CURRENT* threadStack)
420 {
421     //printf("Exiting method\n");
422 
423     XMLVM_STACK_TRACE_LINK* linkToDestroy = threadStack->topOfStack;
424     threadStack->topOfStack = linkToDestroy->nextLink;
425     threadStack->stackSize--;
426 
427     free(linkToDestroy->currentLocation);
428     free(linkToDestroy);
429 }
430 
xmlvmUnwindException(XMLVM_STACK_TRACE_CURRENT * threadStack,int unwindToStackSize)431 void xmlvmUnwindException(XMLVM_STACK_TRACE_CURRENT* threadStack, int unwindToStackSize)
432 {
433     while (unwindToStackSize + 1 < threadStack->stackSize) {
434         //printf("Unwinding stack after catching an exception: %i > %i\n", unwindToStackSize, threadStack->stackSize);
435         xmlvmExitMethod(threadStack);
436     }
437 }
438 
439 #endif
440 
441 
442 #ifdef XMLVM_ENABLE_CLASS_LOGGING
443 //---------------------------------------------------------------------------------------------
444 // Reflection/Class Usage logging
445 
446 FILE *logFile    = 0;
447 int   useLogging = 1;
448 
xmlvmClassUsed(const char * prefix,const char * className)449 void xmlvmClassUsed(const char *prefix, const char *className) {
450 	if (useLogging && (logFile == 0)) {
451 		logFile = fopen("touched_classes.txt", "w");
452 	}
453 	if (useLogging && (logFile != 0)) {
454 		fprintf(logFile, "%s:%s\n", prefix, className);
455 	} else {
456 		useLogging = 0; // Failed to open file, so stop
457 	}
458 }
459 
460 #endif
461 
462 //---------------------------------------------------------------------------------------------
463 // XMLVMArray
464 
465 
XMLVMArray_createSingleDimension(JAVA_OBJECT type,JAVA_INT size)466 JAVA_OBJECT XMLVMArray_createSingleDimension(JAVA_OBJECT type, JAVA_INT size)
467 {
468     return org_xmlvm_runtime_XMLVMArray_createSingleDimension___java_lang_Class_int(type, size);
469 }
470 
XMLVMArray_createSingleDimensionWithData(JAVA_OBJECT type,JAVA_INT size,JAVA_OBJECT data)471 JAVA_OBJECT XMLVMArray_createSingleDimensionWithData(JAVA_OBJECT type, JAVA_INT size, JAVA_OBJECT data)
472 {
473     return org_xmlvm_runtime_XMLVMArray_createSingleDimensionWithData___java_lang_Class_int_java_lang_Object(type, size, data);
474 }
475 
476 
XMLVMArray_createMultiDimensions(JAVA_OBJECT type,JAVA_OBJECT dimensions)477 JAVA_OBJECT XMLVMArray_createMultiDimensions(JAVA_OBJECT type, JAVA_OBJECT dimensions)
478 {
479     return org_xmlvm_runtime_XMLVMArray_createMultiDimensions___java_lang_Class_org_xmlvm_runtime_XMLVMArray(type, dimensions);
480 }
481 
XMLVMArray_createFromString(const char * str)482 JAVA_OBJECT XMLVMArray_createFromString(const char* str)
483 {
484     int len = strlen(str);
485     int size = len * sizeof(JAVA_ARRAY_CHAR);
486     int i;
487     JAVA_ARRAY_CHAR* data = XMLVM_ATOMIC_MALLOC(size);
488     for (i = 0; i < len; i++) {
489         data[i] = *str++;
490     }
491     return XMLVMArray_createSingleDimensionWithData(__CLASS_char, len, data);
492 }
493 
XMLVMArray_fillArray(JAVA_OBJECT array,void * data)494 void XMLVMArray_fillArray(JAVA_OBJECT array, void* data)
495 {
496     org_xmlvm_runtime_XMLVMArray_fillArray___org_xmlvm_runtime_XMLVMArray_java_lang_Object(array, data);
497 }
498 
XMLVMArray_count(JAVA_OBJECT array)499 int XMLVMArray_count(JAVA_OBJECT array)
500 {
501     org_xmlvm_runtime_XMLVMArray* a = (org_xmlvm_runtime_XMLVMArray*) array;
502     return a->fields.org_xmlvm_runtime_XMLVMArray.length_;
503 }
504 
xmlvm_unhandled_exception()505 void xmlvm_unhandled_exception()
506 {
507     java_lang_Thread* curThread;
508     curThread = (java_lang_Thread*) java_lang_Thread_currentThread__();
509     JAVA_OBJECT exception = curThread->fields.java_lang_Thread.xmlvmException_;
510 
511     JAVA_OBJECT thread_name;
512 #ifdef XMLVM_VTABLE_IDX_java_lang_Thread_getName__
513     thread_name =  ((Func_OO) ((java_lang_Thread*) curThread)->tib->vtable[XMLVM_VTABLE_IDX_java_lang_Thread_getName__])(curThread);
514 #else
515     thread_name = java_lang_Thread_getName__(curThread);
516 #endif
517 
518 #ifdef XMLVM_ENABLE_STACK_TRACES
519 
520     printf("Exception in thread \"%s\" ",
521             xmlvm_java_string_to_const_char(thread_name));
522     java_lang_Throwable_printStackTrace__(exception);
523 
524 #else
525 
526     JAVA_OBJECT message;
527 #ifdef XMLVM_VTABLE_IDX_java_lang_Throwable_getMessage__
528     message = ((Func_OO) ((java_lang_Throwable*) exception)->tib->vtable[XMLVM_VTABLE_IDX_java_lang_Throwable_getMessage__])(exception);
529 #else
530     message = java_lang_Throwable_getMessage__(exception);
531 #endif
532 
533     JAVA_OBJECT exception_class;
534 #ifdef XMLVM_VTABLE_IDX_java_lang_Object_getClass__
535     exception_class = ((Func_OO) ((java_lang_Object*) exception)->tib->vtable[XMLVM_VTABLE_IDX_java_lang_Object_getClass__])(exception);
536 #else
537     exception_class = java_lang_Object_getClass__(exception);
538 #endif
539 
540     JAVA_OBJECT class_name;
541 #ifdef XMLVM_VTABLE_IDX_java_lang_Class_getName__
542     class_name = ((Func_OO) ((java_lang_Class*) exception_class)->tib->vtable[XMLVM_VTABLE_IDX_java_lang_Class_getName__])(exception_class);
543 #else
544     class_name = java_lang_Class_getName__(exception_class);
545 #endif
546 
547     printf("Exception in thread \"%s\" %s: %s\n",
548             xmlvm_java_string_to_const_char(thread_name),
549             xmlvm_java_string_to_const_char(class_name),
550             xmlvm_java_string_to_const_char(message));
551 
552 #endif
553 }
554 
xmlvm_unimplemented_native_method()555 void xmlvm_unimplemented_native_method()
556 {
557     XMLVM_ERROR("Unimplemented native method", __FILE__, __FUNCTION__, __LINE__);
558 }
559 
XMLVM_ERROR(const char * msg,const char * file,const char * function,int line)560 void XMLVM_ERROR(const char* msg, const char* file, const char* function, int line)
561 {
562     printf("XMLVM Error: %s: (%s):%s:%d\n", msg, function, file, line);
563     exit(-1);
564 }
565 
566