类 RubyVM::InstructionSequence

The InstructionSequence 类表示 MRI 中使用的虚拟机编译的指令序列。并非所有 Ruby 实现都可能实现此类,对于实现它的实现,定义的方法和方法的行为可能会在任何版本中发生变化。

使用它,您可以获取构成方法或 proc 的指令的句柄,将 Ruby 代码字符串编译为 VM 指令,并将指令序列反汇编为字符串以方便检查。如果您想了解 YARV 的工作原理,它非常有用,但它还允许您控制 Ruby iseq 编译器的各种设置。

您可以在 Ruby 源代码中的 insns.def 中找到 VM 指令的源代码。

指令序列结果几乎肯定会随着 Ruby 的变化而变化,因此本文档中的示例输出可能与您看到的不同。

当然,此类是 MRI 特定的。

公共类方法

compile(source[, file[, path[, line[, options]]]]) → iseq 点击切换源代码
new(source[, file[, path[, line[, options]]]]) → iseq

接受 source,它可以是 Ruby 代码字符串,也可以是包含 Ruby 源代码的打开的 File 对象。

可选地接受 filepathline,它们描述了 source 中的 Ruby 代码的文件路径、真实路径和第一行号,这些是附加到返回的 iseq 的元数据。

file 用于 ‘__FILE__` 和异常回溯。path 用于 require_relative 基准。建议这些应该是相同的完整路径。

options 可以是 truefalseHash,用于修改 Ruby iseq 编译器的默认行为。

有关有效编译选项的详细信息,请参阅 ::compile_option=.

RubyVM::InstructionSequence.compile("a = 1 + 2")
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>

path = "test.rb"
RubyVM::InstructionSequence.compile(File.read(path), path, File.expand_path(path))
#=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>

file = File.open("test.rb")
RubyVM::InstructionSequence.compile(file)
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>

path = File.expand_path("test.rb")
RubyVM::InstructionSequence.compile(File.read(path), path, path)
#=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
static VALUE
iseqw_s_compile(int argc, VALUE *argv, VALUE self)
{
    VALUE src, file = Qnil, path = Qnil, line = Qnil, opt = Qnil;
    int i;

    i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
    if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
    switch (i) {
      case 5: opt = argv[--i];
      case 4: line = argv[--i];
      case 3: path = argv[--i];
      case 2: file = argv[--i];
    }

    if (NIL_P(file)) file = rb_fstring_lit("<compiled>");
    if (NIL_P(path)) path = file;
    if (NIL_P(line)) line = INT2FIX(1);

    Check_Type(path, T_STRING);
    Check_Type(file, T_STRING);

    return iseqw_new(rb_iseq_compile_with_option(src, file, path, line, opt));
}
compile_file(file[, options]) → iseq 点击切换源代码

接收 `file`,一个指向 Ruby 源代码文件的 String,读取、解析和编译该文件,并返回 `iseq`,即已编译的 InstructionSequence,其中包含已设置的源代码位置元数据。

可选地接收 `options`,可以是 `true`、`false` 或一个 `Hash`,用于修改 Ruby iseq 编译器的默认行为。

有关有效编译选项的详细信息,请参阅 ::compile_option=.

# /tmp/hello.rb
puts "Hello, world!"

# elsewhere
RubyVM::InstructionSequence.compile_file("/tmp/hello.rb")
#=> <RubyVM::InstructionSequence:<main>@/tmp/hello.rb>
static VALUE
iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
{
    VALUE file, opt = Qnil;
    VALUE parser, f, exc = Qnil, ret;
    rb_ast_t *ast;
    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 = (rb_ast_t *)rb_parser_load_file(parser, file);
    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->body, rb_fstring_lit("<main>"),
                                         file,
                                         rb_realpath_internal(Qnil, file, 1),
                                         1, NULL, 0, ISEQ_TYPE_TOP, &option));
    rb_ast_dispose(ast);

    rb_vm_pop_frame(ec);
    RB_GC_GUARD(v);
    return ret;
}
compile_file_prism(p1, *args, p3 = {}) 点击切换源代码
static VALUE
iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self)
{
    VALUE file = Qnil, opt = Qnil;
    int i;

    i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
    if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 5);
    switch (i) {
      case 2: opt = argv[--i];
    }
    FilePathValue(file);
    file = rb_fstring(file); /* rb_io_t->pathv gets frozen anyways */

    pm_string_t input;
    pm_string_mapped_init(&input, RSTRING_PTR(file));

    pm_options_t options = { 0 };
    pm_options_filepath_set(&options, RSTRING_PTR(file));

    pm_parser_t parser;
    pm_parser_init(&parser, pm_string_source(&input), pm_string_length(&input), &options);

    rb_iseq_t *iseq = iseq_alloc();
    iseqw_s_compile_prism_compile(&parser, opt, iseq, file, rb_realpath_internal(Qnil, file, 1), 1);
    pm_parser_free(&parser);
    pm_string_free(&input);
    pm_options_free(&options);

    return iseqw_new(iseq);
}
compile_option → options 点击切换源代码

返回 Ruby iseq 编译器使用的默认选项的哈希表。

有关详细信息,请参阅 InstructionSequence.compile_option=

static VALUE
iseqw_s_compile_option_get(VALUE self)
{
    return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
}
compile_option = options 点击切换源代码

设置 Ruby iseq 编译器中各种优化的默认值。

options 的可能值包括 `true`,它启用所有选项,`false` 它禁用所有选项,以及 `nil` 它保持所有选项不变。

您还可以传递一个 `Hash`,其中包含要更改的 `options`,哈希表中不存在的任何选项将保持不变。

可以设置为 `true` 或 `false` 的可能选项名称(它们是 `options` 中的键)包括

  • :inline_const_cache

  • :instructions_unification

  • :operands_unification

  • :peephole_optimization

  • :specialized_instruction

  • :tailcall_optimization

此外,`:debug_level` 可以设置为整数。

这些默认选项可以通过将上述任何值作为 `options` 参数传递给 ::new::compile::compile_file 来覆盖单个 iseq 编译器运行。

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;
}
compile_prism(p1, *args, p3 = {}) 点击切换源代码
static VALUE
iseqw_s_compile_prism(int argc, VALUE *argv, VALUE self)
{
    VALUE src, file = Qnil, path = Qnil, line = Qnil, opt = Qnil;
    int i;

    i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
    if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
    switch (i) {
      case 5: opt = argv[--i];
      case 4: line = argv[--i];
      case 3: path = argv[--i];
      case 2: file = argv[--i];
    }

    if (NIL_P(file)) file = rb_fstring_lit("<compiled>");
    if (NIL_P(path)) path = file;
    if (NIL_P(line)) line = INT2FIX(1);

    Check_Type(path, T_STRING);
    Check_Type(file, T_STRING);

    pm_options_t options = { 0 };
    pm_options_filepath_set(&options, RSTRING_PTR(file));

    int start_line = NUM2INT(line);
    pm_options_line_set(&options, start_line);

    pm_parser_t parser;

    if (RB_TYPE_P(src, T_FILE)) {
        FilePathValue(src);
        file = rb_fstring(src); /* rb_io_t->pathv gets frozen anyways */

        pm_string_t input;
        pm_string_mapped_init(&input, RSTRING_PTR(file));

        pm_parser_init(&parser, pm_string_source(&input), pm_string_length(&input), &options);
    }
    else {
        pm_parser_init(&parser, (const uint8_t *) RSTRING_PTR(src), RSTRING_LEN(src), &options);
    }

    rb_iseq_t *iseq = iseq_alloc();
    iseqw_s_compile_prism_compile(&parser, opt, iseq, file, path, start_line);
    pm_parser_free(&parser);
    pm_options_free(&options);

    return iseqw_new(iseq);
}
disasm(body) → str 点击切换源代码
disassemble(body) → str

接收 `body`,一个 MethodProc 对象,并返回一个 String,其中包含 `body` 的人类可读指令。

对于 Method 对象

# /tmp/method.rb
def hello
  puts "hello, world"
end

puts RubyVM::InstructionSequence.disasm(method(:hello))

生成

== disasm: <RubyVM::InstructionSequence:hello@/tmp/method.rb>============
0000 trace            8                                               (   1)
0002 trace            1                                               (   2)
0004 putself
0005 putstring        "hello, world"
0007 send             :puts, 1, nil, 8, <ic:0>
0013 trace            16                                              (   3)
0015 leave                                                            (   2)

对于 Proc

# /tmp/proc.rb
p = proc { num = 1 + 2 }
puts RubyVM::InstructionSequence.disasm(p)

生成

== 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
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));
}
disasm(body) → str 点击切换源代码
disassemble(body) → str

接收 `body`,一个 MethodProc 对象,并返回一个 String,其中包含 `body` 的人类可读指令。

对于 Method 对象

# /tmp/method.rb
def hello
  puts "hello, world"
end

puts RubyVM::InstructionSequence.disasm(method(:hello))

生成

== disasm: <RubyVM::InstructionSequence:hello@/tmp/method.rb>============
0000 trace            8                                               (   1)
0002 trace            1                                               (   2)
0004 putself
0005 putstring        "hello, world"
0007 send             :puts, 1, nil, 8, <ic:0>
0013 trace            16                                              (   3)
0015 leave                                                            (   2)

对于 Proc

# /tmp/proc.rb
p = proc { num = 1 + 2 }
puts RubyVM::InstructionSequence.disasm(p)

生成

== 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
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));
}
RubyVM::InstructionSequence.load_from_binary(binary) → iseq 点击切换源代码

从由 RubyVM::InstructionSequence.to_binary 创建的二进制格式 String 对象加载 iseq 对象。

此加载器没有验证器,因此加载损坏/修改的二进制文件会导致严重问题。

您不应该加载他人提供的二进制数据。您应该使用自己翻译的二进制数据。

static VALUE
iseqw_s_load_from_binary(VALUE self, VALUE str)
{
    return iseqw_new(rb_iseq_ibf_load(str));
}
RubyVM::InstructionSequence.load_from_binary_extra_data(binary) → str 点击切换源代码

加载嵌入到二进制格式 String 对象中的额外数据。

static VALUE
iseqw_s_load_from_binary_extra_data(VALUE self, VALUE str)
{
    return rb_iseq_ibf_load_extra_data(str);
}
compile(source[, file[, path[, line[, options]]]]) → iseq 点击切换源代码
new(source[, file[, path[, line[, options]]]]) → iseq

接受 source,它可以是 Ruby 代码字符串,也可以是包含 Ruby 源代码的打开的 File 对象。

可选地接受 filepathline,它们描述了 source 中的 Ruby 代码的文件路径、真实路径和第一行号,这些是附加到返回的 iseq 的元数据。

file 用于 ‘__FILE__` 和异常回溯。path 用于 require_relative 基准。建议这些应该是相同的完整路径。

