Added spec:commit task to commit changes to spec/ruby sources.
[rbx.git] / shotgun / lib / machine.c
bloba6d06030bc014fffcec2fbef0688a4558d182bc0
1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <signal.h>
5 #include <sys/param.h>
6 #include <sys/stat.h>
7 #include <ev.h>
9 /* *BSD dl support */
10 #ifdef __FreeBSD__
11 #include <dlfcn.h>
12 #elif defined(__OpenBSD__)
13 #include <dlfcn.h>
14 #endif
16 #include "shotgun/config.h"
17 #include "shotgun/lib/shotgun.h"
18 #include "shotgun/lib/string.h"
19 #include "shotgun/lib/io.h"
20 #include "shotgun/lib/hash.h"
21 #include "shotgun/lib/lookuptable.h"
22 #include "shotgun/lib/machine.h"
23 #include "shotgun/lib/array.h"
24 #include "shotgun/lib/ar.h"
25 #include "shotgun/lib/symbol.h"
26 #include "shotgun/lib/config_hash.h"
27 #include "shotgun/lib/methctx.h"
28 #include "shotgun/lib/tuple.h"
29 #include "shotgun/lib/subtend.h"
30 #include "shotgun/lib/subtend/nmc.h"
31 #include "shotgun/lib/instruction_names.h"
33 static int _recursive_reporting = 0;
35 /* use this to convert symbol into Ruby string
36 * st is for state
38 #define SYM2STR(st, sym) rbx_string_as_cstr(st, rbs_symbol_to_string(st, sym))
41 outputs limited number of lines of VM call stack
42 current active machine used unless explicitly given
44 void machine_print_callstack_limited(machine m, int maxlev) {
45 OBJECT context, tmp;
46 const char *modname, *methname, *filename;
47 struct fast_context *fc;
48 if(!m) m = current_machine;
49 context = m->c->active_context;
51 /* flush stack and instruction pointers */
52 cpu_flush_ip(m->c);
53 cpu_flush_sp(m->c);
55 FASTCTX(context)->ip = m->c->ip;
57 while(RTEST(context) && maxlev--) {
59 methctx_reference(m->s, context);
60 fc = FASTCTX(context);
62 if(fc->method_module && RTEST(fc->method_module)) {
63 modname = SYM2STR(m->s, module_get_name(fc->method_module));
64 } else {
65 modname = "<none>";
68 if(fc->type == FASTCTX_BLOCK) {
69 methname = "<block>";
70 } else if(fc->name && RTEST(fc->name)) {
71 if(SYMBOL_P(fc->name)) {
72 methname = SYM2STR(m->s, fc->name);
73 } else {
74 methname = "<unknown>";
76 } else {
77 methname = "<none>";
80 if(fc->method && RTEST(fc->method)) {
81 tmp = cmethod_get_file(fc->method);
82 if(SYMBOL_P(tmp)) {
83 filename = SYM2STR(m->s, tmp);
84 } else {
85 filename = "<unknown>";
87 } else {
88 filename = "<unknown>";
91 /* execution logging */
92 fprintf(stderr, "%10p %s#%s+%d in %s:%d\n",
93 (void*)context, modname, methname,
94 fc->ip,
95 filename,
96 cpu_ip2line(m->s, fc->method, fc->ip)
98 /* transfer control back to message sender */
99 context = fc->sender;
103 /* prints the whole VM call stack */
104 void machine_print_callstack(machine m) {
105 machine_print_callstack_limited(m, -1);
108 /* prints of given VM stack trace */
109 void machine_print_stack(machine m) {
110 unsigned int i, start, end;
111 cpu_flush_sp(m->c);
112 i = m->c->sp;
113 /* TODO: document these magic numbers */
114 start = (i < 5 ? 0 : i - 5);
115 end = (i + 5 > m->c->stack_size) ? m->c->stack_size : i + 5;
116 for(i = start; i < end; i++) {
117 if(i == m->c->sp) {
118 printf("%4d => ", i);
119 } else {
120 printf("%4d ", i);
122 printf("%s\n", rbs_inspect_verbose(m->s, m->c->stack_top[i]));
127 /* prints VM registers content */
128 void machine_print_registers(machine m) {
129 cpu_flush_sp(m->c);
130 cpu_flush_ip(m->c);
131 printf("IP: %04d\nSP: %04d\n", m->c->ip, m->c->sp);
132 if(NIL_P(m->c->exception)) {
133 printf("Exception: none\n");
134 } else {
135 printf("Exception: %s\n", rbs_inspect(m->s, m->c->exception));
139 /* handles error reporting */
140 void _machine_error_reporter(int sig, siginfo_t *info, void *ctx) {
141 const char *signame;
142 rni_context *rni_ctx;
143 OBJECT addr;
145 /* See if the error happened during the running of a C function.
146 If so, we raise an exception about the error. */
147 /* Grab Subtend context first */
148 rni_ctx = subtend_retrieve_context();
149 if(rni_ctx->nmc && rni_ctx->nmc->system_set) {
150 /* TODO: generate the C backtrace as a string array and pass it
151 via the nmc or global_context so that the exception can include
152 it. */
153 /* Set RNI faulting instruction and switch to system context */
154 rni_ctx->fault_address = info->si_addr;
155 rni_ctx->nmc->jump_val = SEGFAULT_DETECTED;
156 setcontext(&rni_ctx->nmc->system);
159 /* This is really nice. We don't have to do this check at every
160 fetch, instead, let it segfault and handle it here.
161 The check for - 4 is because the bounds checks grabs the number
162 of fields from a ref right away, which is where it will segfault
163 if it's not a ref. The fields are 4 bytes into the header.
164 The check for - 8 is because it's common this happens when
165 trying to grab the class of a non-reference. The class is
166 8 bytes into the header. */
167 if(sig == SIGSEGV || sig == SIGBUS) {
168 addr = (OBJECT)(info->si_addr);
169 if(!REFERENCE_P(addr) || !REFERENCE_P(addr - 4) || !REFERENCE_P(addr - 8)) {
170 printf("Attempted to access field of non-reference.\n");
171 if(current_machine->g_use_firesuit) {
172 machine_handle_fire(FIRE_NULL);
177 if(_recursive_reporting) exit(-2);
178 _recursive_reporting++;
180 switch(sig) {
181 case SIGSEGV:
182 signame = "Segmentation fault (SIGSEGV)";
183 break;
184 case SIGBUS:
185 signame = "Bus violation (SIGBUS)";
186 break;
187 case SIGABRT:
188 signame = "Software abort (SIGABRT)";
189 break;
190 default:
191 signame = "<UNKNOWN>";
194 printf("\nAn error has occured: %s (%d)\n\n", signame, sig);
196 if(getenv("CRASH_WAIT")) {
197 printf("Pausing so I can be debugged.\n");
198 pause();
199 printf("Continuing after debugger.\n");
202 printf("Ruby backtrace:\n");
203 machine_print_callstack(current_machine);
205 printf("\nVM Registers:\n");
206 machine_print_registers(current_machine);
208 exit(-2);
211 /* initialize signals handling and errors reporting */
212 void machine_setup_signals(machine m) {
213 m->error_report.sa_sigaction = _machine_error_reporter;
214 sigemptyset(&m->error_report.sa_mask);
215 m->error_report.sa_flags = SA_SIGINFO;
216 sigaction(SIGSEGV, &m->error_report, NULL);
217 sigaction(SIGBUS, &m->error_report, NULL);
218 sigaction(SIGABRT, &m->error_report, NULL);
221 /* initialize event base used by libevent */
222 static void machine_setup_events(machine m) {
223 /* libev will not "autodetect" kqueue because it is broken on darwin */
224 m->s->event_base = ev_loop_new(EVFLAG_FORKCHECK);
225 m->s->thread_infos = NULL;
228 /* Creates and initializes Rubinius VM.
229 * Sets up the VM CPU, machine message buckets,
230 * subtend, event handling, context and state,
231 * universe and everything.
234 machine machine_new(environment e) {
235 machine m;
236 int pipes[2];
238 m = calloc(1, sizeof(struct rubinius_machine));
239 m->g_use_firesuit = 0;
240 m->g_access_violation = 0;
241 m->sub = 0;
242 pipe(pipes);
245 m->message_read_fd = pipes[0];
246 m->message_write_fd = pipes[1];
247 m->s = rubinius_state_new();
248 m->c = cpu_new(m->s);
249 cpu_run(m->s, m->c, TRUE);
250 m->c->ip_ptr = &m->s->external_ip;
252 machine_setup_signals(m);
253 machine_setup_events(m);
255 cpu_initialize(m->s, m->c);
256 cpu_bootstrap(m->s);
257 subtend_setup(m->s);
258 cpu_setup_top_scope(m->s, m->c);
259 cpu_initialize_context(m->s, m->c);
260 /* make MAIN Ruby contant point to main routine of the application*/
261 machine_set_const(m, "MAIN", m->c->main);
262 cpu_task_configure_preemption(m->s);
263 environment_add_machine(e, m);
265 m->s->om->bootstrap_loaded = 1;
267 return m;
270 void machine_destroy(machine m) {
271 cpu_destroy(m->c);
272 state_destroy(m->s);
273 free(m);
276 /* handles errors gracefully */
277 void machine_handle_fire(int kind) {
278 /* store type of violation */
279 current_machine->g_access_violation = kind;
280 /* then switch to special context to handle it gracefully */
281 setcontext(&current_machine->g_firesuit);
284 /* handles type errors in the VM: error message and type are preserved */
285 void machine_handle_type_error(OBJECT obj, const char *message) {
286 current_machine->g_firesuit_message = strdup(message);
288 if(FIXNUM_P(obj)) {
289 current_machine->g_firesuit_arg = FixnumType;
290 } else if(SYMBOL_P(obj)) {
291 current_machine->g_firesuit_arg = SymbolType;
292 } else if(REFERENCE_P(obj)) {
293 current_machine->g_firesuit_arg = obj->obj_type;
294 } else if(NIL_P(obj)) {
295 current_machine->g_firesuit_arg = NilType;
296 } else {
297 current_machine->g_firesuit_arg = 0;
299 machine_handle_fire(FIRE_TYPE);
302 /* handles failed assertions in the VM code */
303 void machine_handle_assert(const char *reason, const char *file, int line) {
304 fprintf(stderr, "VM Assertion: %s (%s:%d)\n", reason, file, line);
306 printf("\nRuby backtrace:\n");
307 machine_print_callstack(current_machine);
309 if(!current_machine->g_use_firesuit) abort();
310 current_machine->g_access_violation = FIRE_ASSERT;
311 setcontext(&current_machine->g_firesuit);
314 /* returns unmarshalled file */
315 OBJECT machine_load_file(machine m, const char *path) {
316 return cpu_unmarshal_file(m->s, path, 0);
319 void machine_show_exception(machine m, OBJECT exc) {
320 OBJECT msg;
321 const char *buf;
322 printf("\nError: An unhandled exception has terminated this VM.\n");
323 msg = exception_get_message(exc);
324 if(REFERENCE_P(msg)) {
325 buf = rbx_string_as_cstr(m->s, msg);
326 } else {
327 buf = "<no message>";
329 printf(" => %s (%s)\n\n", buf, rbs_inspect(m->s, exc->klass));
331 /* Restore the context it happened at so print_callstack shows it. */
332 m->c->active_context = exception_get_context(exc);
333 machine_print_callstack(m);
334 puts("");
337 /* initializes VM globals, clears instruction pointer, op, firesuit and so forth.
338 returns FALSE on exception
340 int machine_run(machine m) {
341 cpu_run(m->s, m->c, 0);
342 m->c->ip_ptr = &m->s->external_ip;
344 if(RTEST(m->c->exception)) {
345 printf("Toplevel exception detected.\n");
346 machine_show_exception(m, m->c->exception);
347 return FALSE;
349 return TRUE;
352 /* loads and executes a script. Returns FALSE if load failed. */
353 int machine_run_file(machine m, const char *path) {
354 OBJECT meth;
355 int out;
357 if(m->s->excessive_tracing) {
358 printf("[ Loading file %s]\n", path);
361 meth = machine_load_file(m, path);
362 if(!RTEST(meth)) {
363 printf("Unable to load '%s'.\n", path);
364 return FALSE;
367 /* re-init cpu stack */
368 m->c->depth = 0;
369 cpu_stack_push(m->s, m->c, meth, FALSE);
370 cpu_run_script(m->s, m->c, meth);
371 out = machine_run(m);
372 if(m->s->excessive_tracing) {
373 printf("[ Finished loading file %s]\n", path);
375 return out;
378 /* sets contstand under given module or class */
379 void machine_set_const_under(machine m, const char *str, OBJECT val, OBJECT under) {
380 OBJECT tbl;
381 tbl = module_get_constants(under);
382 lookuptable_store(m->s, tbl, string_new(m->s, str), val);
385 /* Sets constant under Object class */
386 void machine_set_const(machine m, const char *str, OBJECT val) {
387 machine_set_const_under(m, str, val, m->s->global->object);
390 /* stores Ruby VM launch arguments */
391 void machine_save_args(machine m, int argc, char **argv) {
392 char **na;
393 na = calloc(argc, sizeof(char*));
394 memcpy(na, argv, argc);
395 m->argc = argc;
396 m->argv = na;
398 machine_setup_ruby(m, argv[0]);
399 machine_setup_argv(m, argc, argv);
402 /* Sets standard IO streams (stdin, stdout, stderr) to Ruby constants */
403 void machine_setup_standard_io(machine m) {
404 machine_set_const(m, "STDIN", io_new(m->s, 0, "r"));
405 machine_set_const(m, "STDOUT", io_new(m->s, 1, "w"));
406 machine_set_const(m, "STDERR", io_new(m->s, 2, "w"));
409 int *machine_setup_piped_io(machine m) {
410 int pin[2];
411 int pout[2];
412 int perr[2];
413 int *pipes;
415 pipe(pin);
416 pipe(pout);
417 pipe(perr);
419 machine_set_const(m, "STDIN", io_new(m->s, pin[0], "r"));
420 machine_set_const(m, "STDOUT", io_new(m->s, pout[1], "w"));
421 machine_set_const(m, "STDERR", io_new(m->s, perr[1], "w"));
423 pipes = ALLOC_N(int, 3);
424 pipes[0] = pin[1];
425 pipes[1] = pout[0];
426 pipes[2] = perr[0];
428 return pipes;
431 /* sets up RUBY_BIN_PATH Ruby constant and VM interpreter name */
432 void machine_setup_ruby(machine m, char *name) {
433 char buf[MAXPATHLEN];
434 char wd[MAXPATHLEN];
436 HACK: this should be replaced by normal ruby code.
437 C sucks - Ryan Davis
439 if(name[0] != '/') {
440 getcwd(wd, MAXPATHLEN);
441 snprintf(buf, MAXPATHLEN, "%s/%s", wd, name);
442 name = buf;
444 machine_set_const(m, "RUBY_BIN_PATH", string_new(m->s, name));
445 m->interpreter = strdup(name);
448 /* sets ARGV and ARG0 Ruby constants */
449 void machine_setup_argv(machine m, int argc, char **argv) {
450 OBJECT ary;
451 int i;
453 machine_set_const(m, "ARG0", string_new(m->s, argv[0]));
455 ary = array_new(m->s, argc - 1);
456 for(i = 0; i < argc - 1; i++) {
457 array_set(m->s, ary, i, string_new(m->s, argv[i+1]));
460 machine_set_const(m, "ARGV", ary);
463 /* utility: checks whether string contains only digits */
464 int is_number(char *str) {
465 while(*str) {
466 if(!isdigit(*str)) return FALSE;
467 str++;
470 return TRUE;
473 /* utility: strips trailing non-alnum chars from string */
474 static char *trim_str(char *str) {
475 int i;
476 while(*str && !isalnum(*str) && *str != '/') str++;
478 for(i = strlen(str) - 1; str[i] && !isalnum(str[i]) && *str != '/'; i++) {
479 str[i] = 0;
482 return str;
485 static void machine_parse_config_var(machine m, const char *input) {
486 char *name, *val, *var, *eq;
488 var = strdup(input);
489 eq = strchr(var, '=');
491 if(eq) {
492 *eq++ = 0;
494 name = trim_str(var);
495 val = trim_str(eq);
497 if(!strcmp("include", name)) {
498 machine_parse_config_file(m, val);
499 } else {
500 if(m->show_config) {
501 printf("[config] '%s' => '%s'\n", name, val);
504 ht_config_insert(m->s->config, cstr2bstr(name), cstr2bstr(val));
506 } else {
507 if(m->show_config) {
508 printf("[config] '%s' => '1'\n", var);
511 name = trim_str(var);
512 ht_config_insert(m->s->config, cstr2bstr(name), cstr2bstr("1"));
515 XFREE(var);
518 void machine_parse_configs(machine m, const char *config) {
519 char *semi;
520 char tmp[1024];
521 int sz;
522 semi = strstr(config, ";");
523 while(semi) {
524 sz = semi - config;
525 strncpy(tmp, config, sz);
526 tmp[sz] = 0;
527 machine_parse_config_var(m, tmp);
528 config += (sz + 1);
529 semi = strstr(config, ";");
532 machine_parse_config_var(m, config);
535 void machine_parse_config_file(machine m, const char *path) {
536 FILE *fo;
537 char line[1024];
539 fo = fopen(path, "r");
540 if(!fo) return;
542 while (fgets(line, sizeof(line), fo)) {
543 if(*line) {
544 machine_parse_config_var(m, line);
548 fclose(fo);
551 void machine_migrate_config(machine m) {
552 /* hash table iterator */
553 struct hashtable_itr iter;
554 rstate state = m->s;
555 OBJECT rbx_module;
557 /* initialize new hash for environment global configuration */
558 m->s->global->config = hash_new_sized(m->s, 500);
560 if(hashtable_count(m->s->config) > 0) {
561 hashtable_iterator_init(&iter, m->s->config);
563 do {
564 /* Key, value */
565 OBJECT ok, ov;
566 bstring k = (bstring)hashtable_iterator_key(&iter);
567 bstring v = (bstring)hashtable_iterator_value(&iter);
568 /* object key: Ruby string created from bstring library C string */
569 ok = string_newfrombstr(m->s, k);
570 if(is_number(bdata(v))) {
571 ov = LL2N(strtoll(bdatae(v,""), NULL, 10));
572 } else {
573 ov = string_newfrombstr(m->s, v);
576 hash_set(m->s, m->s->global->config, ok, ov);
577 } while (hashtable_iterator_advance(&iter));
580 /* Make Rubinius::RUBY_CONFIG point to global configuration */
581 rbx_module = rbs_const_get(m->s, m->s->global->object, "Rubinius");
582 machine_set_const_under(m, "RUBY_CONFIG", m->s->global->config, rbx_module);
583 machine_setup_from_config(m);
586 /* applies debug configuraiton options to VM state */
587 void machine_setup_from_config(machine m) {
588 bstring s;
590 s = cstr2bstr("rbx.debug.trace");
592 if(ht_config_search(m->s->config, s)) {
593 m->s->excessive_tracing = 1;
596 bassigncstr (s, "rbx.debug.gc");
598 if(ht_config_search(m->s->config, s)) {
599 m->s->gc_stats = 1;
602 bdestroy (s);
605 /* initializes platform and arc related Ruby constants like RUBY_PLATFORM, OS and L64 */
606 void machine_setup_config(machine m) {
607 OBJECT mod;
608 STATE;
610 state = m->s;
612 mod = rbs_const_get(m->s, m->s->global->object, "Rubinius");
613 machine_set_const(m, "RUBY_PLATFORM", string_new(m->s, CONFIG_HOST));
614 machine_set_const(m, "RUBY_RELEASE_DATE", string_new(m->s, CONFIG_RELDATE));
615 machine_set_const_under(m, "RBX_VERSION", string_new(m->s, CONFIG_VERSION), mod);
616 machine_set_const_under(m, "RUBY_VERSION", string_new(m->s, CONFIG_RUBY_VERSION), mod);
617 machine_set_const_under(m, "RUBY_PATCHLEVEL", string_new(m->s, CONFIG_RUBY_PATCHLEVEL), mod);
618 machine_set_const_under(m, "VERSION", string_new(m->s, CONFIG_RUBY_VERSION), mod);
619 machine_set_const_under(m, "RUBY_ENGINE", string_new(m->s, CONFIG_ENGINE), mod);
620 machine_set_const_under(m, "BUILDREV", string_new(m->s, CONFIG_BUILDREV), mod);
621 machine_set_const_under(m, "CODE_PATH", string_new(m->s, CONFIG_CODEPATH), mod);
622 machine_set_const_under(m, "EXT_PATH", string_new(m->s, CONFIG_EXTPATH), mod);
623 machine_set_const_under(m, "RBA_PATH", string_new(m->s, CONFIG_RBAPATH), mod);
625 machine_set_const_under(m, "WORDSIZE", I2N(CONFIG_WORDSIZE), mod);
627 #if defined(__ppc__) || defined(__POWERPC__) || defined(_POWER)
628 machine_set_const_under(m, "PLATFORM", SYM("ppc"), mod);
629 #elif defined(__amd64__)
630 machine_set_const_under(m, "PLATFORM", SYM("amd64"), mod);
631 #elif defined(i386) || defined(__i386__)
632 machine_set_const_under(m, "PLATFORM", SYM("x86"), mod);
633 #elif defined(__alpha) || defined(__alpha__)
634 machine_set_const_under(m, "PLATFORM", SYM("alpha"), mod);
635 #elif defined(VAX) || defined(__VAX)
636 machine_set_const_under(m, "PLATFORM", SYM("vax"), mod);
637 #elif defined(__hppa__)
638 machine_set_const_under(m, "PLATFORM", SYM("hppa"), mod);
639 #elif defined(__sparc__)
640 machine_set_const_under(m, "PLATFORM", SYM("sparc"), mod);
641 #elif defined(__s390__)
642 machine_set_const_under(m, "PLATFORM", SYM("s390"), mod);
643 #elif (defined(TARGET_CPU_68K) || defined(__CFM68K__) || defined(m68k) || defined(_M_M68K))
644 machine_set_const_under(m, "PLATFORM", SYM("m68k"), mod);
645 #else
646 machine_set_const_under(m, "PLATFORM", SYM("unknown"), mod);
647 #endif
649 #if defined(__APPLE__) || defined(__MACH__)
650 machine_set_const_under(m, "OS", SYM("darwin"), mod);
651 #elif defined(__linux__) || defined(linux) || defined(__linux)
652 machine_set_const_under(m, "OS", SYM("linux"), mod);
653 #elif defined(__FreeBSD__)
654 machine_set_const_under(m, "OS", SYM("freebsd"), mod);
655 #elif defined(__CYGWIN__)
656 machine_set_const_under(m, "OS", SYM("cygwin"), mod);
657 #elif defined(__OS2__)
658 machine_set_const_under(m, "OS", SYM("os2"), mod);
659 #elif defined(__NT__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
660 machine_set_const_under(m, "OS", SYM("win32"), mod);
661 #elif defined(__WINDOWS__)
662 machine_set_const_under(m, "OS", SYM("windows_3x"), mod);
663 #elif defined(__NETWARE_386__)
664 machine_set_const_under(m, "OS", SYM("netware"), mod);
665 #elif defined(__MSDOS__)
666 machine_set_const_under(m, "OS", SYM("dos"), mod);
667 #elif defined(VMS) || defined(__VMS__)
668 machine_set_const_under(m, "OS", SYM("vms"), mod);
669 #elif defined(__hpux__)
670 machine_set_const_under(m, "OS", SYM("hpux"), mod);
671 #elif defined(__sun__) || defined(__sun)
672 machine_set_const_under(m, "OS", SYM("solaris"), mod);
673 #elif defined(__svr4__)
674 machine_set_const_under(m, "OS", SYM("unixware"), mod);
675 #elif defined(_AIX)
676 machine_set_const_under(m, "OS", SYM("aix"), mod);
677 #elif (defined(_SCO_DS) && defined(_SCO_ELF) && defined(_SCO_XPG_VERS) && defined(_SCO_C_DIALECT))
678 machine_set_const_under(m, "OS", SYM("openserver"), mod);
679 #elif defined(__unix__)
680 machine_set_const_under(m, "OS", SYM("decunix"), mod);
681 #else
682 machine_set_const_under(m, "OS", SYM("unknown"), mod);
683 #endif
685 #if defined(__VERSION__)
686 machine_set_const_under(m, "COMPILER_VERSION", string_new(m->s, __VERSION__), mod);
687 #else
688 machine_set_const_under(m, "COMPILER_VERSION", Qnil, mod);
689 #endif
691 #if defined(_MSC_VER)
692 machine_set_const_under(m, "COMPILER", SYM("microsoft"), mod);
693 #elif defined(__DECC) || defined(VAXC)
694 machine_set_const_under(m, "COMPILER", SYM("digital"), mod);
695 #elif defined(__BORLANDC__)
696 machine_set_const_under(m, "COMPILER", SYM("borland"), mod);
697 #elif defined(__WATCOMC__)
698 machine_set_const_under(m, "COMPILER", SYM("watcom"), mod);
699 #elif defined(__GNUC__)
700 machine_set_const_under(m, "COMPILER", SYM("gcc"), mod);
701 #elif defined(__MWERKS__)
702 machine_set_const_under(m, "COMPILER", SYM("metrowerks"), mod);
703 #elif defined(__IBMC__) || defined(__IBMCPP__)
704 machine_set_const_under(m, "COMPILER", SYM("ibm"), mod);
705 #elif defined(__SUNPRO_C)
706 machine_set_const_under(m, "COMPILER", SYM("sunpro"), mod);
707 #else
708 machine_set_const_under(m, "COMPILER", SYM("unknown"), mod);
709 #endif
711 #if CONFIG_BIG_ENDIAN
712 machine_set_const_under(m, "ENDIAN", SYM("big"), mod);
713 #else
714 machine_set_const_under(m, "ENDIAN", SYM("little"), mod);
715 #endif
717 if(sizeof(long) == 8) {
718 machine_set_const_under(m, "L64", Qtrue, mod);
719 } else {
720 machine_set_const_under(m, "L64", Qfalse, mod);
723 /* Shared library file extension */
724 #if defined(_WIN32) || defined(__NT__) || defined(WIN32) || defined(__WIN32__)
725 #define LIBSUFFIX "dll"
726 #elif defined(__APPLE__)
727 #define LIBSUFFIX "bundle"
728 #define ALT_LIBSUFFIX "dylib"
729 #else
730 #define LIBSUFFIX "so"
731 #endif
733 machine_set_const_under(m, "LIBSUFFIX", string_new(m->s, LIBSUFFIX), mod);
734 #ifdef ALT_LIBSUFFIX
735 machine_set_const_under(m, "ALT_LIBSUFFIX", string_new(m->s, ALT_LIBSUFFIX), mod);
736 #endif
738 machine_set_const_under(m, "COMPILER_PATH", string_new(m->s, CONFIG_CC), mod);
740 if(isatty(0)) {
741 machine_set_const_under(m, "Terminal", string_new(m->s, ttyname(0)), mod);
742 } else {
743 machine_set_const_under(m, "Terminal", Qfalse, mod);
746 machine_set_const_under(m, "DEBUG_INST", I2N(CPU_INSTRUCTION_YIELD_DEBUGGER), mod);
748 machine_set_const_under(m, "VM_ID", I2N(m->id), mod);
749 machine_set_const_under(m, "VM_INFERIOR", m->sub ? Qtrue : Qfalse, mod);
751 /* This feels like the wrong place for this, but it works. */
752 machine_set_const_under(m, "MESSAGE_IO", io_new(m->s, m->message_read_fd, "r"), mod);
755 /* sets up debugging flags */
756 void machine_config_env(machine m) {
757 char *config;
758 if(getenv("RDEBUG")) {
759 debug_enable();
762 if(getenv("RBX_CONFIG")) {
763 m->show_config = 1;
766 config = getenv("RBX");
767 if(config) {
768 machine_parse_configs(m, config);
771 config = getenv("RBX_CONFFILE");
772 if(config) {
773 machine_parse_config_file(m, config);
777 /* loads files in the directory, respects load order hint file .load_order.txt */
778 int machine_load_directory(machine m, const char *prefix) {
779 char *path;
780 char *file;
781 FILE *fp;
782 size_t buf_siz = 1024, prefix_len;
784 prefix_len = strlen(prefix);
785 if(prefix_len > (buf_siz - 16)) return FALSE;
787 path = ALLOC_N(char, buf_siz);
788 memcpy(path, prefix, prefix_len);
789 strcpy(path + prefix_len, "/.load_order.txt");
791 fp = fopen(path, "r");
792 if(!fp) {
793 printf("Unable to open directory '%s'\n", prefix);
794 XFREE(path);
795 return FALSE;
798 file = &path[prefix_len + 1];
800 while (fgets(file, buf_siz - prefix_len, fp)) {
801 size_t file_len;
803 /* Get rid of the \n on the end. */
804 file_len = strlen(file);
806 if (path[prefix_len + file_len] == '\n')
807 path[prefix_len + file_len] = 0;
809 if(!machine_run_file(m, path)) {
810 XFREE(path);
811 fclose(fp);
812 return FALSE;
816 fclose(fp);
817 XFREE(path);
819 return TRUE;
822 int machine_load_object(machine m, char *name, uint8_t *data, long length) {
823 OBJECT cm;
825 if(m->s->excessive_tracing) {
826 printf("[ Loading archived file %s]\n", name);
829 cm = cpu_unmarshal(m->s, data, length, 0);
831 if(!RTEST(cm)) {
832 return FALSE;
835 /* We push this on the stack so it's properly seen by the GCs */
836 cpu_stack_push(m->s, m->c, cm, FALSE);
837 cpu_run_script(m->s, m->c, cm);
839 if(!machine_run(m)) {
840 printf("Unable to run '%s'\n", name);
841 return FALSE;
844 /* Pop the return value and script object. */
845 (void)cpu_stack_pop(m->s, m->c);
846 (void)cpu_stack_pop(m->s, m->c);
848 return TRUE;
852 * loads and executes Rubinius bytecode archive (*.rba, similar to *.jar or *.elc)
854 * Rubinius' rba files are essentialy zip archived bytecode. .load_order file
855 * must be loaded first to respect bytecode dependencies.
857 int machine_load_ar(machine m, const char *path) {
858 int ret = FALSE;
860 if(m->s->excessive_tracing) {
861 printf("[ Loading ar rba %s]\n", path);
864 ret = ar_each_file(m, path, machine_load_object);
866 if(m->s->excessive_tracing) {
867 printf("[ Finished loading ar rba %s]\n", path);
870 return ret;
873 int machine_load_rba(machine m, const char *path) {
874 return machine_load_ar(m, path);
877 int machine_load_bundle(machine m, const char *path) {
878 struct stat sb;
880 /* return false if file does no exist */
881 if(stat(path, &sb) != 0) return FALSE;
883 if(S_ISDIR(sb.st_mode)) {
884 return machine_load_directory(m, path);
887 return machine_load_rba(m, path);
890 /* 1. saves the command line arguments used to invoke the VM.
891 * 2. initializes platform and arc related Ruby constants
892 * 3. sets up debugging flags from configuration
893 * 4. sets standard IO streams (stdin, stdout, stderr) to Ruby constants STDIN, STDOUT and STDERR
895 void machine_setup_normal(machine m, int argc, char **argv) {
896 machine_save_args(m, argc, argv);
897 machine_setup_config(m);
898 machine_config_env(m);
899 machine_setup_standard_io(m);
903 * 1. sets inferior machine flag to true (inferior machine is one spawned by another, a "child")
904 * 2. saves the command line arguments used to invoke the VM.
905 * 3. initializes platform and arc related Ruby constants
906 * 4. sets up debugging flags from configuration
907 * 5. sets up piped IO streams (stdin, stdout, stderr) to Ruby constants STDIN, STDOUT and STDERR
909 int *machine_setup_thread(machine m, int argc, char **argv) {
910 m->sub = TRUE;
911 machine_save_args(m, argc, argv);
912 machine_setup_config(m);
913 machine_config_env(m);
914 return machine_setup_piped_io(m);