void mmFree(void* mem) { Block b = {{-1, -1, -1, -1}}; size_t offset = (size_t) (mem - megMap); //total offset in memory area for(int i = 0; i < LEVELS; i++) { b.levels[i] = (offset - subblockStart[i]) / blockSize[i]; if(b.levels[i] * blockSize[i] + subblockStart[i] == offset) break; offset -= (b.levels[i] * blockSize[i] + subblockStart[i]); } //b is the first block of group bool haveParent = false; Block parent; if(getBlockLevel(b) != 0) { haveParent = true; parent = getParentBlock(b); } while(getBlockStatus(b) != MID_END) { setBlockStatus(b, FREE); b = getNextBlock(b); } setBlockStatus(b, FREE); if(haveParent) { //check if parent can also be freed if(getMaxGroup(parent) == numSubblocks[getBlockLevel(parent)]) { setBlockStatus(parent, FREE); } } }
//preconditions: b is a valid block, b can be subdivided (level < LEVELS - 1) static Block getFirstSubblock(Block b) { Block sub = b; int level = getBlockLevel(b); sub.levels[level + 1] = 0; return sub; }
static Block getNthSubblock(Block parent, int index) { Block sub = getFirstSubblock(parent); int level = getBlockLevel(sub); sub.levels[level] = index; return sub; }
//Precondition: newParent is not LEVELS-1 (can be subdivided) static void allocForSub(Block newParent) { int parLevel = getBlockLevel(newParent); //Mark newParent in its bitmap setBlockStatus(newParent, SUBDIV); for(int i = 0; i < numSubblocks[parLevel + 1]; i++) { Block sub = getNthSubblock(newParent, i); setBlockStatus(sub, FREE); } }
//Get the memory location referenced by block //Return NULL for invalid block descriptor static void* getBlockPtr(Block b) { void* ptr = (void*) megMap; if(!validBlock(b)) return NULL; int level = getBlockLevel(b); for(int i = 0; i <= level; i++) { //For each level, add the offset for table as well as the memory for //blocks before this one ptr += subblockStart[i]; ptr += b.levels[i] * blockSize[i]; } return ptr; }
static void setBlockStatus(Block b, int code) { int level = getBlockLevel(b); byte* table; //start of table for parent blocks, or top-level block. byte mask = 0b11; if(level == 0) table = (byte*) megMap; else table = (byte*) getBlockPtr(getParentBlock(b)); int baseIndex = b.levels[level]; byte* entry = table + (baseIndex / 4); //2 bits per entry int shift = 6 - (2 * (baseIndex % 4)); //trust me it works byte newVal = *entry & ~(mask << shift); newVal |= (code << shift); *entry = newVal; }
/* return命令の生成 */ int genCodeReturn(void) { /* 直前の命令がreturnならば, 連続returnになるので * すぐに終わる * FIXME:最後が関数定義だとあかん */ if (code[current_code_size].opcode == LVM_RETURN) return current_code_size; /* コードサイズを確認してから命令生成 */ /* オペランドのブロックレベルやパラメタ数は, table.hからの情報を使う */ checkCodeSize(); code[current_code_size].opcode = LVM_RETURN; code[current_code_size].u.address.block_level = getBlockLevel(); code[current_code_size].u.address.address = getCurrentNumParams(); return current_code_size; }
static int getMaxGroup(Block b) { int bestNum = 0; int num = 0; for(int i = 0; i < numSubblocks[getBlockLevel(b)]; i++) { if(getBlockStatus(b) == FREE) num++; else { if(num > bestNum) bestNum = num; num = 0; } } return bestNum; }
//Find best contiguous group of subblocks that can hold numBlocks //Preconditions: parent is already allocated for static bool findGroupInBlock(Block parent, int numBlocks, Block* result, int* overshoot) { //printf("Searching for group of free blocks in "); //printBlock(parent); //puts(""); if(getBlockStatus(parent) != SUBDIV) { //puts("FATAL: parent is not subdivided!"); return false; } int parentLevel = getBlockLevel(parent); if(parentLevel == LEVELS - 1) { //printf("FATAL ERROR: findGroupInBlock: parent level is level 3!"); return false; } int numSub = numSubblocks[parentLevel]; int bestStart = -1; int bestSize = numSub + 1; Block iter = getNthSubblock(parent, 0); int lvl = parentLevel + 1; while(iter.levels[lvl] < numSub) { //scan to next free block while(getBlockStatus(iter) != FREE && iter.levels[lvl] < numSub) iter.levels[lvl]++; //start counting the run int runStart = iter.levels[lvl]; //scan to end of run while(getBlockStatus(iter) == FREE && iter.levels[lvl] < numSub) iter.levels[lvl]++; //save the run as best if it fits numBlocks and is smaller than last best int runSize = iter.levels[lvl] - runStart; if(runSize < bestSize && runSize >= numBlocks) { bestStart = runStart; bestSize = runSize; } } if(bestStart == -1) return false; *result = getNthSubblock(parent, bestStart); if(overshoot) *overshoot = bestSize - numBlocks; return true; }
static void allocGroup(Block first, int num) { if(num == 1) { setBlockStatus(first, MID_END); return; } else { int* increment = &first.levels[getBlockLevel(first)]; setBlockStatus(first, BEGIN); for(int i = 0; i < num - 1; i++) { (*increment)++; setBlockStatus(first, MID_END); } } }
//Return a BlockStatus value or -1 on error static int getBlockStatus(Block b) { if(!validBlock(b)) return -1; int level = getBlockLevel(b); byte* table; //start of table for parent blocks, or top-level block. byte mask = 0b11; int shift; //set table to address of block status bitmap of parent if(level == 0) table = (byte*) megMap; else table = (byte*) getBlockPtr(getParentBlock(b)); int baseIndex = b.levels[level]; byte entry = *(table + (baseIndex / 4)); //2 bits per entry shift = 6 - (2 * (baseIndex % 4)); //trust me it works return (entry & (mask << shift)) >> shift; }
static bool groupSearch(int level, int numBlocks, Block parentBlock, Block* result) { int parLevel = getBlockLevel(parentBlock); if(parLevel == level - 1) { if(findGroupInBlock(parentBlock, numBlocks, result, NULL)) return true; } for(int i = 0; i < numSubblocks[parLevel]; i++) { Block sub = getNthSubblock(parentBlock, i); if(getBlockStatus(sub) == SUBDIV) { if(groupSearch(level, numBlocks, sub, result)) return true; } } return false; }
//Return next block on the same level static Block getNextBlock(Block b) { int level = getBlockLevel(b); b.levels[level]++; return b; }
static Block getParentBlock(Block b) { int level = getBlockLevel(b); b.levels[level] = -1; return b; }