Bug 581747 - Remove JSOP_CONCATN. Good-night, sweet prince. (r=waldo)
authorLuke Wagner <lw@mozilla.com>
Sun, 01 Aug 2010 21:54:09 -0700
changeset 48799 fd1faf906f0067bbb687189594489a1d62d0366a
parent 48798 06d0143b4f7e94c4e7f2f79e9e2ed5a9402e49ef
child 48800 ceb1f5ebe24992f8f499fb9fec7f8f772bb4d020
push id14825
push userrsayre@mozilla.com
push dateWed, 04 Aug 2010 07:47:43 +0000
treeherdermozilla-central@c761f8e85b8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswaldo
bugs581747
milestone2.0b3pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 581747 - Remove JSOP_CONCATN. Good-night, sweet prince. (r=waldo)
js/src/imacros.jsasm
js/src/jsbuiltins.cpp
js/src/jsbuiltins.h
js/src/jsemit.cpp
js/src/jsinterp.cpp
js/src/jsopcode.cpp
js/src/jsopcode.tbl
js/src/jstracer.cpp
js/src/jsxdrapi.h
--- a/js/src/imacros.jsasm
+++ b/js/src/imacros.jsasm
@@ -683,41 +683,16 @@ 3:      swap                            
         pick 9                              # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 call
         pop                                 # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6
         call 7                              #
         stop                                #
     .end                                    #
 
 .end apply
 
-.igroup objtostr JSOP_OBJTOSTR
-
-    .imacro toString                                # obj
-        dup                                         # obj obj
-        dup                                         # obj obj obj
-        getprop valueOf                             # obj obj valueOf?
-        ifprimtop 1                                 # obj obj valueOf?
-        swap                                        # obj valueOf obj
-        string void                                 # obj valueOf obj "void"
-        call 1                                      # obj val?
-        ifprimtop 3                                 # obj val?
-        pop                                         # obj
-        dup                                         # obj obj
-        goto 2
-1:      pop                                         # obj obj
-2:      callprop toString                           # obj toString obj
-        call 0                                      # obj val
-        primtop (JSTYPE_VOID)                       # obj val
-3:      swap                                        # val obj
-        pop                                         # val
-        stop
-    .end
-
-.end objtostr
-
 .igroup getprop JSOP_GETPROP
     .imacro scriptgetter        # obj
         .fixup +1               # getter obj
         call 0                  # val
         stop
     .end
 .end getprop
 
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -359,47 +359,8 @@ js_PopInterpFrame(JSContext* cx, TracerS
     /* Pop the frame and its memory. */
     cx->stack().popInlineFrame(cx, fp, fp->down);
 
     /* Update the inline call count. */
     *state->inlineCallCountp = *state->inlineCallCountp - 1;
     return JS_TRUE;
 }
 JS_DEFINE_CALLINFO_2(extern, BOOL, js_PopInterpFrame, CONTEXT, TRACERSTATE, 0, ACCSET_STORE_ANY)
-
-JSString* FASTCALL
-js_ConcatN(JSContext *cx, JSString **strArray, uint32 size)
-{
-    /* Calculate total size. */
-    size_t numChar = 1;
-    for (uint32 i = 0; i < size; ++i) {
-        size_t before = numChar;
-        numChar += strArray[i]->length();
-        if (numChar < before)
-            return NULL;
-    }
-
-
-    /* Allocate buffer. */
-    if (numChar & js::tl::MulOverflowMask<sizeof(jschar)>::result)
-        return NULL;
-    jschar *buf = (jschar *)cx->malloc(numChar * sizeof(jschar));
-    if (!buf)
-        return NULL;
-
-    /* Fill buffer. */
-    jschar *ptr = buf;
-    for (uint32 i = 0; i < size; ++i) {
-        const jschar *chars;
-        size_t length;
-        strArray[i]->getCharsAndLength(chars, length);
-        js_strncpy(ptr, chars, length);
-        ptr += length;
-    }
-    *ptr = '\0';
-
-    /* Create string. */
-    JSString *str = js_NewString(cx, buf, numChar - 1);
-    if (!str)
-        cx->free(buf);
-    return str;
-}
-JS_DEFINE_CALLINFO_3(extern, STRING, js_ConcatN, CONTEXT, STRINGPTR, UINT32, 0, ACCSET_STORE_ANY)
--- a/js/src/jsbuiltins.h
+++ b/js/src/jsbuiltins.h
@@ -592,17 +592,16 @@ JS_DECLARE_CALLINFO(js_StringToInt32)
 JS_DECLARE_CALLINFO(js_AddProperty)
 JS_DECLARE_CALLINFO(js_AddAtomProperty)
 JS_DECLARE_CALLINFO(js_HasNamedProperty)
 JS_DECLARE_CALLINFO(js_HasNamedPropertyInt32)
 JS_DECLARE_CALLINFO(js_TypeOfObject)
 JS_DECLARE_CALLINFO(js_BooleanIntToString)
 JS_DECLARE_CALLINFO(js_NewNullClosure)
 JS_DECLARE_CALLINFO(js_PopInterpFrame)
