非常教程

Ruby 2.4参考手册

RubyVM

RubyVM::InstructionSequence

Parent:Object

InstructionSequence类表示Ruby虚拟机的已编译指令序列。

有了它,您可以获得构成方法或过程的指令的句柄,将Ruby代码的字符串编译成VM指令,并将指令序列拆分为字符串以便于检查。如果您想要了解Ruby VM的工作原理,那么它非常有用,但它也可以让您控制Ruby iseq编译器的各种设置。

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

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

公共类方法

compile(source[, file[, path[, line, options]]]) → iseq Show source

获取源代码,一串Ruby代码并将其编译为InstructionSequence。

可选择使用文件,路径和行来描述源代码中的ruby代码的文件名,绝对路径和第一行号,这些代码是附加到返回的iseq的元数据。

选项可以是true,false或Hash,用于修改Ruby iseq编译器的默认行为。

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

RubyVM::InstructionSequence.compile("a = 1 + 2")
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
static VALUE
iseqw_s_compile(int argc, VALUE *argv, VALUE self)
{
    VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
    int i;

    rb_secure(1);

    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_cstr("<compiled>");
    if (NIL_P(line)) line = INT2FIX(1);

    return iseqw_new(rb_iseq_compile_with_option(src, file, path, line, 0, opt));
}

compile_file(file, options) → iseq Show source

将包含Ruby源文件位置的String文件读取,解析和编译文件,并返回iseq,这是编译的InstructionSequence,其源位置元数据集已设置。

可以选择使用选项(可以是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, line = INT2FIX(1), opt = Qnil;
    VALUE parser, f, exc = Qnil;
    NODE *node;
    rb_compile_option_t option;
    int i;

    rb_secure(1);
    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");

    parser = rb_parser_new();
    rb_parser_set_context(parser, NULL, FALSE);
    node = rb_parser_compile_file_path(parser, file, f, NUM2INT(line));
    if (!node) exc = GET_THREAD()->errinfo;

    rb_io_close(f);
    if (!node) rb_exc_raise(exc);

    make_compile_option(&option, opt);

    return iseqw_new(rb_iseq_new_with_opt(node, rb_fstring_cstr("<main>"),
                                          file,
                                          rb_realpath_internal(Qnil, file, 1),
                                          line, NULL, ISEQ_TYPE_TOP, &option));
}

compile_option → options Show source

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

有关详细信息,请参阅:: compile_option =。

static VALUE
iseqw_s_compile_option_get(VALUE self)
{
    return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
}

compile_option = options Show source

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

选项的可能值包括true,它启用所有选项,false代表禁用所有选项,而nil代表所有选项不变。

你也可以传递你想改变的哈希选项,任何不存在于哈希中的选项都将保持不变。

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

  • :inline_const_cache
  • :instructions_unification
  • :operands_unification
  • :peephole_optimization
  • :specialized_instruction
  • :stack_caching
  • :tailcall_optimization
  • :trace_instruction

另外,:debug_level可以设置为一个整数。

通过将以上任何一个值作为options参数传递给:: new,:: compile和:: compile_file,这些默认选项可以被islleq编译器的单次运行覆盖。

static VALUE
iseqw_s_compile_option_set(VALUE self, VALUE opt)
{
    rb_compile_option_t option;
    rb_secure(1);
    make_compile_option(&option, opt);
    COMPILE_OPTION_DEFAULT = option;
    return opt;
}

disasm(body) → str Show source

disassemble(body) → str

获取body,Method或Proc对象,并返回一个字符串,其中包含人可读的指令。

对于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 Show source

disassemble(body) → str

获取body,Method或Proc对象,并返回一个字符串,其中包含人可读的指令。

对于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 Show source

从#to_binary创建的二进制格式的String对象加载iseq对象。

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

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

static VALUE
iseqw_s_load_from_binary(VALUE self, VALUE str)
{
    return iseqw_new(iseq_ibf_load(str));
}

RubyVM::InstructionSequence.load_from_binary_extra_data(binary) → str Show source

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

static VALUE
iseqw_s_load_from_binary_extra_data(VALUE self, VALUE str)
{
    return  iseq_ibf_load_extra_data(str);
}

new(source[, file[, path[, line, options]]]) → iseq Show source

获取源代码,一串Ruby代码并将其编译为InstructionSequence。

可选择使用文件,路径和行来描述源代码中的ruby代码的文件名,绝对路径和第一行号,这些代码是附加到返回的iseq的元数据。

