From 995c2e9536a7c0f0476d1f62ac3c9bcb68513c59 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Thu, 8 Aug 2019 22:17:22 +0900 Subject: Reduce unnecessary EXEC_TAG in require --- load.c | 79 +++++++++++++++++++++++++++++++++-------------- test/ruby/test_require.rb | 4 +-- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/load.c b/load.c index ba84ec0d7b..8b872a81b7 100644 --- a/load.c +++ b/load.c @@ -569,6 +569,24 @@ rb_provide(const char *feature) NORETURN(static void load_failed(VALUE)); static inline void +load_iseq_eval(rb_execution_context_t *ec, VALUE fname) +{ + const rb_iseq_t *iseq = rb_iseq_load_iseq(fname); + + if (!iseq) { + rb_ast_t *ast; + VALUE parser = rb_parser_new(); + rb_parser_set_context(parser, NULL, FALSE); + ast = (rb_ast_t *)rb_parser_load_file(parser, fname); + iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit(""), + fname, rb_realpath_internal(Qnil, fname, 1), NULL); + rb_ast_dispose(ast); + } + rb_exec_event_hook_script_compiled(ec, iseq, Qnil); + rb_iseq_eval(iseq); +} + +static inline enum ruby_tag_type rb_load_internal0(rb_execution_context_t *ec, VALUE fname, int wrap) { enum ruby_tag_type state; @@ -594,22 +612,7 @@ rb_load_internal0(rb_execution_context_t *ec, VALUE fname, int wrap) EC_PUSH_TAG(ec); state = EC_EXEC_TAG(); if (state == TAG_NONE) { - rb_ast_t *ast; - const rb_iseq_t *iseq; - - if ((iseq = rb_iseq_load_iseq(fname)) != NULL) { - /* OK */ - } - else { - VALUE parser = rb_parser_new(); - rb_parser_set_context(parser, NULL, FALSE); - ast = (rb_ast_t *)rb_parser_load_file(parser, fname); - iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit(""), - fname, rb_realpath_internal(Qnil, fname, 1), NULL); - rb_ast_dispose(ast); - } - rb_exec_event_hook_script_compiled(ec, iseq, Qnil); - rb_iseq_eval(iseq); + load_iseq_eval(ec, fname); } EC_POP_TAG(); @@ -619,7 +622,12 @@ rb_load_internal0(rb_execution_context_t *ec, VALUE fname, int wrap) #endif th->top_self = self; th->top_wrapper = wrapper; + return state; +} +static inline void +raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state) +{ if (state) { rb_vm_jump_tag_but_local_jump(state); } @@ -633,7 +641,7 @@ static void rb_load_internal(VALUE fname, int wrap) { rb_execution_context_t *ec = GET_EC(); - rb_load_internal0(ec, fname, wrap); + raise_load_if_failed(ec, rb_load_internal0(ec, fname, wrap)); } void @@ -966,11 +974,10 @@ rb_resolve_feature_path(VALUE klass, VALUE fname) * <0: not found (LoadError) * >1: exception */ -int -rb_require_internal(VALUE fname, int safe) +static int +require_internal(rb_execution_context_t *ec, VALUE fname, int safe, int exception) { volatile int result = -1; - rb_execution_context_t *ec = GET_EC(); volatile VALUE errinfo = ec->errinfo; enum ruby_tag_type state; struct { @@ -985,6 +992,7 @@ rb_require_internal(VALUE fname, int safe) EC_PUSH_TAG(ec); saved.safe = rb_safe_level(); + ec->errinfo = Qnil; /* ensure */ if ((state = EC_EXEC_TAG()) == TAG_NONE) { long handle; int found; @@ -1006,7 +1014,7 @@ rb_require_internal(VALUE fname, int safe) else { switch (found) { case 'r': - rb_load_internal(path, 0); + load_iseq_eval(ec, path); break; case 's': @@ -1025,10 +1033,24 @@ rb_require_internal(VALUE fname, int safe) rb_set_safe_level_force(saved.safe); if (state) { + if (exception) { + /* usually state == TAG_RAISE only, except for + * rb_iseq_load_iseq in load_iseq_eval case */ + VALUE exc = rb_vm_make_jump_tag_but_local_jump(state, Qundef); + if (!NIL_P(exc)) ec->errinfo = exc; + return TAG_RAISE; + } + else if (state == TAG_RETURN) { + return TAG_RAISE; + } RB_GC_GUARD(fname); /* never TAG_RETURN */ return state; } + if (!NIL_P(ec->errinfo)) { + if (!exception) return TAG_RAISE; + rb_exc_raise(ec->errinfo); + } ec->errinfo = errinfo; @@ -1037,12 +1059,20 @@ rb_require_internal(VALUE fname, int safe) return result; } +int +rb_require_internal(VALUE fname, int safe) +{ + rb_execution_context_t *ec = GET_EC(); + return require_internal(ec, fname, safe, 1); +} + int ruby_require_internal(const char *fname, unsigned int len) { struct RString fake; VALUE str = rb_setup_fake_str(&fake, fname, len, 0); - int result = rb_require_internal(str, 0); + rb_execution_context_t *ec = GET_EC(); + int result = require_internal(ec, str, 0, 0); rb_set_errinfo(Qnil); return result == TAG_RETURN ? 1 : result ? -1 : 0; } @@ -1050,10 +1080,11 @@ ruby_require_internal(const char *fname, unsigned int len) VALUE rb_require_safe(VALUE fname, int safe) { - int result = rb_require_internal(fname, safe); + rb_execution_context_t *ec = GET_EC(); + int result = require_internal(ec, fname, safe, 1); if (result > TAG_RETURN) { - EC_JUMP_TAG(GET_EC(), result); + EC_JUMP_TAG(ec, result); } if (result < 0) { load_failed(fname); diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb index 56dfd95096..2504b9e67c 100644 --- a/test/ruby/test_require.rb +++ b/test/ruby/test_require.rb @@ -260,8 +260,8 @@ class TestRequire < Test::Unit::TestCase e = assert_raise_with_message(SyntaxError, /unexpected/) { yield req } - assert_not_nil(bt = e.backtrace) - assert_not_empty(bt.find_all {|b| b.start_with? __FILE__}) + assert_not_nil(bt = e.backtrace, "no backtrace") + assert_not_empty(bt.find_all {|b| b.start_with? __FILE__}, proc {bt.inspect}) end end -- cgit v1.2.3