-JS_DECLARE_CALLINFO(js_ConcatN)
 
 /* Defined in jsfun.cpp. */
 JS_DECLARE_CALLINFO(js_AllocFlatClosure)
 JS_DECLARE_CALLINFO(js_PutArguments)
 JS_DECLARE_CALLINFO(js_PutCallObjectOnTrace)
 JS_DECLARE_CALLINFO(js_SetCallVar)
 JS_DECLARE_CALLINFO(js_SetCallArg)
 JS_DECLARE_CALLINFO(js_CloneFunctionObject)
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -5963,57 +5963,16 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                 CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top);
                 *pc = pn->pn_op;
                 top += tmp;
             } while ((pn2 = pn2->pn_next)->pn_next);
         }
         break;
 
       case TOK_PLUS:
-        /* For TCF_IN_FUNCTION test, see TOK_RB concerning JSOP_NEWARRAY. */
-        if (pn->pn_arity == PN_LIST && pn->pn_count < JS_BIT(16) &&
-            cg->inFunction()) {
-            /* 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;
-            }
-
-            if (!pn2)
-                break;
-
-            /*
-             * Having seen a string literal, we know statically that the rest
-             * of the additions are string concatenation, so we emit them as a
-             * single concatn. First, do string conversion on the result of the
-             * preceding zero or more additions so that any side effects of
-             * string conversion occur before the next operand begins.
-             */
-            if (pn2 == pn->pn_head) {
-                index = 0;
-            } else {
-                if (!js_Emit1(cx, cg, JSOP_OBJTOSTR))
-                    return JS_FALSE;
-                index = 1;
-            }
-
-            for (; pn2; pn2 = pn2->pn_next, index++) {
-                if (!js_EmitTree(cx, cg, pn2))
-                    return JS_FALSE;
-                if (!pn2->isLiteral() && js_Emit1(cx, cg, JSOP_OBJTOSTR) < 0)
-                    return JS_FALSE;
-            }
-
-            EMIT_UINT16_IMM_OP(JSOP_CONCATN, index);
-            break;
-        }
       case TOK_BITOR:
       case TOK_BITXOR:
       case TOK_BITAND:
       case TOK_EQOP:
       case TOK_RELOP:
       case TOK_IN:
       case TOK_INSTANCEOF:
       case TOK_SHOP:
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -3482,45 +3482,16 @@ BEGIN_CASE(JSOP_ADD)
             l += r;
             regs.sp--;
             regs.sp[-1].setNumber(l);
         }
     }
 }
 END_CASE(JSOP_ADD)
 
