summaryrefslogtreecommitdiff
path: root/yarvcore.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-12-31 15:02:22 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-12-31 15:02:22 +0000
commita3e1b1ce7ed7e7ffac23015fc2fde56511b30681 (patch)
tree7b725552a9a4ded93849ca2faab1b257f7761790 /yarvcore.c
parent3e7566d8fb5138bb9cd647e5fdefc54fc9803509 (diff)
* Merge YARV
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11439 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'yarvcore.c')
-rw-r--r--yarvcore.c1078
1 files changed, 1078 insertions, 0 deletions
diff --git a/yarvcore.c b/yarvcore.c
new file mode 100644
index 0000000000..eb4e1a91e5
--- /dev/null
+++ b/yarvcore.c
@@ -0,0 +1,1078 @@
+/**********************************************************************
+
+ yarvcore.h -
+
+ $Author$
+ $Date$
+ created at: 04/01/01 01:17:22 JST
+
+ Copyright (C) 2004-2006 Koichi Sasada
+
+**********************************************************************/
+
+#include "ruby.h"
+#include "node.h"
+
+#include "yarv_version.h"
+#include "yarvcore.h"
+#include "yarv.h"
+#include "gc.h"
+
+VALUE mYarvCore;
+VALUE cYarvISeq;
+VALUE cYarvVM;
+VALUE cYarvThread;
+VALUE mYarvInsns;
+VALUE cYarvEnv;
+VALUE cYarvProc;
+VALUE cYarvBinding;
+
+VALUE symIFUNC;
+VALUE symCFUNC;
+
+ID idPLUS;
+ID idMINUS;
+ID idMULT;
+ID idDIV;
+ID idMOD;
+ID idLT;
+ID idLTLT;
+ID idLE;
+ID idEq;
+ID idEqq;
+ID idBackquote;
+ID idEqTilde;
+ID idThrowState;
+ID idAREF;
+ID idASET;
+ID idIntern;
+ID idMethodMissing;
+ID idLength;
+ID idLambda;
+ID idGets;
+ID idSucc;
+ID idEach;
+ID idRangeEachLT;
+ID idRangeEachLE;
+ID idArrayEach;
+ID idTimes;
+ID idEnd;
+ID idBitblt;
+ID idAnswer;
+ID idSvarPlaceholder;
+
+unsigned long yarvGlobalStateVersion = 1;
+
+
+/* from Ruby 1.9 eval.c */
+#ifdef HAVE_STDARG_PROTOTYPES
+#include <stdarg.h>
+#define va_init_list(a,b) va_start(a,b)
+#else
+#include <varargs.h>
+#define va_init_list(a,b) va_start(a)
+#endif
+
+VALUE yarv_th_eval(yarv_thread_t *th, VALUE iseqval);
+
+/************/
+/* YARVCore */
+/************/
+
+yarv_thread_t *yarvCurrentThread = 0;
+yarv_vm_t *theYarvVM = 0;
+static VALUE yarvVMArray = Qnil;
+
+RUBY_EXTERN int rb_thread_critical;
+RUBY_EXTERN int ruby_nerrs;
+RUBY_EXTERN NODE *ruby_eval_tree;
+
+VALUE
+yarv_load(char *file)
+{
+ NODE *node;
+ VALUE iseq;
+ volatile int critical;
+ yarv_thread_t *th = GET_THREAD();
+
+ critical = rb_thread_critical;
+ rb_thread_critical = Qtrue;
+ {
+ th->parse_in_eval++;
+ node = (NODE *)rb_load_file(file);
+ th->parse_in_eval--;
+ node = ruby_eval_tree;
+ }
+ rb_thread_critical = critical;
+
+ if (ruby_nerrs > 0) {
+ return 0;
+ }
+
+ iseq = yarv_iseq_new(node, rb_str_new2("<top (required)>"),
+ rb_str_new2(file), Qfalse, ISEQ_TYPE_TOP);
+
+ yarv_th_eval(GET_THREAD(), iseq);
+ return 0;
+}
+
+VALUE *th_svar(yarv_thread_t *self, int cnt);
+
+VALUE *
+rb_svar(int cnt)
+{
+ return th_svar(GET_THREAD(), cnt);
+}
+
+VALUE
+rb_backref_get(void)
+{
+ VALUE *var = rb_svar(1);
+ if (var) {
+ return *var;
+ }
+ return Qnil;
+}
+
+void
+rb_backref_set(VALUE val)
+{
+ VALUE *var = rb_svar(1);
+ *var = val;
+}
+
+VALUE
+rb_lastline_get(void)
+{
+ VALUE *var = rb_svar(0);
+ if (var) {
+ return *var;
+ }
+ return Qnil;
+}
+
+void
+rb_lastline_set(VALUE val)
+{
+ VALUE *var = rb_svar(0);
+ *var = val;
+}
+
+static NODE *
+compile_string(VALUE str, VALUE file, VALUE line)
+{
+ NODE *node;
+ node = rb_compile_string(StringValueCStr(file), str, NUM2INT(line));
+
+ if (ruby_nerrs > 0) {
+ ruby_nerrs = 0;
+ rb_exc_raise(GET_THREAD()->errinfo); // TODO: check err
+ }
+ return node;
+}
+
+static VALUE
+yarvcore_eval_iseq(VALUE iseq)
+{
+ return yarv_th_eval(GET_THREAD(), iseq);
+}
+
+static VALUE
+th_compile_from_node(yarv_thread_t *th, NODE * node, VALUE file)
+{
+ VALUE iseq;
+ if (th->base_block) {
+ iseq = yarv_iseq_new(node,
+ th->base_block->iseq->name,
+ file,
+ th->base_block->iseq->self,
+ ISEQ_TYPE_EVAL);
+ }
+ else {
+ iseq = yarv_iseq_new(node, rb_str_new2("<main>"), file,
+ Qfalse, ISEQ_TYPE_TOP);
+ }
+ return iseq;
+}
+
+VALUE
+th_compile(yarv_thread_t *th, VALUE str, VALUE file, VALUE line)
+{
+ NODE *node = (NODE *) compile_string(str, file, line);
+ return th_compile_from_node(th, (NODE *) node, file);
+}
+
+VALUE
+yarvcore_eval_parsed(NODE *node, VALUE file)
+{
+ VALUE iseq = th_compile_from_node(GET_THREAD(), node, file);
+ return yarvcore_eval_iseq(iseq);
+}
+
+VALUE
+yarvcore_eval(VALUE self, VALUE str, VALUE file, VALUE line)
+{
+ NODE *node;
+ node = compile_string(str, file, line);
+ return yarvcore_eval_parsed(node, file);
+}
+
+/******/
+/* VM */
+/******/
+
+void native_thread_cleanup(void *);
+
+static void
+vm_free(void *ptr)
+{
+ FREE_REPORT_ENTER("vm");
+ if (ptr) {
+ yarv_vm_t *vmobj = ptr;
+
+ st_free_table(vmobj->living_threads);
+ // TODO: MultiVM Instance
+ // VM object should not be cleaned by GC
+ // ruby_xfree(ptr);
+ // theYarvVM = 0;
+ }
+ FREE_REPORT_LEAVE("vm");
+}
+
+static int
+vm_mark_each_thread_func(st_data_t key, st_data_t value, st_data_t dummy)
+{
+ VALUE thval = (VALUE)key;
+ rb_gc_mark(thval);
+ return ST_CONTINUE;
+}
+
+static void
+vm_mark(void *ptr)
+{
+ MARK_REPORT_ENTER("vm");
+ GC_INFO("-------------------------------------------------\n");
+ if (ptr) {
+ yarv_vm_t *vm = ptr;
+ if (vm->living_threads) {
+ st_foreach(vm->living_threads, vm_mark_each_thread_func, 0);
+ }
+ MARK_UNLESS_NULL(vm->thgroup_default);
+ MARK_UNLESS_NULL(vm->mark_object_ary);
+ }
+ MARK_REPORT_LEAVE("vm");
+}
+
+static VALUE
+vm_alloc(VALUE klass)
+{
+ VALUE volatile obj;
+ yarv_vm_t *vm;
+ obj = Data_Make_Struct(klass, yarv_vm_t, vm_mark, vm_free, vm);
+
+ vm->self = obj;
+ vm->mark_object_ary = rb_ary_new();
+ return obj;
+}
+
+static void
+vm_init2(yarv_vm_t *vm)
+{
+ MEMZERO(vm, yarv_vm_t, 1);
+}
+
+
+/**********/
+/* Thread */
+/**********/
+
+static void
+thread_free(void *ptr)
+{
+ yarv_thread_t *th;
+ FREE_REPORT_ENTER("thread");
+
+ if (ptr) {
+ th = ptr;
+ FREE_UNLESS_NULL(th->stack);
+ FREE_UNLESS_NULL(th->top_local_tbl);
+
+ if (th->local_storage) {
+ st_free_table(th->local_storage);
+ }
+
+#if USE_VALUE_CACHE
+ {
+ VALUE *ptr = th->value_cache_ptr;
+ while (*ptr) {
+ VALUE v = *ptr;
+ RBASIC(v)->flags = 0;
+ RBASIC(v)->klass = 0;
+ ptr++;
+ }
+ }
+#endif
+
+ if (th->vm->main_thread == th) {
+ GC_INFO("main thread\n");
+ }
+ else {
+ ruby_xfree(ptr);
+ }
+ }
+ FREE_REPORT_LEAVE("thread");
+}
+
+void yarv_machine_stack_mark(yarv_thread_t *th);
+
+static void
+thread_mark(void *ptr)
+{
+ yarv_thread_t *th = NULL;
+ MARK_REPORT_ENTER("thread");
+ if (ptr) {
+ th = ptr;
+ if (th->stack) {
+ VALUE *p = th->stack;
+ VALUE *sp = th->cfp->sp;
+ yarv_control_frame_t *cfp = th->cfp;
+ yarv_control_frame_t *limit_cfp =
+ (void *)(th->stack + th->stack_size);
+
+ while (p < sp) {
+ rb_gc_mark(*p++);
+ }
+ while (cfp != limit_cfp) {
+ rb_gc_mark(cfp->proc);
+ cfp = YARV_PREVIOUS_CONTROL_FRAME(cfp);
+ }
+ }
+
+ /* mark ruby objects */
+ MARK_UNLESS_NULL(th->first_proc);
+ MARK_UNLESS_NULL(th->first_args);
+
+ MARK_UNLESS_NULL(th->thgroup);
+ MARK_UNLESS_NULL(th->value);
+ MARK_UNLESS_NULL(th->errinfo);
+ MARK_UNLESS_NULL(th->local_svar);
+
+ rb_mark_tbl(th->local_storage);
+
+ if (GET_THREAD() != th &&
+ th->machine_stack_start && th->machine_stack_end) {
+ yarv_machine_stack_mark(th);
+ rb_gc_mark_locations((VALUE *)&th->machine_regs,
+ (VALUE *)(&th->machine_regs) +
+ sizeof(th->machine_regs) / sizeof(VALUE));
+ }
+ }
+
+ MARK_UNLESS_NULL(th->stat_insn_usage);
+ MARK_REPORT_LEAVE("thread");
+}
+
+static VALUE
+thread_alloc(VALUE klass)
+{
+ VALUE volatile obj;
+ yarv_thread_t *th;
+ obj = Data_Make_Struct(klass, yarv_thread_t,
+ thread_mark, thread_free, th);
+ return obj;
+}
+
+static void
+th_init2(yarv_thread_t *th)
+{
+ MEMZERO(th, yarv_thread_t, 1);
+
+ /* allocate thread stack */
+ th->stack = ALLOC_N(VALUE, YARV_THREAD_STACK_SIZE);
+
+ th->stack_size = YARV_THREAD_STACK_SIZE;
+ th->cfp = (void *)(th->stack + th->stack_size);
+ th->cfp--;
+
+ th->cfp->pc = 0;
+ th->cfp->sp = th->stack;
+ th->cfp->bp = 0;
+ th->cfp->lfp = th->stack;
+ th->cfp->dfp = th->stack;
+ th->cfp->self = Qnil;
+ th->cfp->magic = 0;
+ th->cfp->iseq = 0;
+ th->cfp->proc = 0;
+ th->cfp->block_iseq = 0;
+
+ th->status = THREAD_RUNNABLE;
+ th->errinfo = Qnil;
+
+#if USE_VALUE_CACHE
+ th->value_cache_ptr = &th->value_cache[0];
+#endif
+}
+
+void
+th_klass_init(yarv_thread_t *th)
+{
+ /* */
+}
+
+static void
+th_init(yarv_thread_t *th)
+{
+ th_init2(th);
+ th_klass_init(th);
+}
+
+static VALUE
+thread_init(VALUE self)
+{
+ yarv_thread_t *th;
+ yarv_vm_t *vm = GET_THREAD()->vm;
+ GetThreadPtr(self, th);
+
+ th_init(th);
+ th->self = self;
+ th->vm = vm;
+ return self;
+}
+
+VALUE
+yarv_thread_alloc(VALUE klass)
+{
+ VALUE self = thread_alloc(klass);
+ thread_init(self);
+ return self;
+}
+
+VALUE th_eval_body(yarv_thread_t *th);
+void th_set_top_stack(yarv_thread_t *, VALUE iseq);
+VALUE rb_f_binding(VALUE);
+
+VALUE
+yarv_th_eval(yarv_thread_t *th, VALUE iseqval)
+{
+ VALUE val;
+ volatile VALUE tmp;
+
+ th_set_top_stack(th, iseqval);
+
+ if (!rb_const_defined(rb_cObject, rb_intern("TOPLEVEL_BINDING"))) {
+ rb_define_global_const("TOPLEVEL_BINDING", rb_f_binding(Qnil));
+ }
+ val = th_eval_body(th);
+ tmp = iseqval; /* prohibit tail call optimization */
+ return val;
+}
+
+
+/***************/
+/* YarvEnv */
+/***************/
+
+static void
+env_free(void *ptr)
+{
+ yarv_env_t *env;
+ FREE_REPORT_ENTER("env");
+ if (ptr) {
+ env = ptr;
+ FREE_UNLESS_NULL(env->env);
+ ruby_xfree(ptr);
+ }
+ FREE_REPORT_LEAVE("env");
+}
+
+static void
+env_mark(void *ptr)
+{
+ yarv_env_t *env;
+ MARK_REPORT_ENTER("env");
+ if (ptr) {
+ env = ptr;
+ if (env->env) {
+ /* TODO: should mark more restricted range */
+ GC_INFO("env->env\n");
+ rb_gc_mark_locations(env->env, env->env + env->env_size);
+ }
+ GC_INFO("env->prev_envval\n");
+ MARK_UNLESS_NULL(env->prev_envval);
+
+ if (env->block.iseq) {
+ //printf("env->block.iseq <%p, %d>\n",
+ // env->block.iseq, BUILTIN_TYPE(env->block.iseq));
+ if (BUILTIN_TYPE(env->block.iseq) == T_NODE) {
+ MARK_UNLESS_NULL((VALUE)env->block.iseq);
+ }
+ else {
+ MARK_UNLESS_NULL(env->block.iseq->self);
+ }
+ }
+ }
+ MARK_REPORT_LEAVE("env");
+}
+
+VALUE
+yarv_env_alloc(VALUE klass)
+{
+ VALUE obj;
+ yarv_env_t *env;
+ obj = Data_Make_Struct(klass, yarv_env_t, env_mark, env_free, env);
+ env->env = 0;
+ env->prev_envval = 0;
+ env->block.iseq = 0;
+ return obj;
+}
+
+
+/***************/
+/* YarvProc */
+/***************/
+
+static void
+proc_free(void *ptr)
+{
+ FREE_REPORT_ENTER("proc");
+ if (ptr) {
+ ruby_xfree(ptr);
+ }
+ FREE_REPORT_LEAVE("proc");
+}
+
+static void
+proc_mark(void *ptr)
+{
+ yarv_proc_t *proc;
+ MARK_REPORT_ENTER("proc");
+ if (ptr) {
+ proc = ptr;
+ MARK_UNLESS_NULL(proc->envval);
+ MARK_UNLESS_NULL(proc->blockprocval);
+ MARK_UNLESS_NULL((VALUE)proc->special_cref_stack);
+ if (proc->block.iseq && YARV_IFUNC_P(proc->block.iseq)) {
+ MARK_UNLESS_NULL((VALUE)(proc->block.iseq));
+ }
+ }
+ MARK_REPORT_LEAVE("proc");
+}
+
+static VALUE
+proc_alloc(VALUE klass)
+{
+ VALUE obj;
+ yarv_proc_t *proc;
+ obj = Data_Make_Struct(klass, yarv_proc_t, proc_mark, proc_free, proc);
+ MEMZERO(proc, yarv_proc_t, 1);
+ return obj;
+}
+
+VALUE
+yarv_proc_alloc(VALUE klass)
+{
+ return proc_alloc(cYarvProc);
+}
+
+static VALUE
+proc_call(int argc, VALUE *argv, VALUE procval)
+{
+ yarv_proc_t *proc;
+ GetProcPtr(procval, proc);
+ return th_invoke_proc(GET_THREAD(), proc, proc->block.self, argc, argv);
+}
+
+static VALUE
+proc_yield(int argc, VALUE *argv, VALUE procval)
+{
+ yarv_proc_t *proc;
+ GetProcPtr(procval, proc);
+ return th_invoke_proc(GET_THREAD(), proc, proc->block.self, argc, argv);
+}
+
+static VALUE
+proc_to_proc(VALUE self)
+{
+ return self;
+}
+
+VALUE
+yarv_obj_is_proc(VALUE proc)
+{
+ if (TYPE(proc) == T_DATA &&
+ RDATA(proc)->dfree == (RUBY_DATA_FUNC) proc_free) {
+ return Qtrue;
+ }
+ else {
+ return Qfalse;
+ }
+}
+
+static VALUE
+proc_arity(VALUE self)
+{
+ yarv_proc_t *proc;
+ yarv_iseq_t *iseq;
+ GetProcPtr(self, proc);
+ iseq = proc->block.iseq;
+ if (iseq && BUILTIN_TYPE(iseq) != T_NODE) {
+ if (iseq->arg_rest == 0 && iseq->arg_opts == 0) {
+ return INT2FIX(iseq->argc);
+ }
+ else {
+ return INT2FIX(-iseq->argc - 1);
+ }
+ }
+ else {
+ return INT2FIX(-1);
+ }
+}
+
+int
+rb_proc_arity(VALUE proc)
+{
+ return FIX2INT(proc_arity(proc));
+}
+
+static VALUE
+proc_eq(VALUE self, VALUE other)
+{
+ if (self == other) {
+ return Qtrue;
+ }
+ else {
+ if (TYPE(other) == T_DATA &&
+ RBASIC(other)->klass == cYarvProc &&
+ CLASS_OF(self) == CLASS_OF(other)) {
+ yarv_proc_t *p1, *p2;
+ GetProcPtr(self, p1);
+ GetProcPtr(other, p2);
+ if (p1->block.iseq == p2->block.iseq && p1->envval == p2->envval) {
+ return Qtrue;
+ }
+ }
+ }
+ return Qfalse;
+}
+
+static VALUE
+proc_hash(VALUE self)
+{
+ int hash;
+ yarv_proc_t *proc;
+ GetProcPtr(self, proc);
+ hash = (long)proc->block.iseq;
+ hash ^= (long)proc->envval;
+ hash ^= (long)proc->block.lfp >> 16;
+ return INT2FIX(hash);
+}
+
+static VALUE
+proc_to_s(VALUE self)
+{
+ VALUE str = 0;
+ yarv_proc_t *proc;
+ char *cname = rb_obj_classname(self);
+ yarv_iseq_t *iseq;
+
+ GetProcPtr(self, proc);
+ iseq = proc->block.iseq;
+
+ if (YARV_NORMAL_ISEQ_P(iseq)) {
+ int line_no = 0;
+
+ if (iseq->insn_info_tbl) {
+ line_no = iseq->insn_info_tbl[0].line_no;
+ }
+ str = rb_sprintf("#<%s:%lx@%s:%d>", cname, self,
+ RSTRING_PTR(iseq->file_name),
+ line_no);
+ }
+ else {
+ str = rb_sprintf("#<%s:%p>", cname, proc->block.iseq);
+ }
+
+ if (OBJ_TAINTED(self)) {
+ OBJ_TAINT(str);
+ }
+ return str;
+}
+
+static VALUE
+proc_dup(VALUE self)
+{
+ VALUE procval = proc_alloc(cYarvProc);
+ yarv_proc_t *src, *dst;
+ GetProcPtr(self, src);
+ GetProcPtr(procval, dst);
+
+ dst->block = src->block;
+ dst->envval = src->envval;
+ dst->safe_level = dst->safe_level;
+ dst->special_cref_stack = src->special_cref_stack;
+
+ return procval;
+}
+
+VALUE yarv_proc_dup(VALUE self)
+{
+ return proc_dup(self);
+}
+static VALUE
+proc_clone(VALUE self)
+{
+ VALUE procval = proc_dup(self);
+ CLONESETUP(procval, self);
+ return procval;
+}
+
+
+/***************/
+/* YarvBinding */
+/***************/
+
+static void
+binding_free(void *ptr)
+{
+ yarv_binding_t *bind;
+ FREE_REPORT_ENTER("binding");
+ if (ptr) {
+ bind = ptr;
+ ruby_xfree(ptr);
+ }
+ FREE_REPORT_LEAVE("binding");
+}
+
+static void
+binding_mark(void *ptr)
+{
+ yarv_binding_t *bind;
+ MARK_REPORT_ENTER("binding");
+ if (ptr) {
+ bind = ptr;
+ MARK_UNLESS_NULL(bind->env);
+ MARK_UNLESS_NULL((VALUE)bind->cref_stack);
+ }
+ MARK_REPORT_LEAVE("binding");
+}
+
+static VALUE
+binding_alloc(VALUE klass)
+{
+ VALUE obj;
+ yarv_binding_t *bind;
+ obj = Data_Make_Struct(klass, yarv_binding_t,
+ binding_mark, binding_free, bind);
+ MEMZERO(bind, yarv_binding_t, 1);
+ return obj;
+}
+
+VALUE
+yarv_binding_alloc(VALUE klass)
+{
+ return binding_alloc(klass);
+}
+
+static VALUE
+binding_dup(VALUE self)
+{
+ VALUE bindval = binding_alloc(cYarvBinding);
+ yarv_binding_t *src, *dst;
+ GetBindingPtr(self, src);
+ GetBindingPtr(bindval, dst);
+ dst->env = src->env;
+ dst->cref_stack = src->cref_stack;
+ return bindval;
+}
+
+static VALUE
+binding_clone(VALUE self)
+{
+ VALUE bindval = binding_dup(self);
+ CLONESETUP(bindval, self);
+ return bindval;
+}
+
+
+/********************************************************************/
+
+static VALUE
+yarv_once()
+{
+ return rb_yield(Qnil);
+}
+
+static VALUE
+yarv_segv()
+{
+ volatile int *a = 0;
+ *a = 0;
+ return Qnil;
+}
+
+static VALUE
+cfunc(void)
+{
+ rb_funcall(Qnil, rb_intern("rfunc"), 0, 0);
+ rb_funcall(Qnil, rb_intern("rfunc"), 0, 0);
+ return Qnil;
+}
+
+// VALUE yarv_Hash_each();
+VALUE insns_name_array(void);
+VALUE Init_yarvthread(void);
+extern VALUE *rb_gc_stack_start;
+
+VALUE rb_proc_s_new(VALUE klass);
+
+VALUE
+sdr(void)
+{
+ yarv_bug();
+ return Qnil;
+}
+
+static VALUE
+nsdr(void)
+{
+ VALUE ary = rb_ary_new();
+#if HAVE_BACKTRACE
+#include <execinfo.h>
+#define MAX_NATIVE_TRACE 1024
+ static void *trace[MAX_NATIVE_TRACE];
+ int n = backtrace(trace, MAX_NATIVE_TRACE);
+ char **syms = backtrace_symbols(trace, n);
+ int i;
+
+ if (syms == 0) {
+ rb_memerror();
+ }
+
+ for (i=0; i<n; i++) {
+ rb_ary_push(ary, rb_str_new2(syms[i]));
+ }
+ free(syms);
+#endif
+ return ary;
+}
+
+char yarv_version[0x20];
+char *yarv_options = ""
+#if OPT_DIRECT_THREADED_CODE
+ "[direct threaded code] "
+#elif OPT_TOKEN_THREADED_CODE
+ "[token threaded code] "
+#elif OPT_CALL_THREADED_CODE
+ "[call threaded code] "
+#endif
+
+#if OPT_BASIC_OPERATIONS
+ "[optimize basic operation] "
+#endif
+#if OPT_STACK_CACHING
+ "[stack caching] "
+#endif
+#if OPT_OPERANDS_UNIFICATION
+ "[operands unification] "
+#endif
+#if OPT_INSTRUCTIONS_UNIFICATION
+ "[instructions unification] "
+#endif
+#if OPT_INLINE_METHOD_CACHE
+ "[inline method cache] "
+#endif
+#if OPT_BLOCKINLINING
+ "[block inlining] "
+#endif
+ ;
+
+void Init_ISeq(void);
+
+void
+Init_yarvcore(void)
+{
+ const char *rev = "$Rev:$";
+ const char *date = "$Date:$";
+
+ snprintf(yarv_version, 0x20, "YARVCore %d.%d.%d",
+ MAJOR_VER, MINOR_VER, DEVEL_VER);
+
+ /* declare YARVCore module */
+ mYarvCore = rb_define_module("YARVCore");
+ rb_define_const(mYarvCore, "VERSION", rb_str_new2(yarv_version));
+ rb_define_const(mYarvCore, "MAJOR", INT2FIX(MAJOR_VER));
+ rb_define_const(mYarvCore, "MINOR", INT2FIX(MINOR_VER));
+ rb_define_const(mYarvCore, "REV", rb_str_new2(rev));
+ rb_define_const(mYarvCore, "DATE", rb_str_new2(date));
+ rb_define_const(mYarvCore, "OPTS", rb_str_new2(yarv_options));
+
+ Init_ISeq();
+
+ /* YARVCore::USAGE_ANALISYS_* */
+ rb_define_const(mYarvCore, "USAGE_ANALISYS_INSN", rb_hash_new());
+ rb_define_const(mYarvCore, "USAGE_ANALISYS_REGS", rb_hash_new());
+ rb_define_const(mYarvCore, "USAGE_ANALISYS_INSN_BIGRAM", rb_hash_new());
+
+ /* YARVCore::InsnNameArray */
+ rb_define_const(mYarvCore, "InsnNameArray", insns_name_array());
+
+ rb_define_singleton_method(mYarvCore, "eval", yarvcore_eval, 3);
+
+ /* declare YARVCore::VM */
+ cYarvVM = rb_define_class_under(mYarvCore, "VM", rb_cObject);
+ rb_undef_alloc_func(cYarvVM);
+
+ /* declare YARVCore::VM::Thread */
+ cYarvThread = rb_define_class_under(cYarvVM, "Thread", rb_cObject);
+ rb_define_global_const("Thread", cYarvThread);
+ rb_undef_alloc_func(cYarvThread);
+ rb_define_method(cYarvThread, "initialize", thread_init, 0);
+
+ /* declare YARVCore::VM::Env */
+ cYarvEnv = rb_define_class_under(cYarvVM, "Env", rb_cObject);
+ rb_undef_alloc_func(cYarvEnv);
+
+ /* declare YARVCore::VM::Proc */
+ rb_cProc = cYarvProc = rb_define_class_under(cYarvVM, "Proc", rb_cObject);
+ rb_const_set(rb_cObject, rb_intern("Proc"), cYarvProc);
+ rb_undef_alloc_func(cYarvProc);
+ rb_define_singleton_method(cYarvProc, "new", rb_proc_s_new, 0);
+ rb_define_method(cYarvProc, "call", proc_call, -1);
+ rb_define_method(cYarvProc, "[]", proc_call, -1);
+ rb_define_method(cYarvProc, "yield", proc_yield, -1);
+ rb_define_method(cYarvProc, "to_proc", proc_to_proc, 0);
+ rb_define_method(cYarvProc, "arity", proc_arity, 0);
+ rb_define_method(cYarvProc, "clone", proc_clone, 0);
+ rb_define_method(cYarvProc, "dup", proc_dup, 0);
+ rb_define_method(cYarvProc, "==", proc_eq, 1);
+ rb_define_method(cYarvProc, "eql?", proc_eq, 1);
+ rb_define_method(cYarvProc, "hash", proc_hash, 0);
+ rb_define_method(cYarvProc, "to_s", proc_to_s, 0);
+
+ /* declare YARVCore::VM::Binding */
+ cYarvBinding = rb_define_class_under(cYarvVM, "Binding", rb_cObject);
+ rb_const_set(rb_cObject, rb_intern("Binding"), cYarvBinding);
+ rb_undef_alloc_func(cYarvBinding);
+ rb_undef_method(CLASS_OF(cYarvBinding), "new");
+ rb_define_method(cYarvBinding, "clone", binding_clone, 0);
+ rb_define_method(cYarvBinding, "dup", binding_dup, 0);
+ rb_define_global_function("binding", rb_f_binding, 0);
+
+ /* misc */
+
+
+ /* YARV test functions */
+
+ rb_define_global_function("once", yarv_once, 0);
+ rb_define_global_function("segv", yarv_segv, 0);
+ rb_define_global_function("cfunc", cfunc, 0);
+ rb_define_global_function("SDR", sdr, 0);
+ rb_define_global_function("NSDR", nsdr, 0);
+
+ symIFUNC = ID2SYM(rb_intern("<IFUNC>"));
+ symCFUNC = ID2SYM(rb_intern("<CFUNC>"));
+
+ /* for optimize */
+ idPLUS = rb_intern("+");
+ idMINUS = rb_intern("-");
+ idMULT = rb_intern("*");
+ idDIV = rb_intern("/");
+ idMOD = rb_intern("%");
+ idLT = rb_intern("<");
+ idLTLT = rb_intern("<<");
+ idLE = rb_intern("<=");
+ idEq = rb_intern("==");
+ idEqq = rb_intern("===");
+ idBackquote = rb_intern("`");
+ idEqTilde = rb_intern("=~");
+
+ idAREF = rb_intern("[]");
+ idASET = rb_intern("[]=");
+
+ idEach = rb_intern("each");
+ idTimes = rb_intern("times");
+ idLength = rb_intern("length");
+ idLambda = rb_intern("lambda");
+ idIntern = rb_intern("intern");
+ idGets = rb_intern("gets");
+ idSucc = rb_intern("succ");
+ idEnd = rb_intern("end");
+ idRangeEachLT = rb_intern("Range#each#LT");
+ idRangeEachLE = rb_intern("Range#each#LE");
+ idArrayEach = rb_intern("Array#each");
+ idMethodMissing = rb_intern("method_missing");
+
+ idThrowState = rb_intern("#__ThrowState__");
+
+ idBitblt = rb_intern("bitblt");
+ idAnswer = rb_intern("the_answer_to_life_the_universe_and_everything");
+ idSvarPlaceholder = rb_intern("#svar");
+
+#if TEST_AOT_COMPILE
+ Init_compiled();
+#endif
+ // make vm
+ {
+ /* create vm object */
+ VALUE vmval = vm_alloc(cYarvVM);
+ VALUE thval;
+
+ yarv_vm_t *vm;
+ yarv_thread_t *th;
+ vm = theYarvVM;
+
+ xfree(RDATA(vmval)->data);
+ RDATA(vmval)->data = vm;
+ vm->self = vmval;
+
+ yarvVMArray = rb_ary_new();
+ rb_register_mark_object(yarvVMArray);
+ rb_ary_push(yarvVMArray, vm->self);
+
+ /* create main thread */
+ thval = yarv_thread_alloc(cYarvThread);
+ GetThreadPtr(thval, th);
+
+ vm->main_thread = th;
+ vm->running_thread = th;
+ GET_THREAD()->vm = vm;
+ thread_free(GET_THREAD());
+ th->vm = vm;
+ yarv_set_current_running_thread(th);
+
+ th->machine_stack_start = rb_gc_stack_start;
+ vm->living_threads = st_init_numtable();
+ st_insert(vm->living_threads, th->self, (st_data_t) th->thread_id);
+
+ Init_yarvthread();
+ th->thgroup = th->vm->thgroup_default;
+ }
+ yarv_init_redefined_flag();
+}
+
+static void
+test(void)
+{
+ int i;
+ int *p;
+ printf("!test!\n");
+ for (i = 0; i < 1000000; i++) {
+ p = ALLOC(int);
+ }
+}
+
+void
+Init_yarv(void)
+{
+ /* initialize main thread */
+ yarv_vm_t *vm = ALLOC(yarv_vm_t);
+ yarv_thread_t *th = ALLOC(yarv_thread_t);
+
+ vm_init2(vm);
+ theYarvVM = vm;
+
+ th_init2(th);
+ th->vm = vm;
+ th->machine_stack_start = rb_gc_stack_start;
+ yarv_set_current_running_thread_raw(th);
+}