Erlang源代码编译为beam文件,代码要经过一系列的过程(见下面的简图),Core Erlang之前已经简单介绍过了Core Erlang,代码转换为Core Erlang,就容易拨开一些语法糖的真面目了.下一阶段就是将Core Erlang转换为opcode,使用c(m,'S')生成的是.S文件可以看到反编译的代码.编译器最终输出的是Virtual Beam Code 但这还不是最终VM执行的代码,在erts\emulator\beam\beam_load.c执行的过程中会完成指令优化,优化之后的代码可以通过erts_debug:df(m)生成.dis文件查看,换句话说,这个方法执行成功必须要要求模块已经加载.

下面的代码里面,模块t还没有编译,所以第一次执行erts_debug:df(t)返回值是{undef,t}

Eshell V6.0  (abort with ^G)
1> c(t,'S').
** Warning: No object file created - nothing loaded **
ok
2> erts_debug:df(t).
{undef,t}
3> c(t).
{ok,t}
4> erts_debug:df(t).
ok
5> q().
ok
6>

  

之前有两次使用过反汇编的代码:

[Erlang 0029] Erlang Inline编译 [链接] 里面我们使用过反编译的代码观察inline机制.
    [Erlang 0100] make_ref 与 Selective Receive [链接]通过反汇编代码看到selective receive的优化处理.

除了Erlang源代码几乎没有什么资料可供参考.有两个方法可以继续跟踪下去,一是通过erts_debug:instructions()输出所有命令,再就是编写erl代码对照.S代码去推测意义.霸爷有一篇<实验Erlang语法对应的opcode 让你对erlang理解更深>就是这样做的,下面把我比较关注的一些地方做下测试.

