mruby-compiler: add no_return_value context flag for script optimization

when running scripts via mruby -e or file, return values are unused.
this adds a no_return_value flag to skip generating unnecessary code.

for parallel assignment like a,b = 1,2:
- before: 18 bytes, 5 registers, creates temporary array
- after: 5 bytes, 3 registers, direct register assignment, no RETURN

the flag is set only for the main program, not for libraries loaded
with -r option. eval() and mirb continue returning values correctly.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-12-21 09:16:34 +09:00
parent fb5d966a45
commit 613b03ac18
5 changed files with 3848 additions and 3895 deletions
+2
View File
@@ -33,6 +33,7 @@ typedef struct mrb_ccontext {
mrb_bool keep_lv:1;
mrb_bool no_optimize:1;
mrb_bool no_ext_ops:1;
mrb_bool no_return_value:1;
const struct RProc *upper;
size_t parser_nerr;
@@ -125,6 +126,7 @@ struct mrb_parser_state {
mrb_bool no_optimize:1;
mrb_bool capture_errors:1;
mrb_bool no_ext_ops:1;
mrb_bool no_return_value:1;
const struct RProc *upper;
struct mrb_parser_message error_buffer[10];
struct mrb_parser_message warn_buffer[10];
@@ -345,6 +345,7 @@ main(int argc, char **argv)
/* set program filename */
mrb_ccontext_filename(mrb, c, cmdline);
c->no_return_value = TRUE; /* main program doesn't need return value */
/* Load program */
if (args.mrbfile || mrb_extension_p(cmdline)) {
+16 -5
View File
@@ -2603,14 +2603,25 @@ scope_body(codegen_scope *s, node *locals, node *body, int val)
codegen_scope *scope = scope_new(s->mrb, s, locals);
/* Generate code for the body of the scope. */
codegen(scope, body, VAL);
/* Ensure the scope returns the value of its last expression. */
gen_return(scope, OP_RETURN, scope->sp-1);
codegen(scope, body, val);
/* If this is the outermost scope (e.g., top-level script), add OP_STOP. */
if (!s->iseq) { /* s->iseq would be NULL for the initial dummy scope. */
if (val) {
gen_return(scope, OP_RETURN, scope->sp-1);
}
/* skip RETURN when no_return_value; STOP will terminate VM */
genop_0(scope, OP_STOP);
}
else {
/* Ensure the scope returns the value of its last expression. */
if (val) {
gen_return(scope, OP_RETURN, scope->sp-1);
}
else {
gen_return(scope, OP_RETURN, 0); /* return nil */
}
}
/* Finalize the IREP for this scope. */
scope_finish(scope);
@@ -6120,7 +6131,7 @@ codegen_scope_node(codegen_scope *s, const node *varnode, int val)
struct mrb_ast_scope_node *scope = scope_node(varnode);
/* Pass locals and body directly to scope_body() */
scope_body(s, scope->locals, scope->body, NOVAL);
scope_body(s, scope->locals, scope->body, val);
}
static void
@@ -6937,5 +6948,5 @@ generate_code(mrb_state *mrb, parser_state *p, int val)
MRB_API struct RProc*
mrb_generate_code(mrb_state *mrb, parser_state *p)
{
return generate_code(mrb, p, VAL);
return generate_code(mrb, p, p->no_return_value ? NOVAL : VAL);
}
+1
View File
@@ -7459,6 +7459,7 @@ parser_init_cxt(parser_state *p, mrb_ccontext *cxt)
p->capture_errors = cxt->capture_errors;
p->no_optimize = cxt->no_optimize;
p->no_ext_ops = cxt->no_ext_ops;
p->no_return_value = cxt->no_return_value;
p->upper = cxt->upper;
if (cxt->partial_hook) {
p->cxt = cxt;
File diff suppressed because it is too large Load Diff