* src/vm/loader.c (load_class_from_classloader): Add call to jvmti
[cacao.git] / src / native / vm / VMClassLoader.c
1 /* src/native/vm/VMClassLoader.c - java/lang/VMClassLoader
2
3    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Roman Obermaiser
28
29    Changes: Joseph Wenninger
30             Christian Thalinger
31             Edwin Steiner
32
33    $Id: VMClassLoader.c 5031 2006-06-14 18:36:22Z motse $
34
35 */
36
37
38 #include "config.h"
39
40 #include <sys/stat.h>
41
42 #include "vm/types.h"
43
44 #include "mm/memory.h"
45 #include "native/jni.h"
46 #include "native/native.h"
47 #include "native/include/java_lang_Class.h"
48 #include "native/include/java_lang_String.h"
49 #include "native/include/java_lang_ClassLoader.h"
50 #include "native/include/java_security_ProtectionDomain.h"
51 #include "native/include/java_util_Vector.h"
52 #include "toolbox/logging.h"
53 #include "vm/builtin.h"
54 #include "vm/class.h"
55 #include "vm/classcache.h"
56 #include "vm/exceptions.h"
57 #include "vm/initialize.h"
58 #include "vm/linker.h"
59 #include "vm/loader.h"
60 #include "vm/options.h"
61 #include "vm/statistics.h"
62 #include "vm/stringlocal.h"
63 #include "vm/suck.h"
64 #include "vm/vm.h"
65 #include "vm/zip.h"
66 #include "vm/jit/asmpart.h"
67
68 #if defined(ENABLE_JVMTI)
69 #include "native/jvmti/cacaodbg.h"
70 #endif
71
72
73 /*
74  * Class:     java/lang/VMClassLoader
75  * Method:    defineClass
76  * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;
77  */
78 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_defineClass(JNIEnv *env, jclass clazz, java_lang_ClassLoader *cl, java_lang_String *name, java_bytearray *data, s4 offset, s4 len, java_security_ProtectionDomain *pd)
79 {
80         classinfo   *c;
81         classinfo   *r;
82         classbuffer *cb;
83         utf         *utfname;
84 #if defined(ENABLE_JVMTI)
85         jint new_class_data_len = 0;
86         unsigned char* new_class_data = NULL;
87 #endif
88
89         /* check if data was passed */
90
91         if (data == NULL) {
92                 exceptions_throw_nullpointerexception();
93                 return NULL;
94         }
95
96         /* check the indexes passed */
97
98         if ((offset < 0) || (len < 0) || ((offset + len) > data->header.size)) {
99                 exceptions_throw_arrayindexoutofboundsexception();
100                 return NULL;
101         }
102
103         if (name) {
104                 /* convert '.' to '/' in java string */
105
106                 utfname = javastring_toutf(name, true);
107                 
108                 /* check if this class has already been defined */
109
110                 c = classcache_lookup_defined_or_initiated((java_objectheader *) cl, utfname);
111                 if (c) {
112                         *exceptionptr =
113                                 exceptions_new_linkageerror("duplicate class definition: ",c);
114                         return NULL;
115                 }
116         } 
117         else {
118                 utfname = NULL;
119         }
120
121
122 #if defined(ENABLE_JVMTI)
123         /* fire Class File Load Hook JVMTI event */
124         if (jvmti) jvmti_ClassFileLoadHook(utfname, len, (unsigned char*)data->data, 
125                                                         (java_objectheader *)cl, (java_objectheader *)pd, 
126                                                         &new_class_data_len, &new_class_data);
127 #endif
128
129
130         /* create a new classinfo struct */
131
132         c = class_create_classinfo(utfname);
133
134 #if defined(ENABLE_STATISTICS)
135         /* measure time */
136
137         if (opt_getloadingtime)
138                 loadingtime_start();
139 #endif
140
141         /* build a classbuffer with the given data */
142
143         cb = NEW(classbuffer);
144         cb->class = c;
145 #if defined(ENABLE_JVMTI)
146         /* check if the JVMTI wants to modify the class */
147         if (new_class_data == NULL) {
148 #endif
149         cb->size  = len;
150         cb->data  = (u1 *) &data->data[offset];
151 #if defined(ENABLE_JVMTI)
152         } else {
153                 cb->size  = new_class_data_len;
154                 cb->data  = (u1 *) new_class_data;
155         }
156 #endif
157         cb->pos   = cb->data;
158
159         /* preset the defining classloader */
160
161         c->classloader = (java_objectheader *) cl;
162
163         /* load the class from this buffer */
164
165         r = load_class_from_classbuffer(cb);
166
167         /* free memory */
168
169         FREE(cb, classbuffer);
170
171 #if defined(ENABLE_STATISTICS)
172         /* measure time */
173
174         if (opt_getloadingtime)
175                 loadingtime_stop();
176 #endif
177
178         if (!r) {
179                 /* If return value is NULL, we had a problem and the class is not   */
180                 /* loaded. */
181                 /* now free the allocated memory, otherwise we could run into a DOS */
182
183                 class_free(c);
184
185                 return NULL;
186         }
187
188         /* set ProtectionDomain */
189
190         c->object.pd = pd;
191
192         /* Store the newly defined class in the class cache. This call also       */
193         /* checks whether a class of the same name has already been defined by    */
194         /* the same defining loader, and if so, replaces the newly created class  */
195         /* by the one defined earlier.                                            */
196         /* Important: The classinfo given to classcache_store must be             */
197         /*            fully prepared because another thread may return this       */
198         /*            pointer after the lookup at to top of this function         */
199         /*            directly after the class cache lock has been released.      */
200
201         c = classcache_store((java_objectheader *)cl,c,true);
202
203         return (java_lang_Class *) c;
204 }
205
206
207 /*
208  * Class:     java/lang/VMClassLoader
209  * Method:    getPrimitiveClass
210  * Signature: (C)Ljava/lang/Class;
211  */
212 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_getPrimitiveClass(JNIEnv *env, jclass clazz, s4 type)
213 {
214         classinfo *c;
215
216         /* get primitive class */
217
218         switch (type) {
219         case 'I':
220                 c = primitivetype_table[PRIMITIVETYPE_INT].class_primitive;
221                 break;
222         case 'J':
223                 c = primitivetype_table[PRIMITIVETYPE_LONG].class_primitive;
224                 break;
225         case 'F':
226                 c = primitivetype_table[PRIMITIVETYPE_FLOAT].class_primitive;
227                 break;
228         case 'D':
229                 c = primitivetype_table[PRIMITIVETYPE_DOUBLE].class_primitive;
230                 break;
231         case 'B':
232                 c = primitivetype_table[PRIMITIVETYPE_BYTE].class_primitive;
233                 break;
234         case 'C':
235                 c = primitivetype_table[PRIMITIVETYPE_CHAR].class_primitive;
236                 break;
237         case 'S':
238                 c = primitivetype_table[PRIMITIVETYPE_SHORT].class_primitive;
239                 break;
240         case 'Z':
241                 c = primitivetype_table[PRIMITIVETYPE_BOOLEAN].class_primitive;
242                 break;
243         case 'V':
244                 c = primitivetype_table[PRIMITIVETYPE_VOID].class_primitive;
245                 break;
246         default:
247                 *exceptionptr = new_exception(string_java_lang_ClassNotFoundException);
248                 c = NULL;
249         }
250
251         return (java_lang_Class *) c;
252 }
253
254
255 /*
256  * Class:     java/lang/VMClassLoader
257  * Method:    resolveClass
258  * Signature: (Ljava/lang/Class;)V
259  */
260 JNIEXPORT void JNICALL Java_java_lang_VMClassLoader_resolveClass(JNIEnv *env, jclass clazz, java_lang_Class *c)
261 {
262         classinfo *ci;
263
264         ci = (classinfo *) c;
265
266         if (!ci) {
267                 exceptions_throw_nullpointerexception();
268                 return;
269         }
270
271         /* link the class */
272
273         if (!(ci->state & CLASS_LINKED))
274                 (void) link_class(ci);
275
276         return;
277 }
278
279
280 /*
281  * Class:     java/lang/VMClassLoader
282  * Method:    loadClass
283  * Signature: (Ljava/lang/String;Z)Ljava/lang/Class;
284  */
285 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_loadClass(JNIEnv *env, jclass clazz, java_lang_String *name, jboolean resolve)
286 {
287         classinfo *c;
288         utf *u;
289
290         if (name == NULL) {
291                 exceptions_throw_nullpointerexception();
292                 return NULL;
293         }
294
295         /* create utf string in which '.' is replaced by '/' */
296
297         u = javastring_toutf(name, true);
298
299         /* load class */
300
301         if (!(c = load_class_bootstrap(u)))
302                 goto exception;
303
304         /* resolve class -- if requested */
305
306 /*      if (resolve) */
307                 if (!link_class(c))
308                         goto exception;
309
310         return (java_lang_Class *) c;
311
312  exception:
313         c = (*exceptionptr)->vftbl->class;
314         
315         /* if the exception is a NoClassDefFoundError, we replace it with a
316            ClassNotFoundException, otherwise return the exception */
317
318         if (c == class_java_lang_NoClassDefFoundError) {
319                 /* clear exceptionptr, because builtin_new checks for 
320                    ExceptionInInitializerError */
321                 *exceptionptr = NULL;
322
323                 *exceptionptr =
324                         new_exception_javastring(string_java_lang_ClassNotFoundException, name);
325         }
326
327         return NULL;
328 }
329
330
331 /*
332  * Class:     java/lang/VMClassLoader
333  * Method:    nativeGetResources
334  * Signature: (Ljava/lang/String;)Ljava/util/Vector;
335  */
336 JNIEXPORT java_util_Vector* JNICALL Java_java_lang_VMClassLoader_nativeGetResources(JNIEnv *env, jclass clazz, java_lang_String *name)
337 {
338         jobject               o;         /* vector being created     */
339         methodinfo           *m;         /* "add" method of vector   */
340         java_lang_String     *path;      /* path to be added         */
341         list_classpath_entry *lce;       /* classpath entry          */
342         utf                  *utfname;   /* utf to look for          */
343         char                 *buffer;    /* char buffer              */
344         char                 *namestart; /* start of name to use     */
345         char                 *tmppath;   /* temporary buffer         */
346         s4                    namelen;   /* length of name to use    */
347         s4                    searchlen; /* length of name to search */
348         s4                    bufsize;   /* size of buffer allocated */
349         s4                    pathlen;   /* name of path to assemble */
350         struct stat           buf;       /* buffer for stat          */
351         jboolean              ret;       /* return value of "add"    */
352
353         /* get the resource name as utf string */
354
355         utfname = javastring_toutf(name, false);
356         if (!utfname)
357                 return NULL;
358
359         /* copy it to a char buffer */
360
361         namelen = utf_bytes(utfname);
362         searchlen = namelen;
363         bufsize = namelen + strlen("0");
364         buffer = MNEW(char, bufsize);
365
366         utf_copy(buffer, utfname);
367         namestart = buffer;
368
369         /* skip leading '/' */
370
371         if (namestart[0] == '/') {
372                 namestart++;
373                 namelen--;
374                 searchlen--;
375         }
376
377         /* remove trailing `.class' */
378
379         if (namelen >= 6 && strcmp(namestart + (namelen - 6), ".class") == 0) {
380                 searchlen -= 6;
381         }
382
383         /* create a new needle to look for, if necessary */
384
385         if (searchlen != bufsize-1) {
386                 utfname = utf_new(namestart, searchlen);
387                 if (utfname == NULL)
388                         goto return_NULL;
389         }
390                         
391         /* new Vector() */
392
393         o = native_new_and_init(class_java_util_Vector);
394
395         if (!o)
396                 goto return_NULL;
397
398         /* get Vector.add() method */
399
400         m = class_resolveclassmethod(class_java_util_Vector,
401                                                                  utf_add,
402                                                                  utf_new_char("(Ljava/lang/Object;)Z"),
403                                                                  NULL,
404                                                                  true);
405
406         if (!m)
407                 goto return_NULL;
408
409         /* iterate over all classpath entries */
410
411         for (lce = list_first(list_classpath_entries); lce != NULL;
412                  lce = list_next(list_classpath_entries, lce)) {
413                 /* clear path pointer */
414                 path = NULL;
415
416 #if defined(ENABLE_ZLIB)
417                 if (lce->type == CLASSPATH_ARCHIVE) {
418
419                         if (zip_find(lce, utfname)) {
420                                 pathlen = strlen("jar:file://") + lce->pathlen + strlen("!/") +
421                                         namelen + strlen("0");
422
423                                 tmppath = MNEW(char, pathlen);
424
425                                 sprintf(tmppath, "jar:file://%s!/%s", lce->path, namestart);
426                                 path = javastring_new_from_utf_string(tmppath),
427
428                                 MFREE(tmppath, char, pathlen);
429                         }
430
431                 } else {
432 #endif /* defined(ENABLE_ZLIB) */
433                         pathlen = strlen("file://") + lce->pathlen + namelen + strlen("0");
434
435                         tmppath = MNEW(char, pathlen);
436
437                         sprintf(tmppath, "file://%s%s", lce->path, namestart);
438
439                         /* Does this file exist? */
440
441                         if (stat(tmppath + strlen("file://") - 1, &buf) == 0)
442                                 if (!S_ISDIR(buf.st_mode))
443                                         path = javastring_new_from_utf_string(tmppath);
444
445                         MFREE(tmppath, char, pathlen);
446 #if defined(ENABLE_ZLIB)
447                 }
448 #endif
449
450                 /* if a resource was found, add it to the vector */
451
452                 if (path) {
453                         ret = vm_call_method_int(m, o, path);
454
455                         if (*exceptionptr)
456                                 goto return_NULL;
457
458                         if (ret == 0) 
459                                 goto return_NULL;
460                 }
461         }
462
463         MFREE(buffer, char, bufsize);
464
465         return (java_util_Vector *) o;
466
467 return_NULL:
468         MFREE(buffer, char, bufsize);
469
470         return NULL;
471 }
472
473
474 /*
475  * Class:     java/lang/VMClassLoader
476  * Method:    findLoadedClass
477  * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;
478  */
479 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_findLoadedClass(JNIEnv *env, jclass clazz, java_lang_ClassLoader *cl, java_lang_String *name)
480 {
481         classinfo *c;
482         utf       *u;
483
484         /* replace `.' by `/', this is required by the classcache */
485
486         u = javastring_toutf(name, true);
487
488         /* lookup for defining classloader */
489
490         c = classcache_lookup_defined((classloader *) cl, u);
491
492         /* if not found, lookup for initiating classloader */
493
494         if (c == NULL)
495                 c = classcache_lookup((classloader *) cl, u);
496
497         return (java_lang_Class *) c;
498 }
499
500
501 /*
502  * These are local overrides for various environment variables in Emacs.
503  * Please do not remove this and leave it at the end of the file, where
504  * Emacs will automagically detect them.
505  * ---------------------------------------------------------------------
506  * Local variables:
507  * mode: c
508  * indent-tabs-mode: t
509  * c-basic-offset: 4
510  * tab-width: 4
511  * End:
512  * vim:noexpandtab:sw=4:ts=4:
513  */