📄 hipe_bif0.c
字号:
return p; p = hipe_mfa_info_table_alloc(m, f, arity); p->bucket.hvalue = h; p->bucket.next = hipe_mfa_info_table.bucket[i]; hipe_mfa_info_table.bucket[i] = p; hipe_mfa_info_table.used += 1; size = 1 << hipe_mfa_info_table.log2size; if( hipe_mfa_info_table.used > (4*size/5) ) /* rehash at 80% */ hipe_mfa_info_table_grow(); return p;}static void hipe_mfa_set_na(Eterm m, Eterm f, unsigned int arity, void *address, int is_exported){ struct hipe_mfa_info *p = hipe_mfa_info_table_put(m, f, arity);#ifdef DEBUG_LINKER printf("%s: ", __FUNCTION__); print_mfa(m, f, arity); printf(": changing address from %p to %p\r\n", p->local_address, address);#endif p->local_address = address; if (is_exported) p->remote_address = address;}#if defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__) || defined(__arm__)void *hipe_mfa_get_trampoline(Eterm m, Eterm f, unsigned int arity){ struct hipe_mfa_info *p = hipe_mfa_info_table_put(m, f, arity); return p->trampoline;}void hipe_mfa_set_trampoline(Eterm m, Eterm f, unsigned int arity, void *trampoline){ struct hipe_mfa_info *p = hipe_mfa_info_table_put(m, f, arity); p->trampoline = trampoline;}#endifBIF_RETTYPE hipe_bifs_set_funinfo_native_address_3(BIF_ALIST_3){ struct mfa mfa; void *address; int is_exported; if (!term_to_mfa(BIF_ARG_1, &mfa)) BIF_ERROR(BIF_P, BADARG); address = term_to_address(BIF_ARG_2); if( !address ) BIF_ERROR(BIF_P, BADARG); if (BIF_ARG_3 == am_true) is_exported = 1; else if (BIF_ARG_3 == am_false) is_exported = 0; else BIF_ERROR(BIF_P, BADARG); hipe_mfa_set_na(mfa.mod, mfa.fun, mfa.ari, address, is_exported); BIF_RET(NIL);}BIF_RETTYPE hipe_bifs_invalidate_funinfo_native_addresses_1(BIF_ALIST_1){ Eterm lst; struct mfa mfa; struct hipe_mfa_info *p; lst = BIF_ARG_1; while (is_list(lst)) { if (!term_to_mfa(CAR(list_val(lst)), &mfa)) BIF_ERROR(BIF_P, BADARG); lst = CDR(list_val(lst)); p = hipe_mfa_info_table_get(mfa.mod, mfa.fun, mfa.ari); if (p) { p->remote_address = NULL; p->local_address = NULL; if (p->beam_code) {#ifdef DEBUG_LINKER printf("%s: ", __FUNCTION__); print_mfa(mfa.mod, mfa.fun, mfa.ari); printf(": removing call trap from BEAM pc %p (new op %#lx)\r\n", p->beam_code, p->orig_beam_op);#endif p->beam_code[0] = p->orig_beam_op; p->beam_code = NULL; p->orig_beam_op = 0; } else {#ifdef DEBUG_LINKER printf("%s: ", __FUNCTION__); print_mfa(mfa.mod, mfa.fun, mfa.ari); printf(": no call trap to remove\r\n");#endif } } } if (is_not_nil(lst)) BIF_ERROR(BIF_P, BADARG); BIF_RET(NIL);}void hipe_mfa_save_orig_beam_op(Eterm mod, Eterm fun, unsigned int ari, Eterm *pc){ Uint orig_beam_op; struct hipe_mfa_info *p; orig_beam_op = pc[0]; if (orig_beam_op != BeamOpCode(op_hipe_trap_call_closure) && orig_beam_op != BeamOpCode(op_hipe_trap_call)) { p = hipe_mfa_info_table_put(mod, fun, ari);#ifdef DEBUG_LINKER printf("%s: ", __FUNCTION__); print_mfa(mod, fun, ari); printf(": saving orig op %#lx from BEAM pc %p\r\n", orig_beam_op, pc);#endif p->beam_code = pc; p->orig_beam_op = orig_beam_op; } else {#ifdef DEBUG_LINKER printf("%s: ", __FUNCTION__); print_mfa(mod, fun, ari); printf(": orig op %#lx already saved\r\n", orig_beam_op);#endif }}static void *hipe_make_stub(Eterm m, Eterm f, unsigned int arity, int is_remote){ void *BEAMAddress; void *StubAddress;#if 0 if( is_not_atom(m) || is_not_atom(f) || arity > 255 ) return NULL;#endif BEAMAddress = hipe_get_emu_address(m, f, arity, is_remote); StubAddress = hipe_make_native_stub(BEAMAddress, arity);#if 0 hipe_mfa_set_na(m, f, arity, StubAddress);#endif return StubAddress;}static void *hipe_get_na_nofail(Eterm m, Eterm f, unsigned int a, int is_remote){ struct hipe_mfa_info *p; void *address; p = hipe_mfa_info_table_get(m, f, a); if (p) { /* find address, predicting for a runtime apply call */ address = p->remote_address; if (!is_remote) address = p->local_address; if (address) return address; /* bummer, install stub, checking if one already existed */ address = p->remote_address; if (address) return address; } else { p = hipe_mfa_info_table_put(m, f, a); } address = hipe_make_stub(m, f, a, is_remote); /* XXX: how to tell if a BEAM MFA is exported or not? */ p->remote_address = address; return address;}/* used for apply/3 in hipe_mode_switch */void *hipe_get_remote_na(Eterm m, Eterm f, unsigned int a){ if (is_not_atom(m) || is_not_atom(f) || a > 255) return NULL; return hipe_get_na_nofail(m, f, a, 1);}/* primop, but called like a BIF for error handling purposes */BIF_RETTYPE hipe_find_na_or_make_stub(BIF_ALIST_3){ Uint arity; void *address; if( is_not_atom(BIF_ARG_1) || is_not_atom(BIF_ARG_2) ) BIF_ERROR(BIF_P, BADARG); arity = unsigned_val(BIF_ARG_3); /* no error check */ address = hipe_get_na_nofail(BIF_ARG_1, BIF_ARG_2, arity, 1); BIF_RET((Eterm)address); /* semi-Ok */}BIF_RETTYPE hipe_bifs_find_na_or_make_stub_2(BIF_ALIST_2){ struct mfa mfa; void *address; int is_remote; if (!term_to_mfa(BIF_ARG_1, &mfa)) BIF_ERROR(BIF_P, BADARG); if (BIF_ARG_2 == am_true) is_remote = 1; else if (BIF_ARG_2 == am_false) is_remote = 0; else BIF_ERROR(BIF_P, BADARG); address = hipe_get_na_nofail(mfa.mod, mfa.fun, mfa.ari, is_remote); BIF_RET(address_to_term(address, BIF_P));}/* primop, but called like a BIF for error handling purposes */BIF_RETTYPE hipe_nonclosure_address(BIF_ALIST_2){ Eterm hdr, m, f; void *address; if (!is_boxed(BIF_ARG_1)) goto badfun; hdr = *boxed_val(BIF_ARG_1); if (is_export_header(hdr)) { Export *ep = (Export*)(export_val(BIF_ARG_1)[1]); unsigned int actual_arity = ep->code[2]; if (actual_arity != BIF_ARG_2) goto badfun; m = ep->code[0]; f = ep->code[1]; } else if (hdr == make_arityval(2)) { Eterm *tp = tuple_val(BIF_ARG_1); m = tp[1]; f = tp[2]; if (is_not_atom(m) || is_not_atom(f)) goto badfun; if (!erts_find_export_entry(m, f, BIF_ARG_2)) goto badfun; } else goto badfun; address = hipe_get_na_nofail(m, f, BIF_ARG_2, 1); BIF_RET((Eterm)address); badfun: BIF_P->current = NULL; BIF_P->fvalue = BIF_ARG_1; BIF_ERROR(BIF_P, EXC_BADFUN);}/* * Patch Reference Handling. */struct hipe_mfa_info_list { struct hipe_mfa_info *mfa; struct hipe_mfa_info_list *next;};struct ref { struct hipe_mfa_info *caller_mfa; void *address; void *trampoline; unsigned int flags; struct ref *next;};#define REF_FLAG_IS_LOAD_MFA 1 /* bit 0: 0 == call, 1 == load_mfa */#define REF_FLAG_IS_REMOTE 2 /* bit 1: 0 == local, 1 == remote */#define REF_FLAG_PENDING_REDIRECT 4 /* bit 2: 1 == pending redirect */#define REF_FLAG_PENDING_REMOVE 8 /* bit 3: 1 == pending remove *//* add_ref(CalleeMFA, {CallerMFA,Address,'call'|'load_mfa',Trampoline,'remote'|'local'}) */BIF_RETTYPE hipe_bifs_add_ref_2(BIF_ALIST_2){ struct mfa callee; Eterm *tuple; struct mfa caller; void *address; void *trampoline; unsigned int flags; struct hipe_mfa_info *callee_mfa; struct hipe_mfa_info *caller_mfa; struct hipe_mfa_info_list *refers_to; struct ref *ref; if (!term_to_mfa(BIF_ARG_1, &callee)) goto badarg; if (is_not_tuple(BIF_ARG_2)) goto badarg; tuple = tuple_val(BIF_ARG_2); if (tuple[0] != make_arityval(5)) goto badarg; if (!term_to_mfa(tuple[1], &caller)) goto badarg; address = term_to_address(tuple[2]); if (!address) goto badarg; switch (tuple[3]) { case am_call: flags = 0; break; case am_load_mfa: flags = REF_FLAG_IS_LOAD_MFA; break; default: goto badarg; } if (is_nil(tuple[4])) trampoline = NULL; else { trampoline = term_to_address(tuple[4]); if (!trampoline) goto badarg; } switch (tuple[5]) { case am_local: break; case am_remote: flags |= REF_FLAG_IS_REMOTE; break; default: goto badarg; } callee_mfa = hipe_mfa_info_table_put(callee.mod, callee.fun, callee.ari); caller_mfa = hipe_mfa_info_table_put(caller.mod, caller.fun, caller.ari); refers_to = erts_alloc(ERTS_ALC_T_HIPE, sizeof(*refers_to)); refers_to->mfa = callee_mfa; refers_to->next = caller_mfa->refers_to; caller_mfa->refers_to = refers_to; ref = erts_alloc(ERTS_ALC_T_HIPE, sizeof(*ref)); ref->caller_mfa = caller_mfa; ref->address = address; ref->trampoline = trampoline; ref->flags = flags; ref->next = callee_mfa->referred_from; callee_mfa->referred_from = ref; BIF_RET(NIL); badarg: BIF_ERROR(BIF_P, BADARG); }/* Given a CalleeMFA, mark each ref to it as pending-redirect. * This ensures that remove_refs_from() won't remove them: any * removal is instead done at the end of redirect_referred_from(). */BIF_RETTYPE hipe_bifs_mark_referred_from_1(BIF_ALIST_1) /* get_refs_from */{ struct mfa mfa; const struct hipe_mfa_info *p; struct ref *ref; if (!term_to_mfa(BIF_ARG_1, &mfa)) BIF_ERROR(BIF_P, BADARG); p = hipe_mfa_info_table_get(mfa.mod, mfa.fun, mfa.ari); if (p) for(ref = p->referred_from; ref != NULL; ref = ref->next) ref->flags |= REF_FLAG_PENDING_REDIRECT; BIF_RET(NIL);}BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1){ struct mfa mfa; struct hipe_mfa_info *caller_mfa, *callee_mfa; struct hipe_mfa_info_list *refers_to, *tmp_refers_to; struct ref **prev, *ref; if (!term_to_mfa(BIF_ARG_1, &mfa)) BIF_ERROR(BIF_P, BADARG); caller_mfa = hipe_mfa_info_table_get(mfa.mod, mfa.fun, mfa.ari); if (caller_mfa) { refers_to = caller_mfa->refers_to; while (refers_to) { callee_mfa = refers_to->mfa; prev = &callee_mfa->referred_from; ref = *prev; while (ref) { if (ref->caller_mfa == caller_mfa) { if (ref->flags & REF_FLAG_PENDING_REDIRECT) { ref->flags |= REF_FLAG_PENDING_REMOVE; prev = &ref->next; ref = ref->next; } else { struct ref *tmp = ref; ref = ref->next; *prev = ref; erts_free(ERTS_ALC_T_HIPE, tmp); } } else { prev = &ref->next; ref = ref->next; } } tmp_refers_to = refers_to; refers_to = refers_to->next; erts_free(ERTS_ALC_T_HIPE, tmp_refers_to); } caller_mfa->refers_to = NULL; } BIF_RET(NIL);}/* redirect_referred_from(CalleeMFA) * Redirect all pending-redirect refs in CalleeMFA's referred_from. * Then remove any pending-redirect && pending-remove refs from CalleeMFA's referred_from. */BIF_RETTYPE hipe_bifs_redirect_referred_from_1(BIF_ALIST_1){ struct mfa mfa; struct hipe_mfa_info *p; struct ref **prev, *ref; int is_remote, res; void *new_address; if (!term_to_mfa(BIF_ARG_1, &mfa)) BIF_ERROR(BIF_P, BADARG); p = hipe_mfa_info_table_get(mfa.mod, mfa.fun, mfa.ari); if (p) { prev = &p->referred_from; ref = *prev; while (ref) { if (ref->flags & REF_FLAG_PENDING_REDIRECT) { is_remote = ref->flags & REF_FLAG_IS_REMOTE; new_address = hipe_get_na_nofail(p->m, p->f, p->a, is_remote); if (ref->flags & REF_FLAG_IS_LOAD_MFA) res = hipe_patch_insn(ref->address, (Uint)new_address, am_load_mfa); else res = hipe_patch_call(ref->address, new_address, ref->trampoline); if (res) fprintf(stderr, "%s: patch failed\r\n", __FUNCTION__); ref->flags &= ~REF_FLAG_PENDING_REDIRECT; if (ref->flags & REF_FLAG_PENDING_REMOVE) { struct ref *tmp = ref; ref = ref->next; *prev = ref; erts_free(ERTS_ALC_T_HIPE, tmp); } else { prev = &ref->next; ref = ref->next; } } else { prev = &ref->next; ref = ref->next; } } } BIF_RET(NIL);}BIF_RETTYPE hipe_bifs_check_crc_1(BIF_ALIST_1){ Uint crc; if (!term_to_Uint(BIF_ARG_1, &crc)) BIF_ERROR(BIF_P, BADARG); if (crc == HIPE_SYSTEM_CRC) BIF_RET(am_true); BIF_RET(am_false);}BIF_RETTYPE hipe_bifs_system_crc_1(BIF_ALIST_1){ Uint crc; if (!term_to_Uint(BIF_ARG_1, &crc)) BIF_ERROR(BIF_P, BADARG); crc ^= (HIPE_SYSTEM_CRC ^ HIPE_LITERALS_CRC); BIF_RET(Uint_to_term(crc, BIF_P));}BIF_RETTYPE hipe_bifs_get_rts_param_1(BIF_ALIST_1){ unsigned int is_defined; unsigned long value; if( is_not_small(BIF_ARG_1) ) BIF_ERROR(BIF_P, BADARG); is_defined = 1; value = 0; switch( unsigned_val(BIF_ARG_1) ) { RTS_PARAMS_CASES default: BIF_ERROR(BIF_P, BADARG); } if( !is_defined ) BIF_RET(NIL); BIF_RET(Uint_to_term(value, BIF_P));}void hipe_patch_address(Uint *address, Eterm patchtype, Uint value){ switch( patchtype ) { case am_load_fe: hipe_patch_load_fe(address, value); return; default: fprintf(stderr, "%s: unknown patchtype %#lx\r\n", __FUNCTION__, patchtype); return; }}struct modinfo { HashBucket bucket; /* bucket.hvalue == atom_val(the module name) */ unsigned int code_size;};static Hash modinfo_table;static HashValue modinfo_hash(void *tmpl){ Eterm mod = (Eterm)tmpl; return atom_val(mod);}static int modinfo_cmp(void *tmpl, void *bucket){ /* bucket->hvalue == modinfo_hash(tmpl), so just return 0 (match) */ return 0;}static void *modinfo_alloc(void *tmpl){ struct modinfo *p; p = (struct modinfo*)erts_alloc(ERTS_ALC_T_HIPE, sizeof(*p)); p->code_size = 0; return &p->bucket;}static void init_modinfo_table(void){ HashFunctions f; static int init_done = 0; if (init_done) return; init_done = 1; f.hash = (H_FUN) modinfo_hash; f.cmp = (HCMP_FUN) modinfo_cmp; f.alloc = (HALLOC_FUN) modinfo_alloc; f.free = (HFREE_FUN) NULL; hash_init(ERTS_ALC_T_HIPE, &modinfo_table, "modinfo_table", 11, f);}BIF_RETTYPE hipe_bifs_update_code_size_3(BIF_ALIST_3){ struct modinfo *p; Sint code_size; init_modinfo_table(); if (is_not_atom(BIF_ARG_1) || is_not_small(BIF_ARG_3) || (code_size = signed_val(BIF_ARG_3)) < 0) BIF_ERROR(BIF_P, BADARG); p = (struct modinfo*)hash_put(&modinfo_table, (void*)BIF_ARG_1); if (is_nil(BIF_ARG_2)) /* some MFAs, not whole module */ p->code_size += code_size; else /* whole module */ p->code_size = code_size; BIF_RET(NIL);}BIF_RETTYPE hipe_bifs_code_size_1(BIF_ALIST_1){ struct modinfo *p; unsigned int code_size; init_modinfo_table(); if (is_not_atom(BIF_ARG_1)) BIF_ERROR(BIF_P, BADARG); p = (struct modinfo*)hash_get(&modinfo_table, (void*)BIF_ARG_1); code_size = p ? p->code_size : 0; BIF_RET(make_small(code_size));}BIF_RETTYPE hipe_bifs_patch_insn_3(BIF_ALIST_3){ Uint *address, value; address = term_to_address(BIF_ARG_1); if (!address) BIF_ERROR(BIF_P, BADARG); if (!term_to_Uint(BIF_ARG_2, &value)) BIF_ERROR(BIF_P, BADARG); if (hipe_patch_insn(address, value, BIF_ARG_3)) BIF_ERROR(BIF_P, BADARG); BIF_RET(NIL);}BIF_RETTYPE hipe_bifs_patch_call_3(BIF_ALIST_3){ Uint *callAddress, *destAddress, *trampAddress; callAddress = term_to_address(BIF_ARG_1); if (!callAddress) BIF_ERROR(BIF_P, BADARG); destAddress = term_to_address(BIF_ARG_2); if (!destAddress) BIF_ERROR(BIF_P, BADARG); if (is_nil(BIF_ARG_3)) trampAddress = NULL; else { trampAddress = term_to_address(BIF_ARG_3); if (!trampAddress) BIF_ERROR(BIF_P, BADARG); } if (hipe_patch_call(callAddress, destAddress, trampAddress)) BIF_ERROR(BIF_P, BADARG); BIF_RET(NIL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -