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, ¤tThreadId, 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