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