Eshell V6.0  (abort with ^G)
1> rp(erts_debug:instructions()).
["allocate_tt","allocate_heap_tIt","allocate_heap_zero_tIt",
"allocate_init_tIy","allocate_zero_tt","apply_I",
"apply_bif","apply_last_IP","badarg_j","badmatch_r",
"badmatch_x","badmatch_y","bif1_fbsd","bif1_body_bsd",
"bs_context_to_binary_r","bs_context_to_binary_x",
"bs_context_to_binary_y","bs_init_writable",
"bs_put_string_II","bs_test_tail_imm2_frI",
"bs_test_tail_imm2_fxI","bs_test_unit_frI",
"bs_test_unit_fxI","bs_test_unit8_fr","bs_test_unit8_fx",
"bs_test_zero_tail2_fr","bs_test_zero_tail2_fx",
"call_bif_e","call_error_handler","call_nif","case_end_r",
"case_end_x","case_end_y","catch_yf","catch_end_y",
"continue_exit","deallocate_I","deallocate_return_Q",
"error_action_code","extract_next_element_x",
"extract_next_element_y","extract_next_element2_x",
"extract_next_element2_y","extract_next_element3_x",
"extract_next_element3_y","fclearerror","fconv_dl",
"fmove_ql","fmove_ld","fmove_dl","get_list_rrx",
"get_list_rry","get_list_rxr","get_list_rxx","get_list_rxy",
"get_list_ryr","get_list_ryx","get_list_ryy","get_list_xrx",
"get_list_xry","get_list_xxr","get_list_xxx","get_list_xxy",
"get_list_xyr","get_list_xyx","get_list_xyy","get_list_yrx",
"get_list_yry","get_list_yxr","get_list_yxx","get_list_yxy",
"get_list_yyr","get_list_yyx","get_list_yyy",
"hipe_call_count","hipe_trap_call","hipe_trap_call_closure",
"hipe_trap_resume","hipe_trap_return","hipe_trap_throw",
"i_apply","i_apply_fun","i_apply_fun_last_P",
"i_apply_fun_only","i_apply_last_P","i_apply_only",
"i_band_jId","i_bif2_fbd","i_bif2_body_bd","i_bor_jId",
"i_bs_add_jId","i_bs_append_jIIId",
"i_bs_get_binary2_frIsId","i_bs_get_binary2_fxIsId",
"i_bs_get_binary_all2_frIId","i_bs_get_binary_all2_fxIId",
"i_bs_get_binary_all_reuse_rfI",
"i_bs_get_binary_all_reuse_xfI",
"i_bs_get_binary_imm2_frIIId","i_bs_get_binary_imm2_fxIIId",
"i_bs_get_float2_frIsId","i_bs_get_float2_fxIsId",
"i_bs_get_integer_fIId","i_bs_get_integer_16_rfd",
"i_bs_get_integer_16_xfd","i_bs_get_integer_32_rfId",
"i_bs_get_integer_32_xfId","i_bs_get_integer_8_rfd",
"i_bs_get_integer_8_xfd","i_bs_get_integer_imm_rIIfId",
"i_bs_get_integer_imm_xIIfId",
"i_bs_get_integer_small_imm_rIfId",
"i_bs_get_integer_small_imm_xIfId","i_bs_get_utf16_rfId",
"i_bs_get_utf16_xfId","i_bs_get_utf8_rfd",
"i_bs_get_utf8_xfd","i_bs_init_IId","i_bs_init_bits_IId",
"i_bs_init_bits_fail_rjId","i_bs_init_bits_fail_xjId",
"i_bs_init_bits_fail_yjId","i_bs_init_bits_fail_heap_IjId",
"i_bs_init_bits_heap_IIId","i_bs_init_fail_rjId",
"i_bs_init_fail_xjId","i_bs_init_fail_yjId",
"i_bs_init_fail_heap_IjId","i_bs_init_heap_IIId",
"i_bs_init_heap_bin_IId","i_bs_init_heap_bin_heap_IIId",
"i_bs_match_string_rfII","i_bs_match_string_xfII",
"i_bs_private_append_jId","i_bs_put_utf16_jIs",
"i_bs_put_utf8_js","i_bs_restore2_rI","i_bs_restore2_xI",
"i_bs_save2_rI","i_bs_save2_xI","i_bs_skip_bits2_frxI",
"i_bs_skip_bits2_fryI","i_bs_skip_bits2_fxrI",
"i_bs_skip_bits2_fxxI","i_bs_skip_bits2_fxyI",
"i_bs_skip_bits_all2_frI","i_bs_skip_bits_all2_fxI",
"i_bs_skip_bits_imm2_frI","i_bs_skip_bits_imm2_fxI",
"i_bs_start_match2_rfIId","i_bs_start_match2_xfIId",
"i_bs_start_match2_yfIId","i_bs_utf16_size_sd",
"i_bs_utf8_size_sd","i_bs_validate_unicode_js",
"i_bs_validate_unicode_retract_j","i_bsl_jId","i_bsr_jId",
"i_bxor_jId","i_call_f","i_call_ext_e","i_call_ext_last_eP",
"i_call_ext_only_e","i_call_fun_I","i_call_fun_last_IP",
"i_call_last_fP","i_call_only_f","i_debug_breakpoint",
"i_element_rjsd","i_element_xjsd","i_element_yjsd",
"i_fadd_lll","i_fast_element_rjId","i_fast_element_xjId",
"i_fast_element_yjId","i_fcheckerror","i_fdiv_lll",
"i_fetch_rx","i_fetch_ry","i_fetch_xr","i_fetch_xx",
"i_fetch_xy","i_fetch_yr","i_fetch_yx","i_fetch_yy",
"i_fetch_rc","i_fetch_xc","i_fetch_yc","i_fetch_cr",
"i_fetch_cx","i_fetch_cy","i_fetch_cc","i_fetch_ss",
"i_fmul_lll","i_fnegate_ll","i_fsub_lll","i_func_info_IaaI",
"i_gc_bif1_jIsId","i_gc_bif2_jIId","i_gc_bif3_jIsId",
"i_generic_breakpoint","i_get_sd","i_get_map_element_frar",
"i_get_map_element_frax","i_get_map_element_fray",
"i_get_map_element_frxr","i_get_map_element_frxx",
"i_get_map_element_frxy","i_get_map_element_fxar",
"i_get_map_element_fxax","i_get_map_element_fxay",
"i_get_map_element_fxxr","i_get_map_element_fxxx",
"i_get_map_element_fxxy","i_get_map_element_fyar",
"i_get_map_element_fyax","i_get_map_element_fyay",
"i_get_map_element_fyxr","i_get_map_element_fyxx",
"i_get_map_element_fyxy","i_get_map_elements_fsI",
"i_get_tuple_element_rPr","i_get_tuple_element_rPx",
"i_get_tuple_element_rPy","i_get_tuple_element_xPr",
"i_get_tuple_element_xPx","i_get_tuple_element_xPy",
"i_get_tuple_element_yPr","i_get_tuple_element_yPx",
"i_get_tuple_element_yPy","i_has_map_field_fra",
"i_has_map_field_frr","i_has_map_field_frx",
"i_has_map_field_fry","i_has_map_field_fxa",
"i_has_map_field_fxr","i_has_map_field_fxx",
"i_has_map_field_fxy","i_has_map_field_fya",
"i_has_map_field_fyr","i_has_map_field_fyx",
"i_has_map_field_fyy","i_has_map_fields_fsI","i_hibernate",
"i_increment_rIId","i_increment_xIId","i_increment_yIId",
"i_int_bnot_jsId","i_int_div_jId","i_is_eq_f",
"i_is_eq_exact_f","i_is_eq_exact_immed_frc",
"i_is_eq_exact_immed_fxc","i_is_eq_exact_immed_fyc",
"i_is_eq_exact_literal_rfc","i_is_eq_exact_literal_xfc",
"i_is_eq_exact_literal_yfc","i_is_ge_f","i_is_lt_f",
"i_is_ne_f","i_is_ne_exact_f","i_is_ne_exact_immed_frc",
"i_is_ne_exact_immed_fxc","i_is_ne_exact_immed_fyc",
"i_is_ne_exact_literal_rfc","i_is_ne_exact_literal_xfc",
"i_is_ne_exact_literal_yfc","i_jump_on_val_rfII",
"i_jump_on_val_xfII","i_jump_on_val_yfII",
"i_jump_on_val_zero_rfI","i_jump_on_val_zero_xfI",
"i_jump_on_val_zero_yfI","i_loop_rec_fr","i_m_div_jId",
"i_make_fun_It","i_minus_jId","i_move_call_crf",
"i_move_call_ext_cre","i_move_call_ext_last_ePcr",
"i_move_call_ext_only_ecr","i_move_call_last_fPcr",
"i_move_call_only_fcr","i_new_bs_put_binary_jsIs",
"i_new_bs_put_binary_all_jsI","i_new_bs_put_binary_imm_jIs",
"i_new_bs_put_float_jsIs","i_new_bs_put_float_imm_jIIs",
"i_new_bs_put_integer_jsIs","i_new_bs_put_integer_imm_jIIs",
"i_plus_jId","i_put_tuple_rI","i_put_tuple_xI",
"i_put_tuple_yI","i_recv_set","i_rem_jId",
"i_return_time_trace","i_return_to_trace",
"i_select_tuple_arity_rfI","i_select_tuple_arity_xfI",
"i_select_tuple_arity_yfI","i_select_tuple_arity2_rfAfAf",
"i_select_tuple_arity2_xfAfAf",
"i_select_tuple_arity2_yfAfAf","i_select_val_rfI",
"i_select_val_xfI","i_select_val_yfI",
"i_select_val2_rfcfcf","i_select_val2_xfcfcf",
"i_select_val2_yfcfcf","i_times_jId","i_trim_I",
"i_wait_error","i_wait_error_locked","i_wait_timeout_fI",
"i_wait_timeout_fs","i_wait_timeout_locked_fI",
"i_wait_timeout_locked_fs","i_yield","if_end","init_y",
"init2_yy","init3_yyy","int_code_end","is_atom_fr",
"is_atom_fx","is_atom_fy","is_binary_fr","is_binary_fx",
"is_binary_fy","is_bitstring_fr","is_bitstring_fx",
"is_bitstring_fy","is_boolean_fr","is_boolean_fx",
"is_boolean_fy","is_float_fr","is_float_fx","is_float_fy",
"is_function_fr","is_function_fx","is_function_fy",
"is_function2_fss","is_integer_fr","is_integer_fx",
"is_integer_fy","is_integer_allocate_frII",
"is_integer_allocate_fxII","is_list_fr","is_list_fx",
"is_list_fy","is_map_fr","is_map_fx","is_map_fy",
"is_nil_fr","is_nil_fx","is_nil_fy",
"is_non_empty_list_test_heap_frIt","is_nonempty_list_fr",
"is_nonempty_list_fx","is_nonempty_list_fy",
"is_nonempty_list_allocate_frIt",
"is_nonempty_list_allocate_fxIt","is_number_fr",
"is_number_fx","is_number_fy","is_pid_fr","is_pid_fx",
"is_pid_fy","is_port_fr","is_port_fx","is_port_fy",
"is_reference_fr","is_reference_fx","is_reference_fy",
"is_tuple_fr","is_tuple_fx","is_tuple_fy",
"is_tuple_of_arity_frA","is_tuple_of_arity_fxA",
"is_tuple_of_arity_fyA","jump_f","label_L","line_I",
"loop_rec_end_f","move_nr","move_nx","move_rx","move_ry",
"move_xr","move_xx","move_xy","move_yr","move_yx","move_yy",
"move_cr","move_cx","move2_xxxx","move2_xyxy","move2_yxyx",
"move_call_xrf","move_call_yrf","move_call_last_xrfQ",
"move_call_last_yrfQ","move_call_only_xrf",
"move_deallocate_return_nrQ","move_deallocate_return_xrQ",
"move_deallocate_return_yrQ","move_deallocate_return_crQ",
"move_jump_fn","move_jump_fx","move_jump_fy","move_jump_fc",
"move_return_nr","move_return_xr","move_return_cr",
"move_x1_c","move_x2_c","new_map_jdII","node_r","node_x",
"node_y","normal_exit","on_load","put_list_rnx",
"put_list_rxr","put_list_rxx","put_list_ryx","put_list_xnx",
"put_list_xrr","put_list_xrx","put_list_xxr","put_list_xxx",
"put_list_xyr","put_list_xyx","put_list_ynx","put_list_yrr",
"put_list_yrx","put_list_yxr","put_list_yxx","put_list_yyr",
"put_list_yyx","put_list_rcr","put_list_rcx","put_list_rcy",
"put_list_xcr","put_list_xcx","put_list_xcy","put_list_ycr",
"put_list_ycx","put_list_ycy","put_list_crr","put_list_crx",
"put_list_cry","put_list_cxr","put_list_cxx","put_list_cxy",
"put_list_cyr","put_list_cyx","put_list_cyy","put_list_ssd",
"raise_ss","recv_mark_f","remove_message","return",
"return_trace","self_r","self_x","self_y","send",
"set_tuple_element_sdP","system_limit_j","test_arity_frA",
"test_arity_fxA","test_arity_fyA","test_heap_It",
"test_heap_1_put_list_Iy","timeout","timeout_locked",
"try_case_end_s","try_end_y","update_map_assoc_jsdII",
"update_map_exact_jsdII","wait_f","wait_locked_f",
"wait_unlocked_f"]
ok
2>

