在线文档教程
Ruby 2.4

RubyVM::InstructionSequence

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 }