allow relooper to manager its own output buffer, to avoid fixed output limits

This commit is contained in:
Alon Zakai 2014-01-13 12:37:34 -08:00
Родитель ec3eba7709
Коммит d1f37af979
6 изменённых файлов: 139 добавлений и 16 удалений

Просмотреть файл

@ -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 = ' ';
int Written;
while (1) { // write and potentially resize buffer until we have enough room
int Left = LeftInOutputBuffer();
va_list Args;
va_start(Args, Format);
int left = OutputBufferSize - (OutputBuffer - OutputBufferRoot);
int written = vsnprintf(OutputBuffer, left, Format, Args);
assert(written < left);
OutputBuffer += written;
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';
@ -1158,11 +1187,17 @@ void Relooper::Render() {
void Relooper::SetOutputBuffer(char *Buffer, int Size) {
OutputBufferRoot = OutputBuffer = Buffer;
OutputBufferSize = Size;
OutputBufferOwned = false;
}
void Relooper::MakeOutputBuffer(int Size) {
OutputBufferRoot = OutputBuffer = (char*)malloc(Size);
OutputBufferSize = Size;
OutputBufferOwned = true;
}
char *Relooper::GetOutputBuffer() {
return OutputBufferRoot;
}
void Relooper::SetAsmJSMode(int On) {

Просмотреть файл

@ -200,11 +200,16 @@ struct Relooper {
void Render();
// Sets the global buffer all printing goes to. Must call this or MakeOutputBuffer.
// XXX: this is deprecated, see MakeOutputBuffer
static void SetOutputBuffer(char *Buffer, int Size);
// Creates an output buffer. Must call this or SetOutputBuffer.
// Creates an internal output buffer. Must call this or SetOutputBuffer. Size is
// a hint for the initial size of the buffer, it can be resized later one demand.
// For that reason this is more recommended than SetOutputBuffer.
static void MakeOutputBuffer(int Size);
static char *GetOutputBuffer();
// Sets asm.js mode on or off (default is off)
static void SetAsmJSMode(int On);

Просмотреть файл

@ -47,8 +47,18 @@ while(1) switch(label) {
int main() {
char *buffer = (char*)malloc(10*1024*1024);
'''
if random.randint(0, 1) == 0:
make = False
fast += '''
Relooper::SetOutputBuffer(buffer, 10*1024*1024);
'''
else:
make = True
fast += '''
Relooper::MakeOutputBuffer(%d);
''' % random.randint(1, 1024*1024*10)
for i in range(1, num):
slow += ' case %d: print(%d); state = check(); modded = state %% %d\n' % (i, i, len(branches[i])+1)
@ -102,11 +112,11 @@ int main() {
printf("\\n\\n");
r.Render();
puts(buffer);
puts(%s);
return 1;
}
'''
''' % ('buffer' if not make else 'Relooper::GetOutputBuffer()')
slow += '}'

Просмотреть файл

@ -286,5 +286,33 @@ int main() {
puts(buffer);
}
if (1) {
Relooper::MakeOutputBuffer(10);
printf("\n\n-- If pattern, emulated, using MakeOutputBuffer --\n\n");
Block *b_a = new Block("// block A\n", NULL);
Block *b_b = new Block("// block B\n", "b_check()");
Block *b_c = new Block("// block C\n", NULL);
b_a->AddBranchTo(b_b, "check == 10", "atob();");
b_a->AddBranchTo(b_c, NULL, "atoc();");
b_b->AddBranchTo(b_c, "case 17:", "btoc();");
b_b->AddBranchTo(b_a, NULL, NULL);
Relooper r;
r.SetEmulate(true);
r.AddBlock(b_a);
r.AddBlock(b_b);
r.AddBlock(b_c);
r.Calculate(b_a);
printf("\n\n", "the_var");
r.Render();
puts(buffer);
}
}

Просмотреть файл

@ -276,6 +276,51 @@
label = 1;
L0: while(1) {
switch(label|0) {
case 3: {
// block C
break;
}
case 1: {
// block A
if (check == 10) {
atob();
label = 2;
continue L0;
} else {
atoc();
label = 3;
continue L0;
}
break;
}
case 2: {
// block B
switch (b_check()) {
case 17: {
btoc();
label = 3;
continue L0;
break;
}
default: {
label = 1;
continue L0;
}
}
break;
}
}
}
-- If pattern, emulated, using MakeOutputBuffer --
label = 1;
L0: while(1) {
switch(label|0) {

Просмотреть файл

@ -345,7 +345,7 @@ def find_temp_directory():
# we re-check sanity when the settings are changed)
# We also re-check sanity and clear the cache when the version changes
EMSCRIPTEN_VERSION = '1.8.6'
EMSCRIPTEN_VERSION = '1.8.7'
def generate_sanity():
return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT + '|' + get_clang_version()