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