options 可以是 truefalseHash,用于修改 Ruby iseq 编译器的默认行为。

有关有效编译选项的详细信息,请参阅 ::compile_option=.

RubyVM::InstructionSequence.compile("a = 1 + 2")
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>

path = "test.rb"
RubyVM::InstructionSequence.compile(File.read(path), path, File.expand_path(path))
#=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>

file = File.open("test.rb")
RubyVM::InstructionSequence.compile(file)
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>

path = File.expand_path("test.rb")
RubyVM::InstructionSequence.compile(File.read(path), path, path)
#=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
static VALUE
iseqw_s_compile(int argc, VALUE *argv, VALUE self)
{
    VALUE src, file = Qnil, path = Qnil, line = Qnil, opt = Qnil;
    int i;

    i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
    if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
    switch (i) {
      case 5: opt = argv[--i];
      case 4: line = argv[--i];
      case 3: path = argv[--i];
      case 2: file = argv[--i];
    }

    if (NIL_P(file)) file = rb_fstring_lit("<compiled>");
    if (NIL_P(path)) path = file;
    if (NIL_P(line)) line = INT2FIX(1);

    Check_Type(path, T_STRING);
    Check_Type(file, T_STRING);

    return iseqw_new(rb_iseq_compile_with_option(src, file, path, line, opt));
}
of(p1) 点击切换源代码

