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
}