[英]How can I store and read a RubyVM::InstructionSequence?
有沒有辦法將 RubyVM::InstructionSequence 存儲到文件並稍后讀取?
我試過Marshal.dump
沒有成功。 我收到以下錯誤:
`dump': no _dump_data is defined for class RubyVM::InstructionSequence (TypeError)
是的,有辦法。
首先,您需要創建可訪問的InstructionSequence
load
方法,默認情況下該方法是禁用的:
require 'fiddle'
class RubyVM::InstructionSequence
# Retrieve Ruby Core's C-ext `iseq_load' function address
load_fn_addr = Fiddle::Handle::DEFAULT['rb_iseq_load']
# Retrieve `iseq_load' C function representation
load_fn = Fiddle::Function.new(load_fn_addr,
[Fiddle::TYPE_VOIDP] * 3,
Fiddle::TYPE_VOIDP)
# Make `iseq_load' accessible as `load' class method
define_singleton_method(:load) do |data, parent = nil, opt = nil|
load_fn.call(Fiddle.dlwrap(data), parent, opt).to_value
end
end
由於RubyVM::InstructionSequence.load
方法可以將已編譯的 VM 指令作為數組加載,因此您可以自由地將其用於(反)序列化目的:
irb> # compile simple ruby program into its instruction sequence
irb> seq = RubyVM::InstructionSequence.new <<-EOS
irb: p 'Hello, world !'
irb: EOS
=> <RubyVM::InstructionSequence:<compiled>@<compiled>
irb> # serialize sequence as Array instance representation
irb> data = Marshal.dump seq.to_a
=> "\x04\b[\x13\"-YARVInstructionSequence/SimpleDataFormat … ]"
irb> # de-serialize previously serialized sequence
irb> seq_loaded = Marshal.load data
=> ["YARVInstructionSequence/SimpleDataFormat", 2, 2, 1, { … ]
irb> # load deserialized Array back into instruction sequence
irb> new_iseq = RubyVM::InstructionSequence.load seq_loaded
=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
irb> # execute instruction sequence in current context
irb> new_iseq.eval
"Hello, world !"
=> "Hello, world !"
這就是所有人;)
鑒於該類的方法有限,您可以嘗試的東西也有限。 可能你唯一能做的就是將它的實例保存為一個字符串:
puts RubyVM::InstructionSequence.disasm(proc{puts "foo"})
結果:
== disasm: <RubyVM::InstructionSequence:block in irb_binding@(irb)>=====
== catch table
| catch type: redo st: 0002 ed: 0009 sp: 0000 cont: 0002
| catch type: next st: 0002 ed: 0009 sp: 0000 cont: 0009
|------------------------------------------------------------------------
0000 trace 256 ( 1)
0002 trace 1
0004 putself
0005 putstring \"foo\"
0007 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>
0009 trace 512
0011 leave
當你想反序列化它時,你需要解析這個字符串。
這很簡單。
iseq = RubyVM::InstructionSequence.compile("a = 1 + 2") # just an example
File.open('iseq.bin', 'wb') { |file| file.write iseq.to_binary }
# later
RubyVM::InstructionSequence.load_from_binary(File.read('iseq.bin')).eval # returns 3
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.