* src/vm/exceptions.c: Moved to .cpp.
[cacao.git] / src / native / vm / gnuclasspath / java_lang_VMClassLoader.cpp
1 /* src/native/vm/gnuclasspath/java_lang_VMClassLoader.cpp
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30 #include <sys/stat.h>
31
32 #include "mm/memory.h"
33
34 #include "native/jni.h"
35 #include "native/llni.h"
36 #include "native/native.h"
37 #include "native/include/java_lang_Class.h"
38 #include "native/include/java_lang_String.h"
39 #include "native/include/java_security_ProtectionDomain.h"  /* required by... */
40 #include "native/include/java_lang_ClassLoader.h"
41 #include "native/include/java_util_HashMap.h"
42 #include "native/include/java_util_Map.h"
43 #include "native/include/java_lang_Boolean.h"
44
45 // FIXME
46 extern "C" {
47 #include "native/include/java_lang_VMClassLoader.h"
48 }
49
50 #include "toolbox/logging.h"
51 #include "toolbox/list.h"
52
53 #if defined(ENABLE_ASSERTION)
54 #include "vm/assertion.h"
55 #endif
56
57 #include "vm/builtin.h"
58 #include "vm/exceptions.hpp"
59 #include "vm/initialize.h"
60 #include "vm/primitive.hpp"
61 #include "vm/stringlocal.h"
62 #include "vm/vm.hpp"
63
64 #include "vm/jit/asmpart.h"
65
66 #include "vmcore/class.h"
67 #include "vmcore/classcache.h"
68 #include "vmcore/globals.hpp"
69 #include "vmcore/linker.h"
70 #include "vmcore/loader.h"
71 #include "vmcore/options.h"
72 #include "vmcore/statistics.h"
73 #include "vmcore/suck.h"
74 #include "vmcore/zip.h"
75
76 #if defined(ENABLE_JVMTI)
77 #include "native/jvmti/cacaodbg.h"
78 #endif
79
80
81 // Native functions are exported as C functions.
82 extern "C" {
83
84 /*
85  * Class:     java/lang/VMClassLoader
86  * Method:    defineClass
87  * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;
88  */
89 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIEnv *env, jclass clazz, java_lang_ClassLoader *cl, java_lang_String *name, java_handle_bytearray_t *data, int32_t offset, int32_t len, java_security_ProtectionDomain *pd)
90 {
91         utf             *utfname;
92         classinfo       *c;
93         classloader_t   *loader;
94         java_lang_Class *o;
95
96 #if defined(ENABLE_JVMTI)
97         jint new_class_data_len = 0;
98         unsigned char* new_class_data = NULL;
99 #endif
100
101         /* check if data was passed */
102
103         if (data == NULL) {
104                 exceptions_throw_nullpointerexception();
105                 return NULL;
106         }
107
108         /* check the indexes passed */
109
110         if ((offset < 0) || (len < 0) || ((offset + len) > LLNI_array_size(data))) {
111                 exceptions_throw_arrayindexoutofboundsexception();
112                 return NULL;
113         }
114
115         /* add classloader to classloader hashtable */
116
117         loader = loader_hashtable_classloader_add((java_handle_t *) cl);
118
119         if (name != NULL) {
120                 /* convert '.' to '/' in java string */
121
122                 utfname = javastring_toutf((java_handle_t *) name, true);
123         } 
124         else {
125                 utfname = NULL;
126         }
127
128 #if defined(ENABLE_JVMTI)
129         /* XXX again this will not work because of the indirection cell for classloaders */
130         assert(0);
131         /* fire Class File Load Hook JVMTI event */
132
133         if (jvmti)
134                 jvmti_ClassFileLoadHook(utfname, len, (unsigned char *) data->data, 
135                                                                 loader, (java_handle_t *) pd, 
136                                                                 &new_class_data_len, &new_class_data);
137 #endif
138
139         /* define the class */
140
141 #if defined(ENABLE_JVMTI)
142         /* check if the JVMTI wants to modify the class */
143
144         if (new_class_data == NULL)
145                 c = class_define(utfname, loader, new_class_data_len, new_class_data, pd); 
146         else
147 #endif
148                 c = class_define(utfname, loader, len, (uint8_t *) &LLNI_array_direct(data, offset), (java_handle_t *) pd);
149
150         if (c == NULL)
151                 return NULL;
152
153         /* for convenience */
154
155         o = LLNI_classinfo_wrap(c);
156
157         /* set ProtectionDomain */
158
159         LLNI_field_set_ref(o, pd, pd);
160
161         return o;
162 }
163
164
165 /*
166  * Class:     java/lang/VMClassLoader
167  * Method:    getPrimitiveClass
168  * Signature: (C)Ljava/lang/Class;
169  */
170 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_getPrimitiveClass(JNIEnv *env, jclass clazz, int32_t type)
171 {
172         classinfo *c;
173
174         c = Primitive::get_class_by_char(type);
175
176         if (c == NULL) {
177                 exceptions_throw_classnotfoundexception(utf_null);
178                 return NULL;
179         }
180
181         return LLNI_classinfo_wrap(c);
182 }
183
184
185 /*
186  * Class:     java/lang/VMClassLoader
187  * Method:    resolveClass
188  * Signature: (Ljava/lang/Class;)V
189  */
190 JNIEXPORT void JNICALL Java_java_lang_VMClassLoader_resolveClass(JNIEnv *env, jclass clazz, java_lang_Class *c)
191 {
192         classinfo *ci;
193
194         ci = LLNI_classinfo_unwrap(c);
195
196         if (!ci) {
197                 exceptions_throw_nullpointerexception();
198                 return;
199         }
200
201         /* link the class */
202
203         if (!(ci->state & CLASS_LINKED))
204                 (void) link_class(ci);
205
206         return;
207 }
208
209
210 /*
211  * Class:     java/lang/VMClassLoader
212  * Method:    loadClass
213  * Signature: (Ljava/lang/String;Z)Ljava/lang/Class;
214  */
215 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_loadClass(JNIEnv *env, jclass clazz, java_lang_String *name, int32_t resolve)
216 {
217         classinfo *c;
218         utf       *u;
219
220         if (name == NULL) {
221                 exceptions_throw_nullpointerexception();
222                 return NULL;
223         }
224
225         /* create utf string in which '.' is replaced by '/' */
226
227         u = javastring_toutf((java_handle_t *) name, true);
228
229         /* load class */
230
231         c = load_class_bootstrap(u);
232
233         if (c == NULL)
234                 return NULL;
235
236         /* resolve class -- if requested */
237
238 /*      if (resolve) */
239                 if (!link_class(c))
240                         return NULL;
241
242         return LLNI_classinfo_wrap(c);
243 }
244
245
246 /*
247  * Class:     java/lang/VMClassLoader
248  * Method:    nativeGetResources
249  * Signature: (Ljava/lang/String;)Ljava/util/Vector;
250  */
251 JNIEXPORT struct java_util_Vector* JNICALL Java_java_lang_VMClassLoader_nativeGetResources(JNIEnv *env, jclass clazz, java_lang_String *name)
252 {
253         java_handle_t        *o;         /* vector being created     */
254         methodinfo           *m;         /* "add" method of vector   */
255         java_handle_t        *path;      /* path to be added         */
256         list_classpath_entry *lce;       /* classpath entry          */
257         utf                  *utfname;   /* utf to look for          */
258         char                 *buffer;    /* char buffer              */
259         char                 *namestart; /* start of name to use     */
260         char                 *tmppath;   /* temporary buffer         */
261         int32_t               namelen;   /* length of name to use    */
262         int32_t               searchlen; /* length of name to search */
263         int32_t               bufsize;   /* size of buffer allocated */
264         int32_t               pathlen;   /* name of path to assemble */
265         struct stat           buf;       /* buffer for stat          */
266         jboolean              ret;       /* return value of "add"    */
267
268         /* get the resource name as utf string */
269
270         utfname = javastring_toutf((java_handle_t *) name, false);
271
272         if (utfname == NULL)
273                 return NULL;
274
275         /* copy it to a char buffer */
276
277         namelen   = utf_bytes(utfname);
278         searchlen = namelen;
279         bufsize   = namelen + strlen("0");
280         buffer    = MNEW(char, bufsize);
281
282         utf_copy(buffer, utfname);
283         namestart = buffer;
284
285         /* skip leading '/' */
286
287         if (namestart[0] == '/') {
288                 namestart++;
289                 namelen--;
290                 searchlen--;
291         }
292
293         /* remove trailing `.class' */
294
295         if (namelen >= 6 && strcmp(namestart + (namelen - 6), ".class") == 0) {
296                 searchlen -= 6;
297         }
298
299         /* create a new needle to look for, if necessary */
300
301         if (searchlen != bufsize-1) {
302                 utfname = utf_new(namestart, searchlen);
303                 if (utfname == NULL)
304                         goto return_NULL;
305         }
306                         
307         /* new Vector() */
308
309         o = native_new_and_init(class_java_util_Vector);
310
311         if (o == NULL)
312                 goto return_NULL;
313
314         /* get Vector.add() method */
315
316         m = class_resolveclassmethod(class_java_util_Vector,
317                                                                  utf_add,
318                                                                  utf_new_char("(Ljava/lang/Object;)Z"),
319                                                                  NULL,
320                                                                  true);
321
322         if (m == NULL)
323                 goto return_NULL;
324
325         /* iterate over all classpath entries */
326
327         for (lce = (list_classpath_entry*) list_first(list_classpath_entries); lce != NULL;
328                  lce = (list_classpath_entry*) list_next(list_classpath_entries, lce)) {
329                 /* clear path pointer */
330                 path = NULL;
331
332 #if defined(ENABLE_ZLIB)
333                 if (lce->type == CLASSPATH_ARCHIVE) {
334
335                         if (zip_find(lce, utfname)) {
336                                 pathlen = strlen("jar:file://") + lce->pathlen + strlen("!/") +
337                                         namelen + strlen("0");
338
339                                 tmppath = MNEW(char, pathlen);
340
341                                 sprintf(tmppath, "jar:file://%s!/%s", lce->path, namestart);
342                                 path = javastring_new_from_utf_string(tmppath),
343
344                                 MFREE(tmppath, char, pathlen);
345                         }
346
347                 } else {
348 #endif /* defined(ENABLE_ZLIB) */
349                         pathlen = strlen("file://") + lce->pathlen + namelen + strlen("0");
350
351                         tmppath = MNEW(char, pathlen);
352
353                         sprintf(tmppath, "file://%s%s", lce->path, namestart);
354
355                         /* Does this file exist? */
356
357                         if (stat(tmppath + strlen("file://") - 1, &buf) == 0)
358                                 if (!S_ISDIR(buf.st_mode))
359                                         path = javastring_new_from_utf_string(tmppath);
360
361                         MFREE(tmppath, char, pathlen);
362 #if defined(ENABLE_ZLIB)
363                 }
364 #endif
365
366                 /* if a resource was found, add it to the vector */
367
368                 if (path != NULL) {
369                         ret = vm_call_method_int(m, o, path);
370
371                         if (exceptions_get_exception() != NULL)
372                                 goto return_NULL;
373
374                         if (ret == 0) 
375                                 goto return_NULL;
376                 }
377         }
378
379         MFREE(buffer, char, bufsize);
380
381         return (struct java_util_Vector *) o;
382
383 return_NULL:
384         MFREE(buffer, char, bufsize);
385
386         return NULL;
387 }
388
389
390 /*
391  * Class:     java/lang/VMClassLoader
392  * Method:    defaultAssertionStatus
393  * Signature: ()Z
394  */
395 JNIEXPORT int32_t JNICALL Java_java_lang_VMClassLoader_defaultAssertionStatus(JNIEnv *env, jclass clazz)
396 {
397 #if defined(ENABLE_ASSERTION)
398         return assertion_system_enabled;
399 #else
400         return false;
401 #endif
402 }
403
404 /*
405  * Class:     java/lang/VMClassLoader
406  * Method:    userAssertionStatus
407  * Signature: ()Z
408  */
409 JNIEXPORT int32_t JNICALL Java_java_lang_VMClassLoader_defaultUserAssertionStatus(JNIEnv *env, jclass clazz)
410 {
411 #if defined(ENABLE_ASSERTION)
412         return assertion_user_enabled;
413 #else
414         return false;
415 #endif
416 }
417
418 /*
419  * Class:     java/lang/VMClassLoader
420  * Method:    packageAssertionStatus
421  * Signature: ()Ljava_util_Map;
422  */
423 JNIEXPORT java_util_Map* JNICALL Java_java_lang_VMClassLoader_packageAssertionStatus0(JNIEnv *env, jclass clazz, java_lang_Boolean *jtrue, java_lang_Boolean *jfalse)
424 {
425         java_handle_t     *hm;
426 #if defined(ENABLE_ASSERTION)
427         java_handle_t     *js;
428         methodinfo        *m;
429         assertion_name_t  *item;
430 #endif
431
432         /* new HashMap() */
433
434         hm = native_new_and_init(class_java_util_HashMap);
435         if (hm == NULL) {
436                 return NULL;
437         }
438
439 #if defined(ENABLE_ASSERTION)
440         /* if nothing todo, return now */
441
442         if (assertion_package_count == 0) {
443                 return (java_util_Map *) hm;
444         }
445
446         /* get HashMap.put method */
447
448         m = class_resolveclassmethod(class_java_util_HashMap,
449                                  utf_put,
450                                  utf_new_char("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"),
451                                  NULL,
452                                  true);
453
454         if (m == NULL) {
455                 return NULL;
456         }
457
458         item = (assertion_name_t *)list_first(list_assertion_names);
459
460         while (item != NULL) {
461                 if (item->package == false) {
462                         item = (assertion_name_t *)list_next(list_assertion_names, item);
463                         continue;
464                 }
465                 
466                 if (strcmp(item->name, "") == 0) {
467                         /* unnamed package wanted */
468                         js = NULL;
469                 }
470                 else {
471                         js = javastring_new_from_ascii(item->name);
472                         if (js == NULL) {
473                                 return NULL;
474                         }
475                 }
476
477                 if (item->enabled == true) {
478                         vm_call_method(m, hm, js, jtrue);
479                 }
480                 else {
481                         vm_call_method(m, hm, js, jfalse);
482                 }
483
484                 item = (assertion_name_t *)list_next(list_assertion_names, item);
485         }
486 #endif
487
488         return (java_util_Map *) hm;
489 }
490
491 /*
492  * Class:     java/lang/VMClassLoader
493  * Method:    classAssertionStatus
494  * Signature: ()Ljava_util_Map;
495  */
496 JNIEXPORT java_util_Map* JNICALL Java_java_lang_VMClassLoader_classAssertionStatus0(JNIEnv *env, jclass clazz, java_lang_Boolean *jtrue, java_lang_Boolean *jfalse)
497 {
498         java_handle_t     *hm;
499 #if defined(ENABLE_ASSERTION)
500         java_handle_t     *js;
501         methodinfo        *m;
502         assertion_name_t  *item;
503 #endif
504
505         /* new HashMap() */
506
507         hm = native_new_and_init(class_java_util_HashMap);
508         if (hm == NULL) {
509                 return NULL;
510         }
511
512 #if defined(ENABLE_ASSERTION)
513         /* if nothing todo, return now */
514
515         if (assertion_class_count == 0) {
516                 return (java_util_Map *) hm;
517         }
518
519         /* get HashMap.put method */
520
521         m = class_resolveclassmethod(class_java_util_HashMap,
522                                  utf_put,
523                                  utf_new_char("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"),
524                                  NULL,
525                                  true);
526
527         if (m == NULL) {
528                 return NULL;
529         }
530
531         item = (assertion_name_t *)list_first(list_assertion_names);
532
533         while (item != NULL) {
534                 if (item->package == true) {
535                         item = (assertion_name_t *)list_next(list_assertion_names, item);
536                         continue;
537                 }
538
539                 js = javastring_new_from_ascii(item->name);
540                 if (js == NULL) {
541                         return NULL;
542                 }
543
544                 if (item->enabled == true) {
545                         vm_call_method(m, hm, js, jtrue);
546                 }
547                 else {
548                         vm_call_method(m, hm, js, jfalse);
549                 }
550
551                 item = (assertion_name_t *)list_next(list_assertion_names, item);
552         }
553 #endif
554
555         return (java_util_Map *) hm;
556 }
557
558
559 /*
560  * Class:     java/lang/VMClassLoader
561  * Method:    findLoadedClass
562  * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;
563  */
564 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_findLoadedClass(JNIEnv *env, jclass clazz, java_lang_ClassLoader *loader, java_lang_String *name)
565 {
566         classloader_t *cl;
567         classinfo     *c;
568         utf           *u;
569
570         /* XXX is it correct to add the classloader to the hashtable here? */
571
572         cl = loader_hashtable_classloader_add((java_handle_t *) loader);
573
574         /* replace `.' by `/', this is required by the classcache */
575
576         u = javastring_toutf((java_handle_t *) name, true);
577
578         /* lookup for defining classloader */
579
580         c = classcache_lookup_defined(cl, u);
581
582         /* if not found, lookup for initiating classloader */
583
584         if (c == NULL)
585                 c = classcache_lookup(cl, u);
586
587         return LLNI_classinfo_wrap(c);
588 }
589
590 } // extern "C"
591
592
593 /* native methods implemented by this file ************************************/
594
595 static JNINativeMethod methods[] = {
596         { (char*) "defineClass",                (char*) "(Ljava/lang/ClassLoader;Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;", (void*) (uintptr_t) &Java_java_lang_VMClassLoader_defineClass                },
597         { (char*) "getPrimitiveClass",          (char*) "(C)Ljava/lang/Class;",                                                                             (void*) (uintptr_t) &Java_java_lang_VMClassLoader_getPrimitiveClass          },
598         { (char*) "resolveClass",               (char*) "(Ljava/lang/Class;)V",                                                                             (void*) (uintptr_t) &Java_java_lang_VMClassLoader_resolveClass               },
599         { (char*) "loadClass",                  (char*) "(Ljava/lang/String;Z)Ljava/lang/Class;",                                                           (void*) (uintptr_t) &Java_java_lang_VMClassLoader_loadClass                  },
600         { (char*) "nativeGetResources",         (char*) "(Ljava/lang/String;)Ljava/util/Vector;",                                                           (void*) (uintptr_t) &Java_java_lang_VMClassLoader_nativeGetResources         },
601         { (char*) "defaultAssertionStatus",     (char*) "()Z",                                                                                              (void*) (uintptr_t) &Java_java_lang_VMClassLoader_defaultAssertionStatus     },
602         { (char*) "defaultUserAssertionStatus", (char*) "()Z",                                                                                              (void*) (uintptr_t) &Java_java_lang_VMClassLoader_defaultUserAssertionStatus },
603         { (char*) "packageAssertionStatus0",    (char*) "(Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/util/Map;",                                          (void*) (uintptr_t) &Java_java_lang_VMClassLoader_packageAssertionStatus0    },
604         { (char*) "classAssertionStatus0",      (char*) "(Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/util/Map;",                                          (void*) (uintptr_t) &Java_java_lang_VMClassLoader_classAssertionStatus0      },
605         { (char*) "findLoadedClass",            (char*) "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;",                                     (void*) (uintptr_t) &Java_java_lang_VMClassLoader_findLoadedClass            },
606 };
607
608
609 /* _Jv_java_lang_VMClassLoader_init ********************************************
610
611    Register native functions.
612
613 *******************************************************************************/
614
615 // FIXME
616 extern "C" {
617 void _Jv_java_lang_VMClassLoader_init(void)
618 {
619         utf *u;
620
621         u = utf_new_char("java/lang/VMClassLoader");
622
623         native_method_register(u, methods, NATIVE_METHODS_COUNT);
624 }
625 }
626
627
628 /*
629  * These are local overrides for various environment variables in Emacs.
630  * Please do not remove this and leave it at the end of the file, where
631  * Emacs will automagically detect them.
632  * ---------------------------------------------------------------------
633  * Local variables:
634  * mode: c++
635  * indent-tabs-mode: t
636  * c-basic-offset: 4
637  * tab-width: 4
638  * End:
639  * vim:noexpandtab:sw=4:ts=4:
640  */