Bug 688891: C++ power-armor for Sprinter. (r=cdleary)

This commit is contained in:
Adam 2012-01-20 15:09:56 -08:00
parent b67a4113ce
commit 383585fcc8
7 changed files with 461 additions and 274 deletions

View File

@ -57,11 +57,11 @@ void
PrintBytecode(JSContext *cx, JSScript *script, jsbytecode *pc)
{
printf("#%u:", script->id());
LifoAlloc lifoAlloc(1024);
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &lifoAlloc, 0);
Sprinter sprinter(cx);
if (!sprinter.init())
return;
js_Disassemble1(cx, script, pc, pc - script->code, true, &sprinter);
fprintf(stdout, "%s", sprinter.base);
fprintf(stdout, "%s", sprinter.string());
}
#endif

View File

@ -5600,7 +5600,7 @@ JS_NewStringCopyZ(JSContext *cx, const char *s)
AssertNoGC(cx);
CHECK_REQUEST(cx);
if (!s)
if (!s || !*s)
return cx->runtime->emptyString;
n = strlen(s);
js = InflateString(cx, s, &n);

View File

@ -1620,13 +1620,13 @@ JS_PUBLIC_API(void)
JS_DumpBytecode(JSContext *cx, JSScript *script)
{
#if defined(DEBUG)
LifoAlloc lifoAlloc(1024);
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &lifoAlloc, 0);
Sprinter sprinter(cx);
if (!sprinter.init())
return;
fprintf(stdout, "--- SCRIPT %s:%d ---\n", script->filename, script->lineno);
js_Disassemble(cx, script, true, &sprinter);
fputs(sprinter.base, stdout);
fputs(sprinter.string(), stdout);
fprintf(stdout, "--- END SCRIPT %s:%d ---\n", script->filename, script->lineno);
#endif
}
@ -1637,13 +1637,13 @@ JS_DumpPCCounts(JSContext *cx, JSScript *script)
#if defined(DEBUG)
JS_ASSERT(script->pcCounters);
LifoAlloc lifoAlloc(1024);
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &lifoAlloc, 0);
Sprinter sprinter(cx);
if (!sprinter.init())
return;
fprintf(stdout, "--- SCRIPT %s:%d ---\n", script->filename, script->lineno);
js_DumpPCCounts(cx, script, &sprinter);
fputs(sprinter.base, stdout);
fputs(sprinter.string(), stdout);
fprintf(stdout, "--- END SCRIPT %s:%d ---\n", script->filename, script->lineno);
#endif
}

File diff suppressed because it is too large Load Diff

View File

