diff options
Diffstat (limited to 'src/relooper/Relooper.cpp')
-rw-r--r-- | src/relooper/Relooper.cpp | 87 |
1 files changed, 68 insertions, 19 deletions
diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp index 389d7447..204986da 100644 --- a/src/relooper/Relooper.cpp +++ b/src/relooper/Relooper.cpp @@ -40,27 +40,56 @@ static void PutIndented(const char *String); static char *OutputBufferRoot = NULL; static char *OutputBuffer = NULL; static int OutputBufferSize = 0; +static int OutputBufferOwned = false; + +static int LeftInOutputBuffer() { + return OutputBufferSize - (OutputBuffer - OutputBufferRoot); +} + +static bool EnsureOutputBuffer(int Needed) { // ensures the output buffer is sufficient. returns true is no problem happened + Needed++; // ensure the trailing \0 is not forgotten + int Left = LeftInOutputBuffer(); + if (!OutputBufferOwned) { + assert(Needed < Left); + } else { + // we own the buffer, and can resize if necessary + if (Needed >= Left) { + int Offset = OutputBuffer - OutputBufferRoot; + int TotalNeeded = OutputBufferSize + Needed - Left + 10240; + int NewSize = OutputBufferSize; + while (NewSize < TotalNeeded) NewSize = NewSize + (NewSize/2); + //printf("resize %d => %d\n", OutputBufferSize, NewSize); + OutputBufferRoot = (char*)realloc(OutputBufferRoot, NewSize); + OutputBuffer = OutputBufferRoot + Offset; + OutputBufferSize = NewSize; + return false; + } + } + return true; +} void PrintIndented(const char *Format, ...) { assert(OutputBuffer); - assert(OutputBuffer + Indenter::CurrIndent*INDENTATION - OutputBufferRoot < OutputBufferSize); + EnsureOutputBuffer(Indenter::CurrIndent*INDENTATION); for (int i = 0; i < Indenter::CurrIndent*INDENTATION; i++, OutputBuffer++) *OutputBuffer = ' '; - va_list Args; - va_start(Args, Format); - int left = OutputBufferSize - (OutputBuffer - OutputBufferRoot); - int written = vsnprintf(OutputBuffer, left, Format, Args); - assert(written < left); - OutputBuffer += written; - va_end(Args); + int Written; + while (1) { // write and potentially resize buffer until we have enough room + int Left = LeftInOutputBuffer(); + va_list Args; + va_start(Args, Format); + Written = vsnprintf(OutputBuffer, Left, Format, Args); + va_end(Args); + if (EnsureOutputBuffer(Written)) break; + } + OutputBuffer += Written; } void PutIndented(const char *String) { assert(OutputBuffer); - assert(OutputBuffer + Indenter::CurrIndent*INDENTATION - OutputBufferRoot < OutputBufferSize); + EnsureOutputBuffer(Indenter::CurrIndent*INDENTATION); for (int i = 0; i < Indenter::CurrIndent*INDENTATION; i++, OutputBuffer++) *OutputBuffer = ' '; - int left = OutputBufferSize - (OutputBuffer - OutputBufferRoot); - int needed = strlen(String)+1; - assert(needed < left); + int Needed = strlen(String)+1; + EnsureOutputBuffer(Needed); strcpy(OutputBuffer, String); OutputBuffer += strlen(String); *OutputBuffer++ = '\n'; @@ -293,12 +322,26 @@ void MultipleShape::RenderLoopPostfix() { void MultipleShape::Render(bool InLoop) { RenderLoopPrefix(); - bool First = true; + + // We know that blocks with the same Id were split from the same source, so their contents are identical and they are logically the same, so re-merge them here + typedef std::map<int, Shape*> IdShapeMap; + IdShapeMap IdMap; for (BlockShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) { + int Id = iter->first->Id; + IdShapeMap::iterator Test = IdMap.find(Id); + if (Test != IdMap.end()) { + assert(Shape::IsSimple(iter->second) && Shape::IsSimple(Test->second)); // we can only merge simple blocks, something horrible has gone wrong if we see anything else + continue; + } + IdMap[iter->first->Id] = iter->second; + } + + bool First = true; + for (IdShapeMap::iterator iter = IdMap.begin(); iter != IdMap.end(); iter++) { if (AsmJS) { - PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first->Id); + PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first); } else { - PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first->Id); + PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first); } First = false; Indenter::Indent(); @@ -362,8 +405,8 @@ Relooper::~Relooper() { for (unsigned i = 0; i < Shapes.size(); i++) delete Shapes[i]; } -void Relooper::AddBlock(Block *New) { - New->Id = BlockIdCounter++; +void Relooper::AddBlock(Block *New, int Id) { + New->Id = Id == -1 ? BlockIdCounter++ : Id; Blocks.push_back(New); } @@ -417,8 +460,7 @@ void Relooper::Calculate(Block *Entry) { for (BlockSet::iterator iter = Original->BranchesIn.begin(); iter != Original->BranchesIn.end(); iter++) { Block *Prior = *iter; Block *Split = new Block(Original->Code, Original->BranchVar); - Parent->AddBlock(Split); - PrintDebug(" to %d\n", Split->Id); + Parent->AddBlock(Split, Original->Id); Split->BranchesIn.insert(Prior); Branch *Details = Prior->BranchesOut[Original]; Prior->BranchesOut[Split] = new Branch(Details->Condition, Details->Code); @@ -1158,11 +1200,18 @@ void Relooper::Render() { void Relooper::SetOutputBuffer(char *Buffer, int Size) { OutputBufferRoot = OutputBuffer = Buffer; OutputBufferSize = Size; + OutputBufferOwned = false; } void Relooper::MakeOutputBuffer(int Size) { + if (OutputBufferRoot && OutputBufferSize >= Size && OutputBufferOwned) return; OutputBufferRoot = OutputBuffer = (char*)malloc(Size); OutputBufferSize = Size; + OutputBufferOwned = true; +} + +char *Relooper::GetOutputBuffer() { + return OutputBufferRoot; } void Relooper::SetAsmJSMode(int On) { |