diff --git a/mozilla/js/src/jsemit.c b/mozilla/js/src/jsemit.c index efe0477bee5..ee570318818 100644 --- a/mozilla/js/src/jsemit.c +++ b/mozilla/js/src/jsemit.c @@ -164,6 +164,7 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) if (nuses < 0) { switch (op) { case JSOP_POPN: + case JSOP_CONCATN: nuses = GET_UINT16(pc); break; case JSOP_NEW: @@ -5569,6 +5570,35 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } break; + case TOK_PLUS: + if (pn->pn_arity == PN_LIST && pn->pn_count < JS_BIT(16)) { + /* Emit up to the first string literal conventionally. */ + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (pn2->pn_type == TOK_STRING) + break; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0) + return JS_FALSE; + } + + /* Emit remainder as a single JSOP_CONCATN. */ + for (index = 0; pn2; pn2 = pn2->pn_next, index++) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } + + if (index != 0) { + EMIT_UINT16_IMM_OP(JSOP_CONCATN, index); + + /* If we had a prefix, we need to be added to it now. */ + if (pn->pn_head->pn_type != TOK_STRING && + js_Emit1(cx, cg, JSOP_ADD) < 0) { + return JS_FALSE; + } + } + break; + } case TOK_BITOR: case TOK_BITXOR: case TOK_BITAND: @@ -5577,7 +5607,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_IN: case TOK_INSTANCEOF: case TOK_SHOP: - case TOK_PLUS: case TOK_MINUS: case TOK_STAR: case TOK_DIVOP: diff --git a/mozilla/js/src/jsinterp.c b/mozilla/js/src/jsinterp.c index d8c1e484e9b..3b26594dcb6 100644 --- a/mozilla/js/src/jsinterp.c +++ b/mozilla/js/src/jsinterp.c @@ -4453,10 +4453,10 @@ interrupt: if (JSVAL_IS_INT(rval)) { if (OBJ_IS_DENSE_ARRAY(cx, obj)) { jsuint length; - + length = ARRAY_DENSE_LENGTH(obj); i = JSVAL_TO_INT(rval); - if ((jsuint)i < length && + if ((jsuint)i < length && i < obj->fslots[JSSLOT_ARRAY_LENGTH]) { rval = obj->dslots[i]; if (rval != JSVAL_HOLE) @@ -6573,6 +6573,61 @@ interrupt: #undef FAST_LOCAL_INCREMENT_OP + BEGIN_CASE(JSOP_CONCATN) + { + jschar *buf; + + SAVE_SP_AND_PC(fp); + argc = GET_ARGC(pc); + len = 0; + for (vp = sp - argc; vp < sp; vp++) { + lval = *vp; + if (JSVAL_IS_STRING(lval)) { + len += JSSTRING_LENGTH(JSVAL_TO_STRING(lval)); + } else { + str = js_ValueToString(cx, lval); + if (!str) + goto error; + *vp = STRING_TO_JSVAL(str); + len += JSSTRING_LENGTH(str); + } + + /* + * Check early and often, since we may be concatenating up to + * (2^16 - 1) strings each of maximum length (2^29 - 1). + */ + if ((size_t)len > JSSTRING_LENGTH_MASK) { + JS_ReportOutOfMemory(cx); + goto error; + } + } + + buf = JS_malloc(cx, (len + 1) * sizeof(*buf)); + if (!buf) + goto error; + + len = 0; + for (vp = sp - argc; vp < sp; vp++) { + JS_ASSERT(JSVAL_IS_STRING(*vp)); + lval = *vp; + str = JSVAL_TO_STRING(lval); + js_strncpy(buf + len, JSSTRING_CHARS(str), + JSSTRING_LENGTH(str)); + len += JSSTRING_LENGTH(str); + } + buf[len] = 0; + + str = js_NewString(cx, buf, len); + if (!str) { + JS_free(cx, buf); + goto error; + } + + sp -= argc - 1; + STORE_OPND(-1, STRING_TO_JSVAL(str)); + } + END_CASE(JSOP_CONCATN) + BEGIN_CASE(JSOP_ENDITER) /* * Decrease the stack pointer even when !ok, see comments in the @@ -6690,8 +6745,6 @@ interrupt: L_JSOP_DEFXMLNS: # endif - L_JSOP_UNUSED117: - #else /* !JS_THREADED_INTERP */ default: #endif diff --git a/mozilla/js/src/jsopcode.c b/mozilla/js/src/jsopcode.c index 9ae7820a849..4f212b7adc9 100644 --- a/mozilla/js/src/jsopcode.c +++ b/mozilla/js/src/jsopcode.c @@ -3259,6 +3259,38 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) } break; + case JSOP_CONCATN: + argc = GET_UINT16(pc); + argv = (char **)JS_malloc(cx, (size_t)argc * sizeof *argv); + if (!argv) + return NULL; + + ok = JS_TRUE; + for (i = argc - 1; i >= 0; i--) { + argv[i] = JS_strdup(cx, POP_STR()); + if (!argv[i]) { + ok = JS_FALSE; + break; + } + } + + todo = Sprint(&ss->sprinter, "%s", argv[0]); + if (todo < 0) + ok = JS_FALSE; + for (i = 1; i < argc; i++) { + if (Sprint(&ss->sprinter, " + %s", argv[i]) < 0) { + ok = JS_FALSE; + break; + } + } + + for (i = 0; i < argc; i++) + JS_free(cx, argv[i]); + JS_free(cx, argv); + if (!ok) + return NULL; + break; + case JSOP_NEW: case JSOP_CALL: case JSOP_EVAL: @@ -3325,10 +3357,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) if (Sprint(&ss->sprinter, rval) < 0) ok = JS_FALSE; - for (i = 0; i <= argc; i++) { - if (argv[i]) - JS_free(cx, argv[i]); - } + for (i = 0; i <= argc; i++) + JS_free(cx, argv[i]); JS_free(cx, argv); if (!ok) return NULL; @@ -4973,6 +5003,11 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, continue; } + if (op == JSOP_CONCATN) { + pcdepth -= GET_UINT16(pc) - 1; + continue; + } + /* * A (C ? T : E) expression requires skipping either T (if begin is in * E) or both T and E (if begin is after the whole expression) before diff --git a/mozilla/js/src/jsopcode.tbl b/mozilla/js/src/jsopcode.tbl index 582980ea891..619beb2a0b4 100644 --- a/mozilla/js/src/jsopcode.tbl +++ b/mozilla/js/src/jsopcode.tbl @@ -263,8 +263,8 @@ OPDEF(JSOP_RETSUB, 115,"retsub", NULL, 1, 0, 0, 0, JOF_BYTE) /* More exception handling ops. */ OPDEF(JSOP_EXCEPTION, 116,"exception", NULL, 1, 0, 1, 0, JOF_BYTE) -/* Unused, formerly JSOP_GLOBALTHIS. */ -OPDEF(JSOP_UNUSED117, 117,"unused117", NULL, 1, 0, 0, 0, JOF_BYTE) +/* Concatenate multiple values, coercing to string if necessary. */ +OPDEF(JSOP_CONCATN, 117,"concatn", NULL, 3, -1, 1, 0, JOF_UINT16) /* * ECMA-compliant switch statement ops. diff --git a/mozilla/js/src/jsxdrapi.h b/mozilla/js/src/jsxdrapi.h index 7606760c06b..cbf4a4f5e8d 100644 --- a/mozilla/js/src/jsxdrapi.h +++ b/mozilla/js/src/jsxdrapi.h @@ -202,7 +202,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id); * before deserialization of bytecode. If the saved version does not match * the current version, abort deserialization and invalidate the file. */ -#define JSXDR_BYTECODE_VERSION (0xb973c0de - 21) +#define JSXDR_BYTECODE_VERSION (0xb973c0de - 22) /* * Library-private functions.