author | David Mandelin <dmandelin@mozilla.com> |
Mon, 26 Jul 2010 11:52:26 -0700 | |
changeset 53192 | 25e52f0177f3ecb4056a0b6d64b67e2ddd6802c6 |
parent 53191 | 05552270db86d8c495543778e3c2527a2c2e415d (current diff) |
parent 48582 | 0bf3bcc923dc8bbb2a8e9678dc73e409bddc42d4 (diff) |
child 53193 | 3eeb1dab0369cdee7028ddb2938fd227adce086e |
push id | 15660 |
push user | rsayre@mozilla.com |
push date | Sat, 11 Sep 2010 19:16:24 +0000 |
treeherder | mozilla-central@f1bd314e64ac [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 2.0b2pre |
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
|
--- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1905,16 +1905,30 @@ struct JSContext void restoreSegment(); /* * Perform a linear search of all frames in all segments in the given context * for the given frame, returning the segment, if found, and null otherwise. */ js::CallStackSegment *containingSegment(const JSStackFrame *target); + /* + * Search the call stack for the nearest frame with static level targetLevel. + */ + JSStackFrame *findFrameAtLevel(uintN targetLevel) { + JSStackFrame *fp = this->fp; + while (true) { + JS_ASSERT(fp && fp->script); + if (fp->script->staticLevel == targetLevel) + break; + fp = fp->down; + } + return fp; + } + #ifdef JS_THREADSAFE JSThread *thread; jsrefcount requestDepth; /* Same as requestDepth but ignoring JS_SuspendRequest/JS_ResumeRequest */ jsrefcount outstandingRequests; JSContext *prevRequestContext; jsrefcount prevRequestDepth; # ifdef DEBUG
--- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1357,39 +1357,35 @@ JS_SetDestroyScriptHook(JSRuntime *rt, J JS_PUBLIC_API(JSBool) JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp, const jschar *chars, uintN length, const char *filename, uintN lineno, jsval *rval) { JS_ASSERT_NOT_ON_TRACE(cx); - JSObject *scobj; - JSScript *script; - JSBool ok; - - scobj = JS_GetFrameScopeChain(cx, fp); + JSObject *scobj = JS_GetFrameScopeChain(cx, fp); if (!scobj) - return JS_FALSE; + return false; /* * NB: This function breaks the assumption that the compiler can see all * calls and properly compute a static level. In order to get around this, * we use a static level that will cause us not to attempt to optimize * variable references made by this frame. */ - script = Compiler::compileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp), - TCF_COMPILE_N_GO, chars, length, NULL, filename, - lineno, NULL, UpvarCookie::MAX_LEVEL); + JSScript *script = Compiler::compileScript(cx, scobj, fp, JS_StackFramePrincipals(cx, fp), + TCF_COMPILE_N_GO, chars, length, NULL, + filename, lineno, NULL, + UpvarCookie::UPVAR_LEVEL_LIMIT); if (!script) - return JS_FALSE; + return false; - ok = Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, - Valueify(rval)); + bool ok = !!Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, Valueify(rval)); js_DestroyScript(cx, script); return ok; } JS_PUBLIC_API(JSBool) JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp, const char *bytes, uintN length,
--- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -1920,17 +1920,17 @@ MakeUpvarForEval(JSParseNode *pn, JSCode JSAtom *atom = pn->pn_atom; uintN index; JSLocalKind localKind = js_LookupLocal(cx, fun, atom, &index); if (localKind == JSLOCAL_NONE) return true; JS_ASSERT(cg->staticLevel > upvarLevel); - if (cg->staticLevel >= UpvarCookie::MAX_LEVEL || upvarLevel >= UpvarCookie::MAX_LEVEL) + if (cg->staticLevel >= UpvarCookie::UPVAR_LEVEL_LIMIT) return true; JSAtomListElement *ale = cg->upvarList.lookup(atom); if (!ale) { if (cg->inFunction() && !js_AddLocal(cx, cg->fun, atom, JSLOCAL_UPVAR)) { return false; } @@ -2217,31 +2217,30 @@ BindNameToSlot(JSContext *cx, JSCodeGene pn->pn_cookie = cookie; pn->pn_dflags |= PND_BOUND; return JS_TRUE; } return MakeUpvarForEval(pn, cg); } - uint16 skip = cg->staticLevel - level; + const uintN skip = cg->staticLevel - level; if (skip != 0) { JS_ASSERT(cg->inFunction()); JS_ASSERT_IF(cookie.slot() != UpvarCookie::CALLEE_SLOT, cg->lexdeps.lookup(atom)); JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); JS_ASSERT(cg->fun->u.i.skipmin <= skip); /* - * If op is a mutating opcode, this upvar's static level is too big to - * index into the display, or the function is heavyweight, we fall back - * on JSOP_*NAME*. + * If op is a mutating opcode, this upvar's lookup skips too many levels, + * or the function is heavyweight, we fall back on JSOP_*NAME*. */ if (op != JSOP_NAME) return JS_TRUE; - if (level >= UpvarCookie::MAX_LEVEL) + if (level >= UpvarCookie::UPVAR_LEVEL_LIMIT) return JS_TRUE; if (cg->flags & TCF_FUN_HEAVYWEIGHT) return JS_TRUE; if (FUN_FLAT_CLOSURE(cg->fun)) { op = JSOP_GETDSLOT; } else { /*
--- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -1390,24 +1390,26 @@ js_DoIncDec(JSContext *cx, const JSCodeS return JS_FALSE; (cs->format & JOF_INC) ? ++d : --d; vp->setNumber(d); *vp2 = *vp; return JS_TRUE; } const Value & -js::GetUpvar(JSContext *cx, uint16 closureLevel, UpvarCookie cookie) +js::GetUpvar(JSContext *cx, uintN closureLevel, UpvarCookie cookie) { JS_ASSERT(closureLevel >= cookie.level() && cookie.level() > 0); - const uint16 targetLevel = closureLevel - cookie.level(); - JSStackFrame *fp = FindFrameAtLevel(cx, targetLevel); - - uint16 slot = cookie.slot(); + const uintN targetLevel = closureLevel - cookie.level(); + JS_ASSERT(targetLevel < UpvarCookie::UPVAR_LEVEL_LIMIT); + + JSStackFrame *fp = cx->findFrameAtLevel(targetLevel); + uintN slot = cookie.slot(); Value *vp; + if (!fp->fun || (fp->flags & JSFRAME_EVAL)) { vp = fp->slots() + fp->script->nfixed; } else if (slot < fp->fun->nargs) { vp = fp->argv; } else if (slot == UpvarCookie::CALLEE_SLOT) { vp = &fp->argv[-2]; slot = 0; } else { @@ -2407,17 +2409,16 @@ Interpret(JSContext *cx, JSStackFrame *e * maintaining currentVersion. This is relied upon by testsuites, for * the most part -- web browsers select version before compiling and not * at run-time. */ JSVersion currentVersion = (JSVersion) script->version; JSVersion originalVersion = (JSVersion) cx->version; if (currentVersion != originalVersion) js_SetVersion(cx, currentVersion); - #define CHECK_INTERRUPT_HANDLER() \ JS_BEGIN_MACRO \ if (cx->debugHooks->interruptHook) \ ENABLE_INTERRUPTS(); \ JS_END_MACRO /* * Load the debugger's interrupt hook here and after calling out to native @@ -2732,17 +2733,16 @@ BEGIN_CASE(JSOP_STOP) } interpReturnOK = true; if (entryFrame != fp) inline_return: { JS_ASSERT(!fp->blockChain); JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0)); - void *hookData = fp->hookData; if (JS_UNLIKELY(hookData != NULL)) { if (JSInterpreterHook hook = cx->debugHooks->callHook) { hook(cx, fp, JS_FALSE, &interpReturnOK, hookData); CHECK_INTERRUPT_HANDLER(); } }
--- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -417,17 +417,17 @@ ValueToId(JSContext *cx, const Value &v, /* * @param closureLevel The static level of the closure that the cookie * pertains to. * @param cookie Level amount is a "skip" (delta) value from the * closure level. * @return The value of the upvar. */ extern const js::Value & -GetUpvar(JSContext *cx, uint16 closureLevel, js::UpvarCookie cookie); +GetUpvar(JSContext *cx, uintN level, js::UpvarCookie cookie); } /* namespace js */ /* * JS_LONE_INTERPRET indicates that the compiler should see just the code for * the js_Interpret function when compiling jsinterp.cpp. The rest of the code * from the file should be visible only when compiling jsinvoke.cpp. It allows * platform builds to optimize selectively js_Interpret when the granularity
--- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -73,38 +73,47 @@ namespace js { * TODO: consider giving more bits to the slot value and takings ome from the level. */ class UpvarCookie { uint32 value; static const uint32 FREE_VALUE = 0xfffffffful; + void checkInvariants() { + JS_STATIC_ASSERT(sizeof(UpvarCookie) == sizeof(uint32)); + JS_STATIC_ASSERT(UPVAR_LEVEL_LIMIT < FREE_LEVEL); + } + public: /* * All levels above-and-including FREE_LEVEL are reserved so that * FREE_VALUE can be used as a special value. */ static const uint16 FREE_LEVEL = 0x3fff; - static const uint16 MAX_LEVEL = FREE_LEVEL - 1; + + /* + * If a function has a higher static level than this limit, we will not + * optimize it using UPVAR opcodes. + */ + static const uint16 UPVAR_LEVEL_LIMIT = 16; static const uint16 CALLEE_SLOT = 0xffff; static bool isLevelReserved(uint16 level) { return level >= FREE_LEVEL; } bool isFree() const { return value == FREE_VALUE; } uint32 asInteger() const { return value; } /* isFree check should be performed before using these accessors. */ uint16 level() const { JS_ASSERT(!isFree()); return value >> 16; } - uint16 slot() const { JS_ASSERT(!isFree()); return uint16(value); } + uint16 slot() const { JS_ASSERT(!isFree()); return value; } void set(const UpvarCookie &other) { set(other.level(), other.slot()); } void set(uint16 newLevel, uint16 newSlot) { value = (uint32(newLevel) << 16) | newSlot; } void makeFree() { set(0xffff, 0xffff); JS_ASSERT(isFree()); } void fromInteger(uint32 u32) { value = u32; } }; -JS_STATIC_ASSERT(sizeof(UpvarCookie) == sizeof(uint32)); } /* * Exception handling record. */ struct JSTryNote { uint8 kind; /* one of JSTryNoteKind */
--- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -3119,18 +3119,18 @@ GetUpvarOnTrace(JSContext* cx, uint32 up *result = state->stackBase[native_slot]; return state->callstackBase[0]->get_typemap()[native_slot]; } /* * If we did not find the upvar in the frames for the active traces, * then we simply get the value from the interpreter state. */ - JS_ASSERT(upvarLevel < UpvarCookie::FREE_LEVEL); - JSStackFrame* fp = FindFrameAtLevel(cx, upvarLevel); + JS_ASSERT(upvarLevel < UpvarCookie::UPVAR_LEVEL_LIMIT); + JSStackFrame* fp = cx->findFrameAtLevel(upvarLevel); Value v = T::interp_get(fp, slot); JSValueType type = getCoercedType(v); ValueToNative(v, type, result); return type; } // For this traits type, 'slot' is the argument index, which may be -2 for callee. struct UpvarArgTraits { @@ -12910,17 +12910,17 @@ TraceRecorder::upvar(JSScript* script, J return ins; /* * The upvar is not in the current trace, so get the upvar value exactly as * the interpreter does and unbox. */ uint32 level = script->staticLevel - cookie.level(); uint32 cookieSlot = cookie.slot(); - JSStackFrame* fp = FindFrameAtLevel(cx, level); + JSStackFrame* fp = cx->findFrameAtLevel(level); const CallInfo* ci; int32 slot; if (!fp->fun || (fp->flags & JSFRAME_EVAL)) { ci = &GetUpvarStackOnTrace_ci; slot = cookieSlot; } else if (cookieSlot < fp->fun->nargs) { ci = &GetUpvarArgOnTrace_ci; slot = cookieSlot;
--- a/js/src/nanojit-import-rev +++ b/js/src/nanojit-import-rev @@ -1,1 +1,1 @@ -06774ab0e7e002b4fe6f4091a5dd59904fb6b080 +eb7dfecbdf2fd32d78673e10eb2289129966f6ce
--- a/js/src/nanojit/Assembler.cpp +++ b/js/src/nanojit/Assembler.cpp @@ -819,17 +819,17 @@ namespace nanojit // we are done producing the exit logic for the guard so demark where our exit block code begins NIns* jmpTarget = _nIns; // target in exit path for our mainline conditional jump // swap back pointers, effectively storing the last location used in the exit path swapCodeChunks(); _inExit = false; //verbose_only( verbose_outputf(" LIR_xt/xf swapCodeChunks, _nIns is now %08X(%08X), _nExitIns is now %08X(%08X)",_nIns, *_nIns,_nExitIns,*_nExitIns) ); - verbose_only( verbose_outputf("%p:", jmpTarget);) + verbose_only( verbose_outputf("%010lx:", (unsigned long)jmpTarget);) verbose_only( verbose_outputf("----------------------------------- ## BEGIN exit block (LIR_xt|LIR_xf)") ); #ifdef NANOJIT_IA32 NanoAssertMsgf(_fpuStkDepth == _sv_fpuStkDepth, "LIR_xtf, _fpuStkDepth=%d, expect %d",_fpuStkDepth, _sv_fpuStkDepth); debug_only( _fpuStkDepth = _sv_fpuStkDepth; _sv_fpuStkDepth = 9999; ) #endif return jmpTarget;
--- a/js/src/nanojit/Assembler.h +++ b/js/src/nanojit/Assembler.h @@ -169,17 +169,17 @@ namespace nanojit inline uint32_t AR::stackSlotsNeeded() const { // NB: _highWaterMark is an index, not a count return _highWaterMark+1; } #ifndef AVMPLUS_ALIGN16 - #ifdef _MSC_VER + #ifdef AVMPLUS_WIN32 #define AVMPLUS_ALIGN16(type) __declspec(align(16)) type #else #define AVMPLUS_ALIGN16(type) type __attribute__ ((aligned (16))) #endif #endif // error codes enum AssmError
--- a/js/src/nanojit/Native.h +++ b/js/src/nanojit/Native.h @@ -147,17 +147,17 @@ namespace nanojit { #define gpn(r) regNames[(r)] #elif defined(NJ_VERBOSE) // Used for printing native instructions. Like Assembler::outputf(), // but only outputs if LC_Native is set. Also prepends the output // with the address of the current native instruction. #define asm_output(...) do { \ if (_logc->lcbits & LC_Native) { \ outline[0]='\0'; \ - VMPI_sprintf(outline, "%p ", _nIns); \ + VMPI_sprintf(outline, "%010lx ", (unsigned long)_nIns); \ sprintf(&outline[13], ##__VA_ARGS__); \ output(); \ } \ } while (0) /* no semi */ #define gpn(r) regNames[(r)] #else #define asm_output(...) #define gpn(r)
--- a/js/src/nanojit/NativeARM.cpp +++ b/js/src/nanojit/NativeARM.cpp @@ -312,17 +312,17 @@ void Assembler::asm_sub_imm(Register rd, Register rn, int32_t imm, int stat /* =0 */) { // Operand 2 encoding of the immediate. uint32_t op2imm; NanoAssert(IsGpReg(rd)); NanoAssert(IsGpReg(rn)); NanoAssert((stat & 1) == stat); - + // As a special case to simplify code elsewhere, emit nothing where we // don't want to update the flags (stat == 0), the second operand is 0 and // (rd == rn). Such instructions are effectively NOPs. if ((imm == 0) && (stat == 0) && (rd == rn)) { return; } // Try to encode the value directly as an operand 2 immediate value, then @@ -1173,17 +1173,17 @@ Assembler::nPatchBranch(NIns* branch, NI // Just redirect the jump target, leave the insn alone. *addr = (NIns) target; } } RegisterMask Assembler::nHint(LIns* ins) { - NanoAssert(ins->isop(LIR_paramp)); + NanoAssert(ins->isop(LIR_paramp)); RegisterMask prefer = 0; if (ins->paramKind() == 0) if (ins->paramArg() < 4) prefer = rmask(argRegs[ins->paramArg()]); return prefer; } void
--- a/js/src/nanojit/NativeSparc.cpp +++ b/js/src/nanojit/NativeSparc.cpp @@ -242,16 +242,17 @@ namespace nanojit *(uint32_t*)&branch[0] &= 0xFFC00000; *(uint32_t*)&branch[0] |= ((intptr_t)location >> 10) & 0x3FFFFF; *(uint32_t*)&branch[1] &= 0xFFFFFC00; *(uint32_t*)&branch[1] |= (intptr_t)location & 0x3FF; } RegisterMask Assembler::nHint(LIns* ins) { + // Never called, because no entries in nHints[] == PREFER_SPECIAL. NanoAssert(0); return 0; } bool Assembler::canRemat(LIns* ins) { return ins->isImmI() || ins->isop(LIR_allocp); }
--- a/js/src/nanojit/NativeX64.cpp +++ b/js/src/nanojit/NativeX64.cpp @@ -2022,17 +2022,17 @@ namespace nanojit } RegisterMask Assembler::nHint(LIns* ins) { NanoAssert(ins->isop(LIR_paramp)); RegisterMask prefer = 0; uint8_t arg = ins->paramArg(); if (ins->paramKind() == 0) { - if (arg < maxArgRegs) + if (arg < maxArgRegs) prefer = rmask(argRegs[arg]); } else { if (arg < NumSavedRegs) prefer = rmask(savedRegs[arg]); } return prefer; }
--- a/js/src/nanojit/NativeX64.h +++ b/js/src/nanojit/NativeX64.h @@ -323,17 +323,17 @@ namespace nanojit X86_sete = 0xC0940F0000000003LL, // no-rex version of X64_sete X86_setnp = 0xC09B0F0000000003LL // no-rex set byte if odd parity (ordered fcmp result) (PF == 0) }; typedef uint32_t RegisterMask; static const RegisterMask GpRegs = 0xffff; static const RegisterMask FpRegs = 0xffff0000; -#ifdef _WIN64 +#ifdef _MSC_VER static const RegisterMask SavedRegs = 1<<RBX | 1<<RSI | 1<<RDI | 1<<R12 | 1<<R13 | 1<<R14 | 1<<R15; static const int NumSavedRegs = 7; // rbx, rsi, rdi, r12-15 static const int NumArgRegs = 4; #else static const RegisterMask SavedRegs = 1<<RBX | 1<<R12 | 1<<R13 | 1<<R14 | 1<<R15; static const int NumSavedRegs = 5; // rbx, r12-15 static const int NumArgRegs = 6; #endif
--- a/js/src/nanojit/Nativei386.cpp +++ b/js/src/nanojit/Nativei386.cpp @@ -1128,17 +1128,17 @@ namespace nanojit RegisterMask Assembler::nHint(LIns* ins) { NanoAssert(ins->isop(LIR_paramp)); RegisterMask prefer = 0; uint8_t arg = ins->paramArg(); if (ins->paramKind() == 0) { uint32_t max_regs = max_abi_regs[_thisfrag->lirbuf->abi]; - if (arg < max_regs) + if (arg < max_regs) prefer = rmask(argRegs[arg]); } else { if (arg < NumSavedRegs) prefer = rmask(savedRegs[arg]); } return prefer; }
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1466,21 +1466,18 @@ GetTrapArgs(JSContext *cx, uintN argc, j } return JS_TRUE; } static JSTrapStatus TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure) { - JSString *str; - JSStackFrame *caller; - - str = JSVAL_TO_STRING(closure); - caller = JS_GetScriptedCaller(cx, NULL); + JSString *str = JSVAL_TO_STRING(closure); + JSStackFrame *caller = JS_GetScriptedCaller(cx, NULL); if (!JS_EvaluateUCInStackFrame(cx, caller, JS_GetStringChars(str), JS_GetStringLength(str), caller->script->filename, caller->script->lineno, rval)) { return JSTRAP_ERROR; } if (!JSVAL_IS_VOID(*rval)) return JSTRAP_RETURN;