static void reserve_heap(ErtsHeapFactory* factory, Uint need, Uint xtra) { ErlHeapFragment* bp; switch (factory->mode) { case FACTORY_HALLOC: HRelease(factory->p, factory->hp_end, factory->hp); factory->hp = HAllocX(factory->p, need, xtra); factory->hp_end = factory->hp + need; return; case FACTORY_MESSAGE: if (!factory->heap_frags) { ASSERT(factory->message->data.attached == ERTS_MSG_COMBINED_HFRAG); bp = &factory->message->hfrag; } else { /* Fall through */ case FACTORY_HEAP_FRAGS: case FACTORY_TMP: bp = factory->heap_frags; } if (bp) { ASSERT(factory->hp > bp->mem); ASSERT(factory->hp <= factory->hp_end); ASSERT(factory->hp_end == bp->mem + bp->alloc_size); bp->used_size = factory->hp - bp->mem; } bp = (ErlHeapFragment*) ERTS_HEAP_ALLOC(factory->alloc_type, ERTS_HEAP_FRAG_SIZE(need+xtra)); bp->next = factory->heap_frags; factory->heap_frags = bp; bp->alloc_size = need + xtra; bp->used_size = need; bp->off_heap.first = NULL; bp->off_heap.overhead = 0; factory->hp = bp->mem; factory->hp_end = bp->mem + bp->alloc_size; return; case FACTORY_STATIC: case FACTORY_CLOSED: default: ASSERT(!"Invalid factory mode"); } }
static int subtract_set_finish(Process *p, ErtsSubtractContext *context) { const Sint CHECKS_PER_RED = 8; Sint checks, budget; budget = CHECKS_PER_RED * ERTS_BIF_REDS_LEFT(p); checks = 0; #ifdef DEBUG budget = budget / 10 + 1; #endif while (checks < budget && is_list(context->iterator)) { subtract_tree_t *node; const Eterm *cell; Eterm value, next; cell = list_val(context->iterator); value = CAR(cell); next = CDR(cell); ASSERT(context->rhs_remaining > 0); node = subtract_rbt_lookup(context->u.rhs_set.tree, value); if (node == NULL) { Eterm *hp = HAllocX(p, 2, context->lhs_remaining * 2); *context->result_cdr = make_list(hp); context->result_cdr = &CDR(hp); CAR(hp) = value; } else { if (context->rhs_remaining-- == 1) { *context->result_cdr = next; BUMP_REDS(p, checks / CHECKS_PER_RED); return 1; } if (node->count-- == 1) { subtract_rbt_delete(&context->u.rhs_set.tree, node); } } context->iterator = next; context->lhs_remaining--; checks++; } *context->result_cdr = NIL; BUMP_REDS(p, checks / CHECKS_PER_RED); if (is_list(context->iterator)) { ASSERT(context->lhs_remaining > 0 && context->rhs_remaining > 0); return 0; } return 1; }
void erts_reserve_heap__(ErtsHeapFactory* factory, Uint need, Uint xtra) { /* internal... */ ErlHeapFragment* bp; switch (factory->mode) { case FACTORY_HALLOC: HRelease(factory->p, factory->hp_end, factory->hp); factory->hp = HAllocX(factory->p, need, xtra); factory->hp_end = factory->hp + need; return; case FACTORY_MESSAGE: { int replace_oh; int replace_msg_hfrag; if (!factory->heap_frags) { ASSERT(factory->message->data.attached == ERTS_MSG_COMBINED_HFRAG); bp = &factory->message->hfrag; } else { /* Fall through */ case FACTORY_HEAP_FRAGS: case FACTORY_TMP: bp = factory->heap_frags; } replace_oh = 0; replace_msg_hfrag = 0; if (bp) { ASSERT(factory->hp >= bp->mem); ASSERT(factory->hp <= factory->hp_end); ASSERT(factory->hp_end == bp->mem + bp->alloc_size); bp->used_size = factory->hp - bp->mem; if (!bp->used_size && factory->heap_frags) { factory->heap_frags = bp->next; bp->next = NULL; ASSERT(!bp->off_heap.first); if (factory->off_heap == &bp->off_heap) replace_oh = !0; if (factory->message && factory->message->data.heap_frag == bp) replace_msg_hfrag = !0; free_message_buffer(bp); } } bp = (ErlHeapFragment*) ERTS_HEAP_ALLOC(factory->alloc_type, ERTS_HEAP_FRAG_SIZE(need+xtra)); bp->next = factory->heap_frags; factory->heap_frags = bp; bp->alloc_size = need + xtra; bp->used_size = need + xtra; bp->off_heap.first = NULL; bp->off_heap.overhead = 0; if (replace_oh) { factory->off_heap = &bp->off_heap; factory->off_heap_saved.first = factory->off_heap->first; factory->off_heap_saved.overhead = factory->off_heap->overhead; } if (replace_msg_hfrag) factory->message->data.heap_frag = bp; factory->hp = bp->mem; factory->hp_end = bp->mem + bp->alloc_size; return; } case FACTORY_STATIC: case FACTORY_CLOSED: default: ASSERT(!"Invalid factory mode"); } }
static int subtract_naive_rhs(Process *p, ErtsSubtractContext *context) { const Sint CHECKS_PER_RED = 16; Sint checks, budget; budget = CHECKS_PER_RED * ERTS_BIF_REDS_LEFT(p); checks = 0; #ifdef DEBUG budget = budget / 10 + 1; #endif while (checks < budget && is_list(context->iterator)) { const Eterm *cell; Eterm value, next; int found_at; cell = list_val(context->iterator); value = CAR(cell); next = CDR(cell); for (found_at = context->rhs_remaining - 1; found_at >= 0; found_at--) { if (EQ(value, context->u.rhs_elements[found_at])) { break; } } if (found_at < 0) { /* Destructively add the value to the result. This is safe * since the GC is disabled and the unfinished term is never * leaked to the outside world. */ Eterm *hp = HAllocX(p, 2, context->lhs_remaining * 2); *context->result_cdr = make_list(hp); context->result_cdr = &CDR(hp); CAR(hp) = value; } else if (found_at >= 0) { Eterm swap; if (context->rhs_remaining-- == 1) { /* We've run out of items to remove, so the rest of the * result will be equal to the remainder of the input. We know * that LHS is well-formed as any errors would've been reported * during length determination. */ *context->result_cdr = next; BUMP_REDS(p, MIN(budget, checks) / CHECKS_PER_RED); return 1; } swap = context->u.rhs_elements[context->rhs_remaining]; context->u.rhs_elements[found_at] = swap; } checks += context->rhs_remaining; context->iterator = next; context->lhs_remaining--; } /* The result only has to be terminated when returning it to the user, but * we're doing it when trapping as well to prevent headaches when * debugging. */ *context->result_cdr = NIL; BUMP_REDS(p, MIN(budget, checks) / CHECKS_PER_RED); if (is_list(context->iterator)) { ASSERT(context->lhs_remaining > 0 && context->rhs_remaining > 0); return 0; } return 1; }