is there a way to store a RubyVM::InstructionSequence to a file and read it in later?
I tried Marshal.dump
without success. Im getting the following error:
`dump': no _dump_data is defined for class RubyVM::InstructionSequence (TypeError)
Yes, there is a way.
First, you need make accessible load
method of InstructionSequence
, which is disabled by default:
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
Because the RubyVM::InstructionSequence.load
method can load compiled VM instructions as an array, you can freely use this for (de)serialization purposes:
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 !"
That's all folks ;)
Given that the class has limited methods, there is limited things you can try. Probably the only thing you can do is save its instance as a string:
puts RubyVM::InstructionSequence.disasm(proc{puts "foo"})
Result:
== 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
and when you want to deserialize it, you need to parse this string.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With