Подтвердить что ты не робот

Как наблюдать байт-код Ruby, выполненный YARV

Я хотел бы наблюдать байт-код Ruby, выполненный YARV, post mortem.

Как я могу получить это?

Кто-то еще здесь сказал, что это невозможно. Тем не менее, существует hotruby, которая, похоже, выполняет рубиновый байт-код, поэтому я озадачен...

Спасибо большое!

4b9b3361

Ответ 1

Вы можете очень хорошо скомпилировать кусок кода Ruby для байт-кода с помощью интерпретатора (конечно, будет работать только Ruby MRI 1.9, поскольку это единственная реализация, которая использует виртуальную машину YARV) и получить ее Ruby- ish:

ruby-1.9.2-p180 :007 > require 'pp'
 => true
ruby-1.9.2-p180 :008 > pp RubyVM::InstructionSequence.compile('puts "hello world"').to_a
["YARVInstructionSequence/SimpleDataFormat",
 1,
 2,
 1,
 {:arg_size=>0, :local_size=>1, :stack_max=>2},
 "<compiled>",
 "<compiled>",
 nil,
 1,
 :top,
 [],
 0,
 [],
 [1,
  [:trace, 1],
  [:putnil],
  [:putstring, "hello world"],
  [:send, :puts, 1, nil, 8, 0],
  [:leave]]]

Это именно то, что делает HotRuby: он использует MRI как синтаксический анализатор и переводчик AST-to-YARV, а затем просто выполняет код в JavaScript.

Вы можете получить байт-код для существующего метода с помощью метода RubyVM::InstructionSequence.disasm. Он ожидает Proc в качестве аргумента, поэтому сначала преобразуйте свой метод в блок с помощью object.method(:name).to_proc.

Я не совсем уверен, что вы подразумеваете под "посмертным". В обработчике исключений? После того, как Ruby разбился с SEGV? Последнее вряд ли возможно из-за неспособности поврежденного интерпретатора успешно запустить любой код Ruby. Вам нужно сделать расширение C для этого и сделать довольно много грязных хаков. Использование этого трюка в обработчике исключений вполне возможно, через.

Ответ 2

Насколько я понимаю, RubyVM::InstructionSequence.compile - это то, что вам нужно.

Ответ 3

Чтобы получить более читаемый вывод, вы можете использовать disasm после compile

[17] pry(main)> code = <<STR
[17] pry(main)* puts "Hello World"
[17] pry(main)* STR
=> "puts \"Hello World\"\n"
[19] pry(main)> puts RubyVM::InstructionSequence.compile(code).disasm
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
0000 trace            1                                               (   1)
0002 putself
0003 putstring        "Hello World"
0005 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>
0007 leave
=> nil
[20] pry(main)>