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