回顾 [Erlang 0010] Erlang 热更新 [ 链接 ],看看两种调用时候为什么m:f(a)会触发热更新,测试代码如下:

loop() ->
receive
code_switch ->
m:loop();
Msg ->
io:format("."),
loop()
end. %% t.S文件 {function, loop, 0, 9}.
{label,8}.
{line,[{location,"t.erl",14}]}.
{func_info,{atom,t},{atom,loop},0}.
{label,9}.
{allocate,0,0}.
{line,[{location,"t.erl",15}]}.
{label,10}.
{loop_rec,{f,12},{x,0}}.
{test,is_eq_exact,{f,11},[{x,0},{atom,code_switch}]}.
remove_message.
{line,[{location,"t.erl",17}]}.
{call_ext_last,0,{extfunc,m,loop,0},0}.
{label,11}.
remove_message.
{move,{literal,"."},{x,0}}.
{line,[{location,"t.erl",19}]}.
{call_ext,1,{extfunc,io,format,1}}.
{call_last,0,{f,9},0}.
{label,12}.
{wait,{f,10}}. %% t.dis文件 00007F9D864F6C38: i_func_info_IaaI 0 t loop 0
00007F9D864F6C60: allocate_tt 0 0
00007F9D864F6C70: i_loop_rec_fr f(00007F9D864F6CF0) x(0)
00007F9D864F6C80: i_is_eq_exact_immed_frc f(00007F9D864F6CB8) x(0) code_switch
00007F9D864F6C98: remove_message
00007F9D864F6CA0: i_call_ext_last_eP m:loop/0 0
00007F9D864F6CB8: remove_message
00007F9D864F6CC0: i_move_call_ext_cre "." x(0) io:format/1
00007F9D864F6CD8: i_call_last_fP t:loop/0 0
00007F9D864F6CF0: wait_f f(00007F9D864F6C70)

  

