mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 5a647a3f5f
			
		
	
	
		5a647a3f5f
		
	
	
	
	
		
			
			* *.c: no cache in init functions. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17053 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			465 lines
		
	
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			465 lines
		
	
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**********************************************************************
 | |
| 
 | |
|   blockinlining.c -
 | |
| 
 | |
|   $Author$
 | |
| 
 | |
|   Copyright (C) 2004-2007 Koichi Sasada
 | |
| 
 | |
| **********************************************************************/
 | |
| 
 | |
| #include "ruby/ruby.h"
 | |
| #include "ruby/node.h"
 | |
| #include "vm_core.h"
 | |
| 
 | |
| static VALUE
 | |
| iseq_special_block(rb_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 = rb_iseq_new_with_bopt(iseq->node, iseq->name, iseq->filename,
 | |
| 				      parent, iseq->type,
 | |
| 				      GC_GUARDED_PTR(builder));
 | |
|     if (0) {
 | |
| 	printf("%s\n", RSTRING_PTR(ruby_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", ruby_node_name(nd_type(lnode)));
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static NODE *
 | |
| build_Integer_times_node(rb_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;
 | |
|     CONST_ID(_self, "#_self");
 | |
|     if (iseq->argc == 0) {
 | |
| 	ID e;
 | |
| 	CONST_ID(e, "#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;
 | |
| 	ID e = SYM2ID(rb_ary_entry(param_vars, 0));
 | |
| 	NODE *assign;
 | |
| 
 | |
| 	CONST_ID(_e, "#_e");
 | |
| 	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
 | |
| invoke_Integer_times_special_block(VALUE num)
 | |
| {
 | |
|     rb_thread_t *th = GET_THREAD();
 | |
|     rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
 | |
| 
 | |
|     if (orig_block && BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
 | |
| 	VALUE tsiseqval = iseq_special_block(orig_block->iseq,
 | |
| 					     build_Integer_times_node);
 | |
| 	rb_iseq_t *tsiseq;
 | |
| 	VALUE argv[2], val;
 | |
| 
 | |
| 	if (tsiseqval) {
 | |
| 	    rb_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 = rb_yield_values(2, argv);
 | |
| 	    if (val == Qundef) {
 | |
| 		return num;
 | |
| 	    }
 | |
| 	    else {
 | |
| 		return val;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     return Qundef;
 | |
| }
 | |
| 
 | |
| static NODE *
 | |
| build_Range_each_node(rb_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;
 | |
|     CONST_ID(_last, "#_last");
 | |
|     if (iseq->argc == 0) {
 | |
| 	ID e;
 | |
| 	CONST_ID(e, "#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;
 | |
| 	ID e = SYM2ID(rb_ary_entry(param_vars, 0));
 | |
| 	NODE *assign;
 | |
| 
 | |
| 	CONST_ID(_e, "#_e");
 | |
| 	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(rb_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(rb_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
 | |
| invoke_Range_each_special_block(VALUE range,
 | |
| 				VALUE beg, VALUE end, int excl)
 | |
| {
 | |
|     rb_thread_t *th = GET_THREAD();
 | |
|     rb_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 = iseq_special_block(orig_block->iseq, builder);
 | |
| 	rb_iseq_t *tsiseq;
 | |
| 	VALUE argv[2];
 | |
| 
 | |
| 	if (tsiseqval) {
 | |
| 	    VALUE val;
 | |
| 	    rb_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 = rb_yield_values(2, argv);
 | |
| 	    if (val == Qundef) {
 | |
| 		return range;
 | |
| 	    }
 | |
| 	    else {
 | |
| 		return val;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     return Qundef;
 | |
| }
 | |
| 
 | |
| 
 | |
| static NODE *
 | |
| build_Array_each_node(rb_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, _i;
 | |
| 
 | |
|     CONST_ID(_self, "#_self");
 | |
|     CONST_ID(_i, "#_i");
 | |
|     if (iseq->argc == 0) {
 | |
| 	ID _e;
 | |
| 	CONST_ID(_e, "#_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
 | |
| invoke_Array_each_special_block(VALUE ary)
 | |
| {
 | |
|     rb_thread_t *th = GET_THREAD();
 | |
|     rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
 | |
| 
 | |
|     if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
 | |
| 	VALUE tsiseqval = iseq_special_block(orig_block->iseq,
 | |
| 					     build_Array_each_node);
 | |
| 	rb_iseq_t *tsiseq;
 | |
| 	VALUE argv[2];
 | |
| 
 | |
| 	if (tsiseqval) {
 | |
| 	    VALUE val;
 | |
| 	    rb_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 = rb_yield_values(2, argv);
 | |
| 	    if (val == Qundef) {
 | |
| 		return ary;
 | |
| 	    }
 | |
| 	    else {
 | |
| 		return val;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     return Qundef;
 | |
| }
 |