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

What is the BEAM?

What is the BEAM?

A quick exploration will reveal the BEAM has to do with how Erlang code is executed and is the secret sauce uniting all of us - Erlang, Elixir, LFE, Efene and others. But do you really know what it is? In this talk, Michał will carefully explore the BEAM, both the runtime and the compiler. We'll see how they relate, what particular strengths this gives to our code and how we can leverage it from the applications we write every day in Erlang and Elixir. Finally, we'll see how the BEAM is similar and different to other environments and languages like Java's JVM, C#'s CLR or Lua.

Michał Muskała

April 02, 2020
Tweet

More Decks by Michał Muskała

Other Decks in Programming

Transcript

  1. @michalmuskala QUICK HISTORY OF ERLANG • Prolog library (1986) •

    Joe’s Abstract Machine (1989) • Turbo Erlang Abstract Machine • Bogdan’s Erlang Abstract Machine • Virding’s Erlang Engine • Björn’s Erlang Abstract Machine
  2. @michalmuskala STACK VM VS REGISTER VM Virtual Machine Showdown: Stack

    vs Registers https://www.usenix.org/legacy/events/vee05/full_papers/p153-yunhe.pdf
  3. @michalmuskala BEAM • Register-based VM • Threaded emulator • Per-process

    GC with shared large-object heap • Tail recursion • First-class closures • Immutable data • No custom data types • low-level messaging primitives • NIFs/BIFs • Tracing
  4. @michalmuskala BYTECODE • 1024 general X registers • stack slots

    referred to as Y registers • exchange format between the compiler and the runtime system
  5. LITERALS test() -> [1, 2, #{a => 5}, foo]. {function,

    test, 0, 2}. {label,2}. {move,{literal,[1,2, #{a => 5},foo]},{x,0}}. return.
  6. STACK ALLOCATION & TAIL RECURSION defp id(x), do: x def

    test(a, b), do: id(id(a) + id(b)) {function, test, 2, 12}. {label,12}. {allocate,1,2}. {move,{x,1},{y,0}}. {call,1,{f,10}}. {move,{x,0},{x,1}}. {move,{y,0},{x,0}}. {move,{x,1},{y,0}}. {call,1,{f,10}}. {gc_bif,'+',{f,0},1,[{y,0},{x,0}],{x,0}}. {call_last,1,{f,10},1}.
  7. MULTI-WAY BRANCH def test(x) do case x do 0 ->

    "zero" 1 -> "one" 2 -> "two" end end {function, test, 1, 10}. {label,10}. {test,is_integer,{f,14},[{x,0}]}. {select_val,{x,0},{f,14}, {list,[{integer,0},{f,11}, {integer,1},{f,12}, {integer,2},{f,13}]}}. {label,11}. {move,{literal, <<"zero" >>},{x,0}}. return. {label,12}. {move,{literal, <<"one" >>},{x,0}}. return. {label,13}. {move,{literal, <<"two" >>},{x,0}}. return. {label,14}. {case_end,{x,0}}.
  8. @michalmuskala THE LOADER • maps .beam instructions to VM instructions

    • fuses some common instruction sequences • specialises instructions working on constants or registers • ops.tab and beam_makeops
  9. @michalmuskala THE LOADER move S=cxy x ==0 | call Ar

    P=f => move_call S P i_increment rxy W t d i_plus x xy j? t d i_plus s s j? t d new_map d t I i_new_small_map_lit d t q update_map_assoc s d t I update_map_exact j? s d t I
  10. LITERALS test() -> [1, 2, #{a => 5}, foo]. 00000000582FB1E8:

    i_func_info_IaaI 0 test test 0 00000000582FB210: move_return_c [1,2, #{a =>5},foo]
  11. STACK ALLOCATION & TAIL RECURSION defp id(x), do: x def

    test(a, b), do: id(id(a) + id(b)) 000000001DEBA7B8: i_func_info_IaaI 0 'Elixir.Test' test 2 000000001DEBA7E0: allocate_tt 1 2 000000001DEBA7E8: move_xy x(1) y(0) 000000001DEBA7F0: i_call_f 'Elixir.Test':id/1 000000001DEBA7F8: swap_xy x(0) y(0) 000000001DEBA800: i_call_f 'Elixir.Test':id/1 000000001DEBA808: i_plus_ssjtd y(0) x(0) j(0) 1 x(0) 000000001DEBA830: i_call_last_fQ 'Elixir.Test':id/1 1
  12. MULTI-WAY BRANCH def test(x) do case x do 0 ->

    "zero" 1 -> "one" 2 -> "two" end end 0000000014758100: i_func_info_IaaI 0 'Elixir.Test' test 1 0000000014758128: i_jump_on_val_zero_xfI x(0) f(0000000014758178) 3 f(0000000014758148) f(0000000014758168) f(0000000014758158) 0000000014758148: move_return_c <<"zero" >> 0000000014758158: move_return_c <<"two" >> 0000000014758168: move_return_c <<"one" >> 0000000014758178: case_end_x x(0)
  13. @michalmuskala THE ROAD TO .BEAM Elixir Source Elixir AST Erlang

    Abstract Format Core Erlang Kernel Erlang BEAM SSA BEAM Erlang Source
  14. CORE ERLANG module 'test' ['module_info'/0, 'module_info'/1,'test'/3] attributes [ 'file' =

    [{[116|[101|[115|[116|[46|[101|[114|[108]]]]]]]],1}], 'compile' = ['export_all']] 'test'/3 = fun (_2,_1,_0) -> case <_2,_1,_0> of <'sum',X,Y> when 'true' -> call 'erlang':'+'(X, Y) <'diff',X,Y> when 'true' -> call 'erlang':'-'(X, Y) <_5,_4,_3> when 'true' -> primop ‘match_fail'({'function_clause',_5,_4,_3}) end 'module_info'/0 = fun () -> call 'erlang':'get_module_info'('test') 'module_info'/1 = fun (_0) -> call 'erlang':'get_module_info'('test', _0) end
  15. KERNEL ERLANG fdef 'test'/3(_2, _1, _0) = match _2,_1,_0 alt

    select _2 type k_atom 'diff' -> do bif (remote 'erlang':'-'/2)(_1, _0) >> <_12> then <<_12 >> 'sum' -> do bif (remote 'erlang':'+'/2)(_1, _0) >> <_11> then <<_11 >> do [_0] >> <_8> then do [_1|_8] >> <_9> then do [_2|_9] >> <_10> then enter (remote 'erlang':'error'/2)('function_clause', _10) end >> <> end
  16. BEAM {function, test, 3, 2}. {label,1}. {func_info,{atom,test},{atom,test},3}. {label,2}. {test,is_atom,{f,1},[{x,0}]}. {select_val,{x,0},{f,1},{list,[{atom,diff},{f,3},{atom,sum},{f,4}]}}.

    {label,3}. {gc_bif,’-',{f,0},3,[{x,1},{x,2}],{x,0}}. return. {label,4}. {gc_bif,'+',{f,0},3,[{x,1},{x,2}],{x,0}}. return.
  17. @michalmuskala BINARY PATTERN MATCHING 89: bs_put_integer/5 90: bs_put_binary/5 91: bs_put_float/5

    92: bs_put_string/2 109: bs_init2/6 111: bs_add/5 116: bs_start_match2/5 117: bs_get_integer2/7 118: bs_get_float2/7 119: bs_get_binary2/7 120: bs_skip_bits2/5 121: bs_test_tail2/3 122: bs_save2/2 123: bs_restore2/2 130: bs_context_to_binary/1 131: bs_test_unit/3 132: bs_match_string/4 133: bs_init_writable/0 134: bs_append/8 135: bs_private_append/6 137: bs_init_bits/6 138: bs_get_utf8/5 139: bs_skip_utf8/4 140: bs_get_utf16/5 141: bs_skip_utf16/4 142: bs_get_utf32/5 143: bs_skip_utf32/4 144: bs_utf8_size/3 145: bs_put_utf8/3 146: bs_utf16_size/3 147: bs_put_utf16/3 148: bs_put_utf32/3 165: bs_get_tail/3 166: bs_start_match3/4 167: bs_get_position/3 168: bs_set_position/2
  18. @michalmuskala YOU CAN PLAY WITH IT TOO • http://blog.erlang.org/ •

    http://blog.erlang.org/compiler-time-option/ - “Exploring the Compiler Using the 'time' Option” • http://blog.erlang.org/compiler-lost-in-translation/ - “Lost in Translation (Exploring the Compiler's Front End)” • http://blog.erlang.org/core-erlang-by-example/ - “Core Erlang by Example” • https://github.com/happi/theBeamBook - “The BEAM Book” • http://beam-wisdoms.clau.se/en/latest/ - “BEAM Wisdoms”