mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* vm_core.h: change iseq parameter data structure.
https://bugs.ruby-lang.org/issues/10440#change-49694 * change terminology `arg' to `param'. * move rb_iseq_t::arg_* to rb_iseq_t::param. * move rb_iseq_t::arg_size to rb_iseq_t::param::size. * move rb_iseq_t::argc to rb_iseq_t::param::lead_num. * move rb_iseq_t::arg_opts to rb_iseq_t::param::opt_num. * move rb_iseq_t::arg_rest to rb_iseq_t::param::rest_start. * move rb_iseq_t::arg_post_num to rb_iseq_t::param::post_num. * move rb_iseq_t::arg_post_start to rb_iseq_t::param::post_start. * move rb_iseq_t::arg_block to rb_iseq_t::param::block_start. * move rb_iseq_t::arg_keyword* to rb_iseq_t::param::keyword. rb_iseq_t::param::keyword is allocated only when keyword parameters are available. * introduce rb_iseq_t::param::flags to represent parameter availability. For example, rb_iseq_t::param:🎏:has_kw represents that this iseq has keyword parameters and rb_iseq_t::param::keyword is allocated. We don't need to compare with -1 to check availability. * remove rb_iseq_t::arg_simple. * compile.c: catch up this change. * iseq.c: ditto. * proc.c: ditto. * vm.c, vm_args.c, vm_dump.c, vm_insnhelper.c: ditto. * iseq.c (iseq_data_to_ary): support keyword argument. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48242 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									5d1f152fa3
								
							
						
					
					
						commit
						831e33c780
					
				
					 9 changed files with 386 additions and 353 deletions
				
			
		
							
								
								
									
										36
									
								
								ChangeLog
									
										
									
									
									
								
							
							
						
						
									
										36
									
								
								ChangeLog
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,4 +1,38 @@
 | 
			
		|||
Mon Nov  3 03:39:04 2014  Koichi Sasada  <ko1@atdot.net>
 | 
			
		||||
Mon Nov  3 07:49:34 2014  Koichi Sasada  <ko1@atdot.net>
 | 
			
		||||
 | 
			
		||||
	* vm_core.h: change iseq parameter data structure.
 | 
			
		||||
	  https://bugs.ruby-lang.org/issues/10440#change-49694
 | 
			
		||||
 | 
			
		||||
	  * change terminology `arg' to `param'.
 | 
			
		||||
	  * move rb_iseq_t::arg_* to rb_iseq_t::param.
 | 
			
		||||
	  * move rb_iseq_t::arg_size to rb_iseq_t::param::size.
 | 
			
		||||
	  * move rb_iseq_t::argc to rb_iseq_t::param::lead_num.
 | 
			
		||||
	  * move rb_iseq_t::arg_opts to rb_iseq_t::param::opt_num.
 | 
			
		||||
	  * move rb_iseq_t::arg_rest to rb_iseq_t::param::rest_start.
 | 
			
		||||
	  * move rb_iseq_t::arg_post_num to rb_iseq_t::param::post_num.
 | 
			
		||||
	  * move rb_iseq_t::arg_post_start to rb_iseq_t::param::post_start.
 | 
			
		||||
	  * move rb_iseq_t::arg_block to rb_iseq_t::param::block_start.
 | 
			
		||||
	  * move rb_iseq_t::arg_keyword* to rb_iseq_t::param::keyword.
 | 
			
		||||
	    rb_iseq_t::param::keyword is allocated only when keyword
 | 
			
		||||
	    parameters are available.
 | 
			
		||||
	  * introduce rb_iseq_t::param::flags to represent parameter
 | 
			
		||||
	    availability. For example, rb_iseq_t::param::flags::has_kw
 | 
			
		||||
	    represents that this iseq has keyword parameters and
 | 
			
		||||
	    rb_iseq_t::param::keyword is allocated.
 | 
			
		||||
	    We don't need to compare with -1 to check availability.
 | 
			
		||||
	  * remove rb_iseq_t::arg_simple.
 | 
			
		||||
 | 
			
		||||
	* compile.c: catch up this change.
 | 
			
		||||
 | 
			
		||||
	* iseq.c: ditto.
 | 
			
		||||
 | 
			
		||||
	* proc.c: ditto.
 | 
			
		||||
 | 
			
		||||
	* vm.c, vm_args.c, vm_dump.c, vm_insnhelper.c: ditto.
 | 
			
		||||
 | 
			
		||||
	* iseq.c (iseq_data_to_ary): support keyword argument.
 | 
			
		||||
 | 
			
		||||
