/* SSA doesn't work well when there are dead paths */ static void removeDeadBlock(BLOCK *b) { if (b->pred == NULL) { BLOCKLIST *bl = b->succ; while (bl) { unlinkBlock(bl->block, b); bl = bl->next; } if (b->head != b->tail && b->head->fwd != b->tail) { QUAD *p = b->head->fwd; QUAD *q = b->tail->fwd; while (q != p) { if (p->dc.opcode != i_dbgblock && p->dc.opcode != i_dbgblockend && p->dc.opcode != i_var && p->dc.opcode != i_func) { RemoveInstruction(p); } p = p->fwd; } } } }
/* SSA doesn't work well when there are dead paths */ static void removeDeadBlock(BLOCK *b) { if (b->pred == NULL && !b->alwayslive) { BLOCKLIST *bl = b->succ; while (bl) { unlinkBlock(bl->block, b); bl = bl->next; } if (b->critical) { b->critical = FALSE; blockArray[b->blocknum] = 0; } if (b->head != b->tail && b->head->fwd != b->tail) { QUAD *p = b->head->fwd; QUAD *q = b->tail->fwd; while (q != p) { if (p->dc.opcode != i_dbgblock && p->dc.opcode != i_dbgblockend && p->dc.opcode != i_var && p->dc.opcode != i_func && p->dc.opcode != i_label) { RemoveInstruction(p); } p = p->fwd; } } } }
/* Split an existing free block into two pieces, and put the fragment (the second one along in memory) onto the relevant free list. req_bszW is the required size of the block which isn't the fragment. */ static void splitChunk ( Arena* a, UInt* b, Int b_listno, UInt req_bszW ) { Int b_bszW, frag_bszW; b_bszW = mk_plain_bszW(get_bszW_lo(b)); vg_assert(req_bszW < b_bszW); frag_bszW = b_bszW - req_bszW; vg_assert(frag_bszW >= overhead_szW(a)); /* printf( "split %d into %d and %d\n", b_bszW,req_bszW,frag_bszW ); */ vg_assert(bszW_to_pszW(a, frag_bszW) > 0); unlinkBlock(a, b, b_listno); mkInuseBlock(a, b, req_bszW); mkFreeBlock(a, &b[req_bszW], frag_bszW, pszW_to_listNo(bszW_to_pszW(a, frag_bszW))); }
void* VG_(arena_malloc) ( ArenaId aid, Int req_pszB ) { Int req_pszW, req_bszW, frag_bszW, b_bszW, lno; Superblock* new_sb; Word* b; Arena* a; void* v; VGP_PUSHCC(VgpMalloc); ensure_mm_init(); a = arenaId_to_ArenaP(aid); vg_assert(req_pszB >= 0); vg_assert(req_pszB < 0x7FFFFFF0); req_pszW = req_pszB_to_req_pszW(req_pszB); /* Keep gcc -O happy: */ b = NULL; /* Start searching at this list. */ lno = pszW_to_listNo(req_pszW); /* This loop finds a list which has a block big enough, or sets req_listno to N_LISTS if no such block exists. */ while (True) { if (lno == VG_N_MALLOC_LISTS) break; /* If this list is empty, try the next one. */ if (a->freelist[lno] == NULL) { lno++; continue; } /* Scan a->list[lno] to find a big-enough chunk. */ b = a->freelist[lno]; b_bszW = mk_plain_bszW(get_bszW_lo(b)); while (True) { if (bszW_to_pszW(a, b_bszW) >= req_pszW) break; b = get_next_p(b); b_bszW = mk_plain_bszW(get_bszW_lo(b)); if (b == a->freelist[lno]) break; } if (bszW_to_pszW(a, b_bszW) >= req_pszW) break; /* No luck? Try a larger list. */ lno++; } /* Either lno < VG_N_MALLOC_LISTS and b points to the selected block, or lno == VG_N_MALLOC_LISTS, and we have to allocate a new superblock. */ if (lno == VG_N_MALLOC_LISTS) { req_bszW = pszW_to_bszW(a, req_pszW); new_sb = newSuperblock(a, req_bszW); if (NULL == new_sb) { // Should only fail if for client, otherwise, should have aborted // already. vg_assert(VG_AR_CLIENT == aid); return NULL; } new_sb->next = a->sblocks; a->sblocks = new_sb; b = &(new_sb->payload_words[0]); lno = pszW_to_listNo(bszW_to_pszW(a, new_sb->n_payload_words)); mkFreeBlock ( a, b, new_sb->n_payload_words, lno); } /* Ok, we can allocate from b, which lives in list req_listno. */ vg_assert(b != NULL); vg_assert(lno >= 0 && lno < VG_N_MALLOC_LISTS); vg_assert(a->freelist[lno] != NULL); b_bszW = mk_plain_bszW(get_bszW_lo(b)); req_bszW = pszW_to_bszW(a, req_pszW); /* req_bszW is the size of the block we are after. b_bszW is the size of what we've actually got. */ vg_assert(b_bszW >= req_bszW); /* Could we split this block and still get a useful fragment? Where "useful" means that the payload size of the frag is at least one word. */ frag_bszW = b_bszW - req_bszW; if (frag_bszW > overhead_szW(a)) { splitChunk(a, b, lno, req_bszW); } else { /* No, mark as in use and use as-is. */ unlinkBlock(a, b, lno); /* set_bszW_lo(b, mk_inuse_bszW(b_bszW)); set_bszW_hi(b, mk_inuse_bszW(b_bszW)); */ mkInuseBlock(a, b, b_bszW); } vg_assert(req_bszW <= mk_plain_bszW(get_bszW_lo(b))); a->bytes_on_loan += sizeof(Word) * bszW_to_pszW(a, mk_plain_bszW(get_bszW_lo(b))); if (a->bytes_on_loan > a->bytes_on_loan_max) a->bytes_on_loan_max = a->bytes_on_loan; # ifdef DEBUG_MALLOC mallocSanityCheckArena(aid); # endif VGP_POPCC(VgpMalloc); v = first_to_payload(a, b); vg_assert( (((UInt)v) & 7) == 0 ); return v; }
void VG_(arena_free) ( ArenaId aid, void* ptr ) { Superblock* sb; UInt* sb_payl_firstw; UInt* sb_payl_lastw; UInt* other; UInt* ch; Int ch_bszW, ch_pszW, other_bszW, ch_listno; Arena* a; VGP_PUSHCC(VgpMalloc); ensure_mm_init(); a = arenaId_to_ArenaP(aid); if (ptr == NULL) { VGP_POPCC(VgpMalloc); return; } ch = payload_to_first(a, ptr); # ifdef DEBUG_MALLOC vg_assert(blockSane(a,ch)); # endif a->bytes_on_loan -= sizeof(Word) * bszW_to_pszW(a, mk_plain_bszW(get_bszW_lo(ch))); sb = findSb( a, ch ); sb_payl_firstw = &(sb->payload_words[0]); sb_payl_lastw = &(sb->payload_words[sb->n_payload_words-1]); /* Put this chunk back on a list somewhere. */ ch_bszW = get_bszW_lo(ch); ch_pszW = bszW_to_pszW(a, ch_bszW); ch_listno = pszW_to_listNo(ch_pszW); mkFreeBlock( a, ch, ch_bszW, ch_listno ); /* See if this block can be merged with the following one. */ other = ch + ch_bszW; /* overhead_szW(a) is the smallest possible bszW for this arena. So the nearest possible end to the block beginning at other is other+overhead_szW(a)-1. Hence the test below. */ if (other+overhead_szW(a)-1 <= sb_payl_lastw) { other_bszW = get_bszW_lo(other); if (!is_inuse_bszW(other_bszW)) { /* VG_(printf)( "merge-successor\n"); */ other_bszW = mk_plain_bszW(other_bszW); # ifdef DEBUG_MALLOC vg_assert(blockSane(a, other)); # endif unlinkBlock( a, ch, ch_listno ); unlinkBlock( a, other, pszW_to_listNo(bszW_to_pszW(a,other_bszW)) ); ch_bszW += other_bszW; ch_listno = pszW_to_listNo(bszW_to_pszW(a, ch_bszW)); mkFreeBlock( a, ch, ch_bszW, ch_listno ); } } /* See if this block can be merged with its predecessor. */ if (ch-overhead_szW(a) >= sb_payl_firstw) { other_bszW = get_bszW_hi_from_last_word( ch-1 ); if (!is_inuse_bszW(other_bszW)) { /* VG_(printf)( "merge-predecessor\n"); */ other = last_to_first( ch-1 ); other_bszW = mk_plain_bszW(other_bszW); unlinkBlock( a, ch, ch_listno ); unlinkBlock( a, other, pszW_to_listNo(bszW_to_pszW(a, other_bszW)) ); ch = other; ch_bszW += other_bszW; ch_listno = pszW_to_listNo(bszW_to_pszW(a, ch_bszW)); mkFreeBlock( a, ch, ch_bszW, ch_listno ); } } # ifdef DEBUG_MALLOC mallocSanityCheckArena(aid); # endif VGP_POPCC(VgpMalloc); }