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