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.
28 #include "arch/avr32_jem.h"
35 /* Set by call to initialise -- if true, prints out
36 results of dynamic method resolution */
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
);
51 /* Trace library loading and method lookup */
53 #define TRACE(fmt, ...) jam_printf(fmt, ## __VA_ARGS__)
55 #define TRACE(fmt, ...)
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
];
78 mangledLen
+= isalnum(c
) ? 1 : 6;
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
];
111 mngldPtr
+= sprintf(mngldPtr
, "_0%04x", c
);
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);
128 sprintf(nonMangled
, "Java/%s/%s", classname
, methodname
);
130 mangled
= mangleString(nonMangled
);
135 char *mangleSignature(MethodBlock
*mb
) {
136 char *type
= mb
->type
;
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
);
153 void *lookupInternal(MethodBlock
*mb
) {
154 ClassBlock
*cb
= CLASS_CB(mb
->class);
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
) {
172 jam_printf("internal");
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
;
182 /* Found it -- set the invoker to the native method */
183 return mb
->native_invoker
= (void*)methods
[i
].method
;
191 void *resolveNativeMethod(MethodBlock
*mb
) {
195 char *classname
= slash2dots(CLASS_CB(mb
->class)->name
);
196 jam_printf("[Dynamic-linking native method %s.%s ... ", classname
, mb
->name
);
200 /* First see if it's an internal native method */
201 func
= lookupInternal(mb
);
205 func
= lookupLoadedDlls(mb
);
214 uintptr_t *resolveNativeWrapper(Class
*class, MethodBlock
*mb
, uintptr_t *ostack
) {
215 void *func
= resolveNativeMethod(mb
);
218 signalException("java/lang/UnsatisfiedLinkError", mb
->name
);
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:
229 * | RET1 | --- used to store return value(32/64bit)
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
;
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);
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
]);
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
;
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)){
272 ostack_push_u64(NULL
, 0, ostack
, *(ret_stack
- 2));
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);
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);
289 ostack_push_u32(NULL
, 0, ostack
, *(ret_stack
- 1));
293 TRACE("DLL: native invoker quit\n");
298 return (*(uintptr_t *(*)(Class
*, MethodBlock
*, uintptr_t*))func
)(class, mb
, ostack
);
302 void initialiseDll(InitArgs
*args
) {
304 /* Init hash table, and create lock */
305 initHashTable(hash_table
, HASHTABSZE
, TRUE
);
307 verbose
= args
->verbosedll
;
317 int dllNameHash(char *name
) {
321 hash
= hash
* 37 + *name
++;
326 int resolveDll(char *name
, Object
*loader
) {
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
);
343 void *onload
, *handle
= nativeLibOpen(name
);
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
);
359 dll
= (DllEntry
*)sysMalloc(sizeof(DllEntry
));
360 dll
->name
= strcpy((char*)sysMalloc(strlen(name
)+1), name
);
361 dll
->handle
= handle
;
362 dll
->loader
= loader
;
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
);
373 if(dll
->loader
!= loader
)
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); \
405 hashIterate(hash_table
);
409 void unloadDll(DllEntry
*dll
) {
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
);
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
) {
436 TRACE("<DLL: Unloading DLLs for loader %x\n", loader
);
439 #define ITERATE(ptr) \
441 DllEntry *dll = (DllEntry*)*ptr; \
442 if(dll->loader == loader) { \
449 hashIterateP(hash_table
);
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
);
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
);
484 func
= lookupLoadedDlls0(mangled
, loader
);
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
);
503 mb
->code
= (unsigned char *) func
;
504 mb
->native_extra_arg
= nativeExtraArg(mb
);
506 return (void*)callJNIWrapper
;
508 return mb
->native_invoker
= (void*) callJNIWrapper
;