实验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 这个汇编文件.

root@nd-desktop:~# cat gram.erl
-module(gram).
-export([start/1]).

start([X])->
[color=red] %% bif [/color]
X1 = list_to_integer(atom_to_list(X)),

%% list
W =[1,2,3],
W1 = [4|W],

K=[W1,9],

[color=red] %% constant fold[/color]
A = 1 + 2,

[color=red] %% if[/color]
B =
if X1 + A > 0 -> 5;
true -> 4
end,

[color=red] %% case [/color]
C =
case B of
{x, T} -> T;
5 -> a1;
3 -> a2;
2 -> 1.0;
other -> 2;
true -> 3
end,

[color=red] %% receive[/color]
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),

[color=red] %% fun[/color]
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.

root@nd-desktop:~# erlc +"'S'" gram.erl

root@nd-desktop:~# cat gram.S
{module, gram}. %% version = 0

{exports, [{module_info,0},{module_info,1},{start,1}]}.

{attributes, []}.

{labels, 45}. [color=red]%%每个标签是跳转地址[/color]

[color=red]%%每个指令对应这相应的opcode,在beam_emu中都可以找到。[/color]

{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}}.
[color=red] %% bif调用[/color]
{call_ext,1,{extfunc,erlang,atom_to_list,1}}.
{call_ext,1,{extfunc,erlang,list_to_integer,1}}.
[color=red]%% 符号也是bif[/color]
[color=red] %% 3= 1 +2 const fold[/color]
{gc_bif,'+',{f,3},1,[{x,0},{integer,3}],{x,1}}.
[color=red] %% if 语句是如此简单[/color]
{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}}.
[color=red] %% case语句同样是个if else的判断[/color]

[color=red] %% tuple是如何匹配的 效率高[/color]
{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}]}.
[color=red]%% 2分查找 [/color]
{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}]}.
[color=red] %% 编译器会聪明的做这类事情[/color]
{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}}.

[color=red] %% receive语句[/color]
{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}]}.

[color=red] %%从消息队列移除[/color]
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}.
[color=red]%% timeout添加到定时器[/color]
{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}.
[color=red]%% 列表操作[/color]
{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.

[color=red]%%这2个函数是complier要硬性加上去的[/color]

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

[color=red]%%匿名函数的命名[/color]
{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]}.
[color=red]%% bitstring的代码很优化。[/color]
{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}]}}.
[color=red] %% 一类的数据放在一起 用二分查找匹配[/color]
{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的非常像, 效率也相当。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值