3abcd66a9047377a5228f96f29a04d1ba27b281a
[cacao.git] / src / native / vm / VMClassLoader.c
1 /* src/native/vm/VMClassLoader.c - java/lang/VMClassLoader
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    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., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Roman Obermaiser
28
29    Changes: Joseph Wenninger
30             Christian Thalinger
31             Edwin Steiner
32
33    $Id: VMClassLoader.c 4151 2006-01-12 21:13:27Z twisti $
34
35 */
36
37
38 #include <sys/stat.h>
39
40 #include "config.h"
41 #include "vm/types.h"
42
43 #include "mm/memory.h"
44 #include "native/jni.h"
45 #include "native/native.h"
46 #include "native/include/java_lang_Class.h"
47 #include "native/include/java_lang_String.h"
48 #include "native/include/java_lang_ClassLoader.h"
49 #include "native/include/java_security_ProtectionDomain.h"
50 #include "native/include/java_util_Vector.h"
51 #include "toolbox/logging.h"
52 #include "vm/builtin.h"
53 #include "vm/class.h"
54 #include "vm/classcache.h"
55 #include "vm/exceptions.h"
56 #include "vm/initialize.h"
57 #include "vm/linker.h"
58 #include "vm/loader.h"
59 #include "vm/options.h"
60 #include "vm/statistics.h"
61 #include "vm/stringlocal.h"
62 #include "vm/suck.h"
63 #include "vm/zip.h"
64 #include "vm/jit/asmpart.h"
65
66
67 /*
68  * Class:     java/lang/VMClassLoader
69  * Method:    defineClass
70  * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;
71  */
72 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)
73 {
74         classinfo   *c;
75         classinfo   *r;
76         classbuffer *cb;
77         utf         *utfname;
78
79         /* check if data was passed */
80
81         if (data == NULL) {
82                 exceptions_throw_nullpointerexception();
83                 return NULL;
84         }
85
86         /* check the indexes passed */
87
88         if ((offset < 0) || (len < 0) || ((offset + len) > data->header.size)) {
89                 exceptions_throw_arrayindexoutofboundsexception();
90                 return NULL;
91         }
92
93         if (name) {
94                 /* convert '.' to '/' in java string */
95
96                 utfname = javastring_toutf(name, true);
97                 
98                 /* check if this class has already been defined */
99
100                 c = classcache_lookup_defined_or_initiated((java_objectheader *) cl, utfname);
101                 if (c) {
102                         *exceptionptr =
103                                 exceptions_new_linkageerror("duplicate class definition: ",c);
104                         return NULL;
105                 }
106         } 
107         else {
108                 utfname = NULL;
109         }
110
111         /* create a new classinfo struct */
112
113         c = class_create_classinfo(utfname);
114
115 #if defined(ENABLE_STATISTICS)
116         /* measure time */
117
118         if (getloadingtime)
119                 loadingtime_start();
120 #endif
121
122         /* build a classbuffer with the given data */
123
124         cb = NEW(classbuffer);
125         cb->class = c;
126         cb->size  = len;
127         cb->data  = (u1 *) &data->data[offset];
128         cb->pos   = cb->data;
129
130         /* preset the defining classloader */
131
132         c->classloader = (java_objectheader *) cl;
133
134         /* load the class from this buffer */
135
136         r = load_class_from_classbuffer(cb);
137
138         /* free memory */
139
140         FREE(cb, classbuffer);
141
142 #if defined(ENABLE_STATISTICS)
143         /* measure time */
144
145         if (getloadingtime)
146                 loadingtime_stop();
147 #endif
148
149         if (!r) {
150                 /* If return value is NULL, we had a problem and the class is not   */
151                 /* loaded. */
152                 /* now free the allocated memory, otherwise we could run into a DOS */
153
154                 class_free(c);
155
156                 return NULL;
157         }
158
159         /* set ProtectionDomain */
160
161         c->object.pd = pd;
162
163         /* Store the newly defined class in the class cache. This call also       */
164         /* checks whether a class of the same name has already been defined by    */
165         /* the same defining loader, and if so, replaces the newly created class  */
166         /* by the one defined earlier.                                            */
167         /* Important: The classinfo given to classcache_store_defined must be     */
168         /*            fully prepared because another thread may return this       */
169         /*            pointer after the lookup at to top of this function         */
170         /*            directly after the class cache lock has been released.      */
171
172         c = classcache_store_defined(c);
173
174         return (java_lang_Class *) c;
175 }
176
177
178 /*
179  * Class:     java/lang/VMClassLoader
180  * Method:    getPrimitiveClass
181  * Signature: (C)Ljava/lang/Class;
182  */
183 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_getPrimitiveClass(JNIEnv *env, jclass clazz, s4 type)
184 {
185         classinfo *c;
186
187         /* get primitive class */
188
189         switch (type) {
190         case 'I':
191                 c = primitivetype_table[PRIMITIVETYPE_INT].class_primitive;
192                 break;
193         case 'J':
194                 c = primitivetype_table[PRIMITIVETYPE_LONG].class_primitive;
195                 break;
196         case 'F':
197                 c = primitivetype_table[PRIMITIVETYPE_FLOAT].class_primitive;
198                 break;
199         case 'D':
200                 c = primitivetype_table[PRIMITIVETYPE_DOUBLE].class_primitive;
201                 break;
202         case 'B':
203                 c = primitivetype_table[PRIMITIVETYPE_BYTE].class_primitive;
204                 break;
205         case 'C':
206                 c = primitivetype_table[PRIMITIVETYPE_CHAR].class_primitive;
207                 break;
208         case 'S':
209                 c = primitivetype_table[PRIMITIVETYPE_SHORT].class_primitive;
210                 break;
211         case 'Z':
212                 c = primitivetype_table[PRIMITIVETYPE_BOOLEAN].class_primitive;
213                 break;
214         case 'V':
215                 c = primitivetype_table[PRIMITIVETYPE_VOID].class_primitive;
216                 break;
217         default:
218                 *exceptionptr = new_exception(string_java_lang_ClassNotFoundException);
219                 c = NULL;
220         }
221
222         return (java_lang_Class *) c;
223 }
224
225
226 /*
227  * Class:     java/lang/VMClassLoader
228  * Method:    resolveClass
229  * Signature: (Ljava/lang/Class;)V
230  */
231 JNIEXPORT void JNICALL Java_java_lang_VMClassLoader_resolveClass(JNIEnv *env, jclass clazz, java_lang_Class *c)
232 {
233         classinfo *ci;
234
235         ci = (classinfo *) c;
236
237         if (!ci) {
238                 exceptions_throw_nullpointerexception();
239                 return;
240         }
241
242         /* link the class */
243
244         if (!(ci->state & CLASS_LINKED))
245                 (void) link_class(ci);
246
247         return;
248 }
249
250
251 /*
252  * Class:     java/lang/VMClassLoader
253  * Method:    loadClass
254  * Signature: (Ljava/lang/String;Z)Ljava/lang/Class;
255  */
256 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_loadClass(JNIEnv *env, jclass clazz, java_lang_String *name, jboolean resolve)
257 {
258         classinfo *c;
259         utf *u;
260
261         if (!name) {
262                 exceptions_throw_nullpointerexception();
263                 return NULL;
264         }
265
266         /* create utf string in which '.' is replaced by '/' */
267
268         u = javastring_toutf(name, true);
269
270         /* load class */
271
272         if (!(c = load_class_bootstrap(u)))
273                 goto exception;
274
275         /* resolve class -- if requested */
276         /* XXX TWISTI: we do not support REAL (at runtime) lazy linking */
277 /*      if (resolve) { */
278                 if (!link_class(c))
279                         goto exception;
280 /*      } */
281
282         return (java_lang_Class *) c;
283
284  exception:
285         c = (*exceptionptr)->vftbl->class;
286         
287         /* if the exception is a NoClassDefFoundError, we replace it with a
288            ClassNotFoundException, otherwise return the exception */
289
290         if (c == class_java_lang_NoClassDefFoundError) {
291                 /* clear exceptionptr, because builtin_new checks for 
292                    ExceptionInInitializerError */
293                 *exceptionptr = NULL;
294
295                 *exceptionptr =
296                         new_exception_javastring(string_java_lang_ClassNotFoundException, name);
297         }
298
299         return NULL;
300 }
301
302
303 /*
304  * Class:     java/lang/VMClassLoader
305  * Method:    nativeGetResources
306  * Signature: (Ljava/lang/String;)Ljava/util/Vector;
307  */
308 JNIEXPORT java_util_Vector* JNICALL Java_java_lang_VMClassLoader_nativeGetResources(JNIEnv *env, jclass clazz, java_lang_String *name)
309 {
310         jobject               o;
311         methodinfo           *m;
312         java_lang_String     *path;
313         list_classpath_entry *lce;
314         utf                  *utfname;
315         char                 *charname;
316         char                 *end;
317         char                 *tmppath;
318         s4                    namelen;
319         s4                    pathlen;
320         struct stat           buf;
321         jboolean              ret;
322
323         /* get the resource name as utf string */
324
325         utfname = javastring_toutf(name, false);
326
327         namelen = utf_strlen(utfname) + strlen("0");
328         charname = MNEW(char, namelen);
329
330         utf_sprint(charname, utfname);
331
332         /* search for `.class', if found remove it */
333
334         if ((end = strstr(charname, ".class"))) {
335                 *end = '\0';
336                 utfname = utf_new_char(charname);
337
338                 /* little hack, but it should work */
339                 *end = '.';
340         }
341
342         /* new Vector() */
343
344         o = native_new_and_init(class_java_util_Vector);
345
346         if (!o)
347                 return NULL;
348
349         /* get Vector.add() method */
350
351         m = class_resolveclassmethod(class_java_util_Vector,
352                                                                  utf_add,
353                                                                  utf_new_char("(Ljava/lang/Object;)Z"),
354                                                                  NULL,
355                                                                  true);
356
357         if (!m)
358                 return NULL;
359
360         for (lce = list_first(list_classpath_entries); lce != NULL;
361                  lce = list_next(list_classpath_entries, lce)) {
362                 /* clear path pointer */
363                 path = NULL;
364
365 #if defined(ENABLE_ZLIB)
366                 if (lce->type == CLASSPATH_ARCHIVE) {
367
368                         if (zip_find(lce, utfname)) {
369                                 pathlen = strlen("jar:file://") + lce->pathlen + strlen("!/") +
370                                         namelen + strlen("0");
371
372                                 tmppath = MNEW(char, pathlen);
373
374                                 sprintf(tmppath, "jar:file://%s!/%s", lce->path, charname);
375                                 path = javastring_new_char(tmppath),
376
377                                 MFREE(tmppath, char, pathlen);
378                         }
379
380                 } else {
381 #endif /* defined(ENABLE_ZLIB) */
382                         pathlen = strlen("file://") + lce->pathlen + namelen + strlen("0");
383
384                         tmppath = MNEW(char, pathlen);
385
386                         sprintf(tmppath, "file://%s%s", lce->path, charname);
387
388                         if (stat(tmppath + strlen("file://") - 1, &buf) == 0)
389                                 path = javastring_new_char(tmppath),
390
391                         MFREE(tmppath, char, pathlen);
392 #if defined(ENABLE_ZLIB)
393                 }
394 #endif
395
396                 /* if a resource was found, add it to the vector */
397
398                 if (path) {
399                         ASM_CALLJAVAFUNCTION_INT(ret, m, o, path, NULL, NULL);
400
401                         if (!ret)
402                                 return NULL;
403                 }
404         }
405
406         return (java_util_Vector *) o;
407 }
408
409
410 /*
411  * Class:     java/lang/VMClassLoader
412  * Method:    findLoadedClass
413  * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;
414  */
415 JNIEXPORT java_lang_Class* JNICALL Java_java_lang_VMClassLoader_findLoadedClass(JNIEnv *env, jclass clazz, java_lang_ClassLoader *cl, java_lang_String *name)
416 {
417         classinfo *c;
418         utf       *u;
419
420         /* replace `.' by `/', this is required by the classcache */
421
422         u = javastring_toutf(name, true);
423
424         /* lookup for defining classloader */
425
426         c = classcache_lookup_defined((classloader *) cl, u);
427
428         /* if not found, lookup for initiating classloader */
429
430         if (c == NULL)
431                 c = classcache_lookup((classloader *) cl, u);
432
433         return (java_lang_Class *) c;
434 }
435
436
437 /*
438  * These are local overrides for various environment variables in Emacs.
439  * Please do not remove this and leave it at the end of the file, where
440  * Emacs will automagically detect them.
441  * ---------------------------------------------------------------------
442  * Local variables:
443  * mode: c
444  * indent-tabs-mode: t
445  * c-basic-offset: 4
446  * tab-width: 4
447  * End:
448  */