diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2006-12-31 15:02:22 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2006-12-31 15:02:22 +0000 |
commit | a3e1b1ce7ed7e7ffac23015fc2fde56511b30681 (patch) | |
tree | 7b725552a9a4ded93849ca2faab1b257f7761790 /blockinlining.c | |
parent | 3e7566d8fb5138bb9cd647e5fdefc54fc9803509 (diff) | |
download | ruby-a3e1b1ce7ed7e7ffac23015fc2fde56511b30681.tar.gz |
* Merge YARV
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11439 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'blockinlining.c')
-rw-r--r-- | blockinlining.c | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/blockinlining.c b/blockinlining.c new file mode 100644 index 0000000000..7a74f3492e --- /dev/null +++ b/blockinlining.c @@ -0,0 +1,461 @@ +/********************************************************************** + + blockinlining.c - + + $Author$ + $Date$ + + Copyright (C) 2004-2006 Koichi Sasada + +**********************************************************************/ + +#include "ruby.h" +#include "node.h" +#include "yarvcore.h" + +VALUE yarv_new_iseqval(VALUE node, VALUE name, VALUE file, + VALUE parent, VALUE type, VALUE block_opt, VALUE opt); + +static VALUE +yarv_iseq_special_block(yarv_iseq_t *iseq, void *builder) +{ +#if OPT_BLOCKINLINING + VALUE parent = Qfalse; + VALUE iseqval; + + if (iseq->argc > 1 || iseq->arg_simple == 0) { + /* argument check */ + return 0; + } + + if (iseq->cached_special_block_builder) { + if (iseq->cached_special_block_builder == builder) { + return iseq->cached_special_block; + } + else { + return 0; + } + } + else { + iseq->cached_special_block_builder = (void *)1; + } + + if (iseq->parent_iseq) { + parent = iseq->parent_iseq->self; + } + iseqval = yarv_iseq_new_with_bopt(iseq->node, iseq->name, iseq->file_name, + parent, iseq->type, + GC_GUARDED_PTR(builder)); + if (0) { + printf("%s\n", RSTRING_PTR(iseq_disasm(iseqval))); + } + iseq->cached_special_block = iseqval; + iseq->cached_special_block_builder = builder; + return iseqval; +#else + return 0; +#endif +} + +static NODE * +new_block(NODE * head, NODE * tail) +{ + head = NEW_BLOCK(head); + tail = NEW_BLOCK(tail); + head->nd_next = tail; + return head; +} + +static NODE * +new_ary(NODE * head, NODE * tail) +{ + head = NEW_ARRAY(head); + head->nd_next = tail; + return head; +} + +static NODE * +new_assign(NODE * lnode, NODE * rhs) +{ + switch (nd_type(lnode)) { + case NODE_LASGN:{ + return NEW_NODE(NODE_LASGN, lnode->nd_vid, rhs, lnode->nd_cnt); + /* NEW_LASGN(lnode->nd_vid, rhs); */ + } + case NODE_GASGN:{ + return NEW_GASGN(lnode->nd_vid, rhs); + } + case NODE_DASGN:{ + return NEW_DASGN(lnode->nd_vid, rhs); + } + case NODE_ATTRASGN:{ + NODE *args = 0; + if (lnode->nd_args) { + args = NEW_ARRAY(lnode->nd_args->nd_head); + args->nd_next = NEW_ARRAY(rhs); + args->nd_alen = 2; + } + else { + args = NEW_ARRAY(rhs); + } + + return NEW_ATTRASGN(lnode->nd_recv, + lnode->nd_mid, + args); + } + default: + rb_bug("unimplemented (block inlining): %s", node_name(nd_type(lnode))); + } + return 0; +} + +static NODE * +build_Integer_times_node(yarv_iseq_t *iseq, NODE * node, NODE * lnode, + VALUE param_vars, VALUE local_vars) +{ + /* Special Block for Integer#times + {|e, _self| + _e = e + while(e < _self) + e = _e + redo_point: + BODY + next_point: + _e = _e.succ + end + } + + {|e, _self| + while(e < _self) + BODY + next_point: + e = e.succ + end + } + */ + ID _self = rb_intern("#_self"); + if (iseq->argc == 0) { + ID e = rb_intern("#e"); + rb_ary_push(param_vars, ID2SYM(e)); + rb_ary_push(param_vars, ID2SYM(_self)); + iseq->argc += 2; + + node = + NEW_WHILE(NEW_CALL + (NEW_DVAR(e), idLT, new_ary(NEW_DVAR(_self), 0)), + new_block(NEW_OPTBLOCK(node), + NEW_DASGN(e, + NEW_CALL(NEW_DVAR(e), idSucc, 0))), + Qundef); + } + else { + ID _e = rb_intern("#_e"); + ID e = SYM2ID(rb_ary_entry(param_vars, 0)); + NODE *assign; + + rb_ary_push(param_vars, ID2SYM(_self)); + rb_ary_push(local_vars, ID2SYM(_e)); + iseq->argc++; + + if (nd_type(lnode) == NODE_DASGN_CURR) { + assign = NEW_DASGN(e, NEW_DVAR(_e)); + } + else { + assign = new_assign(lnode, NEW_DVAR(_e)); + } + + node = + new_block(NEW_DASGN(_e, NEW_DVAR(e)), + NEW_WHILE(NEW_CALL + (NEW_DVAR(_e), idLT, + new_ary(NEW_DVAR(_self), 0)), + new_block(assign, + new_block(NEW_OPTBLOCK(node), + NEW_DASGN(_e, + NEW_CALL + (NEW_DVAR(_e), + idSucc, 0)))), + Qundef)); + } + return node; +} + +VALUE +yarv_invoke_Integer_times_special_block(VALUE num) +{ + yarv_thread_t *th = GET_THREAD(); + yarv_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]); + + if (orig_block && BUILTIN_TYPE(orig_block->iseq) != T_NODE) { + VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq, + build_Integer_times_node); + yarv_iseq_t *tsiseq; + VALUE argv[2], val; + + if (tsiseqval) { + yarv_block_t block = *orig_block; + GetISeqPtr(tsiseqval, tsiseq); + block.iseq = tsiseq; + th->cfp->lfp[0] = GC_GUARDED_PTR(&block); + argv[0] = INT2FIX(0); + argv[1] = num; + val = th_invoke_yield(th, 2, argv); + if (val == Qundef) { + return num; + } + else { + return val; + } + } + } + return Qundef; +} + +static NODE * +build_Range_each_node(yarv_iseq_t *iseq, NODE * node, NODE * lnode, + VALUE param_vars, VALUE local_vars, ID mid) +{ + /* Special Block for Range#each + {|e, _last| + _e = e + while _e < _last + e = _e + next_point: + BODY + redo_point: + _e = _e.succ + end + } + {|e, _last| + while e < _last + BODY + redo_point: + e = e.succ + end + } + */ + ID _last = rb_intern("#_last"); + if (iseq->argc == 0) { + ID e = rb_intern("#e"); + rb_ary_push(param_vars, ID2SYM(e)); + rb_ary_push(param_vars, ID2SYM(_last)); + iseq->argc += 2; + + node = + NEW_WHILE(NEW_CALL(NEW_DVAR(e), mid, new_ary(NEW_DVAR(_last), 0)), + new_block(NEW_OPTBLOCK(node), + NEW_DASGN(e, + NEW_CALL(NEW_DVAR(e), idSucc, 0))), + Qundef); + } + else { + ID _e = rb_intern("#_e"); + ID e = SYM2ID(rb_ary_entry(param_vars, 0)); + NODE *assign; + + rb_ary_push(param_vars, ID2SYM(_last)); + rb_ary_push(local_vars, ID2SYM(_e)); + iseq->argc++; + + if (nd_type(lnode) == NODE_DASGN_CURR) { + assign = NEW_DASGN(e, NEW_DVAR(_e)); + } + else { + assign = new_assign(lnode, NEW_DVAR(_e)); + } + + node = + new_block(NEW_DASGN(_e, NEW_DVAR(e)), + NEW_WHILE(NEW_CALL + (NEW_DVAR(_e), mid, + new_ary(NEW_DVAR(_last), 0)), + new_block(assign, + new_block(NEW_OPTBLOCK(node), + NEW_DASGN(_e, + NEW_CALL + (NEW_DVAR(_e), + idSucc, 0)))), + Qundef)); + } + return node; +} + +static NODE * +build_Range_each_node_LE(yarv_iseq_t *iseq, NODE * node, NODE * lnode, + VALUE param_vars, VALUE local_vars) +{ + return build_Range_each_node(iseq, node, lnode, + param_vars, local_vars, idLE); +} + +static NODE * +build_Range_each_node_LT(yarv_iseq_t *iseq, NODE * node, NODE * lnode, + VALUE param_vars, VALUE local_vars) +{ + return build_Range_each_node(iseq, node, lnode, + param_vars, local_vars, idLT); +} + +VALUE +yarv_invoke_Range_each_special_block(VALUE range, + VALUE beg, VALUE end, int excl) +{ + yarv_thread_t *th = GET_THREAD(); + yarv_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]); + + if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) { + void *builder = + excl ? build_Range_each_node_LT : build_Range_each_node_LE; + VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq, builder); + yarv_iseq_t *tsiseq; + VALUE argv[2]; + + if (tsiseqval) { + VALUE val; + yarv_block_t block = *orig_block; + GetISeqPtr(tsiseqval, tsiseq); + block.iseq = tsiseq; + th->cfp->lfp[0] = GC_GUARDED_PTR(&block); + argv[0] = beg; + argv[1] = end; + val = th_invoke_yield(th, 2, argv); + if (val == Qundef) { + return range; + } + else { + return val; + } + } + } + return Qundef; +} + + +static NODE * +build_Array_each_node(yarv_iseq_t *iseq, NODE * node, NODE * lnode, + VALUE param_vars, VALUE local_vars) +{ + /* Special block for Array#each + ary.each{|e| + BODY + } + => + {|e, _self| + _i = 0 + while _i < _self.length + e = _self[_i] + redo_point: + BODY + next_point: + _i = _i.succ + end + } + + ary.each{ + BODY + } + => + {|_i, _self| + _i = 0 + while _i < _self.length + redo_point: + BODY + next_point: + _i = _i.succ + end + } + */ + + ID _self = rb_intern("#_self"); + ID _i = rb_intern("#_i"); + + if (iseq->argc == 0) { + ID _e = rb_intern("#_e"); + rb_ary_push(param_vars, ID2SYM(_e)); + rb_ary_push(param_vars, ID2SYM(_self)); + iseq->argc += 2; + rb_ary_push(local_vars, ID2SYM(_i)); + + node = + new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))), + NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT, + new_ary(NEW_CALL + (NEW_DVAR(_self), idLength, + 0), 0)), + new_block(NEW_OPTBLOCK(node), + NEW_DASGN(_i, + NEW_CALL(NEW_DVAR(_i), + idSucc, 0))), + Qundef)); + } + else { + ID e = SYM2ID(rb_ary_entry(param_vars, 0)); + NODE *assign; + + rb_ary_push(param_vars, ID2SYM(_self)); + iseq->argc++; + rb_ary_push(local_vars, ID2SYM(_i)); + + if (nd_type(lnode) == NODE_DASGN_CURR) { + assign = NEW_DASGN(e, + NEW_CALL(NEW_DVAR(_self), idAREF, + new_ary(NEW_DVAR(_i), 0))); + } + else { + assign = new_assign(lnode, + NEW_CALL(NEW_DVAR(_self), idAREF, + new_ary(NEW_DVAR(_i), 0))); + } + + node = + new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))), + NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT, + new_ary(NEW_CALL + (NEW_DVAR(_self), idLength, + 0), 0)), new_block(assign, + new_block + (NEW_OPTBLOCK + (node), + NEW_DASGN + (_i, + NEW_CALL + (NEW_DVAR + (_i), + idSucc, + 0)))), + Qundef)); + } + return node; +} + +VALUE +yarv_invoke_Array_each_special_block(VALUE ary) +{ + yarv_thread_t *th = GET_THREAD(); + yarv_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]); + + if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) { + VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq, + build_Array_each_node); + yarv_iseq_t *tsiseq; + VALUE argv[2]; + + if (tsiseqval) { + VALUE val; + yarv_block_t block = *orig_block; + GetISeqPtr(tsiseqval, tsiseq); + block.iseq = tsiseq; + th->cfp->lfp[0] = GC_GUARDED_PTR(&block); + argv[0] = 0; + argv[1] = ary; + val = th_invoke_yield(th, 2, argv); + if (val == Qundef) { + return ary; + } + else { + return val; + } + } + } + return Qundef; +} |