Slide 1

Slide 1 text

@michalmuskala WHAT ACTUALLY IS THE BEAM? London, 02.04.2020

Slide 2

Slide 2 text

MICHAŁ MUSKAŁA Big Tech company http://michal.muskala.eu/ https://github.com/michalmuskala/ @michalmuskala

Slide 3

Slide 3 text

@michalmuskala GLOSSARY • Erlang • Erlang/OTP • BEAM • ERTS • Elixir

Slide 4

Slide 4 text

ERLANG/OTP ERTS BEAM compiler stdlib Libraries kernel

Slide 5

Slide 5 text

@michalmuskala 1. THE VM

Slide 6

Slide 6 text

@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

Slide 7

Slide 7 text

@michalmuskala OTHER IMPLEMENTATIONS • https://github.com/trifork/erjang • https://github.com/cloudozer/ling - Erlang on Xen • https://github.com/bettio/AtomVM • https://github.com/lumen/lumen

Slide 8

Slide 8 text

@michalmuskala WHAT IS A VIRTUAL MACHINE?

Slide 9

Slide 9 text

@michalmuskala STACK VM VS REGISTER VM Virtual Machine Showdown: Stack vs Registers https://www.usenix.org/legacy/events/vee05/full_papers/p153-yunhe.pdf

Slide 10

Slide 10 text

https://markfaction.wordpress.com/2012/07/15/stack-based-vs-register-based-virtual-machine-architecture-and-the-dalvik-vm/ STACK VS REGISTER VM PUSH 20 PUSH 7 ADD

Slide 11

Slide 11 text

https://markfaction.wordpress.com/2012/07/15/stack-based-vs-register-based-virtual-machine-architecture-and-the-dalvik-vm/ STACK VS REGISTER VM ADD R3 R1 R2 ADD R3 20 7 or

Slide 12

Slide 12 text

@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

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

@michalmuskala PAM

Slide 15

Slide 15 text

@michalmuskala 2. THE BYTECODE

Slide 16

Slide 16 text

@michalmuskala BYTECODE • 1024 general X registers • stack slots referred to as Y registers • exchange format between the compiler and the runtime system

Slide 17

Slide 17 text

• erlc -S module.erl • mix decompile https: //github.com/michalmuskala/decompile • :erts_debug.df/1,2,3

Slide 18

Slide 18 text

LITERALS test() -> [1, 2, #{a => 5}, foo]. {function, test, 0, 2}. {label,2}. {move,{literal,[1,2, #{a => 5},foo]},{x,0}}. return.

Slide 19

Slide 19 text

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}.

Slide 20

Slide 20 text

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}}.

Slide 21

Slide 21 text

@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

Slide 22

Slide 22 text

@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

Slide 23

Slide 23 text

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]

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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)

Slide 26

Slide 26 text

@michalmuskala 3. THE COMPILER

Slide 27

Slide 27 text

@michalmuskala THE ROAD TO .BEAM Elixir Source Elixir AST Erlang Abstract Format Core Erlang Kernel Erlang BEAM SSA BEAM Erlang Source

Slide 28

Slide 28 text

ERLANG -module(test). -compile(export_all). test(sum, X, Y) -> X + Y; test(diff, X, Y) -> X - Y.

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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.

Slide 32

Slide 32 text

@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

Slide 33

Slide 33 text

@michalmuskala HIPE

Slide 34

Slide 34 text

@michalmuskala 4. THE COMMUNITY

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

@michalmuskala THE FUTURE

Slide 37

Slide 37 text

@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”

Slide 38

Slide 38 text

@michalmuskala WHAT ACTUALLY IS THE BEAM? London, 02.04.2020