mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 12:32:20 +02:00
Initial checkin
This commit is contained in:
parent
c74712dad9
commit
078564ac9e
3242 changed files with 1616395 additions and 0 deletions
228
IDEHelper/Linker/BlMsf.cpp
Normal file
228
IDEHelper/Linker/BlMsf.cpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
#include "BlMsf.h"
|
||||
#include "BeefySysLib/MemStream.h"
|
||||
#include "../Compiler/BfAstAllocator.h"
|
||||
|
||||
USING_NS_BF;
|
||||
|
||||
#define MSF_SIGNATURE_700 "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"
|
||||
#define CV_BLOCK_SIZE 0x1000
|
||||
#define PTR_ALIGN(ptr, origPtr, alignSize) ptr = ( (origPtr)+( ((ptr - origPtr) + (alignSize - 1)) & ~(alignSize - 1) ) )
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
BlMsfWorkThread::BlMsfWorkThread()
|
||||
{
|
||||
mMsf = NULL;
|
||||
mDone = false;
|
||||
mSortDirty = false;
|
||||
}
|
||||
|
||||
BlMsfWorkThread::~BlMsfWorkThread()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void BlMsfWorkThread::Stop()
|
||||
{
|
||||
mDone = true;
|
||||
mWorkEvent.Set();
|
||||
WorkThread::Stop();
|
||||
}
|
||||
|
||||
void BlMsfWorkThread::Run()
|
||||
{
|
||||
while (!mDone)
|
||||
{
|
||||
if (mSortedWriteBlockWorkQueue.empty())
|
||||
{
|
||||
// Only fill in new entries when our queue is empty. This is not a strong ordering guarantee.
|
||||
bool sortDirty = false;
|
||||
mCritSect.Lock();
|
||||
if (!mWriteBlockWorkQueue.empty())
|
||||
{
|
||||
sortDirty = true;
|
||||
mSortedWriteBlockWorkQueue.insert(mSortedWriteBlockWorkQueue.begin(), mWriteBlockWorkQueue.begin(), mWriteBlockWorkQueue.end());
|
||||
mWriteBlockWorkQueue.clear();
|
||||
}
|
||||
mCritSect.Unlock();
|
||||
|
||||
BlMsfBlock* block = NULL;
|
||||
if (sortDirty)
|
||||
{
|
||||
std::sort(mSortedWriteBlockWorkQueue.begin(), mSortedWriteBlockWorkQueue.end(), [](BlMsfBlock* lhs, BlMsfBlock* rhs)
|
||||
{
|
||||
return lhs->mIdx < rhs->mIdx;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
BlMsfBlock* block = NULL;
|
||||
if (!mSortedWriteBlockWorkQueue.empty())
|
||||
{
|
||||
block = mSortedWriteBlockWorkQueue.front();
|
||||
mSortedWriteBlockWorkQueue.pop_front();
|
||||
}
|
||||
|
||||
if (block == NULL)
|
||||
{
|
||||
mWorkEvent.WaitFor();
|
||||
continue;
|
||||
}
|
||||
|
||||
mMsf->WriteBlock(block);
|
||||
}
|
||||
}
|
||||
|
||||
void BlMsfWorkThread::Add(BlMsfBlock* block)
|
||||
{
|
||||
AutoCrit autoCrit(mCritSect);
|
||||
mWriteBlockWorkQueue.push_back(block);
|
||||
mWorkEvent.Set();
|
||||
mSortDirty = true;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
BlMsf::BlMsf()
|
||||
{
|
||||
mCodeView = NULL;
|
||||
mBlockSize = 0x1000;
|
||||
mFreePageBitmapIdx = 1;
|
||||
mFileSize = 0;
|
||||
mAllocatedFileSize = 0;
|
||||
|
||||
mWorkThread.mMsf = this;
|
||||
}
|
||||
|
||||
BlMsf::~BlMsf()
|
||||
{
|
||||
for (auto block : mBlocks)
|
||||
delete block->mData;
|
||||
}
|
||||
|
||||
void BlMsf::WriteBlock(BlMsfBlock* block)
|
||||
{
|
||||
if (mAllocatedFileSize > mFileSize)
|
||||
{
|
||||
mFS.SetSizeFast(mAllocatedFileSize);
|
||||
mFileSize = mAllocatedFileSize;
|
||||
}
|
||||
|
||||
int wantPos = block->mIdx * CV_BLOCK_SIZE;
|
||||
if (wantPos > mFileSize)
|
||||
{
|
||||
mFS.SetSizeFast(wantPos);
|
||||
mFileSize = wantPos;
|
||||
}
|
||||
|
||||
if (mFileSize == wantPos)
|
||||
mFileSize = wantPos + CV_BLOCK_SIZE;
|
||||
|
||||
mFS.SetPos(block->mIdx * CV_BLOCK_SIZE);
|
||||
mFS.Write(block->mData, CV_BLOCK_SIZE);
|
||||
delete block->mData;
|
||||
block->mData = NULL;
|
||||
}
|
||||
|
||||
bool BlMsf::Create(const StringImpl& fileName)
|
||||
{
|
||||
mFileName = fileName;
|
||||
//if (!mFS.Open(fileName, GENERIC_WRITE | GENERIC_READ))
|
||||
//return false;
|
||||
|
||||
if (!mFS.Open(fileName, BfpFileCreateKind_CreateAlways, (BfpFileCreateFlags)(BfpFileCreateFlag_Write | BfpFileCreateFlag_Read)))
|
||||
return false;
|
||||
|
||||
// Header
|
||||
Alloc(true, false);
|
||||
|
||||
// First FPM block
|
||||
Alloc(true, false);
|
||||
|
||||
// 'Old' FPM block
|
||||
Alloc(true, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int BlMsf::Alloc(bool clear, bool skipFPMBlock)
|
||||
{
|
||||
int blockIdx = (int)mBlocks.size();
|
||||
|
||||
BlMsfBlock* msfBlock = mBlocks.Alloc();
|
||||
msfBlock->mData = new uint8[CV_BLOCK_SIZE];
|
||||
if (clear)
|
||||
memset(msfBlock->mData, 0, CV_BLOCK_SIZE);
|
||||
msfBlock->mIdx = blockIdx;
|
||||
|
||||
if ((skipFPMBlock) && ((blockIdx % CV_BLOCK_SIZE) == mFreePageBitmapIdx))
|
||||
{
|
||||
// We need this page as a Free Page Bitmap. This will be triggered once for
|
||||
// every 16MB of PDB. It should be once every 128MB but isn't because of a
|
||||
// Microsoft bug in their initial implementation.
|
||||
return Alloc();
|
||||
}
|
||||
|
||||
mAllocatedFileSize = (int)(mBlocks.size() * CV_BLOCK_SIZE);
|
||||
return blockIdx;
|
||||
}
|
||||
|
||||
void BlMsf::FlushBlock(int blockIdx)
|
||||
{
|
||||
if (mWorkThread.mThread == NULL)
|
||||
mWorkThread.Start();
|
||||
mWorkThread.Add(mBlocks[blockIdx]);
|
||||
}
|
||||
|
||||
void BlMsf::Finish(int rootBlockNum, int streamDirLen)
|
||||
{
|
||||
mWorkThread.Stop();
|
||||
|
||||
int numBlocks = (int)mBlocks.size();
|
||||
|
||||
MemStream headerStream(mBlocks[0]->mData, CV_BLOCK_SIZE, false);
|
||||
headerStream.Write(MSF_SIGNATURE_700, 32);
|
||||
headerStream.Write((int32)CV_BLOCK_SIZE); // Page size
|
||||
headerStream.Write((int32)mFreePageBitmapIdx); // FreeBlockMapBlock - always use page 1. It's allowed to flip between 1 and 2.
|
||||
headerStream.Write((int32)numBlocks); // Total page count
|
||||
headerStream.Write((int32)streamDirLen);
|
||||
headerStream.Write((int32)0); // Unknown
|
||||
headerStream.Write((int32)rootBlockNum);
|
||||
|
||||
// Create Free Page Bitmap
|
||||
BfBitSet bitset;
|
||||
bitset.Init(numBlocks);
|
||||
int numBytes = (numBlocks + 7) / 8;
|
||||
memset(bitset.mBits, 0xFF, numBytes);
|
||||
for (int i = 0; i < numBlocks; i++)
|
||||
bitset.Clear(i);
|
||||
|
||||
// Bits are written in blocks at block nums (mFreePageBitmapIdx + k*CV_BLOCK_SIZE)
|
||||
// This is a little strange, but the actual mFreePageBitmapIdx block can only hold enough bits for
|
||||
// 128MB of pages, so PSBs over that size get spread at 'CV_BLOCK_SIZE' intervals. This is technically
|
||||
// wrong, as it should be 'CV_BLOCK_SIZE*8', but that's an Microsoft bug that can't be fixed now.
|
||||
uint8* data = (uint8*)bitset.mBits;
|
||||
int bytesLeft = numBytes;
|
||||
int curBlockNum = mFreePageBitmapIdx;
|
||||
while (bytesLeft > 0)
|
||||
{
|
||||
int writeBytes = std::min(bytesLeft, CV_BLOCK_SIZE);
|
||||
|
||||
uint8* dataDest = (uint8*)mBlocks[curBlockNum]->mData;
|
||||
memcpy(dataDest, data, writeBytes);
|
||||
bytesLeft -= writeBytes;
|
||||
data += writeBytes;
|
||||
|
||||
curBlockNum += CV_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
// Do actual write
|
||||
for (auto block : mBlocks)
|
||||
{
|
||||
if (block->mData != NULL)
|
||||
WriteBlock(block);
|
||||
}
|
||||
|
||||
mFS.Close();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue