jamvm
view src/dll.c @ 400:5baaa2bcac6b
Support flipping between GNU Classpath and OpenJDK using configure (thanks to twisti).
2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>
* configure.ac:
Add --with-java-runtime-library from CACAO and
change --with-classpath-install-dir to
--with-java-runtime-library-install-dir.
* lib/Makefile.am,
* src/class.h,
* src/dll.c:
Define class library and native libs location
depending on value of --with-java-runtime-library.
2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>
* configure.ac:
Add --with-java-runtime-library from CACAO and
change --with-classpath-install-dir to
--with-java-runtime-library-install-dir.
* lib/Makefile.am,
* src/class.h,
* src/dll.c:
Define class library and native libs location
depending on value of --with-java-runtime-library.
| author | andrew |
|---|---|
| date | Tue Aug 05 04:48:38 2008 +0100 (2008-08-05) |
| parents | ef6fa16d00f7 |
| children | 24373fc1d951 |
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 signalException(java_lang_UnsatisfiedLinkError, mb->name);
210 return ostack;
211 }
212 return (*(uintptr_t *(*)(Class*, MethodBlock*, uintptr_t*))func)(class, mb, ostack);
213 }
215 void initialiseDll(InitArgs *args) {
216 #ifndef NO_JNI
217 /* Init hash table, and create lock */
218 initHashTable(hash_table, HASHTABSZE, TRUE);
219 #endif
220 verbose = args->verbosedll;
221 }
223 #ifndef NO_JNI
224 typedef struct {
225 char *name;
226 void *handle;
227 Object *loader;
228 } DllEntry;
230 int dllNameHash(char *name) {
231 int hash = 0;
233 while(*name)
234 hash = hash * 37 + *name++;
236 return hash;
237 }
239 int resolveDll(char *name, Object *loader) {
240 DllEntry *dll;
242 TRACE("<DLL: Attempting to resolve library %s>\n", name);
244 #define HASH(ptr) dllNameHash(ptr)
245 #define COMPARE(ptr1, ptr2, hash1, hash2) \
246 ((hash1 == hash2) && (strcmp(ptr1, ptr2->name) == 0))
247 #define PREPARE(ptr) ptr
248 #define SCAVENGE(ptr) FALSE
249 #define FOUND(ptr) ptr
251 /* Do not add if absent, no scavenge, locked */
252 findHashEntry(hash_table, name, dll, FALSE, FALSE, TRUE);
254 if(dll == NULL) {
255 DllEntry *dll2;
256 void *onload, *handle = nativeLibOpen(name);
258 if(handle == NULL)
259 return FALSE;
261 TRACE("<DLL: Successfully opened library %s>\n", name);
263 if((onload = nativeLibSym(handle, "JNI_OnLoad")) != NULL) {
264 int ver;
266 initJNILrefs();
267 ver = (*(jint (*)(JavaVM*, void*))onload)(&invokeIntf, NULL);
269 if(ver != JNI_VERSION_1_2 && ver != JNI_VERSION_1_4) {
270 TRACE("<DLL: JNI_OnLoad returned unsupported version %d.\n>", ver);
271 return FALSE;
272 }
273 }
275 dll = (DllEntry*)sysMalloc(sizeof(DllEntry));
276 dll->name = strcpy((char*)sysMalloc(strlen(name)+1), name);
277 dll->handle = handle;
278 dll->loader = loader;
280 #undef HASH
281 #undef COMPARE
282 #define HASH(ptr) dllNameHash(ptr->name)
283 #define COMPARE(ptr1, ptr2, hash1, hash2) \
284 ((hash1 == hash2) && (strcmp(ptr1->name, ptr2->name) == 0))
286 /* Add if absent, no scavenge, locked */
287 findHashEntry(hash_table, dll, dll2, TRUE, FALSE, TRUE);
289 /* If the library has an OnUnload function it must be
290 called from a running Java thread (i.e. not within
291 the GC!). Create an unloader object which will be
292 finalised when the class loader is collected */
293 if(nativeLibSym(dll->handle, "JNI_OnUnload") != NULL)
294 newLibraryUnloader(loader, dll);
296 } else
297 if(dll->loader != loader)
298 return FALSE;
300 return TRUE;
301 }
303 char *getDllPath() {
304 char *env = nativeLibPath();
305 return env ? env : "";
306 }
308 char *getBootDllPath() {
309 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
310 return RUNTIME_INSTALL_DIR"/lib/classpath";
311 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
312 if (strncmp(OS_ARCH, "x86_64", 6) == 0)
313 return RUNTIME_INSTALL_DIR"/jre/lib/amd64";
314 else
315 return RUNTIME_INSTALL_DIR"/jre/lib/"OS_ARCH;
316 #endif
317 }
319 char *getDllName(char *name) {
320 return nativeLibMapName(name);
321 }
323 void *lookupLoadedDlls0(char *name, Object *loader) {
324 TRACE("<DLL: Looking up %s loader %p in loaded DLL's>\n", name, loader);
326 #define ITERATE(ptr) \
327 { \
328 DllEntry *dll = (DllEntry*)ptr; \
329 if(dll->loader == loader) { \
330 void *sym = nativeLibSym(dll->handle, name); \
331 if(sym != NULL) \
332 return sym; \
333 } \
334 }
336 hashIterate(hash_table);
337 return NULL;
338 }
340 void unloadDll(DllEntry *dll, int unloader) {
341 void *on_unload = nativeLibSym(dll->handle, "JNI_OnUnload");
343 if(unloader || on_unload == NULL) {
344 TRACE("<DLL: Unloading DLL %s\n", dll->name);
346 if(on_unload != NULL) {
347 initJNILrefs();
348 (*(void (*)(JavaVM*, void*))on_unload)(&invokeIntf, NULL);
349 }
351 nativeLibClose(dll->handle);
352 sysFree(dll->name);
353 sysFree(dll);
354 }
355 }
357 void unloaderUnloadDll(uintptr_t entry) {
358 unloadDll((DllEntry*)entry, TRUE);
359 }
361 #undef ITERATE
362 #define ITERATE(ptr) \
363 { \
364 DllEntry *dll = (DllEntry*)ptr; \
365 if(isMarked(dll->loader)) \
366 threadReference(&dll->loader); \
367 }
369 void threadLiveClassLoaderDlls() {
370 hashIterate(hash_table);
371 }
373 void unloadClassLoaderDlls(Object *loader) {
374 int unloaded = 0;
376 TRACE("<DLL: Unloading DLLs for loader %p\n", loader);
378 #undef ITERATE
379 #define ITERATE(ptr) \
380 { \
381 DllEntry *dll = (DllEntry*)*ptr; \
382 if(dll->loader == loader) { \
383 unloadDll(dll, FALSE); \
384 *ptr = NULL; \
385 unloaded++; \
386 } \
387 }
389 hashIterateP(hash_table);
391 if(unloaded) {
392 int size;
394 /* Update count to remaining number of DLLs */
395 hash_table.hash_count -= unloaded;
397 /* Calculate nearest multiple of 2 larger than count */
398 for(size = 1; size < hash_table.hash_count; size <<= 1);
400 /* Ensure new table is less than 2/3 full */
401 size = hash_table.hash_count*3 > size*2 ? size<< 1 : size;
403 resizeHash(&hash_table, size);
404 }
405 }
407 static void *env = &Jam_JNINativeInterface;
409 uintptr_t *callJNIWrapper(Class *class, MethodBlock *mb, uintptr_t *ostack) {
410 TRACE("<DLL: Calling JNI method %s.%s%s>\n", CLASS_CB(class)->name, mb->name, mb->type);
412 if(!initJNILrefs())
413 return NULL;
415 return callJNIMethod(&env, (mb->access_flags & ACC_STATIC) ? class : NULL,
416 mb->type, mb->native_extra_arg, ostack, mb->code, mb->args_count);
417 }
419 void *lookupLoadedDlls(MethodBlock *mb) {
420 Object *loader = (CLASS_CB(mb->class))->class_loader;
421 char *mangled = mangleClassAndMethodName(mb);
422 void *func;
424 func = lookupLoadedDlls0(mangled, loader);
426 if(func == NULL) {
427 char *mangledSig = mangleSignature(mb);
428 char *fullyMangled = (char*)sysMalloc(strlen(mangled)+strlen(mangledSig)+3);
430 sprintf(fullyMangled, "%s__%s", mangled, mangledSig);
431 func = lookupLoadedDlls0(fullyMangled, loader);
433 sysFree(fullyMangled);
434 sysFree(mangledSig);
435 }
437 sysFree(mangled);
439 if(func) {
440 if(verbose)
441 jam_printf("JNI");
443 mb->code = (unsigned char *) func;
444 mb->native_extra_arg = nativeExtraArg(mb);
445 return mb->native_invoker = (void*) callJNIWrapper;
446 }
448 return NULL;
449 }
450 #endif