然后,使用这个方法,我把ErlangEfficiency Guide 里面大部分代码都做了一下测试,目的是想从一个新的角度切入以前的问题,其中一个比较有意思的是:

bin()->
Bin0 = <<0>>, %% 1 Bin1 = <<Bin0/binary,1,2,3>>, %% 2 Bin2 = <<Bin1/binary,4,5,6>>, %% 3 Bin3 = <<Bin2/binary,7,8,9>>, %% 4 Bin4 = <<Bin1/binary,17>>, %% 5 !!! {Bin4,Bin3}. %% 6

  

这个方法由于中间的变量都是已知的,编译之后直接使用运算结果了:

{function, bin, 0, 14}.
{label,13}.
{line,[{location,"t.erl",25}]}.
{func_info,{atom,t},{atom,bin},0}.
{label,14}.
{move,{literal,{<<0,1,2,3,17>>,<<0,1,2,3,4,5,6,7,8,9>>}},{x,0}}.
return.

印象比较深刻的是 http://www.erlang.org/doc/efficiency_guide/functions.html#id67136 里面提到函数分支的例子:

atom_map1(one) -> 1;
atom_map1(two) -> 2;
atom_map1(three) -> 3;
atom_map1(Int) when is_integer(Int) -> Int;
atom_map1(four) -> 4;
atom_map1(five) -> 5;
atom_map1(six) -> 6. atom_map2(one) -> 1;
atom_map2(two) -> 2;
atom_map2(three) -> 3;
atom_map2(four) -> 4;
atom_map2(five) -> 5;
atom_map2(six) -> 6;
atom_map2(Int) when is_integer(Int) -> Int. atom_map3(Int) when is_integer(Int) -> Int;
atom_map3(one) -> 1;
atom_map3(two) -> 2;
atom_map3(three) -> 3;
atom_map3(four) -> 4;
atom_map3(five) -> 5;
atom_map3(six) -> 6.

