summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2019-08-08 22:17:22 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-08-08 22:28:00 +0900
commit995c2e9536a7c0f0476d1f62ac3c9bcb68513c59 (patch)
tree5c661293fa1d081197441b515df21cc54aa436b5
parent2a6d7fad133cd6e1e50de6b8627d19eecee5ed8f (diff)
Reduce unnecessary EXEC_TAG in require
-rw-r--r--load.c79
-rw-r--r--test/ruby/test_require.rb4
2 files changed, 57 insertions, 26 deletions
diff --git a/load.c b/load.c
index ba84ec0..8b872a8 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("<top (required)>"),
+ 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("<top (required)>"),
- 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;
@@ -1038,11 +1060,19 @@ rb_require_internal(VALUE fname, int safe)
}
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 56dfd95..2504b9e 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