QTextFrame *QTextDocumentPrivate::insertFrame(int start, int end, const QTextFrameFormat &format) { Q_ASSERT(start >= 0 && start < length()); Q_ASSERT(end >= 0 && end < length()); Q_ASSERT(start <= end || end == -1); if (start != end && frameAt(start) != frameAt(end)) return 0; beginEditBlock(); QTextFrame *frame = qobject_cast<QTextFrame *>(createObject(format)); Q_ASSERT(frame); // #### using the default block and char format below might be wrong int idx = formats.indexForFormat(QTextBlockFormat()); QTextCharFormat cfmt; cfmt.setObjectIndex(frame->objectIndex()); int charIdx = formats.indexForFormat(cfmt); insertBlock(QTextBeginningOfFrame, start, idx, charIdx, QTextUndoCommand::MoveCursor); insertBlock(QTextEndOfFrame, ++end, idx, charIdx, QTextUndoCommand::KeepCursor); frame->d_func()->fragment_start = find(start).n; frame->d_func()->fragment_end = find(end).n; insert_frame(frame); endEditBlock(); return frame; }
void QTextDocumentPrivate::init() { rtFrame = 0; framesDirty = false; bool undoState = undoEnabled; undoEnabled = false; initialBlockCharFormatIndex = formats.indexForFormat(QTextCharFormat()); insertBlock(0, formats.indexForFormat(QTextBlockFormat()), formats.indexForFormat(QTextCharFormat())); undoEnabled = undoState; modified = false; modifiedState = 0; }
/** * Free a memory block in an expanded heap */ void MEMFreeToExpHeap(ExpandedHeap *heap, void *block) { ScopedSpinLock lock(&heap->lock); auto base = mem::untranslate(block); if (!base) { return; } if (base < heap->bottom || base >= heap->top) { gLog->warn("FreeToExpHeap outside heap region; {:08x} not within {:08x}-{:08x}", base, heap->bottom, heap->top); return; } // Get the block header base = base - static_cast<uint32_t>(sizeof(ExpandedHeapBlock)); // Remove used blocked auto usedBlock = make_virtual_ptr<ExpandedHeapBlock>(base); auto addr = usedBlock->addr; auto size = usedBlock->size; eraseBlock(heap->usedBlockList, usedBlock); // Create free block auto freeBlock = make_virtual_ptr<ExpandedHeapBlock>(addr); freeBlock->addr = addr; freeBlock->size = size; insertBlock(heap->freeBlockList, freeBlock); // Merge with next free if contiguous auto nextFree = freeBlock->next; if (nextFree && nextFree->addr == freeBlock->addr + freeBlock->size) { freeBlock->size += nextFree->size; eraseBlock(heap->freeBlockList, nextFree); } // Merge with previous free if contiguous auto prevFree = freeBlock->prev; if (prevFree && freeBlock->addr == prevFree->addr + prevFree->size) { prevFree->size += freeBlock->size; eraseBlock(heap->freeBlockList, freeBlock); } }
void StorageSetOrJoinBase::restoreFromFile(const String & file_path) { ReadBufferFromFile backup_buf(file_path); CompressedReadBuffer compressed_backup_buf(backup_buf); NativeBlockInputStream backup_stream(compressed_backup_buf, 0); backup_stream.readPrefix(); while (Block block = backup_stream.read()) insertBlock(block); backup_stream.readSuffix(); /// TODO Add speed, compressed bytes, data volume in memory, compression ratio ... Generalize all statistics logging in project. LOG_INFO(&Logger::get("StorageSetOrJoinBase"), std::fixed << std::setprecision(2) << "Loaded from backup file " << file_path << ". " << backup_stream.getProfileInfo().rows << " rows, " << backup_stream.getProfileInfo().bytes / 1048576.0 << " MiB. " << "State has " << getSize() << " unique rows."); }
void StorageSetOrJoinBase::restoreFromFile(const String & file_path) { ReadBufferFromFile backup_buf(file_path); CompressedReadBuffer compressed_backup_buf(backup_buf); NativeBlockInputStream backup_stream(compressed_backup_buf); backup_stream.readPrefix(); while (Block block = backup_stream.read()) insertBlock(block); backup_stream.readSuffix(); /// TODO Добавить скорость, сжатые байты, объём данных в памяти, коэффициент сжатия... Обобщить всё логгирование статистики в проекте. LOG_INFO(&Logger::get("StorageSetOrJoinBase"), std::fixed << std::setprecision(2) << "Loaded from backup file " << file_path << ". " << backup_stream.getInfo().rows << " rows, " << backup_stream.getInfo().bytes / 1048576.0 << " MiB. " << "State has " << getSize() << " unique rows."); }
static void replaceBlock(virtual_ptr<ExpandedHeapBlock> &head, virtual_ptr<ExpandedHeapBlock> old, virtual_ptr<ExpandedHeapBlock> block) { if (!old) { insertBlock(head, block); } else { if (head == old) { head = block; } else { old->prev->next = block; } if (old->next) { old->next->prev = block; } block->next = old->next; block->prev = old->prev; } }
void MEMFreeToExpHeap(ExpandedHeap *heap, void *address) { ScopedSpinLock lock(&heap->lock); auto base = gMemory.untranslate(address); if (!base) { return; } // Get the block header base = base - static_cast<uint32_t>(sizeof(ExpandedHeapBlock)); // Remove used blocked auto usedBlock = make_p32<ExpandedHeapBlock>(base); auto addr = usedBlock->addr; auto size = usedBlock->size; eraseBlock(heap->usedBlockList, usedBlock); // Create free block auto freeBlock = make_p32<ExpandedHeapBlock>(addr); freeBlock->addr = addr; freeBlock->size = size; insertBlock(heap->freeBlockList, freeBlock); // Merge with next free if contiguous auto nextFree = freeBlock->next; if (nextFree && nextFree->addr == freeBlock->addr + freeBlock->size) { freeBlock->size += nextFree->size; eraseBlock(heap->freeBlockList, nextFree); } // Merge with previous free if contiguous auto prevFree = freeBlock->prev; if (prevFree && freeBlock->addr == prevFree->addr + prevFree->size) { prevFree->size += freeBlock->size; eraseBlock(heap->freeBlockList, freeBlock); } }
static void releaseMemory(virt_ptr<MEMExpHeap> heap, virt_ptr<uint8_t> memStart, virt_ptr<uint8_t> memEnd) { decaf_check(memEnd - memStart >= sizeof(MEMExpHeapBlock) + 4); // Fill the released memory with debug data if needed if (heap->header.flags & MEMHeapFlags::DebugMode) { auto fillVal = MEMGetFillValForHeap(MEMHeapFillType::Freed); std::memset(memStart.get(), fillVal, memEnd - memStart); } // Find the preceeding block to the memory we are releasing virt_ptr<MEMExpHeapBlock> prevBlock = nullptr; virt_ptr<MEMExpHeapBlock> nextBlock = heap->freeList.head; for (auto block = heap->freeList.head; block; block = block->next) { if (getBlockMemStart(block) < memStart) { prevBlock = block; nextBlock = block->next; } else if (block >= prevBlock) { break; } } virt_ptr<MEMExpHeapBlock> freeBlock = nullptr; if (prevBlock) { // If there is a previous block, we need to check if we // should just steal that block rather than making one. auto prevMemEnd = getBlockMemEnd(prevBlock); if (memStart == prevMemEnd) { // Previous block absorbs the new memory prevBlock->blockSize += static_cast<uint32_t>(memEnd - memStart); // Our free block becomes the previous one freeBlock = prevBlock; } } if (!freeBlock) { // We did not steal the previous block to free into, // we need to allocate our own here. freeBlock = virt_cast<MEMExpHeapBlock *>(memStart); freeBlock->attribs = MEMExpHeapBlockAttribs::get(0); freeBlock->blockSize = static_cast<uint32_t>((memEnd - memStart) - sizeof(MEMExpHeapBlock)); freeBlock->next = nullptr; freeBlock->prev = nullptr; freeBlock->tag = FreeTag; insertBlock(virt_addrof(heap->freeList), prevBlock, freeBlock); } if (nextBlock) { // If there is a next block, we need to possibly merge it down // into this one. auto nextBlockStart = getBlockMemStart(nextBlock); if (nextBlockStart == memEnd) { // The next block needs to be merged into the freeBlock, as they // are directly adjacent to each other in memory. auto nextBlockEnd = getBlockMemEnd(nextBlock); freeBlock->blockSize += static_cast<uint32_t>(nextBlockEnd - nextBlockStart); removeBlock(virt_addrof(heap->freeList), nextBlock); } } }
static virt_ptr<MEMExpHeapBlock> createUsedBlockFromFreeBlock(virt_ptr<MEMExpHeap> heap, virt_ptr<MEMExpHeapBlock> freeBlock, uint32_t size, uint32_t alignment, MEMExpHeapDirection dir) { auto expHeapAttribs = heap->attribs.value(); auto freeBlockAttribs = freeBlock->attribs.value(); auto freeBlockPrev = freeBlock->prev; auto freeMemStart = getBlockMemStart(freeBlock); auto freeMemEnd = getBlockMemEnd(freeBlock); // Free blocks should never have alignment... decaf_check(!freeBlockAttribs.alignment()); removeBlock(virt_addrof(heap->freeList), freeBlock); // Find where we are going to start auto alignedDataStart = virt_ptr<uint8_t> { }; if (dir == MEMExpHeapDirection::FromStart) { alignedDataStart = align_up(freeMemStart + sizeof(MEMExpHeapBlock), alignment); } else if (dir == MEMExpHeapDirection::FromEnd) { alignedDataStart = align_down(freeMemEnd - size, alignment); } else { decaf_abort("Unexpected ExpHeap direction"); } // Grab the block header pointer and validate everything is sane auto alignedBlock = virt_cast<MEMExpHeapBlock *>(alignedDataStart) - 1; decaf_check(alignedDataStart - sizeof(MEMExpHeapBlock) >= freeMemStart); decaf_check(alignedDataStart + size <= freeMemEnd); // Calculate the alignment waste auto topSpaceRemain = (alignedDataStart - freeMemStart) - sizeof(MEMExpHeapBlock); auto bottomSpaceRemain = static_cast<uint32_t>((freeMemEnd - alignedDataStart) - size); if (expHeapAttribs.reuseAlignSpace() || dir == MEMExpHeapDirection::FromEnd) { // If the user wants to reuse the alignment space, or we allocated from the bottom, // we should try to release the top space back to the heap free list. if (topSpaceRemain > sizeof(MEMExpHeapBlock) + 4) { // We have enough room to put some of the memory back to the free list freeBlock = virt_cast<MEMExpHeapBlock *>(freeMemStart); freeBlock->attribs = MEMExpHeapBlockAttribs::get(0); freeBlock->blockSize = static_cast<uint32_t>(topSpaceRemain - sizeof(MEMExpHeapBlock)); freeBlock->next = nullptr; freeBlock->prev = nullptr; freeBlock->tag = FreeTag; insertBlock(virt_addrof(heap->freeList), freeBlockPrev, freeBlock); topSpaceRemain = 0; } } if (expHeapAttribs.reuseAlignSpace() || dir == MEMExpHeapDirection::FromStart) { // If the user wants to reuse the alignment space, or we allocated from the top, // we should try to release the bottom space back to the heap free list. if (bottomSpaceRemain > sizeof(MEMExpHeapBlock) + 4) { // We have enough room to put some of the memory back to the free list freeBlock = virt_cast<MEMExpHeapBlock *>(freeMemEnd - bottomSpaceRemain); freeBlock->attribs = MEMExpHeapBlockAttribs::get(0); freeBlock->blockSize = static_cast<uint32_t>(bottomSpaceRemain - sizeof(MEMExpHeapBlock)); freeBlock->next = nullptr; freeBlock->prev = nullptr; freeBlock->tag = FreeTag; insertBlock(virt_addrof(heap->freeList), freeBlockPrev, freeBlock); bottomSpaceRemain = 0; } } // Update the structure with the new allocation alignedBlock->attribs = MEMExpHeapBlockAttribs::get(0) .alignment(static_cast<uint32_t>(topSpaceRemain)) .allocDir(dir); alignedBlock->blockSize = size + bottomSpaceRemain; alignedBlock->prev = nullptr; alignedBlock->next = nullptr; alignedBlock->tag = UsedTag; insertBlock(virt_addrof(heap->usedList), nullptr, alignedBlock); if (heap->header.flags & MEMHeapFlags::ZeroAllocated) { memset(alignedDataStart, 0, size); } else if (heap->header.flags & MEMHeapFlags::DebugMode) { auto fillVal = MEMGetFillValForHeap(MEMHeapFillType::Allocated); memset(alignedDataStart, fillVal, size); } return alignedBlock; }
/* dfs: * * Current scheme adds articulation point to first non-trivial child * block. If none exists, it will be added to its parent's block, if * non-trivial, or else given its own block. * * FIX: * This should be modified to: * - allow user to specify which block gets a node, perhaps on per-node basis. * - if an articulation point is not used in one of its non-trivial blocks, * dummy edges should be added to preserve biconnectivity * - turn on user-supplied blocks. * */ static void dfs(Agraph_t * g, Agnode_t * n, circ_state * state, int isRoot) { Agedge_t *e; Agnode_t *curtop; LOWVAL(n) = VAL(n) = state->orderCount++; stackPush(state->bcstack, n); for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { Agnode_t *neighbor = e->head; if (neighbor == n) neighbor = e->tail; if (neighbor == PARENT(n)) continue; if (VAL(neighbor)) { LOWVAL(n) = min_value(LOWVAL(n), VAL(neighbor)); continue; } if (!stackCheck(state->bcstack, n)) { stackPush(state->bcstack, n); } PARENT(neighbor) = n; curtop = top(state->bcstack); dfs(g, neighbor, state, 0); LOWVAL(n) = min_value(LOWVAL(n), LOWVAL(neighbor)); if (LOWVAL(neighbor) >= VAL(n)) { block_t *block = NULL; Agnode_t *np; if (top(state->bcstack) != curtop) do { np = stackPop(state->bcstack); if (!BCDONE(np)) { if (!block) block = makeBlock(g, state); addNode(block, np); } } while (np != n); if (block) { /* If block != NULL, it's not empty */ if (isRoot && (BLOCK(n) == block)) insertBlock(&state->bl, block); else appendBlock(&state->bl, block); } if ((LOWVAL(n) < VAL(n)) && (!stackCheck(state->bcstack, n))) { stackPush(state->bcstack, n); } } } if ((LOWVAL(n) == VAL(n)) && !BCDONE(n)) { block_t *block = makeBlock(g, state); stackPop(state->bcstack); addNode(block, n); if (isRoot) insertBlock(&state->bl, block); else appendBlock(&state->bl, block); } }
/* find_blocks: */ static void find_blocks(Agraph_t * g, circ_state * state) { Agnode_t *n; Agnode_t *root = NULL; block_t *rootBlock = NULL; blocklist_t ublks; #ifdef USER_BLOCKS graph_t *clust_subg; graph_t *mg; edge_t *me; node_t *mm; int isRoot; #endif initBlocklist(&ublks); /* check to see if there is a node which is set to be the root */ if (state->rootname) { root = agfindnode(g, state->rootname); } if (!root && state->N_root) { for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (late_bool(ORIGN(n), state->N_root, 0)) { root = n; break; } } } #ifdef USER_BLOCKS /* process clusters first */ /* by construction, all subgraphs are blocks and are non-empty */ mm = g->meta_node; mg = mm->graph; for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) { block_t *block; clust_subg = agusergraph(me->head); isRoot = 0; block = mkBlock(clust_subg); /* block = makeBlock(g, state); */ for (n = agfstnode(clust_subg); n; n = agnxtnode(clust_subg, n)) { if (!BCDONE(n)) { /* test not necessary if blocks disjoint */ SET_BCDONE(n); BLOCK(n) = block; if (n == root) isRoot = 1; } } if (isRoot) { /* Assume blocks are disjoint, so don't check if rootBlock is * already assigned. */ rootBlock = block; insertBlock(&state->bl, block); } else { appendBlock(&state->bl, block); } } ublks.first = state->bl.first; ublks.last = state->bl.last; #endif if (!root) root = agfstnode(g); dfs(g, root, state, !rootBlock); #ifdef USER_BLOCKS /* If g has user-supplied blocks, it may be disconnected. * We then fall into the following ugly loop. * We are guaranteed !VISITED(n) and PARENT(n) has been * set to a visited node. */ if (ublks.first) { while (n = findUnvisited(&ublks)) { dfs(g, n, state, 0); } } #endif }
t_cflow_Graph * createFlowGraph(t_list *instructions) { t_cflow_Graph *result; t_basic_block *bblock; t_list *current_element; t_cflow_Node *current_node; t_axe_instruction *current_instr; int startingNode; int endingNode; /* initialize the global variable `cflow_errorcode' */ cflow_errorcode = CFLOW_OK; /* preconditions */ if (instructions == NULL){ cflow_errorcode = CFLOW_INVALID_PROGRAM_INFO; return NULL; } /* alloc memory for a new control flow graph */ result = allocGraph(); if (result == NULL) return NULL; /* set the starting basic block */ bblock = NULL; /* initialize the current element */ current_element = instructions; while(current_element != NULL) { /* retrieve the current instruction */ current_instr = (t_axe_instruction *) LDATA(current_element); assert(current_instr != NULL); if (isLoadInstruction(current_instr)) { current_element = LNEXT(current_element); continue; } /* create a new node for the current basic block */ current_node = allocNode(result, current_instr); if (current_node == NULL){ finalizeGraph(result); return NULL; } /* test if the current instruction will start or end a block */ startingNode = isStartingNode(current_instr); endingNode = isEndingNode(current_instr); if (startingNode || bblock == NULL) { /* alloc a new basic block */ bblock = allocBasicBlock(); if (bblock == NULL) { finalizeGraph(result); finalizeNode(current_node); return NULL; } /* add the current instruction to the newly created * basic block */ insertNode(bblock, current_node); if (cflow_errorcode != CFLOW_OK) { finalizeGraph(result); finalizeNode(current_node); finalizeBasicBlock(bblock); return NULL; } /* add the new basic block to the control flow graph */ insertBlock(result, bblock); if (cflow_errorcode != CFLOW_OK) { finalizeGraph(result); finalizeNode(current_node); finalizeBasicBlock(bblock); return NULL; } } else { /* add the current instruction to the current * basic block */ insertNode(bblock, current_node); if (cflow_errorcode != CFLOW_OK) { finalizeGraph(result); finalizeNode(current_node); return NULL; } } if (endingNode) bblock = NULL; /* retrieve the next element */ current_element = LNEXT(current_element); } /* update the basic blocks chain */ updateFlowGraph(result); if (cflow_errorcode != CFLOW_OK) { finalizeGraph(result); return NULL; } /*return the graph */ return result; }
void ControlFlowAnalysis::BasicBlocks() { for(auto i = _blockStarts.begin(); i != _blockStarts.end(); ++i) { uint start = *i; if(!IsValidAddress(start)) continue; uint nextStart = _base + _size; auto next = std::next(i); if(next != _blockStarts.end()) nextStart = *next; for(uint addr = start, prevaddr = 0; addr < _base + _size;) { prevaddr = addr; if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER)) { if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3) { insertBlock(BasicBlock(start, addr, 0, 0)); //leaf block break; } else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) { uint dest1 = GetReferenceOperand(); uint dest2 = _cp.GetId() != X86_INS_JMP ? addr + _cp.Size() : 0; insertBlock(BasicBlock(start, addr, dest1, dest2)); insertParent(dest1, start); insertParent(dest2, start); break; } addr += _cp.Size(); } else addr++; if(addr == nextStart) //special case handling overlapping blocks { insertBlock(BasicBlock(start, prevaddr, 0, nextStart)); insertParent(nextStart, start); break; } } } _blockStarts.clear(); #ifdef _WIN64 int count = 0; EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function) { const uint funcAddr = _moduleBase + Function->BeginAddress; const uint funcEnd = _moduleBase + Function->EndAddress; // If within limits... if(funcAddr >= _base && funcAddr < _base + _size) _functionStarts.insert(funcAddr); count++; return true; }); dprintf("%u functions from the exception directory...\n", count); #endif // _WIN64 dprintf("%u basic blocks, %u function starts detected...\n", _blocks.size(), _functionStarts.size()); }
/** * Allocate aligned memory from an expanded heap * * Sets the memory block group ID to the current active group ID. * If alignment is negative the memory is allocated from the top of the heap. * If alignment is positive the memory is allocated from the bottom of the heap. */ void * MEMAllocFromExpHeapEx(ExpandedHeap *heap, uint32_t size, int alignment) { ScopedSpinLock lock(&heap->lock); virtual_ptr<ExpandedHeapBlock> freeBlock, usedBlock; auto direction = MEMExpHeapDirection::FromBottom; uint32_t base; if (alignment < 0) { alignment = -alignment; direction = MEMExpHeapDirection::FromTop; } // Add size for block header and alignment uint32_t originalSize = size; size += sizeof(ExpandedHeapBlock); size += alignment; if (heap->mode == MEMExpHeapMode::FirstFree) { if (direction == MEMExpHeapDirection::FromBottom) { // Find first block large enough from bottom of heap for (auto block = heap->freeBlockList; block; block = block->next) { if (block->size < size) { continue; } freeBlock = block; break; } } else { // direction == MEMExpHeapDirection::FromTop // Find first block large enough from top of heap for (auto block = getTail(heap->freeBlockList); block; block = block->prev) { if (block->size < size) { continue; } freeBlock = block; break; } } } else if (heap->mode == MEMExpHeapMode::NearestSize) { uint32_t nearestSize = -1; if (direction == MEMExpHeapDirection::FromBottom) { // Find block nearest in size from bottom of heap for (auto block = heap->freeBlockList; block; block = block->next) { if (block->size < size) { continue; } if (block->size - size < nearestSize) { nearestSize = block->size - size; freeBlock = block; } } } else { // direction == MEMExpHeapDirection::FromTop // Find block nearest in size from top of heap for (auto block = getTail(heap->freeBlockList); block; block = block->prev) { if (block->size < size) { continue; } if (block->size - size < nearestSize) { nearestSize = block->size - size; freeBlock = block; } } } } if (!freeBlock) { gLog->error("MEMAllocFromExpHeapEx failed, no free block found for size {:08x} ({:08x}+{:x}+{:x})", size, originalSize, sizeof(ExpandedHeapBlock), alignment); MEMiDumpExpHeap(heap); return nullptr; } if (direction == MEMExpHeapDirection::FromBottom) { // Reduce freeblock size base = freeBlock->addr; freeBlock->size -= size; if (freeBlock->size < sMinimumBlockSize) { // Absorb free block as it is too small size += freeBlock->size; eraseBlock(heap->freeBlockList, freeBlock); } else { auto freeSize = freeBlock->size; // Replace free block auto old = freeBlock; freeBlock = make_virtual_ptr<ExpandedHeapBlock>(base + size); freeBlock->addr = base + size; freeBlock->size = freeSize; replaceBlock(heap->freeBlockList, old, freeBlock); } } else { // direction == MEMExpHeapDirection::FromTop // Reduce freeblock size freeBlock->size -= size; base = freeBlock->addr + freeBlock->size; if (freeBlock->size < sMinimumBlockSize) { // Absorb free block as it is too small size += freeBlock->size; eraseBlock(heap->freeBlockList, freeBlock); } } // Create a new used block auto aligned = align_up(base + static_cast<uint32_t>(sizeof(ExpandedHeapBlock)), alignment); usedBlock = make_virtual_ptr<ExpandedHeapBlock>(aligned - static_cast<uint32_t>(sizeof(ExpandedHeapBlock))); usedBlock->addr = base; usedBlock->size = size; usedBlock->group = heap->group; usedBlock->direction = direction; insertBlock(heap->usedBlockList, usedBlock); return make_virtual_ptr<void>(aligned); }
int QTextDocumentPrivate::insertBlock(int pos, int blockFormat, int charFormat, QTextUndoCommand::Operation op) { return insertBlock(QChar::ParagraphSeparator, pos, blockFormat, charFormat, op); }