对于atom_map1为什么有问题文档上是这样说的:

First the input value is compared to one, two, and three (using a single instruction that does a binary search; thus, quite efficient even if there are many values) to select which one of the first three clauses to execute (if any).

If none of the first three clauses matched, the fourth clause will match since a variable always matches. If the guard test is_integer(Int) succeeds, the fourth clause will be executed.

If the guard test failed, the input value is compared to four, five, and six, and the appropriate clause is selected. (There will be a function_clause exception if none of the values matched.)

二分查找,优化等等,虽然道理能明白,但是具体到细节就有点恍惚,看下t.S文件就明白了,代码太长被我折叠了,所谓的二分查找就是select_val指令实现的,可以看到atom_map2,atom_map3都是将所有的分支放在一起做二分查找,而atom_map1的执行过程被分成了三段;再回头看上面的说明,是不是就清晰多了.

{function, atom_map1, 1, 33}.
{label,32}.
{line,[{location,"t.erl",77}]}.
{func_info,{atom,t},{atom,atom_map1},1}.
{label,33}.
{test,is_atom,{f,37},[{x,0}]}.
{select_val,{x,0},
{f,37},
{list,[{atom,three},
{f,34},
{atom,two},
{f,35},
{atom,one},
{f,36}]}}.
{label,34}.
{move,{integer,3},{x,0}}.
return.
{label,35}.
{move,{integer,2},{x,0}}.
return.
{label,36}.
{move,{integer,1},{x,0}}.
return.
{label,37}.
{test,is_integer,{f,38},[{x,0}]}.
return.
{label,38}.
{test,is_atom,{f,32},[{x,0}]}.
{select_val,{x,0},
{f,32},
{list,[{atom,six},
{f,39},
{atom,five},
{f,40},
{atom,four},
{f,41}]}}.
{label,39}.
{move,{integer,6},{x,0}}.
return.
{label,40}.
{move,{integer,5},{x,0}}.
return.
{label,41}.
{move,{integer,4},{x,0}}.
return. {function, atom_map2, 1, 43}.
{label,42}.
{line,[{location,"t.erl",87}]}.
{func_info,{atom,t},{atom,atom_map2},1}.
{label,43}.
{test,is_atom,{f,50},[{x,0}]}.
{select_val,{x,0},
{f,50},
{list,[{atom,six},
{f,44},
{atom,five},
{f,45},
{atom,four},
{f,46},
{atom,three},
{f,47},
{atom,two},
{f,48},
{atom,one},
{f,49}]}}.
{label,44}.
{move,{integer,6},{x,0}}.
return.
{label,45}.
{move,{integer,5},{x,0}}.
return.
{label,46}.
{move,{integer,4},{x,0}}.
return.
{label,47}.
{move,{integer,3},{x,0}}.
return.
{label,48}.
{move,{integer,2},{x,0}}.
return.
{label,49}.
{move,{integer,1},{x,0}}.
return.
{label,50}.
{test,is_integer,{f,42},[{x,0}]}.
return. {function, atom_map3, 1, 52}.
{label,51}.
{line,[{location,"t.erl",97}]}.
{func_info,{atom,t},{atom,atom_map3},1}.
{label,52}.
{test,is_integer,{f,53},[{x,0}]}.
return.
{label,53}.
{test,is_atom,{f,51},[{x,0}]}.
{select_val,{x,0},
{f,51},
{list,[{atom,six},
{f,54},
{atom,five},
{f,55},
{atom,four},
{f,56},
{atom,three},
{f,57},
{atom,two},
{f,58},
{atom,one},
{f,59}]}}.
{label,54}.
{move,{integer,6},{x,0}}.
return.
{label,55}.
{move,{integer,5},{x,0}}.
return.
{label,56}.
{move,{integer,4},{x,0}}.
return.
{label,57}.
{move,{integer,3},{x,0}}.
return.
{label,58}.
{move,{integer,2},{x,0}}.
return.
{label,59}.
{move,{integer,1},{x,0}}.
return.

  

