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