Bug 581747 - Remove JSOP_CONCATN. Good-night, sweet prince. (r=waldo)

This commit is contained in:
Luke Wagner 2010-08-01 21:54:09 -07:00
Родитель 9920fb0623
Коммит e8e95b497f
9 изменённых файлов: 6 добавлений и 243 удалений

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

@ -688,31 +688,6 @@
.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

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

@ -364,42 +364,3 @@ js_PopInterpFrame(JSContext* cx, TracerState* state)
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)

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

@ -597,7 +597,6 @@ 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)

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

@ -5968,47 +5968,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
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:

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

@ -3487,35 +3487,6 @@ BEGIN_CASE(JSOP_ADD)
}
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; \

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

@ -214,8 +214,6 @@ js_GetVariableStackUses(JSOp op, jsbytecode *pc)
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:
@ -3559,51 +3557,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
}
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:

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

@ -590,23 +590,12 @@ OPDEF(JSOP_DEFFUN_DBGFC, 231,"deffun_dbgfc", NULL, 3, 0, 0, 0, JOF_
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)

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

@ -15933,50 +15933,6 @@ 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()
{

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

@ -205,7 +205,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 - 66)
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 67)
/*
* Library-private functions.