我非常喜欢汇丰银行的一句宣传语"不同的视角,打开迥然不同的世界",使用不同的视角对同一个技术问题也会有不同的理解.

参考资料:

[0] A Peek Inside the Erlang Compiler http://prog21.dadgum.com/127.html

[1] Erlang源码汇编格式 http://blog.yufeng.info/archives/498

[2] Erlang代码反编译以及查看汇编码 http://blog.yufeng.info/archives/1599

[3] 实验Erlang语法对应的opcode 让你对erlang理解更深 http://blog.yufeng.info/archives/34

[Erlang 0125] Know a little Erlang opcode的更多相关文章

  1. [Erlang 0117] 当我们谈论Erlang Maps时,我们谈论什么 Part 2

    声明:本文讨论的Erlang Maps是基于17.0-rc2,时间2014-3-4.后续Maps可能会出现语法或函数API上的有所调整,特此说明. 前情提要: [Erlang 0116] 当我们谈论E ...

  2. [Erlang 0116] 当我们谈论Erlang Maps时,我们谈论什么 Part 1

         Erlang 增加 Maps数据类型并不是很突然,因为这个提议已经进行了2~3年之久,只不过Joe Armstrong老爷子最近一篇文章Big changes to Erlang掀起不小了风 ...

  3. Erlang基础 -- 介绍 -- 历史及Erlang并发

    前言 最近在总结一些Erlang编程语言的基础知识,拟系统的介绍Erlang编程语言,从基础到进阶,然后再做Erlang编程语言有意思的库的分析. 其实,还是希望越来越多的人关注Erlang,使用Er ...

  4. [Erlang 0128] Term sharing in Erlang/OTP 下篇

    继续昨天的话题,昨天提到io:format对数据共享的间接影响,如果是下面两种情况恐怕更容易成为"坑", 呃,恰好我都遇到过; 如果是测试代码是下面这样,得到的结果会是怎样?猜! ...

  5. [Erlang 0127] Term sharing in Erlang/OTP 上篇

    之前,在 [Erlang 0126] 我们读过的Erlang论文 提到过下面这篇论文: On Preserving Term Sharing in the Erlang Virtual Machine ...

  6. [Erlang 0121] 当我们谈论Erlang Maps时,我们谈论什么 Part 3

    Erlang/OTP 17.0 has been released  http://www.erlang.org/download/otp_src_17.0.readme     Erlang/OTP ...

  7. [Erlang 0109] From Elixir to Erlang Code

    Elixir代码最终编译成为erlang代码,这个过程是怎样的?本文通过一个小测试做下探索.         编译一旦完成,你就看到了真相   Elixir代码组织方式一方面和Erlang一样才用非常 ...

  8. Erlang ERTS的Trap机制的设计及其用途

    出处:http://mryufeng.iteye.com/blog/334744 erlang的trap机制在实现中用的很多,在费时的BIF操作中基本上都可以看到.它的实现需要erl vm的配合.它的 ...

  9. erlang虚拟机代码执行原理

     转载:http://blog.csdn.NET/mycwq/article/details/45653897 erlang是开源的,很多人都研究过源代码.但是,从erlang代码到c代码,这是个不小 ...

