mruby-compiler: complete NODE_RESCUE and NODE_ENSURE migration to variable-sized nodes exclusively

- remove conditional logic from new_rescue() and new_ensure(), always creating variable-sized nodes
- remove unused new_rescue_var() helper function
- remove traditional NODE_RESCUE and NODE_ENSURE cases from main codegen() switch
- inline codegen_rescue() logic directly into gen_rescue_var() for optimal performance
- inline codegen_ensure() logic directly into gen_ensure_var() for optimal performance
- eliminate temporary cons-like structures, using direct variable-sized node field access
- remove now-unused codegen_rescue() and codegen_ensure() functions

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-09-08 21:05:31 +09:00
parent f5ce65e418
commit 7bfd1a01c8
3 changed files with 1810 additions and 1921 deletions
+109 -166
View File
@@ -2290,7 +2290,6 @@ search_upvar(codegen_scope *s, mrb_sym id, int *idx)
return -1; /* not reached */
}
/*
* Generates the bytecode for the body of a lambda or a block.
* This function is responsible for creating a new scope, handling arguments
@@ -3070,7 +3069,6 @@ gen_assignment(codegen_scope *s, node *tree, node *rhs, int sp, int val)
case NODE_NIL:
break;
default:
codegen_error(s, "unknown lhs");
break;
@@ -3268,7 +3266,6 @@ raise_error(codegen_scope *s, const char *msg)
genop_1(s, OP_ERR, idx);
}
static void
gen_retval(codegen_scope *s, node *tree)
{
@@ -3600,127 +3597,6 @@ codegen_begin(codegen_scope *s, node *tree, int val)
codegen(s, tree, val);
}
static void
codegen_rescue(codegen_scope *s, node *tree, int val)
{
int noexc;
uint32_t exend, pos1, pos2, tmp;
struct loopinfo *lp;
int catch_entry, begin, end;
if (tree->car == NULL) return;
lp = loop_push(s, LOOP_BEGIN);
lp->pc0 = new_label(s);
catch_entry = catch_handler_new(s);
begin = s->pc;
codegen(s, tree->car, VAL);
pop();
lp->type = LOOP_RESCUE;
end = s->pc;
noexc = genjmp_0(s, OP_JMP);
catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc);
tree = tree->cdr;
exend = JMPLINK_START;
pos1 = JMPLINK_START;
if (tree->car) {
node *n2 = tree->car;
int exc = cursp();
genop_1(s, OP_EXCEPT, exc);
push();
while (n2) {
node *n3 = n2->car;
node *n4 = n3->car;
dispatch(s, pos1);
pos2 = JMPLINK_START;
do {
if (n4 && n4->car && node_to_int(n4->car->car) == NODE_SPLAT) {
codegen(s, n4->car, VAL);
gen_move(s, cursp(), exc, 0);
push_n(2); pop_n(2); /* space for one arg and a block */
pop();
genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1);
}
else {
if (n4) {
codegen(s, n4->car, VAL);
}
else {
genop_2(s, OP_GETCONST, cursp(), new_sym(s, MRB_SYM_2(s->mrb, StandardError)));
push();
}
pop();
genop_2(s, OP_RESCUE, exc, cursp());
}
tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val);
pos2 = tmp;
if (n4) {
n4 = n4->cdr;
}
} while (n4);
pos1 = genjmp_0(s, OP_JMP);
dispatch_linked(s, pos2);
pop();
if (n3->cdr->car) {
gen_assignment(s, n3->cdr->car, NULL, exc, NOVAL);
}
if (n3->cdr->cdr->car) {
codegen(s, n3->cdr->cdr->car, val);
if (val) pop();
}
tmp = genjmp(s, OP_JMP, exend);
exend = tmp;
n2 = n2->cdr;
push();
}
if (pos1 != JMPLINK_START) {
dispatch(s, pos1);
genop_1(s, OP_RAISEIF, exc);
}
}
pop();
tree = tree->cdr;
dispatch(s, noexc);
if (tree->car) {
codegen(s, tree->car, val);
}
else if (val) {
push();
}
dispatch_linked(s, exend);
loop_pop(s, NOVAL);
}
static void
codegen_ensure(codegen_scope *s, node *tree, int val)
{
if (!tree->cdr || !tree->cdr->cdr ||
(node_to_int(tree->cdr->cdr->car) == NODE_STMTS &&
tree->cdr->cdr->cdr)) {
int catch_entry, begin, end, target;
int idx;
catch_entry = catch_handler_new(s);
begin = s->pc;
codegen(s, tree->car, val);
end = target = s->pc;
push();
idx = cursp();
genop_1(s, OP_EXCEPT, idx);
push();
codegen(s, tree->cdr->cdr, NOVAL);
pop();
genop_1(s, OP_RAISEIF, idx);
pop();
catch_handler_set(s, catch_entry, MRB_CATCH_ENSURE, begin, end, target);
}
else { /* empty ensure ignored */
codegen(s, tree->car, val);
}
}
static void
codegen_lambda(codegen_scope *s, node *tree, int val)
{
@@ -3741,8 +3617,6 @@ codegen_block(codegen_scope *s, node *tree, int val)
push();
}
static void
codegen_self(codegen_scope *s, node *tree, int val)
{
@@ -3939,7 +3813,6 @@ codegen_scall(codegen_scope *s, node *tree, int val)
gen_call(s, tree, val, 1);
}
static void
codegen_negate(codegen_scope *s, node *tree, int val)
{
@@ -4084,7 +3957,6 @@ codegen_cons_list_string(codegen_scope *s, node *list, int val)
return;
}
mrb_int len = node_to_int(elem->car);
if (len >= 0) {
@@ -4113,7 +3985,6 @@ codegen_cons_list_string(codegen_scope *s, node *list, int val)
elem = n->car;
if (!elem) break;
len = node_to_int(elem->car);
if (len >= 0) {
@@ -4149,7 +4020,6 @@ codegen_cons_list_string(codegen_scope *s, node *list, int val)
node *elem = n->car;
if (!elem) break;
mrb_int len = node_to_int(elem->car);
if (len < 0) {
@@ -4398,7 +4268,6 @@ codegen_sclass(codegen_scope *s, node *tree, int val)
}
}
static void
codegen_undef(codegen_scope *s, node *tree, int val)
{
@@ -4444,7 +4313,6 @@ codegen_next(codegen_scope *s, node *tree, int val)
push();
}
static void
codegen_redo(codegen_scope *s, node *tree, int val)
{
@@ -4519,7 +4387,6 @@ codegen_block_arg(codegen_scope *s, node *tree, int val)
}
}
/* Handle variable-sized node types */
static void
gen_call_var(codegen_scope *s, node *varnode, int val)
@@ -4720,7 +4587,6 @@ gen_array_var(codegen_scope *s, node *varnode, int val)
}
}
/* Phase 3 Variable Node Codegen Functions */
static void
@@ -5561,23 +5427,97 @@ gen_const_var(codegen_scope *s, node *varnode, int val)
static void
gen_rescue_var(codegen_scope *s, node *varnode, int val)
{
/* For now, completely avoid accessing the variable-sized structure */
/* and just fall back to safe codegen to prevent crashes */
struct mrb_ast_rescue_node *rescue = rescue_node(varnode);
node *body = rescue->body;
node *rescue_clauses = rescue->rescue_clauses;
node *else_clause = rescue->else_clause;
if (!varnode) {
if (val) {
genop_1(s, OP_LOADNIL, cursp());
int noexc;
uint32_t exend, pos1, pos2, tmp;
struct loopinfo *lp;
int catch_entry, begin, end;
if (body == NULL) return;
lp = loop_push(s, LOOP_BEGIN);
lp->pc0 = new_label(s);
catch_entry = catch_handler_new(s);
begin = s->pc;
codegen(s, body, VAL);
pop();
lp->type = LOOP_RESCUE;
end = s->pc;
noexc = genjmp_0(s, OP_JMP);
catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc);
exend = JMPLINK_START;
pos1 = JMPLINK_START;
if (rescue_clauses) {
node *n2 = rescue_clauses;
int exc = cursp();
genop_1(s, OP_EXCEPT, exc);
push();
while (n2) {
node *n3 = n2->car;
node *n4 = n3->car;
dispatch(s, pos1);
pos2 = JMPLINK_START;
do {
if (n4 && n4->car && node_to_int(n4->car->car) == NODE_SPLAT) {
codegen(s, n4->car, VAL);
gen_move(s, cursp(), exc, 0);
push_n(2); pop_n(2); /* space for one arg and a block */
pop();
genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1);
}
else {
if (n4) {
codegen(s, n4->car, VAL);
}
else {
genop_2(s, OP_GETCONST, cursp(), new_sym(s, MRB_SYM_2(s->mrb, StandardError)));
push();
}
pop();
genop_2(s, OP_RESCUE, exc, cursp());
}
tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val);
pos2 = tmp;
if (n4) {
n4 = n4->cdr;
}
} while (n4);
pos1 = genjmp_0(s, OP_JMP);
dispatch_linked(s, pos2);
pop();
if (n3->cdr->car) {
gen_assignment(s, n3->cdr->car, NULL, exc, NOVAL);
}
if (n3->cdr->cdr->car) {
codegen(s, n3->cdr->cdr->car, val);
if (val) pop();
}
tmp = genjmp(s, OP_JMP, exend);
exend = tmp;
n2 = n2->cdr;
push();
}
return;
if (pos1 != JMPLINK_START) {
dispatch(s, pos1);
genop_1(s, OP_RAISEIF, exc);
}
}
/* Since rescue is complex, just delegate to safe handling */
/* This may not be optimal but prevents crashes */
if (val) {
genop_1(s, OP_LOADNIL, cursp());
pop();
dispatch(s, noexc);
if (else_clause) {
codegen(s, else_clause, val);
}
else if (val) {
push();
}
dispatch_linked(s, exend);
loop_pop(s, NOVAL);
}
static void
@@ -5641,7 +5581,6 @@ gen_retry_var(codegen_scope *s, node *varnode, int val)
codegen_retry(s, NULL, val);
}
static void
gen_xstr_var(codegen_scope *s, node *varnode, int val)
{
@@ -5940,7 +5879,6 @@ gen_symbols_var(codegen_scope *s, node *varnode, int val)
gen_literal_array(s, n->args, TRUE, val);
}
static void
gen_splat_var(codegen_scope *s, node *varnode, int val)
{
@@ -5991,20 +5929,35 @@ gen_begin_var(codegen_scope *s, const node *varnode, int val)
}
static void
gen_ensure_var(codegen_scope *s, const node *varnode, int val)
gen_ensure_var(codegen_scope *s, node *varnode, int val)
{
struct mrb_ast_ensure_node *ensure = ensure_node(varnode);
// Convert variable-sized ensure to traditional structure for codegen_ensure
node *body = ensure->body;
node *ensure_body = ensure->ensure_clause;
node *ensure_clause = ensure->ensure_clause;
// Create stack-allocated traditional node structure
node ensure_node_stack;
ensure_node_stack.car = body;
ensure_node_stack.cdr = ensure_body;
if (!ensure_clause ||
(node_to_int(ensure_clause->car) == NODE_STMTS &&
ensure_clause->cdr)) {
int catch_entry, begin, end, target;
int idx;
codegen_ensure(s, &ensure_node_stack, val);
catch_entry = catch_handler_new(s);
begin = s->pc;
codegen(s, body, val);
end = target = s->pc;
push();
idx = cursp();
genop_1(s, OP_EXCEPT, idx);
push();
codegen(s, ensure_clause, NOVAL);
pop();
genop_1(s, OP_RAISEIF, idx);
pop();
catch_handler_set(s, catch_entry, MRB_CATCH_ENSURE, begin, end, target);
}
else { /* empty ensure ignored */
codegen(s, body, val);
}
}
// Group 16: Declarations and Definitions
@@ -6361,7 +6314,6 @@ codegen_variable_node(codegen_scope *s, node *varnode, int val)
gen_symbols_var(s, varnode, val);
return TRUE;
case NODE_SPLAT:
gen_splat_var(s, varnode, val);
return TRUE;
@@ -6449,14 +6401,6 @@ codegen(codegen_scope *s, node *tree, int val)
codegen_begin(s, tree, val);
break;
case NODE_RESCUE:
codegen_rescue(s, tree, val);
break;
case NODE_ENSURE:
codegen_ensure(s, tree, val);
break;
case NODE_LAMBDA:
codegen_lambda(s, tree, val);
break;
@@ -6554,7 +6498,6 @@ codegen(codegen_scope *s, node *tree, int val)
codegen_block_arg(s, tree, val);
break;
case NODE_NEGATE:
codegen_negate(s, tree, val);
break;
+13 -42
View File
@@ -50,7 +50,6 @@ static int toklen(parser_state *p);
static node* new_const_var(parser_state *p, mrb_sym symbol);
/* Forward declarations for variable-sized advanced node functions */
static node* new_rescue_var(parser_state *p, node *body, node *rescue_clauses, node *else_clause);
static node* new_block_var(parser_state *p, node *locals, node *args, node *body);
static node* new_args_tail_var(parser_state *p, node *keywords, node *kwrest, mrb_sym block);
@@ -507,14 +506,21 @@ new_begin(parser_state *p, node *body)
#define newline_node(n) (n)
/* (:rescue body rescue else) */
/* (:rescue body rescue else) - Always use variable-sized nodes */
static node*
new_rescue(parser_state *p, node *body, node *resq, node *els)
{
if (p->var_nodes_enabled) {
return new_rescue_var(p, body, resq, els);
}
return list4((node*)NODE_RESCUE, body, resq, els);
size_t total_size = sizeof(struct mrb_ast_rescue_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_rescue_node *n = (struct mrb_ast_rescue_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->hdr, p, NODE_RESCUE, class);
n->body = body;
n->rescue_clauses = resq;
n->else_clause = els;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
static node*
@@ -523,14 +529,10 @@ new_mod_rescue(parser_state *p, node *body, node *resq)
return new_rescue(p, body, list1(list3(0, 0, resq)), 0);
}
/* (:ensure body ensure) */
/* (:ensure body ensure) - Always use variable-sized nodes */
static node*
new_ensure(parser_state *p, node *a, node *b)
{
if (!p->var_nodes_enabled) {
return cons_head((node*)NODE_ENSURE, cons(a, cons(0, b)));
}
size_t total_size = sizeof(struct mrb_ast_ensure_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_ensure_node *ensure_node = (struct mrb_ast_ensure_node*)parser_alloc_var(p, total_size, class);
@@ -849,11 +851,6 @@ new_call_var(parser_state *p, node *receiver, mrb_sym method, node *args, int pa
}
#endif
/* Variable-sized array node creation */
/* Variable-sized method definition node creation */
static node*
new_def_var(parser_state *p, mrb_sym name, node *args, node *body)
@@ -920,7 +917,6 @@ new_sclass_var(parser_state *p, node *obj, node *body)
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* Variable-sized assignment node creation */
static node*
new_asgn_var(parser_state *p, node *lhs, node *rhs)
@@ -970,11 +966,7 @@ new_op_asgn_var(parser_state *p, node *lhs, mrb_sym op, node *rhs)
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
/* Variable-sized expression node creation */
/* Variable-sized simple node creation functions */
static node*
new_const_var(parser_state *p, mrb_sym symbol)
{
@@ -990,22 +982,6 @@ new_const_var(parser_state *p, mrb_sym symbol)
}
/* Variable-sized advanced node creation functions */
static node*
new_rescue_var(parser_state *p, node *body, node *rescue_clauses, node *else_clause)
{
size_t total_size = sizeof(struct mrb_ast_rescue_node);
enum mrb_ast_size_class class = size_to_class(total_size);
struct mrb_ast_rescue_node *n = (struct mrb_ast_rescue_node*)parser_alloc_var(p, total_size, class);
init_var_header(&n->hdr, p, NODE_RESCUE, class);
n->body = body;
n->rescue_clauses = rescue_clauses;
n->else_clause = else_clause;
return cons_head((node*)NODE_VARIABLE, (node*)n);
}
static node*
new_block_var(parser_state *p, node *locals, node *args, node *body)
{
@@ -2859,7 +2835,6 @@ command_rhs : command_call %prec tOP_ASGN
| command_asgn
;
expr : command_call
| expr keyword_and expr
{
@@ -2880,7 +2855,6 @@ expr : command_call
| arg
;
defn_head : keyword_def fname
{
$$ = new_def(p, $2, int_to_node(p->cmdarg_stack), local_switch(p));
@@ -4111,7 +4085,6 @@ block_param_def : '|' {local_add_blk(p);} opt_bv_decl '|'
}
;
opt_bv_decl : opt_nl
{
$$ = 0;
@@ -4466,7 +4439,6 @@ words : tWORDS_BEG tSTRING
}
;
symbol : basic_symbol
{
$$ = new_sym(p, $1);
@@ -5447,7 +5419,6 @@ skips(parser_state *p, const char *s)
return FALSE;
}
static int
newtok(parser_state *p)
{
File diff suppressed because it is too large Load Diff