yarv-diff:61
From: ko1 atdot.net
Date: 30 Jul 2005 12:26:03 -0000
Subject: [yarv-diff:61] r216 - in trunk: . test
Author: ko1
Date: 2005-07-30 21:26:02 +0900 (Sat, 30 Jul 2005)
New Revision: 216
Added:
trunk/test/test_flow.rb
Modified:
trunk/ChangeLog
trunk/compile.c
trunk/insns.def
trunk/test.rb
trunk/test/test_jump.rb
trunk/test/yarvtest.rb
trunk/vm.c
trunk/vm.h
trunk/vm_macro.def
trunk/yarv.h
trunk/yarvcore.h
Log:
* yarvcore.h : struct iseq_compile_data_ensure_node_stack is added
* compile.c : insert ensure clause before break/next/redo
* vm.c : fix return/break handling
* yarv.h, vm.c : fix lightweight yield
* vm.c, insns.def, vm_macro.def : change arguments of th_set_env (add sp)
* test/test_flow.rb : added
* test/yarvtest.rb : add ae_flow
* compile.c, vm_macro.def : add tail-call/tail-recursion optimization
(experimental)
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/ChangeLog 2005-07-30 12:26:02 UTC (rev 216)
@@ -4,6 +4,26 @@
# from Mon, 03 May 2004 01:24:19 +0900
#
+2005-07-30(Sat) 04:44:33 +0900 Koichi Sasada <ko1 atdot.net>
+
+ * yarvcore.h : struct iseq_compile_data_ensure_node_stack is added
+
+ * compile.c : insert ensure clause before break/next/redo
+
+ * vm.c : fix return/break handling
+
+ * yarv.h, vm.c : fix lightweight yield
+
+ * vm.c, insns.def, vm_macro.def : change arguments of th_set_env (add sp)
+
+ * test/test_flow.rb : added
+
+ * test/yarvtest.rb : add ae_flow
+
+ * compile.c, vm_macro.def : add tail-call/tail-recursion optimization
+ (experimental)
+
+
2005-07-29(Fri) 20:14:11 +0900 Koichi Sasada <ko1 atdot.net>
* compile.c : make_name_for_block and make_name_with_str
Modified: trunk/compile.c
===================================================================
--- trunk/compile.c 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/compile.c 2005-07-30 12:26:02 UTC (rev 216)
@@ -433,6 +433,23 @@
verify_list("append", anc1);
}
+#if 0
+/*
+ * anc1: e1, e2, e3
+ * anc2: e4, e5
+ *#=>
+ * anc1: e4, e5
+ * anc2: e1, e2, e3
+ */
+static void SWAP_LIST(LINK_ANCHOR *anc1, LINK_ANCHOR *anc2){
+ LINK_ANCHOR tmp = *anc2;
+ *anc2 = *anc1;
+ *anc1 = tmp;
+ verify_list("swap1", anc1);
+ verify_list("swap2", anc2);
+}
+#endif
+
static LINK_ANCHOR *REVERSE_LIST(LINK_ANCHOR *anc){
LINK_ELEMENT *first, *last, *elem, *e;
first = &anc->anchor;
@@ -1263,6 +1280,17 @@
}
}
}
+
+ if(iobj->insn_id == BIN(end)){
+ INSN *piobj = (INSN*)get_prev_insn((INSN*)list);
+ if(piobj->insn_id == BIN(send)){
+ /* TODO: tail call optimization */
+ if(piobj->operands[2] == 0){
+ //piobj->operands[3] = INT2FIX(FIX2INT(piobj->operands[3]) | VM_CALL_TAILCALL_BIT);
+ //piobj->operands[3] = INT2FIX(FIX2INT(piobj->operands[3]) | VM_CALL_TAILRECURSION_BIT);
+ }
+ }
+ }
}
list = list->next;
}
@@ -1803,6 +1831,22 @@
}
+static
+void add_ensure_iseq(LINK_ANCHOR *ret, yarv_iseq_t *iseq, VALUE self){
+ struct iseq_compile_data_ensure_node_stack *enlp = iseq->compile_data->ensure_node_stack;
+ DECL_ANCHOR(ensure);
+
+ while(enlp){
+ DECL_ANCHOR(ensure_part);
+ LINK_ANCHOR *t;
+ COMPILE_POPED(ensure_part, "ensure part", enlp->ensure_node);
+
+ ADD_SEQ(ensure, ensure_part);
+ enlp = enlp->prev;
+ }
+ ADD_SEQ(ret, ensure);
+}
+
/**
compile each node
@@ -2032,11 +2076,12 @@
}
case NODE_WHILE:
case NODE_UNTIL:{
- LABEL *prev_start_label = iseqobj->compile_data->start_label;
- LABEL * prev_end_label = iseqobj->compile_data->end_label;
- LABEL * prev_redo_label = iseqobj->compile_data->redo_label;
+ LABEL *prev_start_label = iseqobj->compile_data->start_label;
+ LABEL *prev_end_label = iseqobj->compile_data->end_label;
+ LABEL *prev_redo_label = iseqobj->compile_data->redo_label;
VALUE prev_loopval_popped = iseqobj->compile_data->loopval_popped;
-
+ struct iseq_compile_data_ensure_node_stack *enlp = iseqobj->compile_data->ensure_node_stack;
+
LABEL * next_label = iseqobj->compile_data->start_label =
NEW_LABEL(nd_line(node)); /* next */
LABEL * redo_label = iseqobj->compile_data->redo_label =
@@ -2046,12 +2091,13 @@
LABEL * end_label = NEW_LABEL(nd_line(node));
iseqobj->compile_data->loopval_popped = poped;
-
+ iseqobj->compile_data->ensure_node_stack = 0;
+
ADD_INSNL(ret, nd_line(node), jump, next_label);
ADD_LABEL(ret, redo_label);
COMPILE_ (ret, "while body", node->nd_body, 1);
-
+
ADD_LABEL(ret, next_label); /* next */
if(type == NODE_WHILE){
compile_branch_condition(self, iseqobj, ret,
@@ -2068,11 +2114,12 @@
ADD_INSN(ret, nd_line(node), putnil);
}
ADD_LABEL(ret, break_label); /* braek */
-
+
iseqobj->compile_data->start_label = prev_start_label;
iseqobj->compile_data->end_label = prev_end_label;
iseqobj->compile_data->redo_label = prev_redo_label;
iseqobj->compile_data->loopval_popped = prev_loopval_popped;
+ iseqobj->compile_data->ensure_node_stack = enlp;
break;
}
case NODE_ITER:
@@ -2105,17 +2152,32 @@
}
case NODE_BREAK:{
if(iseqobj->compile_data->redo_label != 0){
+ break_in_loop:
/* while/until */
COMPILE_(ret, "break val(while/until)", node->nd_stts,
iseqobj->compile_data->loopval_popped);
+ add_ensure_iseq(ret, iseqobj, self);
ADD_INSNL(ret, nd_line(node), jump, iseqobj->compile_data->end_label);
}
else if(iseqobj->type == ISEQ_TYPE_BLOCK){
+ break_in_block:
/* escape from block */
COMPILE(ret, "break val(block)", node->nd_stts);
ADD_INSN1(ret, nd_line(node), throw, I2F(0x02) /* TAG_BREAK */);
}
else{
+ yarv_iseq_t *ip = iseqobj->parent_iseqobj;
+ while(ip){
+ if(ip->type == ISEQ_TYPE_BLOCK){
+ rb_bug("break in rescue/ensure is not supported");
+ goto break_in_block;
+ }
+ else if(ip->compile_data->redo_label != 0){
+ rb_bug("break in while/until is not supported");
+ goto break_in_loop;
+ }
+ ip = iseqobj->parent_iseqobj;
+ }
COMPILE_ERROR(("can't put break"));
}
@@ -2123,25 +2185,48 @@
}
case NODE_NEXT:{
if(iseqobj->compile_data->redo_label != 0){
+ add_ensure_iseq(ret, iseqobj, self);
ADD_INSNL(ret, nd_line(node), jump, iseqobj->compile_data->start_label);
}
else if(iseqobj->compile_data->end_label){
COMPILE(ret, "next val", node->nd_stts);
+ add_ensure_iseq(ret, iseqobj, self);
ADD_INSNL(ret, nd_line(node), jump, iseqobj->compile_data->end_label);
}
else{
+ yarv_iseq_t *ip = iseqobj->parent_iseqobj;
+ while(ip){
+ if(ip->type == ISEQ_TYPE_BLOCK){
+ rb_bug("next in rescue/ensure is not supported");
+ }
+ else if(ip->compile_data->redo_label != 0){
+ rb_bug("next in while/until is not supported");
+ }
+ ip = iseqobj->parent_iseqobj;
+ }
COMPILE_ERROR(("can't next"));
}
break;
}
case NODE_REDO:{
if(iseqobj->compile_data->redo_label){
+ add_ensure_iseq(ret, iseqobj, self);
ADD_INSNL(ret, nd_line(node), jump, iseqobj->compile_data->redo_label);
}
else if(iseqobj->compile_data->start_label){
ADD_INSNL(ret, nd_line(node), jump, iseqobj->compile_data->start_label);
}
else{
+ yarv_iseq_t *ip = iseqobj->parent_iseqobj;
+ while(ip){
+ if(ip->type == ISEQ_TYPE_BLOCK){
+ rb_bug("redo in rescue/ensure is not supported");
+ }
+ else if(ip->compile_data->redo_label != 0){
+ rb_bug("redo in while/until is not supported");
+ }
+ ip = iseqobj->parent_iseqobj;
+ }
COMPILE_ERROR(("can't redo"));
}
break;
@@ -2219,15 +2304,20 @@
break;
}
case NODE_ENSURE:{
+ DECL_ANCHOR(ensr);
VALUE ensure = NEW_CHILD_ISEQOBJ(node->nd_ensr, rb_str_new2("ensure"),
self, ISEQ_TYPE_ENSURE);
LABEL * lstart = NEW_LABEL(nd_line(node));
LABEL * lend = NEW_LABEL(nd_line(node));
LABEL * lcont = NEW_LABEL(nd_line(node));
- DECL_ANCHOR(ensr);
-
VALUE prev_in_ensure = iseqobj->compile_data->in_ensure;
+ struct iseq_compile_data_ensure_node_stack enl = {
+ node->nd_ensr,
+ iseqobj->compile_data->ensure_node_stack /* prev */
+ };
+
iseqobj->compile_data->in_ensure = Qtrue;
+ iseqobj->compile_data->ensure_node_stack = &enl;
COMPILE_POPED(ensr, "ensure ensr", node->nd_ensr);
@@ -2244,6 +2334,7 @@
iseqobj->compile_data->in_ensure = prev_in_ensure;
ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, lstart, lend, ensure, 0, lcont);
+ iseqobj->compile_data->ensure_node_stack = enl.prev;
break;
}
Modified: trunk/insns.def
===================================================================
--- trunk/insns.def 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/insns.def 2005-07-30 12:26:02 UTC (rev 216)
@@ -951,7 +951,7 @@
GetISeqVal(klass_iseqval, klass_iseq);
th_set_env(th, klass_iseq,
FRAME_MAGIC_CLASS, klass, 0,
- klass_iseq->ISEQ_MEMBER, 0,
+ klass_iseq->ISEQ_MEMBER, GET_SP(), 0,
klass_iseq->local_size, 0, 0);
RESTORE_REGS();
@@ -1013,7 +1013,7 @@
GetISeqVal(module_iseqval, module_iseq);
th_set_env(th, module_iseq,
FRAME_MAGIC_CLASS, module, 0,
- module_iseq->ISEQ_MEMBER, 0,
+ module_iseq->ISEQ_MEMBER, GET_SP(), 0,
module_iseq->local_size, 0, 0);
RESTORE_REGS();
@@ -1209,7 +1209,7 @@
}
th_set_env(th, iseq,
FRAME_MAGIC_BLOCK, block->self, (VALUE)block->dfp,
- iseq->ISEQ_MEMBER, block->lfp,
+ iseq->ISEQ_MEMBER, GET_SP(), block->lfp,
iseq->local_size - argc, 0, 0);
reg_cfp->sp -= argc;
RESTORE_REGS();
Added: trunk/test/test_flow.rb
===================================================================
--- trunk/test/test_flow.rb 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/test/test_flow.rb 2005-07-30 12:26:02 UTC (rev 216)
@@ -0,0 +1,229 @@
+#
+# This test program is contributed by George Marrows
+# Re: [Yarv-devel] Some tests for test_jump.rb
+#
+
+require 'test/yarvtest'
+
+class TestFlow < YarvTestBase
+
+ def test_while_with_ensure
+ ae %q{
+ a = []
+ i = 0
+ begin
+ while i < 1
+ i+=1
+ begin
+ begin
+ next
+ ensure
+ a << :ok
+ end
+ ensure
+ a << :ok2
+ end
+ end
+ ensure
+ a << :last
+ end
+ }
+ ae %q{
+ a = []
+ i = 0
+ begin
+ while i < 1
+ i+=1
+ begin
+ begin
+ break
+ ensure
+ a << :ok
+ end
+ ensure
+ a << :ok2
+ end
+ end
+ ensure
+ a << :last
+ end
+ }
+ ae %q{
+ a = []
+ i = 0
+ begin
+ while i < 1
+ if i>0
+ break
+ end
+ i+=1
+ begin
+ begin
+ redo
+ ensure
+ a << :ok
+ end
+ ensure
+ a << :ok2
+ end
+ end
+ ensure
+ a << :last
+ end
+ }
+ end
+
+ def test_ensure_normal_flow
+ ae_flow %{
+ begin
+ ensure
+ end }
+ end
+
+ def test_ensure_exception
+ ae_flow %{
+ begin
+ raise StandardError
+ ensure
+ end
+ }
+ end
+
+ def test_break_in_block_runs_ensure
+ ae_flow %{
+ [1,2].each do
+ begin
+ break
+ ensure
+ end
+ end
+ }
+ end
+
+ def test_next_in_block_runs_ensure
+ ae_flow %{
+ [1,2].each do
+ begin
+ next
+ ensure
+ end
+ end
+ }
+ end
+ def test_return_from_method_runs_ensure
+ ae_flow %{
+ o = "test"
+ def o.test(a)
+ return a
+ ensure
+ end
+ o.test(123)
+ }
+ end
+
+ def test_break_ensure_interaction1
+ # make sure that any 'break state' set up in the VM is c
+ # the time of the ensure
+ ae_flow %{
+ [1,2].each{
+ break
+ }
+ begin
+ ensure
+ end
+ }
+ end
+
+ def test_break_ensure_interaction2
+ # ditto, different arrangement
+ ae_flow %{
+ begin
+ [1,2].each do
+ break
+ end
+ ensure
+ end
+ }
+ end
+
+ def test_break_through_2_ensures
+ ae_flow %{
+ [1,2].each do
+ begin
+ begin
+ break
+ ensure
+ end
+ ensure
+ end
+ end
+ }
+ end
+
+ def test_ensure_break_ensure
+ # break through an ensure; run 2nd normally
+ ae_flow %{
+ begin
+ [1,2].each do
+ begin
+ break
+ ensure
+ end
+ end
+ ensure
+ end
+ }
+ end
+
+ def test_exception_overrides_break
+ ae_flow %{
+ [1,2].each do
+ begin
+ break
+ ensure
+ raise StandardError
+ end
+ end
+ }
+ end
+
+if false
+ # unsupported
+ def test_break_in_exception
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ ensure
+ next
+ end
+ end
+ }
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ raise
+ rescue
+ next
+ end
+ end
+ }
+ end
+
+ def test_break_overrides_exception
+ ae_flow %{
+ [1,2].each do
+ begin
+ raise StandardError
+ ensure
+ break
+ end
+ end
+ }
+ end
+end
+end
+
Modified: trunk/test/test_jump.rb
===================================================================
--- trunk/test/test_jump.rb 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/test/test_jump.rb 2005-07-30 12:26:02 UTC (rev 216)
@@ -215,6 +215,14 @@
m
}
end
+
+ def test_break_from_times
+ ae %q{
+ 3.times{
+ break :ok
+ }
+ }
+ end
end
Modified: trunk/test/yarvtest.rb
===================================================================
--- trunk/test/yarvtest.rb 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/test/yarvtest.rb 2005-07-30 12:26:02 UTC (rev 216)
@@ -26,7 +26,40 @@
assert_equal(ruby, yarv)
end
-
+
+ def ae_flow(src, for_value=true)
+ # Tracks flow through the code
+ # A test like
+ # begin
+ # ensure
+ # end
+ # gets transformed into
+ # a = []
+ # begin
+ # begin; a << 1
+ # ensure; a << 2
+ # end; a << 3
+ # rescue Exception
+ # a << 99
+ # end
+ # a
+ # before being run. This tracks control flow through the code.
+
+ cnt = 0
+ src = src.gsub(/(\n|$)/) { "; a << #{cnt+=1}\n" }
+ src = "a = []; begin; #{src}; rescue Exception; a << 99; end; a"
+
+ if false#true
+ puts
+ puts '#----'
+ puts src
+ puts '#----'
+ end
+
+ ae(src)
+ end
+
+
def test_
end
Modified: trunk/test.rb
===================================================================
--- trunk/test.rb 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/test.rb 2005-07-30 12:26:02 UTC (rev 216)
@@ -8,137 +8,69 @@
###########################################################
$prog =<<'__EOP__'
-3.times{|i|
- p i
-}
-
-__END__
-def m
-3.times{
- 4.times{
- 5.times{
- return caller 0
- }
- }
-}
+def m1 a
+ if a == 0
+ else
+ m1 a-1
+ end
end
-m
+m1 3
-__END__
-def m
- 1.times{
- raise
- }
-end
+p 1
-def iter
- yield
-end
-
-begin
- m
-rescue => e
- p e
- p e.backtrace
-end
-
-
-
__END__
-def m
- begin
- raise
- rescue => e
- p e.backtrace
+def m n
+ if n == 0
+ #
+ else
+ m n-1
end
end
-def mm
- caller 0
-end
+m 5
+p 1
+__END__
+
def iter
yield
end
begin
iter{
- raise
+ iter{
+ iter{
+ raise
+ }
+ }
}
rescue => e
- e.backtrace
+ puts e.backtrace
end
-
__END__
-3.times{|bl|
- break 10
-}
-
-
-__END__
- def fact(n)
- if(n > 1)
- n * fact(n-1)
- else
- 1
- end
- end
- fact(300)
-__END__
-if true then
-
-elsif true
-then
- 1
-end
-
-__END__
-
-def proc(&pr)
- pr
-end
-
-def m
- a = 1
- m2{
- a
+def m enum
+ enum.map{
+ yield
}
end
-def m2
- b = 2
- proc{
- [yield, b]
+begin
+ m(1..3){
+ raise
}
- 100000.times{|x|
- "#{x}"
- }
- 3.times{
- 3.times{
- 3.times{
- }
- }
- }
- yield
+rescue => e
+ puts e.backtrace
end
-m
-
__END__
+while true
+ class C
+ break
+ end
+end
-pr = m
-x = ['a', 1,2,3,4,5,6,7,8,9,0,
- 1,2,3,4,5,6,7,8,9,0,
- 1,2,3,4,5,6,7,8,9,0,
- 1,2,3,4,5,6,7,8,9,0,
- 1,2,3,4,5,6,7,8,9,0,
- ]
- 100000.times{|i|
- "#{i}"
- }
- pr.call
__EOP__
###########################################################
Modified: trunk/vm.c
===================================================================
--- trunk/vm.c 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/vm.c 2005-07-30 12:26:02 UTC (rev 216)
@@ -63,10 +63,8 @@
static inline
VALUE th_set_env(yarv_thread_t *th, yarv_iseq_t *iseq,
VALUE magic, VALUE self, VALUE specval,
- VALUE *pc, VALUE *lfp,
+ VALUE *pc, VALUE *sp, VALUE *lfp,
int local_size, int argc, const VALUE *argv){
-
- VALUE *sp = th->cfp->sp;
VALUE *dfp;
int i;
@@ -105,7 +103,7 @@
VALUE th_set_finish_env(yarv_thread_t *th){
th_set_env(th, 0,
FRAME_MAGIC_FINISH, Qnil, 0,
- 0, 0,
+ 0, th->cfp->sp, 0,
0, 0, 0);
th->cfp->pc = &yarv_finish_insn_seq[0];
@@ -127,7 +125,7 @@
return th_set_env(th, iseq,
FRAME_MAGIC_TOP, ruby_top_self, 0,
- iseq->ISEQ_MEMBER, 0,
+ iseq->ISEQ_MEMBER, th->cfp->sp, 0,
iseq->local_size, 0, 0);
}
@@ -248,6 +246,7 @@
case YARV_METHOD_NODE:{
yarv_control_frame_t *reg_cfp;
int i;
+ const int flag = 0;
th_set_finish_env(th);
reg_cfp = th->cfp;
@@ -265,7 +264,7 @@
struct cmethod_info cmi = {0, id, klass};
th_set_env(th, (yarv_iseq_t *)&cmi,
FRAME_MAGIC_CFUNC, recv, (VALUE)blockptr,
- 0, 0,
+ 0, reg_cfp->sp, 0,
0, 0, 0);
val = call_cfunc(body->nd_cfnc, recv, body->nd_argc, argc, argv);
@@ -347,7 +346,8 @@
th_set_env(th, 0,
FRAME_MAGIC_IFUNC, block->self, (VALUE)block->dfp,
- 0, block->lfp, 0, 0, 0);
+ 0, th->cfp->sp, block->lfp,
+ 0, 0, 0);
val = (*ifunc->nd_cfnc)(arg, ifunc->nd_tval, Qnil);
@@ -369,7 +369,7 @@
th_set_finish_env(th);
th_set_env(th, block->iseq, FRAME_MAGIC_BLOCK,
block->self, GC_GUARDED_PTR(block->dfp),
- block->iseq->ISEQ_MEMBER, block->lfp,
+ block->iseq->ISEQ_MEMBER, th->cfp->sp, block->lfp,
block->iseq->local_size, argc, argv);
val = th_eval_body(th);
}
@@ -398,15 +398,23 @@
}
else{
if(BUILTIN_TYPE(block->iseq) != T_NODE){
+ int local_size = block->iseq->local_size;
th_set_finish_env(th);
+
+ if(block->iseq->argc < argc){
+ argc = block->iseq->argc;
+ }
+
th_set_env(th, block->iseq, FRAME_MAGIC_BLOCK,
block->self, GC_GUARDED_PTR(block->dfp),
- block->iseq->ISEQ_MEMBER, block->lfp,
- block->iseq->local_size, argc, argv);
+ block->iseq->ISEQ_MEMBER, th->cfp->sp, block->lfp,
+ local_size, argc, argv);
data->local_size = block->iseq->local_size;
data->pc = block->iseq->ISEQ_MEMBER;
data->sp = th->cfp->sp;
+ data->argc = argc;
+
th->cfp+=2; // pop, pop
}
else{
@@ -429,7 +437,7 @@
th->cfp->pc = data->pc;
// th->cfp->sp = data->sp;
- for(i=0; i<argc; i++){
+ for(i=0; i<data->argc; i++){
th->cfp->dfp[i - data->local_size] = argv[i];
}
@@ -447,7 +455,7 @@
th_set_finish_env(th);
th_set_env(th, proc->block.iseq,
FRAME_MAGIC_PROC, proc->block.self, (VALUE)proc->block.dfp,
- proc->block.iseq->ISEQ_MEMBER, proc->block.lfp,
+ proc->block.iseq->ISEQ_MEMBER, th->cfp->sp, proc->block.lfp,
proc->block.iseq->local_size, argc, argv);
//proc_dump_raw(proc);
@@ -1007,6 +1015,31 @@
cfp = th->cfp;
epc = cfp->pc - cfp->iseq->ISEQ_MEMBER;
+ if(state == TAG_BREAK || state == TAG_RETURN){
+ static VALUE *escape_dfp;
+ escape_dfp = GET_THROWOBJ_CATCH_POINT(err);
+
+ // printf("%p, %p\n", escape_dfp, cfp->dfp);
+
+ if(cfp->dfp == escape_dfp){
+ if(state == TAG_RETURN){
+ SET_THROWOBJ_CATCH_POINT(err, (VALUE)(cfp+1)->dfp);
+ SET_THROWOBJ_STATE (err, state = TAG_BREAK);
+ /* through */
+ }
+ else{
+ /* TAG_BREAK */
+#if OPT_STACK_CACHING
+ initial = (GET_THROWOBJ_VAL(err));
+#else
+ *th->cfp->sp++ = (GET_THROWOBJ_VAL(err));
+#endif
+ ruby_errinfo = Qnil;
+ goto vm_loop_start;
+ }
+ }
+ }
+
for(i=0; i<cfp->iseq->catch_table_size; i++){
entry = &cfp->iseq->catch_table[i];
if(entry->start < epc &&
@@ -1029,7 +1062,6 @@
entry->type == CATCH_TYPE_RETRY){
VALUE *escape_dfp;
escape_dfp = GET_THROWOBJ_CATCH_POINT(err);
- // printf("[%d, %d]\n", GET_DFP() - th->stack, escape_dfp - th->stack);
if(cfp->dfp == escape_dfp){
cfp->pc = cfp->iseq->ISEQ_MEMBER + entry->cont;
@@ -1055,7 +1087,7 @@
/* push block frame */
th_set_env(th, catch_iseq,
FRAME_MAGIC_BLOCK, cfp->self, GC_GUARDED_PTR(cfp->dfp),
- catch_iseq->ISEQ_MEMBER, cfp->lfp,
+ catch_iseq->ISEQ_MEMBER, cfp->sp, cfp->lfp,
catch_iseq->local_size - 1, 0, 0);
state = 0;
@@ -1063,34 +1095,6 @@
goto vm_loop_start;
}
else{
- yarv_iseq_t *iseq;
-
- if(state == TAG_BREAK || state == TAG_RETURN){
- static VALUE *escape_dfp;
- escape_dfp = GET_THROWOBJ_CATCH_POINT(err);
-
- // printf("%p, %p\n", escape_dfp, cfp->dfp);
-
- if(cfp->dfp == escape_dfp){
- if(state == TAG_RETURN){
- SET_THROWOBJ_CATCH_POINT(err, (VALUE)(cfp+1)->dfp);
- SET_THROWOBJ_STATE (err, state = TAG_BREAK);
- /* through */
- }
- else{
- /* TAG_BREAK */
-#if OPT_STACK_CACHING
- initial = (GET_THROWOBJ_VAL(err));
-#else
- *th->cfp->sp++ = (GET_THROWOBJ_VAL(err));
-#endif
- ruby_errinfo = Qnil;
- goto vm_loop_start;
- }
- }
- }
-
- rewind_stack_point:
th->cfp++;
if(th->cfp->pc != &yarv_finish_insn_seq[0]){
goto exception_handler;
Modified: trunk/vm.h
===================================================================
--- trunk/vm.h 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/vm.h 2005-07-30 12:26:02 UTC (rev 216)
@@ -33,7 +33,7 @@
#if 0
#undef VMDEBUG
-#define VMDEBUG 10
+#define VMDEBUG 5
#endif
// #define COLLECT_USAGE_ANALYSIS
Modified: trunk/vm_macro.def
===================================================================
--- trunk/vm_macro.def 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/vm_macro.def 2005-07-30 12:26:02 UTC (rev 216)
@@ -55,7 +55,7 @@
th_set_env(th, (yarv_iseq_t *)&cmi,
FRAME_MAGIC_CFUNC, recv, (VALUE)blockptr,
- 0, 0,
+ 0, GET_SP(), 0,
0, 0, 0);
reg_cfp->sp -= num + 1;
@@ -68,7 +68,6 @@
}
MACRO macro_eval_invoke_func(niseqval, recv, klass, blockptr, num){
-
yarv_iseq_t *niseq;
VALUE *sp = GET_SP();
int opt_pc = 0, clear_local_size, i;
@@ -160,13 +159,34 @@
{
VALUE *rsp = reg_cfp->sp - num - 1;
- reg_cfp->sp = sp;
- th_set_env(th, niseq,
- FRAME_MAGIC_METHOD, recv, (VALUE)blockptr,
- niseq->ISEQ_MEMBER + opt_pc, 0,
- 0, 0, 0);
- reg_cfp->sp = rsp;
+ if(0 &&
+ (flag & VM_CALL_TAILCALL_BIT)){
+ th->cfp++;
+ th_set_env(th, niseq,
+ FRAME_MAGIC_METHOD, recv, (VALUE)blockptr,
+ niseq->ISEQ_MEMBER + opt_pc, sp, 0,
+ 0, 0, 0);
+ }
+ else if(0 &&
+ (flag & VM_CALL_TAILRECURSION_BIT) &&
+ niseq == GET_ISEQ()){
+ /* do nothing */
+ GET_CFP()->self = recv;
+ SET_LFP(sp);
+ SET_DFP(sp);
+ *sp++ = (VALUE)blockptr;
+ reg_cfp->sp = sp;
+ reg_cfp->bp = sp;
+ SET_PC(niseq->ISEQ_MEMBER + opt_pc);
+ }
+ else{
+ th_set_env(th, niseq,
+ FRAME_MAGIC_METHOD, recv, (VALUE)blockptr,
+ niseq->ISEQ_MEMBER + opt_pc, sp, 0,
+ 0, 0, 0);
+ reg_cfp->sp = rsp;
+ }
RESTORE_REGS();
}
}
Modified: trunk/yarv.h
===================================================================
--- trunk/yarv.h 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/yarv.h 2005-07-30 12:26:02 UTC (rev 216)
@@ -21,6 +21,7 @@
yarv_block_t *block;
VALUE *pc;
VALUE *sp;
+ int argc;
int local_size;
};
Modified: trunk/yarvcore.h
===================================================================
--- trunk/yarvcore.h 2005-07-29 11:18:39 UTC (rev 215)
+++ trunk/yarvcore.h 2005-07-30 12:26:02 UTC (rev 216)
@@ -79,6 +79,11 @@
char *buff;
};
+struct iseq_compile_data_ensure_node_stack{
+ NODE* ensure_node;
+ struct iseq_compile_data_ensure_node_stack *prev;
+};
+
struct iseq_compile_data{
/* GC is needed */
VALUE err_info;
@@ -91,6 +96,8 @@
VALUE current_block;
VALUE loopval_popped; /* used by NODE_BREAK */
VALUE in_ensure; /* used by NODE_RETURN */
+ VALUE ensure_node;
+ struct iseq_compile_data_ensure_node_stack *ensure_node_stack;
int cached_const;
struct iseq_compile_data_storage *storage_head;
@@ -296,6 +303,7 @@
#define VM_CALL_ARGS_BLOCKARG_BIT 0x02
/* 0x04, 0x08 */
#define VM_CALL_TAILCALL_BIT 0x10
+#define VM_CALL_TAILRECURSION_BIT 0x20
VALUE thread_invoke_proc_call(VALUE self, VALUE proc, int argc, VALUE *args);
--
ML: yarv-diff quickml.atdot.net
Info: http://www.atdot.net/~ko1/quickml