[macruby-changes] [4213] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Tue Jun 8 21:50:35 PDT 2010


Revision: 4213
          http://trac.macosforge.org/projects/ruby/changeset/4213
Author:   lsansonetti at apple.com
Date:     2010-06-08 21:50:33 -0700 (Tue, 08 Jun 2010)
Log Message:
-----------
now interpreting potential cold paths (work in progress)

Modified Paths:
--------------
    MacRuby/trunk/HACKING.rdoc
    MacRuby/trunk/compiler.cpp
    MacRuby/trunk/compiler.h
    MacRuby/trunk/kernel.c
    MacRuby/trunk/rakelib/builder/builder.rb
    MacRuby/trunk/vm.cpp
    MacRuby/trunk/vm.h

Added Paths:
-----------
    MacRuby/trunk/interpreter.cpp
    MacRuby/trunk/interpreter.h

Modified: MacRuby/trunk/HACKING.rdoc
===================================================================
--- MacRuby/trunk/HACKING.rdoc	2010-06-08 01:25:44 UTC (rev 4212)
+++ MacRuby/trunk/HACKING.rdoc	2010-06-09 04:50:33 UTC (rev 4213)
@@ -118,6 +118,9 @@
 
 * VM_DISABLE_RBO: set it to any value to disable the load of .rbo files.
 
