实验Erlang语法对应的opcode 让你对erlang理解更深
September 20th, 2009
原创文章,转载请注明: 转载自系统技术非业余研究
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])-> %% 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.
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}. %%每个标签是跳转地址 %%每个指令对应这相应的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.
现在很少有人去纠结语言的本质了,因为人们总是自以为聪明的去判定什么有用什么没用,实不知潜意识里 只是为自己的怠惰找借口罢了
总之
高手寂寞 曲高和寡 共勉
有用没用,好奇点就行了。