[Erlang 0125] Know a little Erlang opcode
下面的代码里面,模块t还没有编译,所以第一次执行erts_debug:df(t)返回值是{undef,t}
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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理解更深>就是这样做的,下面把我比较关注的一些地方做下测试.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
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)会触发热更新,测试代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
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 里面大部分代码都做了一下测试,目的是想从一个新的角度切入以前的问题,其中一个比较有意思的是:
1
2
3
4
5
6
7
8
9
10
11
12
|
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
|
这个方法由于中间的变量都是已知的,编译之后直接使用运算结果了:
1
2
3
4
5
6
7
|
{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 里面提到函数分支的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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的执行过程被分成了三段;再回头看上面的说明,是不是就清晰多了.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
{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
本文转自博客园坚强2002的博客,原文链接:
http://www.cnblogs.com/me-sa/p/know-a-little-erlang-opcode.html
如需转载请自行联系原博主。
[Erlang 0125] Know a little Erlang opcode相关推荐
- linux查看erlang安装目录,Linux 安装Erlang
Erlang目前已经是Fedora和Debian/Ubuntu软件仓库中的一部分. Erlang目前最新的版本是OTP 17.0.Erlang是一种编程语言,用于构建大规模.高可伸缩性.高可用性的软实 ...
- Erlang基础 -- 介绍 -- 历史及Erlang并发
前言 最近在总结一些Erlang编程语言的基础知识,拟系统的介绍Erlang编程语言,从基础到进阶,然后再做Erlang编程语言有意思的库的分析. 其实,还是希望越来越多的人关注Erlang,使用Er ...
- 【Erlang新手成长日记】Erlang开源项目推荐
学习一门新语言,需要多看,多想,多写. 多看,就要阅读优秀的源代码. 以下是自己找到4款优秀的Erlang开源项目: Cowboy HTTP服务器 简介: Cowboy是一款小而快速的模块化HTTP服 ...
- erlang底层c定时器设计-Erlang源码学习二
Erlang底层的定时器实现位于源码的erts/emulator/beam/time.c文件,用时间轮的方式动态添加和删除定时器,结构体名为typedef struct ErtsTimerWheel_ ...
- Erlang程序设计笔记---(第三节 Erlang的基本概念)
Erlang的基本概念 一. 简单的整数运算 Erlang遵循算术表达式的一般规则 Erlang可以用任意长度的整数执行整数运算.在Erlang里,整数运算是精确的,因此无需担 心运算溢出或无法用特定 ...
- 解决escript: exception error: undefined function rabbitmqctl_escript:main/1问题以及如何安装Erlang和RabbitMq
文章目录 1. 复现问题 2. 分析问题 3. 解决问题 4.如何安装Erlang和RabbitMq 1. 复现问题 今天在安装Erlang和RabbitMq完成后,在cmd窗口中输入如下命令: ra ...
- Erlang 数据类型。。
2019独角兽企业重金招聘Python工程师标准>>> 数值 二进制串/位串 原子 元祖 列表 唯一标识符(pid,端口,引用) Fun 函数 Erlang 中的数据通常被称作项式 ...
- Erlang(起个中文名:易浪)不能错过的盛宴
评:erlang(起个中文名:易浪),在穿戴设备技术,云技术,大数据,游戏服务器等等高并发分布式必然大有用处,这个语言必火!-传统语言除了java和c,其他的必然会死去,今后一定会出现新的类erlan ...
- 不是语言之争---Go vs Erlang
因为 云巴 系统对高并发.低延迟的需求,我们对各个语言.平台做了很多的调研比较工作.这自然就包括致力于开发高并发应用的 Go 和 Erlang. 并发 Go 对高并发的支持通过 goroutine 实 ...
- erlang进程的调度效率
一.概述 与大多数的进程相反,Erlang中的并发很廉价,派生出一个进程就跟面向对象的语言中分配一个对象的开销差不多. 在启动一个复杂的运算时,启动运算.派生进程以及返回结果后,所有进程神奇的烟消云散 ...
最新文章
- Python3.6+Django2.0+Xadmin2.0学生信息管理系统-2
- C++学习之路 | PTA乙级—— 1008 数组元素循环右移问题 (20分)(精简)
- TCP协议中三次握手
- python调试_Python 调试
- List集合中对象的排序
- 如何从12306网站下载自己喜欢的手机铃声
- 云计算和大数据时代网络技术揭秘
- Ubuntu系统安装ghostscript seq2logo
- Python——组合数据类型(字符串、元组、列表、字典)转换总结
- 评估分形指数和HURST指数预测金融时间序列的能力
- springboot + vue 全栈开发实战 读书感想
- EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER
- ip关联是什么意思,亚马逊如何防止ip关联(ip关联过多是什么意思)
- Wishbone总线快速了解
- input选择框样式修改与自定义
- 给嵌入式ARM+Linux的初学者
- 金融工程---马尔科夫预测
- Oralce swap 100%案例分析
- Laravel的created_at与deleted_at 类型
- 零知识证明笔记The 9th BIU Winter School on Cryptography