+* VM_DISABLE_INTERPRETER: set it to any value to disable the use of the
+  builtin interpreter (generally used on cold paths).
+
 * VM_DUMP_IR: set it to any value to dump the LLVM IR on $stderr before the
   interpreter quits.
 

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2010-06-08 01:25:44 UTC (rev 4212)
+++ MacRuby/trunk/compiler.cpp	2010-06-09 04:50:33 UTC (rev 4213)
@@ -1,5 +1,5 @@
 /*
- * MacRuby compiler.
+ * MacRuby Compiler.
  *
  * This file is covered by the Ruby license. See COPYING for more details.
  * 
@@ -40,6 +40,7 @@
     assert(RoxorCompiler::module != NULL);
     debug_info = new DIFactory(*RoxorCompiler::module);
 
+    can_interpret = false;
     debug_mode = _debug_mode;
     fname = "";
     inside_eval = false;
@@ -591,6 +592,56 @@
 }
 
 void
+RoxorCompiler::compile_method_definition(NODE *node)
+{
+    ID mid = node->nd_mid;
+    assert(mid > 0);
+
+    NODE *body = node->nd_defn;
+    assert(body != NULL);
+
+    const bool singleton_method = nd_type(node) == NODE_DEFS;
+
+    const ID old_current_mid = current_mid;
+    current_mid = mid;
+    current_instance_method = !singleton_method;
+    const bool old_current_block_chain = current_block_chain;
+    current_block_chain = false;
+    const bool old_block_declaration = block_declaration;
+    block_declaration = false;
+    const bool old_should_interpret = should_interpret;
+
+    DEBUG_LEVEL_INC();
+    Value *val = compile_node(body);
+    assert(Function::classof(val));
+    Function *func = cast<Function>(val);
+    DEBUG_LEVEL_DEC();
+
+    should_interpret = old_should_interpret;
+    block_declaration = old_block_declaration;
+    current_block_chain = old_current_block_chain;
+    current_mid = old_current_mid;
+    current_instance_method = false;
+
+    Value *classVal;
+    if (singleton_method) {
+	assert(node->nd_recv != NULL);
+	classVal = compile_singleton_class(compile_node(node->nd_recv));
+    }
+    else {
+	classVal = compile_current_class();
+    }
+
+    rb_vm_arity_t arity = rb_vm_node_arity(body);
+    const SEL sel = mid_to_sel(mid, arity.real);
+
+    compile_prepare_method(classVal, compile_sel(sel), singleton_method,
+	    func, arity, body);
+
+    can_interpret = true;
+}
+
+void
 RoxorCompiler::compile_prepare_method(Value *classVal, Value *sel,
 	bool singleton, Function *new_function, rb_vm_arity_t &arity,
 	NODE *body)
@@ -1178,7 +1229,7 @@
 }
 
 Value *
-RoxorCompiler::compile_ivar_read(ID vid)
+RoxorCompiler::compile_ivar_get(ID vid)
 {
     Value *args[] = {
 	current_self,
@@ -1229,6 +1280,9 @@
 Value *
 RoxorCompiler::compile_gvar_assignment(NODE *node, Value *val)
 {
+    assert(node->nd_vid > 0);
+    assert(node->nd_entry != NULL);
+
     if (gvarSetFunc == NULL) {
 	// VALUE rb_gvar_set(struct global_entry *entry, VALUE val);
 	gvarSetFunc = cast<Function>(module->getOrInsertFunction(
@@ -1244,6 +1298,22 @@
 }
 
 Value *
+RoxorCompiler::compile_gvar_get(NODE *node)
+{
+    assert(node->nd_vid > 0);
+    assert(node->nd_entry != NULL);
+
+    if (gvarGetFunc == NULL) {
+	// VALUE rb_gvar_get(struct global_entry *entry);
+	gvarGetFunc = cast<Function>(module->getOrInsertFunction(
+		    "rb_gvar_get", RubyObjTy, PtrTy, NULL));
+    }
+
+    return CallInst::Create(gvarGetFunc, compile_global_entry(node),
+	    "", bb);
+}
+
+Value *
 RoxorCompiler::compile_constant_declaration(NODE *node, Value *val)
 {
     int flags = 0;
@@ -3015,11 +3085,15 @@
 		    || sel == selBinding))) {
 	compile_binding();
     }
+    else {
+	can_interpret = true;
+    }
 
     // Can we optimize the call?
     if (!super_call && !splat_args) {
 	Value *opt_call = compile_optimized_dispatch_call(sel, argc, params);
 	if (opt_call != NULL) {
+	    can_interpret = false;
 	    return opt_call;
 	}
     }
@@ -3065,25 +3139,12 @@
     return val;
 }
 
-Value *
-RoxorCompiler::compile_node(NODE *node)
+inline Value *
+RoxorCompiler::compile_node0(NODE *node)
 {
-#if ROXOR_COMPILER_DEBUG
-    printf("%s:%ld ", fname, nd_line(node));
-    for (int i = 0; i < level; i++) {
-	printf("...");
-    }
-    printf("... %s\n", ruby_node_name(nd_type(node)));
-#endif
-    if (current_line != nd_line(node)) {
-	current_line = nd_line(node);
-	if (debug_mode) {
-	    compile_debug_trap();
-	}
-    }
-
     switch (nd_type(node)) {
 	case NODE_SCOPE:
+	    can_interpret = true;
 	    return cast<Value>(compile_scope(node));
 
 	case NODE_DVAR:
@@ -3092,25 +3153,10 @@
 	    return new LoadInst(compile_lvar_slot(node->nd_vid), "", bb);
 
 	case NODE_GVAR:
-	    {
-		assert(node->nd_vid > 0);
-		assert(node->nd_entry != NULL);
+	    return compile_gvar_get(node);
 
-		if (gvarGetFunc == NULL) {
-		    // VALUE rb_gvar_get(struct global_entry *entry);
-		    gvarGetFunc = cast<Function>(module->getOrInsertFunction(
-				"rb_gvar_get", RubyObjTy, PtrTy, NULL));
-		}
-
-		return CallInst::Create(gvarGetFunc,
-			compile_global_entry(node), "", bb);
-	    }
-	    break;
-
 	case NODE_GASGN:
-	    assert(node->nd_vid > 0);
 	    assert(node->nd_value != NULL);
-	    assert(node->nd_entry != NULL);
 	    return compile_gvar_assignment(node, compile_node(node->nd_value));
 
 	case NODE_CVAR:
@@ -3130,50 +3176,17 @@
 
 	case NODE_DASGN:
 	case NODE_DASGN_CURR:
+	    assert(node->nd_vid > 0);
+	    assert(node->nd_value != NULL);
+	    return compile_dvar_assignment(node->nd_vid,
+		    compile_node(node->nd_value));
+
 	case NODE_LASGN:
-	    {
-		assert(node->nd_vid > 0);
-		assert(node->nd_value != NULL);
+	    assert(node->nd_vid > 0);
+	    assert(node->nd_value != NULL);
+	    return compile_lvar_assignment(node->nd_vid,
+		    compile_node(node->nd_value));
 
-		Value *new_val = compile_node(node->nd_value);
-
-		const int type = nd_type(node);
-		if ((type == NODE_DASGN || type == NODE_DASGN_CURR)
-			&& running_block != NULL) {
-		    // Dynamic variables assignments inside a block are a
-		    // little bit complicated: if we are creating new objects
-		    // we do need to defeat the thread-local collector by
-		    // taking ownership of the objects, otherwise the TLC might
-		    // prematurely collect them. This is because the assignment
-		    // is done into another thread's stack, which is not
-		    // honored by the TLC.
-		    Value *flag = new BitCastInst(running_block, Int32PtrTy,
-			    "", bb);
-		    flag = new LoadInst(flag, "", bb);
-		    Value *flagv = ConstantInt::get(Int32Ty, VM_BLOCK_THREAD);
-		    flag = BinaryOperator::CreateAnd(flag, flagv, "", bb);
-		    Value *is_thread = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
-			    flag, flagv);
-
-		    Function *f = bb->getParent();
-		    BasicBlock *is_thread_bb = BasicBlock::Create(context, "",
-			    f);
-		    BasicBlock *merge_bb = BasicBlock::Create(context, "", f);
-
-		    BranchInst::Create(is_thread_bb, merge_bb, is_thread, bb);
-
-		    bb = is_thread_bb;
-		    CallInst::Create(releaseOwnershipFunc, new_val, "", bb);
-		    BranchInst::Create(merge_bb, bb);
-
-		    bb = merge_bb;
-		}
-
-		new StoreInst(new_val, compile_lvar_slot(node->nd_vid), bb);
-		return new_val;
-	    }
-	    break;
-
 	case NODE_OP_ASGN_OR:
 	    {
 		assert(node->nd_recv != NULL);
@@ -3735,9 +3748,7 @@
 			std::vector<Value *> params;
 			params.push_back(classVal);
 			params.push_back(compile_const_pointer(NULL));
-			Instruction *insn = compile_protected_call(f, params);
-			attach_current_line_metadata(insn);
-			val = insn;
+			val = compile_protected_call(f, params);
 
 			dynamic_class = old_dynamic_class;
 			compile_set_current_scope(classVal, defaultScope);
@@ -3790,9 +3801,10 @@
 
 	case NODE_IVAR:
 	    assert(node->nd_vid > 0);
-	    return compile_ivar_read(node->nd_vid);
+	    return compile_ivar_get(node->nd_vid);
 
 	case NODE_LIT:
+	    can_interpret = true;
 	case NODE_STR:
 	    assert(node->nd_lit != 0);
 	    return compile_literal(node->nd_lit);
@@ -3909,6 +3921,7 @@
 
 	case NODE_BLOCK:
 	    {
+		can_interpret = true;
 		NODE *n = node;
 		Value *val = NULL;
 
@@ -4021,53 +4034,9 @@
 
 	case NODE_DEFN:
 	case NODE_DEFS:
-	    {
-		ID mid = node->nd_mid;
-		assert(mid > 0);
+	    compile_method_definition(node);
+	    return nilVal;
 
-		NODE *body = node->nd_defn;
-		assert(body != NULL);
-
-		const bool singleton_method = nd_type(node) == NODE_DEFS;
-
-		const ID old_current_mid = current_mid;
-		current_mid = mid;
-		current_instance_method = !singleton_method;
-		const bool old_current_block_chain = current_block_chain;
-		current_block_chain = false;
-		const bool old_block_declaration = block_declaration;
-		block_declaration = false;
-
-		DEBUG_LEVEL_INC();
-		Value *val = compile_node(body);
-		assert(Function::classof(val));
-		Function *new_function = cast<Function>(val);
-		DEBUG_LEVEL_DEC();
-
-		block_declaration = old_block_declaration;
-		current_block_chain = old_current_block_chain;
-		current_mid = old_current_mid;
-		current_instance_method = false;
-
-		Value *classVal;
-		if (singleton_method) {
-		    assert(node->nd_recv != NULL);
-		    classVal = compile_singleton_class(compile_node(node->nd_recv));
-		}
-		else {
-		    classVal = compile_current_class();
-		}
-
-		rb_vm_arity_t arity = rb_vm_node_arity(body);
-		const SEL sel = mid_to_sel(mid, arity.real);
-
-		compile_prepare_method(classVal, compile_sel(sel),
-			singleton_method, new_function, arity, body);
-
-		return nilVal;
-	    }
-	    break;
-
 	case NODE_UNDEF:
 	    {
 		if (undefFunc == NULL) {
@@ -4096,12 +4065,15 @@
 	    break;
 
 	case NODE_TRUE:
+	    can_interpret = true;
 	    return trueVal;
 
 	case NODE_FALSE:
+	    can_interpret = true;
 	    return falseVal;
 
 	case NODE_NIL:
+	    can_interpret = true;
 	    return nilVal;
 
 	case NODE_SELF:
@@ -4113,6 +4085,7 @@
 		    ConstantInt::get(Int8Ty, (char)node->nd_nth), "", bb);
 
 	case NODE_BEGIN:
+	    can_interpret = true;
 	    return node->nd_body == NULL
 		? nilVal : compile_node(node->nd_body);
 
@@ -4592,14 +4565,49 @@
     return NULL;
 }
 
+Value *
+RoxorCompiler::compile_node(NODE *node)
+{
+#if ROXOR_COMPILER_DEBUG
+    printf("%s:%ld ", fname, nd_line(node));
+    for (int i = 0; i < level; i++) {
+	printf("...");
+    }
+    printf("... %s\n", ruby_node_name(nd_type(node)));
+#endif
+    if (current_line != nd_line(node)) {
+	current_line = nd_line(node);
+	if (debug_mode) {
+	    compile_debug_trap();
+	}
+    }
+
+    bool old_can_interpret = can_interpret;
+    can_interpret = false;
+
+    Value *val = compile_node0(node);
+
+    if (!can_interpret) {
+#if ROXOR_COMPILER_DEBUG
+	printf("node %s can't be interpreted!\n",
+		ruby_node_name(nd_type(node)));
+#endif
+	should_interpret = false;
+    }
+    can_interpret = old_can_interpret;
+
+    return val;
+}
+
 #include <libgen.h>
 
 void
 RoxorCompiler::set_fname(const char *_fname)
 {
-    if (fname != _fname) {
+    if (fname != _fname
+	    && (fname == NULL || _fname == NULL
+		|| strcmp(fname, _fname) != 0)) {
 	fname = _fname;
-
 	if (fname != NULL) {
 	    // Compute complete path.
 	    char path[PATH_MAX];
@@ -4629,17 +4637,25 @@
 }
 
 Function *
-RoxorCompiler::compile_main_function(NODE *node)
+RoxorCompiler::compile_main_function(NODE *node, bool *can_interpret_p)
 {
     current_instance_method = true;
+    should_interpret = true;
+    can_interpret = false;
 
     Value *val = compile_node(node);
     assert(Function::classof(val));
-    return cast<Function>(val);
+    Function *func =  cast<Function>(val);
+
+    if (can_interpret_p != NULL) {
+	*can_interpret_p = should_interpret;
+    }
+
+    return func;
 }
 
 Function *
-RoxorAOTCompiler::compile_main_function(NODE *node)
+RoxorAOTCompiler::compile_main_function(NODE *node, bool *can_be_interpreted)
 {
     current_instance_method = true;
 
@@ -5009,7 +5025,7 @@
 
     bb = BasicBlock::Create(context, "EntryBlock", f);
 
-    ReturnInst::Create(context, compile_ivar_read(name), bb);
+    ReturnInst::Create(context, compile_ivar_get(name), bb);
 
     return f;
 }
@@ -6049,6 +6065,45 @@
     return slot;
 }
 
+Value *
+RoxorCompiler::compile_dvar_assignment(ID vid, Value *val)
+{
+    if (running_block != NULL) {
+	// Dynamic variables assignments inside a block are a little bit
+	// complicated: if we are creating new objects we do need to defeat
+	// the thread-local collector by releasing ownership of the objects,
+	// otherwise the TLC might prematurely collect them. This is because
+	// the assignment is done into another thread's stack, which is not
+	// honored by the TLC.
+	Value *flag = new BitCastInst(running_block, Int32PtrTy, "", bb);
+	flag = new LoadInst(flag, "", bb);
+	Value *flagv = ConstantInt::get(Int32Ty, VM_BLOCK_THREAD);
+	flag = BinaryOperator::CreateAnd(flag, flagv, "", bb);
+	Value *is_thread = new ICmpInst(*bb, ICmpInst::ICMP_EQ, flag, flagv);
+
+	Function *f = bb->getParent();
+	BasicBlock *is_thread_bb = BasicBlock::Create(context, "", f);
+	BasicBlock *merge_bb = BasicBlock::Create(context, "", f);
+
+	BranchInst::Create(is_thread_bb, merge_bb, is_thread, bb);
+
+	bb = is_thread_bb;
+	CallInst::Create(releaseOwnershipFunc, val, "", bb);
+	BranchInst::Create(merge_bb, bb);
+
+	bb = merge_bb;
+    }
+
+    return compile_lvar_assignment(vid, val);
+}
+
+Value *
+RoxorCompiler::compile_lvar_assignment(ID vid, Value *val)
+{
+    new StoreInst(val, compile_lvar_slot(vid), bb);
+    return val;
+}
+
 #if __LP64__
 # define MAX_GPR_REGS 6
 # define MAX_SSE_REGS 8

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2010-06-08 01:25:44 UTC (rev 4212)
+++ MacRuby/trunk/compiler.h	2010-06-09 04:50:33 UTC (rev 4213)
@@ -1,5 +1,5 @@
 /*
- * MacRuby compiler.
+ * MacRuby Compiler.
  *
  * This file is covered by the Ruby license. See COPYING for more details.
  * 
@@ -31,7 +31,11 @@
 
 #if defined(__cplusplus)
 
+class RoxorInterpreter;
+
 class RoxorCompiler {
+    friend class RoxorInterpreter;
+
     public:
 	static llvm::Module *module;
 	static RoxorCompiler *shared;
@@ -43,7 +47,8 @@
 
 	Value *compile_node(NODE *node);
 
-	virtual Function *compile_main_function(NODE *node);
+	virtual Function *compile_main_function(NODE *node,
+		bool *can_be_interpreted);
 	Function *compile_read_attr(ID name);
 	Function *compile_write_attr(ID name);
 	Function *compile_stub(const char *types, bool variadic, int min_argc,
@@ -77,6 +82,8 @@
 	bool debug_mode;
 	const char *fname;
 	bool inside_eval;
+	bool should_interpret;
+	bool can_interpret;
 
 	std::map<ID, Value *> lvars;
 	std::vector<ID> dvars;
@@ -307,6 +314,7 @@
 
 	bool should_inline_function(Function *f);
 
+	Value *compile_node0(NODE *node);
 	Function *compile_scope(NODE *node);
 	Value *compile_call(NODE *node);
 	Value *compile_yield(NODE *node);
@@ -325,6 +333,7 @@
 		BasicBlock *thenBB);
 	void compile_single_when_argument(NODE *arg, Value *comparedToVal,
 		BasicBlock *thenBB);
+	void compile_method_definition(NODE *node);
 	virtual void compile_prepare_method(Value *classVal, Value *sel,
 		bool singleton, Function *new_function, rb_vm_arity_t &arity,
 		NODE *body);
@@ -338,11 +347,15 @@
 	Value *compile_binding(void);
 	Value *compile_optimized_dispatch_call(SEL sel, int argc,
 		std::vector<Value *> &params);
-	Value *compile_ivar_read(ID vid);
+	Value *compile_lvar_assignment(ID vid, Value *val);
+	Value *compile_dvar_assignment(ID vid, Value *val);
+	Value *compile_lvar_get(ID vid);
 	Value *compile_ivar_assignment(ID vid, Value *val);
+	Value *compile_ivar_get(ID vid);
 	Value *compile_cvar_assignment(ID vid, Value *val);
 	Value *compile_cvar_get(ID vid, bool check);
 	Value *compile_gvar_assignment(NODE *node, Value *val);
+	Value *compile_gvar_get(NODE *node);
 	Value *compile_constant_declaration(NODE *node, Value *val);
 	Value *compile_multiple_assignment(NODE *node, Value *val);
 	void compile_multiple_assignment_element(NODE *node, Value *val);
@@ -430,7 +443,7 @@
     public:
 	RoxorAOTCompiler(void);
 
-	Function *compile_main_function(NODE *node);
+	Function *compile_main_function(NODE *node, bool *can_be_interpreted);
 
     private:
 	std::map<ID, GlobalVariable *> ccaches;

Added: MacRuby/trunk/interpreter.cpp
===================================================================
--- MacRuby/trunk/interpreter.cpp	                        (rev 0)
+++ MacRuby/trunk/interpreter.cpp	2010-06-09 04:50:33 UTC (rev 4213)
@@ -0,0 +1,229 @@
+/*
+ * MacRuby Interpreter.
+ *
+ * This file is covered by the Ruby license. See COPYING for more details.
+ * 
+ * Copyright (C) 2008-2010, Apple Inc. All rights reserved.
+ */
+
+#include "llvm.h"
+#include "ruby/ruby.h"
+#include "ruby/node.h"
+#include "interpreter.h"
+#include "vm.h"
+
+#define PRIMITIVE static inline
+#include "kernel.c"
+
+// Will be set later, in vm.cpp.
+RoxorInterpreter *RoxorInterpreter::shared = NULL;
+
+RoxorInterpreter::RoxorInterpreter(void)
+{
+    stack = (VALUE *)calloc(INTERPRETER_STACK_SIZE, sizeof(VALUE));
+    assert(stack != NULL);
+}
+
+RoxorInterpreter::~RoxorInterpreter(void)
+{
+    free(stack);
+}
+
+extern "C" void rb_vm_prepare_method(Class klass, unsigned char dynamic_class,
+	SEL sel, Function *func, const rb_vm_arity_t arity, int flags);
+
+#define value_as(val, type) ((type)interpret_value(val))
+
+static inline Value *
+call_arg(CallInst *insn, unsigned int i)
+{
+    return insn->getOperand(i + 1);
+}
+
+static inline uint64_t
+get_const_int(Value *val)
+{
+    return cast<ConstantInt>(val)->getZExtValue();
+}
+
+static inline void *
+get_const_ptr(Value *val)
+{
+    return (void *)get_const_int(cast<ConstantExpr>(val)->getOperand(0));
+}
+
+// A macro to avoid stupid compiler warnings.
+#define oops(msg, val) \
+	printf("interpreter: %s (ID: %d)\n", msg, val->getValueID()); \
+	val->dump(); \
+	abort();
+
+VALUE
+RoxorInterpreter::interpret_call(CallInst *call)
+{
+    Function *called = call->getCalledFunction();
+
+    if (called == RoxorCompiler::shared->prepareMethodFunc) {
+	VALUE klass = value_as(call_arg(call, 0), VALUE);
+	uint8_t dynamic_class = value_as(call_arg(call, 1), uint8_t);
+	SEL sel = value_as(call_arg(call, 2), SEL);
+	Function *func = value_as(call_arg(call, 3), Function *);
+	uint64_t arity_data = value_as(call_arg(call, 4), uint64_t);
+	rb_vm_arity_t arity;
+	memcpy(&arity, &arity_data, sizeof(rb_vm_arity_t));
+	int flags = value_as(call_arg(call, 5), int);
+
+	rb_vm_prepare_method((Class)klass, dynamic_class, sel, func, arity,
+		flags);
+	return Qnil;
+    }
+    else if (called == RoxorCompiler::shared->dispatchFunc) {
+	VALUE top = value_as(call_arg(call, 0), VALUE);
+	VALUE self = value_as(call_arg(call, 1), VALUE);
+	void *sel = value_as(call_arg(call, 2), SEL);
+	void *block = value_as(call_arg(call, 3), void *);
+	uint8_t opt = value_as(call_arg(call, 4), uint8_t);
+	int argc = value_as(call_arg(call, 5), int);
+	VALUE *argv = value_as(call_arg(call, 6), VALUE *);
+
+	return vm_dispatch(top, self, sel, block, opt, argc, argv);
+    }
+
+    oops("unrecognized call instruction:", call);
+}
+
+#define return_if_cached(__insn) \
+    std::map<Instruction *, VALUE>::iterator __i = insns.find(__insn); \
+    if (__i != insns.end()) { \
+	return __i->second; \
+    } \
+
+VALUE
+RoxorInterpreter::interpret_instruction(Instruction *insn)
+{
+    switch (insn->getOpcode()) {
+	case Instruction::Br:
+	    {
+		BranchInst *br = static_cast<BranchInst *>(insn);
+		if (br->isUnconditional()) {
+		    BasicBlock *bb = br->getSuccessor(0);
+		    assert(bb != NULL);
+		    return interpret_basicblock(bb);
+		}
+		break;
+	    }
+
+	case Instruction::Ret:
+	    {
+		ReturnInst *ret = static_cast<ReturnInst *>(insn);
+		Value *retval = ret->getReturnValue();
+		assert(retval != NULL);
+		return interpret_value(retval);
+	    }
+
+	case Instruction::Call:
+	    {
+		return_if_cached(insn);
+		VALUE ret = interpret_call(static_cast<CallInst *>(insn));
+		insns[insn] = ret;
+		return ret;
+	    }
+
+	case Instruction::Alloca:
+	    {
+		return_if_cached(insn);
+		// Assuming the allocated type is VALUE.
+		AllocaInst *allocai = static_cast<AllocaInst *>(insn);
+		const size_t n = get_const_int(allocai->getArraySize());
+		assert(n > 0 && stack_p + n < INTERPRETER_STACK_SIZE);
+		VALUE *mem = &stack[stack_p];
+		stack_p += n;
+		insns[insn] = (VALUE)mem;
+		return (VALUE)mem;
+	    }
+
+	case Instruction::Store:
+	    {
+		StoreInst *store = static_cast<StoreInst *>(insn);
+		Value *slot = store->getOperand(1);
+		GetElementPtrInst *ptr = dyn_cast<GetElementPtrInst>(slot);
+		if (ptr == NULL) {
+		    break;
+		}
+		if (ptr->getNumIndices() != 1) {
+		    break;
+		}
+		const size_t off = get_const_int(*ptr->idx_begin());
+		VALUE storage = interpret_instruction(cast<AllocaInst>
+			(ptr->getPointerOperand()));
+		VALUE val = interpret_value(store->getOperand(0));
+		((VALUE *)storage)[off] = val;
+		return val;
+	    }
+
+	// Evaluated later.
+	case Instruction::GetElementPtr:
+	    return Qnil;
+    }
+
+    oops("unrecognized instruction:", insn);
+}
+
+VALUE
+RoxorInterpreter::interpret_value(Value *val)
+{
+    unsigned val_id = val->getValueID();
+    switch (val_id) {
+	case Value::ConstantPointerNullVal:
+	    return 0;
+
+	case Value::ConstantExprVal:
+	    val = static_cast<ConstantExpr *>(val)->getOperand(0);
+	    // fall through
+	case Value::ConstantIntVal:
+	    return static_cast<ConstantInt *>(val)->getZExtValue();
+
+	case Value::ArgumentVal:
+	    switch (static_cast<Argument *>(val)->getArgNo()) {
+		case 0:
+		    return self_arg;
+		case 1:
+		    return (VALUE)sel_arg;
+	    }
+	    break;
+
+	default:
+	    if (val_id >= Value::InstructionVal) {
+		return interpret_instruction(static_cast<Instruction *>(val));
+	    }
+	    break;
+    }
+
+    oops("unrecognized value:", val);
+}
+
+VALUE
+RoxorInterpreter::interpret_basicblock(BasicBlock *bb)
+{
+    for (BasicBlock::iterator insn = bb->begin(); insn != bb->end(); ++insn) {
+	Instruction *i = &*insn;
+	VALUE v = interpret_instruction(i);
+	if (i->isTerminator()) {	
+	    return v;
+	}
+    }
+
+    oops("malformed block:", bb);
+}
+
+VALUE
+RoxorInterpreter::interpret(Function *func, VALUE self, SEL sel)
+{
+    self_arg = self;
+    sel_arg = sel;
+    stack_p = 0;
+    insns.clear();
+
+    BasicBlock &b = func->getEntryBlock();
+    return interpret_basicblock(&b);
+}

