unified mein file comments
[libfirm] / ir / be / bejavacoal.c
1 /*
2  * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       Interface for external Java coalescer.
23  * @author      Sebastian Hack
24  * @version     $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <libcore/lc_opts.h>
31 #include <libcore/lc_opts_enum.h>
32
33 #ifdef _WIN32
34 #include <windows.h>
35 #else
36 #include <dlfcn.h>
37 #endif
38
39 #include <signal.h>
40 #include <stdlib.h>
41 #include <assert.h>
42 #include <stdio.h>
43
44 #include "bejavacoal.h"
45 #include "irtools.h"
46 #include "bemodule.h"
47
48 #ifdef WITH_JVM
49
50 /* Path to the jar file. A little OS dependent convenience. */
51 #ifdef _WIN32
52 static char jar_file[512] = "y:\\user\\hack\\public\\coal.jar";
53 #else
54 static char jar_file[512] = "/ben/hack/public/coal.jar";
55 #endif
56
57 static char cls_name[256] = "coalescing/mst/safe/Algo";
58
59 /* Name of the JVM dll/so */
60 static char jvm_lib[512] = { 0 };
61
62 static const lc_opt_table_entry_t options[] = {
63         LC_OPT_ENT_STR      ("jvm",  "absolute path to jvm dll",                    jvm_lib, sizeof(jvm_lib)),
64         LC_OPT_ENT_STR      ("jar",  "jar file of the coalescer",                   jar_file, sizeof(jar_file)),
65         LC_OPT_ENT_STR      ("cls",  "name of the class providing the factory",     cls_name, sizeof(cls_name)),
66         { NULL }
67 };
68
69 void be_init_javacoal(void)
70 {
71         lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
72         lc_opt_entry_t *ra_grp = lc_opt_get_grp(be_grp, "ra");
73         lc_opt_entry_t *chordal_grp = lc_opt_get_grp(ra_grp, "chordal");
74         lc_opt_entry_t *jc_grp = lc_opt_get_grp(chordal_grp, "jc");
75         lc_opt_add_table(jc_grp, options);
76 }
77
78 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_javacoal);
79
80 #include <jni.h>
81
82 typedef struct _jni_env_t {
83         JavaVM *jvm;
84         JNIEnv *jni;
85 } jni_env_t;
86
87 /*
88
89         Ugly code to retrieve the JVM dll/so file.
90
91 */
92
93 #ifdef _WIN32
94 /* Win32 version */
95 static void *find_jvm_symbol(const char *vmlibpath, const char *sym)
96 {
97         HINSTANCE hVM = LoadLibrary(vmlibpath);
98         return hVM ? GetProcAddress(hVM, sym) : NULL;
99 }
100
101 #define JRE_KEY "SOFTWARE\\JavaSoft\\Java Development Kit"
102
103 static char *locate_jvm_lib(char *path, size_t path_len)
104 {
105         char version[32];
106         char buf[256];
107         DWORD version_len = sizeof(version);
108         DWORD dwPathLen = path_len;
109         HKEY hKey;
110
111         RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_KEY, 0, KEY_QUERY_VALUE, &hKey);
112         RegQueryValueEx(hKey, "CurrentVersion", NULL, NULL, (LPBYTE) version, &version_len);
113         RegCloseKey(hKey);
114
115         _snprintf(buf, sizeof(buf), JRE_KEY "\\%s", version);
116         RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_QUERY_VALUE, &hKey);
117         RegQueryValueEx(hKey, "JavaHome", NULL, NULL, (LPBYTE) path, &dwPathLen);
118         RegCloseKey(hKey);
119
120         strncat(path, "\\jre\\bin\\server\\jvm.dll", path_len);
121         return path;
122 }
123
124 #else /* ! _WIN32 */
125 /* Unix version */
126 static void *find_jvm_symbol(const char *vmlibpath, const char *sym)
127 {
128         void *libVM = dlopen(vmlibpath, RTLD_LAZY);
129         return libVM ? dlsym(libVM, sym) : NULL;
130 }
131
132 static char *locate_jvm_lib(char *path, size_t n)
133 {
134         return NULL;
135 }
136 #endif /* _WIN32 */
137
138 static int start_vm(jni_env_t *env, int argc, char *argv[])
139 {
140         int i;
141         long ret;
142         JavaVMInitArgs args;
143         JavaVMOption *opts;
144
145         long (JNICALL * create_func)(JavaVM **, void **, void *) = find_jvm_symbol(jvm_lib, "JNI_CreateJavaVM");
146
147         if(!create_func) {
148                 fprintf(stderr, "could not find JVM creation function\n");
149                 exit(1);
150         }
151
152         memset(&args, 0, sizeof(args));
153         opts = malloc(argc * sizeof(opts[0]));
154         for(i = 0; i < argc; ++i) {
155                 opts[i].optionString = argv[i];
156                 opts[i].extraInfo    = NULL;
157         }
158
159         args.version  = JNI_VERSION_1_4;
160         args.nOptions = argc;
161         args.options  = opts;
162         args.ignoreUnrecognized = JNI_FALSE;
163
164         ret = create_func(&env->jvm, (void **) &env->jni, &args);
165         free(opts);
166         if(ret != JNI_OK) {
167                 fprintf(stderr, "JNI_CreateJavaVM returned errrocode %ld\n" , ret);
168                 return 0;
169         }
170
171         return 1;
172 }
173
174 static void stop_vm(jni_env_t *env)
175 {
176         JavaVM *jvm = env->jvm;
177         (*jvm)->DetachCurrentThread(jvm);
178         (*jvm)->DestroyJavaVM(jvm);
179 }
180
181 static int jvm_inited = 0;
182 static jni_env_t env;
183 void (*old_int_handler)(int);
184 void (*old_abrt_handler)(int);
185
186 static void sig_jvm_destroy_at_exit(int signal)
187 {
188         if(jvm_inited)
189                 stop_vm(&env);
190
191         switch(signal) {
192         case SIGABRT:
193                 old_abrt_handler(signal);
194                 break;
195         case SIGINT:
196                 old_int_handler(signal);
197                 break;
198         default:;
199         }
200 }
201
202 static void jvm_destroy_at_exit(void)
203 {
204         sig_jvm_destroy_at_exit(0);
205 }
206
207 static jni_env_t *get_jvm(void)
208 {
209         char cp_param[512];
210         char *args[1];
211
212         if(!jvm_inited) {
213                 /* Find the dll */
214                 if(strlen(jvm_lib) == 0) {
215                         if(!locate_jvm_lib(jvm_lib, sizeof(jvm_lib))) {
216                                 fprintf(stderr, "could not find jvm library\n");
217                                 exit(1);
218                         }
219                 }
220
221                 snprintf(cp_param, sizeof(cp_param), "-Djava.class.path=%s", jar_file);
222                 args[0] = cp_param;
223                 if(!start_vm(&env, sizeof(args) / sizeof(args[0]), args)) {
224                         fprintf(stderr, "Couldn't initialize java VM\n");
225                         abort();
226                 }
227                 jvm_inited = 1;
228                 old_int_handler  = signal(SIGINT,  sig_jvm_destroy_at_exit);
229                 old_abrt_handler = signal(SIGABRT, sig_jvm_destroy_at_exit);
230                 atexit(jvm_destroy_at_exit);
231         }
232
233         return &env;
234 }
235
236
237 static void check(jni_env_t *env, const char *file, int line)
238 {
239         JNIEnv *jni = env->jni;
240         jboolean exc = (*jni)->ExceptionCheck(jni);
241         if(exc) {
242                 fprintf(stderr, "%s:%d: ", file, line);
243                 (*jni)->ExceptionDescribe(jni);
244                 (*jni)->ExceptionClear(jni);
245                 stop_vm(env);
246                 abort();
247         }
248 }
249
250 #define CHECK(env) check(env, __FILE__, __LINE__)
251
252 enum {
253         mth_add_int_edge,
254         mth_add_aff_edge,
255         mth_set_color,
256         //mth_set_debug,
257         mth_get_color,
258         mth_forbid_color,
259         mth_coalesce,
260         mth_dump,
261         mth_finish,
262         mth_last
263 };
264
265 struct _mth_info_t {
266         const char *name;
267         const char *sig;
268 };
269
270 static const struct _mth_info_t mthis[mth_last] = {
271         { "addIntEdge",  "(II)V"                   }, /* public void addIntEdge(int, int); */
272         { "addAffEdge",  "(III)V"                  }, /* public void addAffEdge(int, int, int); */
273         { "setColor",    "(II)V"                   }, /* public void setColor(int, int); */
274         //{ "setDebug",    "(ILjava/lang/String;)V"  }, /* public void setDebug(int, String); */
275         { "getColor",    "(I)I"                    }, /* public int getColor(int); */
276         { "forbidColor", "(II)V"                   }, /* public void forbidColor(int, int); */
277         { "coalesce",    "()V"                     }, /* public void coalesce(); */
278         { "dump",        "(Ljava/lang/String;)V"   }, /* public void dump(String); */
279         { "finish",      "()V"                     }  /* public void finish(); */
280 };
281
282 /* public static coalescing.Extern createExtern(java.lang.String, int, int, int); */
283 static const struct _mth_info_t mthi_factory = {
284         "createExtern", "(Ljava/lang/String;III)Lcoalescing/Extern;"
285 };
286
287 struct _be_java_coal_t {
288         jni_env_t *env;
289         jclass    cls;
290         jobject   obj;
291
292         jmethodID mth_ids[mth_last];
293 };
294
295 static void jc_call_void(be_java_coal_t *c, int mth_index, ...)
296 {
297         JNIEnv *jni   = c->env->jni;
298         jmethodID mid = c->mth_ids[mth_index];
299
300         va_list args;
301
302         va_start(args, mth_index);
303         (*jni)->CallVoidMethodV(jni, c->obj, mid, args);
304         CHECK(c->env);
305         va_end(args);
306 }
307
308 static int jc_call_int(be_java_coal_t *c, int mth_index, ...)
309 {
310         JNIEnv *jni   = c->env->jni;
311         jmethodID mid = c->mth_ids[mth_index];
312
313         int res;
314         va_list args;
315
316         va_start(args, mth_index);
317         res = (*jni)->CallIntMethodV(jni, c->obj, mid, args);
318         CHECK(c->env);
319         va_end(args);
320
321         return res;
322 }
323
324 be_java_coal_t *be_java_coal_init(const char *graph_name, int n_nodes, int n_regs, int dbg_level)
325 {
326         be_java_coal_t *c;
327         jni_env_t *env = get_jvm();
328         JNIEnv *jni = env->jni;
329         jmethodID fact;
330         jclass cls;
331         jstring str;
332         int i;
333
334         c = malloc(sizeof(c[0]));
335         memset(c, 0, sizeof(c[0]));
336         c->env = env;
337
338         /* Find the class we are are looking for. */
339         cls = (*jni)->FindClass(jni, cls_name);
340         CHECK(env);
341
342         /* Get the static factory method. */
343         fact = (*jni)->GetStaticMethodID(jni, cls, mthi_factory.name, mthi_factory.sig);
344         CHECK(env);
345
346         /* Call the factory. */
347         str = (*jni)->NewStringUTF(jni, graph_name);
348         CHECK(env);
349         c->obj = (*jni)->CallStaticObjectMethod(jni, cls, fact, str, n_nodes, n_regs, dbg_level);
350         CHECK(env);
351         c->cls = (*jni)->GetObjectClass(jni, c->obj);
352
353         /* Reference the created object. */
354         c->obj = (*jni)->NewGlobalRef(jni, c->obj);
355         CHECK(env);
356
357         /* Lookup the member methods of the object. */
358         for(i = 0; i < mth_last; ++i) {
359                 c->mth_ids[i] = (*jni)->GetMethodID(jni, c->cls, mthis[i].name, mthis[i].sig);
360                 CHECK(env);
361         }
362
363         return c;
364 }
365
366 void be_java_coal_destroy(be_java_coal_t *c) {
367         JNIEnv *jni = c->env->jni;
368         jc_call_void(c, mth_finish);
369         (*jni)->DeleteGlobalRef(jni, c->obj);
370         free(c);
371 }
372
373 void be_java_coal_add_int_edge(be_java_coal_t *c, int n, int m)
374 {
375         jc_call_void(c, mth_add_int_edge, (jint) n, (jint) m);
376 }
377
378 void be_java_coal_add_aff_edge(be_java_coal_t *c, int n, int m, int weight)
379 {
380         jc_call_void(c, mth_add_aff_edge, (jint) n, (jint) m, (jint) weight);
381 }
382
383 void be_java_coal_set_color(be_java_coal_t *c, int n, int col)
384 {
385         jc_call_void(c, mth_set_color, (jint) n, (jint) col);
386 }
387
388 void be_java_coal_set_debug(be_java_coal_t *c, int n, const char *dbg)
389 {
390 #if 0
391         JNIEnv *jni   = c->env->jni;
392         jmethodID mid = c->mth_ids[mth_set_debug];
393         jstring str;
394
395         str = (*jni)->NewStringUTF(jni, dbg);
396         CHECK(c->env);
397         (*jni)->CallVoidMethod(jni, c->obj, mid, (jint) n, str);
398         CHECK(c->env);
399 #endif /* if 0 */
400 }
401
402 void be_java_coal_forbid_color(be_java_coal_t *c, int n, int col)
403 {
404         jc_call_void(c, mth_forbid_color, (jint) n, (jint) col);
405 }
406
407 void be_java_coal_coalesce(be_java_coal_t *c)
408 {
409         jc_call_void(c, mth_coalesce);
410 }
411
412 void be_java_coal_dump(be_java_coal_t *c, const char *fn)
413 {
414         JNIEnv *jni   = c->env->jni;
415         jmethodID mid = c->mth_ids[mth_dump];
416         jstring str;
417
418         str = (*jni)->NewStringUTF(jni, fn);
419         CHECK(c->env);
420         (*jni)->CallVoidMethod(jni, c->obj, mid, str);
421         CHECK(c->env);
422 }
423
424 int be_java_coal_get_color(be_java_coal_t *c, int n)
425 {
426         return jc_call_int(c, mth_get_color, (jint) n);
427 }
428
429 void be_java_coal_start_jvm(void)
430 {
431         get_jvm();
432 }
433
434 #else /* ! WITH_JVM */
435
436 be_java_coal_t *be_java_coal_init(const char *graph_name, int n_nodes, int n_regs, int dbg_level)
437 {
438         assert(0 && "use --enable-jvm");
439         return NULL;
440 }
441
442 void be_java_coal_destroy(be_java_coal_t *c)
443 {
444         assert(0 && "use --enable-jvm");
445 }
446
447
448 void be_java_coal_add_int_edge(be_java_coal_t *c, int n, int m)
449 {
450         assert(0 && "use --enable-jvm");
451 }
452
453 void be_java_coal_add_aff_edge(be_java_coal_t *c, int n, int m, int weight)
454 {
455         assert(0 && "use --enable-jvm");
456 }
457
458 void be_java_coal_set_color(be_java_coal_t *c, int n, int col)
459 {
460         assert(0 && "use --enable-jvm");
461 }
462
463 void be_java_coal_set_debug(be_java_coal_t *c, int n, const char *dbg)
464 {
465         assert(0 && "use --enable-jvm");
466 }
467
468 void be_java_coal_forbid_color(be_java_coal_t *c, int n, int col)
469 {
470         assert(0 && "use --enable-jvm");
471 }
472
473 void be_java_coal_coalesce(be_java_coal_t *c)
474 {
475         assert(0 && "use --enable-jvm");
476 }
477
478 void be_java_coal_dump(be_java_coal_t *c, const char *fn)
479 {
480         assert(0 && "use --enable-jvm");
481 }
482
483 int be_java_coal_get_color(be_java_coal_t *c, int n)
484 {
485         assert(0 && "use --enable-jvm");
486         return -1;
487 }
488
489 void be_java_coal_start_jvm(void)
490 {
491 }
492
493 #endif /* WITH_JVM */