-BEGIN_CASE(JSOP_OBJTOSTR)
-{
-    const Value &ref = regs.sp[-1];
-    if (ref.isObject()) {
-        JSString *str = js_ValueToString(cx, ref);
-        if (!str)
-            goto error;
-        regs.sp[-1].setString(str);
-    }
-}
-END_CASE(JSOP_OBJTOSTR)
-
-BEGIN_CASE(JSOP_CONCATN)
-{
-    JSCharBuffer buf(cx);
-    uintN argc = GET_ARGC(regs.pc);
-    for (Value *vp = regs.sp - argc; vp < regs.sp; vp++) {
-        JS_ASSERT(vp->isPrimitive());
-        if (!js_ValueToCharBuffer(cx, *vp, buf))
-            goto error;
-    }
-    JSString *str = js_NewStringFromCharBuffer(cx, buf);
-    if (!str)
-        goto error;
-    regs.sp -= argc - 1;
-    regs.sp[-1].setString(str);
-}
-END_CASE(JSOP_CONCATN)
-
 #define BINARY_OP(OP)                                                         \
     JS_BEGIN_MACRO                                                            \
         double d1, d2;                                                        \
         if (!ValueToNumber(cx, regs.sp[-2], &d1) ||                           \
             !ValueToNumber(cx, regs.sp[-1], &d2)) {                           \
             goto error;                                                       \
         }                                                                     \
         double d = d1 OP d2;                                                  \
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -209,18 +209,16 @@ js_GetVariableBytecodeLength(jsbytecode 
 uintN
 js_GetVariableStackUses(JSOp op, jsbytecode *pc)
 {
     JS_ASSERT(*pc == op || *pc == JSOP_TRAP);
     JS_ASSERT(js_CodeSpec[op].nuses == -1);
     switch (op) {
       case JSOP_POPN:
         return GET_UINT16(pc);
-      case JSOP_CONCATN:
-        return GET_UINT16(pc);
       case JSOP_LEAVEBLOCK:
         return GET_UINT16(pc);
       case JSOP_LEAVEBLOCKEXPR:
         return GET_UINT16(pc) + 1;
       case JSOP_NEWARRAY:
         return GET_UINT16(pc);
       default:
         /* stack: fun, this, [argc arguments] */
@@ -3554,61 +3552,16 @@ Decompile(SprintStack *ss, jsbytecode *p
                         return NULL;
                     rval = POP_STR();
                     LOCAL_ASSERT(*rval != '\0');
                     js_printf(jp, "\t%s;\n", rval);
                     todo = -2;
                 }
                 break;
 
-              case JSOP_CONCATN:
-              {
-                argc = GET_UINT16(pc);
-                JS_ASSERT(argc > 0);
-
-                js::Vector<char *> argv(cx);
-                if (!argv.resize(argc))
-                    return NULL;
-
-                MUST_FLOW_THROUGH("out");
-                ok = JS_FALSE;
-
-                for (i = argc - 1; i >= 0; i--) {
-                    argv[i] = JS_strdup(cx, POP_STR_PREC(cs->prec + 1));
-                    if (!argv[i])
-                        goto out;
-                }
-
-                todo = Sprint(&ss->sprinter, "%s", argv[0]);
-                if (todo < 0)
-                    goto out;
-                for (i = 1; i < argc; i++) {
-                    if (Sprint(&ss->sprinter, " + %s", argv[i]) < 0)
-                        goto out;
-                }
-
-                /*
-                 * The only way that our next op could be a JSOP_ADD is
-                 * if we are about to concatenate at least one non-string
-                 * literal. Deal with that here in order to avoid extra
-                 * parentheses (because JSOP_ADD is left-associative).
-                 */
-                if (pc[len] == JSOP_ADD)
-                    saveop = JSOP_NOP;
-
-                ok = JS_TRUE;
-
-              out:
-                for (i = 0; i < argc; i++)
-                    JS_free(cx, argv[i]);
-                if (!ok)
-                    return NULL;
-                break;
-              }
-
               case JSOP_NEW:
               case JSOP_CALL:
               case JSOP_EVAL:
               case JSOP_APPLY:
               case JSOP_SETCALL:
                 argc = GET_ARGC(pc);
                 argv = (char **)
                     cx->malloc((size_t)(argc + 1) * sizeof *argv);
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -586,27 +586,16 @@ OPDEF(JSOP_TRACE,         228, "trace", 
  */
 OPDEF(JSOP_GETUPVAR_DBG,  229,"getupvar_dbg",  NULL,  3,  0,  1, 19,  JOF_UINT16|JOF_NAME)
 OPDEF(JSOP_CALLUPVAR_DBG, 230,"callupvar_dbg", NULL,  3,  0,  2, 19,  JOF_UINT16|JOF_NAME|JOF_CALLOP)
 OPDEF(JSOP_DEFFUN_DBGFC,     231,"deffun_dbgfc",     NULL,  3,  0,  0,  0,  JOF_OBJECT|JOF_DECLARING)
 OPDEF(JSOP_DEFLOCALFUN_DBGFC,232,"deflocalfun_dbgfc",NULL,  5,  0,  0,  0,  JOF_SLOTOBJECT|JOF_DECLARING)
 OPDEF(JSOP_LAMBDA_DBGFC,     233,"lambda_dbgfc",     NULL,  3,  0,  1, 19,  JOF_OBJECT)
 
 /*
- * Concatenate N values, coercing to string if necessary, where N is concatn's
- * immediate.  See record_JSOP_CONCATN for recording behavior.
- */
-OPDEF(JSOP_CONCATN,       234,"concatn",       NULL,  3, -1,  1, 13,  JOF_UINT16|JOF_TMPSLOT2)
-
-/*
  * Joined function object as method optimization support.
  */
-OPDEF(JSOP_SETMETHOD,     235,"setmethod",     NULL,  3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
-OPDEF(JSOP_INITMETHOD,    236,"initmethod",    NULL,  3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
-OPDEF(JSOP_UNBRAND,       237,"unbrand",       NULL,  1,  1,  1,  0,  JOF_BYTE)
-OPDEF(JSOP_UNBRANDTHIS,   238,"unbrandthis",   NULL,  1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_SETMETHOD,     234,"setmethod",     NULL,  3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
+OPDEF(JSOP_INITMETHOD,    235,"initmethod",    NULL,  3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
+OPDEF(JSOP_UNBRAND,       236,"unbrand",       NULL,  1,  1,  1,  0,  JOF_BYTE)
+OPDEF(JSOP_UNBRANDTHIS,   237,"unbrandthis",   NULL,  1,  0,  0,  0,  JOF_BYTE)
 
-OPDEF(JSOP_SHARPINIT,     239,"sharpinit",     NULL,  3,  0,  0,  0,  JOF_UINT16|JOF_SHARPSLOT)
-
-/*
- * If the argument is an object, perform toString conversion (E-262-3 section 9.8).
- */
-OPDEF(JSOP_OBJTOSTR,      240,"objtostr",      NULL,  1,  1,  1,  0,  JOF_BYTE)
+OPDEF(JSOP_SHARPINIT,     238,"sharpinit",     NULL,  3,  0,  0,  0,  JOF_UINT16|JOF_SHARPSLOT)
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -15928,60 +15928,16 @@ TraceRecorder::record_JSOP_HOLE()
 }
 
 AbortableRecordingStatus
 TraceRecorder::record_JSOP_TRACE()
 {
     return ARECORD_CONTINUE;
 }
 
-static const uint32 sMaxConcatNSize = 32;
-
-JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_OBJTOSTR()
-{
-    Value &v = stackval(-1);
-    JS_ASSERT_IF(cx->fp->imacpc, v.isPrimitive() &&
-                                 *cx->fp->imacpc == JSOP_OBJTOSTR);
-    if (v.isPrimitive())
-        return ARECORD_CONTINUE;
-    CHECK_STATUS_A(guardNativeConversion(v));
-    return InjectStatus(callImacro(objtostr_imacros.toString));
-}
-
-JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_CONCATN()
-{
-    JSFrameRegs regs = *cx->regs;
-    uint32 argc = GET_ARGC(regs.pc);
-    Value *argBase = regs.sp - argc;
-
-    /* Prevent code/alloca explosion. */
-    if (argc > sMaxConcatNSize)
-        return ARECORD_STOP;
-
-    /* Build an array of the stringified primitives. */
-    int32_t bufSize = argc * sizeof(JSString *);
-    LIns *buf_ins = lir->insAlloc(bufSize);
-    int32_t d = 0;
-    for (Value *vp = argBase; vp != regs.sp; ++vp, d += sizeof(void *)) {
-        JS_ASSERT(vp->isPrimitive());
-        lir->insStore(stringify(*vp), buf_ins, d, ACCSET_OTHER);
-    }
-
-    /* Perform concatenation using a builtin. */
-    LIns *args[] = { lir->insImmI(argc), buf_ins, cx_ins };
-    LIns *result_ins = lir->insCall(&js_ConcatN_ci, args);
-    guard(false, lir->insEqP_0(result_ins), OOM_EXIT);
-
-    /* Update tracker with result. */
-    set(argBase, result_ins);
-    return ARECORD_CONTINUE;
-}
-
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETMETHOD()
 {
     return record_JSOP_SETPROP();
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_INITMETHOD()
--- a/js/src/jsxdrapi.h
+++ b/js/src/jsxdrapi.h
@@ -200,17 +200,17 @@ JS_XDRFindClassById(JSXDRState *xdr, uin
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number should be XDR'ed once near the front of any file or
  * larger storage unit containing XDR'ed bytecode and other data, and checked
  * 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 - 66)
+#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 67)
 
 /*
  * Library-private functions.
  */
 extern JSBool
 js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
 
 JS_END_EXTERN_C