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