diff --git a/include/mruby/proc.h b/include/mruby/proc.h index 4c3db2a62..def00628f 100644 --- a/include/mruby/proc.h +++ b/include/mruby/proc.h @@ -136,12 +136,46 @@ MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx); MRB_API mrb_value mrb_load_proc(mrb_state *mrb, const struct RProc *proc); +/** + * It can be used to isolate top-level scopes referenced by blocks generated by + * `mrb_load_string_cxt()` or similar called before entering the mruby VM (e.g. from `main()`). + * In that case, the `ci` parameter should be `mrb->c->cibase`. + * + * #include + * #include + * #include + * + * int + * main(int argc, char **argv) + * { + * mrb_state *mrb; + * mrbc_context *cxt; + * mrb_value blk, ret; + * + * mrb = mrb_open(); + * cxt = mrbc_context_new(mrb); + * blk = mrb_load_string_cxt(mrb, "x, y, z = 1, 2, 3; proc { [x, y, z] }", cxt); + * mrb_vm_ci_env_clear(mrb, mrb->c->cibase); + * mrb_load_string_cxt(mrb, "x, y, z = 4, 5, 6", cxt); + * ret = mrb_funcall(mrb, blk, "call", 0); + * mrb_p(mrb, ret); // => [1, 2, 3] + * // => [4, 5, 6] if `mrb_vm_ci_env_clear()` is commented out + * mrbc_context_free(mrb, cxt); + * mrb_close(mrb); + * + * return 0; + * } + * + * The top-level local variable names stored in `mrbc_context` are retained. + * Use also `mrbc_cleanup_local_variables()` at the same time, if necessary. + */ +MRB_API void mrb_vm_ci_env_clear(mrb_state *mrb, mrb_callinfo *ci); + void mrb_vm_ci_proc_set(mrb_callinfo *ci, const struct RProc *p); struct RClass * mrb_vm_ci_target_class(const mrb_callinfo *ci); void mrb_vm_ci_target_class_set(mrb_callinfo *ci, struct RClass *tc); struct REnv * mrb_vm_ci_env(const mrb_callinfo *ci); -MRB_API void mrb_vm_ci_env_clear(mrb_callinfo *ci); -MRB_API void mrb_vm_ci_env_set(mrb_callinfo *ci, struct REnv *e); +void mrb_vm_ci_env_set(mrb_callinfo *ci, struct REnv *e); MRB_END_DECL diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index 3ac952fcb..c04c2d44c 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -223,9 +223,7 @@ module MRuby f.puts %Q[ mrb_close(mrb);] f.puts %Q[ exit(EXIT_FAILURE);] f.puts %Q[ }] - f.puts %Q[ struct REnv *e = mrb_vm_ci_env(mrb->c->cibase);] - f.puts %Q[ mrb_vm_ci_env_clear(mrb->c->cibase);] - f.puts %Q[ mrb_env_unshare(mrb, e, FALSE);] + f.puts %Q[ mrb_vm_ci_env_clear(mrb, mrb->c->cibase);] end f.puts %Q[ mrb_gc_arena_restore(mrb, ai);] f.puts %Q[}] diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 78c3ed40f..8a723b12f 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -508,7 +508,6 @@ main(int argc, char **argv) /* Load libraries */ for (i = 0; i < args.libc; i++) { - struct REnv *e; FILE *lfp = fopen(args.libv[i], "r"); if (lfp == NULL) { printf("Cannot open library file. (%s)\n", args.libv[i]); @@ -517,9 +516,7 @@ main(int argc, char **argv) } mrb_load_file_cxt(mrb, lfp, cxt); fclose(lfp); - e = mrb_vm_ci_env(mrb->c->cibase); - mrb_vm_ci_env_set(mrb->c->cibase, NULL); - mrb_env_unshare(mrb, e, FALSE); + mrb_vm_ci_env_clear(mrb, mrb->c->cibase); mrbc_cleanup_local_variables(mrb, cxt); } diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c index 3faaaccd3..966014dc1 100644 --- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c @@ -326,7 +326,6 @@ main(int argc, char **argv) /* Load libraries */ for (i = 0; i < args.libc; i++) { - struct REnv *e; FILE *lfp = fopen(args.libv[i], "rb"); if (lfp == NULL) { fprintf(stderr, "%s: Cannot open library file: %s\n", *argv, args.libv[i]); @@ -342,9 +341,7 @@ main(int argc, char **argv) v = mrb_load_detect_file_cxt(mrb, lfp, c); } fclose(lfp); - e = mrb_vm_ci_env(mrb->c->cibase); - mrb_vm_ci_env_set(mrb->c->cibase, NULL); - mrb_env_unshare(mrb, e, FALSE); + mrb_vm_ci_env_clear(mrb, mrb->c->cibase); mrbc_cleanup_local_variables(mrb, c); } diff --git a/src/vm.c b/src/vm.c index 2c72e35ab..f88ae6df5 100644 --- a/src/vm.c +++ b/src/vm.c @@ -318,22 +318,19 @@ ci_env_set(mrb_callinfo *ci, struct REnv *e) } } -MRB_API void +void mrb_vm_ci_env_set(mrb_callinfo *ci, struct REnv *e) { ci_env_set(ci, e); } MRB_API void -mrb_vm_ci_env_clear(mrb_callinfo *ci) +mrb_vm_ci_env_clear(mrb_state *mrb, mrb_callinfo *ci) { - if (ci->u.env) { - if (ci->u.env->tt == MRB_TT_ENV) { - ci->u.target_class = ci->u.env->c; - } - } - else { - ci->u.env = NULL; + struct REnv *e = ci->u.env; + if (e && e->tt == MRB_TT_ENV) { + ci->u.target_class = e->c; + mrb_env_unshare(mrb, e, FALSE); } }