Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby Internals V3

Ruby Internals V3

How Ruby code gets executed by MRI

Mario Alberto Chávez

September 08, 2017
Tweet

More Decks by Mario Alberto Chávez

Other Decks in Technology

Transcript

  1. michelada.io on_int 10 . on_ident “times” on_kw “do” | on_ident

    “i” | on_ident “puts” on_ident “i” on_kw “end”
  2. michelada.io require ‘ripper’ require ‘pp’ code = <<STR 
 10.times

    do |i| puts i end
 STR
 
 pp Ripper.lex(code)
  3. michelada.io [[[1, 0], :on_int, "10"], [[1, 2], :on_period, "."], [[1,

    3], :on_ident, "times"], [[1, 8], :on_sp, " "], [[1, 9], :on_kw, "do"], [[1, 11], :on_sp, " "], [[1, 12], :on_op, "|"], [[1, 13], :on_ident, "i"], [[1, 14], :on_op, "|"], [[1, 15], :on_ignored_nl, "\n"], [[2, 0], :on_ident, "puts"], [[2, 4], :on_sp, " "], [[2, 5], :on_ident, "i"], [[2, 6], :on_nl, "\n"], [[3, 0], :on_kw, "end"], [[3, 3], :on_nl, "\n"]]
  4. michelada.io 10.times do|i| puts i end var ref command args

    add 
 block indetifier “puts” indetifier “i”
  5. michelada.io expr : command_call | expr keyword_and expr { $$

    = logop(idAND, $1, $3); } | expr keyword_or expr { $$ = logop(idOR, $1, $3); }
  6. michelada.io [:program, [[:method_add_block, [:call, [:@int, "10", [1, 0]], :".", [:@ident,

    "times", [1, 3]]], [:do_block, [:block_var, [:params, [[:@ident, "i", [1, 13]]], nil, nil, nil, nil, nil, nil], false], [[:command, [:@ident, "puts", [2, 2]], [:args_add_block, [[:var_ref, [:@ident, "i", [2, 7]]]], false]]]]]]]
  7. michelada.io # | @ NODE_FCALL (line: 1) # | +-

    nd_mid: :puts # | +- nd_args: # | @ NODE_ARRAY (line: 1) # | +- nd_alen: 1 # | +- nd_head: # | | @ NODE_CALL (line: 1) # | | +- nd_mid: :+ # | | +- nd_recv: # | | | @ NODE_LIT (line: 1) # | | | +- nd_lit: 2 # | | +- nd_args: # | | @ NODE_ARRAY (line: 1) # | | +- nd_alen: 1 # | | +- nd_head: # | | | @ NODE_LIT (line: 1) # | | | +- nd_lit: 2 # | | +- nd_next: # | | (null node)
  8. michelada.io puts 2 + 2 NODE_FCALL method_id: “puts” NODE_CALL method_id:

    “+” NODE_LITERAL “2” NODE_LITERAL “2”
  9. michelada.io code = <<STR Puts 2 + 2 STR pp

    RubyVM::InstructionSequence.compile( code).disasm
  10. michelada.io 0000 trace 1 ( 1) 0002 putself 0003 putobject

    2 0005 putobject 2 0007 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE>, <callcache> 0010 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache> 0013 leave
  11. michelada.io puts 2 + 2 NODE_FCALL method_id: “puts” NODE_CALL method_id:

    “+” NODE_LITERAL “2” NODE_LITERAL “2” INSTRUCCIONES YARV putself putobject 2 putobject 2 send :+, 1 send :puts, 1 opt_plus
  12. michelada.io puts 2 + 2 rb_control_frame_t Instrucciones YARV
 putself putobject

    2 putobject 2 opt_plus send :puts, 1 stack interno de YARV 
 self rb_control_frame_t PC SP self type SP PC rb_control_frame_t 2 2 4
  13. michelada.io opt_plus (CALL_INFO ci, CALL_CACHE cc) (VALUE recv, VALUE obj)

    (VALUE val) { val = vm_opt_plus(recv, obj); if (val == Qundef) { /* other */ PUSH(recv); PUSH(obj); CALL_SIMPLE_METHOD(recv); } }