added Changes: Edwin Steiner to exceptions.[ch]
[cacao.git] / src / vm / exceptions.c
1 /* src/vm/exceptions.c - exception related functions
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Christian Thalinger
28
29    Changes: Edwin Steiner
30
31    $Id: exceptions.c 3466 2005-10-20 10:42:12Z edwin $
32
33 */
34
35
36 #include <string.h>
37 #include <stdarg.h>
38 #include <stdlib.h>
39
40 #include "config.h"
41
42 #include "mm/memory.h"
43 #include "native/native.h"
44 #include "native/include/java_lang_String.h"
45 #include "native/include/java_lang_Throwable.h"
46 #include "toolbox/logging.h"
47 #include "toolbox/util.h"
48 #include "vm/class.h"
49 #include "vm/exceptions.h"
50 #include "vm/global.h"
51 #include "vm/loader.h"
52 #include "vm/options.h"
53 #include "vm/stringlocal.h"
54 #include "vm/tables.h"
55 #include "vm/jit/asmpart.h"
56 #include "vm/jit/jit.h"
57
58
59 /* for raising exceptions from native methods *********************************/
60
61 #if !defined(USE_THREADS) || !defined(NATIVE_THREADS)
62 java_objectheader *_no_threads_exceptionptr = NULL;
63 #endif
64
65
66 /* init_system_exceptions ******************************************************
67
68    Load and link exceptions used in the system.
69
70 *******************************************************************************/
71
72 bool exceptions_init(void)
73 {
74         /* java/lang/Throwable */
75
76         if (!(class_java_lang_Throwable =
77                   load_class_bootstrap(utf_java_lang_Throwable)) ||
78                 !link_class(class_java_lang_Throwable))
79                 return false;
80
81
82         /* java/lang/VMThrowable */
83
84         if (!(class_java_lang_VMThrowable =
85                   load_class_bootstrap(utf_java_lang_VMThrowable)) ||
86                 !link_class(class_java_lang_VMThrowable))
87                 return false;
88
89
90         /* java/lang/Error */
91
92         if (!(class_java_lang_Error = load_class_bootstrap(utf_java_lang_Error)) ||
93                 !link_class(class_java_lang_Error))
94                 return false;
95
96         /* java/lang/NoClassDefFoundError */
97
98         if (!(class_java_lang_NoClassDefFoundError =
99                   load_class_bootstrap(utf_java_lang_NoClassDefFoundError)) ||
100                 !link_class(class_java_lang_NoClassDefFoundError))
101                 return false;
102
103         /* java/lang/OutOfMemoryError */
104
105         if (!(class_java_lang_OutOfMemoryError =
106                   load_class_bootstrap(utf_java_lang_OutOfMemoryError)) ||
107                 !link_class(class_java_lang_OutOfMemoryError))
108                 return false;
109
110
111         /* java/lang/Exception */
112
113         if (!(class_java_lang_Exception =
114                   load_class_bootstrap(utf_java_lang_Exception)) ||
115                 !link_class(class_java_lang_Exception))
116                 return false;
117
118         /* java/lang/ClassNotFoundException */
119
120         if (!(class_java_lang_ClassNotFoundException =
121                   load_class_bootstrap(utf_java_lang_ClassNotFoundException)) ||
122                 !link_class(class_java_lang_ClassNotFoundException))
123                 return false;
124
125         /* java/lang/IllegalArgumentException */
126
127         if (!(class_java_lang_IllegalArgumentException =
128                   load_class_bootstrap(utf_java_lang_IllegalArgumentException)) ||
129                 !link_class(class_java_lang_IllegalArgumentException))
130                 return false;
131
132
133         return true;
134 }
135
136
137 static void throw_exception_exit_intern(bool doexit)
138 {
139         java_objectheader *xptr;
140         classinfo *c;
141         methodinfo *pss;
142
143         xptr = *exceptionptr;
144
145         if (xptr) {
146                 /* clear exception, because we are calling jit code again */
147                 *exceptionptr = NULL;
148
149                 c = xptr->vftbl->class;
150
151                 pss = class_resolveclassmethod(c,
152                                                                            utf_printStackTrace,
153                                                                            utf_void__void,
154                                                                            class_java_lang_Object,
155                                                                            false);
156
157                 /* print the stacktrace */
158                 if (pss) {
159                         asm_calljavafunction(pss, xptr, NULL, NULL, NULL);
160
161                         /* This normally means, we are EXTREMLY out of memory or have a   */
162                         /* serious problem while printStackTrace. But may be another      */
163                         /* exception, so print it.                                        */
164
165                         if (*exceptionptr) {
166                                 java_lang_Throwable *t;
167
168                                 t = (java_lang_Throwable *) *exceptionptr;
169
170                                 fprintf(stderr, "Exception while printStackTrace(): ");
171                                 utf_fprint_classname(stderr, t->header.vftbl->class->name);
172
173                                 if (t->detailMessage) {
174                                         char *buf;
175
176                                         buf = javastring_tochar((java_objectheader *) t->detailMessage);
177                                         fprintf(stderr, ": %s", buf);
178                                         MFREE(buf, char, strlen(buf));
179                                 }
180                                         
181                                 fprintf(stderr, "\n");
182                         }
183
184                 } else {
185                         utf_fprint_classname(stderr, c->name);
186                         fprintf(stderr, ": printStackTrace()V not found!\n");
187                 }
188
189                 fflush(stderr);
190
191                 /* good bye! */
192
193                 if (doexit)
194                         exit(1);
195         }
196 }
197
198
199 void throw_exception(void)
200 {
201         throw_exception_exit_intern(false);
202 }
203
204
205 void throw_exception_exit(void)
206 {
207         throw_exception_exit_intern(true);
208 }
209
210
211 void throw_main_exception(void)
212 {
213         fprintf(stderr, "Exception in thread \"main\" ");
214         fflush(stderr);
215
216         throw_exception_exit_intern(false);
217 }
218
219
220 void throw_main_exception_exit(void)
221 {
222         fprintf(stderr, "Exception in thread \"main\" ");
223         fflush(stderr);
224
225         throw_exception_exit_intern(true);
226 }
227
228
229 void throw_cacao_exception_exit(const char *exception, const char *message, ...)
230 {
231         s4 i;
232         char *tmp;
233         s4 len;
234         va_list ap;
235
236         len = strlen(exception);
237         tmp = MNEW(char, len + 1);
238         strncpy(tmp, exception, len);
239         tmp[len] = '\0';
240
241         /* convert to classname */
242
243         for (i = len - 1; i >= 0; i--)
244                 if (tmp[i] == '/') tmp[i] = '.';
245
246         fprintf(stderr, "Exception in thread \"main\" %s", tmp);
247
248         MFREE(tmp, char, len);
249
250         if (strlen(message) > 0) {
251                 fprintf(stderr, ": ");
252
253                 va_start(ap, message);
254                 vfprintf(stderr, message, ap);
255                 va_end(ap);
256         }
257
258         fprintf(stderr, "\n");
259         fflush(stderr);
260
261         /* good bye! */
262
263         exit(1);
264 }
265
266
267 /* new_exception ***************************************************************
268
269    Creates an exception object with the given name and initalizes it.
270
271 *******************************************************************************/
272
273 java_objectheader *new_exception(const char *classname)
274 {
275         java_objectheader *o;
276         classinfo         *c;
277
278         if (!(c = load_class_bootstrap(utf_new_char(classname))))
279                 return *exceptionptr;
280
281         o = native_new_and_init(c);
282
283         if (!o)
284                 return *exceptionptr;
285
286         return o;
287 }
288
289
290 /* new_exception_message *******************************************************
291
292    Creates an exception object with the given name and initalizes it
293    with the given char message.
294
295 *******************************************************************************/
296
297 java_objectheader *new_exception_message(const char *classname,
298                                                                                  const char *message)
299 {
300         java_objectheader *o;
301         classinfo         *c;
302    
303         if (!(c = load_class_bootstrap(utf_new_char(classname))))
304                 return *exceptionptr;
305
306         o = native_new_and_init_string(c, javastring_new_char(message));
307
308         if (!o)
309                 return *exceptionptr;
310
311         return o;
312 }
313
314
315 /* new_exception_throwable *****************************************************
316
317    Creates an exception object with the given name and initalizes it
318    with the given java/lang/Throwable exception.
319
320 *******************************************************************************/
321
322 java_objectheader *new_exception_throwable(const char *classname,
323                                                                                    java_lang_Throwable *throwable)
324 {
325         java_objectheader *o;
326         classinfo         *c;
327    
328         if (!(c = load_class_bootstrap(utf_new_char(classname))))
329                 return *exceptionptr;
330
331         o = native_new_and_init_throwable(c, throwable);
332
333         if (!o)
334                 return *exceptionptr;
335
336         return o;
337 }
338
339
340 /* new_exception_utfmessage ****************************************************
341
342    Creates an exception object with the given name and initalizes it
343    with the given utf message.
344
345 *******************************************************************************/
346
347 java_objectheader *new_exception_utfmessage(const char *classname, utf *message)
348 {
349         java_objectheader *o;
350         classinfo         *c;
351    
352         if (!(c = load_class_bootstrap(utf_new_char(classname))))
353                 return *exceptionptr;
354
355         o = native_new_and_init_string(c, javastring_new(message));
356
357         if (!o)
358                 return *exceptionptr;
359
360         return o;
361 }
362
363
364 /* new_exception_javastring ****************************************************
365
366    Creates an exception object with the given name and initalizes it
367    with the given java/lang/String message.
368
369 *******************************************************************************/
370
371 java_objectheader *new_exception_javastring(const char *classname,
372                                                                                         java_lang_String *message)
373 {
374         java_objectheader *o;
375         classinfo         *c;
376    
377         if (!(c = load_class_bootstrap(utf_new_char(classname))))
378                 return *exceptionptr;
379
380         o = native_new_and_init_string(c, message);
381
382         if (!o)
383                 return *exceptionptr;
384
385         return o;
386 }
387
388
389 /* new_exception_int ***********************************************************
390
391    Creates an exception object with the given name and initalizes it
392    with the given int value.
393
394 *******************************************************************************/
395
396 java_objectheader *new_exception_int(const char *classname, s4 i)
397 {
398         java_objectheader *o;
399         classinfo         *c;
400    
401         if (!(c = load_class_bootstrap(utf_new_char(classname))))
402                 return *exceptionptr;
403
404         o = native_new_and_init_int(c, i);
405
406         if (!o)
407                 return *exceptionptr;
408
409         return o;
410 }
411
412
413 /* new_classformaterror ********************************************************
414
415    generates a java.lang.ClassFormatError for the classloader
416
417 *******************************************************************************/
418
419 java_objectheader *new_classformaterror(classinfo *c, const char *message, ...)
420 {
421         java_objectheader *o;
422         char              *msg;
423         s4                 msglen;
424         va_list            ap;
425
426         /* calculate message length */
427
428         msglen = 0;
429
430         if (c)
431                 msglen += utf_strlen(c->name) + strlen(" (");
432
433         va_start(ap, message);
434         msglen += get_variable_message_length(message, ap);
435         va_end(ap);
436
437         if (c)
438                 msglen += strlen(")");
439
440         msglen += strlen("0");
441
442         /* allocate a buffer */
443
444         msg = MNEW(char, msglen);
445
446         /* print message into allocated buffer */
447
448         if (c) {
449                 utf_sprint_classname(msg, c->name);
450                 strcat(msg, " (");
451         }
452
453         va_start(ap, message);
454         vsprintf(msg + strlen(msg), message, ap);
455         va_end(ap);
456
457         if (c)
458                 strcat(msg, ")");
459
460         o = new_exception_message(string_java_lang_ClassFormatError, msg);
461
462         MFREE(msg, char, msglen);
463
464         return o;
465 }
466
467
468 /* new_classnotfoundexception **************************************************
469
470    Generates a java.lang.ClassNotFoundException for the classloader.
471
472 *******************************************************************************/
473
474 java_objectheader *new_classnotfoundexception(utf *name)
475 {
476         java_objectheader *o;
477
478         o = native_new_and_init_string(class_java_lang_ClassNotFoundException,
479                                                                    javastring_new(name));
480
481         if (!o)
482                 return *exceptionptr;
483
484         return o;
485 }
486
487
488 /* new_noclassdeffounderror ****************************************************
489
490    Generates a java.lang.NoClassDefFoundError
491
492 *******************************************************************************/
493
494 java_objectheader *new_noclassdeffounderror(utf *name)
495 {
496         java_objectheader *o;
497
498         o = native_new_and_init_string(class_java_lang_NoClassDefFoundError,
499                                                                    javastring_new(name));
500
501         if (!o)
502                 return *exceptionptr;
503
504         return o;
505 }
506
507
508 /* classnotfoundexception_to_noclassdeffounderror ******************************
509
510    Check the *exceptionptr for a ClassNotFoundException. If it is one,
511    convert it to a NoClassDefFoundError.
512
513 *******************************************************************************/
514
515 void classnotfoundexception_to_noclassdeffounderror(void)
516 {
517         java_objectheader *xptr;
518         java_objectheader *cause;
519
520         /* get the cause */
521
522         cause = *exceptionptr;
523
524         /* convert ClassNotFoundException's to NoClassDefFoundError's */
525
526         if (builtin_instanceof(cause, class_java_lang_ClassNotFoundException)) {
527                 /* clear exception, because we are calling jit code again */
528
529                 *exceptionptr = NULL;
530
531                 /* create new error */
532
533                 xptr =
534                         new_exception_javastring(string_java_lang_NoClassDefFoundError,
535                                         ((java_lang_Throwable *) cause)->detailMessage);
536
537                 /* we had an exception while creating the error */
538
539                 if (*exceptionptr)
540                         return;
541
542                 /* set new exception */
543
544                 *exceptionptr = xptr;
545         }
546 }
547
548
549 /* new_internalerror ***********************************************************
550
551    Generates a java.lang.InternalError for the VM.
552
553 *******************************************************************************/
554
555 java_objectheader *new_internalerror(const char *message, ...)
556 {
557         java_objectheader *o;
558         va_list            ap;
559         char              *msg;
560         s4                 msglen;
561
562         /* calculate exception message length */
563
564         va_start(ap, message);
565         msglen = get_variable_message_length(message, ap);
566         va_end(ap);
567
568         /* allocate memory */
569
570         msg = MNEW(char, msglen);
571
572         /* generate message */
573
574         va_start(ap, message);
575         vsprintf(msg, message, ap);
576         va_end(ap);
577
578         /* create exception object */
579
580         o = new_exception_message(string_java_lang_InternalError, msg);
581
582         /* free memory */
583
584         MFREE(msg, char, msglen);
585
586         return o;
587 }
588
589
590 /* new_unsupportedclassversionerror ********************************************
591
592    generates a java.lang.UnsupportedClassVersionError for the classloader
593
594 *******************************************************************************/
595
596 java_objectheader *new_unsupportedclassversionerror(classinfo *c, const char *message, ...)
597 {
598         java_objectheader *o;
599         va_list            ap;
600         char              *msg;
601     s4                 msglen;
602
603         /* calculate exception message length */
604
605         msglen = utf_strlen(c->name) + strlen(" (") + strlen(")") + strlen("0");
606
607         va_start(ap, message);
608         msglen += get_variable_message_length(message, ap);
609         va_end(ap);
610
611         /* allocate memory */
612
613         msg = MNEW(char, msglen);
614
615         /* generate message */
616
617         utf_sprint_classname(msg, c->name);
618         strcat(msg, " (");
619
620         va_start(ap, message);
621         vsprintf(msg + strlen(msg), message, ap);
622         va_end(ap);
623
624         strcat(msg, ")");
625
626         /* create exception object */
627
628         o = new_exception_message(string_java_lang_UnsupportedClassVersionError,
629                                                           msg);
630
631         /* free memory */
632
633         MFREE(msg, char, msglen);
634
635         return o;
636 }
637
638
639 /* new_verifyerror *************************************************************
640
641    generates a java.lang.VerifyError for the jit compiler
642
643 *******************************************************************************/
644
645 java_objectheader *new_verifyerror(methodinfo *m, const char *message, ...)
646 {
647         java_objectheader *o;
648         va_list            ap;
649         char              *msg;
650         s4                 msglen;
651
652         useinlining = false; /* at least until sure inlining works with exceptions*/
653
654         /* calculate exception message length */
655
656         msglen = strlen("(class: ") + utf_strlen(m->class->name) +
657                 strlen(", method: ") + utf_strlen(m->name) +
658                 strlen(" signature: ") + utf_strlen(m->descriptor) +
659                 strlen(") ") + strlen("0");
660
661         va_start(ap, message);
662         msglen += get_variable_message_length(message, ap);
663         va_end(ap);
664
665         /* allocate memory */
666
667         msg = MNEW(char, msglen);
668
669         /* generate message */
670
671         strcpy(msg, "(class: ");
672         utf_strcat(msg, m->class->name);
673         strcat(msg, ", method: ");
674         utf_strcat(msg, m->name);
675         strcat(msg, " signature: ");
676         utf_strcat(msg, m->descriptor);
677         strcat(msg, ") ");
678
679         va_start(ap, message);
680         vsprintf(msg + strlen(msg), message, ap);
681         va_end(ap);
682
683         /* create exception object */
684
685         o = new_exception_message(string_java_lang_VerifyError, msg);
686
687         /* free memory */
688
689         MFREE(msg, char, msglen);
690
691         return o;
692 }
693
694
695 /* new_arithmeticexception *****************************************************
696
697    Generates a java.lang.ArithmeticException for the jit compiler.
698
699 *******************************************************************************/
700
701 java_objectheader *new_arithmeticexception(void)
702 {
703         java_objectheader *e;
704
705         e = new_exception_message(string_java_lang_ArithmeticException,
706                                                           string_java_lang_ArithmeticException_message);
707
708         if (!e)
709                 return *exceptionptr;
710
711         return e;
712 }
713
714
715 /* new_arrayindexoutofboundsexception ******************************************
716
717    Generates a java.lang.ArrayIndexOutOfBoundsException for the JIT
718    compiler.
719
720 *******************************************************************************/
721
722 java_objectheader *new_arrayindexoutofboundsexception(s4 index)
723 {
724         java_objectheader *e;
725         methodinfo *m;
726         java_lang_String *s;
727
728         /* convert the index into a String, like Sun does */
729
730         m = class_resolveclassmethod(class_java_lang_String,
731                                                                  utf_new_char("valueOf"),
732                                                                  utf_new_char("(I)Ljava/lang/String;"),
733                                                                  class_java_lang_Object,
734                                                                  true);
735
736         if (!m)
737                 return *exceptionptr;
738
739         s = (java_lang_String *) asm_calljavafunction(m,
740                                                                                                   (void *) (ptrint) index,
741                                                                                                   NULL,
742                                                                                                   NULL,
743                                                                                                   NULL);
744
745         if (!s)
746                 return *exceptionptr;
747
748         e = new_exception_javastring(string_java_lang_ArrayIndexOutOfBoundsException,
749                                                                  s);
750
751         if (!e)
752                 return *exceptionptr;
753
754         return e;
755 }
756
757
758 /* new_arraystoreexception *****************************************************
759
760    generates a java.lang.ArrayStoreException for the jit compiler
761
762 *******************************************************************************/
763
764 java_objectheader *new_arraystoreexception(void)
765 {
766         java_objectheader *e;
767
768         e = new_exception(string_java_lang_ArrayStoreException);
769
770         if (!e)
771                 return *exceptionptr;
772
773         return e;
774 }
775
776
777 /* new_classcastexception ******************************************************
778
779    generates a java.lang.ClassCastException for the jit compiler
780
781 *******************************************************************************/
782
783 java_objectheader *new_classcastexception(void)
784 {
785         java_objectheader *e;
786
787         e = new_exception(string_java_lang_ClassCastException);
788
789         if (!e)
790                 return *exceptionptr;
791
792         return e;
793 }
794
795
796 /* new_illegalargumentexception ************************************************
797
798    Generates a java.lang.IllegalArgumentException for the VM system.
799
800 *******************************************************************************/
801
802 java_objectheader *new_illegalargumentexception(void)
803 {
804         java_objectheader *e;
805
806         if (!(e = native_new_and_init(class_java_lang_IllegalArgumentException)))
807                 return *exceptionptr;
808
809         return e;
810 }
811
812
813 /* new_negativearraysizeexception **********************************************
814
815    generates a java.lang.NegativeArraySizeException for the jit compiler
816
817 *******************************************************************************/
818
819 java_objectheader *new_negativearraysizeexception(void)
820 {
821         java_objectheader *e;
822
823         e = new_exception(string_java_lang_NegativeArraySizeException);
824
825         if (!e)
826                 return *exceptionptr;
827
828         return e;
829 }
830
831
832 /* new_nullpointerexception ****************************************************
833
834    generates a java.lang.NullPointerException for the jit compiler
835
836 *******************************************************************************/
837
838 java_objectheader *new_nullpointerexception(void)
839 {
840         java_objectheader *e;
841
842         e = new_exception(string_java_lang_NullPointerException);
843
844         if (!e)
845                 return *exceptionptr;
846
847         return e;
848 }
849
850
851 /*
852  * These are local overrides for various environment variables in Emacs.
853  * Please do not remove this and leave it at the end of the file, where
854  * Emacs will automagically detect them.
855  * ---------------------------------------------------------------------
856  * Local variables:
857  * mode: c
858  * indent-tabs-mode: t
859  * c-basic-offset: 4
860  * tab-width: 4
861  * End:
862  */