xMon Nov  3 03:39:04 2014  Koichi Sasada  <ko1@atdot.net>
 | 
			
		||||
 | 
			
		||||
	* test/ruby/test_method.rb: r48239 makes this test green.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										329
									
								
								compile.c
									
										
									
									
									
								
							
							
						
						
									
										329
									
								
								compile.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1076,8 +1076,9 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	iseq->argc = (int)args->pre_args_num;
 | 
			
		||||
	debugs("  - argc: %d\n", iseq->argc);
 | 
			
		||||
	iseq->param.lead_num = (int)args->pre_args_num;
 | 
			
		||||
	if (iseq->param.lead_num > 0) iseq->param.flags.has_lead = TRUE;
 | 
			
		||||
	debugs("  - argc: %d\n", iseq->param.lead_num);
 | 
			
		||||
 | 
			
		||||
	rest_id = args->rest_arg;
 | 
			
		||||
	if (rest_id == 1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1087,8 +1088,9 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
 | 
			
		|||
	block_id = args->block_arg;
 | 
			
		||||
 | 
			
		||||
	if (args->first_post_arg) {
 | 
			
		||||
	    iseq->arg_post_start = get_dyna_var_idx_at_raw(iseq, args->first_post_arg);
 | 
			
		||||
	    iseq->arg_post_num = args->post_args_num;
 | 
			
		||||
	    iseq->param.post_start = get_dyna_var_idx_at_raw(iseq, args->first_post_arg);
 | 
			
		||||
	    iseq->param.post_num = args->post_args_num;
 | 
			
		||||
	    iseq->param.flags.has_post = TRUE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (args->opt_args) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1112,16 +1114,15 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
 | 
			
		|||
	    ADD_LABEL(optargs, label);
 | 
			
		||||
	    i += 1;
 | 
			
		||||
 | 
			
		||||
	    iseq->arg_opts = i;
 | 
			
		||||
	    iseq->arg_opt_table = ALLOC_N(VALUE, i);
 | 
			
		||||
	    MEMCPY(iseq->arg_opt_table, RARRAY_CONST_PTR(labels), VALUE, i);
 | 
			
		||||
	    iseq->param.opt_num = i;
 | 
			
		||||
	    iseq->param.opt_table = ALLOC_N(VALUE, i);
 | 
			
		||||
	    MEMCPY(iseq->param.opt_table, RARRAY_CONST_PTR(labels), VALUE, i);
 | 
			
		||||
	    for (j = 0; j < i; j++) {
 | 
			
		||||
		iseq->arg_opt_table[j] &= ~1;
 | 
			
		||||
		iseq->param.opt_table[j] &= ~1;
 | 
			
		||||
	    }
 | 
			
		||||
	    rb_ary_clear(labels);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    iseq->arg_opts = 0;
 | 
			
		||||
 | 
			
		||||
	    iseq->param.flags.has_opt = TRUE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (args->kw_args) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1130,7 +1131,9 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
 | 
			
		|||
	    const VALUE complex_mark = rb_str_tmp_new(0);
 | 
			
		||||
	    int kw = 0, rkw = 0, di = 0, i;
 | 
			
		||||
 | 
			
		||||
	    iseq->arg_keyword_bits = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid);
 | 
			
		||||
	    iseq->param.flags.has_kw = TRUE;
 | 
			
		||||
	    iseq->param.keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
 | 
			
		||||
	    iseq->param.keyword->bits_start = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid);
 | 
			
		||||
 | 
			
		||||
	    while (node) {
 | 
			
		||||
		NODE *val_node = node->nd_body->nd_value;
 | 
			
		||||
| 
						 | 
				
			
			@ -1152,7 +1155,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
 | 
			
		|||
			dv = complex_mark;
 | 
			
		||||
		    }
 | 
			
		||||
 | 
			
		||||
		    iseq->arg_keyword_num = ++di;
 | 
			
		||||
		    iseq->param.keyword->num = ++di;
 | 
			
		||||
		    rb_ary_push(default_values, dv);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1160,25 +1163,26 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
 | 
			
		|||
		node = node->nd_next;
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    iseq->arg_keyword_num = kw;
 | 
			
		||||
	    iseq->arg_keyword_rest = args->kw_rest_arg->nd_cflag != 0 ? get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_cflag) : -1;
 | 
			
		||||
	    iseq->arg_keyword_required = rkw;
 | 
			
		||||
	    iseq->arg_keyword_table = &iseq->local_table[iseq->arg_keyword_bits - iseq->arg_keyword_num];
 | 
			
		||||
	    iseq->arg_keyword_default_values = ALLOC_N(VALUE, RARRAY_LEN(default_values));
 | 
			
		||||
	    iseq->param.keyword->num = kw;
 | 
			
		||||
 | 
			
		||||
	    if (args->kw_rest_arg->nd_cflag != 0) {
 | 
			
		||||
		iseq->param.keyword->rest_start =  get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_cflag);
 | 
			
		||||
		iseq->param.flags.has_kwrest = TRUE;
 | 
			
		||||
	    }
 | 
			
		||||
	    iseq->param.keyword->required_num = rkw;
 | 
			
		||||
	    iseq->param.keyword->table = &iseq->local_table[iseq->param.keyword->bits_start - iseq->param.keyword->num];
 | 
			
		||||
	    iseq->param.keyword->default_values = ALLOC_N(VALUE, RARRAY_LEN(default_values));
 | 
			
		||||
 | 
			
		||||
	    for (i = 0; i < RARRAY_LEN(default_values); i++) {
 | 
			
		||||
		VALUE dv = RARRAY_AREF(default_values, i);
 | 
			
		||||
		if (dv == complex_mark) dv = Qundef;
 | 
			
		||||
		iseq->arg_keyword_default_values[i] = dv;
 | 
			
		||||
		iseq->param.keyword->default_values[i] = dv;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
	else if (args->kw_rest_arg) {
 | 
			
		||||
	    iseq->arg_keyword_bits = -1;
 | 
			
		||||
	    iseq->arg_keyword_rest = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    iseq->arg_keyword_bits = -1;
 | 
			
		||||
	    iseq->arg_keyword_rest = -1;
 | 
			
		||||
	    iseq->param.flags.has_kwrest = TRUE;
 | 
			
		||||
	    iseq->param.keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
 | 
			
		||||
	    iseq->param.keyword->rest_start = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (args->pre_init) { /* m_init */
 | 
			
		||||
| 
						 | 
				
			
			@ -1189,76 +1193,67 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (rest_id) {
 | 
			
		||||
	    iseq->arg_rest = get_dyna_var_idx_at_raw(iseq, rest_id);
 | 
			
		||||
	    iseq->param.rest_start = get_dyna_var_idx_at_raw(iseq, rest_id);
 | 
			
		||||
	    iseq->param.flags.has_rest = TRUE;
 | 
			
		||||
	    assert(iseq->param.rest_start != -1);
 | 
			
		||||
 | 
			
		||||
	    if (iseq->arg_rest == -1) {
 | 
			
		||||
		rb_bug("arg_rest: -1");
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    if (iseq->arg_post_start == 0) {
 | 
			
		||||
		iseq->arg_post_start = iseq->arg_rest + 1;
 | 
			
		||||
	    if (iseq->param.post_start == 0) { /* TODO: why that? */
 | 
			
		||||
		iseq->param.post_start = iseq->param.rest_start + 1;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (block_id) {
 | 
			
		||||
	    iseq->arg_block = get_dyna_var_idx_at_raw(iseq, block_id);
 | 
			
		||||
	    iseq->param.block_start = get_dyna_var_idx_at_raw(iseq, block_id);
 | 
			
		||||
	    iseq->param.flags.has_block = TRUE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (iseq->arg_opts != 0 ||
 | 
			
		||||
	    iseq->arg_post_num != 0 ||
 | 
			
		||||
	    iseq->arg_rest != -1 ||
 | 
			
		||||
	    iseq->arg_block != -1 ||
 | 
			
		||||
	    iseq->arg_keyword_bits != -1 ||
 | 
			
		||||
	    iseq->arg_keyword_rest != -1) {
 | 
			
		||||
	    iseq->arg_simple = 0;
 | 
			
		||||
	if (iseq->param.flags.has_opt ||
 | 
			
		||||
	    iseq->param.flags.has_post ||
 | 
			
		||||
	    iseq->param.flags.has_rest ||
 | 
			
		||||
	    iseq->param.flags.has_block ||
 | 
			
		||||
	    iseq->param.flags.has_kw ||
 | 
			
		||||
	    iseq->param.flags.has_kwrest) {
 | 
			
		||||
 | 
			
		||||
	    /* set arg_size: size of arguments */
 | 
			
		||||
	    if (iseq->arg_block != -1) {
 | 
			
		||||
		iseq->arg_size = iseq->arg_block + 1;
 | 
			
		||||
	    if (iseq->param.flags.has_block) {
 | 
			
		||||
		iseq->param.size = iseq->param.block_start + 1;
 | 
			
		||||
	    }
 | 
			
		||||
	    else if (iseq->arg_keyword_rest != -1) {
 | 
			
		||||
		iseq->arg_size = iseq->arg_keyword_rest + 1;
 | 
			
		||||
	    else if (iseq->param.flags.has_kwrest) {
 | 
			
		||||
		iseq->param.size = iseq->param.keyword->rest_start + 1;
 | 
			
		||||
	    }
 | 
			
		||||
	    else if (iseq->arg_keyword_bits != -1) {
 | 
			
		||||
		iseq->arg_size = iseq->arg_keyword_bits + 1;
 | 
			
		||||
	    else if (iseq->param.flags.has_kw) {
 | 
			
		||||
		iseq->param.size = iseq->param.keyword->bits_start + 1;
 | 
			
		||||
	    }
 | 
			
		||||
	    else if (iseq->arg_post_num) {
 | 
			
		||||
		iseq->arg_size = iseq->arg_post_start + iseq->arg_post_num;
 | 
			
		||||
	    else if (iseq->param.flags.has_post) {
 | 
			
		||||
		iseq->param.size = iseq->param.post_start + iseq->param.post_num;
 | 
			
		||||
	    }
 | 
			
		||||
	    else if (iseq->arg_rest != -1) {
 | 
			
		||||
		iseq->arg_size = iseq->arg_rest + 1;
 | 
			
		||||
	    else if (iseq->param.flags.has_rest) {
 | 
			
		||||
		iseq->param.size = iseq->param.rest_start + 1;
 | 
			
		||||
	    }
 | 
			
		||||
	    else if (iseq->arg_opts) {
 | 
			
		||||
		iseq->arg_size = iseq->argc + iseq->arg_opts - 1;
 | 
			
		||||
	    else if (iseq->param.flags.has_opt) {
 | 
			
		||||
		iseq->param.size = iseq->param.lead_num + iseq->param.opt_num - 1;
 | 
			
		||||
	    }
 | 
			
		||||
	    else {
 | 
			
		||||
		iseq->arg_size = iseq->argc;
 | 
			
		||||
		rb_bug("unreachable");
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    iseq->arg_simple = 1;
 | 
			
		||||
	    iseq->arg_size = iseq->argc;
 | 
			
		||||
	    iseq->param.size = iseq->param.lead_num;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (iseq->type == ISEQ_TYPE_BLOCK) {
 | 
			
		||||
	    if (iseq->arg_opts == 0 &&
 | 
			
		||||
		iseq->arg_post_num == 0 &&
 | 
			
		||||
		iseq->arg_rest == -1 &&
 | 
			
		||||
		iseq->arg_keyword_bits == -1 &&
 | 
			
		||||
		iseq->arg_keyword_rest == -1) {
 | 
			
		||||
	    if (iseq->param.flags.has_opt    == FALSE &&
 | 
			
		||||
		iseq->param.flags.has_post   == FALSE &&
 | 
			
		||||
		iseq->param.flags.has_rest   == FALSE &&
 | 
			
		||||
		iseq->param.flags.has_kw     == FALSE &&
 | 
			
		||||
		iseq->param.flags.has_kwrest == FALSE) {
 | 
			
		||||
 | 
			
		||||
		/* TODO: why not check block? */
 | 
			
		||||
 | 
			
		||||
		if (iseq->argc == 1 && last_comma == 0) {
 | 
			
		||||
		if (iseq->param.lead_num == 1 && last_comma == 0) {
 | 
			
		||||
		    /* {|a|} */
 | 
			
		||||
		    iseq->arg_simple |= 0x02;
 | 
			
		||||
		    iseq->param.flags.ambiguous_param0 = TRUE;
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	iseq->arg_simple = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return COMPILE_OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1691,10 +1686,9 @@ iseq_set_optargs_table(rb_iseq_t *iseq)
 | 
			
		|||
{
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    if (iseq->arg_opts != 0) {
 | 
			
		||||
	for (i = 0; i < iseq->arg_opts; i++) {
 | 
			
		||||
	    iseq->arg_opt_table[i] =
 | 
			
		||||
		label_get_position((LABEL *)iseq->arg_opt_table[i]);
 | 
			
		||||
    if (iseq->param.flags.has_opt) {
 | 
			
		||||
	for (i = 0; i < iseq->param.opt_num; i++) {
 | 
			
		||||
	    iseq->param.opt_table[i] = label_get_position((LABEL *)iseq->param.opt_table[i]);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    return COMPILE_OK;
 | 
			
		||||
| 
						 | 
				
			
			@ -4490,95 +4484,91 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
 | 
			
		|||
	    rb_iseq_t *liseq = iseq->local_iseq;
 | 
			
		||||
	    int lvar_level = get_lvar_level(iseq);
 | 
			
		||||
 | 
			
		||||
	    argc = liseq->argc;
 | 
			
		||||
	    argc = liseq->param.lead_num;
 | 
			
		||||
 | 
			
		||||
	    /* normal arguments */
 | 
			
		||||
	    for (i = 0; i < liseq->argc; i++) {
 | 
			
		||||
	    for (i = 0; i < liseq->param.lead_num; i++) {
 | 
			
		||||
		int idx = liseq->local_size - i;
 | 
			
		||||
		ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    if (!liseq->arg_simple) {
 | 
			
		||||
		if (liseq->arg_opts) {
 | 
			
		||||
		    /* optional arguments */
 | 
			
		||||
		    int j;
 | 
			
		||||
		    for (j = 0; j < liseq->arg_opts - 1; j++) {
 | 
			
		||||
			int idx = liseq->local_size - (i + j);
 | 
			
		||||
			ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
 | 
			
		||||
		    }
 | 
			
		||||
		    i += j;
 | 
			
		||||
		    argc = i;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (liseq->arg_rest != -1) {
 | 
			
		||||
		    /* rest argument */
 | 
			
		||||
		    int idx = liseq->local_size - liseq->arg_rest;
 | 
			
		||||
	    if (liseq->param.flags.has_opt) {
 | 
			
		||||
		/* optional arguments */
 | 
			
		||||
		int j;
 | 
			
		||||
		for (j = 0; j < liseq->param.opt_num - 1; j++) {
 | 
			
		||||
		    int idx = liseq->local_size - (i + j);
 | 
			
		||||
		    ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
 | 
			
		||||
		    argc = liseq->arg_rest + 1;
 | 
			
		||||
		    flag |= VM_CALL_ARGS_SPLAT;
 | 
			
		||||
		}
 | 
			
		||||
		i += j;
 | 
			
		||||
		argc = i;
 | 
			
		||||
	    }
 | 
			
		||||
	    if (liseq->param.flags.has_rest) {
 | 
			
		||||
		/* rest argument */
 | 
			
		||||
		int idx = liseq->local_size - liseq->param.rest_start;
 | 
			
		||||
		ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
 | 
			
		||||
		argc = liseq->param.rest_start + 1;
 | 
			
		||||
		flag |= VM_CALL_ARGS_SPLAT;
 | 
			
		||||
	    }
 | 
			
		||||
	    if (liseq->param.flags.has_post) {
 | 
			
		||||
		/* post arguments */
 | 
			
		||||
		int post_len = liseq->param.post_num;
 | 
			
		||||
		int post_start = liseq->param.post_start;
 | 
			
		||||
 | 
			
		||||
		if (liseq->arg_post_num > 0) {
 | 
			
		||||
		    /* post arguments */
 | 
			
		||||
		    int post_len = liseq->arg_post_num;
 | 
			
		||||
		    int post_start = liseq->arg_post_start;
 | 
			
		||||
 | 
			
		||||
		    if (liseq->arg_rest != -1) {
 | 
			
		||||
			int j;
 | 
			
		||||
			for (j=0; j<post_len; j++) {
 | 
			
		||||
			    int idx = liseq->local_size - (post_start + j);
 | 
			
		||||
			    ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
 | 
			
		||||
			}
 | 
			
		||||
			ADD_INSN1(args, line, newarray, INT2FIX(j));
 | 
			
		||||
			ADD_INSN (args, line, concatarray);
 | 
			
		||||
			/* argc is settled at above */
 | 
			
		||||
		    }
 | 
			
		||||
		    else {
 | 
			
		||||
			int j;
 | 
			
		||||
			for (j=0; j<post_len; j++) {
 | 
			
		||||
			    int idx = liseq->local_size - (post_start + j);
 | 
			
		||||
			    ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
 | 
			
		||||
			}
 | 
			
		||||
			argc = post_len + post_start;
 | 
			
		||||
		    }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (liseq->arg_keyword_bits >= 0) { /* TODO: support keywords */
 | 
			
		||||
		    int local_size = liseq->local_size;
 | 
			
		||||
		    argc++;
 | 
			
		||||
 | 
			
		||||
		    ADD_INSN1(args, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
 | 
			
		||||
 | 
			
		||||
		    if (liseq->arg_keyword_rest > 0) {
 | 
			
		||||
			ADD_INSN2(args, line, getlocal, INT2FIX(liseq->local_size - liseq->arg_keyword_rest), INT2FIX(lvar_level));
 | 
			
		||||
			ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0));
 | 
			
		||||
		    }
 | 
			
		||||
		    else {
 | 
			
		||||
			ADD_INSN1(args, line, newhash, INT2FIX(0));
 | 
			
		||||
		    }
 | 
			
		||||
		    for (i = 0; i < liseq->arg_keyword_num; ++i) {
 | 
			
		||||
			ID id = liseq->arg_keyword_table[i];
 | 
			
		||||
			int idx = local_size - get_local_var_idx(liseq, id);
 | 
			
		||||
			ADD_INSN1(args, line, putobject, ID2SYM(id));
 | 
			
		||||
		if (liseq->param.flags.has_rest) {
 | 
			
		||||
		    int j;
 | 
			
		||||
		    for (j=0; j<post_len; j++) {
 | 
			
		||||
			int idx = liseq->local_size - (post_start + j);
 | 
			
		||||
			ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
 | 
			
		||||
		    }
 | 
			
		||||
		    ADD_SEND(args, line, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
 | 
			
		||||
		    if (liseq->arg_rest != -1) {
 | 
			
		||||
			ADD_INSN1(args, line, newarray, INT2FIX(1));
 | 
			
		||||
			ADD_INSN (args, line, concatarray);
 | 
			
		||||
			--argc;
 | 
			
		||||
		    }
 | 
			
		||||
		    ADD_INSN1(args, line, newarray, INT2FIX(j));
 | 
			
		||||
		    ADD_INSN (args, line, concatarray);
 | 
			
		||||
		    /* argc is settled at above */
 | 
			
		||||
		}
 | 
			
		||||
		else if (liseq->arg_keyword_rest >= 0) {
 | 
			
		||||
		    ADD_INSN2(args, line, getlocal, INT2FIX(liseq->local_size - liseq->arg_keyword_rest), INT2FIX(lvar_level));
 | 
			
		||||
		else {
 | 
			
		||||
		    int j;
 | 
			
		||||
		    for (j=0; j<post_len; j++) {
 | 
			
		||||
			int idx = liseq->local_size - (post_start + j);
 | 
			
		||||
			ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
 | 
			
		||||
		    }
 | 
			
		||||
		    argc = post_len + post_start;
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    if (liseq->param.flags.has_kw) { /* TODO: support keywords */
 | 
			
		||||
		int local_size = liseq->local_size;
 | 
			
		||||
		argc++;
 | 
			
		||||
 | 
			
		||||
		ADD_INSN1(args, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
 | 
			
		||||
 | 
			
		||||
		if (liseq->param.flags.has_kwrest) {
 | 
			
		||||
		    ADD_INSN2(args, line, getlocal, INT2FIX(liseq->local_size - liseq->param.keyword->rest_start), INT2FIX(lvar_level));
 | 
			
		||||
		    ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0));
 | 
			
		||||
		    if (liseq->arg_rest != -1) {
 | 
			
		||||
			ADD_INSN1(args, line, newarray, INT2FIX(1));
 | 
			
		||||
			ADD_INSN (args, line, concatarray);
 | 
			
		||||
		    }
 | 
			
		||||
		    else {
 | 
			
		||||
			argc++;
 | 
			
		||||
		    }
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
		    ADD_INSN1(args, line, newhash, INT2FIX(0));
 | 
			
		||||
		}
 | 
			
		||||
		for (i = 0; i < liseq->param.keyword->num; ++i) {
 | 
			
		||||
		    ID id = liseq->param.keyword->table[i];
 | 
			
		||||
		    int idx = local_size - get_local_var_idx(liseq, id);
 | 
			
		||||
		    ADD_INSN1(args, line, putobject, ID2SYM(id));
 | 
			
		||||
		    ADD_INSN2(args, line, getlocal, INT2FIX(idx), INT2FIX(lvar_level));
 | 
			
		||||
		}
 | 
			
		||||
		ADD_SEND(args, line, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
 | 
			
		||||
		if (liseq->param.flags.has_rest) {
 | 
			
		||||
		    ADD_INSN1(args, line, newarray, INT2FIX(1));
 | 
			
		||||
		    ADD_INSN (args, line, concatarray);
 | 
			
		||||
		    --argc;
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
	    else if (liseq->param.flags.has_kwrest) {
 | 
			
		||||
		ADD_INSN2(args, line, getlocal, INT2FIX(liseq->local_size - liseq->param.keyword->rest_start), INT2FIX(lvar_level));
 | 
			
		||||
		ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0));
 | 
			
		||||
		if (liseq->param.flags.has_rest) {
 | 
			
		||||
		    ADD_INSN1(args, line, newarray, INT2FIX(1));
 | 
			
		||||
		    ADD_INSN (args, line, concatarray);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
		    argc++;
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -5303,8 +5293,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
 | 
			
		|||
		 *   kw = default_value
 | 
			
		||||
		 * end
 | 
			
		||||
		 */
 | 
			
		||||
		int kw_bits_idx = iseq->local_size - iseq->arg_keyword_bits;
 | 
			
		||||
		int keyword_idx = iseq->arg_keyword_num;
 | 
			
		||||
		int kw_bits_idx = iseq->local_size - iseq->param.keyword->bits_start;
 | 
			
		||||
		int keyword_idx = iseq->param.keyword->num;
 | 
			
		||||
 | 
			
		||||
		ADD_INSN2(ret, line, checkkeyword, INT2FIX(kw_bits_idx), INT2FIX(keyword_idx));
 | 
			
		||||
		ADD_INSNL(ret, line, branchif, end_label);
 | 
			
		||||
| 
						 | 
				
			
			@ -5889,8 +5879,8 @@ rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
 | 
			
		|||
 | 
			
		||||
    /* args */
 | 
			
		||||
    if (FIXNUM_P(args)) {
 | 
			
		||||
	iseq->arg_size = iseq->argc = FIX2INT(args);
 | 
			
		||||
	iseq->arg_simple = 1;
 | 
			
		||||
	iseq->param.size = iseq->param.lead_num = FIX2INT(args);
 | 
			
		||||
	iseq->param.flags.has_lead = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	int i = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -5900,36 +5890,31 @@ rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
 | 
			
		|||
	VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++));
 | 
			
		||||
	VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++));
 | 
			
		||||
	VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++));
 | 
			
		||||
	VALUE arg_simple = CHECK_INTEGER(rb_ary_entry(args, i++));
 | 
			
		||||
 | 
			
		||||
	iseq->argc = FIX2INT(argc);
 | 
			
		||||
	iseq->arg_rest = FIX2INT(arg_rest);
 | 
			
		||||
	iseq->arg_post_num = FIX2INT(arg_post_num);
 | 
			
		||||
	iseq->arg_post_start = FIX2INT(arg_post_start);
 | 
			
		||||
	iseq->arg_block = FIX2INT(arg_block);
 | 
			
		||||
	iseq->arg_opts = RARRAY_LENINT(arg_opt_labels);
 | 
			
		||||
	iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, iseq->arg_opts);
 | 
			
		||||
	iseq->param.lead_num = FIX2INT(argc);
 | 
			
		||||
	iseq->param.rest_start = FIX2INT(arg_rest);
 | 
			
		||||
	iseq->param.post_num = FIX2INT(arg_post_num);
 | 
			
		||||
	iseq->param.post_start = FIX2INT(arg_post_start);
 | 
			
		||||
	iseq->param.block_start = FIX2INT(arg_block);
 | 
			
		||||
	iseq->param.opt_num = RARRAY_LENINT(arg_opt_labels);
 | 
			
		||||
	iseq->param.opt_table = (VALUE *)ALLOC_N(VALUE, iseq->param.opt_num);
 | 
			
		||||
 | 
			
		||||
	if (iseq->arg_block != -1) {
 | 
			
		||||
	    iseq->arg_size = iseq->arg_block + 1;
 | 
			
		||||
	if (iseq->param.flags.has_block) {
 | 
			
		||||
	    iseq->param.size = iseq->param.block_start + 1;
 | 
			
		||||
	}
 | 
			
		||||
	else if (iseq->arg_post_num) {
 | 
			
		||||
	    iseq->arg_size = iseq->arg_post_start + iseq->arg_post_num;
 | 
			
		||||
	else if (iseq->param.flags.has_post) {
 | 
			
		||||
	    iseq->param.size = iseq->param.post_start + iseq->param.post_num;
 | 
			
		||||
	}
 | 
			
		||||
	else if (iseq->arg_rest != -1) {
 | 
			
		||||
	    iseq->arg_size = iseq->arg_rest + 1;
 | 
			
		||||
	else if (iseq->param.flags.has_rest) {
 | 
			
		||||
	    iseq->param.size = iseq->param.rest_start + 1;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    iseq->arg_size = iseq->argc + (iseq->arg_opts ? iseq->arg_opts - 1 : 0);
 | 
			
		||||
	    iseq->param.size = iseq->param.lead_num + (iseq->param.opt_num - (iseq->param.flags.has_opt == TRUE));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<RARRAY_LEN(arg_opt_labels); i++) {
 | 
			
		||||
	    iseq->arg_opt_table[i] =
 | 
			
		||||
	      (VALUE)register_label(iseq, labels_table,
 | 
			
		||||
				    rb_ary_entry(arg_opt_labels, i));
 | 
			
		||||
	    iseq->param.opt_table[i] = (VALUE)register_label(iseq, labels_table, rb_ary_entry(arg_opt_labels, i));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iseq->arg_simple = NUM2INT(arg_simple);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* exception */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										172
									
								
								iseq.c
									
										
									
									
									
								
							
							
						
						
									
										172
									
								
								iseq.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -23,7 +23,7 @@
 | 
			
		|||
#include "insns_info.inc"
 | 
			
		||||
 | 
			
		||||
#define ISEQ_MAJOR_VERSION 2
 | 
			
		||||
#define ISEQ_MINOR_VERSION 1
 | 
			
		||||
#define ISEQ_MINOR_VERSION 2
 | 
			
		||||
 | 
			
		||||
VALUE rb_cISeq;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +87,8 @@ iseq_free(void *ptr)
 | 
			
		|||
	    }
 | 
			
		||||
	    RUBY_FREE_UNLESS_NULL(iseq->callinfo_entries);
 | 
			
		||||
	    RUBY_FREE_UNLESS_NULL(iseq->catch_table);
 | 
			
		||||
	    RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table);
 | 
			
		||||
	    RUBY_FREE_UNLESS_NULL(iseq->param.opt_table);
 | 
			
		||||
	    RUBY_FREE_UNLESS_NULL(iseq->param.keyword);
 | 
			
		||||
	    compile_data_free(iseq->compile_data);
 | 
			
		||||
	    RUBY_FREE_UNLESS_NULL(iseq->iseq);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +143,7 @@ iseq_memsize(const void *ptr)
 | 
			
		|||
	    if (iseq->catch_table) {
 | 
			
		||||
		size += iseq_catch_table_bytes(iseq->catch_table->size);
 | 
			
		||||
	    }
 | 
			
		||||
	    size += iseq->arg_opts * sizeof(VALUE);
 | 
			
		||||
	    size += iseq->param.opt_num * sizeof(VALUE);
 | 
			
		||||
	    size += iseq->is_size * sizeof(union iseq_inline_storage_entry);
 | 
			
		||||
	    size += iseq->callinfo_size * sizeof(rb_call_info_t);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -262,32 +263,19 @@ prepare_iseq_build(rb_iseq_t *iseq,
 | 
			
		|||
		   const rb_compile_option_t *option)
 | 
			
		||||
{
 | 
			
		||||
    iseq->type = type;
 | 
			
		||||
    iseq->arg_rest = -1;
 | 
			
		||||
    iseq->arg_block = -1;
 | 
			
		||||
    iseq->arg_keyword_bits = -1;
 | 
			
		||||
    iseq->arg_keyword_rest = -1;
 | 
			
		||||
    RB_OBJ_WRITE(iseq->self, &iseq->klass, 0);
 | 
			
		||||
    set_relation(iseq, parent);
 | 
			
		||||
 | 
			
		||||
    name = rb_fstring(name);
 | 
			
		||||
    path = rb_fstring(path);
 | 
			
		||||
    if (RTEST(absolute_path))
 | 
			
		||||
	absolute_path = rb_fstring(absolute_path);
 | 
			
		||||
 | 
			
		||||
    if (RTEST(absolute_path)) absolute_path = rb_fstring(absolute_path);
 | 
			
		||||
    iseq_location_setup(iseq, path, absolute_path, name, first_lineno);
 | 
			
		||||
    if (iseq != iseq->local_iseq) {
 | 
			
		||||
	RB_OBJ_WRITE(iseq->self, &iseq->location.base_label, iseq->local_iseq->location.label);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iseq->defined_method_id = 0;
 | 
			
		||||
    RB_OBJ_WRITE(iseq->self, &iseq->mark_ary, 0);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * iseq->special_block_builder = GC_GUARDED_PTR_REF(block_opt);
 | 
			
		||||
     * iseq->cached_special_block_builder = 0;
 | 
			
		||||
     * iseq->cached_special_block = 0;
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    iseq->compile_data = ZALLOC(struct iseq_compile_data);
 | 
			
		||||
    RB_OBJ_WRITE(iseq->self, &iseq->compile_data->err_info, Qnil);
 | 
			
		||||
    RB_OBJ_WRITE(iseq->self, &iseq->compile_data->mark_ary, rb_ary_tmp_new(3));
 | 
			
		||||
| 
						 | 
				
			
			@ -1056,14 +1044,8 @@ VALUE iseq_data_to_ary(rb_iseq_t *iseq);
 | 
			
		|||
 *    An array containing the names of all arguments and local variables as
 | 
			
		||||
 *    symbols.
 | 
			
		||||
 *
 | 
			
		||||
 *  [args]
 | 
			
		||||
 *    The arity if the method or block only has required arguments.
 | 
			
		||||
 *
 | 
			
		||||
 *    Otherwise an array of:
 | 
			
		||||
 *
 | 
			
		||||
 *      [required_argc, [optional_arg_labels, ...],
 | 
			
		||||
 *       splat_index, post_splat_argc, post_splat_index,
 | 
			
		||||
 *       block_index, simple]
 | 
			
		||||
 *  [params]
 | 
			
		||||
 *    An Hash object containing parameter information.
 | 
			
		||||
 *
 | 
			
		||||
 *    More info about these values can be found in +vm_core.h+.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -1075,6 +1057,8 @@ VALUE iseq_data_to_ary(rb_iseq_t *iseq);
 | 
			
		|||
 *    An array of arrays containing the instruction names and operands that
 | 
			
		||||
 *    make up the body of the instruction sequence.
 | 
			
		||||
 *
 | 
			
		||||
 *  Note that this format is MRI specific and version dependent.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
iseq_to_a(VALUE self)
 | 
			
		||||
| 
						 | 
				
			
			@ -1384,7 +1368,7 @@ catch_type(int type)
 | 
			
		|||
VALUE
 | 
			
		||||
rb_iseq_disasm(VALUE self)
 | 
			
		||||
{
 | 
			
		||||
    rb_iseq_t *iseqdat = iseq_check(self);
 | 
			
		||||
    rb_iseq_t *iseqdat = iseq_check(self); /* TODO: rename to iseq */
 | 
			
		||||
    VALUE *iseq;
 | 
			
		||||
    VALUE str = rb_str_new(0, 0);
 | 
			
		||||
    VALUE child = rb_ary_new();
 | 
			
		||||
| 
						 | 
				
			
			@ -1433,13 +1417,16 @@ rb_iseq_disasm(VALUE self)
 | 
			
		|||
    if (tbl) {
 | 
			
		||||
	rb_str_catf(str,
 | 
			
		||||
		    "local table (size: %d, argc: %d "
 | 
			
		||||
		    "[opts: %d, rest: %d, post: %d, block: %d, kw: %d@%d, kwrest: %d] s%d)\n",
 | 
			
		||||
		    iseqdat->local_size, iseqdat->argc,
 | 
			
		||||
		    iseqdat->arg_opts, iseqdat->arg_rest,
 | 
			
		||||
		    iseqdat->arg_post_num, iseqdat->arg_block,
 | 
			
		||||
		    iseqdat->arg_keyword_num, iseqdat->local_size - iseqdat->arg_keyword_bits,
 | 
			
		||||
		    iseqdat->arg_keyword_rest,
 | 
			
		||||
		    iseqdat->arg_simple);
 | 
			
		||||
		    "[opts: %d, rest: %d, post: %d, block: %d, kw: %d@%d, kwrest: %d])\n",
 | 
			
		||||
		    iseqdat->local_size,
 | 
			
		||||
		    iseqdat->param.lead_num,
 | 
			
		||||
		    iseqdat->param.opt_num - (iseqdat->param.flags.has_opt == TRUE),
 | 
			
		||||
		    iseqdat->param.flags.has_rest ? iseqdat->param.rest_start : -1,
 | 
			
		||||
		    iseqdat->param.post_num,
 | 
			
		||||
		    iseqdat->param.flags.has_block ? iseqdat->param.block_start : -1,
 | 
			
		||||
		    iseqdat->param.flags.has_kw ? iseqdat->param.keyword->num : -1,
 | 
			
		||||
		    iseqdat->param.flags.has_kw ? iseqdat->param.keyword->required_num : -1,
 | 
			
		||||
		    iseqdat->param.flags.has_kwrest ? iseqdat->param.keyword->rest_start : -1);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < iseqdat->local_table_size; i++) {
 | 
			
		||||
	    long width;
 | 
			
		||||
| 
						 | 
				
			
			@ -1447,22 +1434,21 @@ rb_iseq_disasm(VALUE self)
 | 
			
		|||
	    char argi[0x100] = "";
 | 
			
		||||
	    char opti[0x100] = "";
 | 
			
		||||
 | 
			
		||||
	    if (iseqdat->arg_opts) {
 | 
			
		||||
		int argc = iseqdat->argc;
 | 
			
		||||
		int opts = iseqdat->arg_opts;
 | 
			
		||||
	    if (iseqdat->param.flags.has_opt) {
 | 
			
		||||
		int argc = iseqdat->param.lead_num;
 | 
			
		||||
		int opts = iseqdat->param.opt_num;
 | 
			
		||||
		if (i >= argc && i < argc + opts - 1) {
 | 
			
		||||
		    snprintf(opti, sizeof(opti), "Opt=%"PRIdVALUE,
 | 
			
		||||
			     iseqdat->arg_opt_table[i - argc]);
 | 
			
		||||
			     iseqdat->param.opt_table[i - argc]);
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    snprintf(argi, sizeof(argi), "%s%s%s%s%s",	/* arg, opts, rest, post  block */
 | 
			
		||||
		     iseqdat->argc > i ? "Arg" : "",
 | 
			
		||||
		     iseqdat->param.lead_num > i ? "Arg" : "",
 | 
			
		||||
		     opti,
 | 
			
		||||
		     iseqdat->arg_rest == i ? "Rest" : "",
 | 
			
		||||
		     (iseqdat->arg_post_start <= i &&
 | 
			
		||||
		      i < iseqdat->arg_post_start + iseqdat->arg_post_num) ? "Post" : "",
 | 
			
		||||
		     iseqdat->arg_block == i ? "Block" : "");
 | 
			
		||||
		     (iseqdat->param.flags.has_rest && iseqdat->param.rest_start == i) ? "Rest" : "",
 | 
			
		||||
		     (iseqdat->param.flags.has_post && iseqdat->param.post_start <= i && i < iseqdat->param.post_start + iseqdat->param.post_num) ? "Post" : "",
 | 
			
		||||
		     (iseqdat->param.flags.has_block && iseqdat->param.block_start == i) ? "Block" : "");
 | 
			
		||||
 | 
			
		||||
	    rb_str_catf(str, "[%2d] ", iseqdat->local_size - i);
 | 
			
		||||
	    width = RSTRING_LEN(str) + 11;
 | 
			
		||||
| 
						 | 
				
			
			@ -1669,7 +1655,7 @@ iseq_data_to_ary(rb_iseq_t *iseq)
 | 
			
		|||
    VALUE val = rb_ary_new();
 | 
			
		||||
    VALUE type; /* Symbol */
 | 
			
		||||
    VALUE locals = rb_ary_new();
 | 
			
		||||
    VALUE args = rb_ary_new();
 | 
			
		||||
    VALUE params = rb_hash_new();
 | 
			
		||||
    VALUE body = rb_ary_new(); /* [[:insn1, ...], ...] */
 | 
			
		||||
    VALUE nbody;
 | 
			
		||||
    VALUE exception = rb_ary_new(); /* [[....]] */
 | 
			
		||||
| 
						 | 
				
			
			@ -1729,39 +1715,39 @@ iseq_data_to_ary(rb_iseq_t *iseq)
 | 
			
		|||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* args */
 | 
			
		||||
    /* params */
 | 
			
		||||
    {
 | 
			
		||||
	/*
 | 
			
		||||
	 * [argc,                 # argc
 | 
			
		||||
	 *  [label1, label2, ...] # opts
 | 
			
		||||
	 *  rest index,
 | 
			
		||||
	 *  post_len
 | 
			
		||||
	 *  post_start
 | 
			
		||||
	 *  block index,
 | 
			
		||||
	 *  simple,
 | 
			
		||||
         * ]
 | 
			
		||||
	 */
 | 
			
		||||
	VALUE arg_opt_labels = rb_ary_new();
 | 
			
		||||
	int j;
 | 
			
		||||
 | 
			
		||||
	for (j=0; j<iseq->arg_opts; j++) {
 | 
			
		||||
	    rb_ary_push(arg_opt_labels,
 | 
			
		||||
			register_label(labels_table, iseq->arg_opt_table[j]));
 | 
			
		||||
	for (j=0; j<iseq->param.opt_num; j++) {
 | 
			
		||||
	    rb_ary_push(arg_opt_labels, register_label(labels_table, iseq->param.opt_table[j]));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* commit */
 | 
			
		||||
	if (iseq->arg_simple == 1) {
 | 
			
		||||
	    args = INT2FIX(iseq->argc);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
	    rb_ary_push(args, INT2FIX(iseq->argc));
 | 
			
		||||
	    rb_ary_push(args, arg_opt_labels);
 | 
			
		||||
	    rb_ary_push(args, INT2FIX(iseq->arg_post_num));
 | 
			
		||||
	    rb_ary_push(args, INT2FIX(iseq->arg_post_start));
 | 
			
		||||
	    rb_ary_push(args, INT2FIX(iseq->arg_rest));
 | 
			
		||||
	    rb_ary_push(args, INT2FIX(iseq->arg_block));
 | 
			
		||||
	    rb_ary_push(args, INT2FIX(iseq->arg_simple));
 | 
			
		||||
	if (iseq->param.flags.has_lead) rb_hash_aset(params, ID2SYM(rb_intern("lead_num")), INT2FIX(iseq->param.lead_num));
 | 
			
		||||
	if (iseq->param.flags.has_opt) rb_hash_aset(params, ID2SYM(rb_intern("opt")),  arg_opt_labels);
 | 
			
		||||
	if (iseq->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_num")), INT2FIX(iseq->param.post_num));
 | 
			
		||||
	if (iseq->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_start")), INT2FIX(iseq->param.post_start));
 | 
			
		||||
	if (iseq->param.flags.has_rest) rb_hash_aset(params, ID2SYM(rb_intern("rest_start")), INT2FIX(iseq->param.rest_start));
 | 
			
		||||
	if (iseq->param.flags.has_block) rb_hash_aset(params, ID2SYM(rb_intern("block_start")), INT2FIX(iseq->param.block_start));
 | 
			
		||||
	if (iseq->param.flags.has_kw) {
 | 
			
		||||
	    VALUE keywords = rb_ary_new();
 | 
			
		||||
	    int i, j;
 | 
			
		||||
	    for (i=0; i<iseq->param.keyword->required_num; i++) {
 | 
			
		||||
		rb_ary_push(keywords, ID2SYM(iseq->param.keyword->table[i]));
 | 
			
		||||
	    }
 | 
			
		||||
	    for (j=0; i<iseq->param.keyword->num; i++, j++) {
 | 
			
		||||
		VALUE key = rb_ary_new_from_args(1, ID2SYM(iseq->param.keyword->table[i]));
 | 
			
		||||
		if (iseq->param.keyword->default_values[j] != Qundef) {
 | 
			
		||||
		    rb_ary_push(key, iseq->param.keyword->default_values[j]);
 | 
			
		||||
		}
 | 
			
		||||
		rb_ary_push(keywords, key);
 | 
			
		||||
	    }
 | 
			
		||||
	    rb_hash_aset(params, ID2SYM(rb_intern("keyword")), keywords);
 | 
			
		||||
	}
 | 
			
		||||
	if (iseq->param.flags.has_kwrest) rb_hash_aset(params, ID2SYM(rb_intern("kwrest")), INT2FIX(iseq->param.keyword->rest_start));
 | 
			
		||||
	if (iseq->param.flags.ambiguous_param0) rb_hash_aset(params, ID2SYM(rb_intern("ambiguous_param0")), Qtrue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* body */
 | 
			
		||||
| 
						 | 
				
			
			@ -1897,7 +1883,7 @@ iseq_data_to_ary(rb_iseq_t *iseq)
 | 
			
		|||
 | 
			
		||||
    st_free_table(labels_table);
 | 
			
		||||
 | 
			
		||||
    rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq->arg_size));
 | 
			
		||||
    rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq->param.size));
 | 
			
		||||
    rb_hash_aset(misc, ID2SYM(rb_intern("local_size")), INT2FIX(iseq->local_size));
 | 
			
		||||
    rb_hash_aset(misc, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq->stack_max));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1918,7 +1904,7 @@ iseq_data_to_ary(rb_iseq_t *iseq)
 | 
			
		|||
    rb_ary_push(val, iseq->location.first_lineno);
 | 
			
		||||
    rb_ary_push(val, type);
 | 
			
		||||
    rb_ary_push(val, locals);
 | 
			
		||||
    rb_ary_push(val, args);
 | 
			
		||||
    rb_ary_push(val, params);
 | 
			
		||||
    rb_ary_push(val, exception);
 | 
			
		||||
    rb_ary_push(val, body);
 | 
			
		||||
    return val;
 | 
			
		||||
| 
						 | 
				
			
			@ -1959,7 +1945,7 @@ VALUE
 | 
			
		|||
rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
 | 
			
		||||
{
 | 
			
		||||
    int i, r;
 | 
			
		||||
    VALUE a, args = rb_ary_new2(iseq->arg_size);
 | 
			
		||||
    VALUE a, args = rb_ary_new2(iseq->param.size);
 | 
			
		||||
    ID req, opt, rest, block, key, keyrest;
 | 
			
		||||
#define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
 | 
			
		||||
#define PARAM_ID(i) iseq->local_table[(i)]
 | 
			
		||||
| 
						 | 
				
			
			@ -1972,18 +1958,18 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
 | 
			
		|||
    CONST_ID(req, "req");
 | 
			
		||||
    CONST_ID(opt, "opt");
 | 
			
		||||
    if (is_proc) {
 | 
			
		||||
	for (i = 0; i < iseq->argc; i++) {
 | 
			
		||||
	for (i = 0; i < iseq->param.lead_num; i++) {
 | 
			
		||||
	    PARAM_TYPE(opt);
 | 
			
		||||
	    rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
 | 
			
		||||
	    rb_ary_push(args, a);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	for (i = 0; i < iseq->argc; i++) {
 | 
			
		||||
	for (i = 0; i < iseq->param.lead_num; i++) {
 | 
			
		||||
	    rb_ary_push(args, PARAM(i, req));
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    r = iseq->argc + iseq->arg_opts - 1;
 | 
			
		||||
    r = iseq->param.lead_num + iseq->param.opt_num - 1;
 | 
			
		||||
    for (; i < r; i++) {
 | 
			
		||||
	PARAM_TYPE(opt);
 | 
			
		||||
	if (rb_id2str(PARAM_ID(i))) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1991,52 +1977,52 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
 | 
			
		|||
	}
 | 
			
		||||
	rb_ary_push(args, a);
 | 
			
		||||
    }
 | 
			
		||||
    if (iseq->arg_rest != -1) {
 | 
			
		||||
    if (iseq->param.flags.has_rest) {
 | 
			
		||||
	CONST_ID(rest, "rest");
 | 
			
		||||
	rb_ary_push(args, PARAM(iseq->arg_rest, rest));
 | 
			
		||||
	rb_ary_push(args, PARAM(iseq->param.rest_start, rest));
 | 
			
		||||
    }
 | 
			
		||||
    r = iseq->arg_post_start + iseq->arg_post_num;
 | 
			
		||||
    r = iseq->param.post_start + iseq->param.post_num;
 | 
			
		||||
    if (is_proc) {
 | 
			
		||||
	for (i = iseq->arg_post_start; i < r; i++) {
 | 
			
		||||
	for (i = iseq->param.post_start; i < r; i++) {
 | 
			
		||||
	    PARAM_TYPE(opt);
 | 
			
		||||
	    rb_ary_push(a, rb_id2str(PARAM_ID(i)) ? ID2SYM(PARAM_ID(i)) : Qnil);
 | 
			
		||||
	    rb_ary_push(args, a);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	for (i = iseq->arg_post_start; i < r; i++) {
 | 
			
		||||
	for (i = iseq->param.post_start; i < r; i++) {
 | 
			
		||||
	    rb_ary_push(args, PARAM(i, req));
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    if (iseq->arg_keyword_bits != -1) {
 | 
			
		||||
    if (iseq->param.flags.has_kw) {
 | 
			
		||||
	i = 0;
 | 
			
		||||
	if (iseq->arg_keyword_required) {
 | 
			
		||||
	if (iseq->param.keyword->required_num > 0) {
 | 
			
		||||
	    ID keyreq;
 | 
			
		||||
	    CONST_ID(keyreq, "keyreq");
 | 
			
		||||
	    for (; i < iseq->arg_keyword_required; i++) {
 | 
			
		||||
	    for (; i < iseq->param.keyword->required_num; i++) {
 | 
			
		||||
		PARAM_TYPE(keyreq);
 | 
			
		||||
		if (rb_id2str(iseq->arg_keyword_table[i])) {
 | 
			
		||||
		    rb_ary_push(a, ID2SYM(iseq->arg_keyword_table[i]));
 | 
			
		||||
		if (rb_id2str(iseq->param.keyword->table[i])) {
 | 
			
		||||
		    rb_ary_push(a, ID2SYM(iseq->param.keyword->table[i]));
 | 
			
		||||
		}
 | 
			
		||||
		rb_ary_push(args, a);
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
	CONST_ID(key, "key");
 | 
			
		||||
	for (; i < iseq->arg_keyword_num; i++) {
 | 
			
		||||
	for (; i < iseq->param.keyword->num; i++) {
 | 
			
		||||
	    PARAM_TYPE(key);
 | 
			
		||||
	    if (rb_id2str(iseq->arg_keyword_table[i])) {
 | 
			
		||||
		rb_ary_push(a, ID2SYM(iseq->arg_keyword_table[i]));
 | 
			
		||||
	    if (rb_id2str(iseq->param.keyword->table[i])) {
 | 
			
		||||
		rb_ary_push(a, ID2SYM(iseq->param.keyword->table[i]));
 | 
			
		||||
	    }
 | 
			
		||||
	    rb_ary_push(args, a);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    if (iseq->arg_keyword_rest >= 0) {
 | 
			
		||||
    if (iseq->param.flags.has_kwrest) {
 | 
			
		||||
	CONST_ID(keyrest, "keyrest");
 | 
			
		||||
	rb_ary_push(args, PARAM(iseq->arg_keyword_rest, keyrest));
 | 
			
		||||
	rb_ary_push(args, PARAM(iseq->param.keyword->rest_start, keyrest));
 | 
			
		||||
    }
 | 
			
		||||
    if (iseq->arg_block != -1) {
 | 
			
		||||
    if (iseq->param.flags.has_block) {
 | 
			
		||||
	CONST_ID(block, "block");
 | 
			
		||||
	rb_ary_push(args, PARAM(iseq->arg_block, block));
 | 
			
		||||
	rb_ary_push(args, PARAM(iseq->param.block_start, block));
 | 
			
		||||
    }
 | 
			
		||||
    return args;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2136,8 +2122,8 @@ rb_iseq_build_for_ruby2cext(
 | 
			
		|||
	    struct iseq_catch_table_entry, iseq->catch_table->size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ALLOC_AND_COPY(iseq->arg_opt_table, arg_opt_table,
 | 
			
		||||
		   VALUE, iseq->arg_opts);
 | 
			
		||||
    ALLOC_AND_COPY(iseq->param.opt_table, arg_opt_table,
 | 
			
		||||
		   VALUE, iseq->param.opt_num);
 | 
			
		||||
 | 
			
		||||
    set_relation(iseq, 0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								proc.c
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								proc.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -735,7 +735,7 @@ proc_call(int argc, VALUE *argv, VALUE procval)
 | 
			
		|||
    GetProcPtr(procval, proc);
 | 
			
		||||
 | 
			
		||||
    iseq = proc->block.iseq;
 | 
			
		||||
    if (BUILTIN_TYPE(iseq) == T_NODE || iseq->arg_block != -1) {
 | 
			
		||||
    if (BUILTIN_TYPE(iseq) == T_NODE || iseq->param.flags.has_block) {
 | 
			
		||||
	if (rb_block_given_p()) {
 | 
			
		||||
	    rb_proc_t *passed_proc;
 | 
			
		||||
	    RB_GC_GUARD(passed_procval) = rb_block_proc();
 | 
			
		||||
| 
						 | 
				
			
			@ -847,11 +847,13 @@ proc_arity(VALUE self)
 | 
			
		|||
static inline int
 | 
			
		||||
rb_iseq_min_max_arity(const rb_iseq_t *iseq, int *max)
 | 
			
		||||
{
 | 
			
		||||
    *max = iseq->arg_rest == -1 ?
 | 
			
		||||
	iseq->argc + iseq->arg_post_num + iseq->arg_opts -
 | 
			
		||||
	(iseq->arg_opts > 0) + (iseq->arg_keyword_num > 0) + (iseq->arg_keyword_rest >= 0)
 | 
			
		||||
    *max = iseq->param.flags.has_rest == FALSE ?
 | 
			
		||||
      iseq->param.lead_num + iseq->param.post_num +
 | 
			
		||||
      iseq->param.opt_num - (iseq->param.flags.has_opt == TRUE) +
 | 
			
		||||
      (iseq->param.flags.has_kw == TRUE) +
 | 
			
		||||
      (iseq->param.flags.has_kwrest == TRUE)
 | 
			
		||||
      : UNLIMITED_ARGUMENTS;
 | 
			
		||||
    return iseq->argc + iseq->arg_post_num + (iseq->arg_keyword_required > 0);
 | 
			
		||||
    return iseq->param.lead_num + iseq->param.post_num + (iseq->param.flags.has_kw && iseq->param.keyword->required_num > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								vm.c
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								vm.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -776,7 +776,7 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
 | 
			
		|||
	VALUE ret;
 | 
			
		||||
	const rb_iseq_t *iseq = block->iseq;
 | 
			
		||||
	const rb_control_frame_t *cfp;
 | 
			
		||||
	int i, opt_pc, arg_size = iseq->arg_size;
 | 
			
		||||
	int i, opt_pc, arg_size = iseq->param.size;
 | 
			
		||||
	int type = block_proc_is_lambda(block->proc) ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK;
 | 
			
		||||
	const rb_method_entry_t *me = th->passed_bmethod_me;
 | 
			
		||||
	th->passed_bmethod_me = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										60
									
								
								vm_args.c
									
										
									
									
									
								
							
							
						
						
									
										60
									
								
								vm_args.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -381,10 +381,10 @@ static void
 | 
			
		|||
args_setup_kw_parameters(VALUE* const passed_values, const int passed_keyword_len, const ID * const passed_keywords,
 | 
			
		||||
			 const rb_iseq_t * const iseq, VALUE * const locals)
 | 
			
		||||
{
 | 
			
		||||
    const ID *acceptable_keywords = iseq->arg_keyword_table;
 | 
			
		||||
    const int req_key_num = iseq->arg_keyword_required;
 | 
			
		||||
    const int key_num = iseq->arg_keyword_num;
 | 
			
		||||
    const VALUE * const default_values = iseq->arg_keyword_default_values;
 | 
			
		||||
    const ID *acceptable_keywords = iseq->param.keyword->table;
 | 
			
		||||
    const int req_key_num = iseq->param.keyword->required_num;
 | 
			
		||||
    const int key_num = iseq->param.keyword->num;
 | 
			
		||||
    const VALUE * const default_values = iseq->param.keyword->default_values;
 | 
			
		||||
    VALUE missing = 0;
 | 
			
		||||
    int i, di, found = 0;
 | 
			
		||||
    int unspecified_bits = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -435,7 +435,7 @@ args_setup_kw_parameters(VALUE* const passed_values, const int passed_keyword_le
 | 
			
		|||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iseq->arg_keyword_rest >= 0) {
 | 
			
		||||
    if (iseq->param.flags.has_kwrest) {
 | 
			
		||||
	const int rest_hash_index = key_num + 1;
 | 
			
		||||
	locals[rest_hash_index] = make_unused_kw_hash(passed_keywords, passed_keyword_len, passed_values, FALSE);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -522,13 +522,13 @@ static int
 | 
			
		|||
setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, rb_call_info_t * const ci,
 | 
			
		||||
			 VALUE * const locals, const enum arg_setup_type arg_setup_type)
 | 
			
		||||
{
 | 
			
		||||
    const int min_argc = iseq->argc + iseq->arg_post_num;
 | 
			
		||||
    const int max_argc = (iseq->arg_rest == -1) ? min_argc + (iseq->arg_opts - (iseq->arg_opts > 0)) : UNLIMITED_ARGUMENTS;
 | 
			
		||||
    const int min_argc = iseq->param.lead_num + iseq->param.post_num;
 | 
			
		||||
    const int max_argc = (iseq->param.flags.has_rest == FALSE) ? min_argc + (iseq->param.opt_num - (iseq->param.flags.has_opt == TRUE)) : UNLIMITED_ARGUMENTS;
 | 
			
		||||
    int opt_pc = 0;
 | 
			
		||||
    int given_argc;
 | 
			
		||||
    struct args_info args_body, *args;
 | 
			
		||||
    VALUE keyword_hash = Qnil;
 | 
			
		||||
    const int msl = ci->argc + iseq->arg_size;
 | 
			
		||||
    const int msl = ci->argc + iseq->param.size;
 | 
			
		||||
 | 
			
		||||
    th->mark_stack_len = msl;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -539,7 +539,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
 | 
			
		|||
    args->argv = locals;
 | 
			
		||||
 | 
			
		||||
    if (ci->kw_arg) {
 | 
			
		||||
	if (iseq->arg_keyword_bits >= 0) {
 | 
			
		||||
	if (iseq->param.flags.has_kw) {
 | 
			
		||||
	    int kw_len = ci->kw_arg->keyword_len;
 | 
			
		||||
	    /* copy kw_argv */
 | 
			
		||||
	    args->kw_argv = ALLOCA_N(VALUE, kw_len);
 | 
			
		||||
| 
						 | 
				
			
			@ -571,16 +571,16 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
 | 
			
		|||
      case arg_setup_block:
 | 
			
		||||
	if (given_argc == 1 &&
 | 
			
		||||
	    (min_argc > 0 ||
 | 
			
		||||
	     iseq->arg_opts > 2 || iseq->arg_keyword_bits >= 0 || iseq->arg_keyword_rest >= 0) && /* TODO: can be shrink with flags */
 | 
			
		||||
	    !(iseq->arg_simple & 0x02) &&
 | 
			
		||||
	     iseq->param.opt_num > 2 || iseq->param.flags.has_kw || iseq->param.flags.has_kwrest) && /* TODO: can be shrink with flags */
 | 
			
		||||
	    !iseq->param.flags.ambiguous_param0 &&
 | 
			
		||||
	    args_check_block_arg0(args, th, msl)) {
 | 
			
		||||
	    given_argc = RARRAY_LEN(args->rest);
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
      case arg_setup_lambda:
 | 
			
		||||
	if (given_argc == 1 &&
 | 
			
		||||
	    given_argc != iseq->argc &&
 | 
			
		||||
	    !(iseq->arg_rest >= 0) &&
 | 
			
		||||
	    given_argc != iseq->param.lead_num &&
 | 
			
		||||
	    !iseq->param.flags.has_rest &&
 | 
			
		||||
	    args_check_block_arg0(args, th, msl)) {
 | 
			
		||||
	    given_argc = RARRAY_LEN(args->rest);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -605,7 +605,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if (given_argc > min_argc &&
 | 
			
		||||
	(iseq->arg_keyword_bits >= 0 || iseq->arg_keyword_rest >= 0) &&
 | 
			
		||||
	(iseq->param.flags.has_kw || iseq->param.flags.has_kwrest) &&
 | 
			
		||||
	args->kw_argv == NULL) {
 | 
			
		||||
	if (args_pop_keyword_hash(args, &keyword_hash, th, msl)) {
 | 
			
		||||
	    given_argc--;
 | 
			
		||||
| 
						 | 
				
			
			@ -623,25 +623,25 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
 | 
			
		|||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iseq->argc > 0) {
 | 
			
		||||
	args_setup_lead_parameters(args, iseq->argc, locals + 0);
 | 
			
		||||
    if (iseq->param.flags.has_lead) {
 | 
			
		||||
	args_setup_lead_parameters(args, iseq->param.lead_num, locals + 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iseq->arg_post_num > 0) {
 | 
			
		||||
	args_setup_post_parameters(args, iseq->arg_post_num, locals + iseq->arg_post_start);
 | 
			
		||||
    if (iseq->param.flags.has_post) {
 | 
			
		||||
	args_setup_post_parameters(args, iseq->param.post_num, locals + iseq->param.post_start);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iseq->arg_opts > 0) {
 | 
			
		||||
	int opt = args_setup_opt_parameters(args, iseq->arg_opts - 1, locals + iseq->argc);
 | 
			
		||||
	opt_pc = (int)iseq->arg_opt_table[opt];
 | 
			
		||||
    if (iseq->param.flags.has_opt) {
 | 
			
		||||
	int opt = args_setup_opt_parameters(args, iseq->param.opt_num - 1, locals + iseq->param.lead_num);
 | 
			
		||||
	opt_pc = (int)iseq->param.opt_table[opt];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iseq->arg_rest >= 0) {
 | 
			
		||||
	args_setup_rest_parameter(args, locals + iseq->arg_rest);
 | 
			
		||||
    if (iseq->param.flags.has_rest) {
 | 
			
		||||
	args_setup_rest_parameter(args, locals + iseq->param.rest_start);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iseq->arg_keyword_bits >= 0) {
 | 
			
		||||
	VALUE * const klocals = locals + iseq->arg_keyword_bits - iseq->arg_keyword_num;
 | 
			
		||||
    if (iseq->param.flags.has_kw) {
 | 
			
		||||
	VALUE * const klocals = locals + iseq->param.keyword->bits_start - iseq->param.keyword->num;
 | 
			
		||||
 | 
			
		||||
	if (args->kw_argv != NULL) {
 | 
			
		||||
	    args_setup_kw_parameters(args->kw_argv, args->ci->kw_arg->keyword_len, args->ci->kw_arg->keywords, iseq, klocals);
 | 
			
		||||
| 
						 | 
				
			
			@ -662,18 +662,18 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r
 | 
			
		|||
	    args_setup_kw_parameters(NULL, 0, NULL, iseq, klocals);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    else if (iseq->arg_keyword_rest >= 0) {
 | 
			
		||||
	args_setup_kw_rest_parameter(keyword_hash, locals + iseq->arg_keyword_rest);
 | 
			
		||||
    else if (iseq->param.flags.has_kwrest) {
 | 
			
		||||
	args_setup_kw_rest_parameter(keyword_hash, locals + iseq->param.keyword->rest_start);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (iseq->arg_block >= 0) {
 | 
			
		||||
	args_setup_block_parameter(th, ci, locals + iseq->arg_block);
 | 
			
		||||
    if (iseq->param.flags.has_block) {
 | 
			
		||||
	args_setup_block_parameter(th, ci, locals + iseq->param.block_start);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
    {
 | 
			
		||||
	int i;
 | 
			
		||||
	for (i=0; i<iseq->arg_size; i++) {
 | 
			
		||||
	for (i=0; i<iseq->param.size; i++) {
 | 
			
		||||
	    fprintf(stderr, "local[%d] = %p\n", i, (void *)locals[i]);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										72
									
								
								vm_core.h
									
										
									
									
									
								
							
							
						
						
									
										72
									
								
								vm_core.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -240,7 +240,7 @@ struct rb_iseq_struct {
 | 
			
		|||
    rb_call_info_t *callinfo_entries;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * argument information
 | 
			
		||||
     * parameter information
 | 
			
		||||
     *
 | 
			
		||||
     *  def m(a1, a2, ..., aM,                    # mandatory
 | 
			
		||||
     *        b1=(...), b2=(...), ..., bN=(...),  # optional
 | 
			
		||||
| 
						 | 
				
			
			@ -251,36 +251,50 @@ struct rb_iseq_struct {
 | 
			
		|||
     *        &g)                                 # block
 | 
			
		||||
     * =>
 | 
			
		||||
     *
 | 
			
		||||
     *  argc             = M                 // or  0 if no mandatory arg
 | 
			
		||||
     *  arg_opts         = N+1               // or  0 if no optional arg
 | 
			
		||||
     *  arg_rest         = M+N               // or -1 if no rest arg
 | 
			
		||||
     *  arg_opt_table    = [ (arg_opts entries) ]
 | 
			
		||||
     *  arg_post_start   = M+N+(*1)          // or 0 if no post arguments
 | 
			
		||||
     *  arg_post_num     = O                 // or 0 if no post arguments
 | 
			
		||||
     *  arg_keyword_num  = K                 // or 0 if no keyword arg
 | 
			
		||||
     *  arg_block        = M+N+(*1)+O+K      // or -1 if no block arg
 | 
			
		||||
     *  arg_keyword_bits = M+N+(*1)+O+K+(&1) // or -1 if no keyword arg/rest
 | 
			
		||||
     *  arg_simple       = 0 if not simple arguments.
 | 
			
		||||
     *                   = 1 if no opt, rest, post, block.
 | 
			
		||||
     *                   = 2 if ambiguous block parameter ({|a|}).
 | 
			
		||||
     *  arg_size         = M+N+O+(*1)+K+(&1)+(**1) argument size.
 | 
			
		||||
     *  lead_num     = M
 | 
			
		||||
     *  opt_num      = N+1
 | 
			
		||||
     *  rest_start   = M+N
 | 
			
		||||
     *  post_start   = M+N+(*1)
 | 
			
		||||
     *  post_num     = O
 | 
			
		||||
     *  keyword_num  = K
 | 
			
		||||
     *  block_start  = M+N+(*1)+O+K
 | 
			
		||||
     *  keyword_bits = M+N+(*1)+O+K+(&1)
 | 
			
		||||
     *  size         = M+N+O+(*1)+K+(&1)+(**1) // parameter size.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    int argc;
 | 
			
		||||
    int arg_simple;
 | 
			
		||||
    int arg_rest;
 | 
			
		||||
    int arg_block;
 | 
			
		||||
    int arg_opts;
 | 
			
		||||
    int arg_post_num;
 | 
			
		||||
    int arg_post_start;
 | 
			
		||||
    int arg_size;
 | 
			
		||||
    VALUE *arg_opt_table;
 | 
			
		||||
    int arg_keyword_num;
 | 
			
		||||
    int arg_keyword_bits;
 | 
			
		||||
    int arg_keyword_rest;
 | 
			
		||||
    int arg_keyword_required;
 | 
			
		||||
    ID *arg_keyword_table;
 | 
			
		||||
    VALUE *arg_keyword_default_values;
 | 
			
		||||
    struct {
 | 
			
		||||
	struct {
 | 
			
		||||
	    unsigned int has_lead   : 1;
 | 
			
		||||
	    unsigned int has_opt    : 1;
 | 
			
		||||
	    unsigned int has_rest   : 1;
 | 
			
		||||
	    unsigned int has_post   : 1;
 | 
			
		||||
	    unsigned int has_kw     : 1;
 | 
			
		||||
	    unsigned int has_kwrest : 1;
 | 
			
		||||
	    unsigned int has_block  : 1;
 | 
			
		||||
 | 
			
		||||
	    unsigned int ambiguous_param0 : 1; /* {|a|} */
 | 
			
		||||
	} flags;
 | 
			
		||||
 | 
			
		||||
	int size;
 | 
			
		||||
 | 
			
		||||
	int lead_num;
 | 
			
		||||
	int opt_num;
 | 
			
		||||
	int rest_start;
 | 
			
		||||
	int post_start;
 | 
			
		||||
	int post_num;
 | 
			
		||||
	int block_start;
 | 
			
		||||
 | 
			
		||||
	VALUE *opt_table;
 | 
			
		||||
 | 
			
		||||
	struct rb_iseq_param_keyword {
 | 
			
		||||
	    int num;
 | 
			
		||||
	    int required_num;
 | 
			
		||||
	    int bits_start;
 | 
			
		||||
	    int rest_start;
 | 
			
		||||
	    ID *table;
 | 
			
		||||
	    VALUE *default_values;
 | 
			
		||||
	} *keyword;
 | 
			
		||||
    } param;
 | 
			
		||||
 | 
			
		||||
    /* catch table */
 | 
			
		||||
    struct iseq_catch_table *catch_table;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -265,7 +265,7 @@ vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp)
 | 
			
		|||
	name = "<ifunc>";
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	argc = iseq->argc;
 | 
			
		||||
	argc = iseq->param.lead_num;
 | 
			
		||||
	local_size = iseq->local_size;
 | 
			
		||||
	name = RSTRING_PTR(iseq->location.label);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1008,19 +1008,30 @@ vm_callee_setup_block_arg_arg0_splat(rb_control_frame_t *cfp, const rb_iseq_t *i
 | 
			
		|||
    int i;
 | 
			
		||||
    long len = RARRAY_LEN(ary);
 | 
			
		||||
 | 
			
		||||
    CHECK_VM_STACK_OVERFLOW(cfp, iseq->argc);
 | 
			
		||||
    CHECK_VM_STACK_OVERFLOW(cfp, iseq->param.lead_num);
 | 
			
		||||
 | 
			
		||||
    for (i=0; i<len && i<iseq->argc; i++) {
 | 
			
		||||
    for (i=0; i<len && i<iseq->param.lead_num; i++) {
 | 
			
		||||
	argv[i] = RARRAY_AREF(ary, i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int
 | 
			
		||||
simple_iseq_p(const rb_iseq_t *iseq)
 | 
			
		||||
{
 | 
			
		||||
    return iseq->param.flags.has_opt == FALSE &&
 | 
			
		||||
           iseq->param.flags.has_rest == FALSE &&
 | 
			
		||||
	   iseq->param.flags.has_post == FALSE &&
 | 
			
		||||
	   iseq->param.flags.has_kw == FALSE &&
 | 
			
		||||
	   iseq->param.flags.has_kwrest == FALSE &&
 | 
			
		||||
	   iseq->param.flags.has_block == FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
vm_callee_setup_block_arg(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *iseq, VALUE *argv, const enum arg_setup_type arg_setup_type)
 | 
			
		||||
{
 | 
			
		||||
    if (LIKELY(iseq->arg_simple & 0x01)) {
 | 
			
		||||
    if (LIKELY(simple_iseq_p(iseq))) {
 | 
			
		||||
	rb_control_frame_t *cfp = th->cfp;
 | 
			
		||||
	VALUE arg0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1028,31 +1039,32 @@ vm_callee_setup_block_arg(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *
 | 
			
		|||
 | 
			
		||||
	if (arg_setup_type == arg_setup_block &&
 | 
			
		||||
	    ci->argc == 1 &&
 | 
			
		||||
	    iseq->argc > 0 && !(iseq->arg_simple & 0x02) &&
 | 
			
		||||
	    iseq->param.flags.has_lead &&
 | 
			
		||||
	    !iseq->param.flags.ambiguous_param0 &&
 | 
			
		||||
	    !NIL_P(arg0 = vm_callee_setup_block_arg_arg0_check(argv))) {
 | 
			
		||||
	    ci->argc = vm_callee_setup_block_arg_arg0_splat(cfp, iseq, argv, arg0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ci->argc != iseq->argc) {
 | 
			
		||||
	if (ci->argc != iseq->param.lead_num) {
 | 
			
		||||
	    if (arg_setup_type == arg_setup_block) {
 | 
			
		||||
		if (ci->argc < iseq->argc) {
 | 
			
		||||
		if (ci->argc < iseq->param.lead_num) {
 | 
			
		||||
		    int i;
 | 
			
		||||
		    CHECK_VM_STACK_OVERFLOW(cfp, iseq->argc);
 | 
			
		||||
		    for (i=ci->argc; i<iseq->argc; i++) argv[i] = Qnil;
 | 
			
		||||
		    ci->argc = iseq->argc; /* fill rest parameters */
 | 
			
		||||
		    CHECK_VM_STACK_OVERFLOW(cfp, iseq->param.lead_num);
 | 
			
		||||
		    for (i=ci->argc; i<iseq->param.lead_num; i++) argv[i] = Qnil;
 | 
			
		||||
		    ci->argc = iseq->param.lead_num; /* fill rest parameters */
 | 
			
		||||
		}
 | 
			
		||||
		else if (ci->argc > iseq->argc) {
 | 
			
		||||
		    ci->argc = iseq->argc; /* simply truncate arguments */
 | 
			
		||||
		else if (ci->argc > iseq->param.lead_num) {
 | 
			
		||||
		    ci->argc = iseq->param.lead_num; /* simply truncate arguments */
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
	    else if (arg_setup_type == arg_setup_lambda &&
 | 
			
		||||
		     ci->argc == 1 &&
 | 
			
		||||
		     !NIL_P(arg0 = vm_callee_setup_block_arg_arg0_check(argv)) &&
 | 
			
		||||
		     RARRAY_LEN(arg0) == iseq->argc) {
 | 
			
		||||
		     RARRAY_LEN(arg0) == iseq->param.lead_num) {
 | 
			
		||||
		ci->argc = vm_callee_setup_block_arg_arg0_splat(cfp, iseq, argv, arg0);
 | 
			
		||||
	    }
 | 
			
		||||
	    else {
 | 
			
		||||
		argument_error(iseq, ci->argc, iseq->argc, iseq->argc);
 | 
			
		||||
		argument_error(iseq, ci->argc, iseq->param.lead_num, iseq->param.lead_num);
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1066,13 +1078,13 @@ vm_callee_setup_block_arg(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *
 | 
			
		|||
static inline void
 | 
			
		||||
vm_callee_setup_arg(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *iseq, VALUE *argv)
 | 
			
		||||
{
 | 
			
		||||
    if (LIKELY(iseq->arg_simple & 0x01)) {
 | 
			
		||||
    if (LIKELY(simple_iseq_p(iseq))) {
 | 
			
		||||
	rb_control_frame_t *cfp = th->cfp;
 | 
			
		||||
 | 
			
		||||
	CALLER_SETUP_ARG(cfp, ci); /* splat arg */
 | 
			
		||||
 | 
			
		||||
	if (ci->argc != iseq->argc) {
 | 
			
		||||
	    argument_error(iseq, ci->argc, iseq->argc, iseq->argc);
 | 
			
		||||
	if (ci->argc != iseq->param.lead_num) {
 | 
			
		||||
	    argument_error(iseq, ci->argc, iseq->param.lead_num, iseq->param.lead_num);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ci->aux.opt_pc = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1110,10 +1122,10 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info
 | 
			
		|||
    int i, local_size;
 | 
			
		||||
    VALUE *argv = cfp->sp - ci->argc;
 | 
			
		||||
    rb_iseq_t *iseq = ci->me->def->body.iseq;
 | 
			
		||||
    VALUE *sp = argv + iseq->arg_size;
 | 
			
		||||
    VALUE *sp = argv + iseq->param.size;
 | 
			
		||||
 | 
			
		||||
    /* clear local variables (arg_size...local_size) */
 | 
			
		||||
    for (i = iseq->arg_size, local_size = iseq->local_size; i < local_size; i++) {
 | 
			
		||||
    for (i = iseq->param.size, local_size = iseq->local_size; i < local_size; i++) {
 | 
			
		||||
	*sp++ = Qnil;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1146,12 +1158,12 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in
 | 
			
		|||
    sp++;
 | 
			
		||||
 | 
			
		||||
    /* copy arguments */
 | 
			
		||||
    for (i=0; i < iseq->arg_size; i++) {
 | 
			
		||||
    for (i=0; i < iseq->param.size; i++) {
 | 
			
		||||
	*sp++ = src_argv[i];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* clear local variables */
 | 
			
		||||
    for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
 | 
			
		||||
    for (i = 0; i < iseq->local_size - iseq->param.size; i++) {
 | 
			
		||||
	*sp++ = Qnil;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2031,7 +2043,7 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci
 | 
			
		|||
 | 
			
		||||
    if (BUILTIN_TYPE(iseq) != T_NODE) {
 | 
			
		||||
	int opt_pc;
 | 
			
		||||
	const int arg_size = iseq->arg_size;
 | 
			
		||||
	const int arg_size = iseq->param.size;
 | 
			
		||||
	int is_lambda = block_proc_is_lambda(block->proc);
 | 
			
		||||
	VALUE * const rsp = GET_SP() - ci->argc;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue