mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
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:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
+1688
-1713
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user