Backed out bugs 607539, 606890, 609212 - perf regressions & test failures
authorBill McCloskey <wmccloskey@mozilla.com>
Thu, 11 Nov 2010 19:37:12 -0800
changeset 57802 cb76b2d6109678b8a7a9c3165d38a96d99c2ac3e
parent 57801 96a84cd98d845d49a467bac7ca02de9e4f2349a8
child 57803 2e91aa1d2ff54f01d10ed94afeda5dd5986decca
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
bugs607539, 606890, 609212
milestone2.0b8pre
Backed out bugs 607539, 606890, 609212 - perf regressions & test failures
js/src/assembler/assembler/MacroAssemblerARM.h
js/src/jscntxt.cpp
js/src/jshotloop.h
js/src/jsinterp.cpp
js/src/jstracer.cpp
js/src/jstracer.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MonoIC.h
--- a/js/src/assembler/assembler/MacroAssemblerARM.h
+++ b/js/src/assembler/assembler/MacroAssemblerARM.h
@@ -645,23 +645,16 @@ public:
 
     Jump branchSub32(Condition cond, Address src, RegisterID dest)
     {
         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
         sub32(src, dest);
         return Jump(m_assembler.jmp(ARMCondition(cond)));
     }
 
-    Jump branchSub32(Condition cond, Imm32 imm, Address dest)
-    {
-        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
-        sub32(imm, dest);
-        return Jump(m_assembler.jmp(ARMCondition(cond)));
-    }
-
     Jump branchNeg32(Condition cond, RegisterID srcDest)
     {
         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
         neg32(srcDest);
         return Jump(m_assembler.jmp(ARMCondition(cond)));
     }
 
     Jump branchOr32(Condition cond, RegisterID src, RegisterID dest)
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -2283,17 +2283,17 @@ JSContext::updateJITEnabled()
     methodJitEnabled = (options & JSOPTION_METHODJIT) &&
                        !IsJITBrokenHere()
 # if defined JS_CPU_X86 || defined JS_CPU_X64
                        && JSC::MacroAssemblerX86Common::getSSEState() >=
                           JSC::MacroAssemblerX86Common::HasSSE2
 # endif
                         ;
 #ifdef JS_TRACER
