Merge from Tracemonkey.
authorDavid 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 id15660
push userrsayre@mozilla.com
push dateSat, 11 Sep 2010 19:16:24 +0000
treeherdermozilla-central@f1bd314e64ac [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.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
Merge from Tracemonkey.
content/canvas/src/CustomQS_WebGL.h
js/src/jsarray.cpp
js/src/jsbuiltins.cpp
js/src/jsbuiltins.h
js/src/jscntxt.h
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsemit.cpp
js/src/jsfun.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsrecursion.cpp
js/src/jsregexp.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jstracer.cpp
js/src/jstracer.h
js/src/jstypedarray.cpp
js/src/shell/js.cpp
js/src/xpconnect/src/qsgen.py
--- 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;