选项可以是true,false或Hash,用于修改Ruby iseq编译器的默认行为。

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

RubyVM::InstructionSequence.compile("a = 1 + 2")
#=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
static VALUE
iseqw_s_compile(int argc, VALUE *argv, VALUE self)
{
    VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
    int i;

    rb_secure(1);

    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_cstr("<compiled>");
    if (NIL_P(line)) line = INT2FIX(1);

    return iseqw_new(rb_iseq_compile_with_option(src, file, path, line, 0, opt));
}

of(p1) Show source

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

例如,使用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)>

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

    rb_secure(1);

    if (rb_obj_is_proc(body)) {
        iseq = vm_proc_iseq(body);

        if (!rb_obj_is_iseq((VALUE)iseq)) {
            iseq = NULL;
        }
    }
    else {
        iseq = rb_method_iseq(body);
    }

    return iseq ? iseqw_new(iseq) : Qnil;
}

公共实例方法

absolute_path() Show source

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

nil (如果iseq是从字符串中评估的)。

例如,使用:: 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_absolute_path(iseqw_check(self));
}

base_label() Show source

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

例如,使用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>
static VALUE
iseqw_base_label(VALUE self)
{
    return rb_iseq_base_label(iseqw_check(self));
}

disasm → str Show source

以可读形式返回指令序列作为字符串。

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 → str Show source

以可读形式返回指令序列作为字符串。

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

eval → obj Show source

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

RubyVM::InstructionSequence.compile("1 + 2").eval #=> 3
static VALUE
iseqw_eval(VALUE self)
{
    rb_secure(1);
    return rb_iseq_eval(iseqw_check(self));
}

first_lineno() Show source

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

例如,使用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() Show source

返回此指令序列的人类可读字符串表示形式,包括标签和路径。

static VALUE
iseqw_inspect(VALUE self)
{
    const rb_iseq_t *iseq = iseqw_check(self);

    if (!iseq->body->location.label) {
        return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
    }
    else {
        return rb_sprintf("<%s:%s@%s>",
                          rb_obj_classname(self),
                          RSTRING_PTR(iseq->body->location.label), RSTRING_PTR(iseq->body->location.path));
    }
}

label() Show source

返回此指令序列的标签。

如果<main>位于顶层,则为<compiled>(如果它是从字符串求值的话)。

例如,使用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>
static VALUE
iseqw_label(VALUE self)
{
    return rb_iseq_label(iseqw_check(self));
}

line_trace_all() Show source

实验型的MRI特定功能,只能用于C级api。

返回所有specified_line事件。

VALUE
rb_iseqw_line_trace_all(VALUE iseqw)
{
    VALUE result = rb_ary_new();
    rb_iseqw_line_trace_each(iseqw, collect_trace, (void *)result);
    return result;
}

line_trace_specify(p1, p2) Show source

实验MRI特定功能,只能用于C级api。

如果set参数为true,则在给定的行位置设置一个specified_line事件。

此方法对于在特定行建立调试器断点很有用。

如果set不是布尔值,则会引发TypeError。

如果pos是一个负整数,则会引发TypeError异常。

VALUE
rb_iseqw_line_trace_specify(VALUE iseqval, VALUE pos, VALUE set)
{
    struct set_specifc_data data;

    data.prev = 0;
    data.pos = NUM2INT(pos);
    if (data.pos < 0) rb_raise(rb_eTypeError, "`pos' is negative");

    switch (set) {
      case Qtrue:  data.set = 1; break;
      case Qfalse: data.set = 0; break;
      default:
        rb_raise(rb_eTypeError, "`set' should be true/false");
    }

    rb_iseqw_line_trace_each(iseqval, line_trace_specify, (void *)&data);

    if (data.prev == 0) {
        rb_raise(rb_eTypeError, "`pos' is out of range.");
    }
    return data.prev == 1 ? Qtrue : Qfalse;
}

path() Show source

返回此指令序列的路径。

如果iseq是从字符串中进行评估的话,则为<compiled>。

例如,使用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
static VALUE
iseqw_path(VALUE self)
{
    return rb_iseq_path(iseqw_check(self));
}

to_a → ary Show source

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

magic

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

major_version

指令序列的主要版本。

minor_version

次要版本的指令序列。

format_type

一个标识数据格式的数字。总是1

misc

哈希包含:

:arg_size

