Class: RubyVM::InstructionSequence
Overview
The InstructionSequence class represents a compiled sequence of
instructions for the Virtual Machine used in MRI. Not all implementations of ::Ruby
may implement this class, and for the implementations that implement it,
the methods defined and behavior of the methods can change in any version.
With it, you can get a handle to the instructions that make up a method or
a proc, compile strings of ::Ruby code down to VM instructions, and
disassemble instruction sequences to strings for easy inspection. It is
mostly useful if you want to learn how YARV works, but it also lets
you control various settings for the ::Ruby iseq compiler.
You can find the source for the VM instructions in insns.def in the ::Ruby
source.
The instruction sequence results will almost certainly change as ::Ruby
changes, so example output in this documentation may be different from what
you see.
Of course, this class is MRI specific.
Class Attribute Summary
-
.compile_option ⇒ options
rw
Returns a hash of default options used by the
::Rubyiseq compiler. -
.compile_option=(options)
rw
Sets the default values for various optimizations in the
::Rubyiseq compiler.
Class Method Summary
-
.compile(source[, file[, path[, line[, options]]]]) ⇒ iseq
Alias for .new.
- .compile_file(file[, options]) ⇒ iseq
- .compile_file_prism(file[, options]) ⇒ iseq
- .compile_parsey(source[, file[, path[, line[, options]]]]) ⇒ iseq
- .compile_prism(source[, file[, path[, line[, options]]]]) ⇒ iseq
- .disasm(body) ⇒ String (also: .disassemble)
-
.disassemble(body) ⇒ String
Alias for .disasm.
-
.load_from_binary(binary) ⇒ iseq
Load an iseq object from binary format
::Stringobject created by #to_binary. -
.load_from_binary_extra_data(binary) ⇒ String
Load extra data embed into binary format
::Stringobject. - .new(source[, file[, path[, line[, options]]]]) ⇒ iseq (also: .compile) constructor
-
.of(body)
Returns the instruction sequence containing the given proc or method.
- .load(*args) Internal use only
Instance Method Summary
-
#absolute_path
Returns the absolute path of this instruction sequence.
-
#base_label
Returns the base label of this instruction sequence.
-
#disasm ⇒ String
(also: #disassemble)
Returns the instruction sequence as a
::Stringin human readable form. -
#disassemble ⇒ String
Alias for #disasm.
-
#each_child {|child_iseq| ... } ⇒ iseq
Iterate all direct child instruction sequences.
-
#eval ⇒ Object
Evaluates the instruction sequence and returns the result.
-
#first_lineno
Returns the number of the first source line where the instruction sequence was loaded from.
- #inspect
-
#label
Returns the label of this instruction sequence.
-
#node_id
Returns the node id of the AST node this iseq corresponds to.
-
#path
Returns the path of this instruction sequence.
-
#script_lines ⇒ Array?
It returns recorded script lines if it is available.
-
#source_hash
Returns the hash of the source this iseq was compiled from, or nil if it is unavailable.
-
#syntax_tree ⇒ Prism::Node | {RubyVM::AbstractSyntaxTree::Node} | nil
Returns the AST node that this instruction sequence was compiled from, by re-parsing the source with the same parser that compiled it: a
Prism::Nodeif it was compiled by prism, or aAbstractSyntaxTree::Nodeif it was compiled by parse.y. -
#to_a ⇒ Array
Returns an
::Arraywith 14 elements representing the instruction sequence with the following data: -
#to_binary(extra_data = nil) ⇒ binary str
Returns serialized iseq binary format data as a
::Stringobject. -
#trace_points ⇒ Array
Return trace points in the instruction sequence.
- #marshal_dump private
- #marshal_load private
Constructor Details
.compile(source[, file[, path[, line[, options]]]]) ⇒ iseq
.new(source[, file[, path[, line[, options]]]]) ⇒ iseq
Also known as: .compile
iseq
.new(source[, file[, path[, line[, options]]]]) ⇒ iseq
Takes source, which can be a string of ::Ruby code, or an open ::File object.
that contains ::Ruby source code.
Optionally takes file, #path, and line which describe the file path,
real path and first line number of the ruby code in source which are
metadata attached to the returned iseq.
file is used for __FILE__ and exception backtrace. #path is used for
require_relative base. It is recommended these should be the same full
path.
options, which can be true, false or a ::Hash, is used to
modify the default behavior of the ::Ruby iseq compiler.
For details regarding valid compile options see .compile_option=.
RubyVM::InstructionSequence.compile("a = 1 + 2")
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
path = "test.rb"
RubyVM::InstructionSequence.compile(File.read(path), path, File.(path))
#=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
file = File.open("test.rb")
RubyVM::InstructionSequence.compile(file)
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
path = File.("test.rb")
RubyVM::InstructionSequence.compile(File.read(path), path, path)
#=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
# File 'iseq.c', line 1772
static VALUE
iseqw_s_compile(int argc, VALUE *argv, VALUE self)
{
return iseqw_s_compile_parser(argc, argv, self, rb_ruby_prism_p());
}
Class Attribute Details
.compile_option ⇒ options (rw)
Returns a hash of default options used by the ::Ruby iseq compiler.
For details, see .compile_option=.
# File 'iseq.c', line 2076
static VALUE
iseqw_s_compile_option_get(VALUE self)
{
return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
}
.compile_option=(options) (rw)
Sets the default values for various optimizations in the ::Ruby iseq
compiler.
Possible values for options include true, which enables all options,
false which disables all options, and nil which leaves all options
unchanged.
You can also pass a ::Hash of options that you want to change, any
options not present in the hash will be left unchanged.
Possible option names (which are keys in options) which can be set to
true or false include:
:inline_const_cache:instructions_unification:operands_unification:peephole_optimization:specialized_instruction:tailcall_optimization
Additionally, :debug_level can be set to an integer.
These default options can be overwritten for a single run of the iseq
compiler by passing any of the above values as the options parameter to
.new, .compile and .compile_file.
# File 'iseq.c', line 2059
static VALUE
iseqw_s_compile_option_set(VALUE self, VALUE opt)
{
rb_compile_option_t option;
make_compile_option(&option, opt);
COMPILE_OPTION_DEFAULT = option;
return opt;
}
Class Method Details
.compile(source[, file[, path[, line[, options]]]]) ⇒ iseq
.new(source[, file[, path[, line[, options]]]]) ⇒ iseq
iseq
.new(source[, file[, path[, line[, options]]]]) ⇒ iseq
Alias for .new.
.compile_file(file[, options]) ⇒ iseq
Takes file, a ::String with the location of a ::Ruby source file, reads,
parses and compiles the file, and returns iseq, the compiled
InstructionSequence with source location metadata set.
Optionally takes options, which can be true, false or a ::Hash, to
modify the default behavior of the ::Ruby iseq compiler.
For details regarding valid compile options see .compile_option=.
# /tmp/hello.rb
puts "Hello, world!"
# elsewhere
RubyVM::InstructionSequence.compile_file("/tmp/hello.rb")
#=> <RubyVM::InstructionSequence:<main>@/tmp/hello.rb>
# File 'iseq.c', line 1884
static VALUE
iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
{
if (rb_ruby_prism_p()) {
return iseqw_s_compile_file_prism(argc, argv, self);
}
VALUE file, opt = Qnil;
VALUE parser, f, exc = Qnil, ret;
rb_ast_t *ast;
VALUE ast_value;
rb_compile_option_t option;
int i;
i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 2);
switch (i) {
case 2: opt = argv[--i];
}
FilePathValue(file);
file = rb_fstring(file); /* rb_io_t->pathv gets frozen anyways */
f = rb_file_open_str(file, "r");
rb_execution_context_t *ec = GET_EC();
VALUE v = rb_vm_push_frame_fname(ec, file);
parser = rb_parser_new();
rb_parser_set_context(parser, NULL, FALSE);
ast_value = rb_parser_load_file(parser, file);
iseq_new_setup_coverage(file, ast_line_count(ast_value));
ast = rb_ruby_ast_data_get(ast_value);
if (!ast->body.root) exc = GET_EC()->errinfo;
rb_io_close(f);
if (!ast->body.root) {
rb_ast_dispose(ast);
rb_exc_raise(exc);
}
make_compile_option(&option, opt);
ret = iseqw_new(rb_iseq_new_with_opt(ast_value, rb_fstring_lit("<main>"),
file,
rb_realpath_internal(Qnil, file, 1),
1, NULL, 0, ISEQ_TYPE_TOP, &option,
Qnil));
rb_ast_dispose(ast);
RB_GC_GUARD(ast_value);
rb_vm_pop_frame(ec);
RB_GC_GUARD(v);
return ret;
}
.compile_file_prism(file[, options]) ⇒ iseq
Takes file, a ::String with the location of a ::Ruby source file, reads,
parses and compiles the file, and returns iseq, the compiled
InstructionSequence with source location metadata set. It parses and
compiles using prism.
Optionally takes options, which can be true, false or a ::Hash, to
modify the default behavior of the ::Ruby iseq compiler.
For details regarding valid compile options see .compile_option=.
# /tmp/hello.rb
puts "Hello, world!"
# elsewhere
RubyVM::InstructionSequence.compile_file_prism("/tmp/hello.rb")
#=> <RubyVM::InstructionSequence:<main>@/tmp/hello.rb>
# File 'iseq.c', line 1960
static VALUE
iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self)
{
VALUE file, opt = Qnil, ret;
rb_compile_option_t option;
int i;
i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 2);
switch (i) {
case 2: opt = argv[--i];
}
FilePathValue(file);
file = rb_fstring(file); /* rb_io_t->pathv gets frozen anyways */
rb_execution_context_t *ec = GET_EC();
VALUE v = rb_vm_push_frame_fname(ec, file);
make_compile_option(&option, opt);
pm_parse_result_t result;
pm_parse_result_init(&result);
result.node.coverage_enabled = 1;
switch (option.frozen_string_literal) {
case ISEQ_FROZEN_STRING_LITERAL_UNSET:
break;
case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
pm_options_frozen_string_literal_set(result.options, false);
break;
case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
pm_options_frozen_string_literal_set(result.options, true);
break;
default:
rb_bug("iseqw_s_compile_file_prism: invalid frozen_string_literal=%d", option.frozen_string_literal);
break;
}
VALUE script_lines;
VALUE error = pm_load_parse_file(&result, file, ruby_vm_keep_script_lines ? &script_lines : NULL);
if (error == Qnil) {
int error_state;
iseq_new_setup_coverage(file, (int) (pm_parser_line_offsets(result.node.parser)->size - 1));
rb_iseq_t *iseq = pm_iseq_new_with_opt(&result.node, rb_fstring_lit("<main>"),
file,
rb_realpath_internal(Qnil, file, 1),
1, NULL, 0, ISEQ_TYPE_TOP, &option, &error_state);
pm_parse_result_free(&result);
if (error_state) {
RUBY_ASSERT(iseq == NULL);
rb_jump_tag(error_state);
}
ret = iseqw_new(iseq);
rb_vm_pop_frame(ec);
RB_GC_GUARD(v);
return ret;
}
else {
pm_parse_result_free(&result);
rb_vm_pop_frame(ec);
RB_GC_GUARD(v);
rb_exc_raise(error);
}
}
.compile_parsey(source[, file[, path[, line[, options]]]]) ⇒ iseq
Takes source, which can be a string of ::Ruby code, or an open ::File object.
that contains ::Ruby source code. It parses and compiles using parse.y.
Optionally takes file, #path, and line which describe the file path,
real path and first line number of the ruby code in source which are
metadata attached to the returned iseq.
file is used for __FILE__ and exception backtrace. #path is used for
require_relative base. It is recommended these should be the same full
path.
options, which can be true, false or a ::Hash, is used to
modify the default behavior of the ::Ruby iseq compiler.
For details regarding valid compile options see .compile_option=.
RubyVM::InstructionSequence.compile_parsey("a = 1 + 2")
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
path = "test.rb"
RubyVM::InstructionSequence.compile_parsey(File.read(path), path, File.(path))
#=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
file = File.open("test.rb")
RubyVM::InstructionSequence.compile_parsey(file)
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
path = File.("test.rb")
RubyVM::InstructionSequence.compile_parsey(File.read(path), path, path)
#=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
# File 'iseq.c', line 1814
static VALUE
iseqw_s_compile_parsey(int argc, VALUE *argv, VALUE self)
{
return iseqw_s_compile_parser(argc, argv, self, false);
}
.compile_prism(source[, file[, path[, line[, options]]]]) ⇒ iseq
Takes source, which can be a string of ::Ruby code, or an open ::File object.
that contains ::Ruby source code. It parses and compiles using prism.
Optionally takes file, #path, and line which describe the file path,
real path and first line number of the ruby code in source which are
metadata attached to the returned iseq.
file is used for __FILE__ and exception backtrace. #path is used for
require_relative base. It is recommended these should be the same full
path.
options, which can be true, false or a ::Hash, is used to
modify the default behavior of the ::Ruby iseq compiler.
For details regarding valid compile options see .compile_option=.
RubyVM::InstructionSequence.compile_prism("a = 1 + 2")
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
path = "test.rb"
RubyVM::InstructionSequence.compile_prism(File.read(path), path, File.(path))
#=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
file = File.open("test.rb")
RubyVM::InstructionSequence.compile_prism(file)
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
path = File.("test.rb")
RubyVM::InstructionSequence.compile_prism(File.read(path), path, path)
#=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
# File 'iseq.c', line 1856
static VALUE
iseqw_s_compile_prism(int argc, VALUE *argv, VALUE self)
{
return iseqw_s_compile_parser(argc, argv, self, true);
}
Also known as: .disassemble
Takes body, a ::Method or ::Proc object, and returns a ::String
with the human readable instructions for body.
For a ::Method object:
# /tmp/method.rb
def hello
puts "hello, world"
end
puts RubyVM::InstructionSequence.disasm(method(:hello))
Produces:
== disasm: <RubyVM::InstructionSequence:hello@/tmp/method.rb>============
0000 trace 8 ( 1)
0002 trace 1 ( 2)
0004 putself
0005 dupstring "hello, world"
0007 send :puts, 1, nil, 8, <ic:0>
0013 trace 16 ( 3)
0015 leave ( 2)
For a ::Proc object:
# /tmp/proc.rb
p = proc { num = 1 + 2 }
puts RubyVM::InstructionSequence.disasm(p)
Produces:
== disasm: <RubyVM::InstructionSequence:block in <main>@/tmp/proc.rb>===
== catch table
| catch type: redo st: 0000 ed: 0012 sp: 0000 cont: 0000
| catch type: next st: 0000 ed: 0012 sp: 0000 cont: 0012
|------------------------------------------------------------------------
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1] s1)
[ 2] num
0000 trace 1 ( 1)
0002 putobject 1
0004 putobject 2
0006 opt_plus <ic:1>
0008 dup
0009 setlocal num, 0
0012 leave
# File 'iseq.c', line 3366
static VALUE
iseqw_s_disasm(VALUE klass, VALUE body)
{
VALUE iseqw = iseqw_s_of(klass, body);
return NIL_P(iseqw) ? Qnil : rb_iseq_disasm(iseqw_check(iseqw));
}
Alias for .disasm.
.load(*args)
# File 'iseq.c', line 1398
static VALUE
iseq_s_load(int argc, VALUE *argv, VALUE self)
{
VALUE data, opt=Qnil;
rb_scan_args(argc, argv, "11", &data, &opt);
return iseq_load(data, NULL, opt);
}
.load_from_binary(binary) ⇒ iseq
Load an iseq object from binary format ::String object
created by #to_binary.
This loader does not have a verifier, so that loading broken/modified binary causes critical problem.
You should not load binary data provided by others. You should only use binary data translated by yourself.
# File 'iseq.c', line 4422
static VALUE
iseqw_s_load_from_binary(VALUE self, VALUE str)
{
return iseqw_new(rb_iseq_ibf_load(str));
}
.load_from_binary_extra_data(binary) ⇒ String
Load extra data embed into binary format ::String object.
# File 'iseq.c', line 4440
static VALUE
iseqw_s_load_from_binary_extra_data(VALUE self, VALUE str)
{
return rb_iseq_ibf_load_extra_data(str);
}
.of(body)
Returns the instruction sequence containing the given proc or method.
For example, using irb:
# a proc
> p = proc { num = 1 + 2 }
> RubyVM::InstructionSequence.of(p)
> #=> <RubyVM::InstructionSequence:block in irb_binding@(irb)>
# for a method
> def foo(); puts ; end
> RubyVM::InstructionSequence.of(method(:foo))
> #=> <RubyVM::InstructionSequence:foo@(irb)>
Using .compile_file:
# /tmp/iseq_of.rb
def hello
puts "hello, world"
end
$a_global_proc = proc { str = 'a' + 'b' }
# in irb
> require '/tmp/iseq_of.rb'
# first the method hello
> RubyVM::InstructionSequence.of(method(:hello))
> #=> #<RubyVM::InstructionSequence:0x007fb73d7cb1d0>
# then the global proc
> RubyVM::InstructionSequence.of($a_global_proc)
> #=> #<RubyVM::InstructionSequence:0x007fb73d7caf78>
# File 'iseq.c', line 3289
static VALUE
iseqw_s_of(VALUE klass, VALUE body)
{
const rb_iseq_t *iseq = NULL;
if (rb_frame_info_p(body)) {
iseq = rb_get_iseq_from_frame_info(body);
}
else if (rb_obj_is_proc(body)) {
iseq = vm_proc_iseq(body);
if (!rb_obj_is_iseq((VALUE)iseq)) {
iseq = NULL;
}
}
else if (rb_obj_is_method(body)) {
iseq = rb_method_iseq(body);
}
else if (rb_typeddata_is_instance_of(body, &iseqw_data_type)) {
return body;
}
return iseq ? iseqw_new(iseq) : Qnil;
}
Instance Method Details
#absolute_path
Returns the absolute path of this instruction sequence.
nil if the iseq was evaluated from a string.
For example, using .compile_file:
# /tmp/method.rb
def hello
puts "hello, world"
end
# in irb
> iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
> iseq.absolute_path #=> /tmp/method.rb
# File 'iseq.c', line 2190
static VALUE
iseqw_absolute_path(VALUE self)
{
return rb_iseq_realpath(iseqw_check(self));
}
#base_label
Returns the base label of this instruction sequence.
For example, using irb:
iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
iseq.base_label
#=> "<compiled>"
Using .compile_file:
# /tmp/method.rb
def hello
puts "hello, world"
end
# in irb
> iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
> iseq.base_label #=> <main>
# File 'iseq.c', line 2245
static VALUE
iseqw_base_label(VALUE self)
{
return rb_iseq_base_label(iseqw_check(self));
}
Also known as: #disassemble
# File 'iseq.c', line 3137
static VALUE
iseqw_disasm(VALUE self)
{
return rb_iseq_disasm(iseqw_check(self));
}
Alias for #disasm.
#each_child {|child_iseq| ... } ⇒ iseq
Iterate all direct child instruction sequences. Iteration order is implementation/version defined so that people should not rely on the order.
# File 'iseq.c', line 3207
static VALUE
iseqw_each_child(VALUE self)
{
const rb_iseq_t *iseq = iseqw_check(self);
iseq_iterate_children(iseq, yield_each_children, NULL);
return self;
}
#eval ⇒ Object
# File 'iseq.c', line 2113
static VALUE
iseqw_eval(VALUE self)
{
const rb_iseq_t *iseq = iseqw_check(self);
if (0 == ISEQ_BODY(iseq)->iseq_size) {
rb_raise(rb_eTypeError, "attempt to evaluate dummy InstructionSequence");
}
return rb_iseq_eval(iseq, rb_current_box());
}
#first_lineno
# File 'iseq.c', line 2261
static VALUE
iseqw_first_lineno(VALUE self)
{
return rb_iseq_first_lineno(iseqw_check(self));
}
#inspect
# File 'iseq.c', line 2127
static VALUE
iseqw_inspect(VALUE self)
{
const rb_iseq_t *iseq = iseqw_check(self);
const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
VALUE klass = rb_class_name(rb_obj_class(self));
if (!body->location.label) {
return rb_sprintf("#<%"PRIsVALUE": uninitialized>", klass);
}
else {
return rb_sprintf("<%"PRIsVALUE":%"PRIsVALUE"@%"PRIsVALUE":%d>",
klass,
body->location.label, rb_iseq_path(iseq),
FIX2INT(rb_iseq_first_lineno(iseq)));
}
}
#label
Returns the label of this instruction sequence.
if it's at the top level, if it
was evaluated from a string.
For example, using irb:
iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
iseq.label
#=> "<compiled>"
Using .compile_file:
# /tmp/method.rb
def hello
puts "hello, world"
end
# in irb
> iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
> iseq.label #=> <main>
# File 'iseq.c', line 2219
static VALUE
iseqw_label(VALUE self)
{
return rb_iseq_label(iseqw_check(self));
}
#marshal_dump (private)
[ GitHub ]#marshal_load (private)
[ GitHub ]#node_id
Returns the node id of the AST node this iseq corresponds to.
# File 'iseq.c', line 4612
static VALUE
iseqw_node_id(VALUE self)
{
const rb_iseq_t *iseq = iseqw_check(self);
return INT2NUM(ISEQ_BODY(iseq)->location.node_id);
}
#path
Returns the path of this instruction sequence.
if the iseq was evaluated from a string.
For example, using irb:
iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
iseq.path
#=> "<compiled>"
Using .compile_file:
# /tmp/method.rb
def hello
puts "hello, world"
end
# in irb
> iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
> iseq.path #=> /tmp/method.rb
# File 'iseq.c', line 2168
static VALUE
iseqw_path(VALUE self)
{
return rb_iseq_path(iseqw_check(self));
}
#script_lines ⇒ Array?
It returns recorded script lines if it is available. The script lines are not limited to the iseq range, but are entire lines of the source file.
Note that this is an API for ruby internal use, debugging, and research. Do not use this for any other purpose. The compatibility is not guaranteed.
# File 'iseq.c', line 4594
static VALUE
iseqw_script_lines(VALUE self)
{
const rb_iseq_t *iseq = iseqw_check(self);
return ISEQ_BODY(iseq)->variable.script_lines;
}
#source_hash
Returns the hash of the source this iseq was compiled from, or nil if it is unavailable.
# File 'iseq.c', line 4603
static VALUE
iseqw_source_hash(VALUE self)
{
const rb_iseq_t *iseq = iseqw_check(self);
if (!ISEQ_BODY(iseq)->has_source_hash) return Qnil;
return ULL2NUM(ISEQ_BODY(iseq)->source_hash);
}
#syntax_tree ⇒ Prism::Node | {RubyVM::AbstractSyntaxTree::Node} | nil
Returns the AST node that this instruction sequence was compiled from,
by re-parsing the source with the same parser that compiled it: a
Prism::Node if it was compiled by prism, or a
AbstractSyntaxTree::Node if it was compiled by parse.y.
Returns nil whenever the node cannot be retrieved reliably. For
example: the source is not available (such as eval'ed code without
RubyVM.keep_script_lines enabled), or the source file has been modified
since it was compiled.
When a prism gem other than the default gem is loaded, a warning is emitted in verbose mode. In that case, the loaded prism may parse the source differently from the parser that compiled the instruction sequence, and the returned node may not correspond to the code that was actually executed.
This method is experimental and might change without notice.
# File 'ast.rb', line 357
def syntax_tree source_hash = self.source_hash return nil unless source_hash # When the source is kept in memory (RubyVM.keep_script_lines), use it # instead of the file. This also works for eval'ed code. if (lines = script_lines) source = lines.join else path = absolute_path return nil unless path && File.file?(path) end node_id = self.node_id if Primitive.iseq_compiled_by_prism_p require "prism" # Only the default gem prism is the same parser as the one built into # the interpreter. Another prism gem is still likely to parse the # source in the same way, so continue with a warning. if $VERBOSE && (spec = defined?(Gem) && Gem.loaded_specs["prism"]) && !spec.default_gem? warn "syntax_tree: a prism gem other than the default gem is loaded; " \ "the result may not correspond exactly to the compiled code" end begin result = source ? Prism.parse(source, version: "current") : Prism.parse_file(path, version: "current") rescue ArgumentError # The loaded prism does not know the grammar of the running Ruby. return nil end return nil unless result.success? # Hash exactly the bytes that prism parsed. The data section after an # __END__ marker is not part of the code, so the hash covers the source # only up to the end of the __END__ line. code = result.source.source if (data_loc = result.data_loc) && (eol = code.byteindex("\n", data_loc.start_offset)) code = code.byteslice(0, eol + 1) end return nil unless Primitive.source_hash_of(code) == source_hash root = result.value else begin root = source ? RubyVM::AbstractSyntaxTree.parse(source, keep_script_lines: true) : RubyVM::AbstractSyntaxTree.parse_file(path, keep_script_lines: true) rescue SyntaxError # The source has been modified into invalid Ruby. return nil end return nil unless Primitive.ast_node_source_hash(root) == source_hash return Primitive.ast_node_find(root, node_id) end return root if root.node_id == node_id queue = [root] while (node = queue.shift) node.compact_child_nodes.each do |child| if child.node_id == node_id # A block iseq refers to the block node itself. Return the outer # node that owns the block (a CallNode, SuperNode, or # ForwardingSuperNode) instead. return child.type == :block_node ? node : child end queue << child end end nil end
#to_a ⇒ Array
Returns an ::Array with 14 elements representing the instruction sequence
with the following data:
[magic]
A string identifying the data format. Always
YARVInstructionSequence/SimpleDataFormat.
[major_version] The major version of the instruction sequence.
[minor_version] The minor version of the instruction sequence.
[format_type] A number identifying the data format. Always 1.
[misc] A hash containing:
[:arg_size]
the total number of arguments taken by the method or the block (0 if
_iseq_ doesn't represent a method or block)
[:local_size]
the number of local variables + 1
[:stack_max]
used in calculating the stack depth at which a SystemStackError is
thrown.
[#label] The name of the context (block, method, class, module, etc.) that this instruction sequence belongs to.
<code><main></code> if it's at the top level, <code><compiled></code> if
it was evaluated from a string.
[#path] The relative path to the Ruby file where the instruction sequence was loaded from.
<code><compiled></code> if the iseq was evaluated from a string.
[#absolute_path] The absolute path to the Ruby file where the instruction sequence was loaded from.
{nil} if the iseq was evaluated from a string.
[#first_lineno] The number of the first source line where the instruction sequence was loaded from.
[type] The type of the instruction sequence.
Valid values are {:top}, {:method}, {:block}, {:class}, {:rescue},
{:ensure}, {:eval}, {:main}, and {plain}.
[locals] An array containing the names of all arguments and local variables as symbols.
[params] An Hash object containing parameter information.
More info about these values can be found in {vm_core.h}.
[catch_table] A list of exceptions and control flow operators (rescue, next, redo, break, etc.).
[bytecode] An array of arrays containing the instruction names and operands that make up the body of the instruction sequence.
Note that this format is MRI specific and version dependent.
# File 'iseq.c', line 2350
static VALUE
iseqw_to_a(VALUE self)
{
const rb_iseq_t *iseq = iseqw_check(self);
return iseq_data_to_ary(iseq);
}
#to_binary(extra_data = nil) ⇒ binary str
Returns serialized iseq binary format data as a ::String object.
A corresponding iseq object is created by
.load_from_binary() method.
::String extra_data will be saved with binary data.
You can access this data with
.load_from_binary_extra_data(binary).
Note that the translated binary data is not portable.
You can not move this binary data to another machine.
You can not use the binary data which is created by another
version/another architecture of ::Ruby.
# File 'iseq.c', line 4402
static VALUE
iseqw_to_binary(int argc, VALUE *argv, VALUE self)
{
VALUE opt = !rb_check_arity(argc, 0, 1) ? Qnil : argv[0];
return rb_iseq_ibf_dump(iseqw_check(self), opt);
}
#trace_points ⇒ Array
Return trace points in the instruction sequence. Return an array of [line, event_symbol] pair.
# File 'iseq.c', line 3237
static VALUE
iseqw_trace_points(VALUE self)
{
const rb_iseq_t *iseq = iseqw_check(self);
const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
unsigned int i;
VALUE ary = rb_ary_new();
for (i=0; i<body->insns_info.size; i++) {
const struct iseq_insn_info_entry *entry = &body->insns_info.body[i];
if (entry->events) {
push_event_info(iseq, entry->events, entry->line_no, ary);
}
}
return ary;
}