From c474ae8cc457f0e6dbc33525264f18d503ce1325 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 28 Feb 2023 22:12:24 +0900 Subject: [PATCH 1/2] Perform chores with `mrb_init_mrbgems()` function Make the `mrb_init_mrbgems()` function do the cleanup and error handling. Instead, simplify processing in the `GENERATED_TMP_mrb_XXX_gem_init()` function. Previously, `mrb_load_irep()` or `mrb_load_proc()` would kill the process when an exception occurred. With this patch, it is now caught by `mrb_core_init_protect()`. --- lib/mruby/gem.rb | 8 -------- tasks/mrbgems.rake | 25 +++++++++++++++++++++---- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index a03342a30..8fc1aeaaf 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -209,7 +209,6 @@ module MRuby f.puts %Q[void mrb_#{funcname}_gem_final(mrb_state *mrb);] f.puts %Q[] f.puts %Q[void GENERATED_TMP_mrb_#{funcname}_gem_init(mrb_state *mrb) {] - f.puts %Q[ int ai = mrb_gc_arena_save(mrb);] f.puts %Q[ gem_mrblib_#{funcname}_proc_init_syms(mrb);] if !rbfiles.empty? && cdump? f.puts %Q[ mrb_#{funcname}_gem_init(mrb);] if objs != [objfile("#{build_dir}/gem_init")] unless rbfiles.empty? @@ -218,14 +217,7 @@ module MRuby else f.puts %Q[ mrb_load_irep(mrb, gem_mrblib_irep_#{funcname});] end - f.puts %Q[ if (mrb->exc) {] - f.puts %Q[ mrb_print_error(mrb);] - f.puts %Q[ mrb_close(mrb);] - f.puts %Q[ exit(EXIT_FAILURE);] - f.puts %Q[ }] - 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[}] f.puts %Q[] f.puts %Q[void GENERATED_TMP_mrb_#{funcname}_gem_final(mrb_state *mrb) {] diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake index 444971476..ea381467f 100644 --- a/tasks/mrbgems.rake +++ b/tasks/mrbgems.rake @@ -17,8 +17,8 @@ MRuby.each_target do s << "void GENERATED_TMP_mrb_#{g.funcname}_gem_init(mrb_state*);\n" \ "void GENERATED_TMP_mrb_#{g.funcname}_gem_final(mrb_state*);\n" end - gem_init_calls = gem_func_gems.each_with_object('') do |g, s| - s << " GENERATED_TMP_mrb_#{g.funcname}_gem_init(mrb);\n" + gem_funcs = gem_func_gems.each_with_object('') do |g, s| + s << " { GENERATED_TMP_mrb_#{g.funcname}_gem_init },\n" end gem_final_calls = gem_func_gems.reverse_each.with_object('') do |g, s| s << " GENERATED_TMP_mrb_#{g.funcname}_gem_final(mrb);\n" @@ -36,8 +36,17 @@ MRuby.each_target do f.puts %Q[ */] f.puts %Q[] f.puts %Q[#include ] + f.puts %Q[#include ] f.puts %Q[] f.write gem_func_decls + f.puts %Q[] + f.puts %Q[static const struct {] + f.puts %Q[ void (*init)(mrb_state*);] + f.puts %Q[} gem_funcs[] = {] + f.write gem_funcs + f.puts %Q[};] + f.puts %Q[] + f.puts %Q[#define NUM_GEMS ((int)(sizeof(gem_funcs) / sizeof(gem_funcs[0])))] unless gem_final_calls.empty? f.puts %Q[] f.puts %Q[static void] @@ -48,8 +57,16 @@ MRuby.each_target do f.puts %Q[] f.puts %Q[void] f.puts %Q[mrb_init_mrbgems(mrb_state *mrb) {] - f.write gem_init_calls - f.puts %Q[ mrb_state_atexit(mrb, mrb_final_mrbgems);] unless gem_final_calls.empty? + f.puts %Q[ int ai = mrb_gc_arena_save(mrb);] + f.puts %Q[ for (int i = 0; i < NUM_GEMS; i++) {] + f.puts %Q[ gem_funcs[i].init(mrb);] + f.puts %Q[ mrb_gc_arena_restore(mrb, ai);] + f.puts %Q[ mrb_vm_ci_env_clear(mrb, mrb->c->cibase);] + f.puts %Q[ if (mrb->exc) {] + f.puts %Q[ mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));] + f.puts %Q[ }] + f.puts %Q[ }] + f.puts %Q[ mrb_state_atexit(mrb, mrb_final_mrbgems);] f.puts %Q[}] end end From 1432baec1d63751cf9b05ae91e817d6d733b5da9 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 28 Feb 2023 22:12:25 +0900 Subject: [PATCH 2/2] Perform chores with `mrb_final_mrbgems()` function The main purpose is to ignore exceptions raised by the GEMS finalizer. --- tasks/mrbgems.rake | 50 +++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake index ea381467f..26d736bfd 100644 --- a/tasks/mrbgems.rake +++ b/tasks/mrbgems.rake @@ -13,15 +13,14 @@ MRuby.each_target do mkdir_p "#{build_dir}/mrbgems" open(t.name, 'w') do |f| gem_func_gems = gems.select { |g| g.generate_functions } - gem_func_decls = gem_func_gems.each_with_object('') do |g, s| - s << "void GENERATED_TMP_mrb_#{g.funcname}_gem_init(mrb_state*);\n" \ - "void GENERATED_TMP_mrb_#{g.funcname}_gem_final(mrb_state*);\n" - end - gem_funcs = gem_func_gems.each_with_object('') do |g, s| - s << " { GENERATED_TMP_mrb_#{g.funcname}_gem_init },\n" - end - gem_final_calls = gem_func_gems.reverse_each.with_object('') do |g, s| - s << " GENERATED_TMP_mrb_#{g.funcname}_gem_final(mrb);\n" + gem_func_decls = '' + gem_funcs = '' + gem_func_gems.each do |g| + init = "GENERATED_TMP_mrb_#{g.funcname}_gem_init" + final = "GENERATED_TMP_mrb_#{g.funcname}_gem_final" + gem_func_decls << "void #{init}(mrb_state*);\n" \ + "void #{final}(mrb_state*);\n" + gem_funcs << " { #{init}, #{final} },\n" end f.puts %Q[/*] f.puts %Q[ * This file contains a list of all] @@ -36,24 +35,43 @@ MRuby.each_target do f.puts %Q[ */] f.puts %Q[] f.puts %Q[#include ] + f.puts %Q[#include ] f.puts %Q[#include ] f.puts %Q[] f.write gem_func_decls f.puts %Q[] f.puts %Q[static const struct {] f.puts %Q[ void (*init)(mrb_state*);] + f.puts %Q[ void (*final)(mrb_state*);] f.puts %Q[} gem_funcs[] = {] f.write gem_funcs f.puts %Q[};] f.puts %Q[] f.puts %Q[#define NUM_GEMS ((int)(sizeof(gem_funcs) / sizeof(gem_funcs[0])))] - unless gem_final_calls.empty? - f.puts %Q[] - f.puts %Q[static void] - f.puts %Q[mrb_final_mrbgems(mrb_state *mrb) {] - f.write gem_final_calls - f.puts %Q[}] - end + f.puts %Q[] + f.puts %Q[struct final_mrbgems {] + f.puts %Q[ int i;] + f.puts %Q[ int ai;] + f.puts %Q[};] + f.puts %Q[] + f.puts %Q[static mrb_value] + f.puts %Q[final_mrbgems_body(mrb_state *mrb, void *ud) {] + f.puts %Q[ struct final_mrbgems *p = (struct final_mrbgems*)ud;] + f.puts %Q[ for (; p->i >= 0; p->i--) {] + f.puts %Q[ gem_funcs[p->i].final(mrb);] + f.puts %Q[ mrb_gc_arena_restore(mrb, p->ai);] + f.puts %Q[ }] + f.puts %Q[ return mrb_nil_value();] + f.puts %Q[}] + f.puts %Q[] + f.puts %Q[static void] + f.puts %Q[mrb_final_mrbgems(mrb_state *mrb) {] + f.puts %Q[ struct final_mrbgems a = { NUM_GEMS - 1, mrb_gc_arena_save(mrb) };] + f.puts %Q[ for (; a.i >= 0; a.i--) {] + f.puts %Q[ mrb_protect_error(mrb, final_mrbgems_body, &a, NULL);] + f.puts %Q[ mrb_gc_arena_restore(mrb, a.ai);] + f.puts %Q[ }] + f.puts %Q[}] f.puts %Q[] f.puts %Q[void] f.puts %Q[mrb_init_mrbgems(mrb_state *mrb) {]