[macruby-changes] [1288] MacRuby/branches/experimental
source_changes at macosforge.org
source_changes at macosforge.org
Thu Apr 2 19:11:56 PDT 2009
Revision: 1288
http://trac.macosforge.org/projects/ruby/changeset/1288
Author: lsansonetti at apple.com
Date: 2009-04-02 19:11:56 -0700 (Thu, 02 Apr 2009)
Log Message:
-----------
a faster implementation of dvars + fixed eval bugs + preliminary implementation of binding
Modified Paths:
--------------
MacRuby/branches/experimental/TODO
MacRuby/branches/experimental/bench.rb
MacRuby/branches/experimental/eval.c
MacRuby/branches/experimental/id.c
MacRuby/branches/experimental/id.h
MacRuby/branches/experimental/load.c
MacRuby/branches/experimental/main.c
MacRuby/branches/experimental/numeric.c
MacRuby/branches/experimental/proc.c
MacRuby/branches/experimental/roxor.cpp
MacRuby/branches/experimental/roxor.h
MacRuby/branches/experimental/tool/compile_prelude.rb
MacRuby/branches/experimental/vm_eval.c
Modified: MacRuby/branches/experimental/TODO
===================================================================
--- MacRuby/branches/experimental/TODO 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/TODO 2009-04-03 02:11:56 UTC (rev 1288)
@@ -16,6 +16,7 @@
[X] fast #send
[ ] fast regexp =~
[X] fast break
+[ ] write a pass manager to eliminate unnecessary arrays generated by massigns
[ ] Array and Hash subclasses to hold immediate Ruby objects without boxing
[/] implement backtracing/symbolication
[/] port all rb_define_method() calls to rb_objc_define_method()
Modified: MacRuby/branches/experimental/bench.rb
===================================================================
--- MacRuby/branches/experimental/bench.rb 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/bench.rb 2009-04-03 02:11:56 UTC (rev 1288)
@@ -147,7 +147,25 @@
o = proc {}
i=0; while i<30000000; o.call; i+=1; end
end
+ bm.report('30000000 dvar write') do
+ i=0
+ 30000000.times { i=1 }
+ end
+ # Eval
+ bm.report('1000 eval') do
+ i=0
+ s = "#{1+1}+#{20+20}"
+ while i<1000
+ eval(s)
+ i+=1
+ end
+ end
+ bm.report('30000000 binding-var write') do
+ i=0
+ eval('while i<30000000; i+=1; end')
+ end
+
# Break
bm.report('30000000 while break') do
i=0; while i<30000000; while true; i+=1; break; end; end
@@ -198,16 +216,6 @@
end
end
- # Eval
- bm.report('1000 eval') do
- i=0
- s = "#{1+1}+#{20+20}"
- while i<1000
- eval(s)
- i+=1
- end
- end
-
# Method
bm.report('3000000 Method#call w/ 0 arg') do
o = Class1.new
Modified: MacRuby/branches/experimental/eval.c
===================================================================
--- MacRuby/branches/experimental/eval.c 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/eval.c 2009-04-03 02:11:56 UTC (rev 1288)
@@ -97,6 +97,7 @@
static void
ruby_finalize_1(void)
{
+ rb_vm_finalize();
ruby_sig_finalize();
//GET_THREAD()->errinfo = Qnil;
rb_gc_call_finalizer_at_exit();
@@ -195,7 +196,7 @@
return FIX2INT(n);
}
rb_vm_set_running(true);
- rb_vm_run(RSTRING_PTR(rb_progname), (NODE *)n);
+ rb_vm_run(RSTRING_PTR(rb_progname), (NODE *)n, NULL);
return ruby_cleanup(0);
}
@@ -736,8 +737,17 @@
static VALUE
rb_f_local_variables(VALUE rcv, SEL sel)
{
- // TODO
- return Qnil;
+ rb_vm_binding_t *binding = rb_vm_current_binding();
+ assert(binding != NULL);
+
+ VALUE ary = rb_ary_new();
+ rb_vm_local_t *l;
+
+ for (l = binding->locals; l != NULL; l = l->next) {
+ rb_ary_push(ary, ID2SYM(l->name));
+ }
+
+ return ary;
}
@@ -820,27 +830,3 @@
//rb_ivar_set(exception_error, idThrowState, INT2FIX(TAG_FATAL));
rb_objc_retain((void *)exception_error);
}
-
-
-/* for parser */
-
-int
-rb_dvar_defined(ID id)
-{
- // TODO
- return 0;
-}
-
-int
-rb_local_defined(ID id)
-{
- // TODO
- return 0;
-}
-
-int
-rb_parse_in_eval(void)
-{
- // TODO
- return 0;
-}
Modified: MacRuby/branches/experimental/id.c
===================================================================
--- MacRuby/branches/experimental/id.c 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/id.c 2009-04-03 02:11:56 UTC (rev 1288)
@@ -74,6 +74,11 @@
sel__send__ = sel_registerName("__send__:");
selEqTilde = sel_registerName("=~:");
selEval = sel_registerName("eval:");
+ selInstanceEval = sel_registerName("instance_eval:");
+ selClassEval = sel_registerName("class_eval:");
+ selModuleEval = sel_registerName("module_eval:");
+ selLocalVariables = sel_registerName("local_variables");
+ selBinding = sel_registerName("binding");
selEach = sel_registerName("each");
selEqq = sel_registerName("===:");
selBackquote = sel_registerName("`:");
Modified: MacRuby/branches/experimental/id.h
===================================================================
--- MacRuby/branches/experimental/id.h 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/id.h 2009-04-03 02:11:56 UTC (rev 1288)
@@ -85,6 +85,11 @@
extern SEL sel__send__;
extern SEL selEqTilde;
extern SEL selEval;
+extern SEL selInstanceEval;
+extern SEL selClassEval;
+extern SEL selModuleEval;
+extern SEL selLocalVariables;
+extern SEL selBinding;
extern SEL selEach;
extern SEL selEqq;
extern SEL selBackquote;
Modified: MacRuby/branches/experimental/load.c
===================================================================
--- MacRuby/branches/experimental/load.c 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/load.c 2009-04-03 02:11:56 UTC (rev 1288)
@@ -270,7 +270,7 @@
if (node == NULL) {
rb_raise(rb_eSyntaxError, "compile error");
}
- rb_vm_run(fname_str, node);
+ rb_vm_run(fname_str, node, NULL);
}
void
Modified: MacRuby/branches/experimental/main.c
===================================================================
--- MacRuby/branches/experimental/main.c 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/main.c 2009-04-03 02:11:56 UTC (rev 1288)
@@ -30,6 +30,6 @@
ruby_sysinit(&argc, &argv);
{
ruby_init();
- return ruby_run_node(ruby_options(argc, argv));
+ rb_exit(ruby_run_node(ruby_options(argc, argv)));
}
}
Modified: MacRuby/branches/experimental/numeric.c
===================================================================
--- MacRuby/branches/experimental/numeric.c 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/numeric.c 2009-04-03 02:11:56 UTC (rev 1288)
@@ -532,30 +532,11 @@
VALUE
rb_float_new(double d)
{
-#if 0
- //printf("double %f\n", d);
- struct rb_float_cache *cache = rb_vm_float_cache(d);
-
- if (cache->obj != Qnil) {
- //printf("cached\n");
- return cache->obj;
- }
-
- cache->count++;
-#endif
-
NEWOBJ(flt, struct RFloat);
OBJSETUP(flt, rb_cFloat, T_FLOAT);
flt->float_value = d;
-#if 0
- rb_objc_retain((void *)flt);
- //if (cache->count == 10) {
- cache->obj = (VALUE)flt;
- //}
-#endif
-
return (VALUE)flt;
}
Modified: MacRuby/branches/experimental/proc.c
===================================================================
--- MacRuby/branches/experimental/proc.c 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/proc.c 2009-04-03 02:11:56 UTC (rev 1288)
@@ -17,10 +17,6 @@
#define GetProcPtr(obj, ptr) GetCoreDataFromValue(obj, rb_vm_block_t, ptr)
-typedef struct {
- // TODO
-} rb_binding_t;
-
VALUE rb_cUnboundMethod;
VALUE rb_cMethod;
VALUE rb_cBinding;
@@ -202,8 +198,8 @@
binding_alloc(VALUE klass)
{
VALUE obj;
- rb_binding_t *bind;
- obj = Data_Make_Struct(klass, rb_binding_t,
+ rb_vm_binding_t *bind;
+ obj = Data_Make_Struct(klass, rb_vm_binding_t,
NULL, NULL, bind);
return obj;
}
@@ -232,17 +228,9 @@
VALUE
rb_binding_new(void)
{
-#if 0 // TODO
- rb_thread_t *th = GET_THREAD();
- rb_control_frame_t *cfp = vm_get_ruby_level_cfp(th, th->cfp);
- VALUE bindval = binding_alloc(rb_cBinding);
- rb_binding_t *bind;
-
- GetBindingPtr(bindval, bind);
- GC_WB(&bind->env, vm_make_env_object(th, cfp));
- return bindval;
-#endif
- return Qnil;
+ rb_vm_binding_t *bind = rb_vm_current_binding();
+ assert(bind != NULL);
+ return Data_Wrap_Struct(rb_cBinding, NULL, NULL, bind);
}
/*
@@ -1497,22 +1485,16 @@
static VALUE
proc_binding(VALUE self, SEL sel)
{
-#if 0 // TODO
- rb_proc_t *proc;
- VALUE bindval = binding_alloc(rb_cBinding);
- rb_binding_t *bind;
+ rb_vm_block_t *block;
+ GetProcPtr(self, block);
- GetProcPtr(self, proc);
- GetBindingPtr(bindval, bind);
+ rb_vm_binding_t *binding = (rb_vm_binding_t *)xmalloc(
+ sizeof(rb_vm_binding_t));
- if (TYPE(proc->block.iseq) == T_NODE) {
- rb_raise(rb_eArgError, "Can't create Binding from C level Proc");
- }
+ GC_WB(&binding->self, self);
+ GC_WB(&binding->locals, block->locals);
- bind->env = proc->envval;
- return bindval;
-#endif
- return Qnil;
+ return Data_Wrap_Struct(rb_cBinding, NULL, NULL, binding);
}
static VALUE curry(VALUE dummy, VALUE args, int argc, VALUE *argv);
Modified: MacRuby/branches/experimental/roxor.cpp
===================================================================
--- MacRuby/branches/experimental/roxor.cpp 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/roxor.cpp 2009-04-03 02:11:56 UTC (rev 1288)
@@ -1,8 +1,8 @@
/* ROXOR: the new MacRuby VM that rocks! */
-#define ROXOR_COMPILER_DEBUG 0
-#define ROXOR_VM_DEBUG 0
-#define ROXOR_DUMP_IR 0
+#define ROXOR_COMPILER_DEBUG 0
+#define ROXOR_VM_DEBUG 0
+#define ROXOR_DUMP_IR_BEFORE_EXIT 0
#include <llvm/Module.h>
#include <llvm/DerivedTypes.h>
@@ -170,7 +170,7 @@
const char *fname;
std::map<ID, Value *> lvars;
- std::map<ID, Value *> dvars;
+ std::vector<ID> dvars;
std::map<ID, int *> ivar_slots_cache;
#if ROXOR_COMPILER_DEBUG
@@ -203,6 +203,7 @@
Function *fastEqqFunc;
Function *whenSplatFunc;
Function *prepareBlockFunc;
+ Function *pushBindingFunc;
Function *getBlockFunc;
Function *currentBlockObjectFunc;
Function *getConstFunc;
@@ -245,7 +246,8 @@
Constant *undefVal;
Constant *splatArgFollowsVal;
const Type *RubyObjTy;
- const Type *RubyObjPtrTy;
+ const Type *RubyObjPtrTy;
+ const Type *RubyObjPtrPtrTy;
const Type *PtrTy;
const Type *IntTy;
@@ -275,6 +277,7 @@
Value *compile_fast_eqq_call(Value *selfVal, Value *comparedToVal);
Value *compile_attribute_assign(NODE *node, Value *extra_val);
Value *compile_block_create(NODE *node=NULL);
+ Value *compile_binding(void);
Value *compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Value *> ¶ms);
Value *compile_ivar_read(ID vid);
Value *compile_ivar_assignment(ID vid, Value *val);
@@ -284,30 +287,14 @@
Value *compile_singleton_class(Value *obj);
Value *compile_defined_expression(NODE *node);
Value *compile_dstr(NODE *node);
+ Value *compile_dvar_slot(ID name);
+
void compile_dead_branch(void);
void compile_landing_pad_header(void);
void compile_landing_pad_footer(void);
void compile_rethrow_exception(void);
+ Value *compile_lvar_slot(ID name);
- Value *get_var(ID name, std::map<ID, Value *> &container,
- bool do_assert) {
- std::map<ID, Value *>::iterator iter = container.find(name);
- if (do_assert) {
-#if ROXOR_COMPILER_DEBUG
- printf("get_var %s\n", rb_id2name(name));
-#endif
- assert(iter != container.end());
- return iter->second;
- }
- else {
- return iter != container.end() ? iter->second : NULL;
- }
- }
-
- Value *get_lvar(ID name, bool do_assert=true) {
- return get_var(name, lvars, do_assert);
- }
-
int *get_slot_cache(ID id) {
if (current_block || !current_instance_method) {
// TODO should also return NULL if we are inside a module
@@ -413,6 +400,7 @@
VALUE last_status;
VALUE errinfo;
int safe_level;
+ std::vector<rb_vm_binding_t *> bindings;
std::map<NODE *, rb_vm_block_t *> blocks;
std::map<double, struct rb_float_cache *> float_cache;
unsigned char method_missing_reason;
@@ -520,6 +508,18 @@
outers[klass] = class_outer;
}
}
+
+ VALUE *get_binding_lvar(ID name) {
+ if (!bindings.empty()) {
+ rb_vm_binding_t *b = bindings.back();
+ for (rb_vm_local_t *l = b->locals; l != NULL; l = l->next) {
+ if (l->name == name) {
+ return l->value;
+ }
+ }
+ }
+ return NULL;
+ }
};
RoxorVM *RoxorVM::current = NULL;
@@ -551,6 +551,7 @@
fastEqqFunc = NULL;
whenSplatFunc = NULL;
prepareBlockFunc = NULL;
+ pushBindingFunc = NULL;
getBlockFunc = NULL;
currentBlockObjectFunc = NULL;
getConstFunc = NULL;
@@ -595,6 +596,7 @@
twoVal = ConstantInt::get(IntTy, 2);
RubyObjPtrTy = PointerType::getUnqual(RubyObjTy);
+ RubyObjPtrPtrTy = PointerType::getUnqual(RubyObjPtrTy);
nilVal = ConstantInt::get(RubyObjTy, Qnil);
trueVal = ConstantInt::get(RubyObjTy, Qtrue);
falseVal = ConstantInt::get(RubyObjTy, Qfalse);
@@ -943,7 +945,8 @@
assert(current_block_func != NULL && current_block_node != NULL);
if (prepareBlockFunc == NULL) {
- // void *rb_vm_prepare_block(Function *func, NODE *node, VALUE self, int dvars_size, ...);
+ // void *rb_vm_prepare_block(Function *func, NODE *node, VALUE self,
+ // int dvars_size, ...);
std::vector<const Type *> types;
types.push_back(PtrTy);
types.push_back(PtrTy);
@@ -959,20 +962,58 @@
params.push_back(compile_const_pointer(current_block_node));
params.push_back(current_self);
+ // Dvars.
params.push_back(ConstantInt::get(Type::Int32Ty, (int)dvars.size()));
+ for (std::vector<ID>::iterator iter = dvars.begin();
+ iter != dvars.end(); ++iter) {
+ params.push_back(compile_lvar_slot(*iter));
+ }
- std::map<ID, Value *>::iterator iter = dvars.begin();
- while (iter != dvars.end()) {
- std::map<ID, Value *>::iterator iter2 = lvars.find(iter->first);
- assert(iter2 != lvars.end());
- params.push_back(iter2->second);
- ++iter;
+ // Lvars.
+ params.push_back(ConstantInt::get(Type::Int32Ty, (int)lvars.size()));
+ for (std::map<ID, Value *>::iterator iter = lvars.begin();
+ iter != lvars.end(); ++iter) {
+ ID name = iter->first;
+ Value *slot = iter->second;
+ if (std::find(dvars.begin(), dvars.end(), name) == dvars.end()) {
+ params.push_back(ConstantInt::get(IntTy, (long)name));
+ params.push_back(slot);
+ }
}
- return CallInst::Create(prepareBlockFunc, params.begin(), params.end(), "", bb);
+ return CallInst::Create(prepareBlockFunc, params.begin(), params.end(),
+ "", bb);
}
Value *
+RoxorCompiler::compile_binding(void)
+{
+ if (pushBindingFunc == NULL) {
+ // void rb_vm_push_binding(VALUE self, int lvars_size, ...);
+ std::vector<const Type *> types;
+ types.push_back(RubyObjTy);
+ types.push_back(Type::Int32Ty);
+ FunctionType *ft = FunctionType::get(Type::VoidTy, types, true);
+ pushBindingFunc = cast<Function>
+ (module->getOrInsertFunction("rb_vm_push_binding", ft));
+ }
+
+ std::vector<Value *> params;
+ params.push_back(current_self);
+
+ // Lvars.
+ params.push_back(ConstantInt::get(Type::Int32Ty, (int)lvars.size()));
+ for (std::map<ID, Value *>::iterator iter = lvars.begin();
+ iter != lvars.end(); ++iter) {
+ params.push_back(ConstantInt::get(IntTy, (long)iter->first));
+ params.push_back(iter->second);
+ }
+
+ return CallInst::Create(pushBindingFunc, params.begin(), params.end(),
+ "", bb);
+}
+
+Value *
RoxorCompiler::compile_ivar_read(ID vid)
{
if (getIvarFunc == NULL) {
@@ -1277,6 +1318,34 @@
}
Value *
+RoxorCompiler::compile_dvar_slot(ID name)
+{
+ // TODO we should cache this
+ int i = 0, idx = -1;
+ for (std::vector<ID>::iterator iter = dvars.begin();
+ iter != dvars.end(); ++iter) {
+ if (*iter == name) {
+ idx = i;
+ break;
+ }
+ i++;
+ }
+ if (idx == -1) {
+ return NULL;
+ }
+
+ Function::ArgumentListType::iterator fargs_i =
+ bb->getParent()->getArgumentList().begin();
+ ++fargs_i; // skip self
+ ++fargs_i; // skip sel
+ Value *dvars_ary = fargs_i;
+
+ Value *index = ConstantInt::get(Type::Int32Ty, idx);
+ Value *slot = GetElementPtrInst::Create(dvars_ary, index, rb_id2name(name), bb);
+ return new LoadInst(slot, "", bb);
+}
+
+Value *
RoxorCompiler::compile_class_path(NODE *node)
{
if (nd_type(node) == NODE_COLON3) {
@@ -2273,15 +2342,22 @@
{
rb_vm_arity_t arity = rb_vm_node_arity(node);
const int nargs = bb == NULL ? 0 : arity.real;
+ const bool has_dvars = current_block && current_mid == 0;
// Get dynamic vars.
- if (current_block && node->nd_tbl != NULL) {
+ if (has_dvars && node->nd_tbl != NULL) {
const int args_count = (int)node->nd_tbl[0];
const int lvar_count = (int)node->nd_tbl[args_count + 1];
for (int i = 0; i < lvar_count; i++) {
ID id = node->nd_tbl[i + args_count + 2];
if (lvars.find(id) != lvars.end()) {
- dvars[id] = NULL;
+ std::vector<ID>::iterator iter = std::find(dvars.begin(), dvars.end(), id);
+ if (iter == dvars.end()) {
+#if ROXOR_COMPILER_DEBUG
+ printf("dvar %s\n", rb_id2name(id));
+#endif
+ dvars.push_back(id);
+ }
}
}
}
@@ -2290,8 +2366,8 @@
std::vector<const Type *> types;
types.push_back(RubyObjTy); // self
types.push_back(PtrTy); // sel
- for (int i = 0, count = dvars.size(); i < count; i++) {
- types.push_back(RubyObjPtrTy);
+ if (has_dvars) {
+ types.push_back(RubyObjPtrPtrTy); // dvars array
}
for (int i = 0; i < nargs; ++i) {
types.push_back(RubyObjTy);
@@ -2319,19 +2395,9 @@
Value *sel = arg++;
sel->setName("sel");
- for (std::map<ID, Value *>::iterator iter = dvars.begin();
- iter != dvars.end();
- ++iter) {
-
- ID id = iter->first;
- assert(iter->second == NULL);
-
- Value *val = arg++;
- val->setName(std::string("dyna_") + rb_id2name(id));
-#if ROXOR_COMPILER_DEBUG
- printf("dvar %s\n", rb_id2name(id));
-#endif
- lvars[id] = val;
+ if (has_dvars) {
+ Value *dvars_arg = arg++;
+ dvars_arg->setName("dvars");
}
if (node->nd_tbl != NULL) {
@@ -2373,12 +2439,14 @@
if (lvars.find(id) != lvars.end()) {
continue;
}
+ if (std::find(dvars.begin(), dvars.end(), id) == dvars.end()) {
#if ROXOR_COMPILER_DEBUG
- printf("var %s\n", rb_id2name(id));
+ printf("lvar %s\n", rb_id2name(id));
#endif
- Value *store = new AllocaInst(RubyObjTy, "", bb);
- new StoreInst(nilVal, store, bb);
- lvars[id] = store;
+ Value *store = new AllocaInst(RubyObjTy, "", bb);
+ new StoreInst(nilVal, store, bb);
+ lvars[id] = store;
+ }
}
NODE *args_node = node->nd_args;
@@ -2410,9 +2478,12 @@
++iter; // skip sel
NODE *opt_node = args_node->nd_opt;
if (opt_node != NULL) {
- int to_skip = dvars.size() + args_node->nd_frml;
+ int to_skip = args_node->nd_frml;
+ if (has_dvars) {
+ to_skip++; // dvars array
+ }
for (i = 0; i < to_skip; i++) {
- ++iter; // skip dvars and args required on the left-side
+ ++iter; // skip dvars and args required on the left-side
}
iter = compile_optional_arguments(iter, opt_node);
}
@@ -2448,8 +2519,8 @@
case NODE_LVAR:
{
assert(node->nd_vid > 0);
-
- return new LoadInst(get_lvar(node->nd_vid), "", bb);
+
+ return new LoadInst(compile_lvar_slot(node->nd_vid), "", bb);
}
break;
@@ -2577,7 +2648,7 @@
case NODE_DASGN:
case NODE_DASGN_CURR:
{
- Value *slot = get_lvar(ln->nd_vid);
+ Value *slot = compile_lvar_slot(ln->nd_vid);
new StoreInst(elt, slot, bb);
}
break;
@@ -2616,12 +2687,9 @@
assert(node->nd_vid > 0);
assert(node->nd_value != NULL);
- Value *slot = get_lvar(node->nd_vid);
-
Value *new_val = compile_node(node->nd_value);
+ new StoreInst(new_val, compile_lvar_slot(node->nd_vid), bb);
- new StoreInst(new_val, slot, bb);
-
return new_val;
}
break;
@@ -3279,9 +3347,23 @@
}
params[3] = blockVal;
+ // If we are calling a method that needs a top-level binding
+ // object, let's create it.
+ // (Note: this won't work if the method is aliased, but we can
+ // live with that for now)
+ if (sel == selEval
+ || sel == selInstanceEval
+ || sel == selClassEval
+ || sel == selModuleEval
+ || sel == selLocalVariables
+ || sel == selBinding) {
+ compile_binding();
+ }
+
// Can we optimize the call?
if (!super_call && !splat_args) {
- Value *optimizedCall = compile_optimized_dispatch_call(sel, argc, params);
+ Value *optimizedCall =
+ compile_optimized_dispatch_call(sel, argc, params);
if (optimizedCall != NULL) {
return optimizedCall;
}
@@ -4080,7 +4162,7 @@
case NODE_FOR:
case NODE_ITER:
{
- std::map<ID, Value *> old_dvars = dvars;
+ std::vector<ID> old_dvars = dvars;
BasicBlock *old_current_loop_begin_bb = current_loop_begin_bb;
BasicBlock *old_current_loop_body_bb = current_loop_body_bb;
@@ -4302,6 +4384,33 @@
return f;
}
+Value *
+RoxorCompiler::compile_lvar_slot(ID name)
+{
+ std::map<ID, Value *>::iterator iter = lvars.find(name);
+ if (iter != lvars.end()) {
+#if ROXOR_COMPILER_DEBUG
+ printf("get_lvar %s\n", rb_id2name(name));
+#endif
+ return iter->second;
+ }
+ VALUE *var = GET_VM()->get_binding_lvar(name);
+ if (var != NULL) {
+#if ROXOR_COMPILER_DEBUG
+ printf("get_binding_lvar %s (%p)\n", rb_id2name(name), *(void **)var);
+#endif
+ Value *int_val = ConstantInt::get(IntTy, (long)var);
+ return new IntToPtrInst(int_val, RubyObjPtrTy, "", bb);
+ }
+ assert(current_block);
+ Value *slot = compile_dvar_slot(name);
+ assert(slot != NULL);
+#if ROXOR_COMPILER_DEBUG
+ printf("get_dvar %s\n", rb_id2name(name));
+#endif
+ return slot;
+}
+
// VM primitives
#define MAX_ARITY 20
@@ -4872,6 +4981,87 @@
}
static inline VALUE
+__rb_vm_bcall(VALUE self, VALUE dvars, IMP pimp, const rb_vm_arity_t &arity, int argc, const VALUE *argv)
+{
+ if ((arity.real != argc) || (arity.max == -1)) {
+ VALUE *new_argv = (VALUE *)alloca(sizeof(VALUE) * arity.real);
+ assert(argc >= arity.min);
+ assert((arity.max == -1) || (argc <= arity.max));
+ int used_opt_args = argc - arity.min;
+ int opt_args, rest_pos;
+ if (arity.max == -1) {
+ opt_args = arity.real - arity.min - 1;
+ rest_pos = arity.left_req + opt_args;
+ }
+ else {
+ opt_args = arity.real - arity.min;
+ rest_pos = -1;
+ }
+ for (int i = 0; i < arity.real; ++i) {
+ if (i < arity.left_req) {
+ // required args before optional args
+ new_argv[i] = argv[i];
+ }
+ else if (i < arity.left_req + opt_args) {
+ // optional args
+ int opt_arg_index = i - arity.left_req;
+ if (opt_arg_index >= used_opt_args) {
+ new_argv[i] = Qundef;
+ }
+ else {
+ new_argv[i] = argv[i];
+ }
+ }
+ else if (i == rest_pos) {
+ // rest
+ int rest_size = argc - arity.real + 1;
+ if (rest_size <= 0) {
+ new_argv[i] = rb_ary_new();
+ }
+ else {
+ new_argv[i] = rb_ary_new4(rest_size, &argv[i]);
+ }
+ }
+ else {
+ // required args after optional args
+ new_argv[i] = argv[argc-(arity.real - i)];
+ }
+ }
+ argv = new_argv;
+ argc = arity.real;
+ }
+
+ assert(pimp != NULL);
+
+ VALUE (*imp)(VALUE, SEL, VALUE, ...) = (VALUE (*)(VALUE, SEL, VALUE, ...))pimp;
+
+ switch (argc) {
+ case 0:
+ return (*imp)(self, 0, dvars);
+ case 1:
+ return (*imp)(self, 0, dvars, argv[0]);
+ case 2:
+ return (*imp)(self, 0, dvars, argv[0], argv[1]);
+ case 3:
+ return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2]);
+ case 4:
+ return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3]);
+ case 5:
+ return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4]);
+ case 6:
+ return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
+ case 7:
+ return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
+ case 8:
+ return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
+ case 9:
+ return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
+ }
+ printf("invalid argc %d\n", argc);
+ abort();
+}
+
+static inline VALUE
__rb_vm_rcall(VALUE self, NODE *node, IMP pimp, const rb_vm_arity_t &arity,
int argc, const VALUE *argv)
{
@@ -4952,7 +5142,6 @@
}
printf("invalid argc %d\n", argc);
abort();
- return Qnil;
}
static inline Method
@@ -5151,8 +5340,11 @@
ocache.helper = (struct ocall_helper *)malloc(
sizeof(struct ocall_helper));
ocache.helper->bs_method = rb_bs_find_method(klass, sel);
- assert(rb_objc_fill_sig(self, klass, sel,
- &ocache.helper->sig, ocache.helper->bs_method));
+ const bool ok = rb_objc_fill_sig(self, klass, sel,
+ &ocache.helper->sig, ocache.helper->bs_method);
+ if (!ok) {
+ abort();
+ }
}
}
else {
@@ -5301,6 +5493,12 @@
GET_VM()->current_block = old_b;
GET_VM()->block_saved = old_block_saved;
+
+ if (!GET_VM()->bindings.empty()) {
+ rb_objc_release(GET_VM()->bindings.back());
+ GET_VM()->bindings.pop_back();
+ }
+
return retval;
}
@@ -5428,10 +5626,11 @@
GET_VM()->blocks.find(node);
rb_vm_block_t *b;
+ bool cached = false;
if (iter == GET_VM()->blocks.end()) {
b = (rb_vm_block_t *)xmalloc(sizeof(rb_vm_block_t)
- + (sizeof(VALUE) * dvars_size));
+ + (sizeof(VALUE *) * dvars_size));
if (nd_type(node) == NODE_IFUNC) {
assert(llvm_function == NULL);
@@ -5452,24 +5651,85 @@
else {
b = iter->second;
assert(b->dvars_size == dvars_size);
+ cached = true;
}
b->self = self;
b->node = node;
- if (dvars_size > 0) {
- va_list ar;
- va_start(ar, dvars_size);
- for (int i = 0; i < dvars_size; ++i) {
- b->dvars[i] = va_arg(ar, VALUE *);
+ va_list ar;
+ va_start(ar, dvars_size);
+ for (int i = 0; i < dvars_size; ++i) {
+ b->dvars[i] = va_arg(ar, VALUE *);
+ }
+ int lvars_size = va_arg(ar, int);
+ if (lvars_size > 0) {
+ if (!cached) {
+ rb_vm_local_t **l = &b->locals;
+ for (int i = 0; i < lvars_size; i++) {
+ GC_WB(l, xmalloc(sizeof(rb_vm_local_t)));
+ l = &(*l)->next;
+ }
}
- va_end(ar);
+ rb_vm_local_t *l = b->locals;
+ for (int i = 0; i < lvars_size; ++i) {
+ assert(l != NULL);
+ l->name = va_arg(ar, ID);
+ l->value = va_arg(ar, VALUE *);
+ l = l->next;
+ }
}
+ va_end(ar);
return b;
}
extern "C"
+void
+rb_vm_push_binding(VALUE self, int lvars_size, ...)
+{
+ rb_vm_binding_t *b = (rb_vm_binding_t *)xmalloc(sizeof(rb_vm_binding_t));
+ GC_WB(&b->self, self);
+
+ va_list ar;
+ va_start(ar, lvars_size);
+ rb_vm_local_t **l = &b->locals;
+ for (int i = 0; i < lvars_size; ++i) {
+ GC_WB(l, xmalloc(sizeof(rb_vm_local_t)));
+ (*l)->name = va_arg(ar, ID);
+ (*l)->value = va_arg(ar, VALUE *);
+ (*l)->next = NULL;
+ l = &(*l)->next;
+ }
+ va_end(ar);
+
+ rb_objc_retain(b);
+ GET_VM()->bindings.push_back(b);
+}
+
+extern "C"
+rb_vm_binding_t *
+rb_vm_current_binding(void)
+{
+ return GET_VM()->bindings.empty() ? NULL : GET_VM()->bindings.back();
+}
+
+extern "C"
+void
+rb_vm_add_binding(rb_vm_binding_t *binding)
+{
+ GET_VM()->bindings.push_back(binding);
+}
+
+extern "C"
+void
+rb_vm_pop_binding(void)
+{
+ GET_VM()->bindings.pop_back();
+}
+
+
+extern "C"
VALUE
rb_vm_call(VALUE self, SEL sel, int argc, const VALUE *argv, bool super)
{
@@ -5636,10 +5896,9 @@
}
}
- int dvars_size = b->dvars_size;
rb_vm_arity_t arity = b->arity;
- if (dvars_size > 0 || argc < arity.min || argc > arity.max) {
+ if (argc < arity.min || argc > arity.max) {
VALUE *new_argv;
if (argc == 1 && TYPE(argv[0]) == T_ARRAY && (arity.min > 1 || (arity.min == 1 && arity.min != arity.max))) {
// Expand the array
@@ -5650,63 +5909,47 @@
}
argv = new_argv;
argc = ary_len;
- if (dvars_size == 0 && argc >= arity.min
- && (argc <= arity.max || b->arity.max == -1)) {
- return __rb_vm_rcall(b->self, b->node, b->imp, arity, argc,
- argv);
+ if (argc >= arity.min && (argc <= arity.max || b->arity.max == -1)) {
+ goto block_call;
}
}
int new_argc;
if (argc <= arity.min) {
- new_argc = dvars_size + arity.min;
+ new_argc = arity.min;
}
else if (argc > arity.max && b->arity.max != -1) {
- new_argc = dvars_size + arity.max;
+ new_argc = arity.max;
}
else {
- new_argc = dvars_size + argc;
+ new_argc = argc;
}
new_argv = (VALUE *)alloca(sizeof(VALUE) * new_argc);
- for (int i = 0; i < dvars_size; i++) {
- new_argv[i] = (VALUE)b->dvars[i];
+ for (int i = 0; i < new_argc; i++) {
+ new_argv[i] = i < argc ? argv[i] : Qnil;
}
- for (int i = 0; i < new_argc - dvars_size; i++) {
- new_argv[dvars_size + i] = i < argc ? argv[i] : Qnil;
- }
argc = new_argc;
argv = new_argv;
- if (dvars_size > 0) {
- arity.min += dvars_size;
- if (arity.max != -1) {
- arity.max += dvars_size;
- }
- arity.real += dvars_size;
- arity.left_req += dvars_size;
- }
}
#if ROXOR_VM_DEBUG
- printf("yield block %p argc %d arity %d dvars %d\n", b, argc,
- arity.real, b->dvars_size);
+ printf("yield block %p argc %d arity %d\n", b, argc, arity.real);
#endif
+block_call:
+
// We need to preserve dynamic variable slots here because our block may
// call the parent method which may call the block again, and since dvars
// are currently implemented using alloca() we will painfully die if the
// previous slots are not restored.
-
- VALUE **old_dvars;
- if (dvars_size > 0) {
- old_dvars = (VALUE **)alloca(sizeof(VALUE *) * dvars_size);
- memcpy(old_dvars, b->dvars, sizeof(VALUE) * dvars_size);
+ VALUE *old_dvars[100];
+ assert(b->dvars_size < 100);
+ for (int i = 0; i < b->dvars_size; i++) {
+ old_dvars[i] = b->dvars[i];
}
- else {
- old_dvars = NULL;
- }
- VALUE v = __rb_vm_rcall(b->self, b->node, b->imp, arity, argc, argv);
+ VALUE v = __rb_vm_bcall(b->self, (VALUE)b->dvars, b->imp, b->arity, argc, argv);
- if (old_dvars != NULL) {
- memcpy(b->dvars, old_dvars, sizeof(VALUE) * dvars_size);
+ for (int i = 0; i < b->dvars_size; i++) {
+ b->dvars[i] = old_dvars[i];
}
return v;
@@ -5780,27 +6023,6 @@
return rb_vm_yield0(argc, argv);
}
-extern "C"
-struct rb_float_cache *
-rb_vm_float_cache(double d)
-{
- std::map<double, struct rb_float_cache *>::iterator iter =
- GET_VM()->float_cache.find(d);
- if (iter == GET_VM()->float_cache.end()) {
- struct rb_float_cache *fc = (struct rb_float_cache *)malloc(
- sizeof(struct rb_float_cache));
- assert(fc != NULL);
-
- fc->count = 0;
- fc->obj = Qnil;
- GET_VM()->float_cache[d] = fc;
-
- return fc;
- }
-
- return iter->second;
-}
-
extern IMP basic_respond_to_imp; // vm_method.c
extern "C"
@@ -6065,6 +6287,28 @@
}
extern "C"
+int
+rb_parse_in_eval(void)
+{
+ return rb_vm_parse_in_eval() ? 1 : 0;
+}
+
+extern "C"
+int
+rb_local_defined(ID id)
+{
+ return GET_VM()->get_binding_lvar(id) != NULL ? 1 : 0;
+}
+
+extern "C"
+int
+rb_dvar_defined(ID id)
+{
+ // TODO
+ return 0;
+}
+
+extern "C"
IMP
rb_vm_compile(const char *fname, NODE *node)
{
@@ -6099,12 +6343,6 @@
printf("compilation/optimization done, took %lld ns\n", elapsedNano);
#endif
-#if ROXOR_DUMP_IR
- printf("IR dump ----------------------------------------------\n");
- RoxorCompiler::module->dump();
- printf("------------------------------------------------------\n");
-#endif
-
delete compiler;
return imp;
@@ -6112,10 +6350,18 @@
extern "C"
VALUE
-rb_vm_run(const char *fname, NODE *node)
+rb_vm_run(const char *fname, NODE *node, rb_vm_binding_t *binding)
{
+ if (binding != NULL) {
+ GET_VM()->bindings.push_back(binding);
+ }
+
IMP imp = rb_vm_compile(fname, node);
+ if (binding != NULL) {
+ GET_VM()->bindings.pop_back();
+ }
+
try {
return ((VALUE(*)(VALUE, SEL))imp)(GET_VM()->current_top_object, 0);
}
@@ -6133,18 +6379,22 @@
extern "C"
VALUE
-rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node)
+rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node,
+ rb_vm_binding_t *binding)
{
assert(klass != 0);
VALUE old_top_object = GET_VM()->current_top_object;
+ if (binding != NULL) {
+ self = binding->self;
+ }
if (self != 0) {
GET_VM()->current_top_object = self;
}
Class old_class = GET_VM()->current_class;
GET_VM()->current_class = (Class)klass;
- VALUE val = rb_vm_run(fname, node);
+ VALUE val = rb_vm_run(fname, node, binding);
GET_VM()->current_top_object = old_top_object;
GET_VM()->current_class = old_class;
@@ -6314,3 +6564,14 @@
rb_objc_retain((void *)top_self);
GET_VM()->current_top_object = top_self;
}
+
+extern "C"
+void
+rb_vm_finalize(void)
+{
+#if ROXOR_DUMP_IR_BEFORE_EXIT
+ printf("IR dump ----------------------------------------------\n");
+ RoxorCompiler::module->dump();
+ printf("------------------------------------------------------\n");
+#endif
+}
Modified: MacRuby/branches/experimental/roxor.h
===================================================================
--- MacRuby/branches/experimental/roxor.h 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/roxor.h 2009-04-03 02:11:56 UTC (rev 1288)
@@ -5,8 +5,52 @@
extern "C" {
#endif
-VALUE rb_vm_run(const char *fname, NODE *node);
-VALUE rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node);
+typedef struct {
+ short min; // min number of args that we accept
+ short max; // max number of args that we accept (-1 if rest)
+ short left_req; // number of args required on the left side
+ short real; // number of args of the low level function
+} rb_vm_arity_t;
+
+struct rb_vm_local {
+ ID name;
+ VALUE *value;
+ struct rb_vm_local *next;
+};
+typedef struct rb_vm_local rb_vm_local_t;
+
+#define VM_BLOCK_PROC 0x0001 // block is a Proc object
+#define VM_BLOCK_LAMBDA 0x0002 // block is a lambda
+
+typedef struct {
+ VALUE self;
+ NODE *node;
+ rb_vm_arity_t arity;
+ IMP imp;
+ int flags;
+ rb_vm_local_t *locals;
+ int dvars_size;
+ VALUE *dvars[1];
+} rb_vm_block_t;
+
+typedef struct {
+ VALUE self;
+ rb_vm_local_t *locals;
+} rb_vm_binding_t;
+
+typedef struct {
+ VALUE oclass;
+ VALUE rclass;
+ VALUE recv;
+ SEL sel;
+ int arity;
+ NODE *node; // can be NULL (if pure Objective-C)
+ void *cache;
+} rb_vm_method_t;
+
+VALUE rb_vm_run(const char *fname, NODE *node, rb_vm_binding_t *binding);
+VALUE rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node,
+ rb_vm_binding_t *binding);
IMP rb_vm_compile(const char *fname, NODE *node);
bool rb_vm_running(void);
@@ -79,38 +123,8 @@
GC_WB(&robj->slots[slot], val);
}
-typedef struct {
- VALUE oclass;
- VALUE rclass;
- VALUE recv;
- SEL sel;
- int arity;
- NODE *node; // can be NULL (if pure Objective-C)
- void *cache;
-} rb_vm_method_t;
-
rb_vm_method_t *rb_vm_get_method(VALUE klass, VALUE obj, ID mid, int scope);
-typedef struct {
- short min; // min number of args that we accept
- short max; // max number of args that we accept (-1 if rest)
- short left_req; // number of args required on the left side
- short real; // number of args of the low level function
-} rb_vm_arity_t;
-
-#define VM_BLOCK_PROC 0x0001 // block is a Proc object
-#define VM_BLOCK_LAMBDA 0x0002 // block is a lambda
-
-typedef struct {
- VALUE self;
- NODE *node;
- rb_vm_arity_t arity;
- IMP imp;
- int flags;
- int dvars_size;
- VALUE *dvars[1];
-} rb_vm_block_t;
-
static inline rb_vm_block_t *
rb_proc_get_block(VALUE proc)
{
@@ -124,13 +138,10 @@
void rb_vm_restore_current_block(void);
VALUE rb_vm_block_eval(rb_vm_block_t *block, int argc, const VALUE *argv);
-struct rb_float_cache {
- unsigned int count;
- VALUE obj;
-};
+rb_vm_binding_t *rb_vm_current_binding(void);
+void rb_vm_add_binding(rb_vm_binding_t *binding);
+void rb_vm_pop_binding();
-struct rb_float_cache *rb_vm_float_cache(double d);
-
static inline VALUE
rb_robject_allocate_instance(VALUE klass)
{
@@ -168,6 +179,8 @@
} \
while (0)
+void rb_vm_finalize(void);
+
VALUE rb_iseq_compile(VALUE src, VALUE file, VALUE line);
VALUE rb_iseq_eval(VALUE iseq);
VALUE rb_iseq_new(NODE *node, VALUE filename);
Modified: MacRuby/branches/experimental/tool/compile_prelude.rb
===================================================================
--- MacRuby/branches/experimental/tool/compile_prelude.rb 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/tool/compile_prelude.rb 2009-04-03 02:11:56 UTC (rev 1288)
@@ -80,7 +80,7 @@
rb_vm_run(prelude_name<%=i%>, rb_compile_string(
prelude_name<%=i%>,
rb_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 1),
- 1));
+ 1), NULL);
% }
}
Modified: MacRuby/branches/experimental/vm_eval.c
===================================================================
--- MacRuby/branches/experimental/vm_eval.c 2009-04-01 12:49:41 UTC (rev 1287)
+++ MacRuby/branches/experimental/vm_eval.c 2009-04-03 02:11:56 UTC (rev 1288)
@@ -278,7 +278,7 @@
VALUE (*bl_proc) (ANYARGS), VALUE data2)
{
NODE *node = NEW_IFUNC(bl_proc, data2);
- rb_vm_block_t *b = rb_vm_prepare_block(NULL, node, obj, 0);
+ rb_vm_block_t *b = rb_vm_prepare_block(NULL, node, obj, 0, 0);
rb_vm_change_current_block(b);
if (cache == NULL) {
cache = rb_vm_get_call_cache(sel);
@@ -311,13 +311,34 @@
}
static VALUE
-eval_string(VALUE self, VALUE klass, VALUE src, VALUE scope, const char *file, int line)
+eval_string(VALUE self, VALUE klass, VALUE src, VALUE scope, const char *file,
+ const int line)
{
- // TODO honor scope
+ rb_vm_binding_t *b = NULL;
+ if (scope != Qnil) {
+ if (!rb_obj_is_kind_of(scope, rb_cBinding)) {
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Binding)",
+ rb_obj_classname(scope));
+ }
+ b = (rb_vm_binding_t *)DATA_PTR(scope);
+ }
+
bool old_parse_in_eval = rb_vm_parse_in_eval();
rb_vm_set_parse_in_eval(true);
+ if (b != NULL) {
+ // Binding must be added because the parser needs it.
+ rb_vm_add_binding(b);
+ }
+
NODE *node = rb_compile_string(file, src, line);
+
+ if (b != NULL) {
+ // We remove the binding now but we still pass it to the VM, which
+ // will use it for compilation.
+ rb_vm_pop_binding();
+ }
rb_vm_set_parse_in_eval(old_parse_in_eval);
+
if (node == NULL) {
VALUE exc = rb_vm_current_exception();
if (exc != Qnil) {
@@ -327,10 +348,11 @@
rb_raise(rb_eSyntaxError, "compile error");
}
}
+
if (klass == 0) {
klass = rb_cObject;
}
- return rb_vm_run_under(klass, self, file, node);
+ return rb_vm_run_under(klass, self, file, node, b);
}
static VALUE
@@ -417,13 +439,13 @@
if (!NIL_P(vfile)) {
file = RSTRING_PTR(vfile);
}
- return eval_string(0, self, src, scope, file, line);
+ return eval_string(self, 0, src, scope, file, line);
}
VALUE
rb_eval_string(const char *str)
{
- return eval_string(0, rb_vm_top_self(), rb_str_new2(str), Qnil, "(eval)", 1);
+ return eval_string(rb_vm_top_self(), 0, rb_str_new2(str), Qnil, "(eval)", 1);
}
VALUE
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090402/d2dbbe3f/attachment-0001.html>
More information about the macruby-changes
mailing list