static BIF_RETTYPE append(Process* p, Eterm A, Eterm B) { Eterm list; Eterm copy; Eterm last; size_t need; Eterm* hp; int i; // 列表长度小于0 if ((i = erts_list_length(A)) < 0) { BIF_ERROR(p, BADARG); } if (i == 0) { BIF_RET(B); } else if (is_nil(B)) { BIF_RET(A); } // 先分配 2 * i个大小 need = 2*i; hp = HAlloc(p, need); list = A; /* #define CONS(hp, car, cdr) \ (CAR(hp)=(car), CDR(hp)=(cdr), make_list(hp)) #define CAR(x) ((x)[0]) #define CDR(x) ((x)[1]) */ /* hp[0] = list[0]; hp[1] = (hp[2] + TAG_PRIMARY_LIST); copy = last = (hp + TAG_PRIMARY_LIST); list = list[1]; */ copy = last = CONS(hp, CAR(list_val(list)), make_list(hp+2)); list = CDR(list_val(list)); hp += 2; i--; // 将A的元素全部都复制一遍 while(i--) { Eterm* listp = list_val(list); last = CONS(hp, CAR(listp), make_list(hp+2)); list = CDR(listp); hp += 2; } // 将复制后的一个元素直接指向B CDR(list_val(last)) = B; BIF_RET(copy); }
static void shrink(Process *p, Eterm* ret) { unsigned int range = HASH_RANGE(p->dictionary); unsigned int steps = (range*3) / 10; Eterm hi, lo, tmp; unsigned int i; Eterm *hp; #ifdef DEBUG Eterm *hp_limit; #endif if (range - steps < INITIAL_SIZE) { steps = range - INITIAL_SIZE; } for (i = 0; i < steps; ++i) { ProcDict *pd = p->dictionary; if (pd->splitPosition == 0) { pd->homeSize /= 2; pd->splitPosition = pd->homeSize; } --(pd->splitPosition); hi = ARRAY_GET(pd, (pd->splitPosition + pd->homeSize)); lo = ARRAY_GET(pd, pd->splitPosition); if (hi != NIL) { if (lo == NIL) { array_put(&(p->dictionary), pd->splitPosition, hi); } else { int needed = 4; if (is_list(hi) && is_list(lo)) { needed = 2*erts_list_length(hi); } if (HeapWordsLeft(p) < needed) { BUMP_REDS(p, erts_garbage_collect(p, needed, ret, 1)); hi = pd->data[(pd->splitPosition + pd->homeSize)]; lo = pd->data[pd->splitPosition]; } #ifdef DEBUG hp_limit = p->htop + needed; #endif if (is_tuple(lo)) { if (is_tuple(hi)) { hp = HeapOnlyAlloc(p, 4); tmp = CONS(hp, hi, NIL); hp += 2; array_put(&(p->dictionary), pd->splitPosition, CONS(hp,lo,tmp)); hp += 2; ASSERT(hp <= hp_limit); } else { /* hi is a list */ hp = HeapOnlyAlloc(p, 2); array_put(&(p->dictionary), pd->splitPosition, CONS(hp, lo, hi)); hp += 2; ASSERT(hp <= hp_limit); } } else { /* lo is a list */ if (is_tuple(hi)) { hp = HeapOnlyAlloc(p, 2); array_put(&(p->dictionary), pd->splitPosition, CONS(hp, hi, lo)); hp += 2; ASSERT(hp <= hp_limit); } else { /* Two lists */ hp = HeapOnlyAlloc(p, needed); for (tmp = hi; tmp != NIL; tmp = TCDR(tmp)) { lo = CONS(hp, TCAR(tmp), lo); hp += 2; } ASSERT(hp <= hp_limit); array_put(&(p->dictionary), pd->splitPosition, lo); } } } } array_put(&(p->dictionary), (pd->splitPosition + pd->homeSize), NIL); } if (HASH_RANGE(p->dictionary) <= (p->dictionary->size / 4)) { array_shrink(&(p->dictionary), (HASH_RANGE(p->dictionary) * 3) / 2); } }
BIF_RETTYPE finish_loading_1(BIF_ALIST_1) { Sint i; Sint n; struct m* p = NULL; Uint exceptions; Eterm res; int is_blocking = 0; int do_commit = 0; if (!erts_try_seize_code_write_permission(BIF_P)) { ERTS_BIF_YIELD1(bif_export[BIF_finish_loading_1], BIF_P, BIF_ARG_1); } /* * Validate the argument before we start loading; it must be a * proper list where each element is a magic binary containing * prepared (not previously loaded) code. * * First count the number of elements and allocate an array * to keep the elements in. */ n = erts_list_length(BIF_ARG_1); if (n < 0) { badarg: if (p) { erts_free(ERTS_ALC_T_LOADER_TMP, p); } erts_release_code_write_permission(); BIF_ERROR(BIF_P, BADARG); } p = erts_alloc(ERTS_ALC_T_LOADER_TMP, n*sizeof(struct m)); /* * We now know that the argument is a proper list. Validate * and collect the binaries into the array. */ for (i = 0; i < n; i++) { Eterm* cons = list_val(BIF_ARG_1); Eterm term = CAR(cons); ProcBin* pb; if (!ERTS_TERM_IS_MAGIC_BINARY(term)) { goto badarg; } pb = (ProcBin*) binary_val(term); p[i].code = pb->val; p[i].module = erts_module_for_prepared_code(p[i].code); if (p[i].module == NIL) { goto badarg; } BIF_ARG_1 = CDR(cons); } /* * Since we cannot handle atomic loading of a group of modules * if one or more of them uses on_load, we will only allow * more than one element in the list if none of the modules * have an on_load function. */ if (n > 1) { for (i = 0; i < n; i++) { if (erts_has_code_on_load(p[i].code) == am_true) { erts_free(ERTS_ALC_T_LOADER_TMP, p); erts_release_code_write_permission(); BIF_ERROR(BIF_P, SYSTEM_LIMIT); } } } /* * All types are correct. There cannot be a BADARG from now on. * Before we can start loading, we must check whether any of * the modules already has old code. To avoid a race, we must * not allow other process to initiate a code loading operation * from now on. */ res = am_ok; erts_start_staging_code_ix(n); for (i = 0; i < n; i++) { p[i].modp = erts_put_module(p[i].module); p[i].modp->seen = 0; } exceptions = 0; for (i = 0; i < n; i++) { p[i].exception = 0; if (p[i].modp->seen) { p[i].exception = 1; exceptions++; } p[i].modp->seen = 1; } if (exceptions) { res = exception_list(BIF_P, am_duplicated, p, exceptions); goto done; } for (i = 0; i < n; i++) { if (p[i].modp->curr.num_breakpoints > 0 || p[i].modp->curr.num_traced_exports > 0 || erts_is_default_trace_enabled()) { /* tracing involved, fallback with thread blocking */ erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); is_blocking = 1; break; } } if (is_blocking) { for (i = 0; i < n; i++) { if (p[i].modp->curr.num_breakpoints) { erts_clear_module_break(p[i].modp); ASSERT(p[i].modp->curr.num_breakpoints == 0); } } } exceptions = 0; for (i = 0; i < n; i++) { p[i].exception = 0; if (p[i].modp->curr.code_hdr && p[i].modp->old.code_hdr) { p[i].exception = 1; exceptions++; } } if (exceptions) { res = exception_list(BIF_P, am_not_purged, p, exceptions); } else { /* * Now we can load all code. This can't fail. */ exceptions = 0; for (i = 0; i < n; i++) { Eterm mod; Eterm retval; erts_refc_inc(&p[i].code->refc, 1); retval = erts_finish_loading(p[i].code, BIF_P, 0, &mod); ASSERT(retval == NIL || retval == am_on_load); if (retval == am_on_load) { p[i].exception = 1; exceptions++; } } /* * Check whether any module has an on_load_handler. */ if (exceptions) { res = exception_list(BIF_P, am_on_load, p, exceptions); } do_commit = 1; } done: return staging_epilogue(BIF_P, do_commit, res, is_blocking, p, n); }
static byte* convert_environment(Process* p, Eterm env) { Eterm all; Eterm* temp_heap; Eterm* hp; Uint heap_size; Sint n; Sint size; byte* bytes; int encoding = erts_get_native_filename_encoding(); if ((n = erts_list_length(env)) < 0) { return NULL; } heap_size = 2*(5*n+1); temp_heap = hp = (Eterm *) erts_alloc(ERTS_ALC_T_TMP, heap_size*sizeof(Eterm)); bytes = NULL; /* Indicating error */ /* * All errors below are handled by jumping to 'done', to ensure that the memory * gets deallocated. Do NOT return directly from this function. */ all = CONS(hp, make_small(0), NIL); hp += 2; while(is_list(env)) { Eterm tmp; Eterm* tp; tmp = CAR(list_val(env)); if (is_not_tuple_arity(tmp, 2)) { goto done; } tp = tuple_val(tmp); tmp = CONS(hp, make_small(0), NIL); hp += 2; if (tp[2] != am_false) { tmp = CONS(hp, tp[2], tmp); hp += 2; } tmp = CONS(hp, make_small('='), tmp); hp += 2; tmp = CONS(hp, tp[1], tmp); hp += 2; all = CONS(hp, tmp, all); hp += 2; env = CDR(list_val(env)); } if (is_not_nil(env)) { goto done; } if ((size = erts_native_filename_need(all,encoding)) < 0) { goto done; } /* * Put the result in a binary (no risk for a memory leak that way). */ (void) erts_new_heap_binary(p, NULL, size, &bytes); erts_native_filename_put(all,encoding,bytes); done: erts_free(ERTS_ALC_T_TMP, temp_heap); return bytes; }
static Eterm subtract(Process* p, Eterm A, Eterm B) { Eterm list; Eterm* hp; Uint need; Eterm res; Eterm small_vec[SMALL_VEC_SIZE]; /* Preallocated memory for small lists */ Eterm* vec_p; Eterm* vp; int i; int n; int m; if ((n = erts_list_length(A)) < 0) { BIF_ERROR(p, BADARG); } if ((m = erts_list_length(B)) < 0) { BIF_ERROR(p, BADARG); } if (n == 0) BIF_RET(NIL); if (m == 0) BIF_RET(A); /* allocate element vector */ if (n <= SMALL_VEC_SIZE) vec_p = small_vec; else vec_p = (Eterm*) erts_alloc(ERTS_ALC_T_TMP, n * sizeof(Eterm)); /* PUT ALL ELEMENTS IN VP */ vp = vec_p; list = A; i = n; while(i--) { Eterm* listp = list_val(list); *vp++ = CAR(listp); list = CDR(listp); } /* UNMARK ALL DELETED CELLS */ list = B; m = 0; /* number of deleted elements */ while(is_list(list)) { Eterm* listp = list_val(list); Eterm elem = CAR(listp); i = n; vp = vec_p; while(i--) { if (is_value(*vp) && eq(*vp, elem)) { *vp = THE_NON_VALUE; m++; break; } vp++; } list = CDR(listp); } if (m == n) /* All deleted ? */ res = NIL; else if (m == 0) /* None deleted ? */ res = A; else { /* REBUILD LIST */ res = NIL; need = 2*(n - m); hp = HAlloc(p, need); vp = vec_p + n - 1; while(vp >= vec_p) { if (is_value(*vp)) { res = CONS(hp, *vp, res); hp += 2; } vp--; } } if (vec_p != small_vec) erts_free(ERTS_ALC_T_TMP, (void *) vec_p); BIF_RET(res); }
static BIF_RETTYPE append(Process* p, Eterm A, Eterm B) { Eterm list; Eterm copy; Eterm last; Eterm* hp = NULL; Sint i; list = A; if (is_nil(list)) { BIF_RET(B); } if (is_not_list(list)) { BIF_ERROR(p, BADARG); } /* optimistic append on heap first */ if ((i = HeapWordsLeft(p) / 2) < 4) { goto list_tail; } hp = HEAP_TOP(p); copy = last = CONS(hp, CAR(list_val(list)), make_list(hp+2)); list = CDR(list_val(list)); hp += 2; i -= 2; /* don't use the last 2 words (extra i--;) */ while(i-- && is_list(list)) { Eterm* listp = list_val(list); last = CONS(hp, CAR(listp), make_list(hp+2)); list = CDR(listp); hp += 2; } /* A is proper and B is NIL return A as-is, don't update HTOP */ if (is_nil(list) && is_nil(B)) { BIF_RET(A); } if (is_nil(list)) { HEAP_TOP(p) = hp; CDR(list_val(last)) = B; BIF_RET(copy); } list_tail: if ((i = erts_list_length(list)) < 0) { BIF_ERROR(p, BADARG); } /* remaining list was proper and B is NIL */ if (is_nil(B)) { BIF_RET(A); } if (hp) { /* Note: fall through case, already written * on the heap. * The last 2 words of the heap is not written yet */ Eterm *hp_save = hp; ASSERT(i != 0); HEAP_TOP(p) = hp + 2; if (i == 1) { hp[0] = CAR(list_val(list)); hp[1] = B; BIF_RET(copy); } hp = HAlloc(p, 2*(i - 1)); last = CONS(hp_save, CAR(list_val(list)), make_list(hp)); } else { hp = HAlloc(p, 2*i); copy = last = CONS(hp, CAR(list_val(list)), make_list(hp+2)); hp += 2; } list = CDR(list_val(list)); i--; ASSERT(i > -1); while(i--) { Eterm* listp = list_val(list); last = CONS(hp, CAR(listp), make_list(hp+2)); list = CDR(listp); hp += 2; } CDR(list_val(last)) = B; BIF_RET(copy); }