@ -440,27 +440,81 @@ DecompileValueGenerator(JSContext *cx, intN spindex, const Value &v,
/*
* Sprintf, but with unlimited and automatically allocated buffering.
*/
struct Sprinter {
JSContext *context; /* context executing the decompiler */
LifoAlloc *pool; /* string allocation pool */
char *base; /* base address of buffer in pool */
size_t size; /* size of buffer allocated at base */
ptrdiff_t offset; /* offset of next free char in buffer */
class Sprinter
{
public:
struct InvariantChecker
{
const Sprinter *parent;
explicit InvariantChecker(const Sprinter *p) : parent(p) {
parent->checkInvariants();
}
~InvariantChecker() {
parent->checkInvariants();
}
};
JSContext *context; /* context executing the decompiler */
private:
static const size_t DefaultSize;
#ifdef DEBUG
bool initialized; /* true if this is initialized, use for debug builds */
#endif
char *base; /* malloc'd buffer address */
size_t size; /* size of buffer allocated at base */
ptrdiff_t offset; /* offset of next free char in buffer */
bool realloc_(size_t newSize);
public:
explicit Sprinter(JSContext *cx);
~Sprinter();
/* Initialize this sprinter, returns false on error */
bool init();
void checkInvariants() const;
const char *string() const;
const char *stringEnd() const;
/* Returns the string at offset |off| */
char *stringAt(ptrdiff_t off) const;
/* Returns the char at offset |off| */
char &operator[](size_t off);
/* Test if this Sprinter is empty */
bool empty() const;
/*
* Attempt to reserve len + 1 space (for a trailing NULL byte). If the
* attempt succeeds, return a pointer to the start of that space and adjust the
* internal content. The caller *must* completely fill this space on success.
*/
char *reserve(size_t len);
/* Like reserve, but memory is initialized to 0 */
char *reserveAndClear(size_t len);
/*
* Puts |len| characters from |s| at the current position and return an offset to
* the beginning of this new data
*/
ptrdiff_t put(const char *s, size_t len);
ptrdiff_t putString(JSString *str);
/* Prints a formatted string into the buffer */
int printf(const char *fmt, ...);
/* Change the offset */
void setOffset(const char *end);
void setOffset(ptrdiff_t off);
/* Get the offset */
ptrdiff_t getOffset() const;
ptrdiff_t getOffsetOf(const char *string) const;
};
#define INIT_SPRINTER(cx, sp, ap, off) \
((sp)->context = cx, (sp)->pool = ap, (sp)->base = NULL, (sp)->size = 0, \
(sp)->offset = off)
/*
* Attempt to reserve len space in sp (including a trailing NULL byte). If the
* attempt succeeds, return a pointer to the start of that space and adjust the
* length of sp's contents. The caller *must* completely fill this space
* (including the space for the trailing NULL byte) on success.
*/
extern char *
SprintReserveAmount(Sprinter *sp, size_t len);
extern ptrdiff_t
SprintPut(Sprinter *sp, const char *s, size_t len);

View File

@ -1840,13 +1840,12 @@ mjit::Compiler::finishThisUp()
#define SPEW_OPCODE() \
JS_BEGIN_MACRO \
if (IsJaegerSpewChannelActive(JSpew_JSOps)) { \
LifoAllocScope las(&cx->tempLifoAlloc()); \
Sprinter sprinter; \
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0); \
Sprinter sprinter(cx); \
sprinter.init(); \
js_Disassemble1(cx, script, PC, PC - script->code, \
JS_TRUE, &sprinter); \
JaegerSpew(JSpew_JSOps, " %2d %s", \
frame.stackDepth(), sprinter.base); \
frame.stackDepth(), sprinter.string()); \
} \
JS_END_MACRO;
#else

View File

