summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2021-10-26 01:58:01 +0900
committerGitHub <noreply@github.com>2021-10-26 01:58:01 +0900
commit09fa773e04f183e5eb685f07e174efa2cf77f9dc (patch)
tree43b58901056217443ddfcee79decd2a9c71596cc
parent33113c6b64b9017e8b31b6c5e9cbcd7bdf30f05a (diff)
ast.c: Use kept script_lines data instead of re-opening the source file (#5019)
ast.c: Use kept script_lines data instead of re-open the source file
Notes
Notes: Merged-By: mame <mame@ruby-lang.org>
-rw-r--r--ast.c9
-rw-r--r--internal/vm.h2
-rw-r--r--parse.y1
-rw-r--r--vm_backtrace.c22
4 files changed, 18 insertions, 16 deletions
diff --git a/ast.c b/ast.c
index 84e5fdcecc..96116d43eb 100644
--- a/ast.c
+++ b/ast.c
@@ -195,12 +195,12 @@ script_lines(VALUE path)
static VALUE
ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE keep_script_lines)
{
- VALUE path, node, lines;
+ VALUE path, node, lines = Qnil;
int node_id;
if (rb_frame_info_p(body)) {
- rb_frame_info_get(body, &path, &node_id);
- if (NIL_P(path)) return Qnil;
+ rb_frame_info_get(body, &path, &lines, &node_id);
+ if (NIL_P(path) && NIL_P(lines)) return Qnil;
}
else {
const rb_iseq_t *iseq = NULL;
@@ -220,10 +220,11 @@ ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE keep_script
rb_raise(rb_eArgError, "cannot get AST for method defined in eval");
}
path = rb_iseq_path(iseq);
+ lines = iseq->body->variable.script_lines;
node_id = iseq->body->location.node_id;
}
- if (!NIL_P(lines = script_lines(path))) {
+ if (!NIL_P(lines) || !NIL_P(lines = script_lines(path))) {
node = rb_ast_parse_array(lines, keep_script_lines);
}
else if (RSTRING_LEN(path) == 2 && memcmp(RSTRING_PTR(path), "-e", 2) == 0) {
diff --git a/internal/vm.h b/internal/vm.h
index 8893d70cd4..e902a81411 100644
--- a/internal/vm.h
+++ b/internal/vm.h
@@ -111,7 +111,7 @@ VALUE rb_backtrace_to_str_ary(VALUE obj);
VALUE rb_backtrace_to_location_ary(VALUE obj);
void rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output);
int rb_frame_info_p(VALUE obj);
-void rb_frame_info_get(VALUE obj, VALUE *path, int *node_id);
+void rb_frame_info_get(VALUE obj, VALUE *path, VALUE *script_lines, int *node_id);
MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_ec_backtrace_object(const struct rb_execution_context_struct *ec);
diff --git a/parse.y b/parse.y
index 2ec9d7770c..5948f6e2f6 100644
--- a/parse.y
+++ b/parse.y
@@ -6414,6 +6414,7 @@ lex_getline(struct parser_params *p)
VALUE line = (*p->lex.gets)(p, p->lex.input);
if (NIL_P(line)) return line;
must_be_ascii_compatible(line);
+ if (RB_OBJ_FROZEN(line)) line = rb_str_dup(line); // needed for RubyVM::AST.of because script_lines in iseq is deep-frozen
#ifndef RIPPER
if (p->debug_lines) {
rb_enc_associate(line, p->enc);
diff --git a/vm_backtrace.c b/vm_backtrace.c
index 8294d218a4..f2e9bed6ba 100644
--- a/vm_backtrace.c
+++ b/vm_backtrace.c
@@ -283,19 +283,16 @@ location_base_label_m(VALUE self)
return location_base_label(location_ptr(self));
}
-static VALUE
-location_path(rb_backtrace_location_t *loc)
+static const rb_iseq_t *
+location_iseq(rb_backtrace_location_t *loc)
{
switch (loc->type) {
case LOCATION_TYPE_ISEQ:
- return rb_iseq_path(loc->iseq);
+ return loc->iseq;
case LOCATION_TYPE_CFUNC:
- if (loc->iseq) {
- return rb_iseq_path(loc->iseq);
- }
- return Qnil;
+ return loc->iseq;
default:
- rb_bug("location_path: unreachable");
+ rb_bug("location_iseq: unreachable");
UNREACHABLE;
}
}
@@ -313,7 +310,8 @@ location_path(rb_backtrace_location_t *loc)
static VALUE
location_path_m(VALUE self)
{
- return location_path(location_ptr(self));
+ const rb_iseq_t *iseq = location_iseq(location_ptr(self));
+ return iseq ? rb_iseq_path(iseq) : Qnil;
}
#ifdef USE_ISEQ_NODE_ID
@@ -336,11 +334,13 @@ location_node_id(rb_backtrace_location_t *loc)
#endif
void
-rb_frame_info_get(VALUE obj, VALUE *path, int *node_id)
+rb_frame_info_get(VALUE obj, VALUE *path, VALUE *script_lines, int *node_id)
{
#ifdef USE_ISEQ_NODE_ID
rb_backtrace_location_t *loc = location_ptr(obj);
- *path = location_path(loc);
+ const rb_iseq_t *iseq = location_iseq(loc);
+ *path = iseq ? rb_iseq_path(iseq) : Qnil;
+ *script_lines = iseq ? iseq->body->variable.script_lines : Qnil;
*node_id = location_node_id(loc);
#else
*path = Qnil;