aboutsummaryrefslogtreecommitdiff
path: root/src/relooper/Relooper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/relooper/Relooper.cpp')
-rw-r--r--src/relooper/Relooper.cpp87
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) {