Whitespace fixes
[jamvm-avr32-jem.git] / src / dll.c
blob426ef8cb20efd726ff183da01af8a61b3b47b836
1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007
3 * Robert Lougher <rob@lougher.org.uk>.
5 * This file is part of JamVM.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
27 #include "jam.h"
28 #include "arch/avr32_jem.h"
30 #ifndef NO_JNI
31 #include "hash.h"
32 #include "jni.h"
33 #include "natives.h"
35 /* Set by call to initialise -- if true, prints out
36 results of dynamic method resolution */
37 static int verbose;
39 extern int nativeExtraArg(MethodBlock *mb);
40 extern uintptr_t *callJNIMethod(void *env, Class *class, char *sig, int extra,
41 uintptr_t *ostack, unsigned char *native_func, int args);
42 extern struct _JNINativeInterface Jam_JNINativeInterface;
43 extern int initJNILrefs();
44 extern JavaVM invokeIntf;
46 #define HASHTABSZE 1<<4
47 static HashTable hash_table;
48 void *lookupLoadedDlls(MethodBlock *mb);
49 #endif
51 /* Trace library loading and method lookup */
52 #ifdef TRACEDLL
53 #define TRACE(fmt, ...) jam_printf(fmt, ## __VA_ARGS__)
54 #else
55 #define TRACE(fmt, ...)
56 #endif
58 char *mangleString(char *utf8) {
59 int len = utf8Len(utf8);
60 unsigned short *unicode = (unsigned short*) sysMalloc(len * 2);
61 char *mangled, *mngldPtr;
62 int i, mangledLen = 0;
64 convertUtf8(utf8, unicode);
66 /* Work out the length of the mangled string */
68 for(i = 0; i < len; i++) {
69 unsigned short c = unicode[i];
70 switch(c) {
71 case '_':
72 case ';':
73 case '[':
74 mangledLen += 2;
75 break;
77 default:
78 mangledLen += isalnum(c) ? 1 : 6;
79 break;
83 mangled = mngldPtr = (char*) sysMalloc(mangledLen + 1);
85 /* Construct the mangled string */
87 for(i = 0; i < len; i++) {
88 unsigned short c = unicode[i];
89 switch(c) {
90 case '_':
91 *mngldPtr++ = '_';
92 *mngldPtr++ = '1';
93 break;
94 case ';':
95 *mngldPtr++ = '_';
96 *mngldPtr++ = '2';
97 break;
98 case '[':
99 *mngldPtr++ = '_';
100 *mngldPtr++ = '3';
101 break;
103 case '/':
104 *mngldPtr++ = '_';
105 break;
107 default:
108 if(isalnum(c))
109 *mngldPtr++ = c;
110 else
111 mngldPtr += sprintf(mngldPtr, "_0%04x", c);
112 break;
116 *mngldPtr = '\0';
118 sysFree(unicode);
119 return mangled;
122 char *mangleClassAndMethodName(MethodBlock *mb) {
123 char *classname = CLASS_CB(mb->class)->name;
124 char *methodname = mb->name;
125 char *nonMangled = (char*) sysMalloc(strlen(classname) + strlen(methodname) + 7);
126 char *mangled;
128 sprintf(nonMangled, "Java/%s/%s", classname, methodname);
130 mangled = mangleString(nonMangled);
131 sysFree(nonMangled);
132 return mangled;
135 char *mangleSignature(MethodBlock *mb) {
136 char *type = mb->type;
137 char *nonMangled;
138 char *mangled;
139 int i;
141 /* find ending ) */
142 for(i = strlen(type) - 1; type[i] != ')'; i--);
144 nonMangled = (char *) sysMalloc(i);
145 strncpy(nonMangled, type + 1, i - 1);
146 nonMangled[i - 1] = '\0';
148 mangled = mangleString(nonMangled);
149 sysFree(nonMangled);
150 return mangled;
153 void *lookupInternal(MethodBlock *mb) {
154 ClassBlock *cb = CLASS_CB(mb->class);
155 int i;
157 TRACE("<DLL: Looking up %s internally>\n", mb->name);
159 /* First try to locate the class */
160 for(i = 0; native_methods[i].classname &&
161 (strcmp(cb->name, native_methods[i].classname) != 0); i++);
163 if(native_methods[i].classname) {
164 VMMethod *methods = native_methods[i].methods;
166 /* Found the class -- now try to locate the method */
167 for(i = 0; methods[i].methodname &&
168 (strcmp(mb->name, methods[i].methodname) != 0); i++);
170 if(methods[i].methodname) {
171 if(verbose)
172 jam_printf("internal");
174 /* Found it -- set the invoker to the native method */
175 return mb->native_invoker = (void*)methods[i].method;
179 return NULL;
182 void *resolveNativeMethod(MethodBlock *mb) {
183 void *func;
185 if(verbose) {
186 char *classname = slash2dots(CLASS_CB(mb->class)->name);
187 jam_printf("[Dynamic-linking native method %s.%s ... ", classname, mb->name);
188 sysFree(classname);
191 /* First see if it's an internal native method */
192 func = lookupInternal(mb);
194 #ifndef NO_JNI
195 if(func == NULL)
196 func = lookupLoadedDlls(mb);
197 #endif
199 if(verbose)
200 jam_printf("]\n");
202 return func;
205 uintptr_t *resolveNativeWrapper(Class *class, MethodBlock *mb, uintptr_t *ostack) {
206 void *func = resolveNativeMethod(mb);
208 if(func == NULL) {
209 signalException("java/lang/UnsatisfiedLinkError", mb->name);
210 return ostack;
212 #ifdef JEM
214 * In order to avoid the overhead to modify each native method
215 * implementation, we modify the JamVM's native invoker wrapper.
216 * Since all objrefs/arrayrefs residing in ostack are all JEM aware,
217 * JamVM's native methods only accept JamVM's "Object*". So here, we
218 * prepare a separate temp stack storage, layout as below:
219 * | RET2 |
220 * | RET1 | --- used to store return value(32/64bit)
221 * | ARGN |
222 * | ... |
223 * | ARG1 | --- method arguments
224 * On return, the return value should be copied back to original ostack
225 * and objrefs/arrayrefs should be restored into JEM type
227 uint32_t *ret_stack, *temp;
228 int i;
229 uint32_t *temp_stack = sysMalloc((mb->args_count + 2) * sizeof(uint32_t));
231 memcpy(temp_stack, ostack, mb->args_count * sizeof(uint32_t));
233 //check if it is an valid object ref (see alloc.c)
234 #define OBJECT_GRAIN 8
235 #define IS_OBJECT(ptr) !(((uintptr_t)(ptr))&(OBJECT_GRAIN-1))
237 TRACE("DLL: invoke native method (%s:%s) %d on JEM\n", mb->name, mb->type, mb->args_count);
239 extern void *getHeapBase(void);
240 //scan arguments
241 for(i = 0; i < mb->args_count; i++){
242 if(temp_stack[i] != 0x0 && temp_stack[i] > (uint32_t)getHeapBase()){
243 Object *obj = JAM_OBJECT(temp_stack[i]);
244 if(!IS_OBJECT(obj))
245 obj = JAM_ARRAY(temp_stack[i]);
247 if(IS_JAM_OBJECT(obj))
248 temp_stack[i] = (uint32_t)obj;
252 temp = temp_stack;
254 ret_stack = (*(uintptr_t *(*)(Class*, MethodBlock*, uintptr_t*))func)(class, mb, temp_stack);
256 TRACE("DLL: native method return %x\n",ret_stack);
257 ostack += mb->args_count;
258 /* copy result to ostack */
259 switch(*(strchr(mb->type,')')+1)){
260 case 'J':
261 case 'D':
262 //64 bits
263 ostack_push_u64(NULL, 0, ostack, *(ret_stack - 2));
264 break;
265 case 'L':
266 //objref
267 TRACE("DLL: return objref\n");
268 ostack_push_u32(NULL, 0, ostack, (uint32_t)INST_DATA((Object*)*(ret_stack - 1)));
269 break;
270 case '[':
271 //array ref
272 TRACE("DLL :return arrayref\n");
273 ostack_push_u32(NULL, 0, ostack, (uint32_t)ARRAY_DATA((Object*)*(ret_stack - 1)));
274 break;
275 case 'V':
276 //void
277 break;
278 default:
279 //32 bits
280 ostack_push_u32(NULL, 0, ostack, *(ret_stack - 1));
281 break;
284 TRACE("DLL: native invoker quit\n");
285 sysFree(temp);
286 return ostack;
288 #else
289 return (*(uintptr_t *(*)(Class*, MethodBlock*, uintptr_t*))func)(class, mb, ostack);
290 #endif
293 void initialiseDll(InitArgs *args) {
294 #ifndef NO_JNI
295 /* Init hash table, and create lock */
296 initHashTable(hash_table, HASHTABSZE, TRUE);
297 #endif
298 verbose = args->verbosedll;
301 #ifndef NO_JNI
302 typedef struct {
303 char *name;
304 void *handle;
305 Object *loader;
306 } DllEntry;
308 int dllNameHash(char *name) {
309 int hash = 0;
311 while(*name)
312 hash = hash * 37 + *name++;
314 return hash;
317 int resolveDll(char *name, Object *loader) {
318 DllEntry *dll;
320 TRACE("<DLL: Attempting to resolve library %s>\n", name);
322 #define HASH(ptr) dllNameHash(ptr)
323 #define COMPARE(ptr1, ptr2, hash1, hash2) \
324 ((hash1 == hash2) && (strcmp(ptr1, ptr2->name) == 0))
325 #define PREPARE(ptr) ptr
326 #define SCAVENGE(ptr) FALSE
327 #define FOUND(ptr) ptr
329 /* Do not add if absent, no scavenge, locked */
330 findHashEntry(hash_table, name, dll, FALSE, FALSE, TRUE);
332 if(dll == NULL) {
333 DllEntry *dll2;
334 void *onload, *handle = nativeLibOpen(name);
336 if(handle == NULL)
337 return FALSE;
339 TRACE("<DLL: Successfully opened library %s>\n", name);
341 if((onload = nativeLibSym(handle, "JNI_OnLoad")) != NULL) {
342 int ver = (*(jint (*)(JavaVM*, void*))onload)(&invokeIntf, NULL);
344 if(ver != JNI_VERSION_1_2 && ver != JNI_VERSION_1_4) {
345 TRACE("<DLL: JNI_OnLoad returned unsupported version %d.\n>", ver);
346 return FALSE;
350 dll = (DllEntry*)sysMalloc(sizeof(DllEntry));
351 dll->name = strcpy((char*)sysMalloc(strlen(name)+1), name);
352 dll->handle = handle;
353 dll->loader = loader;
355 #undef HASH
356 #undef COMPARE
357 #define HASH(ptr) dllNameHash(ptr->name)
358 #define COMPARE(ptr1, ptr2, hash1, hash2) \
359 ((hash1 == hash2) && (strcmp(ptr1->name, ptr2->name) == 0))
361 /* Add if absent, no scavenge, locked */
362 findHashEntry(hash_table, dll, dll2, TRUE, FALSE, TRUE);
363 } else
364 if(dll->loader != loader)
365 return FALSE;
367 return TRUE;
370 char *getDllPath() {
371 char *env = nativeLibPath();
372 return env ? env : "";
375 char *getBootDllPath() {
376 return CLASSPATH_INSTALL_DIR"/lib/classpath";
379 char *getDllName(char *name) {
380 return nativeLibMapName(name);
383 void *lookupLoadedDlls0(char *name, Object *loader) {
384 TRACE("<DLL: Looking up %s loader %x in loaded DLL's>\n", name, loader);
386 #define ITERATE(ptr) \
388 DllEntry *dll = (DllEntry*)ptr; \
389 if(dll->loader == loader) { \
390 void *sym = nativeLibSym(dll->handle, name); \
391 if(sym != NULL) \
392 return sym; \
396 hashIterate(hash_table);
397 return NULL;
400 void unloadDll(DllEntry *dll) {
401 void *on_unload;
403 TRACE("<DLL: Unloading DLL %s\n", dll->name);
405 if((on_unload = nativeLibSym(dll->handle, "JNI_OnUnload")) != NULL)
406 (*(void (*)(JavaVM*, void*))on_unload)(&invokeIntf, NULL);
408 nativeLibClose(dll->handle);
409 sysFree(dll);
412 #undef ITERATE
413 #define ITERATE(ptr) \
415 DllEntry *dll = (DllEntry*)ptr; \
416 if(isMarked(dll->loader)) \
417 threadReference(&dll->loader); \
420 void threadLiveClassLoaderDlls() {
421 hashIterate(hash_table);
424 void unloadClassLoaderDlls(Object *loader) {
425 int unloaded = 0;
427 TRACE("<DLL: Unloading DLLs for loader %x\n", loader);
429 #undef ITERATE
430 #define ITERATE(ptr) \
432 DllEntry *dll = (DllEntry*)*ptr; \
433 if(dll->loader == loader) { \
434 unloadDll(dll); \
435 *ptr = NULL; \
436 unloaded++; \
440 hashIterateP(hash_table);
442 if(unloaded) {
443 int size;
445 /* Update count to remaining number of DLLs */
446 hash_table.hash_count -= unloaded;
448 /* Calculate nearest multiple of 2 larger than count */
449 for(size = 1; size < hash_table.hash_count; size <<= 1);
451 /* Ensure new table is less than 2/3 full */
452 size = hash_table.hash_count*3 > size*2 ? size<< 1 : size;
454 resizeHash(&hash_table, size);
458 static void *env = &Jam_JNINativeInterface;
460 uintptr_t *callJNIWrapper(Class *class, MethodBlock *mb, uintptr_t *ostack) {
461 TRACE("<DLL: Calling JNI method %s.%s%s>\n", CLASS_CB(class)->name, mb->name, mb->type);
463 if(!initJNILrefs())
464 return NULL;
466 return callJNIMethod(&env, (mb->access_flags & ACC_STATIC) ? class : NULL,
467 mb->type, mb->native_extra_arg, ostack, mb->code, mb->args_count);
470 void *lookupLoadedDlls(MethodBlock *mb) {
471 Object *loader = (CLASS_CB(mb->class))->class_loader;
472 char *mangled = mangleClassAndMethodName(mb);
473 void *func;
475 func = lookupLoadedDlls0(mangled, loader);
477 if(func == NULL) {
478 char *mangledSig = mangleSignature(mb);
479 char *fullyMangled = (char*)sysMalloc(strlen(mangled)+strlen(mangledSig)+3);
481 sprintf(fullyMangled, "%s__%s", mangled, mangledSig);
482 func = lookupLoadedDlls0(fullyMangled, loader);
484 sysFree(fullyMangled);
485 sysFree(mangledSig);
488 sysFree(mangled);
490 if(func) {
491 if(verbose)
492 jam_printf("JNI");
494 mb->code = (unsigned char *) func;
495 mb->native_extra_arg = nativeExtraArg(mb);
496 return mb->native_invoker = (void*) callJNIWrapper;
499 return NULL;
501 #endif