Added: MacRuby/trunk/interpreter.h
===================================================================
--- MacRuby/trunk/interpreter.h	                        (rev 0)
+++ MacRuby/trunk/interpreter.h	2010-06-09 04:50:33 UTC (rev 4213)
@@ -0,0 +1,39 @@
+/*
+ * MacRuby Interpreter.
+ *
+ * This file is covered by the Ruby license. See COPYING for more details.
+ * 
+ * Copyright (C) 2010, Apple Inc. All rights reserved.
+ */
+
+#ifndef __INTERPRETER_H_
+#define __INTERPRETER_H_
+
+#if defined(__cplusplus)
+
+class RoxorInterpreter {
+    public:
+	static RoxorInterpreter *shared;
+
+	RoxorInterpreter(void);
+	~RoxorInterpreter(void); 
+
+	VALUE interpret(Function *func, VALUE self, SEL sel);
+
+    private:
+	VALUE self_arg;
+	SEL sel_arg;
+	VALUE *stack;
+	unsigned int stack_p;
+#define INTERPRETER_STACK_SIZE	1000
+	std::map<Instruction *, VALUE> insns;
+
+	VALUE interpret_basicblock(BasicBlock *bb);
+	VALUE interpret_instruction(Instruction *insn);
+	VALUE interpret_value(Value *val);
+	VALUE interpret_call(CallInst *call);
+};
+
+#endif // __cplusplus
+
+#endif // __INTERPRETER_H_