返回包含给定 proc 或方法的指令序列。

例如,使用 irb

# a proc
> p = proc { num = 1 + 2 }
> RubyVM::InstructionSequence.of(p)
> #=> <RubyVM::InstructionSequence:block in irb_binding@(irb)>

# for a method
> def foo(bar); puts bar; end
> RubyVM::InstructionSequence.of(method(:foo))
> #=> <RubyVM::InstructionSequence:foo@(irb)>

使用 ::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>
static VALUE
iseqw_s_of(VALUE klass, VALUE body)
{
    const rb_iseq_t *iseq = NULL;

    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;
}

公共实例方法

absolute_path() 点击切换源代码

返回此指令序列的绝对路径。

如果 iseq 是从字符串中评估的,则为 nil

例如,使用 ::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
static VALUE
iseqw_absolute_path(VALUE self)
{
    return rb_iseq_realpath(iseqw_check(self));
}
base_label() 点击切换源代码

返回此指令序列的基本标签。

例如,使用 irb

iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
iseq.base_label
#=> "<compiled>"

使用 ::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>
static VALUE
iseqw_base_label(VALUE self)
{
    return rb_iseq_base_label(iseqw_check(self));
}
disasm → str 点击切换源代码

以人类可读的形式将指令序列作为 String 返回。

puts RubyVM::InstructionSequence.compile('1 + 2').disasm

生成

== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
0000 trace            1                                               (   1)
0002 putobject        1
0004 putobject        2
0006 opt_plus         <ic:1>
0008 leave
static VALUE
iseqw_disasm(VALUE self)
{
    return rb_iseq_disasm(iseqw_check(self));
}
也称为:disassemble,disassemble
disassemble → str

以人类可读的形式将指令序列作为 String 返回。

puts RubyVM::InstructionSequence.compile('1 + 2').disasm

