系統技術非業餘研究 » 實驗Erlang語法對應的opcode 讓你對erlang理解更深
阿新 • • 發佈:2018-12-31
Erlang作為一門FP語言,和傳統的語言結構一樣, 有模組, 有函式, 有語句, 有判斷, 有迴圈, 還有特別的模式匹配。 那麼這些在底層是如何運作的。 我在底下給大家做個簡單的實驗,讓大家一窺內部的細節,讓大家寫碼的時候知道個大概。
erlang的VM作為register based的VM, 大概有400條指令.指令分為hot, normal, cold 3大類別。beam_emu.c是vm的實現,hot和cold指令在編譯的時候 由指令碼生成的,include到beam_emu去的。 hot是熱門的操作如list, tuple操作, cold的就是比較偏的指令。
erlang的編譯器支援生成彙編碼, 讓我們的研究成可能,具體用法是 erlc +”‘S'” m.erl
會生成m.S 這個彙編檔案.
[email protected]:~# cat gram.erl
-module(gram). -export([start/1]). start([X])-> %% bif X1 = list_to_integer(atom_to_list(X)), %% list W =[1,2,3], W1 = [4|W], K=[W1,9], %% constant fold A = 1 + 2, %% if B = if X1 + A > 0 -> 5; true -> 4 end, %% case C = case B of {x, T} -> T; 5 -> a1; 3 -> a2; 2 -> 1.0; other -> 2; true -> 3 end, %% receive D = receive a1 -> 2 + 1.2; 2 -> 3; {tag, N}->N; a2 -> 5; _ -> ok after A -> timeout end, %% anon fun E = fun (1)-> D; (x)-> 2; (y)-> C; (<<"12">>)->1; (_) -> error end, F = E(D), %% fun G = f(B), io:format("~p~p~p~p~n",[F, G,W,K]), done. f(1)-> 1; f(2) ->2; f(3) ->3; f(4) ->4; f(5) ->5; f(x1) ->1; f(x2) ->2; f(x3) ->3; f(x4) ->4; f(x5) ->5; f({x,1}) -> 1; f({x,2}) ->2; f({x,3}) ->3; f({x,4}) ->4; f({x,5}) ->5; f(<<1:8, X:32, "xyz", F/float>>) -> {X, F}; f(_) -> err.
[email protected]:~# erlc +"'S'" gram.erl [email protected]:~# cat gram.S
{module, gram}. %% version = 0 {exports, [{module_info,0},{module_info,1},{start,1}]}. {attributes, []}. {labels, 45}. %%每個標籤是跳轉地址 %%每個指令對應這相應的opcode,在beam_emu中都可以找到。 {function, start, 1, 2}. {label,1}. {func_info,{atom,gram},{atom,start},1}. {label,2}. {test,is_nonempty_list,{f,1},[{x,0}]}. {get_list,{x,0},{x,1},{x,2}}. {test,is_nil,{f,1},[{x,2}]}. {allocate_zero,2,2}. {move,{x,1},{x,0}}. %% bif呼叫 {call_ext,1,{extfunc,erlang,atom_to_list,1}}. {call_ext,1,{extfunc,erlang,list_to_integer,1}}. %% 符號也是bif %% 3= 1 +2 const fold {gc_bif,'+',{f,3},1,[{x,0},{integer,3}],{x,1}}. %% if 語句是如此簡單 {test,is_lt,{f,3},[{integer,0},{x,1}]}. {move,{integer,5},{x,0}}. {jump,{f,4}}. {label,3}. {move,{integer,4},{x,0}}. {label,4}. {move,{x,0},{y,1}}. %% case語句同樣是個if else的判斷 %% tuple是如何匹配的 效率高 {test,is_tuple,{f,5},[{x,0}]}. {test,test_arity,{f,21},[{x,0},2]}. {get_tuple_element,{x,0},0,{x,1}}. {get_tuple_element,{x,0},1,{x,2}}. {test,is_eq_exact,{f,21},[{x,1},{atom,x}]}. {move,{x,2},{x,0}}. {jump,{f,12}}. {label,5}. {test,is_atom,{f,8},[{x,0}]}. %% 2分查詢 {select_val,{x,0},{f,21},{list,[{atom,true},{f,6},{atom,other},{f,7}]}}. {label,6}. {move,{integer,3},{x,0}}. {jump,{f,12}}. {label,7}. {move,{integer,2},{x,0}}. {jump,{f,12}}. {label,8}. {test,is_integer,{f,21},[{x,0}]}. %% 編譯器會聰明的做這類事情 {select_val,{x,0}, {f,21}, {list,[{integer,2}, {f,9}, {integer,3}, {f,10}, {integer,5}, {f,11}]}}. {label,9}. {move,{float,1.0},{x,0}}. {jump,{f,12}}. {label,10}. {move,{atom,a2},{x,0}}. {jump,{f,12}}. {label,11}. {move,{atom,a1},{x,0}}. {label,12}. {move,{x,0},{y,0}}. %% receive語句 {label,13}. {loop_rec,{f,19},{x,0}}. {test,is_tuple,{f,14},[{x,0}]}. {test,test_arity,{f,18},[{x,0},2]}. {get_tuple_element,{x,0},0,{x,1}}. {get_tuple_element,{x,0},1,{x,2}}. {test,is_eq_exact,{f,18},[{x,1},{atom,tag}]}. %%從訊息佇列移除 remove_message. {move,{x,2},{x,0}}. {jump,{f,20}}. {label,14}. {test,is_atom,{f,17},[{x,0}]}. {select_val,{x,0},{f,18},{list,[{atom,a2},{f,15},{atom,a1},{f,16}]}}. {label,15}. remove_message. {move,{integer,5},{x,0}}. {jump,{f,20}}. {label,16}. remove_message. {move,{float,3.2},{x,0}}. {jump,{f,20}}. {label,17}. {test,is_eq_exact,{f,18},[{x,0},{integer,2}]}. remove_message. {move,{integer,3},{x,0}}. {jump,{f,20}}. {label,18}. remove_message. {move,{atom,ok},{x,0}}. {jump,{f,20}}. {label,19}. %% timeout新增到定時器 {wait_timeout,{f,13},{integer,3}}. timeout. {move,{atom,timeout},{x,0}}. {label,20}. %% 閉包 {move,{x,0},{x,1}}. {move,{y,0},{x,0}}. {move,{x,1},{y,0}}. {make_fun2,{f,39},0,133275192,2}. {move,{x,0},{x,1}}. {move,{y,0},{x,0}}. {trim,1,1}. {call_fun,1}. {move,{x,0},{x,1}}. {move,{y,0},{x,0}}. {move,{x,1},{y,0}}. {call,1,{f,23}}. {test_heap,4,1}. %% 列表操作 {put_list,{x,0},{literal,[[1,2,3],[[4,1,2,3],9]]},{x,0}}. {put_list,{y,0},{x,0},{x,1}}. {trim,1,0}. {move,{literal,"~p~p~p~p~n"},{x,0}}. {call_ext,2,{extfunc,io,format,2}}. {move,{atom,done},{x,0}}. {deallocate,0}. return. {label,21}. {case_end,{x,0}}. {function, f, 1, 23}. {label,22}. {func_info,{atom,gram},{atom,f},1}. {label,23}. {test,bs_start_match2,{f,24},1,[{x,0},0],{x,0}}. {test,bs_match_string,{f,33},[{x,0},8,{string,[1]}]}. {test,bs_get_integer2, {f,33}, 1, [{x,0}, {integer,32}, 1, {field_flags,[{anno,[78,{file,"./gram.erl"}]},unsigned,big]}], {x,1}}. {test,bs_match_string,{f,33},[{x,0},24,{string,"xyz"}]}. {test,bs_get_float2, {f,33}, 2, [{x,0}, {integer,64}, 1, {field_flags,[{anno,[78,{file,"./gram.erl"}]},unsigned,big]}], {x,2}}. {test,bs_test_tail2,{f,33},[{x,0},0]}. {test_heap,3,3}. {put_tuple,2,{x,0}}. {put,{x,1}}. {put,{x,2}}. return. {label,24}. {test,is_tuple,{f,25},[{x,0}]}. {test,test_arity,{f,33},[{x,0},2]}. {get_tuple_element,{x,0},0,{x,1}}. {get_tuple_element,{x,0},1,{x,2}}. {test,is_eq_exact,{f,33},[{x,1},{atom,x}]}. {test,is_integer,{f,33},[{x,2}]}. {select_val,{x,2}, {f,33}, {list,[{integer,5}, {f,26}, {integer,4}, {f,27}, {integer,3}, {f,28}, {integer,2}, {f,29}, {integer,1}, {f,30}]}}. {label,25}. {test,is_atom,{f,31},[{x,0}]}. {select_val,{x,0}, {f,33}, {list,[{atom,x5}, {f,26}, {atom,x4}, {f,27}, {atom,x3}, {f,28}, {atom,x2}, {f,29}, {atom,x1}, {f,30}]}}. {label,26}. {move,{integer,5},{x,0}}. return. {label,27}. {move,{integer,4},{x,0}}. return. {label,28}. {move,{integer,3},{x,0}}. return. {label,29}. {move,{integer,2},{x,0}}. return. {label,30}. {move,{integer,1},{x,0}}. return. {label,31}. {test,is_integer,{f,33},[{x,0}]}. {select_val,{x,0}, {f,33}, {list,[{integer,5}, {f,32}, {integer,4}, {f,32}, {integer,3}, {f,32}, {integer,2}, {f,32}, {integer,1}, {f,32}]}}. {label,32}. return. {label,33}. {move,{atom,err},{x,0}}. return. %%這2個函式是complier要硬性加上去的 {function, module_info, 0, 35}. {label,34}. {func_info,{atom,gram},{atom,module_info},0}. {label,35}. {move,{atom,gram},{x,0}}. {call_ext_only,1,{extfunc,erlang,get_module_info,1}}. {function, module_info, 1, 37}. {label,36}. {func_info,{atom,gram},{atom,module_info},1}. {label,37}. {move,{x,0},{x,1}}. {move,{atom,gram},{x,0}}. {call_ext_only,2,{extfunc,erlang,get_module_info,2}}. %%匿名函式的命名 {function, '-start/1-fun-0-', 3, 39}. {label,38}. {func_info,{atom,gram},{atom,'-start/1-fun-0-'},3}. {label,39}. {test,bs_start_match2,{f,40},3,[{x,0},0],{x,0}}. {test,bs_match_string,{f,44},[{x,0},16,{string,"12"}]}. {test,bs_test_tail2,{f,44},[{x,0},0]}. %% bitstring的程式碼很優化。 {move,{integer,1},{x,0}}. return. {label,40}. {test,is_atom,{f,43},[{x,0}]}. {select_val,{x,0},{f,44},{list,[{atom,y},{f,41},{atom,x},{f,42}]}}. %% 一類的資料放在一起 用二分查詢匹配 {label,41}. {move,{x,1},{x,0}}. return. {label,42}. {move,{integer,2},{x,0}}. return. {label,43}. {test,is_eq_exact,{f,44},[{x,0},{integer,1}]}. {move,{x,2},{x,0}}. return. {label,44}. {move,{atom,error},{x,0}}. return.
所以無論函式match, 表示式match在vm層面都是if else這樣的判斷。從這個角度來講if, case這些都只是erlang的語法糖。事實上也是,這些語法都是後來新增的,取悅使用者的。
函式匹配是erlang的所有事情的核心。
結論:erlang的compiler很智慧,這個VM和lua的非常像, 效率也相當。
Post Footer automatically generated by wp-posturl plugin for wordpress.
No related posts.