随机推荐

  1. [转载]:STM32为什么必须先配置时钟再配置GPIO

    转载来源 :http://blog.csdn.net/fushiqianxun/article/details/7926442 [原创]:我来添两句,就是很多同学(包括我)之前搞低端单片机,到了stm ...

  2. ASP.NET中Session的sessionState 4种mode模式

    1. sessionState的4种mode模式 在ASP.NET中Session的sessionState的4中mode模式:Off.InProc.StateServer及SqlServer. 2. ...

  3. ASP.NET OAuth:access token的加密解密,client secret与refresh token的生成

    在 ASP.NET OWIN OAuth(Microsoft.Owin.Security.OAuth)中,access token 的默认加密方法是: 1) System.Security.Crypt ...

  4. .NET中的逆变协变

    MSDN上的说法: 协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更小(不太具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型----------(注 ...

  5. Python标准模块--concurrent.futures

    1 模块简介 concurrent.futures模块是在Python3.2中添加的.根据Python的官方文档,concurrent.futures模块提供给开发者一个执行异步调用的高级接口.con ...

  6. .NET Core采用的全新配置系统[4]: “Options模式”下各种类型的Options对象是如何绑定的?

    旨在生成Options对象的配置绑定实现在IConfiguration接口的扩展方法Bind上.配置绑定的目标类型可以是一个简单的基元类型,也可以是一个自定义数据类型,还可以是一个数组.集合或者字典类 ...

  7. 读书笔记--SQL必知必会18--视图

    读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...

  8. 匹夫细说C#:庖丁解牛聊委托,那些编译器藏的和U3D给的

    0x00 前言 由于工作繁忙所以距离上一篇博客已经过去一个多月的时间了,因此决心这个周末无论如何也得写点东西出来,既是总结也是分享.那么本文主要的内容集中在了委托的使用以及内部结构(当然还有事件了,但 ...

  9. Spring IoC源码解析——Bean的创建和初始化

    Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器 ...

  10. 作为一个程序猿,是不是经常会用到.chm文档,但是我们可能会遇到这样那样的问题,比如.chm文档打不开

    .chm文档不能正常打开,一般有两种情形下会造成文档打不开, 1.系统语言栏的语言和文档的语言类别不一同,也就是说比如你的文档是中文版的,但是系统设置的语言是其他国家的.不过一般这种情况很少出现 ,谁 ...