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