-    profilingEnabled = (options & JSOPTION_PROFILING) && traceJitEnabled;
+    profilingEnabled = (options & JSOPTION_PROFILING) && traceJitEnabled && methodJitEnabled;
 #endif
 #endif
 }
 
 namespace js {
 
 void
 SetPendingException(JSContext *cx, const Value &v)
deleted file mode 100644
--- a/js/src/jshotloop.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Mozilla SpiderMonkey JaegerMonkey implementation
- *
- * The Initial Developer of the Original Code is
- *   Mozilla Foundation
- * Portions created by the Initial Developer are Copyright (C) 2002-2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef jshotloop_h___
-#define jshotloop_h___
-
-#include "jscntxt.h"
-
-namespace js {
-
-uint32
-GetHotloop(JSContext *cx);
-
-}
-
-#endif
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -743,20 +743,16 @@ Invoke(JSContext *cx, const CallArgs &ar
 }
 
 bool
 InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &thisv, uintN argc)
 {
 #ifdef JS_TRACER
     if (TRACE_RECORDER(cx))
         AbortRecording(cx, "attempt to reenter VM while recording");
-#ifdef JS_METHODJIT
-    if (TRACE_PROFILER(cx))
-        AbortProfiling(cx);
-#endif
     LeaveTrace(cx);
 #endif
 
     /* Always push arguments, regardless of optimized/normal invoke. */
     StackSpace &stack = cx->stack();
     if (!stack.pushInvokeArgs(cx, argc, &args_))
         return false;
 
@@ -2328,31 +2324,21 @@ Interpret(JSContext *cx, JSStackFrame *e
 # define END_VARLEN_CASE    goto advance_pc;
 # define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP)
 # define END_EMPTY_CASES    goto advance_pc_by_one;
 
 #endif /* !JS_THREADED_INTERP */
 
     /* Check for too deep of a native thread stack. */
 #ifdef JS_TRACER
-#ifdef JS_METHODJIT
-    JS_CHECK_RECURSION(cx, do {
-            if (TRACE_RECORDER(cx))
-                AbortRecording(cx, "too much recursion");
-            if (TRACE_PROFILER(cx))
-                AbortProfiling(cx);
-            return JS_FALSE;
-        } while (0););
-#else
     JS_CHECK_RECURSION(cx, do {
             if (TRACE_RECORDER(cx))
                 AbortRecording(cx, "too much recursion");
             return JS_FALSE;
         } while (0););
-#endif
 #else
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 #endif
 
 #define LOAD_ATOM(PCOFF, atom)                                                \
     JS_BEGIN_MACRO                                                            \
         JS_ASSERT(regs.fp->hasImacropc()                                      \
                   ? atoms == COMMON_ATOMS_START(&rt->atomState) &&            \
@@ -2405,25 +2391,19 @@ Interpret(JSContext *cx, JSStackFrame *e
     JS_END_MACRO
 
 #define MONITOR_BRANCH()                                                      \
     JS_BEGIN_MACRO                                                            \
         if (TRACING_ENABLED(cx)) {                                            \
             MonitorResult r = MonitorLoopEdge(cx, inlineCallCount);           \
             if (r == MONITOR_RECORDING) {                                     \
                 JS_ASSERT(TRACE_RECORDER(cx));                                \
-                JS_ASSERT(!TRACE_PROFILER(cx));                               \
                 MONITOR_BRANCH_TRACEVIS;                                      \
                 ENABLE_INTERRUPTS();                                          \
                 CLEAR_LEAVE_ON_TRACE_POINT();                                 \
-            } else if (r == MONITOR_PROFILING) {                              \
-                JS_ASSERT(TRACE_PROFILER(cx));                                \
-                JS_ASSERT(!TRACE_RECORDER(cx));                               \
-                ENABLE_INTERRUPTS();                                          \
-                CLEAR_LEAVE_ON_TRACE_POINT();                                 \
             }                                                                 \
             RESTORE_INTERP_VARS();                                            \
             JS_ASSERT_IF(cx->throwing, r == MONITOR_ERROR);                   \
             if (r == MONITOR_ERROR)                                           \
                 goto error;                                                   \
         }                                                                     \
     JS_END_MACRO
 
@@ -2447,17 +2427,16 @@ Interpret(JSContext *cx, JSStackFrame *e
 #define TRACE_RECORDER(cx) (false)
 #define TRACE_PROFILER(cx) (false)
 #endif
 
 #if defined(JS_TRACER) && defined(JS_METHODJIT)
 # define LEAVE_ON_SAFE_POINT()                                                \
     do {                                                                      \
         JS_ASSERT_IF(leaveOnSafePoint, !TRACE_RECORDER(cx));                  \
-        JS_ASSERT_IF(leaveOnSafePoint, !TRACE_PROFILER(cx));                  \
         if (leaveOnSafePoint && !regs.fp->hasImacropc() &&                    \
             script->maybeNativeCodeForPC(regs.fp->isConstructing(), regs.pc)) { \
             JS_ASSERT(!TRACE_RECORDER(cx));                                   \
             interpReturnOK = true;                                            \
             goto leave_on_safe_point;                                         \
         }                                                                     \
     } while (0)
 #else
@@ -2559,30 +2538,21 @@ Interpret(JSContext *cx, JSStackFrame *e
 #ifdef JS_TRACER
     /*
      * The method JIT may have already initiated a recording, in which case
      * there should already be a valid recorder. Otherwise...
      * we cannot reenter the interpreter while recording.
      */
     if (interpMode == JSINTERP_RECORD) {
         JS_ASSERT(TRACE_RECORDER(cx));
-        JS_ASSERT(!TRACE_PROFILER(cx));
         ENABLE_INTERRUPTS();
-#ifdef JS_METHODJIT
     } else if (interpMode == JSINTERP_PROFILE) {
-        JS_ASSERT(TRACE_PROFILER(cx));
-        JS_ASSERT(!TRACE_RECORDER(cx));
         ENABLE_INTERRUPTS();
-#endif
     } else if (TRACE_RECORDER(cx)) {
         AbortRecording(cx, "attempt to reenter interpreter while recording");
-#ifdef JS_METHODJIT
-    } else if (TRACE_PROFILER(cx)) {
-        AbortProfiling(cx);
-#endif
     }
 
     if (regs.fp->hasImacropc())
         atoms = COMMON_ATOMS_START(&rt->atomState);
 #endif
 
     /* Don't call the script prologue if executing between Method and Trace JIT. */
     if (interpMode == JSINTERP_NORMAL) {
@@ -2647,20 +2617,16 @@ Interpret(JSContext *cx, JSStackFrame *e
 #endif /* !JS_THREADED_INTERP */
     {
         bool moreInterrupts = false;
         JSInterruptHook hook = cx->debugHooks->interruptHook;
         if (hook) {
 #ifdef JS_TRACER
             if (TRACE_RECORDER(cx))
                 AbortRecording(cx, "interrupt hook");
-#ifdef JS_METHODJIT
-            if (TRACE_PROFILER(cx))
-                AbortProfiling(cx);
-#endif
 #endif
             Value rval;
             switch (hook(cx, script, regs.pc, Jsvalify(&rval),
                          cx->debugHooks->interruptHookData)) {
               case JSTRAP_ERROR:
                 goto error;
               case JSTRAP_CONTINUE:
                 break;
@@ -2675,31 +2641,29 @@ Interpret(JSContext *cx, JSStackFrame *e
               default:;
             }
             moreInterrupts = true;
         }
 
 #ifdef JS_TRACER
 #ifdef JS_METHODJIT
         if (LoopProfile *prof = TRACE_PROFILER(cx)) {
-            JS_ASSERT(!TRACE_RECORDER(cx));
             LoopProfile::ProfileAction act = prof->profileOperation(cx, op);
             switch (act) {
                 case LoopProfile::ProfComplete:
                     leaveOnSafePoint = true;
                     LEAVE_ON_SAFE_POINT();
                     break;
                 default:
                     moreInterrupts = true;
                     break;
             }
         }
 #endif
         if (TraceRecorder* tr = TRACE_RECORDER(cx)) {
-            JS_ASSERT(!TRACE_PROFILER(cx));
             AbortableRecordingStatus status = tr->monitorRecording(op);
             JS_ASSERT_IF(cx->throwing, status == ARECORD_ERROR);
 
             if (interpMode != JSINTERP_NORMAL) {
                 JS_ASSERT(interpMode == JSINTERP_RECORD || JSINTERP_SAFEPOINT);
                 switch (status) {
                   case ARECORD_IMACRO_ABORTED:
                   case ARECORD_ABORTED:
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -6551,17 +6551,17 @@ ExecuteTree(JSContext* cx, TreeFragment*
                       f->treeLineNumber, prefix, (uintN)iters, f->execs,
                       getExitName(lr->exitType),
                       fp->script()->filename,
                       js_FramePCToLineNumber(cx, fp),
                       js_CodeName[fp->hasImacropc() ? *fp->imacropc() : *cx->regs->pc]);
 #endif
     
 #ifdef JS_METHODJIT
-    if (cx->methodJitEnabled && !cx->profilingEnabled) {
+    if (cx->methodJitEnabled) {
         if (lr->exitType == LOOP_EXIT && f->iters < MIN_LOOP_ITERS
             && f->execs >= LOOP_CHECK_ITERS)
         {
             debug_only_printf(LC_TMMinimal, "  Blacklisting at line %u (executed only %d iters)\n",
                               f->treeLineNumber, f->iters);
             Blacklist((jsbytecode *)f->ip);
         }
     }
@@ -6907,17 +6907,17 @@ LeaveTree(TraceMonitor *tm, TracerState&
     else
         AUDIT(timeoutIntoInterpreter);
 #endif
 
     state.innermost = innermost;
 }
 
 JS_REQUIRES_STACK MonitorResult
-RecordLoopEdge(JSContext* cx, uintN& inlineCallCount, bool execOK)
+RecordLoopEdge(JSContext* cx, uintN& inlineCallCount)
 {
 #ifdef MOZ_TRACEVIS
     TraceVisStateObj tvso(cx, S_MONITOR);
 #endif
 
     TraceMonitor* tm = &JS_TRACE_MONITOR(cx);
 
     /* Is the recorder currently active? */
@@ -7030,19 +7030,16 @@ RecordLoopEdge(JSContext* cx, uintN& inl
         debug_only_print0(LC_TMTracer, "Blacklisted: too many peer trees.\n");
         Blacklist((jsbytecode*) f->root->ip);
 #ifdef MOZ_TRACEVIS
         tvso.r = R_MAX_PEERS;
 #endif
         return MONITOR_NOT_RECORDING;
     }
 
-    if (!execOK)
-        return MONITOR_NOT_RECORDING;
-    
     VMSideExit* lr = NULL;
     VMSideExit* innermostNestedGuard = NULL;
 
     if (!ExecuteTree(cx, match, inlineCallCount, &innermostNestedGuard, &lr))
         return MONITOR_ERROR;
 
     if (!lr) {
 #ifdef MOZ_TRACEVIS
@@ -16164,18 +16161,17 @@ class AutoRetBlacklist
 
     ~AutoRetBlacklist()
     {
         *blacklist = IsBlacklisted(pc);
     }
 };
 
 JS_REQUIRES_STACK TracePointAction
-RecordTracePoint(JSContext* cx, uintN& inlineCallCount, bool* blacklist, uint32 *loopCounter,
-                 bool execAllowed)
+RecordTracePoint(JSContext* cx, uintN& inlineCallCount, bool* blacklist, bool execAllowed)
 {
     JSStackFrame* fp = cx->fp();
     TraceMonitor* tm = &JS_TRACE_MONITOR(cx);
     jsbytecode* pc = cx->regs->pc;
 
     JS_ASSERT(!TRACE_RECORDER(cx));
 
     JSObject* globalObj = cx->fp()->scopeChain().getGlobal();
@@ -16205,34 +16201,23 @@ RecordTracePoint(JSContext* cx, uintN& i
             VMSideExit* innermostNestedGuard = NULL;
 
             if (!execAllowed) {
                 /* We've already compiled a trace for it, but we don't want to use that trace. */
                 Blacklist((jsbytecode*)tree->root->ip);
                 return TPA_Nothing;
             }
 
-            uintN oldIters = match->iters;
-
             /* Best case - just go and execute. */
             if (!ExecuteTree(cx, match, inlineCallCount, &innermostNestedGuard, &lr))
                 return TPA_Error;
 
             if (!lr)
                 return TPA_Nothing;
 
-            if (lr->exitType == LOOP_EXIT
-                && match->iters - oldIters < MIN_LOOP_ITERS/LOOP_CHECK_ITERS
-                && match->execs >= LOOP_CHECK_ITERS)
-            {
-                debug_only_printf(LC_TMMinimal, "  Wait-and-see at line %u (executed only %d iters)\n",
-                                  match->treeLineNumber, match->iters);
-                *loopCounter = 5000;
-            }
-            
             switch (lr->exitType) {
               case UNSTABLE_LOOP_EXIT:
                 if (!AttemptToStabilizeTree(cx, globalObj, lr, NULL, 0, NULL))
                     return TPA_RanStuff;
                 break;
 
               case MUL_ZERO_EXIT:
               case OVERFLOW_EXIT:
@@ -16284,72 +16269,59 @@ RecordTracePoint(JSContext* cx, uintN& i
     if (!Interpret(cx, fp, inlineCallCount, JSINTERP_RECORD))
         return TPA_Error;
 
     JS_ASSERT(!cx->throwing);
     
     return TPA_RanStuff;
 }
 
-LoopProfile::LoopProfile(JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom)
-    : script(entryfp->script()),
-      entryfp(entryfp),
+LoopProfile::LoopProfile(JSScript *script, jsbytecode *top, jsbytecode *bottom)
+    : script(script),
       top(top),
       bottom(bottom),
       hits(0),
-      undecided(false),
-      expensive(false),
-      unprofitable(false)
-{
-    reset();
-}
-
-void
-LoopProfile::reset()
-{
-    profiled = false;
-    traceOK = false;
-    execOK = false;
-    numAllOps = 0;
-    numSelfOps = 0;
-    numSelfOpsMult = 0;
-    branchMultiplier = 1;
-    shortLoop = false;
-    maybeShortLoop = false;
-    numInnerLoops = 0;
-    loopStackDepth = 0;
-    sp = 0;
-
+      profiled(false),
+      traceOK(false),
+      numAllOps(0),
+      numSelfOps(0),
+      numSelfOpsMult(0),
+      branchMultiplier(1),
+      shortLoop(false),
+      maybeShortLoop(false),
+      numInnerLoops(0),
+      loopStackDepth(0),
+      sp(0)
+{
     memset(allOps, 0, sizeof(allOps));
     memset(selfOps, 0, sizeof(selfOps));
 }
 
 MonitorResult
 LoopProfile::profileLoopEdge(JSContext* cx, uintN& inlineCallCount)
 {
     if (cx->regs->pc == top) {
         debug_only_print0(LC_TMProfiler, "Profiling complete (edge)\n");
         decide(cx);
     } else {
         /* Record an inner loop invocation. */
-        JSStackFrame *fp = cx->fp();
+        JSScript *script = cx->fp()->script();
         jsbytecode *pc = cx->regs->pc;
         bool found = false;
 
         /* We started with the most deeply nested one first, since it gets hit most often.*/
         for (int i = int(numInnerLoops)-1; i >= 0; i--) {
-            if (innerLoops[i].entryfp == fp && innerLoops[i].top == pc) {
+            if (innerLoops[i].script == script && innerLoops[i].top == pc) {
                 innerLoops[i].iters++;
                 found = true;
-                break;
             }
         }
 
         if (!found && numInnerLoops < PROFILE_MAX_INNER_LOOPS)
-            innerLoops[numInnerLoops++] = InnerLoop(fp, pc, NULL);
+            innerLoops[numInnerLoops++] = InnerLoop(script, pc, NULL);
     }
 
     return MONITOR_NOT_RECORDING;
 }
 
 
 static const uintN PROFILE_HOTLOOP = 61;
 static const uintN MAX_PROFILE_OPS = 4096;
@@ -16381,52 +16353,52 @@ LookupOrAddProfile(JSContext *cx, TraceM
      * follows. Every time the trace monitor is flushed,
      * |tm->flushEpoch| is incremented. When storing the profile in
      * the IC, we store the current |tm->flushEpoch| along with it.
      * Before pulling a profile out of the IC, we check that its
      * stored epoch is still up-to-date with |tm->flushEpoch|.
      * This ensures that no flush has happened in between.
      */
 
-    if (traceData) {
-        if (*traceData && *traceEpoch == tm->flushEpoch) {
-            prof = (LoopProfile *)*traceData;
-        } else {
-            jsbytecode* pc = cx->regs->pc;
-            jsbytecode* bottom = GetLoopBottom(cx);
-            if (!bottom)
-                return NULL;
-            prof = new (*tm->dataAlloc) LoopProfile(cx->fp(), pc, bottom);
-            *traceData = prof;
-            *traceEpoch = tm->flushEpoch;
-            tm->loopProfiles->put(pc, prof);
-        }
-    } else {
-        LoopProfileMap &table = *tm->loopProfiles;
+#if JS_MONOIC
+    if (*traceData && *traceEpoch == tm->flushEpoch) {
+        prof = (LoopProfile *)*traceData;
+    } else {
         jsbytecode* pc = cx->regs->pc;
-        if (LoopProfileMap::AddPtr p = table.lookupForAdd(pc)) {
-            prof = p->value;
-        } else {
-            jsbytecode* bottom = GetLoopBottom(cx);
-            if (!bottom)
-                return NULL;
-            prof = new (*tm->dataAlloc) LoopProfile(cx->fp(), pc, bottom);
-            table.add(p, pc, prof);
-        }
-    }
+        jsbytecode* bottom = GetLoopBottom(cx);
+        if (!bottom)
+            return NULL;
+        prof = new (*tm->dataAlloc) LoopProfile(cx->fp()->script(), pc, bottom);
+        *traceData = prof;
+        *traceEpoch = tm->flushEpoch;
+        tm->loopProfiles->put(pc, prof);
+    }
+#else
+    LoopProfileMap &table = *tm->loopProfiles;
+    jsbytecode* pc = cx->regs->pc;
+    if (LoopProfileMap::AddPtr p = table.lookupForAdd(pc)) {
+        prof = p->value;
+    } else {
+        jsbytecode* bottom = GetLoopBottom(cx);
+        if (!bottom)
+            return NULL;
+        prof = new (*tm->dataAlloc) LoopProfile(cx->fp()->script(), pc, bottom);
+        table.add(p, pc, prof);
+    }
+#endif
 
     return prof;
 }
 
 JS_REQUIRES_STACK TracePointAction
 MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist,
-                  void** traceData, uintN *traceEpoch, uint32 *loopCounter, uint32 hits)
+                  void** traceData, uintN *traceEpoch)
 {
     if (!cx->profilingEnabled)
-        return RecordTracePoint(cx, inlineCallCount, blacklist, loopCounter, true);
+        return RecordTracePoint(cx, inlineCallCount, blacklist, true);
 
     *blacklist = false;
 
     TraceMonitor *tm = &JS_TRACE_MONITOR(cx);
     /*
      * We may have re-entered Interpret while profiling. We don't profile
      * the nested invocation.
      */
@@ -16434,99 +16406,93 @@ MonitorTracePoint(JSContext *cx, uintN& 
         return TPA_Nothing;
 
     LoopProfile *prof = LookupOrAddProfile(cx, tm, traceData, traceEpoch);
     if (!prof) {
         *blacklist = true;
         return TPA_Nothing;
     }
 
-    prof->hits += hits;
-    if (prof->hits < PROFILE_HOTLOOP)
+    if (prof->hits++ < PROFILE_HOTLOOP)
         return TPA_Nothing;
 
     AutoRetBlacklist autoRetBlacklist(cx->regs->pc, blacklist);
 
     if (prof->profiled) {
         if (prof->traceOK) {
-            return RecordTracePoint(cx, inlineCallCount, blacklist, loopCounter, prof->execOK);
+            return RecordTracePoint(cx, inlineCallCount, blacklist, prof->execOK);
         } else {
             return TPA_Nothing;
         }
     }
 
     debug_only_printf(LC_TMProfiler, "Profiling at line %d\n",
                       js_FramePCToLineNumber(cx, cx->fp()));
 
     tm->profile = prof;
 
     if (!Interpret(cx, cx->fp(), inlineCallCount, JSINTERP_PROFILE))
         return TPA_Error;
 
     JS_ASSERT(!cx->throwing);
-
-    if (prof->undecided) {
-        *loopCounter = 5000;
-        prof->reset();
-    }
     
     return TPA_RanStuff;
 }
 
 /*
- * Returns true if pc is within the given loop. Also returns true if
- * we are in some function called by the loop.
+ * Returns true if pc is within the given loop.
+ * If we're in a different script, then we must have come from
+ * a call instruction within the loop (since we check if we're within
+ * the loop before each instruction) so we're still in the loop.
  */
 template<class T>
 static inline bool
-PCWithinLoop(JSStackFrame *fp, jsbytecode *pc, T& loop)
-{
-    return fp > loop.entryfp || (fp == loop.entryfp && pc >= loop.top && pc <= loop.bottom);
+PCWithinLoop(JSScript *script, jsbytecode *pc, T& loop)
+{
+    return script != loop.script || (pc >= loop.top && pc <= loop.bottom);
 }
 
 LoopProfile::ProfileAction
 LoopProfile::profileOperation(JSContext* cx, JSOp op)
 {
     TraceMonitor* tm = &JS_TRACE_MONITOR(cx);
 
     if (profiled) {
         tm->profile = NULL;
         return ProfComplete;
     }
 
     jsbytecode *pc = cx->regs->pc;
-    JSStackFrame *fp = cx->fp();
-    JSScript *script = fp->script();
-
-    if (!PCWithinLoop(fp, pc, *this)) {
-        debug_only_printf(LC_TMProfiler, "Profiling complete (loop exit) at line %u\n",
+    JSScript *script = cx->fp()->maybeScript();
+
+    if (!PCWithinLoop(script, pc, *this)) {
+        debug_only_printf(LC_TMProfiler, "Profiling complete (loop exit) at %d (line %u)\n",
+                          (int)(cx->regs->pc - cx->fp()->script()->code),
                           js_FramePCToLineNumber(cx, cx->fp()));
         tm->profile->decide(cx);
         tm->profile = NULL;
         return ProfComplete;
     }
 
-    while (loopStackDepth > 0 && !PCWithinLoop(fp, pc, loopStack[loopStackDepth-1])) {
-        debug_only_printf(LC_TMProfiler, "Profiler: Exiting inner loop at line %u\n",
-                          js_FramePCToLineNumber(cx, cx->fp()));
+    while (loopStackDepth > 0 && !PCWithinLoop(script, pc, loopStack[loopStackDepth-1])) {
+        debug_only_print0(LC_TMProfiler, "Profiler: Exiting inner loop\n");
         loopStackDepth--;
     }
 
     if (op == JSOP_TRACE || op == JSOP_NOTRACE) {
         if (pc != top && (loopStackDepth == 0 || pc != loopStack[loopStackDepth-1].top)) {
             if (loopStackDepth == PROFILE_MAX_INNER_LOOPS) {
                 debug_only_print0(LC_TMProfiler, "Profiling complete (maxnest)\n");
                 tm->profile->decide(cx);
                 tm->profile = NULL;
                 return ProfComplete;
             }
 
-            debug_only_printf(LC_TMProfiler, "Profiler: Entering inner loop at line %d\n",
-                              js_FramePCToLineNumber(cx, cx->fp()));
-            loopStack[loopStackDepth++] = InnerLoop(fp, pc, GetLoopBottom(cx));
+            debug_only_print0(LC_TMProfiler, "Profiler: Entering inner loop\n");
+            loopStack[loopStackDepth++] = InnerLoop(script, pc, GetLoopBottom(cx));
         }
     }
 
     numAllOps++;
     if (loopStackDepth == 0) {
         numSelfOps++;
         numSelfOpsMult += branchMultiplier;
     }
@@ -16556,18 +16522,16 @@ LoopProfile::profileOperation(JSContext*
 
     if (op == JSOP_NEW)
         increment(OP_NEW);
 
     if (op == JSOP_GETELEM || op == JSOP_SETELEM) {
         Value& lval = cx->regs->sp[op == JSOP_GETELEM ? -2 : -3];
         if (lval.isObject() && js_IsTypedArray(&lval.toObject()))
             increment(OP_TYPED_ARRAY);
-        else if (lval.isObject() && lval.toObject().isDenseArray() && op == JSOP_GETELEM)
-            increment(OP_ARRAY_READ);
     }
 
     if (op == JSOP_CALL) {
         increment(OP_CALL);
 
         uintN argc = GET_ARGC(cx->regs->pc);
         Value &v = cx->regs->sp[-((int)argc + 2)];
         JSObject *callee;
@@ -16580,17 +16544,17 @@ LoopProfile::profileOperation(JSContext*
                 js::Native native = fun->u.n.native;
                 if (js_IsMathFunction(JS_JSVALIFY_NATIVE(native)))
                     increment(OP_FLOAT);
             }
         }
     }
 
     if (op == JSOP_CALLPROP && loopStackDepth == 0)
-        branchMultiplier *= mjit::GetCallTargetCount(script, cx->regs->pc);
+        branchMultiplier *= mjit::GetCallTargetCount(cx->fp()->script(), cx->regs->pc);
 
     if (op == JSOP_TABLESWITCH) {
         jsint low = GET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN);
         jsint high = GET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN*2);
         branchMultiplier *= high - low + 1;
     }
 
     if (op == JSOP_LOOKUPSWITCH)
@@ -16605,25 +16569,26 @@ LoopProfile::profileOperation(JSContext*
 
     /* These are the places where the interpreter skips over branches. */
     jsbytecode *testPC = cx->regs->pc;
     if (op == JSOP_EQ || op == JSOP_NE || op == JSOP_LT || op == JSOP_GT
         || op == JSOP_LE || op == JSOP_GE || op == JSOP_IN || op == JSOP_MOREITER)
     {
         const JSCodeSpec *cs = &js_CodeSpec[op];
         ptrdiff_t oplen = cs->length;
+        JSScript *script = cx->fp()->script();
         JS_ASSERT(oplen != -1);
 
         if (cx->regs->pc - script->code + oplen < ptrdiff_t(script->length))
             if (cx->regs->pc[oplen] == JSOP_IFEQ || cx->regs->pc[oplen] == JSOP_IFNE)
                 testPC = cx->regs->pc + oplen;
     }
 
     /* Check if we're exiting the loop being profiled. */
-    JSOp testOp = js_GetOpcode(cx, script, testPC);
+    JSOp testOp = js_GetOpcode(cx, cx->fp()->script(), testPC);
     if (testOp == JSOP_IFEQ || testOp == JSOP_IFNE || testOp == JSOP_GOTO
         || testOp == JSOP_AND || testOp == JSOP_OR)
     {
         ptrdiff_t len = GET_JUMP_OFFSET(testPC);
         if (testPC + len == top && (op == JSOP_LT || op == JSOP_LE)) {
             StackValue v = stackAt(-1);
             if (v.hasValue && v.value < 8)
                 shortLoop = true;
@@ -16677,70 +16642,78 @@ LookupLoopProfile(JSContext *cx, jsbytec
     LoopProfileMap &table = *tm->loopProfiles;
     if (LoopProfileMap::Ptr p = table.lookup(pc)) {
         JS_ASSERT(p->value->top == pc);
         return p->value;
     } else
         return NULL;
 }
 
-/* Returns true if the loop would probably take a long time to compile. */
+/*
+ * Returns true if the loop would probably take a long time to
+ * compile. Since this function recurses into nested loops, we
+ * pass a depth argument to ensure that we don't recurse too
+ * far and overflow the stack. Mostly, we're guarding against
+ * the possibility that we (incorrectly) track a loop as being
+ * nested inside itself, leading to infinite recursion.
+ */
 bool
-LoopProfile::isCompilationExpensive(JSContext *cx)
-{
+LoopProfile::isCompilationExpensive(JSContext *cx, uintN depth)
+{
+    if (depth == 0)
+        return true;
+
     /* Too many ops to compile? */
     if (numSelfOps == MAX_PROFILE_OPS)
-        expensive = true;
+        return true;
 
     /* Is the code too branchy? */
-    if (numSelfOpsMult > numSelfOps*100000)
-        expensive = true;
+    if (numSelfOpsMult >= numSelfOps*100000)
+        return true;
 
     /* Ensure that inner loops aren't too expensive. */
     for (uintN i=0; i<numInnerLoops; i++) {
         LoopProfile *prof = LookupLoopProfile(cx, innerLoops[i].top);
-        if (prof && prof->expensive)
-            expensive = true;
-    }
-
-    return expensive;
+        if (prof && prof->isCompilationExpensive(cx, depth-1))
+            return true;
+    }
+
+    return false;
 }
 
 /*
  * This function recognizes loops that are short and that contain
  * jumps. The tracer does badly with these loops because it
  * needs to do a lot of side exits, which are somewhat
  * expensive.
  */
 bool
-LoopProfile::isCompilationUnprofitable(JSContext *cx, uintN goodOps)
-{
-    if (goodOps <= 20 && allOps[OP_FWDJUMP])
-        unprofitable = true;
+LoopProfile::isCompilationUnprofitable(JSContext *cx, uintN depth)
+{
+    if (depth == 0)
+        return true;
+
+    if (numAllOps < 15 && allOps[OP_FWDJUMP])
+        return true;
     
     /* Ensure that inner loops aren't fleeting. */
     for (uintN i=0; i<numInnerLoops; i++) {
         LoopProfile *prof = LookupLoopProfile(cx, innerLoops[i].top);
-        if (prof && prof->unprofitable)
-            unprofitable = true;
-    }
-
-    return unprofitable;
+        if (prof && prof->isCompilationUnprofitable(cx, depth-1))
+            return true;
+    }
+
+    return false;
 }
 
 /* After profiling is done, this method decides whether to trace the loop. */
 void
 LoopProfile::decide(JSContext *cx)
 {
-    bool wasUndecided = undecided;
     profiled = true;
-    undecided = false;
-
-    if (traceOK)
-        return; /* We must have enabled it from an outer loop already. */
 
 #ifdef DEBUG
     uintN line = js_PCToLineNumber(cx, script, top);
 
     debug_only_printf(LC_TMProfiler, "LOOP %s:%d\n", script->filename, line);
 
     for (uintN i=0; i<numInnerLoops; i++) {
         InnerLoop &loop = innerLoops[i];
@@ -16752,65 +16725,56 @@ LoopProfile::decide(JSContext *cx)
     }
     debug_only_printf(LC_TMProfiler, "FEATURE float %d\n", allOps[OP_FLOAT]);
     debug_only_printf(LC_TMProfiler, "FEATURE int %d\n", allOps[OP_INT]);
     debug_only_printf(LC_TMProfiler, "FEATURE bit %d\n", allOps[OP_BIT]);
     debug_only_printf(LC_TMProfiler, "FEATURE equality %d\n", allOps[OP_EQ]);
     debug_only_printf(LC_TMProfiler, "FEATURE eval %d\n", allOps[OP_EVAL]);
     debug_only_printf(LC_TMProfiler, "FEATURE new %d\n", allOps[OP_NEW]);
     debug_only_printf(LC_TMProfiler, "FEATURE call %d\n", allOps[OP_CALL]);
-    debug_only_printf(LC_TMProfiler, "FEATURE arrayread %d\n", allOps[OP_ARRAY_READ]);
     debug_only_printf(LC_TMProfiler, "FEATURE typedarray %d\n", allOps[OP_TYPED_ARRAY]);
     debug_only_printf(LC_TMProfiler, "FEATURE fwdjump %d\n", allOps[OP_FWDJUMP]);
     debug_only_printf(LC_TMProfiler, "FEATURE recursive %d\n", allOps[OP_RECURSIVE]);
     debug_only_printf(LC_TMProfiler, "FEATURE shortLoop %d\n", shortLoop);
     debug_only_printf(LC_TMProfiler, "FEATURE maybeShortLoop %d\n", maybeShortLoop);
     debug_only_printf(LC_TMProfiler, "FEATURE numAllOps %d\n", numAllOps);
     debug_only_printf(LC_TMProfiler, "FEATURE selfOps %d\n", numSelfOps);
     debug_only_printf(LC_TMProfiler, "FEATURE selfOpsMult %g\n", numSelfOpsMult);
 #endif
 
     traceOK = false;
     if (count(OP_RECURSIVE)) {
-        debug_only_print0(LC_TMProfiler, "NOTRACE: recursive\n");
+        /* don't trace */
     } else if (count(OP_EVAL)) {
-        debug_only_print0(LC_TMProfiler, "NOTRACE: eval\n");
-    } else if (numInnerLoops > 7) {
-        debug_only_print0(LC_TMProfiler, "NOTRACE: >3 inner loops\n");
+        /* don't trace */
+    } else if (numInnerLoops > 3) {
+        /* don't trace */
     } else if (shortLoop) {
-        debug_only_print0(LC_TMProfiler, "NOTRACE: short\n");
-    } else if (isCompilationExpensive(cx)) {
-        debug_only_print0(LC_TMProfiler, "NOTRACE: expensive\n");
+        /* don't trace */
     } else if (maybeShortLoop && numInnerLoops < 2) {
-        if (wasUndecided) {
-            debug_only_print0(LC_TMProfiler, "NOTRACE: maybe short\n");
-        } else {
-            debug_only_print0(LC_TMProfiler, "UNDECIDED: maybe short\n");
-            undecided = true; /* Profile the loop again to see if it's still short. */
-        }
+        /* don't trace */
+    } else if (isCompilationExpensive(cx, 4)) {
+        /* don't trace */
+    } else if (isCompilationUnprofitable(cx, 4)) {
+        /* don't trace */
     } else {
         uintN goodOps = 0;
 
         /* The tracer handles these ops well because of type specialization. */
-        goodOps += count(OP_FLOAT)*10 + count(OP_BIT)*10 + count(OP_INT)*5 + count(OP_EQ)*15;
+        goodOps += count(OP_FLOAT)*10 + count(OP_BIT)*10 + count(OP_INT)*5;
 
         /* The tracer handles these ops well because of inlining. */
         goodOps += (count(OP_CALL) + count(OP_NEW))*20;
 
         /* The tracer specialized typed array access. */
         goodOps += count(OP_TYPED_ARRAY)*10;
 
-        /* The methodjit is faster at array writes, but the tracer is faster for reads. */
-        goodOps += count(OP_ARRAY_READ)*15;
-
         debug_only_printf(LC_TMProfiler, "FEATURE goodOps %u\n", goodOps);
-
-        if (isCompilationUnprofitable(cx, goodOps))
-            debug_only_print0(LC_TMProfiler, "NOTRACE: unprofitable\n");
-        else if (goodOps >= numAllOps)
+        
+        if (goodOps >= numAllOps)
             traceOK = true;
     }
 
     debug_only_printf(LC_TMProfiler, "TRACE %s:%d = %d\n", script->filename, line, traceOK);
 
     if (traceOK) {
         /* Unblacklist the inner loops. */
         for (uintN i=0; i<numInnerLoops; i++) {
@@ -16821,91 +16785,56 @@ LoopProfile::decide(JSContext *cx)
                  * Note that execOK for the inner loop is left unchanged. So even
                  * if we trace the inner loop, we will never call that trace
                  * on its own. We'll only call it from this trace.
                  */
                 prof->profiled = true;
                 prof->traceOK = true;
                 if (IsBlacklisted(loop.top))
                     debug_only_printf(LC_TMProfiler, "Unblacklisting at %d\n",
-                                      js_PCToLineNumber(cx, prof->script, loop.top));
-                Unblacklist(prof->script, loop.top);
+                                      js_PCToLineNumber(cx, loop.script, loop.top));
+                Unblacklist(loop.script, loop.top);
             }
         }
     }
 
-    if (!traceOK && !undecided) {
+    if (!traceOK) {
         debug_only_printf(LC_TMProfiler, "Blacklisting at %d\n", line);
         Blacklist(top);
     }
 
     debug_only_print0(LC_TMProfiler, "\n");
 
     execOK = traceOK;
 }
 
 JS_REQUIRES_STACK MonitorResult
 MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount)
 {
-    if (!cx->profilingEnabled || TRACE_RECORDER(cx))
-        return RecordLoopEdge(cx, inlineCallCount, true);
-
     TraceMonitor *tm = &JS_TRACE_MONITOR(cx);
-
     if (tm->profile)
         return tm->profile->profileLoopEdge(cx, inlineCallCount);
-
-    LoopProfile *prof = LookupOrAddProfile(cx, tm, NULL, NULL);
-    if (!prof)
-        return MONITOR_NOT_RECORDING;
-
-    if (prof->hits++ < PROFILE_HOTLOOP)
-        return MONITOR_NOT_RECORDING;
-
-    if (prof->profiled || prof->undecided) {
-        if (prof->traceOK)
-            return RecordLoopEdge(cx, inlineCallCount, prof->execOK);
-        return MONITOR_NOT_RECORDING;
-    }
-
-    debug_only_printf(LC_TMProfiler, "Profiling at line %d\n",
-                      js_FramePCToLineNumber(cx, cx->fp()));
-
-    tm->profile = prof;
-
-    return MONITOR_PROFILING;
+    else
+        return RecordLoopEdge(cx, inlineCallCount);
 }
 
 void
 AbortProfiling(JSContext *cx)
 {
     debug_only_print0(LC_TMProfiler, "Profiling complete (aborted)\n");
     TraceMonitor *tm = &JS_TRACE_MONITOR(cx);
-    tm->profile->profiled = true;
-    tm->profile->traceOK = false;
-    tm->profile->execOK = false;
-    tm->profile->undecided = false;
+    tm->profile->numSelfOps = MAX_PROFILE_OPS;
+    tm->profile->decide(cx);
     tm->profile = NULL;
 }
 
 #else /* JS_METHODJIT */
 
 JS_REQUIRES_STACK MonitorResult
 MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount)
 {
-    return RecordLoopEdge(cx, inlineCallCount, true);
+    return RecordLoopEdge(cx, inlineCallCount);
 }
 
 #endif /* JS_METHODJIT */
 
-uint32
-GetHotloop(JSContext *cx)
-{
-#ifdef JS_METHODJIT
-    if (cx->profilingEnabled)
-        return PROFILE_HOTLOOP;
-    else
-#endif
-        return 1;
-}
-
 } /* namespace js */
 
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -635,17 +635,16 @@ inline TreeFragment*
 VMFragment::toTreeFragment()
 {
     JS_ASSERT(root == this);
     return static_cast<TreeFragment*>(this);
 }
 
 enum MonitorResult {
     MONITOR_RECORDING,
-    MONITOR_PROFILING,
     MONITOR_NOT_RECORDING,
     MONITOR_ERROR
 };
 
 const uintN PROFILE_MAX_INNER_LOOPS = 8;
 const uintN PROFILE_MAX_STACK = 6;
 
 /*
@@ -661,39 +660,32 @@ public:
         OP_INT, // Integer arithmetic
         OP_BIT, // Bit operations
         OP_EQ, // == and !=
         OP_EVAL, // Calls to eval()
         OP_CALL, // JSOP_CALL instructions
         OP_FWDJUMP, // Jumps with positive delta
         OP_NEW, // JSOP_NEW instructions
         OP_RECURSIVE, // Recursive calls
-        OP_ARRAY_READ, // Reads from dense arrays
         OP_TYPED_ARRAY, // Accesses to typed arrays
         OP_LIMIT
     };
 
     /* The script in which the loop header lives. */
     JSScript *script;
 
-    /* The stack frame where we started profiling. Only valid while profiling! */
-    JSStackFrame *entryfp;
-    
     /* The bytecode locations of the loop header and the back edge. */
     jsbytecode *top, *bottom;
 
     /* Number of times we have seen this loop executed; used to decide when to profile. */
     uintN hits;
 
     /* Whether we have run a complete profile of the loop. */
     bool profiled;
 
-    /* Sometimes we can't decide in one profile run whether to trace, so we set undecided. */
-    bool undecided;
-
     /* If we have profiled the loop, this saves the decision of whether to trace it. */
     bool traceOK;
 
     /*
      * Sometimes loops are not good tracing opportunities, but they are nested inside
      * loops that we want to trace. In that case, we set their traceOK flag to true,
      * but we set execOK to false. That way, the loop is traced so that it can be
      * integrated into the outer trace. But we never execute the trace on its only.
@@ -725,32 +717,28 @@ public:
     double branchMultiplier;
 
     /* Set to true if the loop is short (i.e., has fewer than 8 iterations). */
     bool shortLoop;
 
     /* Set to true if the loop may be short (has few iterations at profiling time). */
     bool maybeShortLoop;
 
-    /* These are memoized versions of isCompilationExpensive/Unprofitable. */
-    bool expensive;
-    bool unprofitable;
-
     /*
      * When we hit a nested loop while profiling, we record where it occurs
      * and how many iterations we execute it.
      */
     struct InnerLoop {
-        JSStackFrame *entryfp;
+        JSScript *script;
         jsbytecode *top, *bottom;
         uintN iters;
 
         InnerLoop() {}
-        InnerLoop(JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom)
-            : entryfp(entryfp), top(top), bottom(bottom), iters(0) {}
+        InnerLoop(JSScript *script, jsbytecode *top, jsbytecode *bottom)
+            : script(script), top(top), bottom(bottom), iters(0) {}
     };
 
     /* These two variables track all the inner loops seen while profiling (up to a limit). */
     InnerLoop innerLoops[PROFILE_MAX_INNER_LOOPS];
     uintN numInnerLoops;
 
     /*
      * These two variables track the loops that we are currently nested
@@ -790,20 +778,18 @@ public:
     inline StackValue stackAt(int pos) {
         pos += sp;
         if (pos >= 0 && uintN(pos) < PROFILE_MAX_STACK)
             return stack[pos];
         else
             return StackValue(false);
     }
     
-    LoopProfile(JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom);
+    LoopProfile(JSScript *script, jsbytecode *top, jsbytecode *bottom);
 
-    void reset();
-    
     enum ProfileAction {
         ProfContinue,
         ProfComplete
     };
 
     /* These two functions track the instruction mix. */
     inline void increment(OpKind kind)
     {
@@ -816,18 +802,18 @@ public:
 
     /* Called for every back edge being profiled. */
     MonitorResult profileLoopEdge(JSContext* cx, uintN& inlineCallCount);
     
     /* Called for every instruction being profiled. */
     ProfileAction profileOperation(JSContext *cx, JSOp op);
 
     /* Once a loop's profile is done, these decide whether it should be traced. */
-    bool isCompilationExpensive(JSContext *cx);
-    bool isCompilationUnprofitable(JSContext *cx, uintN goodOps);
+    bool isCompilationExpensive(JSContext *cx, uintN depth);
+    bool isCompilationUnprofitable(JSContext *cx, uintN depth);
     void decide(JSContext *cx);
 };
 
 /*
  * BUILTIN_NO_FIXUP_NEEDED indicates that after the initial LeaveTree of a deep
  * bail, the builtin call needs no further fixup when the trace exits and calls
  * LeaveTree the second time.
  */
@@ -1570,17 +1556,17 @@ class TraceRecorder
     friend class AdjustCallerStackTypesVisitor;
     friend class TypeCompatibilityVisitor;
     friend class ImportFrameSlotsVisitor;
     friend class SlotMap;
     friend class DefaultSlotMap;
     friend class DetermineTypesVisitor;
     friend class RecursiveSlotMap;
     friend class UpRecursiveSlotMap;
-    friend MonitorResult RecordLoopEdge(JSContext*, uintN&, bool);
+    friend MonitorResult RecordLoopEdge(JSContext*, uintN&);
     friend TracePointAction RecordTracePoint(JSContext*, uintN &inlineCallCount,
                                              bool *blacklist);
     friend AbortResult AbortRecording(JSContext*, const char*);
     friend class BoxArg;
     friend void TraceMonitor::sweep();
 
   public:
     static bool JS_REQUIRES_STACK
@@ -1662,21 +1648,21 @@ class TraceRecorder
 
 extern JS_REQUIRES_STACK MonitorResult
 MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount);
 
 extern JS_REQUIRES_STACK MonitorResult
 ProfileLoopEdge(JSContext* cx, uintN& inlineCallCount);
 
 extern JS_REQUIRES_STACK TracePointAction
-RecordTracePoint(JSContext*, uintN& inlineCallCount, uint32 *loopCounter, bool* blacklist);
+RecordTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist);
 
 extern JS_REQUIRES_STACK TracePointAction
 MonitorTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist,
-                  void** traceData, uintN *traceEpoch, uint32 *loopCounter, uint32 hits);
+                  void** traceData, uintN *traceEpoch);
 
 extern JS_REQUIRES_STACK TraceRecorder::AbortResult
 AbortRecording(JSContext* cx, const char* reason);
 
 extern void
 InitJIT(TraceMonitor *tm);
 
 extern void
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -52,17 +52,16 @@
 #include "assembler/assembler/LinkBuffer.h"
 #include "FrameState-inl.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 #include "InlineFrameAssembler.h"
 #include "jscompartment.h"
 #include "jsobjinlines.h"
 #include "jsopcodeinlines.h"
-#include "jshotloop.h"
 
 #include "jsautooplen.h"
 
 using namespace js;
 using namespace js::mjit;
 #if defined(JS_POLYIC) || defined(JS_MONOIC)
 using namespace js::mjit::ic;
 #endif
@@ -596,18 +595,16 @@ mjit::Compiler::finishThisUp(JITScript *
             scriptTICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry);
             scriptTICs[i].traceData = NULL;
 #ifdef DEBUG
             scriptTICs[i].jumpTargetPC = traceICs[i].jumpTarget;
 #endif
             scriptTICs[i].hasSlowTraceHint = traceICs[i].slowTraceHint.isSet();
             if (traceICs[i].slowTraceHint.isSet())
                 scriptTICs[i].slowTraceHint = stubCode.locationOf(traceICs[i].slowTraceHint.get());
-            scriptTICs[i].loopCounterStart = GetHotloop(cx);
-            scriptTICs[i].loopCounter = scriptTICs[i].loopCounterStart;
             
             stubCode.patch(traceICs[i].addrLabel, &scriptTICs[i]);
         }
     }
 #endif /* JS_MONOIC */
 
     for (size_t i = 0; i < callPatches.length(); i++) {
         CallPatchInfo &patch = callPatches[i];
@@ -4752,39 +4749,35 @@ mjit::Compiler::jumpAndTrace(Jump j, jsb
     Label traceStart = stubcc.masm.label();
 
     stubcc.linkExitDirect(j, traceStart);
     if (slow)
         slow->linkTo(traceStart, &stubcc.masm);
 # if JS_MONOIC
     ic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
     traceICs[index] = ic;
-
-    Jump nonzero = stubcc.masm.branchSub32(Assembler::NonZero, Imm32(1),
-                                           Address(Registers::ArgReg1,
-                                                   offsetof(TraceICInfo, loopCounter)));
-    stubcc.jumpInScript(nonzero, target);
 # endif
 
     /* Save and restore compiler-tracked PC, so cx->regs is right in InvokeTracer. */
     {
         jsbytecode* pc = PC;
         PC = target;
 
         OOL_STUBCALL(stubs::InvokeTracer);
 
         PC = pc;
     }
 
     Jump no = stubcc.masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
                                         Registers::ReturnReg);
-    if (!stubcc.jumpInScript(no, target))
-        return false;
     restoreFrameRegs(stubcc.masm);
     stubcc.masm.jump(Registers::ReturnReg);
+    no.linkTo(stubcc.masm.label(), &stubcc.masm);
+    if (!stubcc.jumpInScript(stubcc.masm.jump(), target))
+        return false;
 #endif
     return true;
 }
 
 void
 mjit::Compiler::enterBlock(JSObject *obj)
 {
     // If this is an exception entry point, then jsl_InternalThrow has set
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -967,36 +967,27 @@ RunTracer(VMFrame &f)
      */
     entryFrame->scopeChain();
     entryFrame->returnValue();
 
     bool blacklist;
     uintN inlineCallCount = 0;
     void **traceData;
     uintN *traceEpoch;
-    uint32 *loopCounter;
-    uint32 hits;
 #if JS_MONOIC
     traceData = &tic.traceData;
     traceEpoch = &tic.traceEpoch;
-    loopCounter = &tic.loopCounter;
-    *loopCounter = 1;
-    hits = tic.loopCounterStart;
 #else
     traceData = NULL;
     traceEpoch = NULL;
-    loopCounter = NULL;
-    hits = 1;
 #endif
-    tpa = MonitorTracePoint(f.cx, inlineCallCount, &blacklist, traceData, traceEpoch,
-                            loopCounter, hits);
+    tpa = MonitorTracePoint(f.cx, inlineCallCount, &blacklist, traceData, traceEpoch);
     JS_ASSERT(!TRACE_RECORDER(cx));
 
 #if JS_MONOIC
-    tic.loopCounterStart = *loopCounter;
     if (blacklist)
         DisableTraceHint(f, tic);
 #endif
 
     // Even though ExecuteTree() bypasses the interpreter, it should propagate
     // error failures correctly.
     JS_ASSERT_IF(cx->throwing, tpa == TPA_Error);
 
--- a/js/src/methodjit/MonoIC.h
+++ b/js/src/methodjit/MonoIC.h
@@ -148,18 +148,16 @@ struct TraceICInfo {
     JSC::CodeLocationJump slowTraceHint;
 #ifdef DEBUG
     jsbytecode *jumpTargetPC;
 #endif
     
     /* This data is used by the tracing JIT. */
     void *traceData;
     uintN traceEpoch;
-    uint32 loopCounter;
-    uint32 loopCounterStart;
 
     bool hasSlowTraceHint : 1;
 };
 
 static const uint16 BAD_TRACEIC_INDEX = (uint16)0xffff;
 
 void JS_FASTCALL GetGlobalName(VMFrame &f, ic::MICInfo *ic);
 void JS_FASTCALL SetGlobalName(VMFrame &f, ic::MICInfo *ic);