BIF_RETTYPE persistent_term_info_0(BIF_ALIST_0) { HashTable* hash_table = (HashTable *) erts_atomic_read_nob(&the_hash_table); TrapData* trap_data; Eterm res = NIL; Eterm magic_ref; Binary* mbp; magic_ref = alloc_trap_data(BIF_P); mbp = erts_magic_ref2bin(magic_ref); trap_data = ERTS_MAGIC_BIN_DATA(mbp); trap_data->table = hash_table; trap_data->idx = 0; trap_data->remaining = hash_table->num_entries; trap_data->memory = 0; res = do_info(BIF_P, trap_data); if (trap_data->remaining == 0) { BUMP_REDS(BIF_P, hash_table->num_entries); trap_data->table = NULL; /* Prevent refc decrement */ BIF_RET(res); } else { /* * Increment the ref counter to prevent an update operation (by put/2 * or erase/1) to delete this hash table. */ erts_atomic_inc_nob(&hash_table->refc); BUMP_ALL_REDS(BIF_P); BIF_TRAP2(&persistent_term_info_export, BIF_P, magic_ref, res); } }
static BIF_RETTYPE persistent_term_get_all_trap(BIF_ALIST_2) { TrapData* trap_data; Eterm res = BIF_ARG_2; Uint bump_reds; Binary* mbp; ASSERT(is_list(BIF_ARG_2)); mbp = erts_magic_ref2bin(BIF_ARG_1); trap_data = ERTS_MAGIC_BIN_DATA(mbp); bump_reds = trap_data->remaining; res = do_get_all(BIF_P, trap_data, res); ASSERT(is_list(res)); if (trap_data->remaining > 0) { BUMP_ALL_REDS(BIF_P); BIF_TRAP2(&persistent_term_get_all_export, BIF_P, BIF_ARG_1, res); } else { /* * Decrement ref count (and possibly delete the hash table * and associated literal area). */ dec_table_refc(BIF_P, trap_data->table); trap_data->table = NULL; /* Prevent refc decrement */ BUMP_REDS(BIF_P, bump_reds); BIF_RET(res); } }
BIF_RETTYPE lists_member_2(BIF_ALIST_2) { Eterm term; Eterm list; Eterm item; int non_immed_key; int max_iter = 10 * CONTEXT_REDS; if (is_nil(BIF_ARG_2)) { BIF_RET(am_false); } else if (is_not_list(BIF_ARG_2)) { BIF_ERROR(BIF_P, BADARG); } term = BIF_ARG_1; non_immed_key = is_not_immed(term); list = BIF_ARG_2; while (is_list(list)) { if (--max_iter < 0) { BUMP_ALL_REDS(BIF_P); BIF_TRAP2(bif_export[BIF_lists_member_2], BIF_P, term, list); } item = CAR(list_val(list)); if ((item == term) || (non_immed_key && eq(item, term))) { BIF_RET2(am_true, CONTEXT_REDS - max_iter/10); } list = CDR(list_val(list)); } if (is_not_nil(list)) { BIF_ERROR(BIF_P, BADARG); } BIF_RET2(am_false, CONTEXT_REDS - max_iter/10); }
static BIF_RETTYPE lists_reverse_onheap(Process *c_p, Eterm list_in, Eterm tail_in) { static const Uint CELLS_PER_RED = 60; Eterm *alloc_start, *alloc_top, *alloc_end; Uint cells_left, max_cells; Eterm list, tail; list = list_in; tail = tail_in; cells_left = max_cells = CELLS_PER_RED * (1 + ERTS_BIF_REDS_LEFT(c_p)); ASSERT(HEAP_LIMIT(c_p) >= HEAP_TOP(c_p) + 2); alloc_start = HEAP_TOP(c_p); alloc_end = HEAP_LIMIT(c_p) - 2; alloc_top = alloc_start; /* Don't process more cells than we have reductions for. */ alloc_end = MIN(alloc_top + (cells_left * 2), alloc_end); while (alloc_top < alloc_end && is_list(list)) { Eterm *pair = list_val(list); tail = CONS(alloc_top, CAR(pair), tail); list = CDR(pair); alloc_top += 2; } cells_left -= (alloc_top - alloc_start) / 2; HEAP_TOP(c_p) = alloc_top; ASSERT(cells_left >= 0 && cells_left <= max_cells); BUMP_REDS(c_p, (max_cells - cells_left) / CELLS_PER_RED); if (is_nil(list)) { BIF_RET(tail); } else if (is_list(list)) { ASSERT(is_list(tail)); if (cells_left > CELLS_PER_RED) { return lists_reverse_alloc(c_p, list, tail); } BUMP_ALL_REDS(c_p); BIF_TRAP2(bif_export[BIF_lists_reverse_2], c_p, list, tail); } BIF_ERROR(c_p, BADARG); }
static BIF_RETTYPE lists_reverse_alloc(Process *c_p, Eterm list_in, Eterm tail_in) { static const Uint CELLS_PER_RED = 40; Eterm *alloc_top, *alloc_end; Uint cells_left, max_cells; Eterm list, tail; Eterm lookahead; list = list_in; tail = tail_in; cells_left = max_cells = CELLS_PER_RED * (1 + ERTS_BIF_REDS_LEFT(c_p)); lookahead = list; while (cells_left != 0 && is_list(lookahead)) { lookahead = CDR(list_val(lookahead)); cells_left--; } BUMP_REDS(c_p, (max_cells - cells_left) / CELLS_PER_RED); if (is_not_list(lookahead) && is_not_nil(lookahead)) { BIF_ERROR(c_p, BADARG); } alloc_top = HAlloc(c_p, 2 * (max_cells - cells_left)); alloc_end = alloc_top + 2 * (max_cells - cells_left); while (alloc_top < alloc_end) { Eterm *pair = list_val(list); tail = CONS(alloc_top, CAR(pair), tail); list = CDR(pair); ASSERT(is_list(list) || is_nil(list)); alloc_top += 2; } if (is_nil(list)) { BIF_RET(tail); } ASSERT(is_list(tail) && cells_left == 0); BIF_TRAP2(bif_export[BIF_lists_reverse_2], c_p, list, tail); }
BIF_RETTYPE lists_reverse_2(BIF_ALIST_2) { Eterm list; Eterm tmp_list; Eterm result; Eterm* hp; Uint n; int max_iter; /* * Handle legal and illegal non-lists quickly. */ if (is_nil(BIF_ARG_1)) { BIF_RET(BIF_ARG_2); } else if (is_not_list(BIF_ARG_1)) { error: BIF_ERROR(BIF_P, BADARG); } /* * First use the rest of the remaning heap space. */ list = BIF_ARG_1; result = BIF_ARG_2; hp = HEAP_TOP(BIF_P); n = HeapWordsLeft(BIF_P) / 2; while (n != 0 && is_list(list)) { Eterm* pair = list_val(list); result = CONS(hp, CAR(pair), result); list = CDR(pair); hp += 2; n--; } HEAP_TOP(BIF_P) = hp; if (is_nil(list)) { BIF_RET(result); } /* * Calculate length of remaining list (up to a suitable limit). */ max_iter = CONTEXT_REDS * 40; n = 0; tmp_list = list; while (max_iter-- > 0 && is_list(tmp_list)) { tmp_list = CDR(list_val(tmp_list)); n++; } if (is_not_nil(tmp_list) && is_not_list(tmp_list)) { goto error; } /* * Now do one HAlloc() and continue reversing. */ hp = HAlloc(BIF_P, 2*n); while (n != 0 && is_list(list)) { Eterm* pair = list_val(list); result = CONS(hp, CAR(pair), result); list = CDR(pair); hp += 2; n--; } if (is_nil(list)) { BIF_RET(result); } else { BUMP_ALL_REDS(BIF_P); BIF_TRAP2(bif_export[BIF_lists_reverse_2], BIF_P, list, result); } }
/* erlang:'--'/2 */ static Eterm subtract(Export *bif_entry, BIF_ALIST_2) { Eterm lhs = BIF_ARG_1, rhs = BIF_ARG_2; if ((is_list(lhs) || is_nil(lhs)) && (is_list(rhs) || is_nil(rhs))) { /* We start with the context on the stack in the hopes that we won't * have to trap. */ ErtsSubtractContext context; int res; res = subtract_start(BIF_P, lhs, rhs, &context); if (res == 0) { Eterm state_mref; state_mref = subtract_create_trap_state(BIF_P, &context); erts_set_gc_state(BIF_P, 0); BIF_TRAP2(bif_entry, BIF_P, state_mref, NIL); } subtract_ctx_dtor(&context); if (res < 0) { BIF_ERROR(BIF_P, BADARG); } BIF_RET(context.result); } else if (is_internal_magic_ref(lhs)) { ErtsSubtractContext *context; int (*dtor)(Binary*); Binary *magic_bin; int res; magic_bin = erts_magic_ref2bin(lhs); dtor = ERTS_MAGIC_BIN_DESTRUCTOR(magic_bin); if (dtor != subtract_ctx_bin_dtor) { BIF_ERROR(BIF_P, BADARG); } ASSERT(BIF_P->flags & F_DISABLE_GC); ASSERT(rhs == NIL); context = ERTS_MAGIC_BIN_DATA(magic_bin); res = subtract_continue(BIF_P, context); if (res == 0) { BIF_TRAP2(bif_entry, BIF_P, lhs, NIL); } erts_set_gc_state(BIF_P, 1); if (res < 0) { ERTS_BIF_ERROR_TRAPPED2(BIF_P, BADARG, bif_entry, context->lhs_original, context->rhs_original); } BIF_RET(context->result); } ASSERT(!(BIF_P->flags & F_DISABLE_GC)); BIF_ERROR(BIF_P, BADARG); }