How can I store and read RubyVM :: InstructionSequence?

Is there a way to save RubyVM :: InstructionSequence in a file and read it later?

I tried Marshal.dump without success. Im getting the following error:

 `dump': no _dump_data is defined for class RubyVM::InstructionSequence (TypeError) 
+5
source share
2 answers

Yes, there is a way.

First you need to make the InstructionSequence method available to the load , which is disabled by default:

 require 'fiddle' class RubyVM::InstructionSequence # Retrieve Ruby Core 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 

Since the RubyVM::InstructionSequence.load method can load compiled VM instructions as an array, you can freely use this for serialization (de) 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 !" 

What are all people;)

+11
source

Given that a class has limited methods, there are 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 if you want to deserialize it, you need to parse this line.

+2
source

All Articles