mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-compiler: complete NODE_IF migration to variable-sized nodes
Remove conditional logic and consolidate NODE_IF implementation to use variable-sized nodes exclusively. This eliminates dual code paths and completes the NODE_IF migration started in previous commits. Changes: - inline new_if_var into new_if, remove p->var_nodes_enabled condition - remove new_unless function, replace calls with new_if (swap then/else) - remove codegen_if function, merge nil? optimization into gen_if_var - remove NODE_IF case from main codegen switch (always wrapped in NODE_VARIABLE) - fix nil? optimization to handle both traditional and variable-sized nodes - update gen_if_var to use direct struct field access instead of macros The nil? optimization now works with both node representations: - Traditional: NODE_TYPE(condition) == NODE_CALL (preserved) - Variable-sized: NODE_VARIABLE wrapper containing NODE_CALL struct This ensures obj.nil? patterns generate optimized OP_JMPNIL bytecode regardless of AST node representation. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3787,75 +3787,6 @@ codegen_block(codegen_scope *s, node *tree, int val)
|
||||
push();
|
||||
}
|
||||
|
||||
static void
|
||||
codegen_if(codegen_scope *s, node *tree, int val)
|
||||
{
|
||||
uint32_t pos1, pos2;
|
||||
mrb_bool nil_p = FALSE;
|
||||
node *elsepart = tree->cdr->cdr->car;
|
||||
|
||||
if (!tree->car) {
|
||||
codegen(s, elsepart, val);
|
||||
return;
|
||||
}
|
||||
if (true_always(tree->car)) {
|
||||
codegen(s, tree->cdr->car, val);
|
||||
return;
|
||||
}
|
||||
if (false_always(tree->car)) {
|
||||
codegen(s, elsepart, val);
|
||||
return;
|
||||
}
|
||||
if (node_to_int(tree->car->car) == NODE_CALL) {
|
||||
node *n = tree->car->cdr;
|
||||
mrb_sym mid = node_to_sym(n->cdr->car);
|
||||
mrb_sym sym_nil_p = MRB_SYM_Q_2(s->mrb, nil);
|
||||
if (mid == sym_nil_p && n->cdr->cdr->car == NULL) {
|
||||
nil_p = TRUE;
|
||||
codegen(s, n->car, VAL);
|
||||
}
|
||||
}
|
||||
if (!nil_p) {
|
||||
codegen(s, tree->car, VAL);
|
||||
}
|
||||
pop();
|
||||
if (val || tree->cdr->car) {
|
||||
if (nil_p) {
|
||||
pos2 = genjmp2_0(s, OP_JMPNIL, cursp(), val);
|
||||
pos1 = genjmp_0(s, OP_JMP);
|
||||
dispatch(s, pos2);
|
||||
}
|
||||
else {
|
||||
pos1 = genjmp2_0(s, OP_JMPNOT, cursp(), val);
|
||||
}
|
||||
codegen(s, tree->cdr->car, val);
|
||||
if (val) pop();
|
||||
if (elsepart || val) {
|
||||
pos2 = genjmp_0(s, OP_JMP);
|
||||
dispatch(s, pos1);
|
||||
codegen(s, elsepart, val);
|
||||
dispatch(s, pos2);
|
||||
}
|
||||
else {
|
||||
dispatch(s, pos1);
|
||||
}
|
||||
}
|
||||
else { /* empty then-part */
|
||||
if (elsepart) {
|
||||
if (nil_p) {
|
||||
pos1 = genjmp2_0(s, OP_JMPNIL, cursp(), val);
|
||||
}
|
||||
else {
|
||||
pos1 = genjmp2_0(s, OP_JMPIF, cursp(), val);
|
||||
}
|
||||
codegen(s, elsepart, val);
|
||||
dispatch(s, pos1);
|
||||
}
|
||||
else if (val && !nil_p) {
|
||||
gen_load_nil(s, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
@@ -4903,10 +4834,11 @@ static void
|
||||
gen_if_var(codegen_scope *s, node *varnode, int val)
|
||||
{
|
||||
struct mrb_ast_if_node *if_n = if_node(varnode);
|
||||
node *condition = IF_NODE_CONDITION(if_n);
|
||||
node *then_body = IF_NODE_THEN(if_n);
|
||||
node *else_body = IF_NODE_ELSE(if_n);
|
||||
node *condition = if_n->condition;
|
||||
node *then_body = if_n->then_body;
|
||||
node *else_body = if_n->else_body;
|
||||
uint32_t pos1, pos2;
|
||||
mrb_bool nil_p = FALSE;
|
||||
|
||||
if (!condition) {
|
||||
codegen(s, else_body, val);
|
||||
@@ -4921,12 +4853,42 @@ gen_if_var(codegen_scope *s, node *varnode, int val)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate condition code */
|
||||
codegen(s, condition, VAL);
|
||||
/* Check for nil? optimization - handle both traditional and variable-sized nodes */
|
||||
if (NODE_TYPE(condition) == NODE_CALL) {
|
||||
/* Traditional cons-list NODE_CALL */
|
||||
node *n = condition->cdr;
|
||||
mrb_sym mid = node_to_sym(n->cdr->car);
|
||||
mrb_sym sym_nil_p = MRB_SYM_Q_2(s->mrb, nil);
|
||||
if (mid == sym_nil_p && n->cdr->cdr->car == NULL) {
|
||||
nil_p = TRUE;
|
||||
codegen(s, n->car, VAL);
|
||||
}
|
||||
}
|
||||
else if (NODE_TYPE(condition) == NODE_VARIABLE && VAR_NODE_TYPE(condition->cdr) == NODE_CALL) {
|
||||
/* Variable-sized NODE_CALL wrapped in NODE_VARIABLE */
|
||||
struct mrb_ast_call_node *call_n = (struct mrb_ast_call_node*)condition->cdr;
|
||||
mrb_sym sym_nil_p = MRB_SYM_Q_2(s->mrb, nil);
|
||||
if (call_n->method_name == sym_nil_p && call_n->argc == 0) {
|
||||
nil_p = TRUE;
|
||||
codegen(s, call_n->receiver, VAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (!nil_p) {
|
||||
/* Generate condition code */
|
||||
codegen(s, condition, VAL);
|
||||
}
|
||||
pop();
|
||||
|
||||
if (val || then_body) {
|
||||
pos1 = genjmp2_0(s, OP_JMPNOT, cursp(), val);
|
||||
if (nil_p) {
|
||||
pos2 = genjmp2_0(s, OP_JMPNIL, cursp(), val);
|
||||
pos1 = genjmp_0(s, OP_JMP);
|
||||
dispatch(s, pos2);
|
||||
}
|
||||
else {
|
||||
pos1 = genjmp2_0(s, OP_JMPNOT, cursp(), val);
|
||||
}
|
||||
codegen(s, then_body, val);
|
||||
if (val) pop();
|
||||
if (else_body || val) {
|
||||
@@ -4941,13 +4903,17 @@ gen_if_var(codegen_scope *s, node *varnode, int val)
|
||||
}
|
||||
else { /* empty then-part */
|
||||
if (else_body) {
|
||||
pos1 = genjmp2_0(s, OP_JMPIF, cursp(), val);
|
||||
if (nil_p) {
|
||||
pos1 = genjmp2_0(s, OP_JMPNIL, cursp(), val);
|
||||
}
|
||||
else {
|
||||
pos1 = genjmp2_0(s, OP_JMPIF, cursp(), val);
|
||||
}
|
||||
codegen(s, else_body, val);
|
||||
dispatch(s, pos1);
|
||||
}
|
||||
else if (val) {
|
||||
genop_1(s, OP_LOADNIL, cursp());
|
||||
push();
|
||||
else if (val && !nil_p) {
|
||||
gen_load_nil(s, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6351,11 +6317,6 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
codegen_block(s, tree, val);
|
||||
break;
|
||||
|
||||
case NODE_IF:
|
||||
codegen_if(s, tree, val);
|
||||
break;
|
||||
|
||||
|
||||
case NODE_WHILE_MOD:
|
||||
case NODE_UNTIL_MOD:
|
||||
case NODE_WHILE:
|
||||
|
||||
@@ -598,7 +598,6 @@ new_alias(parser_state *p, mrb_sym a, mrb_sym b)
|
||||
/* Forward declarations for variable-sized AST node creation functions */
|
||||
static node* new_array_var(parser_state *p, node *a);
|
||||
static node* new_hash_var(parser_state *p, node *a);
|
||||
static node* new_if_var(parser_state *p, node *condition, node *then_body, node *else_body);
|
||||
static node* new_while_var(parser_state *p, node *condition, node *body);
|
||||
static node* new_until_var(parser_state *p, node *condition, node *body);
|
||||
static node* new_case_var(parser_state *p, node *value, node *when_list);
|
||||
@@ -613,22 +612,21 @@ static node* new_op_asgn_var(parser_state *p, node *lhs, mrb_sym op, node *rhs);
|
||||
|
||||
/* (:if cond then else) */
|
||||
static node*
|
||||
new_if(parser_state *p, node *a, node *b, node *c)
|
||||
new_if(parser_state *p, node *condition, node *then_body, node *else_body)
|
||||
{
|
||||
void_expr_error(p, a);
|
||||
// If variable-sized nodes are enabled, use the specialized creation function
|
||||
if (p->var_nodes_enabled) {
|
||||
return new_if_var(p, a, b, c);
|
||||
}
|
||||
return list4((node*)NODE_IF, a, b, c);
|
||||
}
|
||||
void_expr_error(p, condition);
|
||||
|
||||
/* (:unless cond then else) */
|
||||
static node*
|
||||
new_unless(parser_state *p, node *a, node *b, node *c)
|
||||
{
|
||||
void_expr_error(p, a);
|
||||
return list4((node*)NODE_IF, a, c, b);
|
||||
size_t total_size = sizeof(struct mrb_ast_if_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
struct mrb_ast_if_node *n;
|
||||
|
||||
n = (struct mrb_ast_if_node*)parser_alloc_var(p, total_size, class);
|
||||
init_var_header(&n->header, p, NODE_IF, class);
|
||||
n->condition = condition;
|
||||
n->then_body = then_body;
|
||||
n->else_body = else_body;
|
||||
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* (:while cond body) */
|
||||
@@ -896,23 +894,6 @@ new_hash_var(parser_state *p, node *a)
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* Variable-sized if node creation */
|
||||
static node*
|
||||
new_if_var(parser_state *p, node *condition, node *then_body, node *else_body)
|
||||
{
|
||||
size_t total_size = sizeof(struct mrb_ast_if_node);
|
||||
enum mrb_ast_size_class class = size_to_class(total_size);
|
||||
|
||||
struct mrb_ast_if_node *n = (struct mrb_ast_if_node*)parser_alloc_var(p, total_size, class);
|
||||
|
||||
init_var_header(&n->header, p, NODE_IF, class);
|
||||
n->condition = condition;
|
||||
n->then_body = then_body;
|
||||
n->else_body = else_body;
|
||||
|
||||
return cons_head((node*)NODE_VARIABLE, (node*)n);
|
||||
}
|
||||
|
||||
/* Variable-sized while node creation */
|
||||
static node*
|
||||
new_while_var(parser_state *p, node *condition, node *body)
|
||||
@@ -2823,7 +2804,7 @@ stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym
|
||||
}
|
||||
| stmt modifier_unless expr_value
|
||||
{
|
||||
$$ = new_unless(p, cond($3), $1, 0);
|
||||
$$ = new_if(p, cond($3), 0, $1);
|
||||
}
|
||||
| stmt modifier_while expr_value
|
||||
{
|
||||
@@ -3880,7 +3861,7 @@ primary : literal
|
||||
opt_else
|
||||
keyword_end
|
||||
{
|
||||
$$ = new_unless(p, cond($2), $4, $5);
|
||||
$$ = new_if(p, cond($2), $5, $4);
|
||||
SET_LINENO($$, $1);
|
||||
}
|
||||
| keyword_while {COND_PUSH(1);} expr_value do {COND_POP();}
|
||||
|
||||
+1082
-1101
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user