@ -1916,9 +1916,9 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp)
JSAtom *atom = script->getAtom(index);
Sprint(sp, " atom %u (", index);
size_t len = PutEscapedString(NULL, 0, atom, '\0');
if (char *buf = SprintReserveAmount(sp, len)) {
if (char *buf = sp->reserve(len)) {
PutEscapedString(buf, len, atom, 0);
buf[len] = '\0';
buf[len] = 0;
}
Sprint(sp, ")");
break;
@ -1964,9 +1964,9 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp)
static JSBool
Notes(JSContext *cx, uintN argc, jsval *vp)
{
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
Sprinter sprinter(cx);
if (!sprinter.init())
return JS_FALSE;
jsval *argv = JS_ARGV(cx, vp);
for (uintN i = 0; i < argc; i++) {
@ -1977,7 +1977,7 @@ Notes(JSContext *cx, uintN argc, jsval *vp)
SrcNotes(cx, script, &sprinter);
}
JSString *str = JS_NewStringCopyZ(cx, sprinter.base);
JSString *str = JS_NewStringCopyZ(cx, sprinter.string());
if (!str)
return JS_FALSE;
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
@ -2117,19 +2117,18 @@ DisassembleToString(JSContext *cx, uintN argc, jsval *vp)
if (!p.parse(cx))
return false;
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
Sprinter *sp = &sprinter;
Sprinter sprinter(cx);
if (!sprinter.init())
return false;
bool ok = true;
if (p.argc == 0) {
/* Without arguments, disassemble the current script. */
if (JSStackFrame *frame = JS_GetScriptedCaller(cx, NULL)) {
JSScript *script = JS_GetFrameScript(cx, frame);
if (js_Disassemble(cx, script, p.lines, sp)) {
SrcNotes(cx, script, sp);
TryNotes(cx, script, sp);
if (js_Disassemble(cx, script, p.lines, &sprinter)) {
SrcNotes(cx, script, &sprinter);
TryNotes(cx, script, &sprinter);
} else {
ok = false;
}
@ -2138,11 +2137,11 @@ DisassembleToString(JSContext *cx, uintN argc, jsval *vp)
for (uintN i = 0; i < p.argc; i++) {
JSFunction *fun;
JSScript *script = ValueToScript(cx, p.argv[i], &fun);
ok = ok && script && DisassembleScript(cx, script, fun, p.lines, p.recursive, sp);
ok = ok && script && DisassembleScript(cx, script, fun, p.lines, p.recursive, &sprinter);
}
}
JSString *str = ok ? JS_NewStringCopyZ(cx, sprinter.base) : NULL;
JSString *str = ok ? JS_NewStringCopyZ(cx, sprinter.string()) : NULL;
if (!str)
return false;
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
@ -2156,19 +2155,18 @@ Disassemble(JSContext *cx, uintN argc, jsval *vp)
if (!p.parse(cx))
return false;
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
Sprinter *sp = &sprinter;
Sprinter sprinter(cx);
if (!sprinter.init())
return false;
bool ok = true;
if (p.argc == 0) {
/* Without arguments, disassemble the current script. */
if (JSStackFrame *frame = JS_GetScriptedCaller(cx, NULL)) {
JSScript *script = JS_GetFrameScript(cx, frame);
if (js_Disassemble(cx, script, p.lines, sp)) {
SrcNotes(cx, script, sp);
TryNotes(cx, script, sp);
if (js_Disassemble(cx, script, p.lines, &sprinter)) {
SrcNotes(cx, script, &sprinter);
TryNotes(cx, script, &sprinter);
} else {
ok = false;
}
@ -2177,12 +2175,12 @@ Disassemble(JSContext *cx, uintN argc, jsval *vp)
for (uintN i = 0; i < p.argc; i++) {
JSFunction *fun;
JSScript *script = ValueToScript(cx, p.argv[i], &fun);
ok = ok && script && DisassembleScript(cx, script, fun, p.lines, p.recursive, sp);
ok = ok && script && DisassembleScript(cx, script, fun, p.lines, p.recursive, &sprinter);
}
}
if (ok)
fprintf(stdout, "%s\n", sprinter.base);
fprintf(stdout, "%s\n", sprinter.string());
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return ok;
}
@ -2218,12 +2216,12 @@ DisassFile(JSContext *cx, uintN argc, jsval *vp)
if (!script)
return false;
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempLifoAlloc(), 0);
Sprinter sprinter(cx);
if (!sprinter.init())
return false;
bool ok = DisassembleScript(cx, script, NULL, p.lines, p.recursive, &sprinter);
if (ok)
fprintf(stdout, "%s\n", sprinter.base);
fprintf(stdout, "%s\n", sprinter.string());
if (!ok)
return false;
@ -2267,10 +2265,11 @@ DisassWithSrc(JSContext *cx, uintN argc, jsval *vp)
pc = script->code;
end = pc + script->length;
LifoAllocScope las(&cx->tempLifoAlloc());
Sprinter sprinter;
Sprinter *sp = &sprinter;
INIT_SPRINTER(cx, sp, &cx->tempLifoAlloc(), 0);
Sprinter sprinter(cx);
if (!sprinter.init()) {
ok = JS_FALSE;
goto bail;
}
/* burn the leading lines */
line2 = JS_PCToLineNumber(cx, script, pc);
@ -2290,11 +2289,11 @@ DisassWithSrc(JSContext *cx, uintN argc, jsval *vp)
if (line2 < line1) {
if (bupline != line2) {
bupline = line2;
Sprint(sp, "%s %3u: BACKUP\n", sep, line2);
Sprint(&sprinter, "%s %3u: BACKUP\n", sep, line2);
}
} else {
if (bupline && line1 == line2)
Sprint(sp, "%s %3u: RESTORE\n", sep, line2);
Sprint(&sprinter, "%s %3u: RESTORE\n", sep, line2);
bupline = 0;
while (line1 < line2) {
if (!fgets(linebuf, LINE_BUF_LEN, file)) {
@ -2305,11 +2304,11 @@ DisassWithSrc(JSContext *cx, uintN argc, jsval *vp)
goto bail;
}
line1++;
Sprint(sp, "%s %3u: %s", sep, line1, linebuf);
Sprint(&sprinter, "%s %3u: %s", sep, line1, linebuf);
}
}
len = js_Disassemble1(cx, script, pc, pc - script->code, JS_TRUE, sp);
len = js_Disassemble1(cx, script, pc, pc - script->code, JS_TRUE, &sprinter);
if (!len) {
ok = JS_FALSE;
goto bail;