* src/vm/linker.c (link_class_intern): Handle miranda methods
[cacao.git] / src / native / vm / VMClass.c
1 /* src/native/vm/VMClass.c - java/lang/VMClass
2
3    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, 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., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Roman Obermaiser
28
29    Changes: Joseph Wenninger
30             Christian Thalinger
31                         Edwin Steiner
32
33    $Id: VMClass.c 4551 2006-03-03 00:00:39Z twisti $
34
35 */
36
37
38 #include "config.h"
39
40 #include <assert.h>
41 #include <string.h>
42
43 #include "vm/types.h"
44
45 #include "mm/memory.h"
46 #include "native/jni.h"
47 #include "native/native.h"
48 #include "native/include/java_lang_Class.h"
49 #include "native/include/java_lang_ClassLoader.h"
50 #include "native/include/java_lang_Object.h"
51 #include "native/include/java_lang_VMClass.h"
52 #include "native/include/java_lang_reflect_Constructor.h"
53 #include "native/include/java_lang_reflect_Field.h"
54 #include "native/include/java_lang_reflect_Method.h"
55 #include "native/include/java_security_ProtectionDomain.h"
56 #include "toolbox/logging.h"
57 #include "vm/builtin.h"
58 #include "vm/exceptions.h"
59 #include "vm/global.h"
60 #include "vm/initialize.h"
61 #include "vm/loader.h"
62 #include "vm/resolve.h"
63 #include "vm/stringlocal.h"
64
65
66 /*
67  * Class:     java/lang/VMClass
68  * Method:    forName
69  * Signature: (Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;
70  */
71 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClass_forName(JNIEnv *env, jclass clazz, java_lang_String *name, s4 initialize, java_lang_ClassLoader *loader)
72 {
73         classinfo *c;
74         utf       *u;
75         u2        *pos;
76         s4         i;
77
78         /* illegal argument */
79
80         if (!name)
81                 return NULL;
82
83         /* name must not contain '/' (mauve test) */
84
85         for (i = 0, pos = name->value->data + name->offset; i < name->count; i++, pos++) {
86                 if (*pos == '/') {
87                         *exceptionptr =
88                                 new_exception_javastring(string_java_lang_ClassNotFoundException, name);
89                         return NULL;
90                 }
91         }
92
93         /* create utf string in which '.' is replaced by '/' */
94
95         u = javastring_toutf(name, true);
96
97         /* try to load, ... */
98
99         if (!(c = load_class_from_classloader(u, (java_objectheader *) loader))) {
100                 classinfo *xclass;
101
102                 xclass = (*exceptionptr)->vftbl->class;
103
104                 /* if the exception is a NoClassDefFoundError, we replace it with a
105                    ClassNotFoundException, otherwise return the exception */
106
107                 if (xclass == class_java_lang_NoClassDefFoundError) {
108                         /* clear exceptionptr, because builtin_new checks for 
109                            ExceptionInInitializerError */
110                         *exceptionptr = NULL;
111
112                         *exceptionptr =
113                                 new_exception_javastring(string_java_lang_ClassNotFoundException, name);
114                 }
115
116             return NULL;
117         }
118
119         /* link, ... */
120
121         if (!link_class(c))
122                 return NULL;
123         
124         /* ...and initialize it, if required */
125
126         if (initialize)
127                 if (!initialize_class(c))
128                         return NULL;
129
130         return (java_lang_Class *) c;
131 }
132
133
134 /*
135  * Class:     java/lang/VMClass
136  * Method:    getClassLoader
137  * Signature: ()Ljava/lang/ClassLoader;
138  */
139 JNIEXPORT java_lang_ClassLoader* JNICALL Java_java_lang_VMClass_getClassLoader(JNIEnv *env, jclass clazz, java_lang_Class *klass)
140 {
141         classinfo *c;
142
143         c = (classinfo *) klass;
144
145         return (java_lang_ClassLoader *) c->classloader;
146 }
147
148
149 /*
150  * Class:     java/lang/VMClass
151  * Method:    getComponentType
152  * Signature: ()Ljava/lang/Class;
153  */
154 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClass_getComponentType(JNIEnv *env, jclass clazz, java_lang_Class *klass)
155 {
156         classinfo       *c;
157         classinfo       *comp;
158         arraydescriptor *desc;
159         
160         c = (classinfo *) klass;
161         desc = c->vftbl->arraydesc;
162         
163         if (desc == NULL)
164                 return NULL;
165         
166         if (desc->arraytype == ARRAYTYPE_OBJECT)
167                 comp = desc->componentvftbl->class;
168         else
169                 comp = primitivetype_table[desc->arraytype].class_primitive;
170                 
171         return (java_lang_Class *) comp;
172 }
173
174
175 /*
176  * Class:     java/lang/VMClass
177  * Method:    getDeclaredConstructors
178  * Signature: (Z)[Ljava/lang/reflect/Constructor;
179  */
180 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMClass_getDeclaredConstructors(JNIEnv *env, jclass clazz, java_lang_Class *klass, s4 publicOnly)
181 {
182         classinfo                     *c;
183         methodinfo                    *m; /* the current method to be represented */
184         java_objectarray              *oa;     /* result: array of Method-objects */
185         java_objectheader             *o;
186         java_lang_reflect_Constructor *rc;
187         s4 public_methods;               /* number of public methods of the class */
188         s4 pos;
189         s4 i;
190
191         c = (classinfo *) klass;
192
193         /* determine number of constructors */
194
195         for (i = 0, public_methods = 0; i < c->methodscount; i++) {
196                 m = &c->methods[i];
197
198                 if (((m->flags & ACC_PUBLIC) || (publicOnly == 0)) &&
199                         (m->name == utf_init))
200                         public_methods++;
201         }
202
203         oa = builtin_anewarray(public_methods, class_java_lang_reflect_Constructor);
204
205         if (!oa) 
206                 return NULL;
207
208         for (i = 0, pos = 0; i < c->methodscount; i++) {
209                 m = &c->methods[i];
210
211                 if (((m->flags & ACC_PUBLIC) || (publicOnly == 0)) &&
212                         (m->name == utf_init)) {
213
214                         if (!(o = native_new_and_init(class_java_lang_reflect_Constructor)))
215                                 return NULL;
216
217                         /* initialize instance fields */
218
219                         rc = (java_lang_reflect_Constructor *) o;
220
221                         rc->clazz = (java_lang_Class *) c;
222                         rc->slot  = i;
223
224                         /* store object into array */
225
226                         oa->data[pos++] = o;
227                 }
228         }
229
230         return oa;
231 }
232
233
234 /*
235  * Class:     java/lang/VMClass
236  * Method:    getDeclaredClasses
237  * Signature: (Z)[Ljava/lang/Class;
238  */
239 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMClass_getDeclaredClasses(JNIEnv *env, jclass clazz, java_lang_Class *klass, s4 publicOnly)
240 {
241         classinfo             *c;
242         classref_or_classinfo  outer;
243         utf                   *outername;
244         s4                     declaredclasscount;  /* number of declared classes */
245         s4                     pos;                     /* current declared class */
246         java_objectarray      *oa;                   /* array of declared classes */
247         s4                     i;
248
249         c = (classinfo *) klass;
250         declaredclasscount = 0;
251
252         if (!Java_java_lang_VMClass_isPrimitive(env, clazz, klass) &&
253                 (c->name->text[0] != '[')) {
254                 /* determine number of declared classes */
255
256                 for (i = 0; i < c->innerclasscount; i++) {
257                         outer = c->innerclass[i].outer_class;
258
259                         /* check if outer_class is a classref or a real class and
260                get the class name from the structure */
261
262                         outername = IS_CLASSREF(outer) ? outer.ref->name : outer.cls->name;
263
264                         /* outer class is this class */
265
266                         if ((outername == c->name) &&
267                                 ((publicOnly == 0) || (c->innerclass[i].flags & ACC_PUBLIC)))
268                                 declaredclasscount++;
269                 }
270         }
271
272         /* allocate Class[] and check for OOM */
273
274         oa = builtin_anewarray(declaredclasscount, class_java_lang_Class);
275
276         if (!oa)
277                 return NULL;
278
279         for (i = 0, pos = 0; i < c->innerclasscount; i++) {
280                 outer = c->innerclass[i].outer_class;
281
282                 /* check if outer_class is a classref or a real class and
283                    get the class name from the structure */
284
285                 outername = IS_CLASSREF(outer) ? outer.ref->name : outer.cls->name;
286
287                 /* outer class is this class */
288
289                 if ((outername == c->name) &&
290                         ((publicOnly == 0) || (c->innerclass[i].flags & ACC_PUBLIC))) {
291                         classinfo *inner;
292
293                         if (!resolve_classref_or_classinfo(NULL,
294                                                                                            c->innerclass[i].inner_class,
295                                                                                            resolveEager, false, false,
296                                                                                            &inner))
297                                 return NULL;
298
299                         if (!(inner->state & CLASS_LINKED))
300                                 if (!link_class(inner))
301                                         return NULL;
302
303                         oa->data[pos++] = (java_objectheader *) inner;
304                 }
305         }
306
307         return oa;
308 }
309
310
311 /*
312  * Class:     java/lang/VMClass
313  * Method:    getDeclaringClass
314  * Signature: ()Ljava/lang/Class;
315  */
316 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClass_getDeclaringClass(JNIEnv *env, jclass clazz, java_lang_Class *klass)
317 {
318         classinfo             *c;
319         classref_or_classinfo  inner;
320         utf                   *innername;
321         classinfo             *outer;
322         s4                     i;
323
324         c = (classinfo *) klass;
325
326         if (!Java_java_lang_VMClass_isPrimitive(env, clazz, klass) &&
327                 (c->name->text[0] != '[')) {
328
329                 if (c->innerclasscount == 0)  /* no innerclasses exist */
330                         return NULL;
331     
332                 for (i = 0; i < c->innerclasscount; i++) {
333                         inner = c->innerclass[i].inner_class;
334
335                         /* check if inner_class is a classref or a real class and
336                get the class name from the structure */
337
338                         innername = IS_CLASSREF(inner) ? inner.ref->name : inner.cls->name;
339
340                         /* innerclass is this class */
341
342                         if (innername == c->name) {
343                                 /* maybe the outer class is not loaded yet */
344
345                                 if (!resolve_classref_or_classinfo(NULL,
346                                                                                                    c->innerclass[i].outer_class,
347                                                                                                    resolveEager, false, false,
348                                                                                                    &outer))
349                                         return NULL;
350
351                                 if (!(outer->state & CLASS_LINKED))
352                                         if (!link_class(outer))
353                                                 return NULL;
354
355                                 return (java_lang_Class *) outer;
356                         }
357                 }
358         }
359
360         /* return NULL for arrayclasses and primitive classes */
361
362         return NULL;
363 }
364
365
366 /*
367  * Class:     java/lang/VMClass
368  * Method:    getDeclaredFields
369  * Signature: (Z)[Ljava/lang/reflect/Field;
370  */
371 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMClass_getDeclaredFields(JNIEnv *env, jclass clazz, java_lang_Class *klass, s4 publicOnly)
372 {
373         classinfo               *c;
374         java_objectarray        *oa;            /* result: array of field-objects */
375         fieldinfo               *f;
376         java_objectheader       *o;
377         java_lang_reflect_Field *rf;
378         s4 public_fields;                    /* number of elements in field-array */
379         s4 pos;
380         s4 i;
381
382         c = (classinfo *) klass;
383
384         /* determine number of fields */
385
386         for (i = 0, public_fields = 0; i < c->fieldscount; i++)
387                 if ((c->fields[i].flags & ACC_PUBLIC) || (publicOnly == 0))
388                         public_fields++;
389
390         /* create array of fields */
391
392         oa = builtin_anewarray(public_fields, class_java_lang_reflect_Field);
393
394         if (!oa)
395                 return NULL;
396
397         /* get the fields and store in the array */
398
399         for (i = 0, pos = 0; i < c->fieldscount; i++) {
400                 f = &(c->fields[i]);
401
402                 if ((f->flags & ACC_PUBLIC) || (publicOnly == 0)) {
403                         /* create Field object */
404
405                         if (!(o = native_new_and_init(class_java_lang_reflect_Field)))
406                                 return NULL;
407
408                         /* initialize instance fields */
409
410                         rf = (java_lang_reflect_Field *) o;
411
412                         rf->declaringClass = (java_lang_Class *) c;
413                         rf->name           = javastring_new(f->name);
414                         rf->slot           = i;
415
416                         /* store object into array */
417
418                         oa->data[pos++] = o;
419                 }
420         }
421
422         return oa;
423 }
424
425
426 /*
427  * Class:     java/lang/VMClass
428  * Method:    getInterfaces
429  * Signature: ()[Ljava/lang/Class;
430  */
431 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMClass_getInterfaces(JNIEnv *env, jclass clazz, java_lang_Class *klass)
432 {
433         classinfo        *c;
434         classinfo        *ic;
435         java_objectarray *oa;
436         u4                i;
437
438         c = (classinfo *) klass;
439
440         if (!(c->state & CLASS_LINKED))
441                 if (!link_class(c))
442                         return NULL;
443
444         oa = builtin_anewarray(c->interfacescount, class_java_lang_Class);
445
446         if (!oa)
447                 return NULL;
448
449         for (i = 0; i < c->interfacescount; i++) {
450                 ic = c->interfaces[i].cls;
451
452                 oa->data[i] = (java_objectheader *) ic;
453         }
454
455         return oa;
456 }
457
458
459 /*
460  * Class:     java/lang/VMClass
461  * Method:    getDeclaredMethods
462  * Signature: (Z)[Ljava/lang/reflect/Method;
463  */
464 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMClass_getDeclaredMethods(JNIEnv *env, jclass clazz, java_lang_Class *klass, s4 publicOnly)
465 {
466         classinfo                *c;
467         java_objectheader        *o;
468         java_lang_reflect_Method *rm;
469         java_objectarray         *oa;          /* result: array of Method-objects */
470         methodinfo               *m;      /* the current method to be represented */
471         s4 public_methods;               /* number of public methods of the class */
472         s4 pos;
473         s4 i;
474
475         c = (classinfo *) klass;    
476         public_methods = 0;
477
478         /* JOWENN: array classes do not declare methods according to mauve
479            test.  It should be considered, if we should return to my old
480            clone method overriding instead of declaring it as a member
481            function. */
482
483         if (Java_java_lang_VMClass_isArray(env, clazz, klass))
484                 return builtin_anewarray(0, class_java_lang_reflect_Method);
485
486         /* determine number of methods */
487
488         for (i = 0; i < c->methodscount; i++) {
489                 m = &c->methods[i];
490
491                 if (((m->flags & ACC_PUBLIC) || (publicOnly == false)) &&
492                         ((m->name != utf_init) && (m->name != utf_clinit)) &&
493                         !(m->flags & ACC_MIRANDA))
494                         public_methods++;
495         }
496
497         oa = builtin_anewarray(public_methods, class_java_lang_reflect_Method);
498
499         if (!oa) 
500                 return NULL;
501
502         for (i = 0, pos = 0; i < c->methodscount; i++) {
503                 m = &c->methods[i];
504
505                 if (((m->flags & ACC_PUBLIC) || (publicOnly == false)) && 
506                         ((m->name != utf_init) && (m->name != utf_clinit)) &&
507                         !(m->flags & ACC_MIRANDA)) {
508
509                         if (!(o = native_new_and_init(class_java_lang_reflect_Method)))
510                                 return NULL;
511
512                         /* initialize instance fields */
513
514                         rm = (java_lang_reflect_Method *) o;
515
516                         rm->declaringClass = (java_lang_Class *) m->class;
517                         rm->name           = javastring_new(m->name);
518                         rm->slot           = i;
519
520                         /* store object into array */
521
522                         oa->data[pos++] = o;
523                 }
524         }
525
526         return oa;
527 }
528
529
530 /*
531  * Class:     java/lang/VMClass
532  * Method:    getModifiers
533  * Signature: (Z)I
534  */
535 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_getModifiers(JNIEnv *env, jclass clazz, java_lang_Class *klass, s4 ignoreInnerClassesAttrib)
536 {
537         classinfo             *c;
538         classref_or_classinfo  inner;
539         classref_or_classinfo  outer;
540         utf                   *innername;
541         s4                     i;
542
543         c = (classinfo *) klass;
544
545         if (!ignoreInnerClassesAttrib && (c->innerclasscount != 0)) {
546                 /* search for passed class as inner class */
547
548                 for (i = 0; i < c->innerclasscount; i++) {
549                         inner = c->innerclass[i].inner_class;
550                         outer = c->innerclass[i].outer_class;
551
552                         /* Check if inner is a classref or a real class and get
553                the name of the structure */
554
555                         innername = IS_CLASSREF(inner) ? inner.ref->name : inner.cls->name;
556
557                         /* innerclass is this class */
558
559                         if (innername == c->name) {
560                                 /* has the class actually an outer class? */
561
562                                 if (outer.any)
563                                         /* return flags got from the outer class file */
564                                         return c->innerclass[i].flags;
565                                 else
566                                         return c->flags;
567                         }
568                 }
569         }
570
571         /* passed class is no inner class or it was not requested */
572
573         return c->flags;
574 }
575
576
577 /*
578  * Class:     java/lang/VMClass
579  * Method:    getName
580  * Signature: ()Ljava/lang/String;
581  */
582 JNIEXPORT java_lang_String* JNICALL Java_java_lang_VMClass_getName(JNIEnv *env, jclass clazz, java_lang_Class *klass)
583 {
584         classinfo        *c;
585         java_lang_String *s;
586         u4                i;
587
588         c = (classinfo *) klass;
589         s = (java_lang_String *) javastring_new(c->name);
590
591         if (!s)
592                 return NULL;
593
594         /* return string where '/' is replaced by '.' */
595
596         for (i = 0; i < s->value->header.size; i++) {
597                 if (s->value->data[i] == '/')
598                         s->value->data[i] = '.';
599         }
600
601         return s;
602 }
603
604
605 /*
606  * Class:     java/lang/Class
607  * Method:    getSuperclass
608  * Signature: ()Ljava/lang/Class;
609  */
610 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClass_getSuperclass(JNIEnv *env, jclass clazz, java_lang_Class *klass)
611 {
612         classinfo *c;
613         classinfo *sc;
614
615         c = (classinfo *) klass;
616         sc = c->super.cls;
617
618         if (c->flags & ACC_INTERFACE)
619                 return NULL;
620
621         if (!sc)
622                 return NULL;
623
624         return (java_lang_Class *) sc;
625 }
626
627
628 /*
629  * Class:     java/lang/Class
630  * Method:    isArray
631  * Signature: ()Z
632  */
633 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_isArray(JNIEnv *env, jclass clazz, java_lang_Class *klass)
634 {
635         classinfo *c = (classinfo *) klass;
636
637         if (!(c->state & CLASS_LINKED))
638                 if (!link_class(c))
639                         return 0;
640
641         return (c->vftbl->arraydesc != NULL);
642 }
643
644
645 /*
646  * Class:     java/lang/Class
647  * Method:    isAssignableFrom
648  * Signature: (Ljava/lang/Class;)Z
649  */
650 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_isAssignableFrom(JNIEnv *env, jclass clazz, java_lang_Class *klass, java_lang_Class *c)
651 {
652         classinfo *kc;
653         classinfo *cc;
654
655         kc = (classinfo *) klass;
656         cc = (classinfo *) c;
657
658         if (cc == NULL) {
659                 exceptions_throw_nullpointerexception();
660                 return 0;
661         }
662
663         if (!(kc->state & CLASS_LINKED))
664                 if (!link_class(kc))
665                         return 0;
666
667         if (!(cc->state & CLASS_LINKED))
668                 if (!link_class(cc))
669                         return 0;
670
671         /* XXX this may be wrong for array classes */
672
673         return builtin_isanysubclass(cc, kc);
674 }
675
676
677 /*
678  * Class:     java/lang/Class
679  * Method:    isInstance
680  * Signature: (Ljava/lang/Object;)Z
681  */
682 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_isInstance(JNIEnv *env, jclass clazz, java_lang_Class *klass, java_lang_Object *o)
683 {
684         classinfo         *c;
685         java_objectheader *ob;
686
687         c = (classinfo *) klass;
688         ob = (java_objectheader *) o;
689
690         if (!(c->state & CLASS_LINKED))
691                 if (!link_class(c))
692                         return 0;
693
694         return builtin_instanceof(ob, c);
695 }
696
697
698 /*
699  * Class:     java/lang/Class
700  * Method:    isInterface
701  * Signature: ()Z
702  */
703 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_isInterface(JNIEnv *env, jclass clazz, java_lang_Class *klass)
704 {
705         classinfo *c;
706
707         c = (classinfo *) klass;
708
709         if (c->flags & ACC_INTERFACE)
710                 return true;
711
712         return false;
713 }
714
715
716 /*
717  * Class:     java/lang/Class
718  * Method:    isPrimitive
719  * Signature: ()Z
720  */
721 JNIEXPORT s4 JNICALL Java_java_lang_VMClass_isPrimitive(JNIEnv *env, jclass clazz, java_lang_Class *klass)
722 {
723         classinfo *c;
724         s4         i;
725
726         c = (classinfo *) klass;
727
728         /* search table of primitive classes */
729
730         for (i = 0; i < PRIMITIVETYPE_COUNT; i++)
731                 if (primitivetype_table[i].class_primitive == c)
732                         return true;
733
734         return false;
735 }
736
737
738 /*
739  * Class:     java/lang/VMClass
740  * Method:    throwException
741  * Signature: (Ljava/lang/Throwable;)V
742  */
743 JNIEXPORT void JNICALL Java_java_lang_VMClass_throwException(JNIEnv *env, jclass clazz, java_lang_Throwable *t)
744 {
745         *exceptionptr = (java_objectheader *) t;
746 }
747
748
749 /*
750  * These are local overrides for various environment variables in Emacs.
751  * Please do not remove this and leave it at the end of the file, where
752  * Emacs will automagically detect them.
753  * ---------------------------------------------------------------------
754  * Local variables:
755  * mode: c
756  * indent-tabs-mode: t
757  * c-basic-offset: 4
758  * tab-width: 4
759  * End:
760  * vim:noexpandtab:sw=4:ts=4:
761  */