diff options
| author | Bob Jamison <ishmalius@gmail.com> | 2007-03-05 10:34:59 +0000 |
|---|---|---|
| committer | ishmal <ishmal@users.sourceforge.net> | 2007-03-05 10:34:59 +0000 |
| commit | 33837efd4b94c4ebb80f95b3d9dbb6efd5499a98 (patch) | |
| tree | de482d7687b3bffa97cc78608ba75a8ad7e52b60 /src/dom/js/jsopcode.c | |
| parent | Adding optional dialog preview. Implments RFE [ 1435276 ] switch preview on/o... (diff) | |
| download | inkscape-33837efd4b94c4ebb80f95b3d9dbb6efd5499a98.tar.gz inkscape-33837efd4b94c4ebb80f95b3d9dbb6efd5499a98.zip | |
update JS
(bzr r2555)
Diffstat (limited to 'src/dom/js/jsopcode.c')
| -rw-r--r-- | src/dom/js/jsopcode.c | 675 |
1 files changed, 556 insertions, 119 deletions
diff --git a/src/dom/js/jsopcode.c b/src/dom/js/jsopcode.c index e751103a0..80c7eb4dd 100644 --- a/src/dom/js/jsopcode.c +++ b/src/dom/js/jsopcode.c @@ -1,4 +1,5 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=80: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 @@ -82,6 +83,7 @@ const char js_null_str[] = "null"; const char js_this_str[] = "this"; const char js_false_str[] = "false"; const char js_true_str[] = "true"; +const char js_default_str[] = "default"; const char *js_incop_str[] = {"++", "--"}; @@ -111,7 +113,7 @@ static ptrdiff_t GetJumpOffset(jsbytecode *pc, jsbytecode *pc2) { uint32 type; - + type = (js_CodeSpec[*pc].format & JOF_TYPEMASK); if (JOF_TYPE_IS_EXTENDED_JUMP(type)) return GET_JUMPX_OFFSET(pc2); @@ -120,7 +122,7 @@ GetJumpOffset(jsbytecode *pc, jsbytecode *pc2) #ifdef DEBUG -JS_FRIEND_API(void) +JS_FRIEND_API(JSBool) js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp) { jsbytecode *pc, *end; @@ -135,9 +137,10 @@ js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp) PTRDIFF(pc, script->code, jsbytecode), lines, fp); if (!len) - return; + return JS_FALSE; pc += len; } + return JS_TRUE; } JS_FRIEND_API(uintN) @@ -150,7 +153,6 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc, uint32 type; JSAtom *atom; JSString *str; - char *cstr; op = (JSOp)*pc; if (op >= JSOP_LIMIT) { @@ -189,11 +191,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc, str = js_ValueToSource(cx, ATOM_KEY(atom)); if (!str) return 0; - cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str)); - if (!cstr) - return 0; - fprintf(fp, " %s", cstr); - JS_free(cx, cstr); + fprintf(fp, " %s", JS_GetStringBytes(str)); break; case JOF_UINT16: @@ -249,12 +247,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc, str = js_ValueToSource(cx, ATOM_KEY(atom)); if (!str) return 0; - cstr = js_DeflateString(cx, JSSTRING_CHARS(str), - JSSTRING_LENGTH(str)); - if (!cstr) - return 0; - fprintf(fp, "\n\t%s: %d", cstr, off); - JS_free(cx, cstr); + fprintf(fp, "\n\t%s: %d", JS_GetStringBytes(str), off); npairs--; } len = 1 + pc2 - pc; @@ -271,21 +264,59 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc, break; #if JS_HAS_LEXICAL_CLOSURE - case JOF_DEFLOCALVAR: + case JOF_INDEXCONST: fprintf(fp, " %u", GET_VARNO(pc)); pc += VARNO_LEN; atom = GET_ATOM(cx, script, pc); str = js_ValueToSource(cx, ATOM_KEY(atom)); if (!str) return 0; - cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str)); - if (!cstr) - return 0; - fprintf(fp, " %s", cstr); - JS_free(cx, cstr); + fprintf(fp, " %s", JS_GetStringBytes(str)); break; #endif + case JOF_UINT24: + if (op == JSOP_FINDNAME) { + /* Special case to avoid a JOF_FINDNAME just for this op. */ + atom = js_GetAtom(cx, &script->atomMap, GET_LITERAL_INDEX(pc)); + str = js_ValueToSource(cx, ATOM_KEY(atom)); + if (!str) + return 0; + fprintf(fp, " %s", JS_GetStringBytes(str)); + break; + } + + JS_ASSERT(op == JSOP_UINT24 || op == JSOP_LITERAL); + fprintf(fp, " %u", GET_LITERAL_INDEX(pc)); + break; + + case JOF_LITOPX: + atom = js_GetAtom(cx, &script->atomMap, GET_LITERAL_INDEX(pc)); + str = js_ValueToSource(cx, ATOM_KEY(atom)); + if (!str) + return 0; + + /* + * Bytecode: JSOP_LITOPX <uint24> op [<varno> if JSOP_DEFLOCALFUN]. + * Advance pc to point at op. + */ + pc += 1 + LITERAL_INDEX_LEN; + op = *pc; + cs = &js_CodeSpec[op]; + fprintf(fp, " %s op %s", JS_GetStringBytes(str), cs->name); +#if JS_HAS_LEXICAL_CLOSURE + if ((cs->format & JOF_TYPEMASK) == JOF_INDEXCONST) + fprintf(fp, " %u", GET_VARNO(pc)); +#endif + + /* + * Set len to advance pc to skip op and any other immediates (namely, + * <varno> if JSOP_DEFLOCALFUN). + */ + JS_ASSERT(cs->length > ATOM_INDEX_LEN); + len = cs->length - ATOM_INDEX_LEN; + break; + default: { char numBuf[12]; JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) cs->format); @@ -365,7 +396,7 @@ Sprint(Sprinter *sp, const char *format, ...) ptrdiff_t offset; va_start(ap, format); - bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ + bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ va_end(ap); if (!bp) { JS_ReportOutOfMemory(sp->context); @@ -432,10 +463,36 @@ QuoteString(Sprinter *sp, JSString *str, jschar quote) break; /* Use js_EscapeMap, \u, or \x only if necessary. */ - if ((u = js_strchr(js_EscapeMap, c)) != NULL) + if ((u = js_strchr(js_EscapeMap, c)) != NULL) { ok = Sprint(sp, "\\%c", (char)u[1]) >= 0; - else + } else { +#ifdef JS_C_STRINGS_ARE_UTF8 + /* If this is a surrogate pair, make sure to print the pair. */ + if (c >= 0xD800 && c <= 0xDBFF) { + jschar buffer[3]; + buffer[0] = c; + buffer[1] = *++t; + buffer[2] = 0; + if (t == z) { + char numbuf[10]; + JS_snprintf(numbuf, sizeof numbuf, "0x%x", c); + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_BAD_SURROGATE_CHAR, + numbuf); + ok = JS_FALSE; + break; + } + ok = Sprint(sp, "%hs", buffer) >= 0; + } else { + /* Print as UTF-8 string. */ + ok = Sprint(sp, "%hc", c) >= 0; + } +#else + /* Use \uXXXX or \xXX if the string can't be displayed as UTF-8. */ ok = Sprint(sp, (c >> 8) ? "\\u%04X" : "\\x%02X", c) >= 0; +#endif + } if (!ok) return NULL; } @@ -443,6 +500,13 @@ QuoteString(Sprinter *sp, JSString *str, jschar quote) /* Sprint the closing quote and return the quoted string. */ if (quote && Sprint(sp, "%c", (char)quote) < 0) return NULL; + + /* + * If we haven't Sprint'd anything yet, Sprint an empty string so that + * the OFF2STR below gives a valid result. + */ + if (off == sp->offset && Sprint(sp, "") < 0) + return NULL; return OFF2STR(sp, off); } @@ -545,7 +609,7 @@ js_printf(JSPrinter *jp, const char *format, ...) /* Suppress newlines (must be once per format, at the end) if not pretty. */ fp = NULL; - if (!jp->pretty && format[cc = strlen(format)-1] == '\n') { + if (!jp->pretty && format[cc = strlen(format) - 1] == '\n') { fp = JS_strdup(jp->sprinter.context, format); if (!fp) return -1; @@ -554,7 +618,7 @@ js_printf(JSPrinter *jp, const char *format, ...) } /* Allocate temp space, convert format, and put. */ - bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ + bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ if (fp) { JS_free(jp->sprinter.context, fp); format = NULL; @@ -590,7 +654,7 @@ typedef struct SprintStack { } SprintStack; /* Gap between stacked strings to allow for insertion of parens and commas. */ -#define PAREN_SLOP (2 + 1) +#define PAREN_SLOP (2 + 1) /* * These pseudo-ops help js_DecompileValueGenerator decompile JSOP_SETNAME, @@ -701,7 +765,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength, diff = table[0].offset - defaultOffset; if (diff > 0) { jp->indent += 2; - js_printf(jp, "\tdefault:\n"); + js_printf(jp, "\t%s:\n", js_default_str); jp->indent += 2; if (!Decompile(ss, pc + defaultOffset, diff)) return JS_FALSE; @@ -751,7 +815,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength, return JS_FALSE; } rval = QuoteString(&ss->sprinter, str, - JSVAL_IS_STRING(key) ? (jschar)'"' : 0); + (jschar)(JSVAL_IS_STRING(key) ? '"' : 0)); if (!rval) return JS_FALSE; RETRACT(&ss->sprinter, rval); @@ -768,7 +832,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength, off = defaultOffset; } jp->indent -= 2; - js_printf(jp, "\tdefault:\n"); + js_printf(jp, "\t%s:\n", js_default_str); jp->indent += 2; } if (!Decompile(ss, pc + off, off2 - off)) @@ -779,7 +843,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength, if (defaultOffset == switchLength) { jp->indent += 2; - js_printf(jp, "\tdefault:;\n"); + js_printf(jp, "\t%s:;\n", js_default_str); jp->indent -= 2; } js_printf(jp, "\t}\n"); @@ -800,9 +864,9 @@ GetSlotAtom(JSPrinter *jp, JSPropertyOp getter, uintN slot) if (sprop->getter != getter) continue; JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID); - JS_ASSERT(!JSVAL_IS_INT(sprop->id)); + JS_ASSERT(JSID_IS_ATOM(sprop->id)); if ((uintN) sprop->shortid == slot) - return (JSAtom *) sprop->id; + return JSID_TO_ATOM(sprop->id); } obj = scope->object; if (!obj) @@ -818,20 +882,13 @@ GetSlotAtom(JSPrinter *jp, JSPropertyOp getter, uintN slot) static const char * VarPrefix(jssrcnote *sn) { - const char *kw; - static char buf[8]; - - kw = NULL; if (sn) { if (SN_TYPE(sn) == SRC_VAR) - kw = js_var_str; - else if (SN_TYPE(sn) == SRC_CONST) - kw = js_const_str; + return "var "; + if (SN_TYPE(sn) == SRC_CONST) + return "const "; } - if (!kw) - return ""; - JS_snprintf(buf, sizeof buf, "%s ", kw); - return buf; + return ""; } static JSBool @@ -847,21 +904,28 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) const char *lval, *rval, *xval, *fmt; jsint i, argc; char **argv; + jsatomid atomIndex; JSAtom *atom; JSObject *obj; JSFunction *fun; JSString *str; JSBool ok; +#if JS_HAS_XML_SUPPORT + JSBool foreach, inXML, quoteAttr; +#else +#define inXML JS_FALSE +#endif jsval val; + int stackDummy; static const char catch_cookie[] = "/*CATCH*/"; static const char with_cookie[] = "/*WITH*/"; /* * Local macros */ -#define DECOMPILE_CODE(pc,nb) if (!Decompile(ss, pc, nb)) return JS_FALSE -#define POP_STR() OFF2STR(&ss->sprinter, PopOff(ss, op)) -#define LOCAL_ASSERT(expr) JS_ASSERT(expr); if (!(expr)) return JS_FALSE +#define DECOMPILE_CODE(pc,nb) if (!Decompile(ss, pc, nb)) return JS_FALSE +#define POP_STR() OFF2STR(&ss->sprinter, PopOff(ss, op)) +#define LOCAL_ASSERT(expr) JS_ASSERT(expr); if (!(expr)) return JS_FALSE /* * Callers know that ATOM_IS_STRING(atom), and we leave it to the optimizer to @@ -871,13 +935,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) (!ATOM_KEYWORD(atom) && js_IsIdentifier(ATOM_TO_STRING(atom))) /* - * Get atom from script's atom map, quote/escape its string appropriately into - * rval, and select fmt from the quoted and unquoted alternatives. + * Given an atom already fetched from jp->script's atom map, quote/escape its + * string appropriately into rval, and select fmt from the quoted and unquoted + * alternatives. */ -#define GET_ATOM_QUOTE_AND_FMT(qfmt, ufmt, rval) \ +#define GET_QUOTE_AND_FMT(qfmt, ufmt, rval) \ JS_BEGIN_MACRO \ jschar quote_; \ - atom = GET_ATOM(cx, jp->script, pc); \ if (!ATOM_IS_IDENTIFIER(atom)) { \ quote_ = '\''; \ fmt = qfmt; \ @@ -890,15 +954,33 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) return JS_FALSE; \ JS_END_MACRO +/* + * Get atom from jp->script's atom map, quote/escape its string appropriately + * into rval, and select fmt from the quoted and unquoted alternatives. + */ +#define GET_ATOM_QUOTE_AND_FMT(qfmt, ufmt, rval) \ + JS_BEGIN_MACRO \ + atom = GET_ATOM(cx, jp->script, pc); \ + GET_QUOTE_AND_FMT(qfmt, ufmt, rval); \ + JS_END_MACRO + cx = ss->sprinter.context; + if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); + return JS_FALSE; + } + jp = ss->printer; endpc = pc + nb; forelem_tail = forelem_done = NULL; tail = -1; - todo = -2; /* NB: different from Sprint() error return. */ + todo = -2; /* NB: different from Sprint() error return. */ op = JSOP_NOP; sn = NULL; rval = NULL; +#if JS_HAS_XML_SUPPORT + foreach = inXML = quoteAttr = JS_FALSE; +#endif while (pc < endpc) { lastop = op; @@ -926,9 +1008,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) { /* Print only the right operand of the assignment-op. */ todo = SprintPut(&ss->sprinter, rval, strlen(rval)); - } else { + } else if (!inXML) { todo = Sprint(&ss->sprinter, "%s %s %s", lval, cs->token, rval); + } else { + /* In XML, just concatenate the two operands. */ + JS_ASSERT(op == JSOP_ADD); + todo = Sprint(&ss->sprinter, "%s%s", lval, rval); } break; @@ -938,12 +1024,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) break; case 0: -#if JS_HAS_GETTER_SETTER - if (op == JSOP_GETTER || op == JSOP_SETTER) { - todo = -2; - break; - } -#endif todo = SprintPut(&ss->sprinter, cs->token, strlen(cs->token)); break; @@ -953,6 +1033,15 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) } } else { switch (op) { +#define BEGIN_LITOPX_CASE(OP) \ + case OP: \ + atomIndex = GET_ATOM_INDEX(pc); \ + do_##OP: \ + atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); + +#define END_LITOPX_CASE \ + break; + case JSOP_NOP: /* * Check for a do-while loop, a for-loop with an empty @@ -1054,14 +1143,22 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) pc += js_CodeSpec[JSOP_NEWINIT].length; LOCAL_ASSERT(*pc == JSOP_EXCEPTION); pc += js_CodeSpec[JSOP_EXCEPTION].length; - LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR); - atom = GET_ATOM(cx, jp->script, pc); + if (*pc == JSOP_LITOPX) { + atomIndex = GET_LITERAL_INDEX(pc); + pc += 1 + LITERAL_INDEX_LEN; + LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR); + ++pc; + } else { + LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR); + atomIndex = GET_ATOM_INDEX(pc); + pc += js_CodeSpec[JSOP_INITCATCHVAR].length; + } + atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!rval) return JS_FALSE; RETRACT(&ss->sprinter, rval); js_printf(jp, "%s", rval); - pc += js_CodeSpec[JSOP_INITCATCHVAR].length; LOCAL_ASSERT(*pc == JSOP_ENTERWITH); pc += js_CodeSpec[JSOP_ENTERWITH].length; @@ -1093,12 +1190,20 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) if (!jp2) return JS_FALSE; jp2->scope = jp->scope; - if (js_DecompileFunction(jp2, fun)) { + js_puts(jp2, "\n"); + ok = js_DecompileFunction(jp2, fun); + if (ok) { + js_puts(jp2, "\n"); str = js_GetPrinterOutput(jp2); if (str) js_printf(jp, "%s\n", JS_GetStringBytes(str)); + else + ok = JS_FALSE; } js_DestroyPrinter(jp2); + if (!ok) + return JS_FALSE; + break; default:; @@ -1122,6 +1227,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_PUSH: case JSOP_PUSHOBJ: case JSOP_BINDNAME: + do_JSOP_BINDNAME: todo = Sprint(&ss->sprinter, ""); break; @@ -1133,7 +1239,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) break; { - static const char finally_cookie[] = "/*FINALLY*/"; + static const char exception_cookie[] = "/*EXCEPTION*/"; + static const char retsub_pc_cookie[] = "/*RETSUB_PC*/"; case JSOP_FINALLY: jp->indent -= 4; @@ -1145,12 +1252,17 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) * address, popped by JSOP_RETSUB and counted by script->depth * but not by ss->top (see JSOP_SETSP, below). */ - todo = Sprint(&ss->sprinter, finally_cookie); + todo = Sprint(&ss->sprinter, exception_cookie); + if (todo < 0 || !PushOff(ss, todo, op)) + return JS_FALSE; + todo = Sprint(&ss->sprinter, retsub_pc_cookie); break; case JSOP_RETSUB: rval = POP_STR(); - LOCAL_ASSERT(strcmp(rval, finally_cookie) == 0); + LOCAL_ASSERT(strcmp(rval, retsub_pc_cookie) == 0); + lval = POP_STR(); + LOCAL_ASSERT(strcmp(lval, exception_cookie) == 0); todo = -2; break; } @@ -1285,6 +1397,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) break; #if JS_HAS_EXCEPTIONS + case JSOP_THROWING: + todo = -2; + break; + case JSOP_THROW: sn = js_GetSrcNote(jp->script, pc); todo = -2; @@ -1489,15 +1605,26 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) tail = js_GetSrcNoteOffset(sn2, 0); do_forinbody: - js_printf(jp, "\tfor (%s%s", VarPrefix(sn), lval); +#if JS_HAS_XML_SUPPORT + if (foreach) { + foreach = JS_FALSE; + js_printf(jp, "\tfor %s (%s%s", + js_each_str, VarPrefix(sn), lval); + } else +#endif + js_printf(jp, "\tfor (%s%s", VarPrefix(sn), lval); if (atom) { xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!xval) return JS_FALSE; RETRACT(&ss->sprinter, xval); js_printf(jp, *lval ? ".%s" : "%s", xval); - } else if (xval) { - js_printf(jp, "[%s]", xval); + } else if (xval && *xval) { + js_printf(jp, + (js_CodeSpec[lastop].format & JOF_XMLNAME) + ? ".%s" + : "[%s]", + xval); } rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-1]); js_printf(jp, " in %s) {\n", rval); @@ -1559,6 +1686,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) forelem_done = NULL; goto do_forinbody; +#if JS_HAS_GETTER_SETTER + case JSOP_GETTER: + case JSOP_SETTER: + todo = -2; + break; +#endif + case JSOP_DUP2: rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-2]); todo = SprintPut(&ss->sprinter, rval, strlen(rval)); @@ -1585,7 +1719,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_SETCONST: case JSOP_SETNAME: case JSOP_SETGVAR: - atom = GET_ATOM(cx, jp->script, pc); + atomIndex = GET_ATOM_INDEX(pc); + + do_JSOP_SETCONST: + atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); + do_setname: lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!lval) @@ -1593,6 +1731,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) rval = POP_STR(); if (op == JSOP_SETNAME) (void) PopOff(ss, op); + do_setlval: sn = js_GetSrcNote(jp->script, pc - 1); if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) { @@ -1694,10 +1833,22 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_DELELEM: xval = POP_STR(); lval = POP_STR(); - todo = Sprint(&ss->sprinter, "%s %s[%s]", + todo = Sprint(&ss->sprinter, + (js_CodeSpec[lastop].format & JOF_XMLNAME) + ? "%s %s.%s" + : "%s %s[%s]", js_delete_str, lval, xval); break; +#if JS_HAS_XML_SUPPORT + case JSOP_DELDESC: + xval = POP_STR(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s %s..%s", + js_delete_str, lval, xval); + break; +#endif + case JSOP_TYPEOF: case JSOP_VOID: rval = POP_STR(); @@ -1743,9 +1894,17 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_DECELEM: xval = POP_STR(); lval = POP_STR(); - todo = Sprint(&ss->sprinter, "%s%s[%s]", - js_incop_str[!(cs->format & JOF_INC)], - lval, xval); + if (*xval != '\0') { + todo = Sprint(&ss->sprinter, + (js_CodeSpec[lastop].format & JOF_XMLNAME) + ? "%s%s.%s" + : "%s%s[%s]", + js_incop_str[!(cs->format & JOF_INC)], + lval, xval); + } else { + todo = Sprint(&ss->sprinter, "%s%s", + js_incop_str[!(cs->format & JOF_INC)], lval); + } break; case JSOP_ARGINC: @@ -1787,9 +1946,17 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_ELEMDEC: xval = POP_STR(); lval = POP_STR(); - todo = Sprint(&ss->sprinter, "%s[%s]%s", - lval, xval, - js_incop_str[!(cs->format & JOF_INC)]); + if (*xval != '\0') { + todo = Sprint(&ss->sprinter, + (js_CodeSpec[lastop].format & JOF_XMLNAME) + ? "%s.%s%s" + : "%s[%s]%s", + lval, xval, + js_incop_str[!(cs->format & JOF_INC)]); + } else { + todo = Sprint(&ss->sprinter, "%s%s", + lval, js_incop_str[!(cs->format & JOF_INC)]); + } break; case JSOP_GETPROP2: @@ -1798,13 +1965,41 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) /* FALL THROUGH */ case JSOP_GETPROP: - GET_ATOM_QUOTE_AND_FMT("%s[%s]", "%s.%s", rval); + atom = GET_ATOM(cx, jp->script, pc); + + do_getprop: + GET_QUOTE_AND_FMT("%s[%s]", "%s.%s", rval); + + do_getprop_lval: lval = POP_STR(); todo = Sprint(&ss->sprinter, fmt, lval, rval); break; +#if JS_HAS_XML_SUPPORT + BEGIN_LITOPX_CASE(JSOP_GETMETHOD) + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_PCBASE) + goto do_getprop; + GET_QUOTE_AND_FMT("%s.function::[%s]", "%s.function::%s", rval); + goto do_getprop_lval; + + BEGIN_LITOPX_CASE(JSOP_SETMETHOD) + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_PCBASE) + goto do_setprop; + GET_QUOTE_AND_FMT("%s.function::[%s] %s= %s", + "%s.function::%s %s= %s", + xval); + goto do_setprop_rval; +#endif + case JSOP_SETPROP: - GET_ATOM_QUOTE_AND_FMT("%s[%s] %s= %s", "%s.%s %s= %s", xval); + atom = GET_ATOM(cx, jp->script, pc); + + do_setprop: + GET_QUOTE_AND_FMT("%s[%s] %s= %s", "%s.%s %s= %s", xval); + + do_setprop_rval: rval = POP_STR(); lval = POP_STR(); sn = js_GetSrcNote(jp->script, pc - 1); @@ -1825,10 +2020,15 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) xval = POP_STR(); op = JSOP_GETELEM; lval = POP_STR(); - if (*xval == '\0') + if (*xval == '\0') { todo = Sprint(&ss->sprinter, "%s", lval); - else - todo = Sprint(&ss->sprinter, "%s[%s]", lval, xval); + } else { + todo = Sprint(&ss->sprinter, + (js_CodeSpec[lastop].format & JOF_XMLNAME) + ? "%s.%s" + : "%s[%s]", + lval, xval); + } break; case JSOP_SETELEM: @@ -1840,7 +2040,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) if (*xval == '\0') goto do_setlval; sn = js_GetSrcNote(jp->script, pc - 1); - todo = Sprint(&ss->sprinter, "%s[%s] %s= %s", + todo = Sprint(&ss->sprinter, + (js_CodeSpec[lastop].format & JOF_XMLNAME) + ? "%s.%s %s= %s" + : "%s[%s] %s= %s", lval, xval, (sn && SN_TYPE(sn) == SRC_ASSIGNOP) ? js_CodeSpec[lastop].token @@ -1883,11 +2086,62 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_UINT16: i = (jsint) GET_ATOM_INDEX(pc); + goto do_sprint_int; + + case JSOP_UINT24: + i = (jsint) GET_LITERAL_INDEX(pc); + do_sprint_int: todo = Sprint(&ss->sprinter, "%u", (unsigned) i); break; - case JSOP_NUMBER: - atom = GET_ATOM(cx, jp->script, pc); + case JSOP_LITERAL: + atomIndex = GET_LITERAL_INDEX(pc); + goto do_JSOP_STRING; + + case JSOP_FINDNAME: + atomIndex = GET_LITERAL_INDEX(pc); + todo = Sprint(&ss->sprinter, ""); + if (todo < 0 || !PushOff(ss, todo, op)) + return JS_FALSE; + atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); + goto do_name; + + case JSOP_LITOPX: + atomIndex = GET_LITERAL_INDEX(pc); + op = pc[1 + LITERAL_INDEX_LEN]; + switch (op) { + case JSOP_ANONFUNOBJ: goto do_JSOP_ANONFUNOBJ; + case JSOP_BINDNAME: goto do_JSOP_BINDNAME; + case JSOP_CLOSURE: goto do_JSOP_CLOSURE; +#if JS_HAS_EXPORT_IMPORT + case JSOP_EXPORTNAME: goto do_JSOP_EXPORTNAME; +#endif +#if JS_HAS_XML_SUPPORT + case JSOP_GETMETHOD: goto do_JSOP_GETMETHOD; + case JSOP_SETMETHOD: goto do_JSOP_SETMETHOD; +#endif + case JSOP_NAMEDFUNOBJ: goto do_JSOP_NAMEDFUNOBJ; + case JSOP_NUMBER: goto do_JSOP_NUMBER; + case JSOP_OBJECT: goto do_JSOP_OBJECT; +#if JS_HAS_XML_SUPPORT + case JSOP_QNAMECONST: goto do_JSOP_QNAMECONST; + case JSOP_QNAMEPART: goto do_JSOP_QNAMEPART; +#endif + case JSOP_REGEXP: goto do_JSOP_REGEXP; + case JSOP_SETCONST: goto do_JSOP_SETCONST; + case JSOP_STRING: goto do_JSOP_STRING; +#if JS_HAS_XML_SUPPORT + case JSOP_XMLCDATA: goto do_JSOP_XMLCDATA; + case JSOP_XMLCOMMENT: goto do_JSOP_XMLCOMMENT; + case JSOP_XMLOBJECT: goto do_JSOP_XMLOBJECT; + case JSOP_XMLPI: goto do_JSOP_XMLPI; +#endif + default: JS_ASSERT(0); + } + /* NOTREACHED */ + break; + + BEGIN_LITOPX_CASE(JSOP_NUMBER) val = ATOM_KEY(atom); if (JSVAL_IS_INT(val)) { long ival = (long)JSVAL_TO_INT(val); @@ -1902,22 +2156,27 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) } todo = Sprint(&ss->sprinter, numStr); } - break; + END_LITOPX_CASE - case JSOP_STRING: - atom = GET_ATOM(cx, jp->script, pc); + BEGIN_LITOPX_CASE(JSOP_STRING) rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), - (jschar)'"'); + inXML ? 0 : (jschar)'"'); if (!rval) return JS_FALSE; todo = STR2OFF(&ss->sprinter, rval); - break; + END_LITOPX_CASE case JSOP_OBJECT: case JSOP_REGEXP: case JSOP_ANONFUNOBJ: case JSOP_NAMEDFUNOBJ: - atom = GET_ATOM(cx, jp->script, pc); + atomIndex = GET_ATOM_INDEX(pc); + + do_JSOP_OBJECT: + do_JSOP_REGEXP: + do_JSOP_ANONFUNOBJ: + do_JSOP_NAMEDFUNOBJ: + atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); if (op == JSOP_OBJECT || op == JSOP_REGEXP) { if (!js_regexp_toString(cx, ATOM_TO_OBJECT(atom), 0, NULL, &val)) { @@ -1946,7 +2205,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) jsbytecode *pc2; ptrdiff_t jmplen, off, off2; jsint j, n, low, high; - TableEntry *table; + TableEntry *table, pivot; sn = js_GetSrcNote(jp->script, pc); JS_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); @@ -1989,7 +2248,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) } pc2 += jmplen; } - js_HeapSort(table, (size_t) j, sizeof(TableEntry), + js_HeapSort(table, (size_t) j, &pivot, sizeof(TableEntry), CompareOffsets, NULL); } @@ -2149,19 +2408,20 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) lval, (op == JSOP_NEW_EQ) ? '=' : '!', #if JS_HAS_TRIPLE_EQOPS - JSVERSION_IS_ECMA(cx->version) ? "==" : + JS_VERSION_IS_ECMA(cx) ? "==" : #endif "=", rval); break; -#endif /* !JS_BUG_FALLIBLE_EQOPS */ +#endif #if JS_HAS_LEXICAL_CLOSURE - case JSOP_CLOSURE: - atom = GET_ATOM(cx, jp->script, pc); + BEGIN_LITOPX_CASE(JSOP_CLOSURE) JS_ASSERT(ATOM_IS_OBJECT(atom)); + todo = -2; goto do_function; -#endif /* JS_HAS_LEXICAL_CLOSURE */ + END_LITOPX_CASE +#endif #if JS_HAS_EXPORT_IMPORT case JSOP_EXPORTALL: @@ -2169,15 +2429,14 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) todo = -2; break; - case JSOP_EXPORTNAME: - atom = GET_ATOM(cx, jp->script, pc); + BEGIN_LITOPX_CASE(JSOP_EXPORTNAME) rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!rval) return JS_FALSE; RETRACT(&ss->sprinter, rval); js_printf(jp, "\texport %s\n", rval); todo = -2; - break; + END_LITOPX_CASE case JSOP_IMPORTALL: lval = POP_STR(); @@ -2186,6 +2445,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) break; case JSOP_IMPORTPROP: + do_importprop: GET_ATOM_QUOTE_AND_FMT("\timport %s[%s]\n", "\timport %s.%s\n", rval); lval = POP_STR(); @@ -2196,6 +2456,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_IMPORTELEM: xval = POP_STR(); op = JSOP_GETELEM; + if (js_CodeSpec[lastop].format & JOF_XMLNAME) + goto do_importprop; lval = POP_STR(); js_printf(jp, "\timport %s[%s]\n", lval, xval); todo = -2; @@ -2246,10 +2508,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) break; case JSOP_INITPROP: - case JSOP_INITCATCHVAR: atom = GET_ATOM(cx, jp->script, pc); xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), - ATOM_IS_IDENTIFIER(atom) ? 0 : '\''); + (jschar) + (ATOM_IS_IDENTIFIER(atom) ? 0 : '\'')); if (!xval) return JS_FALSE; rval = POP_STR(); @@ -2268,13 +2530,15 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) rval); #else if (lastop == JSOP_GETTER || lastop == JSOP_SETTER) { - todo = Sprint(&ss->sprinter, "%s%s%s %s%s", + rval += strlen(js_function_str) + 1; + todo = Sprint(&ss->sprinter, "%s%s%s %s%.*s", lval, (lval[1] != '\0') ? ", " : "", (lastop == JSOP_GETTER) ? js_get_str : js_set_str, xval, - rval + strlen(js_function_str) + 1); + strlen(rval) - 1, + rval); } else { todo = Sprint(&ss->sprinter, "%s%s%s:%s", lval, @@ -2319,9 +2583,166 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) break; #endif /* JS_HAS_DEBUGGER_KEYWORD */ +#if JS_HAS_XML_SUPPORT + case JSOP_STARTXML: + case JSOP_STARTXMLEXPR: + inXML = op == JSOP_STARTXML; + todo = -2; + break; + + case JSOP_DEFXMLNS: + rval = POP_STR(); + js_printf(jp, "\t%s %s %s = %s;\n", + js_default_str, js_xml_str, js_namespace_str, rval); + todo = -2; + break; + + case JSOP_ANYNAME: + todo = SprintPut(&ss->sprinter, "*", 1); + break; + + BEGIN_LITOPX_CASE(JSOP_QNAMEPART) + goto do_name; + END_LITOPX_CASE + + BEGIN_LITOPX_CASE(JSOP_QNAMECONST) + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return JS_FALSE; + RETRACT(&ss->sprinter, rval); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s::%s", lval, rval); + END_LITOPX_CASE + + case JSOP_QNAME: + rval = POP_STR(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s::[%s]", lval, rval); + break; + + case JSOP_TOATTRNAME: + rval = POP_STR(); + todo = Sprint(&ss->sprinter, "@%s", rval); + break; + + case JSOP_TOATTRVAL: + todo = -2; + break; + + case JSOP_ADDATTRNAME: + rval = POP_STR(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s %s", lval, rval); + /* This gets reset by all XML tag expressions. */ + quoteAttr = JS_TRUE; + break; + + case JSOP_ADDATTRVAL: + rval = POP_STR(); + lval = POP_STR(); + if (quoteAttr) + todo = Sprint(&ss->sprinter, "%s=\"%s\"", lval, rval); + else + todo = Sprint(&ss->sprinter, "%s=%s", lval, rval); + break; + + case JSOP_BINDXMLNAME: + /* Leave the name stacked and push a dummy string. */ + todo = Sprint(&ss->sprinter, ""); + break; + + case JSOP_SETXMLNAME: + /* Pop the r.h.s., the dummy string, and the name. */ + rval = POP_STR(); + (void) PopOff(ss, op); + lval = POP_STR(); + goto do_setlval; + + case JSOP_XMLELTEXPR: + case JSOP_XMLTAGEXPR: + todo = Sprint(&ss->sprinter, "{%s}", POP_STR()); + inXML = JS_TRUE; + /* If we're an attribute value, we shouldn't quote this. */ + quoteAttr = JS_FALSE; + break; + + case JSOP_TOXMLLIST: + todo = Sprint(&ss->sprinter, "<>%s</>", POP_STR()); + inXML = JS_FALSE; + break; + + case JSOP_FOREACH: + foreach = JS_TRUE; + todo = -2; + break; + + case JSOP_TOXML: + inXML = JS_FALSE; + /* FALL THROUGH */ + + case JSOP_XMLNAME: + case JSOP_FILTER: + /* Conversion and prefix ops do nothing in the decompiler. */ + todo = -2; + break; + + case JSOP_ENDFILTER: + rval = POP_STR(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s.(%s)", lval, rval); + break; + + case JSOP_DESCENDANTS: + rval = POP_STR(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s..%s", lval, rval); + break; + + BEGIN_LITOPX_CASE(JSOP_XMLOBJECT) + atom = GET_ATOM(cx, jp->script, pc); + todo = Sprint(&ss->sprinter, "<xml address='%p'>", + ATOM_TO_OBJECT(atom)); + END_LITOPX_CASE + + BEGIN_LITOPX_CASE(JSOP_XMLCDATA) + todo = SprintPut(&ss->sprinter, "<![CDATA[", 9); + if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) + return JS_FALSE; + SprintPut(&ss->sprinter, "]]>", 3); + END_LITOPX_CASE + + BEGIN_LITOPX_CASE(JSOP_XMLCOMMENT) + todo = SprintPut(&ss->sprinter, "<!--", 4); + if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) + return JS_FALSE; + SprintPut(&ss->sprinter, "-->", 3); + END_LITOPX_CASE + + BEGIN_LITOPX_CASE(JSOP_XMLPI) + rval = JS_strdup(cx, POP_STR()); + if (!rval) + return JS_FALSE; + todo = SprintPut(&ss->sprinter, "<?", 2); + ok = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0) && + SprintPut(&ss->sprinter, " ", 1) >= 0 && + SprintPut(&ss->sprinter, rval, strlen(rval)); + JS_free(cx, (char *)rval); + if (!ok) + return JS_FALSE; + SprintPut(&ss->sprinter, "?>", 2); + END_LITOPX_CASE + + case JSOP_GETFUNNS: + todo = SprintPut(&ss->sprinter, js_function_str, 8); + break; +#endif /* JS_HAS_XML_SUPPORT */ + default: todo = -2; break; + +#undef BEGIN_LITOPX_CASE +#undef END_LITOPX_CASE } } @@ -2339,10 +2760,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) /* * Undefine local macros. */ +#undef inXML #undef DECOMPILE_CODE #undef POP_STR #undef LOCAL_ASSERT #undef ATOM_IS_IDENTIFIER +#undef GET_QUOTE_AND_FMT #undef GET_ATOM_QUOTE_AND_FMT return JS_TRUE; @@ -2443,7 +2866,6 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun) * an expression by parenthesizing. */ if (jp->pretty) { - js_puts(jp, "\n"); js_printf(jp, "\t"); } else { if (!jp->grouped && (fun->flags & JSFUN_LAMBDA)) @@ -2460,6 +2882,8 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun) js_puts(jp, "("); if (fun->interpreted && fun->object) { + size_t paramsize; + /* * Print the parameters. * @@ -2473,20 +2897,21 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun) cx = jp->sprinter.context; nargs = fun->nargs; mark = JS_ARENA_MARK(&cx->tempPool); - JS_ARENA_ALLOCATE_CAST(params, JSAtom **, &cx->tempPool, - nargs * sizeof(JSAtom *)); + paramsize = nargs * sizeof(JSAtom *); + JS_ARENA_ALLOCATE_CAST(params, JSAtom **, &cx->tempPool, paramsize); if (!params) { JS_ReportOutOfMemory(cx); return JS_FALSE; } + memset(params, 0, paramsize); scope = OBJ_SCOPE(fun->object); for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) { if (sprop->getter != js_GetArgument) continue; JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID); - JS_ASSERT((uintN) sprop->shortid < nargs); - JS_ASSERT(!JSVAL_IS_INT(sprop->id)); - params[(uintN) sprop->shortid] = (JSAtom *) sprop->id; + JS_ASSERT((uint16) sprop->shortid < nargs); + JS_ASSERT(JSID_IS_ATOM(sprop->id)); + params[(uint16) sprop->shortid] = JSID_TO_ATOM(sprop->id); } for (i = 0; i < nargs; i++) { if (i > 0) @@ -2519,9 +2944,7 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun) jp->indent -= 4; js_printf(jp, "\t}"); - if (jp->pretty) { - js_puts(jp, "\n"); - } else { + if (!jp->pretty) { if (!jp->grouped && (fun->flags & JSFUN_LAMBDA)) js_puts(jp, ")"); } @@ -2538,14 +2961,15 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, JSScript *script; JSOp op; const JSCodeSpec *cs; - uint32 format, mode; + uint32 format, mode, type; intN depth; jssrcnote *sn; uintN len, off; JSPrinter *jp; JSString *name; - fp = cx->fp; + for (fp = cx->fp; fp && !fp->script; fp = fp->down) + continue; if (!fp) goto do_fallback; @@ -2657,8 +3081,11 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, begin = pc; } else { sn = js_GetSrcNote(script, pc); - if (!sn || SN_TYPE(sn) != SRC_PCBASE) + if (!sn || (SN_TYPE(sn) != SRC_PCBASE && SN_TYPE(sn) != SRC_PCDELTA)) { + if (cs->token) + return JS_NewStringCopyZ(cx, cs->token); goto do_fallback; + } begin = pc - js_GetSrcNoteOffset(sn, 0); } end = pc + cs->length; @@ -2670,7 +3097,17 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, return NULL; memcpy(tmp, begin, len * sizeof(jsbytecode)); if (mode == JOF_NAME) { - tmp[0] = JSOP_NAME; + /* + * JOF_NAME does not imply JOF_CONST, so we must check for the + * QARG and QVAR format types and translate those to JSOP_GETARG + * or JSOP_GETVAR appropriately, instead of JSOP_NAME. + */ + type = format & JOF_TYPEMASK; + tmp[0] = (type == JOF_QARG) + ? JSOP_GETARG + : (type == JOF_QVAR) + ? JSOP_GETVAR + : JSOP_NAME; } else { /* * We must replace the faulting pc's bytecode with a corresponding @@ -2719,8 +3156,8 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, } if (js_DecompileCode(jp, script, begin, len)) name = js_GetPrinterOutput(jp); + js_DestroyPrinter(jp); } - js_DestroyPrinter(jp); if (tmp) JS_free(cx, tmp); return name; |
