jamvm
view src/dll.c @ 402:24373fc1d951
Add additional tracing support.
2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>
* .hgignore: Updated with autogen.sh output.
* configure.ac: Add new trace options.
* src/class.c,
* src/excep.c,
* src/natives.c,
* src/resolve.c: Add trace support.
* src/jam.h,
* src/dll.c,
* src/os/linux/os.c: Add support for reporting
the linking error using dlerror.
2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>
* .hgignore: Updated with autogen.sh output.
* configure.ac: Add new trace options.
* src/class.c,
* src/excep.c,
* src/natives.c,
* src/resolve.c: Add trace support.
* src/jam.h,
* src/dll.c,
* src/os/linux/os.c: Add support for reporting
the linking error using dlerror.
| author | andrew |
|---|---|
| date | Tue Aug 05 05:46:09 2008 +0100 (2008-08-05) |
| parents | 5baaa2bcac6b |
| children |
line source
1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
3 * Robert Lougher <rob@lougher.org.uk>.
4 *
5 * This file is part of JamVM.
6 *
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.
11 *
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.
16 *
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.
20 */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
27 #include "jam.h"
29 #ifndef NO_JNI
30 #include "hash.h"
31 #include "jni.h"
32 #include "natives.h"
33 #include "symbol.h"
34 #include "excep.h"
36 /* Set by call to initialise -- if true, prints out
37 results of dynamic method resolution */
38 static int verbose;
40 extern int nativeExtraArg(MethodBlock *mb);
41 extern uintptr_t *callJNIMethod(void *env, Class *class, char *sig, int extra,
42 uintptr_t *ostack, unsigned char *native_func, int args);
43 extern struct _JNINativeInterface Jam_JNINativeInterface;
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;
80 }
81 }
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;
113 }
114 }
116 *mngldPtr = '\0';
118 sysFree(unicode);
119 return mangled;
120 }
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;
133 }
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;
151 }
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;
176 }
177 }
179 return NULL;
180 }
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);
189 }
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;
203 }
205 uintptr_t *resolveNativeWrapper(Class *class, MethodBlock *mb, uintptr_t *ostack) {
206 void *func = resolveNativeMethod(mb);
208 if(func == NULL) {
209 TRACE("<DLL: Couldn't link %s in %s>\n", mb->name, CLASS_CB(class)->name);
210 signalException(java_lang_UnsatisfiedLinkError, mb->name);
211 return ostack;
212 }
213 return (*(uintptr_t *(*)(Class*, MethodBlock*, uintptr_t*))func)(class, mb, ostack);
214 }
216 void initialiseDll(InitArgs *args) {
217 #ifndef NO_JNI
218 /* Init hash table, and create lock */
219 initHashTable(hash_table, HASHTABSZE, TRUE);
220 #endif
221 verbose = args->verbosedll;
222 }
224 #ifndef NO_JNI
225 typedef struct {
226 char *name;
227 void *handle;
228 Object *loader;
229 } DllEntry;
231 int dllNameHash(char *name) {
232 int hash = 0;
234 while(*name)
235 hash = hash * 37 + *name++;
237 return hash;
238 }
240 int resolveDll(char *name, Object *loader) {
241 DllEntry *dll;
243 TRACE("<DLL: Attempting to resolve library %s>\n", name);
245 #define HASH(ptr) dllNameHash(ptr)
246 #define COMPARE(ptr1, ptr2, hash1, hash2) \
247 ((hash1 == hash2) && (strcmp(ptr1, ptr2->name) == 0))
248 #define PREPARE(ptr) ptr
249 #define SCAVENGE(ptr) FALSE
250 #define FOUND(ptr) ptr
252 /* Do not add if absent, no scavenge, locked */
253 findHashEntry(hash_table, name, dll, FALSE, FALSE, TRUE);
255 if(dll == NULL) {
256 DllEntry *dll2;
257 void *onload, *handle = nativeLibOpen(name);
259 if(handle == NULL) {
260 TRACE("<DLL: Load failed: %s>\n", nativeLibError());
261 return FALSE;
262 }
264 TRACE("<DLL: Successfully opened library %s>\n", name);
266 if((onload = nativeLibSym(handle, "JNI_OnLoad")) != NULL) {
267 int ver;
269 initJNILrefs();
270 ver = (*(jint (*)(JavaVM*, void*))onload)(&invokeIntf, NULL);
272 if(ver != JNI_VERSION_1_2 && ver != JNI_VERSION_1_4) {
273 TRACE("<DLL: JNI_OnLoad returned unsupported version %d.\n>", ver);
274 return FALSE;
275 }
276 }
278 dll = (DllEntry*)sysMalloc(sizeof(DllEntry));
279 dll->name = strcpy((char*)sysMalloc(strlen(name)+1), name);
280 dll->handle = handle;
281 dll->loader = loader;
283 #undef HASH
284 #undef COMPARE
285 #define HASH(ptr) dllNameHash(ptr->name)
286 #define COMPARE(ptr1, ptr2, hash1, hash2) \
287 ((hash1 == hash2) && (strcmp(ptr1->name, ptr2->name) == 0))
289 /* Add if absent, no scavenge, locked */
290 findHashEntry(hash_table, dll, dll2, TRUE, FALSE, TRUE);
292 /* If the library has an OnUnload function it must be
293 called from a running Java thread (i.e. not within
294 the GC!). Create an unloader object which will be
295 finalised when the class loader is collected */
296 if(nativeLibSym(dll->handle, "JNI_OnUnload") != NULL)
297 newLibraryUnloader(loader, dll);
299 } else
300 if(dll->loader != loader)
301 return FALSE;
303 return TRUE;
304 }
306 char *getDllPath() {
307 char *env = nativeLibPath();
308 return env ? env : "";
309 }
311 char *getBootDllPath() {
312 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
313 return RUNTIME_INSTALL_DIR"/lib/classpath";
314 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
315 if (strncmp(OS_ARCH, "x86_64", 6) == 0)
316 return RUNTIME_INSTALL_DIR"/jre/lib/amd64";
317 else
318 return RUNTIME_INSTALL_DIR"/jre/lib/"OS_ARCH;
319 #endif
320 }
322 char *getDllName(char *name) {
323 return nativeLibMapName(name);
324 }
326 void *lookupLoadedDlls0(char *name, Object *loader) {
327 TRACE("<DLL: Looking up %s loader %p in loaded DLL's>\n", name, loader);
329 #define ITERATE(ptr) \
330 { \
331 DllEntry *dll = (DllEntry*)ptr; \
332 if(dll->loader == loader) { \
333 void *sym = nativeLibSym(dll->handle, name); \
334 if(sym != NULL) \
335 return sym; \
336 } \
337 }
339 hashIterate(hash_table);
340 return NULL;
341 }
343 void unloadDll(DllEntry *dll, int unloader) {
344 void *on_unload = nativeLibSym(dll->handle, "JNI_OnUnload");
346 if(unloader || on_unload == NULL) {
347 TRACE("<DLL: Unloading DLL %s\n", dll->name);
349 if(on_unload != NULL) {
350 initJNILrefs();
351 (*(void (*)(JavaVM*, void*))on_unload)(&invokeIntf, NULL);
352 }
354 nativeLibClose(dll->handle);
355 sysFree(dll->name);
356 sysFree(dll);
357 }
358 }
360 void unloaderUnloadDll(uintptr_t entry) {
361 unloadDll((DllEntry*)entry, TRUE);
362 }
364 #undef ITERATE
365 #define ITERATE(ptr) \
366 { \
367 DllEntry *dll = (DllEntry*)ptr; \
368 if(isMarked(dll->loader)) \
369 threadReference(&dll->loader); \
370 }
372 void threadLiveClassLoaderDlls() {
373 hashIterate(hash_table);
374 }
376 void unloadClassLoaderDlls(Object *loader) {
377 int unloaded = 0;
379 TRACE("<DLL: Unloading DLLs for loader %p\n", loader);
381 #undef ITERATE
382 #define ITERATE(ptr) \
383 { \
384 DllEntry *dll = (DllEntry*)*ptr; \
385 if(dll->loader == loader) { \
386 unloadDll(dll, FALSE); \
387 *ptr = NULL; \
388 unloaded++; \
389 } \
390 }
392 hashIterateP(hash_table);
394 if(unloaded) {
395 int size;
397 /* Update count to remaining number of DLLs */
398 hash_table.hash_count -= unloaded;
400 /* Calculate nearest multiple of 2 larger than count */
401 for(size = 1; size < hash_table.hash_count; size <<= 1);
403 /* Ensure new table is less than 2/3 full */
404 size = hash_table.hash_count*3 > size*2 ? size<< 1 : size;
406 resizeHash(&hash_table, size);
407 }
408 }
410 static void *env = &Jam_JNINativeInterface;
412 uintptr_t *callJNIWrapper(Class *class, MethodBlock *mb, uintptr_t *ostack) {
413 TRACE("<DLL: Calling JNI method %s.%s%s>\n", CLASS_CB(class)->name, mb->name, mb->type);
415 if(!initJNILrefs())
416 return NULL;
418 return callJNIMethod(&env, (mb->access_flags & ACC_STATIC) ? class : NULL,
419 mb->type, mb->native_extra_arg, ostack, mb->code, mb->args_count);
420 }
422 void *lookupLoadedDlls(MethodBlock *mb) {
423 Object *loader = (CLASS_CB(mb->class))->class_loader;
424 char *mangled = mangleClassAndMethodName(mb);
425 void *func;
427 func = lookupLoadedDlls0(mangled, loader);
429 if(func == NULL) {
430 char *mangledSig = mangleSignature(mb);
431 char *fullyMangled = (char*)sysMalloc(strlen(mangled)+strlen(mangledSig)+3);
433 sprintf(fullyMangled, "%s__%s", mangled, mangledSig);
434 func = lookupLoadedDlls0(fullyMangled, loader);
436 sysFree(fullyMangled);
437 sysFree(mangledSig);
438 }
440 sysFree(mangled);
442 if(func) {
443 if(verbose)
444 jam_printf("JNI");
446 mb->code = (unsigned char *) func;
447 mb->native_extra_arg = nativeExtraArg(mb);
448 return mb->native_invoker = (void*) callJNIWrapper;
449 }
451 return NULL;
452 }
453 #endif