生成

== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
0000 trace            1                                               (   1)
0002 putobject        1
0004 putobject        2
0006 opt_plus         <ic:1>
0008 leave
别名:disasm
each_child{|child_iseq| ...} → iseq 点击切换源代码

迭代所有直接子指令序列。迭代顺序由实现/版本定义,因此人们不应该依赖顺序。

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 → obj 点击切换源代码

评估指令序列并返回结果。

RubyVM::InstructionSequence.compile("1 + 2").eval #=> 3
static VALUE
iseqw_eval(VALUE self)
{
    return rb_iseq_eval(iseqw_check(self));
}
first_lineno() 点击切换源代码

返回加载指令序列的第一个源代码行的行号。

例如,使用 irb

iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
iseq.first_lineno
#=> 1
static VALUE
iseqw_first_lineno(VALUE self)
{
    return rb_iseq_first_lineno(iseqw_check(self));
}
inspect() 点击切换源代码

返回此指令序列的人类可读的字符串表示形式,包括 labelpath

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() 点击切换源代码

返回此指令序列的标签。

如果在顶层,则为<main>,如果从字符串中求值,则为<compiled>

例如,使用 irb

iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
iseq.label
#=> "<compiled>"

使用 ::compile_file

# /tmp/method.rb
def hello
  puts "hello, world"
end

# in irb
> iseq = RubyVM::InstructionSequence.compile_file('/tmp/method.rb')
> iseq.label #=> <main>
static VALUE
iseqw_label(VALUE self)
{
    return rb_iseq_label(iseqw_check(self));
}
path() 点击切换源代码

返回此指令序列的路径。

如果 iseq 从字符串中求值,则为<compiled>

例如,使用 irb

iseq = RubyVM::InstructionSequence.compile('num = 1 + 2')
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
iseq.path
#=> "<compiled>"

使用 ::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
static VALUE
iseqw_path(VALUE self)
{
    return rb_iseq_path(iseqw_check(self));
}
script_lines → array 或 nil 点击切换源代码

如果可用,它将返回记录的脚本行。脚本行不限于 iseq 范围,而是源文件的完整行。

请注意,这是一个用于 Ruby 内部使用、调试和研究的 API。不要将其用于任何其他目的。兼容性无法保证。

static VALUE
iseqw_script_lines(VALUE self)
{
    const rb_iseq_t *iseq = iseqw_check(self);
    return ISEQ_BODY(iseq)->variable.script_lines;
}
to_a → ary 点击切换源代码

返回一个包含 14 个元素的Array,表示使用以下数据的指令序列

magic

标识数据格式的字符串。始终为YARVInstructionSequence/SimpleDataFormat

major_version

指令序列的主版本。

minor_version

指令序列的次版本。

format_type

标识数据格式的数字。始终为 1

misc

包含以下内容的哈希表

:arg_size

方法或块接受的总参数数量(如果iseq不代表方法或块,则为 0)

:local_size

局部变量数量 + 1

:stack_max

用于计算抛出SystemStackError的堆栈深度。

label

此指令序列所属的上下文(块、方法、类、模块等)的名称。

如果在顶层,则为<main>,如果从字符串中求值,则为<compiled>

path

加载指令序列的 Ruby 文件的相对路径。

如果 iseq 从字符串中求值,则为<compiled>

absolute_path

加载指令序列的 Ruby 文件的绝对路径。

如果 iseq 是从字符串中评估的,则为 nil

first_lineno

指令序列加载的第一个源代码行的行号。

类型

指令序列的类型。

有效值为 :top:method:block:class:rescue:ensure:eval:mainplain

局部变量

包含所有参数和局部变量名称的数组(以符号形式表示)。

参数

包含参数信息的 Hash 对象。

有关这些值的更多信息,请参阅 vm_core.h

捕获表

异常和控制流运算符(rescue、next、redo、break 等)的列表。

字节码

包含指令名称和操作数的数组,这些指令名称和操作数构成了指令序列的主体。

请注意,此格式是 MRI 特定的,并且依赖于版本。

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 点击切换源代码

将序列化后的 iseq 二进制格式数据作为 String 对象返回。相应的 iseq 对象由 RubyVM::InstructionSequence.load_from_binary() 方法创建。

String extra_data 将与二进制数据一起保存。您可以使用 RubyVM::InstructionSequence.load_from_binary_extra_data(binary) 访问此数据。

请注意,转换后的二进制数据不可移植。您不能将此二进制数据移动到另一台机器。您不能使用由另一个版本的 Ruby 或另一个架构的 Ruby 创建的二进制数据。

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 → ary 点击切换源代码

返回指令序列中的跟踪点。返回一个包含 [行号,事件符号] 对的数组。

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;
}