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