

File | Path |
beam_makeops | erts/emulator/utils/ |
ops.tab | erts/emulator/beam/ |
beam_opcodes.c | erts/emulator/<machine>/opt/smp/ |
beam_load.c | erts/emulator/beam/ |
genop.tab | lib/compiler/src/ |
/*
* X register zero; also called r(0)
*/
register Eterm x0 REG_x0 = NIL;register修饰符的作用是暗示编译器,某个变量将被频繁使用,尽可能将其保存在CPU的寄存器中,以加快其存储速度。随着编译程序设计技术的进步,在决定那些变量应该被存到寄存器中时,现在的编译器能比程序员做出更好的决定,往往会忽略register修饰符。但是就erlang虚拟机对寄存器变量的使用程度,应该是可以利用到CPU寄存器的好处。while(1){
opcode = *vPC++;
switch(opcode){
case i_call_fun:
..
break;
case call_bif_e:
..
break;
//and many more..
}
};字节码在虚拟机中执行,执行过程类似CPU执行指令过程,分为取指,解码,执行3个过程。通常情况下,每个操作码对应一段处理函数,然后通过一个无限循环加一个switch的方式进行分派。start()->
spawn(fun() -> fun1(1) end). %% 创建进程,执行 fun1/1
fun1(A) ->
A1 = A + 1,
B = trunc(A1), %% 执行 trunc/1
{ok, A1+B}.以上,进程在执行函数( trunc/1)调用前,会将当前的本地变量和返回地址指针CP写入栈。然后,在执行完这个函数(trunc/1)后再从栈取出CP指令和本地变量,根据CP指针返回调用处,继续执行后面的代码。




Export* bif_export[BIF_SIZE];
BifEntry bif_table[] = {
{am_erlang, am_abs, 1, abs_1, abs_1},
{am_erlang, am_adler32, 1, adler32_1, wrap_adler32_1},
{am_erlang, am_adler32, 2, adler32_2, wrap_adler32_2},
{am_erlang, am_adler32_combine, 3, adler32_combine_3, wrap_adler32_combine_3},
{am_erlang, am_apply, 3, apply_3, wrap_apply_3},
{am_erlang, am_atom_to_list, 1, atom_to_list_1, wrap_atom_to_list_1},typedef struct bif_entry {
Eterm module;
Eterm name;
int arity;
BifFunction f; // bif函数
BifFunction traced; // 函数调用跟踪函数
} BifEntry;erlang BEAM模拟器启动时会初始化bif函数表,init_emulator:
{
em_call_error_handler = OpCode(call_error_handler);
em_apply_bif = OpCode(apply_bif);
beam_apply[0] = (BeamInstr) OpCode(i_apply);
beam_apply[1] = (BeamInstr) OpCode(normal_exit);
beam_exit[0] = (BeamInstr) OpCode(error_action_code);
beam_continue_exit[0] = (BeamInstr) OpCode(continue_exit);
beam_return_to_trace[0] = (BeamInstr) OpCode(i_return_to_trace);
beam_return_trace[0] = (BeamInstr) OpCode(return_trace);
beam_exception_trace[0] = (BeamInstr) OpCode(return_trace); /* UGLY */
beam_return_time_trace[0] = (BeamInstr) OpCode(i_return_time_trace);
/*
* Enter all BIFs into the export table.
*/
for (i = 0; i < BIF_SIZE; i++) {
ep = erts_export_put(bif_table[i].module, //模块名
bif_table[i].name,
bif_table[i].arity);
bif_export[i] = ep;
ep->code[3] = (BeamInstr) OpCode(apply_bif);
ep->code[4] = (BeamInstr) bif_table[i].f; // BIF函数
/* XXX: set func info for bifs */
ep->fake_op_func_info_for_hipe[0] = (BeamInstr) BeamOp(op_i_func_info_IaaI);
}
/*
* 以下截取 bif 处理过程
*/
OpCase(call_bif_e):
{
Eterm (*bf)(Process*, Eterm*, BeamInstr*) = GET_BIF_ADDRESS(Arg(0)); // 根据参数获取bif实际执行函数
Eterm result;
BeamInstr *next;
PRE_BIF_SWAPOUT(c_p);
c_p->fcalls = FCALLS - 1;
if (FCALLS <= 0) {
save_calls(c_p, (Export *) Arg(0));
}
PreFetch(1, next);
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
reg[0] = r(0);
result = (*bf)(c_p, reg, I); // 执行bif函数
ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result));
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
ERTS_HOLE_CHECK(c_p);
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
if (c_p->mbuf || MSO(c_p).overhead >= BIN_VHEAP_SZ(c_p)) {
Uint arity = ((Export *)Arg(0))->code[2];
result = erts_gc_after_bif_call(c_p, result, reg, arity);
E = c_p->stop;
}
HTOP = HEAP_TOP(c_p);
FCALLS = c_p->fcalls;
if (is_value(result)) {
r(0) = result;
CHECK_TERM(r(0));
NextPF(1, next);
} else if (c_p->freason == TRAP) {
SET_CP(c_p, I+2);
SET_I(c_p->i);
SWAPIN;
r(0) = reg[0];
Dispatch();
}上面涉及到一个宏,就是取得bif函数地址。#define GET_BIF_ADDRESS(p) ((BifFunction) (((Export *) p)->code[4]))根据前面提到的,((Export *) p)->code[4] 就是 bif_table表的中BIF函数的地址。
| Type | Description |
|---|---|
| t | An arbitrary term, e.g. {ok,[]} |
| I | An integer literal, e.g. 137 |
| x | A register, r.g. R1 |
| y | A stack slot |
| c | An immediate term, i.e. atom/small int/nil |
| a | An atom, e.g. ‘ok‘ |
| f | A code label |
| s | Either a literal, a register or a stack slot |
| d | Either a register or a stack slot |
| r | A register R0 |
| P | A unsigned integer literal |
| j | An optional code label |
| e | A reference to an export table entry |
| l | A floating-point register |
原文:http://blog.csdn.net/mycwq/article/details/45653897