ebeeb162885c7f07b55162ea875171cfeebc57a2
[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.hpp"
33
34 #include "native/jni.hpp"
35 #include "native/llni.h"
36 #include "native/native.hpp"
37
38 #if defined(ENABLE_JNI_HEADERS)
39 # include "native/vm/include/java_lang_VMClassLoader.h"
40 #endif
41
42 #include "toolbox/logging.hpp"
43 #include "toolbox/list.hpp"
44
45 #if defined(ENABLE_ASSERTION)
46 #include "vm/assertion.hpp"
47 #endif
48
49 #include "vm/jit/builtin.hpp"
50 #include "vm/class.hpp"
51 #include "vm/classcache.hpp"
52 #include "vm/exceptions.hpp"
53 #include "vm/globals.hpp"
54 #include "vm/initialize.hpp"
55 #include "vm/javaobjects.hpp"
56 #include "vm/linker.hpp"
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.hpp"
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         utf                  *utfname;   /* utf to look for          */
252         char                 *buffer;    /* char buffer              */
253         char                 *namestart; /* start of name to use     */
254         char                 *tmppath;   /* temporary buffer         */
255         int32_t               namelen;   /* length of name to use    */
256         int32_t               searchlen; /* length of name to search */
257         int32_t               bufsize;   /* size of buffer allocated */
258         int32_t               pathlen;   /* name of path to assemble */
259         struct stat           buf;       /* buffer for stat          */
260         jboolean              ret;       /* return value of "add"    */
261
262         /* get the resource name as utf string */
263
264         utfname = javastring_toutf((java_handle_t *) name, false);
265
266         if (utfname == NULL)
267                 return NULL;
268
269         /* copy it to a char buffer */
270
271         namelen   = utf_bytes(utfname);
272         searchlen = namelen;
273         bufsize   = namelen + strlen("0");
274         buffer    = MNEW(char, bufsize);
275
276         utf_copy(buffer, utfname);
277         namestart = buffer;
278
279         /* skip leading '/' */
280
281         if (namestart[0] == '/') {
282                 namestart++;
283                 namelen--;
284                 searchlen--;
285         }
286
287         /* remove trailing `.class' */
288
289         if (namelen >= 6 && strcmp(namestart + (namelen - 6), ".class") == 0) {
290                 searchlen -= 6;
291         }
292
293         /* create a new needle to look for, if necessary */
294
295         if (searchlen != bufsize-1) {
296                 utfname = utf_new(namestart, searchlen);
297                 if (utfname == NULL)
298                         goto return_NULL;
299         }
300                         
301         /* new Vector() */
302
303         o = native_new_and_init(class_java_util_Vector);
304
305         if (o == NULL)
306                 goto return_NULL;
307
308         /* get Vector.add() method */
309
310         m = class_resolveclassmethod(class_java_util_Vector,
311                                                                  utf_add,
312                                                                  utf_new_char("(Ljava/lang/Object;)Z"),
313                                                                  NULL,
314                                                                  true);
315
316         if (m == NULL)
317                 goto return_NULL;
318
319         /* iterate over all classpath entries */
320
321         for (List<list_classpath_entry*>::iterator it = list_classpath_entries->begin(); it != list_classpath_entries->end(); it++) {
322                 list_classpath_entry* lce = *it;
323
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 #endif
425
426         /* new HashMap() */
427
428         hm = native_new_and_init(class_java_util_HashMap);
429         if (hm == NULL) {
430                 return NULL;
431         }
432
433 #if defined(ENABLE_ASSERTION)
434         /* if nothing todo, return now */
435
436         if (assertion_package_count == 0) {
437                 return (jobject) hm;
438         }
439
440         /* get HashMap.put method */
441
442         m = class_resolveclassmethod(class_java_util_HashMap,
443                                  utf_put,
444                                  utf_new_char("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"),
445                                  NULL,
446                                  true);
447
448         if (m == NULL) {
449                 return NULL;
450         }
451
452         for (List<assertion_name_t*>::iterator it = list_assertion_names->begin(); it != list_assertion_names->end(); it++) {
453                 assertion_name_t* item = *it;
454
455                 if (item->package == false)
456                         continue;
457                 
458                 if (strcmp(item->name, "") == 0) {
459                         /* unnamed package wanted */
460                         js = NULL;
461                 }
462                 else {
463                         js = javastring_new_from_ascii(item->name);
464                         if (js == NULL) {
465                                 return NULL;
466                         }
467                 }
468
469                 if (item->enabled == true) {
470                         vm_call_method(m, hm, js, jtrue);
471                 }
472                 else {
473                         vm_call_method(m, hm, js, jfalse);
474                 }
475         }
476 #endif
477
478         return (jobject) hm;
479 }
480
481 /*
482  * Class:     java/lang/VMClassLoader
483  * Method:    classAssertionStatus
484  * Signature: (Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/util/Map;
485  */
486 JNIEXPORT jobject JNICALL Java_java_lang_VMClassLoader_classAssertionStatus0(JNIEnv *env, jclass clazz, jobject jtrue, jobject jfalse)
487 {
488         java_handle_t     *hm;
489 #if defined(ENABLE_ASSERTION)
490         java_handle_t     *js;
491         methodinfo        *m;
492 #endif
493
494         /* new HashMap() */
495
496         hm = native_new_and_init(class_java_util_HashMap);
497         if (hm == NULL) {
498                 return NULL;
499         }
500
501 #if defined(ENABLE_ASSERTION)
502         /* if nothing todo, return now */
503
504         if (assertion_class_count == 0) {
505                 return (jobject) hm;
506         }
507
508         /* get HashMap.put method */
509
510         m = class_resolveclassmethod(class_java_util_HashMap,
511                                  utf_put,
512                                  utf_new_char("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"),
513                                  NULL,
514                                  true);
515
516         if (m == NULL) {
517                 return NULL;
518         }
519
520         for (List<assertion_name_t*>::iterator it = list_assertion_names->begin(); it != list_assertion_names->end(); it++) {
521                 assertion_name_t* item = *it;
522
523                 if (item->package == true)
524                         continue;
525
526                 js = javastring_new_from_ascii(item->name);
527                 if (js == NULL) {
528                         return NULL;
529                 }
530
531                 if (item->enabled == true) {
532                         vm_call_method(m, hm, js, jtrue);
533                 }
534                 else {
535                         vm_call_method(m, hm, js, jfalse);
536                 }
537         }
538 #endif
539
540         return (jobject) hm;
541 }
542
543
544 /*
545  * Class:     java/lang/VMClassLoader
546  * Method:    findLoadedClass
547  * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;
548  */
549 JNIEXPORT jclass JNICALL Java_java_lang_VMClassLoader_findLoadedClass(JNIEnv *env, jclass clazz, jobject loader, jstring name)
550 {
551         classloader_t *cl;
552         classinfo     *c;
553         utf           *u;
554
555         /* XXX is it correct to add the classloader to the hashtable here? */
556
557         cl = loader_hashtable_classloader_add((java_handle_t *) loader);
558
559         /* replace `.' by `/', this is required by the classcache */
560
561         u = javastring_toutf((java_handle_t *) name, true);
562
563         /* lookup for defining classloader */
564
565         c = classcache_lookup_defined(cl, u);
566
567         /* if not found, lookup for initiating classloader */
568
569         if (c == NULL)
570                 c = classcache_lookup(cl, u);
571
572         return (jclass) LLNI_classinfo_wrap(c);
573 }
574
575 } // extern "C"
576
577
578 /* native methods implemented by this file ************************************/
579
580 static JNINativeMethod methods[] = {
581         { (char*) "defineClass",                (char*) "(Ljava/lang/ClassLoader;Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;", (void*) (uintptr_t) &Java_java_lang_VMClassLoader_defineClass                },
582         { (char*) "getPrimitiveClass",          (char*) "(C)Ljava/lang/Class;",                                                                             (void*) (uintptr_t) &Java_java_lang_VMClassLoader_getPrimitiveClass          },
583         { (char*) "resolveClass",               (char*) "(Ljava/lang/Class;)V",                                                                             (void*) (uintptr_t) &Java_java_lang_VMClassLoader_resolveClass               },
584         { (char*) "loadClass",                  (char*) "(Ljava/lang/String;Z)Ljava/lang/Class;",                                                           (void*) (uintptr_t) &Java_java_lang_VMClassLoader_loadClass                  },
585         { (char*) "nativeGetResources",         (char*) "(Ljava/lang/String;)Ljava/util/Vector;",                                                           (void*) (uintptr_t) &Java_java_lang_VMClassLoader_nativeGetResources         },
586         { (char*) "defaultAssertionStatus",     (char*) "()Z",                                                                                              (void*) (uintptr_t) &Java_java_lang_VMClassLoader_defaultAssertionStatus     },
587         { (char*) "defaultUserAssertionStatus", (char*) "()Z",                                                                                              (void*) (uintptr_t) &Java_java_lang_VMClassLoader_defaultUserAssertionStatus },
588         { (char*) "packageAssertionStatus0",    (char*) "(Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/util/Map;",                                          (void*) (uintptr_t) &Java_java_lang_VMClassLoader_packageAssertionStatus0    },
589         { (char*) "classAssertionStatus0",      (char*) "(Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/util/Map;",                                          (void*) (uintptr_t) &Java_java_lang_VMClassLoader_classAssertionStatus0      },
590         { (char*) "findLoadedClass",            (char*) "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;",                                     (void*) (uintptr_t) &Java_java_lang_VMClassLoader_findLoadedClass            },
591 };
592
593
594 /* _Jv_java_lang_VMClassLoader_init ********************************************
595
596    Register native functions.
597
598 *******************************************************************************/
599
600 void _Jv_java_lang_VMClassLoader_init(void)
601 {
602         utf* u = utf_new_char("java/lang/VMClassLoader");
603
604         NativeMethods& nm = VM::get_current()->get_nativemethods();
605         nm.register_methods(u, methods, NATIVE_METHODS_COUNT);
606 }
607
608
609 /*
610  * These are local overrides for various environment variables in Emacs.
611  * Please do not remove this and leave it at the end of the file, where
612  * Emacs will automagically detect them.
613  * ---------------------------------------------------------------------
614  * Local variables:
615  * mode: c++
616  * indent-tabs-mode: t
617  * c-basic-offset: 4
618  * tab-width: 4
619  * End:
620  * vim:noexpandtab:sw=4:ts=4:
621  */