该方法或块采用的参数总数(如果iseq不等于0则表示方法或块)

:local_size

局部变量的数量+ 1

:stack_max

用于计算引发SystemStackError的堆栈深度。

 [label](instructionsequence#method-i-label)   

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

如果<main>位于顶层,则为<compiled>,如果它是从字符串求值的话。

path

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

如果iseq是从字符串中评估的,则为<compiled>

absolute_path

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

如果iseq是从字符串评估的,则为零。

first_lineno

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

type

指令序列的类型。

有效值为:top,:method,:block,:class,:rescue,:ensure,:eval,:main和:defined_guard。

locals

包含所有参数和局部变量名称作为符号的数组。

params

包含参数信息的哈希对象。

有关这些值的更多信息可以在vm_core.h中找到。

catch_table

例外和控制流操作员列表(rescue, next, redo, break,等)。

bytecode

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

请注意,这种格式是MRI特定的和版本相关的。

static VALUE
iseqw_to_a(VALUE self)
{
    const rb_iseq_t *iseq = iseqw_check(self);
    rb_secure(1);
    return iseq_data_to_ary(iseq);
}

to_binary(extra_data = nil) → binary str Show source

将串行化的iseq二进制格式数据作为String对象返回。相应的iseq对象由:: load_from_binary方法创建。

字符串extra_data将被保存为二进制数据。您可以使用:: load_from_binary_extra_data访问这些数据。

请注意,翻译后的二进制数据不可移植。你不能将这个二进制数据移动到另一台机器上。您不能使用由Ruby的另一个版本/另一个体系结构创建的二进制数据。

static VALUE
iseqw_to_binary(int argc, VALUE *argv, VALUE self)
{
    VALUE opt;
    rb_scan_args(argc, argv, "01", &opt);
    return iseq_ibf_dump(iseqw_check(self), opt);
}

RubyVM相关

Ruby 2.4

Ruby 是一种面向对象、命令式、函数式、动态的通用编程语言,是世界上最优美而巧妙的语言。

主页 https://www.ruby-lang.org/
源码 https://github.com/ruby/ruby
版本 2.4
发布版本 2.4.1

Ruby 2.4目录

1.缩略 | Abbrev
2.ARGF
3.数组 | Array
4.Base64
5.基本对象 | BasicObject
6.基准测试 | Benchmark
7.BigDecimal
8.绑定 | Binding
9.CGI
10.类 | Class
11.比较 | Comparable
12.负责 | Complex
13.计算续体 | Continuation
14.覆盖 | Coverage
15.CSV
16.日期 | Date
17.日期时间 | DateTime
18.DBM
19.代理 | Delegator
20.摘要 | Digest
21.Dir
22.DRb
23.编码 | Encoding
24.枚举 | Enumerable
25.枚举 | Enumerator
26.ENV
27.ERB
28.错误 | Errors
29.Etc
30.期望值 | Exception
31.错误类 | FalseClass
32.Fiber
33.Fiddle
34.文件 | File
35.文件实用程序 | FileUtils
36.查找 | Find
37.浮点 | Float
38.Forwardable
39.GC
40.GDBM
41.GetoptLong
42.Hash
43.Integer
44.IO
45.IPAddr
46.JSON
47.Kernel
48.语言 | 3Language
49.记录 | Logger
50.编排 | Marshal
51.MatchData
52.数学 | Math
53.矩阵 | Matrix
54.方法 | Method
55.模型 | Module
56.监控 | Monitor
57. 互斥 | Mutex
58.Net
59.Net::FTP
60.Net::HTTP
61.Net::IMAP
62.Net::SMTP
63.NilClass
64.数字 | Numeric
65.对象 | Object
66.ObjectSpace
67.Observable
68.Open3
69.OpenSSL
70.OpenStruct
71.OpenURI
72.OptionParser
73.路径名 | Pathname
74.完整输出 | PrettyPrint
75.Prime
76.Proc
77.过程 | Process
78.PStore
79.PTY
80.队列 | Queue
81.随机 | Random
82.范围 | Range
83.合理的 | Rational
84.Readline
85.Regexp
86.Resolv
87.Ripper
88.RubyVM
89.Scanf
90.SDBM
91.SecureRandom
92.Set
93.Shell
94.信号 | Signal
95.Singleton
96.套接字 | Socket
97.字符串 | String
98.StringIO
99.StringScanner
100.结构 | Struct