1. 程式人生 > >系統技術非業餘研究 » 實驗Erlang語法對應的opcode 讓你對erlang理解更深

系統技術非業餘研究 » 實驗Erlang語法對應的opcode 讓你對erlang理解更深

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.