Fix Java long (64 bit) operations, add missing ones, fix compiler warnings
[jamvm-avr32-jem.git] / src / dll.c
blob652e0eb19a63377d2732cc38da21b27c827dc35d
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 #ifdef JEM
176 * Since native method would be invoked in separate stack storage in
177 * JEM, still use resolveNativeWrapper as our native_invoker here,
178 * which would pay off the performance lost
180 return (void*)methods[i].method;
181 #else
182 /* Found it -- set the invoker to the native method */
183 return mb->native_invoker = (void*)methods[i].method;
184 #endif
188 return NULL;
191 void *resolveNativeMethod(MethodBlock *mb) {
192 void *func;
194 if(verbose) {
195 char *classname = slash2dots(CLASS_CB(mb->class)->name);
196 jam_printf("[Dynamic-linking native method %s.%s ... ", classname, mb->name);
197 sysFree(classname);
200 /* First see if it's an internal native method */
201 func = lookupInternal(mb);
203 #ifndef NO_JNI
204 if(func == NULL)
205 func = lookupLoadedDlls(mb);
206 #endif
208 if(verbose)
209 jam_printf("]\n");
211 return func;
214 uintptr_t *resolveNativeWrapper(Class *class, MethodBlock *mb, uintptr_t *ostack) {
215 void *func = resolveNativeMethod(mb);
217 if(func == NULL) {
218 signalException("java/lang/UnsatisfiedLinkError", mb->name);
219 return ostack;
221 #ifdef JEM
223 * In order to avoid the overhead to modify each native method
224 * implementation, we modify the JamVM's native invoker wrapper.
225 * Since all objrefs/arrayrefs residing in ostack are all JEM aware,
226 * JamVM's native methods only accept JamVM's "Object*". So here, we
227 * prepare a separate temp stack storage, layout as below:
228 * | RET2 |
229 * | RET1 | --- used to store return value(32/64bit)
230 * | ARGN |
231 * | ... |
232 * | ARG1 | --- method arguments
233 * On return, the return value should be copied back to original ostack
234 * and objrefs/arrayrefs should be restored into JEM type
236 uint32_t *ret_stack, *temp;
237 int i;
238 uint32_t *temp_stack = sysMalloc((mb->args_count + 2) * sizeof(uint32_t));
240 memcpy(temp_stack, ostack, mb->args_count * sizeof(uint32_t));
242 //check if it is an valid object ref (see alloc.c)
243 #define OBJECT_GRAIN 8
244 #define IS_OBJECT(ptr) !(((uintptr_t)(ptr))&(OBJECT_GRAIN-1))
246 TRACE("DLL: invoke native method (%s:%s) %d on JEM\n", mb->name, mb->type, mb->args_count);
248 extern void *getHeapBase(void);
249 //scan arguments
250 for(i = 0; i < mb->args_count; i++){
251 if(temp_stack[i] != 0x0 && temp_stack[i] > (uint32_t)getHeapBase()){
252 Object *obj = JAM_OBJECT((uintptr_t *)temp_stack[i]);
253 if(!IS_OBJECT(obj))
254 obj = JAM_ARRAY((uintptr_t *)temp_stack[i]);
256 if(!JAM_ON_STACK || IS_JAM_OBJECT(obj))
257 temp_stack[i] = (uint32_t)obj;
261 temp = temp_stack;
263 ret_stack = (*(uintptr_t *(*)(Class*, MethodBlock*, uintptr_t*))func)(class, mb, temp_stack);
265 TRACE("DLL: native method return %x\n", ret_stack);
266 ostack += mb->args_count;
267 /* copy result to ostack */
268 switch(*(strchr(mb->type,')')+1)){
269 case 'J':
270 case 'D':
271 //64 bits
272 ostack_push_u64(NULL, 0, ostack, ret_stack - 2);
273 break;
274 case 'L':
275 //objref
276 TRACE("DLL: return objref\n");
277 ostack_push_u32(NULL, 0, ostack, *(ret_stack - 1) ? (uint32_t)INST_DATA((Object*)*(ret_stack - 1)) : 0x0);
278 break;
279 case '[':
280 //array ref
281 TRACE("DLL :return arrayref\n");
282 ostack_push_u32(NULL, 0, ostack, *(ret_stack - 1) ? (uint32_t)ARRAY_DATA((Object*)*(ret_stack - 1)) : 0x0);
283 break;
284 case 'V':
285 //void
286 break;
287 default:
288 //32 bits
289 ostack_push_u32(NULL, 0, ostack, *(ret_stack - 1));
290 break;
293 TRACE("DLL: native invoker quit\n");
294 sysFree(temp);
295 return ostack;
297 #else
298 return (*(uintptr_t *(*)(Class*, MethodBlock*, uintptr_t*))func)(class, mb, ostack);
299 #endif
302 void initialiseDll(InitArgs *args) {
303 #ifndef NO_JNI
304 /* Init hash table, and create lock */
305 initHashTable(hash_table, HASHTABSZE, TRUE);
306 #endif
307 verbose = args->verbosedll;
310 #ifndef NO_JNI
311 typedef struct {
312 char *name;
313 void *handle;
314 Object *loader;
315 } DllEntry;
317 int dllNameHash(char *name) {
318 int hash = 0;
320 while(*name)
321 hash = hash * 37 + *name++;
323 return hash;
326 int resolveDll(char *name, Object *loader) {
327 DllEntry *dll;
329 TRACE("<DLL: Attempting to resolve library %s>\n", name);
331 #define HASH(ptr) dllNameHash(ptr)
332 #define COMPARE(ptr1, ptr2, hash1, hash2) \
333 ((hash1 == hash2) && (strcmp(ptr1, ptr2->name) == 0))
334 #define PREPARE(ptr) ptr
335 #define SCAVENGE(ptr) FALSE
336 #define FOUND(ptr) ptr
338 /* Do not add if absent, no scavenge, locked */
339 findHashEntry(hash_table, name, dll, FALSE, FALSE, TRUE);
341 if(dll == NULL) {
342 DllEntry *dll2;
343 void *onload, *handle = nativeLibOpen(name);
345 if(handle == NULL)
346 return FALSE;
348 TRACE("<DLL: Successfully opened library %s>\n", name);
350 if((onload = nativeLibSym(handle, "JNI_OnLoad")) != NULL) {
351 int ver = (*(jint (*)(JavaVM*, void*))onload)(&invokeIntf, NULL);
353 if(ver != JNI_VERSION_1_2 && ver != JNI_VERSION_1_4) {
354 TRACE("<DLL: JNI_OnLoad returned unsupported version %d.\n>", ver);
355 return FALSE;
359 dll = (DllEntry*)sysMalloc(sizeof(DllEntry));
360 dll->name = strcpy((char*)sysMalloc(strlen(name)+1), name);
361 dll->handle = handle;
362 dll->loader = loader;
364 #undef HASH
365 #undef COMPARE
366 #define HASH(ptr) dllNameHash(ptr->name)
367 #define COMPARE(ptr1, ptr2, hash1, hash2) \
368 ((hash1 == hash2) && (strcmp(ptr1->name, ptr2->name) == 0))
370 /* Add if absent, no scavenge, locked */
371 findHashEntry(hash_table, dll, dll2, TRUE, FALSE, TRUE);
372 } else
373 if(dll->loader != loader)
374 return FALSE;
376 return TRUE;
379 char *getDllPath() {
380 char *env = nativeLibPath();
381 return env ? env : "";
384 char *getBootDllPath() {
385 return CLASSPATH_INSTALL_DIR"/lib/classpath";
388 char *getDllName(char *name) {
389 return nativeLibMapName(name);
392 void *lookupLoadedDlls0(char *name, Object *loader) {
393 TRACE("<DLL: Looking up %s loader %x in loaded DLL's>\n", name, loader);
395 #define ITERATE(ptr) \
397 DllEntry *dll = (DllEntry*)ptr; \
398 if(dll->loader == loader) { \
399 void *sym = nativeLibSym(dll->handle, name); \
400 if(sym != NULL) \
401 return sym; \
405 hashIterate(hash_table);
406 return NULL;
409 void unloadDll(DllEntry *dll) {
410 void *on_unload;
412 TRACE("<DLL: Unloading DLL %s\n", dll->name);
414 if((on_unload = nativeLibSym(dll->handle, "JNI_OnUnload")) != NULL)
415 (*(void (*)(JavaVM*, void*))on_unload)(&invokeIntf, NULL);
417 nativeLibClose(dll->handle);
418 sysFree(dll);
421 #undef ITERATE
422 #define ITERATE(ptr) \
424 DllEntry *dll = (DllEntry*)ptr; \
425 if(isMarked(dll->loader)) \
426 threadReference(&dll->loader); \
429 void threadLiveClassLoaderDlls() {
430 hashIterate(hash_table);
433 void unloadClassLoaderDlls(Object *loader) {
434 int unloaded = 0;
436 TRACE("<DLL: Unloading DLLs for loader %x\n", loader);
438 #undef ITERATE
439 #define ITERATE(ptr) \
441 DllEntry *dll = (DllEntry*)*ptr; \
442 if(dll->loader == loader) { \
443 unloadDll(dll); \
444 *ptr = NULL; \
445 unloaded++; \
449 hashIterateP(hash_table);
451 if(unloaded) {
452 int size;
454 /* Update count to remaining number of DLLs */
455 hash_table.hash_count -= unloaded;
457 /* Calculate nearest multiple of 2 larger than count */
458 for(size = 1; size < hash_table.hash_count; size <<= 1);
460 /* Ensure new table is less than 2/3 full */
461 size = hash_table.hash_count*3 > size*2 ? size<< 1 : size;
463 resizeHash(&hash_table, size);
467 static void *env = &Jam_JNINativeInterface;
469 uintptr_t *callJNIWrapper(Class *class, MethodBlock *mb, uintptr_t *ostack) {
470 TRACE("<DLL: Calling JNI method %s.%s%s>\n", CLASS_CB(class)->name, mb->name, mb->type);
472 if(!initJNILrefs())
473 return NULL;
475 return callJNIMethod(&env, (mb->access_flags & ACC_STATIC) ? class : NULL,
476 mb->type, mb->native_extra_arg, ostack, mb->code, mb->args_count);
479 void *lookupLoadedDlls(MethodBlock *mb) {
480 Object *loader = (CLASS_CB(mb->class))->class_loader;
481 char *mangled = mangleClassAndMethodName(mb);
482 void *func;
484 func = lookupLoadedDlls0(mangled, loader);
486 if(func == NULL) {
487 char *mangledSig = mangleSignature(mb);
488 char *fullyMangled = (char*)sysMalloc(strlen(mangled)+strlen(mangledSig)+3);
490 sprintf(fullyMangled, "%s__%s", mangled, mangledSig);
491 func = lookupLoadedDlls0(fullyMangled, loader);
493 sysFree(fullyMangled);
494 sysFree(mangledSig);
497 sysFree(mangled);
499 if(func) {
500 if(verbose)
501 jam_printf("JNI");
503 mb->code = (unsigned char *) func;
504 mb->native_extra_arg = nativeExtraArg(mb);
505 #ifdef JEM
506 return (void*)callJNIWrapper;
507 #else
508 return mb->native_invoker = (void*) callJNIWrapper;
509 #endif
512 return NULL;
514 #endif