Permalink
Browse files

finished the save of local variables, this time also saving variables…

… used in blocks that are in other blocks

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/branches/experimental@1538 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
1 parent 9cee3ff commit e7cf23e1e97e48f91fcd2094d13627feedb37002 @vincentisambart vincentisambart committed May 6, 2009
Showing with 85 additions and 39 deletions.
  1. +1 −3 proc.c
  2. +63 −33 roxor.cpp
  3. +4 −2 roxor.h
  4. +16 −0 test_vm/block.rb
  5. +1 −1 vm_eval.c
View
@@ -41,9 +41,7 @@ rb_proc_alloc_with_block(VALUE klass, rb_vm_block_t *proc)
obj = Data_Wrap_Struct(klass, NULL, NULL, proc);
if (!(proc->flags & VM_BLOCK_PROC)) {
proc->flags |= VM_BLOCK_PROC;
- if (proc->parent_var_uses != NULL) {
- rb_vm_add_var_use(proc->parent_var_uses, proc);
- }
+ rb_vm_add_var_use(proc);
}
return obj;
}
View
@@ -231,6 +231,7 @@ class RoxorCompiler
Value *current_self;
bool current_block;
Value *current_var_uses;
+ Value *running_block;
BasicBlock *begin_bb;
BasicBlock *rescue_bb;
BasicBlock *ensure_bb;
@@ -678,6 +679,7 @@ RoxorCompiler::RoxorCompiler(const char *_fname)
self_id = rb_intern("self");
current_self = NULL;
current_var_uses = NULL;
+ running_block = NULL;
current_block = false;
current_block_node = NULL;
current_block_func = NULL;
@@ -1250,12 +1252,14 @@ RoxorCompiler::compile_block_create(NODE *node)
if (prepareBlockFunc == NULL) {
// void *rb_vm_prepare_block(Function *func, NODE *node, VALUE self,
// rb_vm_var_uses **parent_var_uses,
+ // rb_vm_block_t *parent_block,
// int dvars_size, ...);
std::vector<const Type *> types;
types.push_back(PtrTy);
types.push_back(PtrTy);
types.push_back(RubyObjTy);
types.push_back(PtrPtrTy);
+ types.push_back(PtrTy);
types.push_back(Type::Int32Ty);
FunctionType *ft = FunctionType::get(PtrTy, types, true);
prepareBlockFunc = cast<Function>
@@ -1273,6 +1277,12 @@ RoxorCompiler::compile_block_create(NODE *node)
else {
params.push_back(current_var_uses);
}
+ if (running_block == NULL) {
+ params.push_back(compile_const_pointer(NULL));
+ }
+ else {
+ params.push_back(running_block);
+ }
// Dvars.
params.push_back(ConstantInt::get(Type::Int32Ty, (int)dvars.size()));
@@ -3021,6 +3031,7 @@ RoxorCompiler::compile_node(NODE *node)
types.push_back(PtrTy); // sel
if (has_dvars) {
types.push_back(RubyObjPtrPtrTy); // dvars array
+ types.push_back(PtrTy); // rb_vm_block_t of the currently running block
}
for (int i = 0; i < nargs; ++i) {
types.push_back(RubyObjTy);
@@ -3048,20 +3059,22 @@ RoxorCompiler::compile_node(NODE *node)
Value *sel = arg++;
sel->setName("sel");
+ Value *old_running_block = running_block;
Value *old_current_var_uses = current_var_uses;
+ current_var_uses = NULL;
if (has_dvars) {
Value *dvars_arg = arg++;
dvars_arg->setName("dvars");
- }
-
- if (node->nd_tbl == NULL) {
- current_var_uses = NULL;
+ running_block = arg++;
+ running_block->setName("running_block");
}
else {
- current_var_uses = new AllocaInst(PtrTy, "", bb);
- new StoreInst(compile_const_pointer(NULL), current_var_uses, bb);
+ running_block = NULL;
+ }
+ if (node->nd_tbl != NULL) {
+ bool has_vars_to_save = false;
int i, args_count = (int)node->nd_tbl[0];
assert(args_count == nargs
|| args_count == nargs + 1 /* optional block */
@@ -3090,6 +3103,7 @@ RoxorCompiler::compile_node(NODE *node)
Value *slot = new AllocaInst(RubyObjTy, "", bb);
new StoreInst(val, slot, bb);
lvars[id] = slot;
+ has_vars_to_save = true;
}
// local vars must be created before the optional arguments
@@ -3107,9 +3121,15 @@ RoxorCompiler::compile_node(NODE *node)
Value *store = new AllocaInst(RubyObjTy, "", bb);
new StoreInst(nilVal, store, bb);
lvars[id] = store;
+ has_vars_to_save = true;
}
}
+ if (has_vars_to_save) {
+ current_var_uses = new AllocaInst(PtrTy, "", bb);
+ new StoreInst(compile_const_pointer(NULL), current_var_uses, bb);
+ }
+
NODE *args_node = node->nd_args;
if (args_node != NULL) {
// compile multiple assignment arguments (def f((a, b, v)))
@@ -3141,7 +3161,7 @@ RoxorCompiler::compile_node(NODE *node)
if (opt_node != NULL) {
int to_skip = args_node->nd_frml;
if (has_dvars) {
- to_skip++; // dvars array
+ to_skip += 2; // dvars array and currently running block
}
for (i = 0; i < to_skip; i++) {
++iter; // skip dvars and args required on the left-side
@@ -3219,6 +3239,7 @@ RoxorCompiler::compile_node(NODE *node)
current_self = old_self;
rescue_bb = old_rescue_bb;
current_var_uses = old_current_var_uses;
+ running_block = old_running_block;
return cast<Value>(f);
}
@@ -7075,7 +7096,7 @@ rb_vm_masgn_get_splat(VALUE ary, int before_splat_count, int after_splat_count)
__attribute__((always_inline))
static VALUE
-__rb_vm_bcall(VALUE self, VALUE dvars,
+__rb_vm_bcall(VALUE self, VALUE dvars, rb_vm_block_t *b,
IMP pimp, const rb_vm_arity_t &arity, int argc, const VALUE *argv)
{
if ((arity.real != argc) || (arity.max == -1)) {
@@ -7128,29 +7149,29 @@ __rb_vm_bcall(VALUE self, VALUE dvars,
assert(pimp != NULL);
- VALUE (*imp)(VALUE, SEL, VALUE, ...) = (VALUE (*)(VALUE, SEL, VALUE, ...))pimp;
+ VALUE (*imp)(VALUE, SEL, VALUE, rb_vm_block_t *, ...) = (VALUE (*)(VALUE, SEL, VALUE, rb_vm_block_t *, ...))pimp;
switch (argc) {
case 0:
- return (*imp)(self, 0, dvars);
+ return (*imp)(self, 0, dvars, b);
case 1:
- return (*imp)(self, 0, dvars, argv[0]);
+ return (*imp)(self, 0, dvars, b, argv[0]);
case 2:
- return (*imp)(self, 0, dvars, argv[0], argv[1]);
+ return (*imp)(self, 0, dvars, b, argv[0], argv[1]);
case 3:
- return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2]);
+ return (*imp)(self, 0, dvars, b, argv[0], argv[1], argv[2]);
case 4:
- return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3]);
+ return (*imp)(self, 0, dvars, b, 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]);
+ return (*imp)(self, 0, dvars, b, 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]);
+ return (*imp)(self, 0, dvars, b, 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]);
+ return (*imp)(self, 0, dvars, b, 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]);
+ return (*imp)(self, 0, dvars, b, 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]);
+ return (*imp)(self, 0, dvars, b, 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();
@@ -7812,7 +7833,7 @@ rb_vm_dispatch(struct mcache *cache, VALUE self, SEL sel, rb_vm_block_t *block,
GET_VM()->previous_block = old_b;
if (!GET_VM()->bindings.empty()) {
- rb_objc_release(GET_VM()->bindings.back());
+ rb_objc_release(GET_VM()->bindings.back());
GET_VM()->bindings.pop_back();
}
@@ -7944,6 +7965,7 @@ extern "C"
rb_vm_block_t *
rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self,
rb_vm_var_uses **parent_var_uses,
+ rb_vm_block_t *parent_block,
int dvars_size, ...)
{
NODE *cache_key;
@@ -7979,6 +8001,7 @@ rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self,
b->flags = 0;
b->dvars_size = dvars_size;
b->parent_var_uses = NULL;
+ b->parent_block = NULL;
rb_objc_retain(b);
GET_VM()->blocks[cache_key] = b;
@@ -7992,6 +8015,7 @@ rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self,
b->self = self;
b->node = node;
b->parent_var_uses = parent_var_uses;
+ b->parent_block = parent_block;
va_list ar;
va_start(ar, dvars_size);
@@ -8037,18 +8061,24 @@ struct rb_vm_var_uses {
extern "C"
void
-rb_vm_add_var_use(rb_vm_var_uses **var_uses, rb_vm_block_t *proc)
+rb_vm_add_var_use(rb_vm_block_t *block)
{
- assert(var_uses != NULL);
- if ((*var_uses == NULL) || ((*var_uses)->uses_count == VM_LVAR_USES_SIZE)) {
- rb_vm_var_uses* new_uses = (rb_vm_var_uses*)malloc(sizeof(rb_vm_var_uses));
- new_uses->next = *var_uses;
- new_uses->uses_count = 0;
- *var_uses = new_uses;
+ for (rb_vm_block_t *block_for_uses = block; block_for_uses != NULL; block_for_uses = block_for_uses->parent_block) {
+ rb_vm_var_uses **var_uses = block_for_uses->parent_var_uses;
+ if (var_uses == NULL) {
+ continue;
+ }
+ if ((*var_uses == NULL) || ((*var_uses)->uses_count == VM_LVAR_USES_SIZE)) {
+ rb_vm_var_uses* new_uses = (rb_vm_var_uses*)malloc(sizeof(rb_vm_var_uses));
+ new_uses->next = *var_uses;
+ new_uses->uses_count = 0;
+ *var_uses = new_uses;
+ }
+ int current_index = (*var_uses)->uses_count;
+ rb_gc_assign_weak_ref(block, &(*var_uses)->uses[current_index]);
+ ++(*var_uses)->uses_count;
}
- int current_index = (*var_uses)->uses_count;
- rb_gc_assign_weak_ref(proc, &(*var_uses)->uses[current_index]);
- ++(*var_uses)->uses_count;
+ block->parent_block = NULL; // we should not keep references that won't be used
}
struct rb_vm_kept_local {
@@ -8095,8 +8125,8 @@ rb_vm_keep_vars(rb_vm_var_uses *uses, int lvars_size, ...)
for (; use_index < current->uses_count; ++use_index) {
rb_vm_block_t *block = (rb_vm_block_t *)rb_gc_read_weak_ref(&current->uses[use_index]);
if (block != NULL) {
- for (int dvar_index=0; dvar_index<block->dvars_size; ++dvar_index) {
- for (int lvar_index=0; lvar_index<lvars_size; ++lvar_index) {
+ for (int dvar_index=0; dvar_index < block->dvars_size; ++dvar_index) {
+ for (int lvar_index=0; lvar_index < lvars_size; ++lvar_index) {
if (block->dvars[dvar_index] == locals[lvar_index].stack_address) {
GC_WB(&block->dvars[dvar_index], locals[lvar_index].new_address);
break;
@@ -8363,7 +8393,7 @@ rb_vm_block_eval0(rb_vm_block_t *b, int argc, const VALUE *argv)
assert(!(b->flags & VM_BLOCK_ACTIVE));
b->flags |= VM_BLOCK_ACTIVE;
- VALUE v = __rb_vm_bcall(b->self, (VALUE)b->dvars,
+ VALUE v = __rb_vm_bcall(b->self, (VALUE)b->dvars, b,
b->imp, b->arity, argc, argv);
b->flags &= ~VM_BLOCK_ACTIVE;
View
@@ -23,14 +23,15 @@ typedef struct rb_vm_local rb_vm_local_t;
#define VM_BLOCK_LAMBDA 0x0002 // block is a lambda
#define VM_BLOCK_ACTIVE 0x0004 // block is active (being executed)
-typedef struct {
+typedef struct rb_vm_block {
VALUE self;
NODE *node;
rb_vm_arity_t arity;
IMP imp;
int flags;
rb_vm_local_t *locals;
struct rb_vm_var_uses **parent_var_uses;
+ struct rb_vm_block *parent_block;
int dvars_size;
VALUE *dvars[1];
} rb_vm_block_t;
@@ -140,9 +141,10 @@ rb_proc_get_block(VALUE proc)
return (rb_vm_block_t *)DATA_PTR(proc);
}
-void rb_vm_add_var_use(struct rb_vm_var_uses **uses, rb_vm_block_t *proc);
+void rb_vm_add_var_use(rb_vm_block_t *proc);
rb_vm_block_t *rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self,
struct rb_vm_var_uses **parent_lvar_uses,
+ rb_vm_block_t *parent_block,
int dvars_size, ...);
rb_vm_block_t *rb_vm_current_block(void);
bool rb_vm_block_saved(void);
View
@@ -371,5 +371,21 @@ def f()
p f.call
}
+assert ':ok', %{
+ $a = []
+
+ def foo(what, &block)
+ $a << block
+ end
+
+ [:ok].each do |type|
+ foo type do
+ p type
+ end
+ end
+
+ $a.each do |b| b.call end
+}
+
# Enumerator
assert "[\"f\", \"o\", \"o\"]", "p 'foo'.chars.to_a"
View
@@ -277,7 +277,7 @@ rb_objc_block_call(VALUE obj, SEL sel, void *cache, int argc, VALUE *argv,
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, NULL, 0, 0);
+ rb_vm_block_t *b = rb_vm_prepare_block(NULL, node, obj, NULL, NULL, 0, 0);
rb_vm_change_current_block(b);
if (cache == NULL) {
cache = rb_vm_get_call_cache(sel);

0 comments on commit e7cf23e

Please sign in to comment.