Modified: MacRuby/trunk/kernel.c
===================================================================
--- MacRuby/trunk/kernel.c	2010-06-08 01:25:44 UTC (rev 4212)
+++ MacRuby/trunk/kernel.c	2010-06-09 04:50:33 UTC (rev 4213)
@@ -20,7 +20,11 @@
 #include "class.h"
 #include "objc.h"
 
-inline VALUE
+#ifndef PRIMITIVE
+#define PRIMITIVE
+#endif
+
+PRIMITIVE VALUE
 vm_ivar_get(VALUE obj, ID name, void *cache_p)
 {
     struct icache *cache = (struct icache *)cache_p;
@@ -61,7 +65,7 @@
     return rb_ivar_get(obj, name);
 }
 
-inline void
+PRIMITIVE void
 vm_ivar_set(VALUE obj, ID name, VALUE val, void *cache_p)
 {
     struct icache *cache = (struct icache *)cache_p; 
@@ -101,7 +105,7 @@
     rb_ivar_set(obj, name, val);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_cvar_get(VALUE klass, ID id, unsigned char check,
 	unsigned char dynamic_class)
 {
@@ -114,7 +118,7 @@
     return rb_cvar_get2(klass, id, check);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_cvar_set(VALUE klass, ID id, VALUE val, unsigned char dynamic_class)
 {
     if (dynamic_class) {
@@ -127,7 +131,7 @@
     return val;
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_get_const(VALUE outer, void *cache_p, ID path, int flags)
 {
     struct ccache *cache = (struct ccache *) cache_p;
@@ -154,7 +158,7 @@
     return val;
 }
 
-inline void 
+PRIMITIVE void 
 vm_set_const(VALUE outer, ID id, VALUE obj, unsigned char dynamic_class)
 {
     if (dynamic_class) {
@@ -225,7 +229,7 @@
     return CLASS_OF(obj);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_dispatch(VALUE top, VALUE self, void *sel, void *block, unsigned char opt,
 	int argc, VALUE *argv)
 {
@@ -248,7 +252,7 @@
 	    argv = new_argv;
 	}
 	if (argc == 0) {
-	    const char *selname = sel_getName(sel);
+	    const char *selname = sel_getName((SEL)sel);
 	    const size_t selnamelen = strlen(selname);
 	    if (selname[selnamelen - 1] == ':') {
 		// Because
@@ -268,7 +272,7 @@
 	    (rb_vm_block_t *)block, opt, argc, argv);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_yield_args(int argc, unsigned char opt, VALUE *argv)
 {
     VALUE buf[100];
@@ -289,25 +293,25 @@
     return rb_vm_yield_args(vm, argc, argv);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_get_broken_value(void)
 {
     return rb_vm_get_broken_value(rb_vm_current_vm());
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_returned_from_block(int id)
 {
     return rb_vm_returned_from_block(rb_vm_current_vm(), id);
 }
 
-inline void
+PRIMITIVE void
 vm_release_ownership(VALUE obj)
 {
     rb_vm_release_ownership(obj);
 }
 
-inline void *
+PRIMITIVE void *
 vm_get_block(VALUE obj)
 {
     if (obj == Qnil) {
@@ -328,7 +332,7 @@
 
 #define IMM2DBL(x) (FIXFLOAT_P(x) ? FIXFLOAT2DBL(x) : FIX2LONG(x))
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_plus(VALUE left, VALUE right, unsigned char overriden)
 {
     if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
@@ -346,7 +350,7 @@
     return vm_dispatch(0, left, selPLUS, NULL, 0, 1, &right);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_minus(VALUE left, VALUE right, unsigned char overriden)
 {
     if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
@@ -364,7 +368,7 @@
     return vm_dispatch(0, left, selMINUS, NULL, 0, 1, &right);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_mult(VALUE left, VALUE right, unsigned char overriden)
 {
     if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
@@ -382,7 +386,7 @@
     return vm_dispatch(0, left, selMULT, NULL, 0, 1, &right);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_div(VALUE left, VALUE right, unsigned char overriden)
 {
     if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
@@ -408,7 +412,7 @@
     return vm_dispatch(0, left, selDIV, NULL, 0, 1, &right);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_lt(VALUE left, VALUE right, unsigned char overriden)
 {
     if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
@@ -422,7 +426,7 @@
     return vm_dispatch(0, left, selLT, NULL, 0, 1, &right);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_le(VALUE left, VALUE right, unsigned char overriden)
 {
     if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
@@ -436,7 +440,7 @@
     return vm_dispatch(0, left, selLE, NULL, 0, 1, &right);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_gt(VALUE left, VALUE right, unsigned char overriden)
 {
     if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
@@ -450,7 +454,7 @@
     return vm_dispatch(0, left, selGT, NULL, 0, 1, &right);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_ge(VALUE left, VALUE right, unsigned char overriden)
 {
     if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
@@ -464,7 +468,7 @@
     return vm_dispatch(0, left, selGE, NULL, 0, 1, &right);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_eq(VALUE left, VALUE right, unsigned char overriden)
 {
     if (overriden == 0) {
@@ -484,7 +488,7 @@
     return vm_dispatch(0, left, selEq, NULL, 0, 1, &right);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_eqq(VALUE left, VALUE right, unsigned char overriden)
 {
     if (overriden == 0) {
@@ -504,7 +508,7 @@
     return vm_dispatch(0, left, selEqq, NULL, 0, 1, &right);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_neq(VALUE left, VALUE right, unsigned char overriden)
 {
     if (overriden == 0) {
@@ -524,7 +528,7 @@
     return vm_dispatch(0, left, selNeq, NULL, 0, 1, &right);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_aref(VALUE obj, VALUE other, unsigned char overriden)
 {
     if (overriden == 0 && !SPECIAL_CONST_P(obj)) {
@@ -541,7 +545,7 @@
     return vm_dispatch(0, obj, selAREF, NULL, 0, 1, &other);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_aset(VALUE obj, VALUE other1, VALUE other2, unsigned char overriden)
 {
     if (overriden == 0 && !SPECIAL_CONST_P(obj)) {
@@ -560,7 +564,7 @@
     return vm_dispatch(0, obj, selASET, NULL, 0, 2, args);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_fast_shift(VALUE obj, VALUE other, unsigned char overriden)
 {
     if (overriden == 0 && !SPECIAL_CONST_P(obj)) {
@@ -577,7 +581,7 @@
     return vm_dispatch(0, obj, selLTLT, NULL, 0, 1, &other);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_when_splat(unsigned char overriden, VALUE comparedTo, VALUE splat)
 {
     VALUE ary = rb_check_convert_type(splat, T_ARRAY, "Array", "to_a");
@@ -594,109 +598,109 @@
     return Qfalse;
 }
 
-inline void
+PRIMITIVE void
 vm_set_current_scope(VALUE mod, int scope)
 {
-    rb_vm_set_current_scope(mod, scope);
+    rb_vm_set_current_scope(mod, (rb_vm_scope_t)scope);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_ocval_to_rval(void *ocval)
 {
     return OC2RB(ocval);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_char_to_rval(char c)
 {
     return INT2FIX(c);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_uchar_to_rval(unsigned char c)
 {
     return INT2FIX(c);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_short_to_rval(short c)
 {
     return INT2FIX(c);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_ushort_to_rval(unsigned short c)
 {
     return INT2FIX(c);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_int_to_rval(int c)
 {
     return INT2FIX(c);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_uint_to_rval(unsigned int c)
 {
     return INT2FIX(c);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_long_to_rval(long l)
 {
     return LONG2NUM(l);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_ulong_to_rval(unsigned long l)
 {
     return ULONG2NUM(l);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_long_long_to_rval(long long l)
 {
     return LL2NUM(l);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_ulong_long_to_rval(unsigned long long l)
 {
     return ULL2NUM(l);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_float_to_rval(float f)
 {
     return DOUBLE2NUM(f);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_double_to_rval(double d)
 {
     return DOUBLE2NUM(d);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_sel_to_rval(void *sel)
 {
     return sel == 0 ? Qnil : ID2SYM(rb_intern(sel_getName((SEL)sel)));
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_charptr_to_rval(const char *ptr)
 {
     return ptr == NULL ? Qnil : rb_str_new2(ptr);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_ocval(VALUE rval, void **ocval)
 {
     *ocval = rval == Qnil ? NULL : RB2OC(rval);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_bool(VALUE rval, BOOL *ocval)
 {
     if (rval == Qfalse || rval == Qnil) {
@@ -726,14 +730,14 @@
     }
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_sel(VALUE rval, void **ocval)
 {
     const char *cstr = rval_to_c_str(rval);
     *(SEL *)ocval = cstr == NULL ? NULL : sel_registerName(cstr);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_charptr(VALUE rval, const char **ocval)
 {
     *ocval = rval_to_c_str(rval);
@@ -769,7 +773,7 @@
     return RFLOAT_VALUE(rb_Float(bool_to_fix(rval)));
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_char(VALUE rval, char *ocval)
 {
     if (TYPE(rval) == T_STRING && RSTRING_LEN(rval) == 1) {
@@ -780,7 +784,7 @@
     }
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_uchar(VALUE rval, unsigned char *ocval)
 {
     if (TYPE(rval) == T_STRING && RSTRING_LEN(rval) == 1) {
@@ -791,67 +795,67 @@
     }
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_short(VALUE rval, short *ocval)
 {
     *ocval = (short)rval_to_long(rval);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_ushort(VALUE rval, unsigned short *ocval)
 {
     *ocval = (unsigned short)rval_to_long(rval);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_int(VALUE rval, int *ocval)
 {
     *ocval = (int)rval_to_long(rval);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_uint(VALUE rval, unsigned int *ocval)
 {
     *ocval = (unsigned int)rval_to_long(rval);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_long(VALUE rval, long *ocval)
 {
     *ocval = (long)rval_to_long(rval);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_ulong(VALUE rval, unsigned long *ocval)
 {
     *ocval = (unsigned long)rval_to_long(rval);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_long_long(VALUE rval, long long *ocval)
 {
     *ocval = (long long)rval_to_long_long(rval);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_ulong_long(VALUE rval, unsigned long long *ocval)
 {
     *ocval = (unsigned long long)rval_to_long_long(rval);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_double(VALUE rval, double *ocval)
 {
     *ocval = (double)rval_to_double(rval);
 }
 
-inline void
+PRIMITIVE void
 vm_rval_to_float(VALUE rval, float *ocval)
 {
     *ocval = (float)rval_to_double(rval);
 }
 
-inline void *
+PRIMITIVE void *
 vm_rval_to_cptr(VALUE rval, const char *type, void **cptr)
 {
     if (NIL_P(rval)) {
@@ -869,7 +873,7 @@
     return *cptr;
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_to_a(VALUE obj)
 {
     VALUE ary = rb_check_convert_type(obj, T_ARRAY, "Array", "to_a");
@@ -879,7 +883,7 @@
     return ary;
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_to_ary(VALUE obj)
 {
     VALUE ary = rb_check_convert_type(obj, T_ARRAY, "Array", "to_ary");
@@ -889,7 +893,7 @@
     return ary;
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_ary_cat(VALUE ary, VALUE obj)
 {
     VALUE ary2 = rb_check_convert_type(obj, T_ARRAY, "Array", "to_a");
@@ -902,13 +906,13 @@
     return ary;
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_ary_dup(VALUE ary)
 {
     return rb_ary_dup(ary);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_rary_new(int len)
 {
     VALUE ary = rb_ary_new2(len);
@@ -916,25 +920,25 @@
     return ary;
 }
 
-inline void
+PRIMITIVE void
 vm_rary_aset(VALUE ary, int i, VALUE obj)
 {
     rary_elt_set(ary, i, obj);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_rhash_new(void)
 {
     return rb_hash_new();
 }
 
-inline void
+PRIMITIVE void
 vm_rhash_store(VALUE hash, VALUE key, VALUE obj)
 {
     rhash_store(hash, key, obj);
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_masgn_get_elem_before_splat(VALUE ary, int offset)
 {
     if (offset < RARRAY_LEN(ary)) {
@@ -943,7 +947,7 @@
     return Qnil;
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_masgn_get_elem_after_splat(VALUE ary, int before_splat_count,
 	int after_splat_count, int offset)
 {
@@ -961,7 +965,7 @@
     return Qnil;
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_masgn_get_splat(VALUE ary, int before_splat_count, int after_splat_count)
 {
     const int len = RARRAY_LEN(ary);
@@ -974,7 +978,7 @@
     }
 }
 
-inline VALUE
+PRIMITIVE VALUE
 vm_get_special(char code)
 {
     VALUE backref = rb_backref_get();

Modified: MacRuby/trunk/rakelib/builder/builder.rb
===================================================================
--- MacRuby/trunk/rakelib/builder/builder.rb	2010-06-08 01:25:44 UTC (rev 4212)
+++ MacRuby/trunk/rakelib/builder/builder.rb	2010-06-09 04:50:33 UTC (rev 4213)
@@ -5,8 +5,9 @@
   gc hash env inits io math numeric object pack parse prec dir process
   random range rational re ruby signal sprintf st string struct time
   util variable version thread id objc bs ucnv encoding main dln dmyext marshal
-  gcd vm_eval gc-stub bridgesupport compiler dispatcher vm symbol debugger MacRuby
-  MacRubyDebuggerConnector NSArray NSDictionary NSString transcode 
+  gcd vm_eval gc-stub bridgesupport compiler dispatcher vm symbol debugger
+  interpreter MacRuby MacRubyDebuggerConnector NSArray NSDictionary NSString
+  transcode 
 }
 
 EXTENSIONS = %w{

Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp	2010-06-08 01:25:44 UTC (rev 4212)
+++ MacRuby/trunk/vm.cpp	2010-06-09 04:50:33 UTC (rev 4213)
@@ -48,6 +48,7 @@
 #include "vm.h"
 #include "compiler.h"
 #include "debugger.h"
+#include "interpreter.h"
 #include "objc.h"
 #include "dtrace.h"
 #include "class.h"
@@ -326,6 +327,8 @@
 
     InitializeNativeTarget();
 
+    interpreter_enabled = getenv("VM_DISABLE_INTERPRETER") == NULL;
+
     CodeGenOpt::Level opt = CodeGenOpt::Default;
     inlining_enabled = false;
     optims_enabled = true;
@@ -3640,31 +3643,46 @@
     bool old_inside_eval = compiler->is_inside_eval();
     compiler->set_inside_eval(inside_eval);
     compiler->set_fname(fname);
-    Function *function = compiler->compile_main_function(node);
-    compiler->set_fname(NULL);
+    bool can_interpret = false;
+    Function *func = compiler->compile_main_function(node, &can_interpret);
+    //compiler->set_fname(NULL);
     compiler->set_inside_eval(old_inside_eval);
     if (binding != NULL) {
 	vm->pop_current_binding();
     }
 
-    // Optimize & compile the function.
-    IMP imp = GET_CORE()->compile(function);
+    VALUE ret;
 
-    // Register it for symbolication.
-    rb_vm_method_node_t *mnode = GET_CORE()->method_node_get(imp, true);
-    mnode->klass = 0;
-    mnode->arity = rb_vm_arity(2);
-    mnode->sel = sel_registerName("<main>");
-    mnode->objc_imp = mnode->ruby_imp = imp;
-    mnode->flags = 0;
+    if (can_interpret && GET_CORE()->get_interpreter_enabled()) {
+//printf("interpret:\n");
+//func->dump();
+	// If the function can be interpreted, do it, then delete the IR.
+	ret = RoxorInterpreter::shared->interpret(func,
+		vm->get_current_top_object(), 0);
+ 	func->eraseFromParent();
+    }
+    else {
+//printf("jit:\n");
+//func->dump();
+	// Optimize & compile the function.
+	IMP imp = GET_CORE()->compile(func);
 
-    // Execute the function.
-    VALUE ret = ((VALUE(*)(VALUE, SEL))imp)(vm->get_current_top_object(), 0);
+	// Register it for symbolication.
+	rb_vm_method_node_t *mnode = GET_CORE()->method_node_get(imp, true);
+	mnode->klass = 0;
+	mnode->arity = rb_vm_arity(2);
+	mnode->sel = sel_registerName("<main>");
+	mnode->objc_imp = mnode->ruby_imp = imp;
+	mnode->flags = 0;
 
-    if (inside_eval) {
-	// XXX We only delete functions created by #eval. In theory it should
-	// also work for other functions, but it makes spec:ci crash.
-	GET_CORE()->delenda(function);
+	// Execute the function.
+	ret = ((VALUE(*)(VALUE, SEL))imp)(vm->get_current_top_object(), 0);
+
+	if (inside_eval) {
+	    // XXX We only delete functions created by #eval. In theory it
+	    // should also work for other functions, but it makes spec:ci crash.
+	    GET_CORE()->delenda(func);
+	}
     }
 
     rb_node_release(node);
@@ -3726,7 +3744,7 @@
 
     // Compile the program as IR.
     RoxorCompiler::shared->set_fname(RSTRING_PTR(rb_progname));
-    Function *f = RoxorCompiler::shared->compile_main_function(node);
+    Function *f = RoxorCompiler::shared->compile_main_function(node, NULL);
     f->setName(RSTRING_PTR(ruby_aot_init_func));
 
     // Force a module verification.
@@ -4593,6 +4611,7 @@
     assert(RoxorCompiler::module != NULL);
 
     RoxorCompiler::module->setTargetTriple(TARGET_TRIPLE);
+    RoxorInterpreter::shared = new RoxorInterpreter();
     RoxorCore::shared = new RoxorCore();
     RoxorVM::main = new RoxorVM();
 

Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h	2010-06-08 01:25:44 UTC (rev 4212)
+++ MacRuby/trunk/vm.h	2010-06-09 04:50:33 UTC (rev 4213)
@@ -683,6 +683,7 @@
 	pthread_mutex_t gl;
 
 	// State.
+	bool interpreter_enabled;
 	bool inlining_enabled;
 	bool optims_enabled;
 	bool running;
@@ -751,6 +752,7 @@
 	ACCESSOR(running, bool);
 	ACCESSOR(abort_on_exception, bool);
 	ACCESSOR(default_random, VALUE);
+	READER(interpreter_enabled, bool);
 	READER(loaded_features, VALUE);
 	READER(load_path, VALUE);
 	READER(threads, VALUE);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100608/dde08dcc/attachment-0001.html>


More information about the macruby-changes mailing list