在beam_bif_load.c中
Eterm
load_module_2(BIF_ALIST_2)
{
Eterm reason;
Eterm* hp;
int i;
int sz;
byte* code;
int trace_pattern_is_on;
Binary *match_spec;
Binary *meta_match_spec;
struct trace_pattern_flags trace_pattern_flags;
Eterm meta_tracer_pid;
Eterm res;
byte* temp_alloc = NULL;
if (is_not_atom(BIF_ARG_1)) {
error:
erts_free_aligned_binary_bytes(temp_alloc);
BIF_ERROR(BIF_P, BADARG);
}
if ((code = erts_get_aligned_binary_bytes(BIF_ARG_2, &temp_alloc)) == NULL) {
goto error;
}
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
erts_smp_block_system(0);
erts_export_consolidate();
hp = HAlloc(BIF_P, 3);
sz = binary_size(BIF_ARG_2);
if ((i = erts_load_module (BIF_P, 0,
BIF_P->group_leader, &BIF_ARG_1, code, sz)) < 0) {
switch (i) {
case -1: reason = am_badfile; break;
case -2: reason = am_nofile; break;
case -3: reason = am_not_purged; break;
case -4:
reason = am_atom_put("native_code", sizeof("native_code")-1);
break;
default: reason = am_badfile; break;
}
res = TUPLE2(hp, am_error, reason);
goto done;
}
erts_get_default_trace_pattern(&trace_pattern_is_on,
&match_spec,
&meta_match_spec,
&trace_pattern_flags,
&meta_tracer_pid);
if (trace_pattern_is_on) {
Eterm mfa[1];
mfa[0] = BIF_ARG_1;
(void) erts_set_trace_pattern(mfa, 1,
match_spec,
meta_match_spec,
1, trace_pattern_flags,
meta_tracer_pid);
}
res = TUPLE2(hp, am_module, BIF_ARG_1);
done:
erts_free_aligned_binary_bytes(temp_alloc);
erts_smp_release_system();
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
BIF_RET(res);
}
看点:1、binary.c中的erts_get_aligned_binary_bytes和erts_free_aligned_binary_bytes
2、export.c中的erts_export_consolidate
3、beam_load.c中的erts_load_module(本bif实质上还是调用的beam_load)
4、erl_bif_trace.c中的erts_set_trace_pattern和get
5、erl_term.c中的TUPLE2
2. beam_load:erts_load_module
int
erts_load_module(Process *c_p,
ErtsProcLocks c_p_locks,
Eterm group_leader, /* Group leader or NIL if none. */
Eterm* modp, /*
* Module name as an atom (NIL to not check).
* On return, contains the actual module name.
*/
byte* code, /* Points to the code to load */
int size) /* Size of code to load. */
{
ErlDrvBinary* bin;
int result;
if (size >= 4 && code[0] == 'F' && code[1] == 'O' &&
code[2] == 'R' && code[3] == '1') {
/*
* The BEAM module is not compressed.
*/
result = bin_load (c_p, c_p_locks, group_leader, modp, code, size);
} else {
/*
* The BEAM module is compressed (or possibly invalid/corrupted).
*/
if ((bin = (ErlDrvBinary *) erts_gzinflate_buffer((char*)code, size)) == NULL) {
return -1;
}
result = bin_load (c_p, c_p_locks, group_leader, modp,
(byte*)bin->orig_bytes, bin->orig_size);
driver_free_binary(bin);
}
return result;
}
代码块开始是“FOR1”,
3. beam_load:bin_load
static int
bin_load(Process *c_p, ErtsProcLocks c_p_locks,
Eterm group_leader, Eterm* modp, byte* bytes, int unloaded_size)
{
LoaderState state;
int rval = -1;
init_state(&state);
state.module = *modp;
state.group_leader = group_leader;
/*
* Scan the IFF file.
*/
state.file_name = "IFF header for Beam file";
state.file_p = bytes;
state.file_left = unloaded_size;
if (!scan_iff_file(&state, chunk_types, NUM_CHUNK_TYPES, NUM_MANDATORY)) {
goto load_error;
}
/*
* Read the header for the code chunk.
*/
define_file(&state, "code chunk header", CODE_CHUNK);
if (!read_code_header(&state)) {
goto load_error;
}
/*
* Read the atom table.
*/
define_file(&state, "atom table", ATOM_CHUNK);
if (!load_atom_table(&state)) {
goto load_error;
}
/*
* Read the import table.
*/
define_file(&state, "import table", IMP_CHUNK);
if (!load_import_table(&state)) {
goto load_error;
}
/*
* Read the lambda (fun) table.
*/
if (state.chunks[LAMBDA_CHUNK].size > 0) {
define_file(&state, "lambda (fun) table", LAMBDA_CHUNK);
if (!read_lambda_table(&state)) {
goto load_error;
}
}
/*
* Read the literal table.
*/
if (state.chunks[LITERAL_CHUNK].size > 0) {
define_file(&state, "literals table (constant pool)", LITERAL_CHUNK);
if (!read_literal_table(&state)) {
goto load_error;
}
}
/*
* Load the code chunk.
*/
state.file_name = "code chunk";
state.file_p = state.code_start;
state.file_left = state.code_size;
if (!load_code(&state) || !freeze_code(&state)) {
goto load_error;
}
/*
* Read and validate the export table. (This must be done after
* loading the code, because it contains labels.)
*/
define_file(&state, "export table", EXP_CHUNK);
if (!read_export_table(&state)) {
goto load_error;
}
/*
* Ready for the final touch: fixing the export table entries for
* exported and imported functions. This can't fail.
*/
rval = insert_new_code (c_p, c_p_locks, state.group_leader, state.module,
state.code, state.loaded_size, state.catches);
if (rval < 0) {
goto load_error;
}
final_touch(&state);
/*
* Loading succeded.
*/
rval = 0;
state.code = NULL; /* Prevent code from being freed. */
*modp = state.module;
load_error:
if (state.code != 0) {
erts_free(ERTS_ALC_T_CODE, state.code);
}
if (state.labels != NULL) {
erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.labels);
}
if (state.atom != NULL) {
erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.atom);
}
if (state.import != NULL) {
erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.import);
}
if (state.export != NULL) {
erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.export);
}
if (state.lambdas != state.def_lambdas) {
erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.lambdas);
}
if (state.literals != NULL) {
int i;
for (i = 0; i < state.num_literals; i++) {
if (state.literals[i].heap != NULL) {
erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.literals[i].heap);
}
}
erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.literals);
}
while (state.literal_patches != NULL) {
LiteralPatch* next = state.literal_patches->next;
erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.literal_patches);
state.literal_patches = next;
}
while (state.string_patches != NULL) {
StringPatch* next = state.string_patches->next;
erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.string_patches);
state.string_patches = next;
}
while (state.genop_blocks) {
GenOpBlock* next = state.genop_blocks->next;
erts_free(ERTS_ALC_T_LOADER_TMP, (void *) state.genop_blocks);
state.genop_blocks = next;
}
return rval;
}
Insert_new_code是把Code放到module_table中,同时更新加载的模块数等全局变量;
final_touch是更新export。
4. beam_load: insert_new_code
static int
insert_new_code(Process *c_p, ErtsProcLocks c_p_locks,
Eterm group_leader, Eterm module, Eterm* code, Uint size, Uint catches)
{
Module* modp;
int rval;
int i;
if ((rval = beam_make_current_old(c_p, c_p_locks, module)) < 0) {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
erts_dsprintf(dsbufp,
"Module %T must be purged before loading\n",
module);
erts_send_error_to_logger(group_leader, dsbufp);
return rval;
}
/*
* Update module table.
*/
erts_total_code_size += size;
modp = erts_put_module(module);
modp->code = code;
modp->code_length = size;
modp->catches = catches;
/*
* Update address table (used for finding a function from a PC value).
*/
if (num_loaded_modules == allocated_modules) {
allocated_modules *= 2;
modules = (Range *) erts_realloc(ERTS_ALC_T_MODULE_REFS,
(void *) modules,
allocated_modules * sizeof(Range));
}
for (i = num_loaded_modules; i > 0; i--) {
if (code > modules[i-1].start) {
break;
}
modules[i] = modules[i-1];
}
modules[i].start = code;
modules[i].end = (Eterm *) (((byte *)code) + size);
num_loaded_modules++;
mid_module = &modules[num_loaded_modules/2];
return 0;
}
如果modules满了,则再分配同样多的;
modules(全局变量)的结构,Range*。只是一个附加变量,主要内容在modp = erts_put_module(module);中,需要看全局变量module_table(index)
typedef struct {
Eterm* start; /* Pointer to start of module. */
Eterm* end; /* Points one word beyond last function in module. */
} Range;
5. beam_load:final_touch
static void
final_touch(LoaderState* stp)
{
int i;
/*
* Export functions.
*/
for (i = 0; i < stp->num_exps; i++) {
Export* ep = erts_export_put (stp->module, stp->export[i].function,
stp->export[i].arity);
ep->address = stp->export[i].address;
}
/*
* Import functions and patch all callers.
*/
for (i = 0; i < stp->num_imports; i++) {
Eterm mod;
Eterm func;
Uint arity;
Uint import;
Uint current;
Uint next;
mod = stp->import[i].module;
func = stp->import[i].function;
arity = stp->import[i].arity;
import = (Uint) erts_export_put(mod, func, arity);
current = stp->import[i].patches;
while (current != 0) {
ASSERT(current < stp->ci);
next = stp->code[current];
stp->code[current] = import;
current = next;
}
}
/*
* Fix all funs.
*/
if (stp->num_lambdas > 0) {
for (i = 0; i < stp->num_lambdas; i++) {
unsigned entry_label = stp->lambdas[i].label;
ErlFunEntry* fe = stp->lambdas[i].fe;
Eterm* code_ptr = (Eterm *) (stp->code + stp->labels[entry_label].value);
if (fe->address[0] != 0) {
/*
* We are hiding a pointer into older code.
*/
erts_refc_dec(&fe->refc, 1);
}
fe->address = code_ptr;
#ifdef HIPE
hipe_set_closure_stub(fe, stp->lambdas[i].num_free);
#endif
}
}
}