mruby-compier: keep stack reference to passed block after modifying &b

To mark `MRB_PROC_ORPHAN` we need to keep track of passed block, even
after the assignment to the block argument. And `yield` should use the
original block; #5786, #5791, #6369
This commit is contained in:
Yukihiro "Matz" Matsumoto
2024-09-26 02:48:16 +09:00
parent d6fa7772a0
commit 9c5812a463
4 changed files with 23 additions and 19 deletions
+12 -4
View File
@@ -1376,7 +1376,7 @@ lambda_body(codegen_scope *s, node *tree, int blk)
pa = node_len(tree->car->cdr->cdr->cdr->car);
pargs = tree->car->cdr->cdr->cdr->car;
/* keyword arguments */
ka = tail? node_len(tail->cdr->car) : 0;
ka = tail ? node_len(tail->cdr->car) : 0;
/* keyword dictionary? */
kd = tail && tail->cdr->cdr->car? 1 : 0;
/* block argument? */
@@ -1388,16 +1388,16 @@ lambda_body(codegen_scope *s, node *tree, int blk)
/* (23bits = 5:5:1:5:5:1:1) */
a = MRB_ARGS_REQ(ma)
| MRB_ARGS_OPT(oa)
| (ra? MRB_ARGS_REST() : 0)
| (ra ? MRB_ARGS_REST() : 0)
| MRB_ARGS_POST(pa)
| MRB_ARGS_KEY(ka, kd)
| (ba? MRB_ARGS_BLOCK() : 0);
| (ba ? MRB_ARGS_BLOCK() : 0);
genop_W(s, OP_ENTER, a);
/* (12bits = 5:1:5:1) */
s->ainfo = (((ma+oa) & 0x3f) << 7)
| ((ra & 0x1) << 6)
| ((pa & 0x1f) << 1)
| ((ka | kd) ? 1 : 0);
| (ka || kd);
/* generate jump table for optional arguments initializer */
pos = new_label(s);
for (i=0; i<oa; i++) {
@@ -1475,6 +1475,14 @@ lambda_body(codegen_scope *s, node *tree, int blk)
if (tail->cdr->car && !kwrest) {
genop_0(s, OP_KEYEND);
}
if (ba) {
mrb_sym bparam = nsym(tail->cdr->cdr->cdr->car);
pos = ma+oa+ra+pa+(ka||kd);
if (bparam) {
int idx = lv_idx(s, bparam);
genop_2(s, OP_MOVE, idx, pos+1);
}
}
}
/* argument destructuring */
+7 -10
View File
@@ -334,12 +334,8 @@ local_add(parser_state *p, mrb_sym sym)
}
}
static void
local_add_blk(parser_state *p, mrb_sym blk)
{
/* allocate register for block */
local_add_f(p, blk ? blk : 0);
}
/* allocate register for block */
#define local_add_blk(p) local_add_f(p, 0)
static void
local_add_kw(parser_state *p, mrb_sym kwd)
@@ -865,7 +861,8 @@ new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk)
local_add_kw(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : 0);
}
local_add_blk(p, blk);
local_add_blk(p);
if (blk) local_add_f(p, blk);
/* allocate register for keywords arguments */
/* order is for Proc#parameters */
@@ -3096,7 +3093,7 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail
opt_block_param : none
{
local_add_blk(p, 0);
local_add_blk(p);
$$ = 0;
}
| block_param_def
@@ -3106,13 +3103,13 @@ opt_block_param : none
}
;
block_param_def : '|' {local_add_blk(p, 0);} opt_bv_decl '|'
block_param_def : '|' {local_add_blk(p);} opt_bv_decl '|'
{
$$ = 0;
}
| tOROP
{
local_add_blk(p, 0);
local_add_blk(p);
$$ = 0;
}
| '|' block_param opt_bv_decl '|'
+3
View File
@@ -152,6 +152,9 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i]));
}
if (p->name == MRB_SYM(block)) {
if (irep->lv[i+1]) {
mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i+1]));
}
block = a; continue;
}
if (p->name == MRB_SYM(keyrest)) {
+1 -5
View File
@@ -33,11 +33,6 @@ assert('Proc#inspect') do
assert_match "#<Proc:0x* #{file}:#{line}>", ins
end
assert('Proc#parameters') do
parameters = Proc.new{|x,y=42,*other|}.parameters
assert_equal [[:opt, :x], [:opt, :y], [:rest, :other]], parameters
end
assert('Proc#lambda?') do
assert_true lambda{}.lambda?
assert_true !Proc.new{}.lambda?
@@ -80,6 +75,7 @@ assert('Proc#parameters') do
assert_equal([[:req, :a]], ->(a){}.parameters)
assert_equal([[:rest, :*]], lambda { |*| }.parameters)
assert_equal([[:rest, :a]], Proc.new {|*a|}.parameters)
assert_equal([[:opt, :x], [:opt, :y], [:rest, :other]], Proc.new{|x,y=42,*other|}.parameters)
assert_equal([[:opt, :a], [:opt, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:opt, :f], [:opt, :g], [:block, :h]], Proc.new {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters)
assert_equal([[:req, :a], [:req, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:req, :f], [:req, :g], [:block, :h]], lambda {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters)
end