Merge backout.
authorDavid Anderson <danderson@mozilla.com>
Fri, 03 Sep 2010 17:26:36 -0700
changeset 74535 621a97f3779660793dddaca4dff43d082ee70b1a
parent 74533 83c4ad328180299b89c5885f9673576afcf3a047 (current diff)
parent 74534 87f0a1f6bfb79bdf5dd687b0bc008d38820a921d (diff)
child 74536 e9c0f9eb7d3ea08d510d456387bc375e225897ac
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone2.0b6pre
Merge backout.
js/src/methodjit/Compiler.cpp
js/src/methodjit/InlineFrameAssembler.h
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/MonoIC.h
--- a/content/events/test/Makefile.in
+++ b/content/events/test/Makefile.in
@@ -41,18 +41,16 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = content/events/test
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 # Disabled due to timeouts.
 # 		test_bug563329.html
-# Disabled due to lack of present support for JSD in JM
-#		test_bug448602.html
 _TEST_FILES = \
 		test_bug226361.xhtml \
 		     bug226361_iframe.xhtml \
 		test_bug238987.html \
 		test_bug288392.html \
 		test_bug299673-1.html \
 		test_bug299673-2.html \
 		     bug299673.js \
@@ -69,16 +67,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug391568.xhtml \
 		test_bug402089.html \
 		test_bug405632.html \
 		test_bug409604.html \
 		test_bug412567.html \
 		test_bug426082.html \
 		test_bug443985.html \
 		test_bug447736.html \
+		test_bug448602.html \
 		test_bug450876.html \
 		test_bug456273.html \
 		test_bug457672.html \
 		test_bug428988.html \
 		bug457672.html \
 		test_draggableprop.html \
 		test_bug489671.html \
 		test_bug493251.html \
--- a/js/src/assembler/assembler/MacroAssemblerCodeRef.h
+++ b/js/src/assembler/assembler/MacroAssemblerCodeRef.h
@@ -154,23 +154,16 @@ public:
     void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return m_value; }
 #endif
 
     bool operator!()
     {
         return !m_value;
     }
 
-    ptrdiff_t operator -(const MacroAssemblerCodePtr &other) const
-    {
-        JS_ASSERT(m_value);
-        return reinterpret_cast<uint8 *>(m_value) -
-               reinterpret_cast<uint8 *>(other.m_value);
-    }
-
 private:
     void* m_value;
 };
 
 // MacroAssemblerCodeRef:
 //
 // A reference to a section of JIT generated code.  A CodeRef consists of a
 // pointer to the code, and a ref pointer to the pool from within which it
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -71,21 +71,16 @@ enum JSFrameFlags {
     JSFRAME_RECORDING          =  0x200, /* recording a trace */
     JSFRAME_BAILED_AT_RETURN   =  0x400, /* bailed at JSOP_RETURN */
     JSFRAME_DUMMY              =  0x800, /* frame is a dummy frame */
     JSFRAME_IN_IMACRO          = 0x1000, /* frame has imacpc value available */
 	
     JSFRAME_SPECIAL            = JSFRAME_DEBUGGER | JSFRAME_EVAL
 };
 
-namespace js { namespace mjit {
-    class Compiler;
-    class InlineFrameAssembler;
-} }
-
 /*
  * JS stack frame, may be allocated on the C stack by native callers.  Always
  * allocated on cx->stackPool for calls from the interpreter to an interpreted
  * function.
  *
  * NB: This struct is manually initialized in jsinterp.c and jsiter.c.  If you
  * add new members, update both files.
  */
@@ -289,20 +284,16 @@ struct JSStackFrame
     JSObject* maybeBlockChain() const {
         return blockChain;
     }
 
     void setBlockChain(JSObject *obj) {
         blockChain = obj;
     }
 
-    static size_t offsetBlockChain() {
-        return offsetof(JSStackFrame, blockChain);
-    }
-
     /* IMacroPC accessors. */
 
     bool hasIMacroPC() const { return flags & JSFRAME_IN_IMACRO; }
 
     /*
      * @pre     hasIMacroPC
      * @return  The PC at which an imacro started executing (guaranteed non-null. The PC of the
      *          executing imacro must be in regs.pc, so the displaced
@@ -339,20 +330,16 @@ struct JSStackFrame
     void* maybeAnnotation() const {
         return annotation;
     }
 
     void setAnnotation(void *annot) {
         annotation = annot;
     }
 
-    static size_t offsetAnnotation() {
-        return offsetof(JSStackFrame, annotation);
-    }
-
     /* Debugger hook data accessors */
 
     bool hasHookData() const {
         return hookData != NULL;
     }
 
     void* getHookData() const {
         JS_ASSERT(hasHookData());
@@ -362,34 +349,26 @@ struct JSStackFrame
     void* maybeHookData() const {
         return hookData;
     }
 
     void setHookData(void *data) {
         hookData = data;
     }
 
-    static size_t offsetHookData() {
-        return offsetof(JSStackFrame, hookData);
-    }
-
     /* Version accessors */
 
     JSVersion getCallerVersion() const {
         return callerVersion;
     }
 
     void setCallerVersion(JSVersion version) {
         callerVersion = version;
     }
 
-    static size_t offsetCallerVersion() {
-        return offsetof(JSStackFrame, callerVersion);
-    }
-
     /* Script accessors */
 
     bool hasScript() const {
         return script != NULL;
     }
 
     JSScript* getScript() const {
         JS_ASSERT(hasScript());
@@ -426,20 +405,16 @@ struct JSStackFrame
         JS_ASSERT(hasFunction());
         return fun;
     }
 
     JSFunction* maybeFunction() const {
         return fun;
     }
 
-    static size_t offsetFunction() {
-        return offsetof(JSStackFrame, fun);
-    }
-
     size_t numFormalArgs() const {
         JS_ASSERT(!isEvalFrame());
         return getFunction()->nargs;
     }
 
     void setFunction(JSFunction *f) {
         fun = f;
     }
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1309,21 +1309,16 @@ js_TraceScript(JSTracer *trc, JSScript *
 
     if (script->u.object) {
         JS_SET_TRACING_NAME(trc, "object");
         Mark(trc, script->u.object, JSTRACE_OBJECT);
     }
 
     if (IS_GC_MARKING_TRACER(trc) && script->filename)
         js_MarkScriptFilename(script->filename);
-
-#ifdef JS_METHODJIT
-    if (script->jit)
-        mjit::TraceScriptCache(trc, script);
-#endif
 }
 
 JSBool
 js_NewScriptObject(JSContext *cx, JSScript *script)
 {
     AutoScriptRooter root(cx, script);
 
     JS_ASSERT(!script->u.object);
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -175,17 +175,16 @@ namespace mjit {
 struct JITScript;
 
 namespace ic {
 # if defined JS_POLYIC
     struct PICInfo;
 # endif
 # if defined JS_MONOIC
     struct MICInfo;
-    struct CallICInfo;
 # endif
 }
 struct CallSite;
 }
 }
 #endif
 
 struct JSScript {
@@ -259,17 +258,16 @@ struct JSScript {
     void            *ncode;     /* native code compiled by the method JIT */
     void            **nmap;     /* maps PCs to native code */
     js::mjit::JITScript *jit;   /* Extra JIT info */
 # if defined JS_POLYIC
     js::mjit::ic::PICInfo *pics; /* PICs in this script */
 # endif
 # if defined JS_MONOIC
     js::mjit::ic::MICInfo *mics; /* MICs in this script. */
-    js::mjit::ic::CallICInfo *callICs; /* CallICs in this script. */
 # endif
 
     bool isValidJitCode(void *jcode);
 #endif
 
     /* Script notes are allocated right after the code. */
     jssrcnote *notes() { return (jssrcnote *)(code + length); }
 
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -131,23 +131,21 @@ class BaseAssembler : public JSC::MacroA
 #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
     static const RegisterID JSFrameReg = JSC::X86Registers::ebx;
 #elif defined(JS_CPU_ARM)
     static const RegisterID JSFrameReg = JSC::ARMRegisters::r11;
 #endif
 
     /* Register pair storing returned type/data for calls. */
 #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
-static const JSC::MacroAssembler::RegisterID JSReturnReg_Type  = JSC::X86Registers::ecx;
-static const JSC::MacroAssembler::RegisterID JSReturnReg_Data  = JSC::X86Registers::edx;
-static const JSC::MacroAssembler::RegisterID JSParamReg_Argc   = JSC::X86Registers::ecx;
+static const JSC::MacroAssembler::RegisterID JSReturnReg_Type = JSC::X86Registers::ecx;
+static const JSC::MacroAssembler::RegisterID JSReturnReg_Data = JSC::X86Registers::edx;
 #elif defined(JS_CPU_ARM)
-static const JSC::MacroAssembler::RegisterID JSReturnReg_Type  = JSC::ARMRegisters::r2;
-static const JSC::MacroAssembler::RegisterID JSReturnReg_Data  = JSC::ARMRegisters::r1;
-static const JSC::MacroAssembler::RegisterID JSParamReg_Argc   = JSC::ARMRegisters::r1;
+static const JSC::MacroAssembler::RegisterID JSReturnReg_Type = JSC::ARMRegisters::r2;
+static const JSC::MacroAssembler::RegisterID JSReturnReg_Data = JSC::ARMRegisters::r1;
 #endif
 
     size_t distanceOf(Label l) {
         return differenceBetween(startLabel, l);
     }
 
     void load32FromImm(void *ptr, RegisterID reg) {
         load32(ptr, reg);
@@ -253,20 +251,16 @@ static const JSC::MacroAssembler::Regist
                  FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, pc)));
 
         /* Store sp */
         fixScriptStack(frameDepth);
 
         /* VMFrame -> ArgReg0 */
         setupVMFrame();
 
-        return wrapCall(pfun);
-    }
-
-    Call wrapCall(void *pfun) {
 #ifdef JS_METHODJIT_PROFILE_STUBS
         push(Registers::ArgReg0);
         push(Registers::ArgReg1);
         call(JS_FUNC_TO_DATA_PTR(void *, mjit::ProfileStubCall));
         pop(Registers::ArgReg1);
         pop(Registers::ArgReg0);
 #endif
 #if defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)
@@ -299,20 +293,16 @@ static const JSC::MacroAssembler::Regist
         storePtr(ClobberInCall,
                  FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, sp)));
     }
 
     void setupVMFrame() {
         move(MacroAssembler::stackPointerRegister, Registers::ArgReg0);
     }
 
-    Call call() {
-        return JSC::MacroAssembler::call();
-    }
-
     Call call(void *fun) {
         Call cl = JSC::MacroAssembler::call();
 
         callPatches.append(CallPatch(differenceBetween(startLabel, cl), fun));
         return cl;
     }
 
     Call call(RegisterID reg) {
@@ -326,36 +316,42 @@ static const JSC::MacroAssembler::Regist
         push(Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
 #else
         /* ARM returns either using its link register (LR) or directly from the stack, but masm.ret()
          * always emits a return to LR. */
         load32(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), JSC::ARMRegisters::lr);
 #endif
     }
 
-    void saveReturnAddress(RegisterID reg)
-    {
-        storePtr(reg, Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
-    }
-
     void finalize(uint8 *ncode) {
         JSC::JITCode jc(ncode, size());
         JSC::CodeBlock cb(jc);
         JSC::RepatchBuffer repatchBuffer(&cb);
 
         for (size_t i = 0; i < callPatches.length(); i++) {
             JSC::MacroAssemblerCodePtr cp(ncode + callPatches[i].distance);
             repatchBuffer.relink(JSC::CodeLocationCall(cp), callPatches[i].fun);
         }
     }
+
+    /*
+     * Write a jump instruction at source which goes to target, clobbering any
+     * instructions already at source.  Can't use a patch/link buffer here
+     * as there is no original instruction we are setting the target for.
+     */
+#ifdef JS_CPU_X86
+    static void insertJump(uint8 *source, const uint8 *target) {
+        source[0] = 0xE9; /* JSC::X86Assembler::OP_JMP_rel32; */
+        *reinterpret_cast<int*>(source + 1) = (int) target - (int) source - 5;
+    }
+#endif
 };
 
 /* Save some typing. */
 static const JSC::MacroAssembler::RegisterID JSFrameReg = BaseAssembler::JSFrameReg;
 static const JSC::MacroAssembler::RegisterID JSReturnReg_Type = BaseAssembler::JSReturnReg_Type;
 static const JSC::MacroAssembler::RegisterID JSReturnReg_Data = BaseAssembler::JSReturnReg_Data;
-static const JSC::MacroAssembler::RegisterID JSParamReg_Argc  = BaseAssembler::JSParamReg_Argc;
 
 } /* namespace mjit */
 } /* namespace js */
 
 #endif
 
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -46,17 +46,16 @@
 #include "StubCalls.h"
 #include "MonoIC.h"
 #include "PolyIC.h"
 #include "Retcon.h"
 #include "assembler/jit/ExecutableAllocator.h"
 #include "assembler/assembler/LinkBuffer.h"
 #include "FrameState-inl.h"
 #include "jsscriptinlines.h"
-#include "InlineFrameAssembler.h"
 
 #include "jsautooplen.h"
 
 using namespace js;
 using namespace js::mjit;
 #if defined JS_POLYIC
 using namespace js::mjit::ic;
 #endif
@@ -72,17 +71,16 @@ static const char *OpcodeNames[] = {
 #endif
 
 mjit::Compiler::Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain)
   : cx(cx), script(script), scopeChain(scopeChain), globalObj(scopeChain->getGlobal()), fun(fun),
     analysis(cx, script), jumpMap(NULL), frame(cx, script, masm),
     branchPatches(ContextAllocPolicy(cx)),
 #if defined JS_MONOIC
     mics(ContextAllocPolicy(cx)),
-    callICs(ContextAllocPolicy(cx)),
 #endif
 #if defined JS_POLYIC
     pics(ContextAllocPolicy(cx)), 
 #endif
     callSites(ContextAllocPolicy(cx)), 
     doubleList(ContextAllocPolicy(cx)),
     escapingList(ContextAllocPolicy(cx)),
     stubcc(cx, *this, frame, script)
@@ -127,23 +125,16 @@ mjit::Compiler::Compile()
         jumpMap[i] = Label();
 #endif
 
 #ifdef JS_METHODJIT_SPEW
     Profiler prof;
     prof.start();
 #endif
 
-    /* Initialize PC early so stub calls in the prologue can be fallible. */
-    PC = script->code;
-
-#ifdef JS_METHODJIT
-    script->debugMode = cx->compartment->debugMode;
-#endif
-
     CHECK_STATUS(generatePrologue());
     CHECK_STATUS(generateMethod());
     CHECK_STATUS(generateEpilogue());
     CHECK_STATUS(finishThisUp());
 
 #ifdef JS_METHODJIT_SPEW
     prof.stop();
     JaegerSpew(JSpew_Prof, "compilation took %d us\n", prof.time_us());
@@ -172,118 +163,44 @@ mjit::TryCompile(JSContext *cx, JSScript
 
     CompileStatus status = cc.Compile();
     if (status != Compile_Okay)
         script->ncode = JS_UNJITTABLE_METHOD;
 
     return status;
 }
 
-JSC::MacroAssembler::RegisterID
-mjit::Compiler::takeHWReturnAddress(Assembler &masm)
+void
+mjit::Compiler::saveReturnAddress()
 {
 #ifndef JS_CPU_ARM
-    JS_STATIC_ASSERT(JSParamReg_Argc != Registers::ReturnReg);
     masm.pop(Registers::ReturnReg);
-    return Registers::ReturnReg;
+    restoreFrameRegs(masm);
+    masm.storePtr(Registers::ReturnReg, Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
 #else
-    return JSC::ARMRegisters::lr;
+    restoreFrameRegs(masm);
+    masm.storePtr(JSC::ARMRegisters::lr, Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
 #endif
 }
 
 CompileStatus
 mjit::Compiler::generatePrologue()
 {
     invokeLabel = masm.label();
 
-    RegisterID retAddr = takeHWReturnAddress(masm);
-    restoreFrameRegs(masm);
-    masm.saveReturnAddress(retAddr);
+    saveReturnAddress();
 
     /*
      * If there is no function, then this can only be called via JaegerShot(),
      * which expects an existing frame to be initialized like the interpreter.
      */
     if (fun) {
         Jump j = masm.jump();
-
-        /*
-         * Entry point #2: The caller has partially constructed a frame, and
-         * either argc >= nargs or the arity check has corrected the frame.
-         */
         invokeLabel = masm.label();
-        RegisterID retAddr = takeHWReturnAddress(masm);
-        masm.saveReturnAddress(retAddr);
-
-        Label fastPath = masm.label();
-
-        /* Store these early on so slow paths can access them. */
-        masm.storePtr(ImmPtr(script), Address(JSFrameReg, JSStackFrame::offsetScript()));
-        masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
-
-        {
-            /*
-             * Entry point #3: The caller has partially constructed a frame,
-             * but argc might be != nargs, so an arity check might be called.
-             *
-             * This loops back to entry point #2.
-             */
-            arityLabel = stubcc.masm.label();
-            RegisterID retAddr = takeHWReturnAddress(stubcc.masm);
-            stubcc.masm.saveReturnAddress(retAddr);
-            Jump argMatch = stubcc.masm.branch32(Assembler::AboveOrEqual, JSParamReg_Argc,
-                                                 Imm32(fun->nargs));
-            stubcc.crossJump(argMatch, fastPath);
-
-            /* Slow path - call the arity check function. Returns new fp. */
-            stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetFunction()));
-            stubcc.masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
-            stubcc.call(stubs::CheckArity);
-            stubcc.masm.move(Registers::ReturnReg, JSFrameReg);
-            stubcc.crossJump(stubcc.masm.jump(), fastPath);
-        }
-
-        /*
-         * Guard that there is enough stack space. Note we include the size of
-         * a second frame, to ensure we can create a frame from call sites.
-         */
-        masm.addPtr(Imm32((script->nslots + VALUES_PER_STACK_FRAME * 2) * sizeof(Value)),
-                    JSFrameReg,
-                    Registers::ReturnReg);
-        Jump stackCheck = masm.branchPtr(Assembler::AboveOrEqual, Registers::ReturnReg,
-                                         FrameAddress(offsetof(VMFrame, stackLimit)));
-
-        /* If the stack check fails... */
-        {
-            stubcc.linkExitDirect(stackCheck, stubcc.masm.label());
-            stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetFunction()));
-            stubcc.call(stubs::CheckStackQuota);
-            stubcc.crossJump(stubcc.masm.jump(), masm.label());
-        }
-
-        /* Easy frame members. Hard ones are in caller. */
-        masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetFunction()));
-        masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetCallObj()));
-        masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetArgsObj()));
-        masm.storeValue(UndefinedValue(), Address(JSFrameReg, JSStackFrame::offsetReturnValue()));
-        masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetAnnotation()));
-        masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetBlockChain()));
-        if (script->debugMode)
-            masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetHookData()));
-#ifdef DEBUG
-        masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC),
-                      Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
-#endif
-
-        /* :TODO: This is entirely wrong. */
-        masm.store32(Imm32(cx->version),
-                     Address(JSFrameReg, JSStackFrame::offsetCallerVersion()));
-
-        /* Set cx->fp */
-        masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), Registers::ReturnReg);
+        saveReturnAddress();
 
         /* Set locals to undefined. */
         for (uint32 i = 0; i < script->nfixed; i++) {
             Address local(JSFrameReg, sizeof(JSStackFrame) + i * sizeof(Value));
             masm.storeValue(UndefinedValue(), local);
         }
 
         /* Create the call object. */
@@ -334,17 +251,16 @@ mjit::Compiler::finishThisUp()
     JSC::LinkBuffer fullCode(result, totalSize);
     JSC::LinkBuffer stubCode(result + masm.size(), stubcc.size());
 
     size_t totalBytes = sizeof(JITScript) +
                         sizeof(uint32) * escapingList.length() +
                         sizeof(void *) * script->length +
 #if defined JS_MONOIC
                         sizeof(ic::MICInfo) * mics.length() +
-                        sizeof(ic::CallICInfo) * callICs.length() +
 #endif
 #if defined JS_POLYIC
                         sizeof(ic::PICInfo) * pics.length() +
 #endif
                         sizeof(CallSite) * callSites.length();
 
     uint8 *cursor = (uint8 *)cx->calloc(totalBytes);
     if (!cursor) {
@@ -379,19 +295,16 @@ mjit::Compiler::finishThisUp()
     for (size_t i = 0; i < script->length; i++) {
         Label L = jumpMap[i];
         if (analysis[i].safePoint) {
             JS_ASSERT(L.isValid());
             nmap[i] = (uint8 *)(result + masm.distanceOf(L));
         }
     }
 
-    if (fun)
-        script->jit->arityCheck = stubCode.locationOf(arityLabel).executableAddress();
-
 #if defined JS_MONOIC
     script->jit->nMICs = mics.length();
     if (mics.length()) {
         script->mics = (ic::MICInfo *)cursor;
         cursor += sizeof(ic::MICInfo) * mics.length();
     } else {
         script->mics = NULL;
     }
@@ -407,88 +320,41 @@ mjit::Compiler::finishThisUp()
             script->mics[i].stubCall = stubCode.locationOf(mics[i].call);
             script->mics[i].stubEntry = stubCode.locationOf(mics[i].stubEntry);
             script->mics[i].u.name.typeConst = mics[i].u.name.typeConst;
             script->mics[i].u.name.dataConst = mics[i].u.name.dataConst;
 #if defined JS_PUNBOX64
             script->mics[i].patchValueOffset = mics[i].patchValueOffset;
 #endif
             break;
+          case ic::MICInfo::CALL:
+            script->mics[i].frameDepth = mics[i].frameDepth;
+            script->mics[i].knownObject = fullCode.locationOf(mics[i].knownObject);
+            script->mics[i].callEnd = fullCode.locationOf(mics[i].callEnd);
+            script->mics[i].stubEntry = stubCode.locationOf(mics[i].stubEntry);
+            script->mics[i].dataReg = mics[i].dataReg;
+            script->mics[i].u.generated = false;
+            /* FALLTHROUGH */
+          case ic::MICInfo::EMPTYCALL:
+            script->mics[i].argc = mics[i].argc;
+            break;
           case ic::MICInfo::TRACER: {
             uint32 offs = uint32(mics[i].jumpTarget - script->code);
             JS_ASSERT(jumpMap[offs].isValid());
             script->mics[i].traceHint = fullCode.locationOf(mics[i].traceHint);
             script->mics[i].load = fullCode.locationOf(jumpMap[offs]);
             script->mics[i].u.hasSlowTraceHint = mics[i].slowTraceHint.isSet();
             if (mics[i].slowTraceHint.isSet())
                 script->mics[i].slowTraceHint = stubCode.locationOf(mics[i].slowTraceHint.get());
             break;
           }
           default:
             JS_NOT_REACHED("Bad MIC kind");
         }
     }
-
-    script->jit->nCallICs = callICs.length();
-    if (callICs.length()) {
-        script->callICs = (ic::CallICInfo *)cursor;
-        cursor += sizeof(ic::CallICInfo) * callICs.length();
-    } else {
-        script->callICs = NULL;
-    }
-
-    for (size_t i = 0; i < callICs.length(); i++) {
-        script->callICs[i].reset();
-        script->callICs[i].funGuard = fullCode.locationOf(callICs[i].funGuard);
-        script->callICs[i].funJump = fullCode.locationOf(callICs[i].funJump);
-        script->callICs[i].slowPathStart = stubCode.locationOf(callICs[i].slowPathStart);
-
-        /* Compute the hot call offset. */
-        uint32 offset = fullCode.locationOf(callICs[i].hotCall) -
-                        fullCode.locationOf(callICs[i].funGuard);
-        script->callICs[i].hotCallOffset = offset;
-        JS_ASSERT(script->callICs[i].hotCallOffset == offset);
-
-        /* Compute the join point offset. */
-        offset = fullCode.locationOf(callICs[i].joinPoint) -
-                 fullCode.locationOf(callICs[i].funGuard);
-        script->callICs[i].joinPointOffset = offset;
-        JS_ASSERT(script->callICs[i].joinPointOffset == offset);
-                                        
-        /* Compute the OOL call offset. */
-        offset = stubCode.locationOf(callICs[i].oolCall) -
-                 stubCode.locationOf(callICs[i].slowPathStart);
-        script->callICs[i].oolCallOffset = offset;
-        JS_ASSERT(script->callICs[i].oolCallOffset == offset);
-
-        /* Compute the OOL jump offset. */
-        offset = stubCode.locationOf(callICs[i].oolJump) -
-                 stubCode.locationOf(callICs[i].slowPathStart);
-        script->callICs[i].oolJumpOffset = offset;
-        JS_ASSERT(script->callICs[i].oolJumpOffset == offset);
-
-        /* Compute the slow join point offset. */
-        offset = stubCode.locationOf(callICs[i].slowJoinPoint) -
-                 stubCode.locationOf(callICs[i].slowPathStart);
-        script->callICs[i].slowJoinOffset = offset;
-        JS_ASSERT(script->callICs[i].slowJoinOffset == offset);
-
-        /* Compute the join point offset for continuing on the hot path. */
-        offset = stubCode.locationOf(callICs[i].hotPathLabel) -
-                 stubCode.locationOf(callICs[i].funGuard);
-        script->callICs[i].hotPathOffset = offset;
-        JS_ASSERT(script->callICs[i].hotPathOffset == offset);
-
-        script->callICs[i].argc = callICs[i].argc;
-        script->callICs[i].funObjReg = callICs[i].funObjReg;
-        script->callICs[i].funPtrReg = callICs[i].funPtrReg;
-        script->callICs[i].frameDepth = callICs[i].frameDepth;
-        script->callICs[i].isConstantThis = callICs[i].isConstantThis;
-        script->callICs[i].constantThis  = callICs[i].constantThis;
-    }
 #endif /* JS_MONOIC */
 
 #if defined JS_POLYIC
     script->jit->nPICs = pics.length();
     if (pics.length()) {
         script->pics = (ic::PICInfo *)cursor;
         cursor += sizeof(ic::PICInfo) * pics.length();
     } else {
@@ -566,16 +432,20 @@ mjit::Compiler::finishThisUp()
         }
         script->jit->callSites = callSiteList;
     } else {
         script->jit->callSites = NULL;
     }
 
     JS_ASSERT(size_t(cursor - (uint8*)script->jit) == totalBytes);
 
+#ifdef JS_METHODJIT
+    script->debugMode = cx->compartment->debugMode;
+#endif
+
     return Compile_Okay;
 }
 
 #ifdef DEBUG
 #define SPEW_OPCODE()                                                         \
     JS_BEGIN_MACRO                                                            \
         if (IsJaegerSpewChannelActive(JSpew_JSOps)) {                         \
             JaegerSpew(JSpew_JSOps, "    %2d ", frame.stackDepth());          \
@@ -593,16 +463,17 @@ mjit::Compiler::finishThisUp()
         PC += name##_LENGTH;                \
     JS_END_MACRO;                           \
     break;
 
 CompileStatus
 mjit::Compiler::generateMethod()
 {
     mjit::AutoScriptRetrapper trapper(cx, script);
+    PC = script->code;
 
     for (;;) {
         JSOp op = JSOp(*PC);
 
         OpcodeStatus &opinfo = analysis[PC];
         frame.setInTryBlock(opinfo.inTryBlock);
         if (opinfo.nincoming || opinfo.trap) {
             frame.syncAndForgetEverything(opinfo.stackDepth);
@@ -1852,268 +1723,193 @@ mjit::Compiler::interruptCheckHelper()
     stubcc.leave();
     stubcc.masm.move(ImmPtr(PC), Registers::ArgReg1);
     stubcc.call(stubs::Interrupt);
     ADD_CALLSITE(true);
     stubcc.rejoin(Changes(0));
 }
 
 void
-mjit::Compiler::emitPrimitiveTestForNew(uint32 argc)
-{
-    Jump primitive = masm.testPrimitive(Assembler::Equal, JSReturnReg_Type);
-    stubcc.linkExitDirect(primitive, stubcc.masm.label());
-    FrameEntry *fe = frame.peek(-int(argc + 1));
-    Address thisv(frame.addressOf(fe));
-    stubcc.masm.loadTypeTag(thisv, JSReturnReg_Type);
-    stubcc.masm.loadPayload(thisv, JSReturnReg_Data);
-    Jump primFix = stubcc.masm.jump();
-    stubcc.crossJump(primFix, masm.label());
-}
-
-void
-mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
+mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
 {
-    RegisterID r0 = Registers::ReturnReg;
-    VoidPtrStubUInt32 stub = callingNew ? stubs::UncachedNew : stubs::UncachedCall;
-
+    /* Check for interrupts on function call */
+    interruptCheckHelper();
+
+    FrameEntry *fe = frame.peek(-int(argc + 2));
+    bool typeKnown = fe->isTypeKnown();
+
+    if (typeKnown && fe->getKnownType() != JSVAL_TYPE_OBJECT) {
+#ifdef JS_MONOIC
+        /*
+         * Make an otherwise empty MIC to hold the argument count.
+         * This can't be a fast native so the rest of the MIC won't be used.
+         */
+        MICGenInfo mic(ic::MICInfo::EMPTYCALL);
+        mic.entry = masm.label();
+        mic.argc = argc;
+        mics.append(mic);
+#endif
+
+        prepareStubCall(Uses(argc + 2));
+        VoidPtrStubUInt32 stub = callingNew ? stubs::SlowNew : stubs::SlowCall;
+#ifdef JS_MONOIC
+        masm.move(Imm32(mics.length() - 1), Registers::ArgReg1);
+#else
+        masm.move(Imm32(argc), Registers::ArgReg1);
+#endif
+        masm.stubCall(stub, PC, frame.stackDepth() + script->nfixed);
+        ADD_CALLSITE(false);
+        frame.popn(argc + 2);
+        frame.pushSynced();
+        return;
+    }
+
+#ifdef JS_MONOIC
+    MICGenInfo mic(ic::MICInfo::CALL);
+    mic.entry = masm.label();
+    mic.argc = argc;
+    mic.frameDepth = frame.frameDepth() - argc - 2;
+#endif
+
+    MaybeRegisterID typeReg;
+    RegisterID data = frame.tempRegForData(fe);
+    frame.pinReg(data);
+
+    Address addr = frame.addressOf(fe);
+
+    if (!typeKnown) {
+        if (!frame.shouldAvoidTypeRemat(fe)) {
+            typeReg = frame.tempRegForType(fe);
+            frame.pinReg(typeReg.reg());
+        }
+    }
+
+    /*
+     * We rely on the fact that syncAndKill() is not allowed to touch the
+     * registers we've preserved.
+     */
     frame.syncAndKill(Registers(Registers::AvailRegs), Uses(argc + 2));
-    prepareStubCall(Uses(argc + 2));
+    frame.unpinKilledReg(data);
+    if (typeReg.isSet())
+        frame.unpinKilledReg(typeReg.reg());
+
+    Label invoke = stubcc.masm.label();
+
+#ifdef JS_MONOIC
+    mic.stubEntry = invoke;
+    mic.dataReg = data;
+#endif
+
+    Jump j;
+    if (!typeKnown) {
+        if (!typeReg.isSet())
+            j = masm.testObject(Assembler::NotEqual, frame.addressOf(fe));
+        else
+            j = masm.testObject(Assembler::NotEqual, typeReg.reg());
+        stubcc.linkExit(j, Uses(argc + 2));
+    }
+
+#ifdef JS_MONOIC
+    mic.knownObject = masm.label();
+#endif
+
+    j = masm.testFunction(Assembler::NotEqual, data);
+    stubcc.linkExit(j, Uses(argc + 2));
+    stubcc.leave();
+#ifdef JS_MONOIC
+    stubcc.masm.move(Imm32(mics.length()), Registers::ArgReg1);
+#else
+    stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
+#endif
+    stubcc.call(callingNew ? stubs::SlowNew : stubs::SlowCall);
+    ADD_CALLSITE(true);
+
+    /* Get function private pointer. */
+    masm.loadFunctionPrivate(data, data);
+
+    frame.takeReg(data);
+    RegisterID t0 = frame.allocReg();
+    RegisterID t1 = frame.allocReg();
+
+    /* Test if the function is interpreted, and if not, take a slow path. */
+    {
+        masm.load16(Address(data, offsetof(JSFunction, flags)), t0);
+        masm.move(t0, t1);
+        masm.and32(Imm32(JSFUN_KINDMASK), t1);
+        Jump notInterp = masm.branch32(Assembler::Below, t1, Imm32(JSFUN_INTERPRETED));
+        stubcc.linkExitDirect(notInterp, invoke);
+    }
+
+    /* Test if it's not got compiled code. */
+    Address scriptAddr(data, offsetof(JSFunction, u) + offsetof(JSFunction::U::Scripted, script));
+    masm.loadPtr(scriptAddr, data);
+    Jump notCompiled = masm.branchPtr(Assembler::BelowOrEqual,
+                                      Address(data, offsetof(JSScript, ncode)),
+                                      ImmIntPtr(1));
+    {
+        stubcc.linkExitDirect(notCompiled, invoke);
+    }
+
+    frame.freeReg(t0);
+    frame.freeReg(t1);
+    frame.freeReg(data);
+
+    /* Scripted call. */
     masm.move(Imm32(argc), Registers::ArgReg1);
-    stubCall(stub);
+    masm.stubCall(callingNew ? stubs::New : stubs::Call,
+                  PC, frame.stackDepth() + script->nfixed);
+
+    Jump invokeCallDone;
+    {
+        /*
+         * Stub call returns a pointer to JIT'd code, or NULL.
+         *
+         * If the function could not be JIT'd, it was already invoked using
+         * js_Interpret() or js_Invoke(). In that case, the stack frame has
+         * already been popped. We don't have to do any extra work.
+         */
+        Jump j = stubcc.masm.branchTestPtr(Assembler::NonZero, Registers::ReturnReg, Registers::ReturnReg);
+        stubcc.crossJump(j, masm.label());
+        if (callingNew)
+            invokeCallDone = stubcc.masm.jump();
+    }
+
+    /* Fast-path: return address contains scripted call. */
+    masm.call(Registers::ReturnReg);
+#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
+    masm.callLabel = masm.label();
+#endif
     ADD_CALLSITE(false);
 
-    Jump notCompiled = masm.branchTestPtr(Assembler::Zero, r0, r0);
-    stubcc.linkExitDirect(notCompiled, stubcc.masm.label());
-
-    masm.call(r0);
-    ADD_CALLSITE(false);
-
-    if (callingNew)
-        emitPrimitiveTestForNew(argc);
+    /*
+     * Functions invoked with |new| can return, for some reason, primitive
+     * values. Just deal with this here.
+     */
+    if (callingNew) {
+        Jump primitive = masm.testPrimitive(Assembler::Equal, JSReturnReg_Type);
+        stubcc.linkExitDirect(primitive, stubcc.masm.label());
+        FrameEntry *fe = frame.peek(-int(argc + 1));
+        Address thisv(frame.addressOf(fe));
+        stubcc.masm.loadTypeTag(thisv, JSReturnReg_Type);
+        stubcc.masm.loadPayload(thisv, JSReturnReg_Data);
+        Jump primFix = stubcc.masm.jump();
+        stubcc.crossJump(primFix, masm.label());
+        invokeCallDone.linkTo(stubcc.masm.label(), &stubcc.masm);
+    }
 
     frame.popn(argc + 2);
     frame.takeReg(JSReturnReg_Type);
     frame.takeReg(JSReturnReg_Data);
     frame.pushRegs(JSReturnReg_Type, JSReturnReg_Data);
 
     stubcc.rejoin(Changes(0));
-}
-
-/* See MonoIC.cpp, CallCompiler for more information on call ICs. */
-void
-mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
-{
-    /* Check for interrupts on function call */
-    interruptCheckHelper();
-
-    FrameEntry *fe = frame.peek(-int(argc + 2));
-
-    /* Currently, we don't support constant functions. */
-    if (fe->isNotType(JSVAL_TYPE_OBJECT) || script->debugMode || fe->isConstant()) {
-        emitUncachedCall(argc, callingNew);
-        return;
-    }
 
 #ifdef JS_MONOIC
-    FrameEntry *thisvFe = frame.peek(-int(argc + 1));
-    Address thisvAddr = frame.addressOf(thisvFe);
-
-    CallGenInfo callIC(argc);
-    uint32 callICIndex = callICs.length();
-
-    /*
-     * Save constant |this| to optimize thisv stores for common call cases
-     * like CALL[LOCAL, GLOBAL, ARG] which push NULL.
-     */
-    callIC.isConstantThis = false;
-    if (thisvFe->isConstant()) {
-        callIC.isConstantThis = true;
-        callIC.constantThis = thisvFe->getValue();
-    }
-    callIC.frameDepth = frame.frameDepth();
-
-    /* Grab type and data registers up-front. */
-    MaybeRegisterID typeReg;
-    frame.ensureFullRegs(fe);
-
-    if (!fe->isTypeKnown()) {
-        typeReg = frame.tempRegForType(fe);
-        frame.pinReg(typeReg.reg());
-    }
-    RegisterID dataReg = frame.tempRegForData(fe);
-    frame.pinReg(dataReg);
-
-    /*
-     * We rely on the fact that syncAndKill() is not allowed to touch the
-     * registers we've preserved.
-     */
-    frame.syncAndKill(Registers(Registers::AvailRegs), Uses(argc + 2));
-    frame.unpinKilledReg(dataReg);
-    if (typeReg.isSet())
-        frame.unpinKilledReg(typeReg.reg());
-
-    Registers tempRegs;
-
-    /* Test the type if necessary. Failing this always takes a really slow path. */
-    MaybeJump notObjectJump;
-    if (typeReg.isSet())
-        notObjectJump = masm.testObject(Assembler::NotEqual, typeReg.reg());
-
-    /*
-     * Ensure that dataReg stays in a register which won't be clobbered
-     * by the intervening call to NewObject.
-     */
-    if (callingNew && !(Registers::maskReg(dataReg) & Registers::SavedRegs)) {
-        RegisterID reg = Registers(Registers::SavedRegs).takeAnyReg();
-        masm.move(dataReg, reg);
-        dataReg = reg;
-    }
-
-    tempRegs.takeReg(dataReg);
-    RegisterID t0 = tempRegs.takeAnyReg();
-    RegisterID t1 = tempRegs.takeAnyReg();
-
-    /*
-     * Guard on the callee identity. This misses on the first run. If the
-     * callee is scripted, compiled/compilable, and argc == nargs, then this
-     * guard is patched, and the compiled code address is baked in.
-     */
-    Jump j = masm.branchPtrWithPatch(Assembler::NotEqual, dataReg, callIC.funGuard);
-    callIC.funJump = j;
-
-    Jump oolCallDone;
-    Jump rejoin1, rejoin2;
-    {
-        stubcc.linkExitDirect(j, stubcc.masm.label());
-        callIC.slowPathStart = stubcc.masm.label();
-
-        /*
-         * Test if the callee is even a function. If this doesn't match, we
-         * take a _really_ slow path later.
-         */
-        Jump notFunction = stubcc.masm.testFunction(Assembler::NotEqual, dataReg);
-
-        /* Test if the function is scripted. */
-        stubcc.masm.loadFunctionPrivate(dataReg, t0);
-        stubcc.masm.load16(Address(t0, offsetof(JSFunction, flags)), t1);
-        stubcc.masm.and32(Imm32(JSFUN_KINDMASK), t1);
-        Jump isNative = stubcc.masm.branch32(Assembler::Below, t1, Imm32(JSFUN_INTERPRETED));
-
-        /* Create the new object. This requires some fiddling to save the two values. */
-        if (callingNew) {
-            void *pfun = stubcc.masm.getCallTarget(JS_FUNC_TO_DATA_PTR(void *, stubs::NewObject));
-            stubcc.masm.storePtr(ImmPtr(PC),
-                             FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, pc)));
-            stubcc.masm.fixScriptStack(frame.frameDepth());
-            stubcc.masm.setupVMFrame();
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
-            /* Need to stay 16-byte aligned on x86/x64. */
-            stubcc.masm.subPtr(Imm32(8), JSC::MacroAssembler::stackPointerRegister);
-#endif
-
-            stubcc.masm.push(dataReg);
-            stubcc.masm.push(t0);
-            stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
-            stubcc.masm.wrapCall(pfun);
-            stubcc.masm.pop(t0);
-            stubcc.masm.pop(dataReg);
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
-            stubcc.masm.addPtr(Imm32(8), JSC::MacroAssembler::stackPointerRegister);
-#endif
-        }
-
-        /*
-         * No-op jump that gets re-patched. This is so ArgReg1 won't be
-         * clobbered, with the added bonus that the generated stub doesn't
-         * need to pop its own return address.
-         */
-        Jump toPatch = stubcc.masm.jump();
-        toPatch.linkTo(stubcc.masm.label(), &stubcc.masm);
-        callIC.oolJump = toPatch;
-
-        /* At this point the function is definitely scripted. Call the link routine. */
-        stubcc.masm.move(Imm32(callICIndex), Registers::ArgReg1);
-        callIC.oolCall = stubcc.call(callingNew ? ic::New : ic::Call);
-
-        callIC.funObjReg = dataReg;
-        callIC.funPtrReg = t0;
-
-        /*
-         * The IC call either returns NULL, meaning call completed, or a
-         * function pointer to jump to. Caveat: Must restore JSFrameReg
-         * because a new frame has been pushed.
-         *
-         * This function only executes once. If hit, it will generate a stub
-         * to compile and execute calls on demand.
-         */
-        rejoin1 = stubcc.masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
-                                            Registers::ReturnReg);
-        stubcc.masm.move(Imm32(argc), JSParamReg_Argc);
-        stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
-        stubcc.masm.call(Registers::ReturnReg);
-        oolCallDone = stubcc.masm.jump();
-
-        /* Catch-all case, for natives this will turn into a MIC. */
-        if (notObjectJump.isSet())
-            stubcc.linkExitDirect(notObjectJump.get(), stubcc.masm.label());
-        notFunction.linkTo(stubcc.masm.label(), &stubcc.masm);
-        isNative.linkTo(stubcc.masm.label(), &stubcc.masm);
-
-        stubcc.masm.move(Imm32(callICIndex), Registers::ArgReg1);
-        stubcc.call(callingNew ? ic::NativeNew : ic::NativeCall);
-
-        rejoin2 = stubcc.masm.jump();
-    }
-
-    /*
-     * If the call site goes to a closure over the same function, it will
-     * generate an out-of-line stub that joins back here.
-     */
-    callIC.hotPathLabel = masm.label();
-
-    /* If calling |new|, make sure to allocate a new object. */
-    if (callingNew) {
-        prepareStubCall(Uses(argc + 2));
-        masm.move(Imm32(argc), Registers::ArgReg1);
-        stubCall(stubs::NewObject);
-    }
-
-    uint32 flags = 0;
-    if (callingNew)
-        flags |= JSFRAME_CONSTRUCTING;
-
-    InlineFrameAssembler inlFrame(masm, callIC, PC, flags);
-    inlFrame.assemble();
-
-    callIC.hotCall = masm.call();
-    stubcc.crossJump(oolCallDone, masm.label());
-
-    callIC.joinPoint = masm.label();
-
-    /*
-     * Functions invoked with |new| can return primitive values.
-     * Just deal with this here.
-     */
-    if (callingNew)
-        emitPrimitiveTestForNew(argc);
-
-    frame.popn(argc + 2);
-    frame.takeReg(JSReturnReg_Type);
-    frame.takeReg(JSReturnReg_Data);
-    frame.pushRegs(JSReturnReg_Type, JSReturnReg_Data);
-
-    callIC.slowJoinPoint = stubcc.masm.label();
-    rejoin1.linkTo(callIC.slowJoinPoint, &stubcc.masm);
-    rejoin2.linkTo(callIC.slowJoinPoint, &stubcc.masm);
-    stubcc.rejoin(Changes(0));
-
-    callICs.append(callIC);
-#else
-    emitUncachedCall(argc, callingNew);
+    mic.callEnd = masm.label();
+    mics.append(mic);
 #endif
 }
 
 /*
  * This function must be called immediately after any instruction which could
  * cause a new JSStackFrame to be pushed and could lead to a new debug trap
  * being set. This includes any API callbacks and any scripted or native call.
  */
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -85,58 +85,33 @@ class Compiler
         DataLabel32 shape;
 #if defined JS_PUNBOX64
         uint32 patchValueOffset;
 #endif
         Label load;
         Call call;
         ic::MICInfo::Kind kind;
         jsbytecode *jumpTarget;
+        uint32 argc;
+        uint32 frameDepth;
+        Label knownObject;
+        Label callEnd;
+        JSC::MacroAssembler::RegisterID dataReg;
         Jump traceHint;
         MaybeJump slowTraceHint;
         union {
             struct {
                 bool typeConst;
                 bool dataConst;
             } name;
             struct {
                 uint32 pcOffs;
             } tracer;
         } u;
     };
-
-    /* InlineFrameAssembler wants to see this. */
-  public:
-    struct CallGenInfo {
-        CallGenInfo(uint32 argc)
-          : argc(argc), constantThis(UndefinedValue())
-        { }
-
-        /*
-         * These members map to members in CallICInfo. See that structure for
-         * more comments.
-         */
-        uint32       argc;
-        DataLabelPtr funGuard;
-        Jump         funJump;
-        Call         hotCall;
-        Call         oolCall;
-        Label        joinPoint;
-        Label        slowJoinPoint;
-        Label        slowPathStart;
-        Label        hotPathLabel;
-        Jump         oolJump;
-        RegisterID   funObjReg;
-        RegisterID   funPtrReg;
-        uint32       frameDepth;
-        bool         isConstantThis;
-        Value        constantThis;
-    };
-
-  private:
 #endif
 
 #if defined JS_POLYIC
     struct PICGenInfo {
         PICGenInfo(ic::PICInfo::Kind kind) : kind(kind)
         { }
         ic::PICInfo::Kind kind;
         Label fastPathStart;
@@ -204,27 +179,25 @@ class Compiler
     BytecodeAnalyzer analysis;
     Label *jumpMap;
     jsbytecode *PC;
     Assembler masm;
     FrameState frame;
     js::Vector<BranchPatch, 64> branchPatches;
 #if defined JS_MONOIC
     js::Vector<MICGenInfo, 64> mics;
-    js::Vector<CallGenInfo, 64> callICs;
 #endif
 #if defined JS_POLYIC
     js::Vector<PICGenInfo, 64> pics;
 #endif
     js::Vector<InternalCallSite, 64> callSites;
     js::Vector<DoublePatch, 16> doubleList;
     js::Vector<uint32, 16> escapingList;
     StubCompiler stubcc;
     Label invokeLabel;
-    Label arityLabel;
     bool addTraceHints;
 
   public:
     // Special atom index used to indicate that the atom is 'length'. This
     // follows interpreter usage in JSOP_LENGTH.
     enum { LengthAtomIndex = uint32(-2) };
 
     Compiler(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain);
@@ -247,17 +220,17 @@ class Compiler
     /* Non-emitting helpers. */
     uint32 fullAtomIndex(jsbytecode *pc);
     void jumpInScript(Jump j, jsbytecode *pc);
     JSC::ExecutablePool *getExecPool(size_t size);
     bool compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs);
     void addCallSite(uint32 id, bool stub);
 
     /* Emitting helpers. */
-    RegisterID takeHWReturnAddress(Assembler &masm);
+    void saveReturnAddress();
     void restoreReturnAddress(Assembler &masm);
     void restoreFrameRegs(Assembler &masm);
     void emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
     void iter(uintN flags);
     void iterNext();
     void iterMore();
     void iterEnd();
     MaybeJump loadDouble(FrameEntry *fe, FPRegisterID fpReg);
@@ -268,18 +241,16 @@ class Compiler
     void jsop_setglobal(uint32 index);
     void jsop_getglobal(uint32 index);
     void jsop_getprop_slow();
     void jsop_getarg(uint32 index);
     void jsop_this();
     void emitReturn();
     void dispatchCall(VoidPtrStubUInt32 stub, uint32 argc);
     void interruptCheckHelper();
-    void emitUncachedCall(uint32 argc, bool callingNew);
-    void emitPrimitiveTestForNew(uint32 argc);
     void inlineCallHelper(uint32 argc, bool callingNew);
     void jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index);
     void jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index);
     void jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index);
     void jsop_eleminc(JSOp op, VoidStub);
     void jsop_getgname(uint32 index);
     void jsop_getgname_slow(uint32 index);
     void jsop_setgname(uint32 index);
@@ -377,17 +348,16 @@ class Compiler
     STUB_CALL_TYPE(JSObjStubJSObj);
     STUB_CALL_TYPE(VoidStubAtom);
     STUB_CALL_TYPE(JSStrStub);
     STUB_CALL_TYPE(JSStrStubUInt32);
     STUB_CALL_TYPE(VoidStubJSObj);
     STUB_CALL_TYPE(VoidPtrStubPC);
     STUB_CALL_TYPE(VoidVpStub);
     STUB_CALL_TYPE(VoidStubPC);
-    STUB_CALL_TYPE(BoolStubUInt32);
 
 #undef STUB_CALL_TYPE
     void prepareStubCall(Uses uses);
     Call stubCall(void *ptr);
 };
 
 } /* namespace js */
 } /* namespace mjit */
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -1216,44 +1216,16 @@ FrameState::allocForSameBinary(FrameEntr
         alloc.lhsNeedsRemat = true;
     }
 
     if (alloc.lhsType.isSet())
         unpinReg(alloc.lhsType.reg());
 }
 
 void
-FrameState::ensureFullRegs(FrameEntry *fe)
-{
-    FrameEntry *backing = fe;
-    if (fe->isCopy())
-        backing = fe->copyOf();
-
-    if (!fe->type.inMemory()) {
-        if (fe->data.inRegister())
-            return;
-        if (fe->type.inRegister())
-            pinReg(fe->type.reg());
-        if (fe->data.inMemory())
-            tempRegForData(fe);
-        if (fe->type.inRegister())
-            unpinReg(fe->type.reg());
-    } else if (!fe->data.inMemory()) {
-        if (fe->type.inRegister())
-            return;
-        if (fe->data.inRegister())
-            pinReg(fe->data.reg());
-        if (fe->type.inMemory())
-            tempRegForType(fe);
-        if (fe->data.inRegister())
-            unpinReg(fe->data.reg());
-    }
-}
-
-void
 FrameState::allocForBinary(FrameEntry *lhs, FrameEntry *rhs, JSOp op, BinaryAlloc &alloc,
                            bool needsResult)
 {
     FrameEntry *backingLeft = lhs;
     FrameEntry *backingRight = rhs;
 
     if (backingLeft->isCopy())
         backingLeft = backingLeft->copyOf();
--- a/js/src/methodjit/FrameState.h
+++ b/js/src/methodjit/FrameState.h
@@ -494,19 +494,16 @@ class FrameState
      *
      * One mutable register is allocated as well, holding the LHS payload. If
      * this would cause a spill that could be avoided by using a mutable RHS,
      * and the operation is commutative, then the resultHasRhs is set to true.
      */
     void allocForBinary(FrameEntry *lhs, FrameEntry *rhs, JSOp op, BinaryAlloc &alloc,
                         bool resultNeeded = true);
 
-    /* Ensures that an FE has both type and data remat'd in registers. */
-    void ensureFullRegs(FrameEntry *fe);
-
     /*
      * Similar to allocForBinary, except works when the LHS and RHS have the
      * same backing FE. Only a reduced subset of BinaryAlloc is used:
      *   lhsType
      *   lhsData
      *   result
      *   lhsNeedsRemat
      */
deleted file mode 100644
--- a/js/src/methodjit/InlineFrameAssembler.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=4 sw=4 et tw=99:
- *
- * ***** 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 Mozilla SpiderMonkey JavaScript 1.9 code, released
- * May 28, 2008.
- *
- * The Initial Developer of the Original Code is
- *   Brendan Eich <brendan@mozilla.org>
- *
- * Contributor(s):
- *   David Anderson <danderson@mozilla.com>
- *
- * 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 ***** */
-
-#if !defined jsjaeger_inl_frame_asm_h__ && defined JS_METHODJIT && defined JS_MONOIC
-#define jsjaeger_inl_frame_asm_h__
-
-#include "assembler/assembler/MacroAssembler.h"
-#include "assembler/assembler/CodeLocation.h"
-#include "methodjit/MethodJIT.h"
-#include "CodeGenIncludes.h"
-
-namespace js {
-namespace mjit {
-
-/*
- * This is used for emitting code to inline callee-side frame creation.
- * Specifically, it initializes the following members:
- *
- *  savedPC
- *  argc
- *  flags
- *  scopeChain
- *  argv
- *  thisv
- *  down
- *
- * Once finished, JSFrameReg is advanced to be the new fp.
- */
-class InlineFrameAssembler {
-    typedef JSC::MacroAssembler::RegisterID RegisterID;
-    typedef JSC::MacroAssembler::Address Address;
-    typedef JSC::MacroAssembler::Imm32 Imm32;
-    typedef JSC::MacroAssembler::ImmPtr ImmPtr;
-
-    Assembler &masm;
-    bool       isConstantThis;  // Is |thisv| constant?
-    Value      constantThis;    // If so, this is the value.
-    uint32     frameDepth;      // script->nfixed + stack depth at caller call site
-    uint32     argc;            // number of args being passed to the function
-    RegisterID funObjReg;       // register containing the function object (callee)
-    jsbytecode *pc;             // bytecode location at the caller call site
-    uint32     flags;           // frame flags
-
-  public:
-    /*
-     * Register state, so consumers of this class can restrict which registers
-     * can and can't be clobbered.
-     */
-    Registers  tempRegs;
-
-    InlineFrameAssembler(Assembler &masm, JSContext *cx, ic::CallICInfo &ic, uint32 flags)
-      : masm(masm), flags(flags)
-    {
-        isConstantThis = ic.isConstantThis;
-        constantThis = ic.constantThis;
-        frameDepth = ic.frameDepth;
-        argc = ic.argc;
-        funObjReg = ic.funObjReg;
-        pc = cx->regs->pc;
-        tempRegs.takeReg(ic.funPtrReg);
-        tempRegs.takeReg(funObjReg);
-    }
-
-    InlineFrameAssembler(Assembler &masm, Compiler::CallGenInfo &gen, jsbytecode *pc, uint32 flags)
-      : masm(masm), pc(pc), flags(flags)
-    {
-        isConstantThis = gen.isConstantThis;
-        constantThis = gen.constantThis;
-        frameDepth = gen.frameDepth;
-        argc = gen.argc;
-        funObjReg = gen.funObjReg;
-        tempRegs.takeReg(funObjReg);
-    }
-
-    struct AdjustedFrame {
-        inline AdjustedFrame(uint32 baseOffset)
-         : baseOffset(baseOffset)
-        { }
-
-        uint32 baseOffset;
-
-        inline Address addrOf(uint32 offset) {
-            return Address(JSFrameReg, baseOffset + offset);
-        }
-    };
-
-    inline void assemble()
-    {
-        RegisterID t0 = tempRegs.takeAnyReg();
-
-        /* Note: savedPC goes into the down frame. */
-        masm.storePtr(ImmPtr(pc), Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
-
-        AdjustedFrame adj(sizeof(JSStackFrame) + frameDepth * sizeof(Value));
-        masm.store32(Imm32(argc), adj.addrOf(offsetof(JSStackFrame, argc)));
-        masm.store32(Imm32(flags), adj.addrOf(offsetof(JSStackFrame, flags)));
-        masm.loadPtr(Address(funObjReg, offsetof(JSObject, parent)), t0);
-        masm.storePtr(t0, adj.addrOf(JSStackFrame::offsetScopeChain()));
-        masm.addPtr(Imm32(adj.baseOffset - (argc * sizeof(Value))), JSFrameReg, t0);
-        masm.storePtr(t0, adj.addrOf(offsetof(JSStackFrame, argv)));
-
-        Address targetThis = adj.addrOf(JSStackFrame::offsetThisValue());
-        if (isConstantThis) {
-            masm.storeValue(constantThis, targetThis);
-        } else {
-            Address thisvAddr = Address(t0, -int32(sizeof(Value) * 1));
-#ifdef JS_NUNBOX32
-            RegisterID t1 = tempRegs.takeAnyReg();
-            masm.loadPayload(thisvAddr, t1);
-            masm.storePayload(t1, targetThis);
-            masm.loadTypeTag(thisvAddr, t1);
-            masm.storeTypeTag(t1, targetThis);
-            tempRegs.putReg(t1);
-#elif JS_PUNBOX64
-            masm.loadPtr(thisvAddr, t0);
-            masm.storePtr(t0, targetThis);
-#endif
-        }
-
-        masm.storePtr(JSFrameReg, adj.addrOf(offsetof(JSStackFrame, down)));
-
-        /* Adjust JSFrameReg. Callee fills in the rest. */
-        masm.addPtr(Imm32(sizeof(JSStackFrame) + sizeof(Value) * frameDepth), JSFrameReg);
-
-        tempRegs.putReg(t0);
-    }
-};
-
-
-} /* namespace mjit */
-} /* namespace js */
-
-#endif /* jsjaeger_inl_frame_asm_h__ */
-
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -176,256 +176,24 @@ top:
                 }
             }
         }
     }
 
     return NULL;
 }
 
-static bool
-InlineReturn(VMFrame &f, JSBool ok)
-{
-    JSContext *cx = f.cx;
-    JSStackFrame *fp = f.regs.fp;
-
-    JS_ASSERT(f.fp() != f.entryFp);
-
-    JS_ASSERT(!fp->hasBlockChain());
-    JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->getScopeChain(), 0));
-
-    // Marker for debug support.
-    if (JS_UNLIKELY(fp->hasHookData())) {
-        JSInterpreterHook hook;
-        JSBool status;
-
-        hook = cx->debugHooks->callHook;
-        if (hook) {
-            /*
-             * Do not pass &ok directly as exposing the address inhibits
-             * optimizations and uninitialised warnings.
-             */
-            status = ok;
-            hook(cx, fp, JS_FALSE, &status, fp->getHookData());
-            ok = (status == JS_TRUE);
-            // CHECK_INTERRUPT_HANDLER();
-        }
-    }
-
-    fp->putActivationObjects(cx);
-
-    /* :TODO: version stuff */
-
-    if (fp->flags & JSFRAME_CONSTRUCTING && fp->getReturnValue().isPrimitive())
-        fp->setReturnValue(fp->getThisValue());
-
-    Value *newsp = fp->argv - 1;
-
-    cx->stack().popInlineFrame(cx, fp, fp->down);
-
-    cx->regs->sp = newsp;
-    cx->regs->sp[-1] = fp->getReturnValue();
-
-    JS_ASSERT(cx->regs->pc != JSStackFrame::sInvalidPC);
-
-    return ok;
-}
-
-JSBool JS_FASTCALL
-stubs::NewObject(VMFrame &f, uint32 argc)
+static inline void
+FixVMFrame(VMFrame &f, JSStackFrame *fp)
 {
-    JSContext *cx = f.cx;
-    Value *vp = f.regs.sp - (argc + 2);
-
-    JSObject *funobj = &vp[0].toObject();
-    JS_ASSERT(funobj->isFunction());
-
-    jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
-    if (!funobj->getProperty(cx, id, &vp[1]))
-        THROWV(JS_FALSE);
-
-    JSObject *proto = vp[1].isObject() ? &vp[1].toObject() : NULL;
-    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, funobj->getParent());
-    if (!obj)
-        THROWV(JS_FALSE);
-
-    vp[1].setObject(*obj);
-
-    return JS_TRUE;
-}
-
-void JS_FASTCALL
-stubs::SlowCall(VMFrame &f, uint32 argc)
-{
-    Value *vp = f.regs.sp - (argc + 2);
-
-    if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0))
-        THROW();
-}
-
-void JS_FASTCALL
-stubs::SlowNew(VMFrame &f, uint32 argc)
-{
-    JSContext *cx = f.cx;
-    Value *vp = f.regs.sp - (argc + 2);
-
-    if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
-        THROW();
-}
-
-static inline void
-RemovePartialFrame(VMFrame &f)
-{
-    /* Unwind the half-pushed frame. */
-    f.regs.pc = f.fp()->down->savedPC;
-    f.regs.sp = f.fp()->argv + f.fp()->argc;
-#ifdef DEBUG
-    f.fp()->down->savedPC = JSStackFrame::sInvalidPC;
-#endif
-    f.regs.fp = f.fp()->down;
-}
-
-void JS_FASTCALL
-stubs::CheckStackQuota(VMFrame &f)
-{
-    if (JS_LIKELY(f.ensureSpace(0, f.fp()->getScript()->nslots)))
-        return;
-
-    RemovePartialFrame(f);
-
-    js_ReportOverRecursed(f.cx);
-    THROW();
+    JS_ASSERT(f.fp() == fp->down);
+    f.fp() = fp;
 }
 
-void * JS_FASTCALL
-stubs::CheckArity(VMFrame &f)
-{
-    JSContext *cx = f.cx;
-    JSStackFrame *fp = f.fp();
-    uint32 argc = fp->argc;
-    JSFunction *fun = fp->getFunction();
-
-    JS_ASSERT(argc < fun->nargs);
-
-    /*
-     * Grossssss! *move* the stack frame. If this ends up being perf-critical,
-     * we can figure out how to spot-optimize it. As the frame shrinks it will
-     * matter less.
-     */
-    uint32 flags = fp->flags;
-    JSObject *scopeChain = fp->getScopeChain();
-    Value *argv = fp->argv;
-    JSStackFrame *down = fp->down;
-    void *ncode = fp->ncode;
-
-    /* Pop the inline frame. */
-    RemovePartialFrame(f);
-
-    uint32 missing = fun->nargs - argc;
-
-    /* Include an extra stack frame for callees. */
-    if (!f.ensureSpace(missing, fun->u.i.script->nslots + VALUES_PER_STACK_FRAME)) {
-        js_ReportOverRecursed(cx);
-        THROWV(NULL);
-    }
-
-#ifdef DEBUG
-    down->savedPC = f.regs.pc;
-#endif
-
-    SetValueRangeToUndefined(f.regs.sp, missing);
-    f.regs.sp += missing;
-
-    JSStackFrame *newfp = (JSStackFrame *)f.regs.sp;
-    newfp->argc = argc;
-    newfp->setFunction(fun);
-    newfp->flags = flags;
-    newfp->argv = argv;
-    newfp->setScopeChain(scopeChain);
-    newfp->down = down;
-    newfp->ncode = ncode;
-    newfp->setThisValue(argv[-1]);
-
-    return newfp;
-}
-
-void * JS_FASTCALL
-stubs::CompileFunction(VMFrame &f)
-{
-    /*
-     * We have a partially constructed frame. That's not really good enough to
-     * compile though because we could throw, so get a full, adjusted frame.
-     */
-    JSContext *cx = f.cx;
-    JSStackFrame *fp = f.fp();
-    uint32 argc = fp->argc;
-
-    JSObject *obj = &fp->argv[-2].toObject();
-    JSFunction *fun = obj->getFunctionPrivate();
-    JSScript *script = fun->u.i.script;
-
-    bool callingNew = !!(fp->flags & JSFRAME_CONSTRUCTING);
-
-    /* Empty script does nothing. */
-    if (script->isEmpty()) {
-        RemovePartialFrame(f);
-        Value *vp = f.regs.sp - argc;
-        if (callingNew)
-            vp[-2] = vp[-1];
-        else
-            vp[-2].setUndefined();
-        return NULL;
-    }
-
-    /* CheckArity expects fun to be set. */
-    fp->setFunction(fun);
-
-    if (argc < fun->nargs) {
-        fp = (JSStackFrame *)CheckArity(f);
-        if (!fp)
-            return NULL;
-    }
-
-    fp->setCallObj(NULL);
-    fp->setArgsObj(NULL);
-    fp->setBlockChain(NULL);
-    fp->setHookData(NULL);
-    fp->setAnnotation(NULL);
-    fp->setCallerVersion(fp->down->getCallerVersion());
-    fp->setScript(script);
-    fp->clearReturnValue();
-#ifdef DEBUG
-    fp->savedPC = JSStackFrame::sInvalidPC;
-#endif
-
-    f.regs.fp = fp;
-    f.regs.sp = fp->base();
-    f.regs.pc = script->code;
-
-    SetValueRangeToUndefined(fp->slots(), script->nfixed);
-
-    if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
-        THROWV(NULL);
-
-    CompileStatus status = CanMethodJIT(cx, script, fun, fp->getScopeChain());
-    if (status == Compile_Okay)
-        return script->jit->invoke;
-
-    /* Function did not compile... interpret it. */
-    JSBool ok = Interpret(cx, fp);
-    InlineReturn(f, ok);
-
-    if (!ok)
-        THROWV(NULL);
-
-    return NULL;
-}
-
-/* Preserved for when calls need to be slow (debug mode, no ICs) */
-static bool
+static inline bool
 CreateFrame(VMFrame &f, uint32 flags, uint32 argc)
 {
     JSContext *cx = f.cx;
     JSStackFrame *fp = f.fp();
     Value *vp = f.regs.sp - (argc + 2);
     JSObject *funobj = &vp->toObject();
     JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
 
@@ -484,28 +252,29 @@ CreateFrame(VMFrame &f, uint32 flags, ui
 
     /* :TODO: Switch version if currentVersion wasn't overridden. */
     newfp->setCallerVersion((JSVersion)cx->version);
 
     // Marker for debug support.
     if (JSInterpreterHook hook = cx->debugHooks->callHook) {
         newfp->setHookData(hook(cx, fp, JS_TRUE, 0,
                                 cx->debugHooks->callHookData));
+        // CHECK_INTERRUPT_HANDLER();
     } else {
         newfp->setHookData(NULL);
     }
 
     stack.pushInlineFrame(cx, fp, cx->regs->pc, newfp);
-    f.regs.fp = newfp;
+    FixVMFrame(f, newfp);
 
     return true;
 }
 
 static inline bool
-UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
+InlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
 {
     if (!CreateFrame(f, flags, argc))
         return false;
 
     JSContext *cx = f.cx;
     JSStackFrame *fp = cx->fp();
     JSScript *script = fp->getScript();
     f.regs.pc = script->code;
@@ -527,113 +296,307 @@ UncachedInlineCall(VMFrame &f, uint32 fl
 
     bool ok = !!Interpret(cx, cx->fp());
     InlineReturn(f, JS_TRUE);
 
     *pret = NULL;
     return ok;
 }
 
+static bool
+InlineReturn(VMFrame &f, JSBool ok)
+{
+    JSContext *cx = f.cx;
+    JSStackFrame *fp = cx->fp();
+
+    JS_ASSERT(f.fp() == cx->fp());
+    JS_ASSERT(f.fp() != f.entryFp);
+
+    JS_ASSERT(!fp->hasBlockChain());
+    JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->getScopeChain(), 0));
+
+    // Marker for debug support.
+    if (JS_UNLIKELY(fp->hasHookData())) {
+        JSInterpreterHook hook;
+        JSBool status;
+
+        hook = cx->debugHooks->callHook;
+        if (hook) {
+            /*
+             * Do not pass &ok directly as exposing the address inhibits
+             * optimizations and uninitialised warnings.
+             */
+            status = ok;
+            hook(cx, fp, JS_FALSE, &status, fp->getHookData());
+            ok = (status == JS_TRUE);
+            // CHECK_INTERRUPT_HANDLER();
+        }
+    }
+
+    fp->putActivationObjects(cx);
+
+    /* :TODO: version stuff */
+
+    if (fp->flags & JSFRAME_CONSTRUCTING && fp->getReturnValue().isPrimitive())
+        fp->setReturnValue(fp->getThisValue());
+
+    Value *newsp = fp->argv - 1;
+
+    cx->stack().popInlineFrame(cx, fp, fp->down);
+    f.fp() = cx->fp();
+
+    cx->regs->sp = newsp;
+    cx->regs->sp[-1] = fp->getReturnValue();
+
+    return ok;
+}
+
+static inline JSObject *
+InlineConstruct(VMFrame &f, uint32 argc)
+{
+    JSContext *cx = f.cx;
+    Value *vp = f.regs.sp - (argc + 2);
+
+    JSObject *funobj = &vp[0].toObject();
+    JS_ASSERT(funobj->isFunction());
+
+    jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
+    if (!funobj->getProperty(cx, id, &vp[1]))
+        return NULL;
+
+    JSObject *proto = vp[1].isObject() ? &vp[1].toObject() : NULL;
+    return NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, funobj->getParent());
+}
+
 void * JS_FASTCALL
-stubs::UncachedNew(VMFrame &f, uint32 argc)
+stubs::SlowCall(VMFrame &f, uint32 argc)
 {
     JSContext *cx = f.cx;
 
-    Value *vp = f.regs.sp - (argc + 2);
-
-    JSObject *obj;
-    if (IsFunctionObject(*vp, &obj)) {
-        JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
-
-        if (fun->isInterpreted()) {
-            JSScript *script = fun->u.i.script;
-            if (!stubs::NewObject(f, argc))
-                THROWV(NULL);
-
-            if (script->isEmpty()) {
-                vp[0] = vp[1];
-                return NULL;
-            }
-
-            void *ret;
-            if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ret, argc))
-                THROWV(NULL);
-
-            return ret;
-        }
-
-        if (fun->isConstructor()) {
-            vp[1].setMagicWithObjectOrNullPayload(NULL);
-            Native fn = fun->u.n.native;
-            if (!fn(cx, argc, vp))
-                THROWV(NULL);
-            JS_ASSERT(!vp->isPrimitive());
-            return NULL;
-        }
-    }
-
-    if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
-        THROWV(NULL);
-
-    return NULL;
-}
-
-void * JS_FASTCALL
-stubs::UncachedCall(VMFrame &f, uint32 argc)
-{
-    JSContext *cx = f.cx;
+#ifdef JS_MONOIC
+    ic::MICInfo &mic = f.fp()->getScript()->mics[argc];
+    argc = mic.argc;
+#endif
 
     Value *vp = f.regs.sp - (argc + 2);
 
     JSObject *obj;
     if (IsFunctionObject(*vp, &obj)) {
         JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
 
         if (fun->isInterpreted()) {
             void *ret;
 
             if (fun->u.i.script->isEmpty()) {
                 vp->setUndefined();
                 f.regs.sp = vp + 1;
                 return NULL;
             }
 
-            if (!UncachedInlineCall(f, 0, &ret, argc))
+            if (!InlineCall(f, 0, &ret, argc))
                 THROWV(NULL);
 
             return ret;
         }
 
         if (fun->isNative()) {
+#ifdef JS_MONOIC
+#ifdef JS_CPU_X86
+            ic::CallNative(cx, f.fp()->getScript(), mic, fun, false);
+#endif
+#endif
+
             if (!fun->u.n.native(cx, argc, vp))
                 THROWV(NULL);
             return NULL;
         }
     }
 
     if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0))
         THROWV(NULL);
 
     return NULL;
 }
 
+void * JS_FASTCALL
+stubs::SlowNew(VMFrame &f, uint32 argc)
+{
+    JSContext *cx = f.cx;
+
+#ifdef JS_MONOIC
+    ic::MICInfo &mic = f.fp()->getScript()->mics[argc];
+    argc = mic.argc;
+#endif
+
+    Value *vp = f.regs.sp - (argc + 2);
+
+    JSObject *obj;
+    if (IsFunctionObject(*vp, &obj)) {
+        JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
+
+        if (fun->isInterpreted()) {
+            JSScript *script = fun->u.i.script;
+            JSObject *obj2 = InlineConstruct(f, argc);
+            if (!obj2)
+                THROWV(NULL);
+
+            if (script->isEmpty()) {
+                vp[0].setObject(*obj2);
+                return NULL;
+            }
+
+            void *ret;
+            vp[1].setObject(*obj2);
+            if (!InlineCall(f, JSFRAME_CONSTRUCTING, &ret, argc))
+                THROWV(NULL);
+
+            return ret;
+        }
+
+        if (fun->isConstructor()) {
+#ifdef JS_MONOIC
+#ifdef JS_CPU_X86
+            ic::CallNative(cx, f.fp()->getScript(), mic, fun, true);
+#endif
+#endif
+
+            vp[1].setMagicWithObjectOrNullPayload(NULL);
+
+            if (!fun->u.n.native(cx, argc, vp))
+                THROWV(NULL);
+            JS_ASSERT(!vp->isPrimitive());
+
+            return NULL;
+        }
+    }
+
+    if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
+        THROWV(NULL);
+
+    return NULL;
+}
+
+static inline bool
+CreateLightFrame(VMFrame &f, uint32 flags, uint32 argc)
+{
+    JSContext *cx = f.cx;
+    JSStackFrame *fp = f.fp();
+    Value *vp = f.regs.sp - (argc + 2);
+    JSObject *funobj = &vp->toObject();
+    JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
+
+    JS_ASSERT(FUN_INTERPRETED(fun));
+
+    JSScript *newscript = fun->u.i.script;
+
+    /* Allocate the frame. */
+    StackSpace &stack = cx->stack();
+    uintN nslots = newscript->nslots;
+    uintN funargs = fun->nargs;
+    Value *argv = vp + 2;
+    JSStackFrame *newfp;
+    if (argc < funargs) {
+        uintN missing = funargs - argc;
+        if (!f.ensureSpace(missing, nslots))
+            return false;
+        newfp = stack.getInlineFrameUnchecked(cx, f.regs.sp, missing);
+        if (!newfp)
+            return false;
+        for (Value *v = argv + argc, *end = v + missing; v != end; ++v)
+            v->setUndefined();
+    } else {
+        if (!f.ensureSpace(0, nslots))
+            return false;
+        newfp = stack.getInlineFrameUnchecked(cx, f.regs.sp, 0);
+        if (!newfp)
+            return false;
+    }
+
+    /* Initialize the frame. */
+    newfp->setCallObj(NULL);
+    newfp->setArgsObj(NULL);
+    newfp->setScript(newscript);
+    newfp->setFunction(fun);
+    newfp->argc = argc;
+    newfp->argv = vp + 2;
+    newfp->clearReturnValue();
+    newfp->setAnnotation(NULL);
+    newfp->setScopeChain(funobj->getParent());
+    newfp->flags = flags;
+    newfp->setBlockChain(NULL);
+    newfp->setThisValue(vp[1]);
+    newfp->setHookData(NULL);
+    JS_ASSERT(!fp->hasIMacroPC());
+
+#if 0
+    /* :TODO: Switch version if currentVersion wasn't overridden. */
+    newfp->setCallerVersion((JSVersion)cx->version);
+#endif
+
+#ifdef DEBUG
+    newfp->savedPC = JSStackFrame::sInvalidPC;
+#endif
+    newfp->down = fp;
+    fp->savedPC = f.regs.pc;
+    FixVMFrame(f, newfp);
+
+    return true;
+}
+
+/*
+ * stubs::Call is guaranteed to be called on a scripted call with JIT'd code.
+ */
+void * JS_FASTCALL
+stubs::Call(VMFrame &f, uint32 argc)
+{
+    if (!CreateLightFrame(f, 0, argc))
+        THROWV(NULL);
+
+    return f.fp()->getScript()->ncode;
+}
+
+/*
+ * stubs::New is guaranteed to be called on a scripted call with JIT'd code.
+ */
+void * JS_FASTCALL
+stubs::New(VMFrame &f, uint32 argc)
+{
+    JSObject *obj = InlineConstruct(f, argc);
+    if (!obj)
+        THROWV(NULL);
+
+    f.regs.sp[-int(argc + 1)].setObject(*obj);
+    if (!CreateLightFrame(f, JSFRAME_CONSTRUCTING, argc))
+        THROWV(NULL);
+
+    return f.fp()->getScript()->ncode;
+}
+
 void JS_FASTCALL
 stubs::PutCallObject(VMFrame &f)
 {
     JS_ASSERT(f.fp()->hasCallObj());
     js_PutCallObject(f.cx, f.fp());
     JS_ASSERT(!f.fp()->hasArgsObj());
 }
 
 void JS_FASTCALL
 stubs::PutArgsObject(VMFrame &f)
 {
     js_PutArgsObject(f.cx, f.fp());
 }
 
+void JS_FASTCALL
+stubs::CopyThisv(VMFrame &f)
+{
+    JS_ASSERT(f.fp()->flags & JSFRAME_CONSTRUCTING);
+    if (f.fp()->getReturnValue().isPrimitive())
+        f.fp()->setReturnValue(f.fp()->getThisValue());
+}
+
 extern "C" void *
 js_InternalThrow(VMFrame &f)
 {
     JSContext *cx = f.cx;
 
     // Make sure sp is up to date.
     JS_ASSERT(cx->regs == &f.regs);
 
--- a/js/src/methodjit/MachineRegs.h
+++ b/js/src/methodjit/MachineRegs.h
@@ -61,23 +61,21 @@ struct Registers {
 #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
     static const RegisterID ReturnReg = JSC::X86Registers::eax;
 # if defined(JS_CPU_X86) || defined(_MSC_VER)
     static const RegisterID ArgReg0 = JSC::X86Registers::ecx;
     static const RegisterID ArgReg1 = JSC::X86Registers::edx;
 # else
     static const RegisterID ArgReg0 = JSC::X86Registers::edi;
     static const RegisterID ArgReg1 = JSC::X86Registers::esi;
-    static const RegisterID ArgReg2 = JSC::X86Registers::edx;
 # endif
 #elif JS_CPU_ARM
     static const RegisterID ReturnReg = JSC::ARMRegisters::r0;
     static const RegisterID ArgReg0 = JSC::ARMRegisters::r0;
     static const RegisterID ArgReg1 = JSC::ARMRegisters::r1;
-    static const RegisterID ArgReg2 = JSC::ARMRegisters::r2;
 #endif
 
     static const RegisterID StackPointer = JSC::MacroAssembler::stackPointerRegister;
 
     static inline uint32 maskReg(RegisterID reg) {
         return (1 << reg);
     }
 
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -751,29 +751,17 @@ EnterMethodJIT(JSContext *cx, JSStackFra
                script->filename, script->lineno);
     prof.start();
 #endif
 
 #ifdef DEBUG
     JSStackFrame *checkFp = fp;
 #endif
 
-    Value *fpAsVp = reinterpret_cast<Value*>(fp);
-    StackSpace &stack = cx->stack();
-    Value *stackLimit = stack.makeStackLimit(fpAsVp);
-
-    /*
-     * We ensure that there is always enough space to speculatively create a
-     * stack frame. By passing nslots = 0, we ensure only sizeof(JSStackFrame).
-     */
-    if (fpAsVp + VALUES_PER_STACK_FRAME >= stackLimit &&
-        !stack.ensureSpace(cx, fpAsVp, cx->regs->sp, stackLimit, 0)) {
-        js_ReportOutOfScriptQuota(cx);
-        return false;
-    }
+    Value *stackLimit = cx->stack().makeStackLimit(reinterpret_cast<Value*>(fp));
 
     JSAutoResolveFlags rf(cx, JSRESOLVE_INFER);
     JSBool ok = JaegerTrampoline(cx, fp, code, stackLimit, safePoint);
 
     JS_ASSERT(checkFp == cx->fp());
 
 #ifdef JS_METHODJIT_SPEW
     prof.stop();
@@ -823,70 +811,41 @@ mjit::ReleaseScriptCode(JSContext *cx, J
 {
     if (script->jit) {
 #if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64) 
         memset(script->jit->invoke, 0xcc, script->jit->inlineLength +
                script->jit->outOfLineLength);
 #endif
         script->jit->execPool->release();
         script->jit->execPool = NULL;
-
         // Releasing the execPool takes care of releasing the code.
         script->ncode = NULL;
 
 #if defined JS_POLYIC
         for (uint32 i = 0; i < script->jit->nPICs; i++) {
             script->pics[i].releasePools();
             Destroy(script->pics[i].execPools);
         }
 #endif
-
-#if defined JS_MONOIC
-        for (uint32 i = 0; i < script->jit->nCallICs; i++)
-            script->callICs[i].releasePools();
-#endif
-
         cx->free(script->jit);
-
         // The recompiler may call ReleaseScriptCode, in which case it
         // will get called again when the script is destroyed, so we
         // must protect against calling ReleaseScriptCode twice.
         script->jit = NULL;
     }
 }
 
-void
-mjit::TraceScriptCache(JSTracer *trc, JSScript *script)
-{
-#ifdef JS_MONOIC
-    uint32 numCallICs = script->jit->nCallICs;
-    for (uint32 i = 0; i < numCallICs; i++) {
-        ic::CallICInfo &ic = script->callICs[i];
-        if (ic.fastGuardedObject) {
-            JS_SET_TRACING_NAME(trc, "callIC fun");
-            Mark(trc, ic.fastGuardedObject, JSTRACE_OBJECT);
-        }
-        if (ic.fastGuardedNative) {
-            JS_SET_TRACING_NAME(trc, "callIC native");
-            Mark(trc, ic.fastGuardedNative, JSTRACE_OBJECT);
-        }
-        if (ic.isConstantThis)
-            MarkValue(trc, ic.constantThis, "callIC this");
-    }
-#endif
-}
-
 #ifdef JS_METHODJIT_PROFILE_STUBS
 void JS_FASTCALL
 mjit::ProfileStubCall(VMFrame &f)
 {
     JSOp op = JSOp(*f.regs.pc);
     StubCallsForOp[op]++;
 }
 #endif
 
 bool
 VMFrame::slowEnsureSpace(uint32 nslots)
 {
     return cx->stack().ensureSpace(cx, reinterpret_cast<Value*>(entryFp), regs.sp,
-                                   stackLimit, nslots + VALUES_PER_STACK_FRAME);
+                                   stackLimit, nslots);
 }
 
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -162,37 +162,34 @@ typedef JSObject * (JS_FASTCALL *JSObjSt
 typedef JSObject * (JS_FASTCALL *JSObjStubUInt32)(VMFrame &, uint32);
 typedef JSObject * (JS_FASTCALL *JSObjStubFun)(VMFrame &, JSFunction *);
 typedef JSObject * (JS_FASTCALL *JSObjStubJSObj)(VMFrame &, JSObject *);
 typedef void (JS_FASTCALL *VoidStubAtom)(VMFrame &, JSAtom *);
 typedef JSString * (JS_FASTCALL *JSStrStub)(VMFrame &);
 typedef JSString * (JS_FASTCALL *JSStrStubUInt32)(VMFrame &, uint32);
 typedef void (JS_FASTCALL *VoidStubJSObj)(VMFrame &, JSObject *);
 typedef void (JS_FASTCALL *VoidStubPC)(VMFrame &, jsbytecode *);
-typedef JSBool (JS_FASTCALL *BoolStubUInt32)(VMFrame &f, uint32);
 
 #define JS_UNJITTABLE_METHOD (reinterpret_cast<void*>(1))
 
 namespace mjit {
 
 struct JITScript {
     JSC::ExecutablePool *execPool;   /* pool that contains |ncode|; script owns the pool */
     uint32          inlineLength;    /* length of inline JIT'd code */
     uint32          outOfLineLength; /* length of out of line JIT'd code */
     js::mjit::CallSite *callSites;
     uint32          nCallSites;
 #ifdef JS_MONOIC
     uint32          nMICs;           /* number of MonoICs */
-    uint32          nCallICs;        /* number of call ICs */
 #endif
 #ifdef JS_POLYIC
     uint32          nPICs;           /* number of PolyICs */
 #endif
     void            *invoke;         /* invoke address */
-    void            *arityCheck;     /* arity check address */
     uint32          *escaping;       /* list of escaping slots */
     uint32          nescaping;       /* number of escaping slots */
 };
 
 /* Execute a method that has been JIT compiled. */
 JSBool JaegerShot(JSContext *cx);
 
 /* Drop into the middle of a method at an arbitrary point, and execute. */
@@ -207,19 +204,16 @@ enum CompileStatus
 
 void JS_FASTCALL
 ProfileStubCall(VMFrame &f);
 
 CompileStatus
 TryCompile(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain);
 
 void
-TraceScriptCache(JSTracer *trc, JSScript *script);
-
-void
 ReleaseScriptCode(JSContext *cx, JSScript *script);
 
 static inline CompileStatus
 CanMethodJIT(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain)
 {
     if (!(cx->options & JSOPTION_METHODJIT) || script->ncode == JS_UNJITTABLE_METHOD)
         return Compile_Abort;
     if (script->ncode == NULL)
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -36,40 +36,28 @@
  * 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 ***** */
 #include "jsscope.h"
 #include "jsnum.h"
 #include "MonoIC.h"
 #include "StubCalls.h"
-#include "StubCalls-inl.h"
 #include "assembler/assembler/LinkBuffer.h"
 #include "assembler/assembler/RepatchBuffer.h"
 #include "assembler/assembler/MacroAssembler.h"
-#include "assembler/assembler/CodeLocation.h"
 #include "CodeGenIncludes.h"
-#include "methodjit/Compiler.h"
-#include "InlineFrameAssembler.h"
 #include "jsobj.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
-#include "jsscriptinlines.h"
 
 using namespace js;
 using namespace js::mjit;
 using namespace js::mjit::ic;
 
-typedef JSC::MacroAssembler::RegisterID RegisterID;
-typedef JSC::MacroAssembler::Address Address;
-typedef JSC::MacroAssembler::Jump Jump;
-typedef JSC::MacroAssembler::Imm32 Imm32;
-typedef JSC::MacroAssembler::ImmPtr ImmPtr;
-typedef JSC::MacroAssembler::Call Call;
-
 #if defined JS_MONOIC
 
 static void
 PatchGetFallback(VMFrame &f, ic::MICInfo &mic)
 {
     JSC::RepatchBuffer repatch(mic.stubEntry.executableAddress(), 64);
     JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stubs::GetGlobalName));
     repatch.relink(mic.stubCall, fptr);
@@ -205,519 +193,143 @@ ic::SetGlobalName(VMFrame &f, uint32 ind
 #elif defined JS_PUNBOX64
     stores.repatch(mic.load.dataLabel32AtOffset(mic.patchValueOffset), slot);
 #endif
 
     // Actually implement the op the slow way.
     GetStubForSetGlobalName(f)(f, atom);
 }
 
-static void * JS_FASTCALL
-SlowCallFromIC(VMFrame &f, uint32 index)
+#ifdef JS_CPU_X86
+
+ic::NativeCallCompiler::NativeCallCompiler()
+    : jumps(SystemAllocPolicy())
+{}
+
+void
+ic::NativeCallCompiler::finish(JSScript *script, uint8 *start, uint8 *fallthrough)
 {
-    JSScript *oldscript = f.fp()->getScript();
-    CallICInfo &ic= oldscript->callICs[index];
-
-    stubs::SlowCall(f, ic.argc);
+    /* Add a jump to fallthrough. */
+    Jump fallJump = masm.jump();
+    addLink(fallJump, fallthrough);
 
-    return NULL;
-}
+    uint8 *result = (uint8 *)script->jit->execPool->alloc(masm.size());
+    JSC::ExecutableAllocator::makeWritable(result, masm.size());
+    masm.executableCopy(result);
+
+    /* Overwrite start with a jump to the call buffer. */
+    BaseAssembler::insertJump(start, result);
 
-static void * JS_FASTCALL
-SlowNewFromIC(VMFrame &f, uint32 index)
-{
-    JSScript *oldscript = f.fp()->getScript();
-    CallICInfo &ic = oldscript->callICs[index];
+    /* Patch all calls with the correct target. */
+    masm.finalize(result);
 
-    stubs::SlowNew(f, ic.argc);
+    /* Patch all jumps with the correct target. */
+    JSC::LinkBuffer linkmasm(result, masm.size());
 
-    return NULL;
+    for (size_t i = 0; i < jumps.length(); i++)
+        linkmasm.link(jumps[i].from, JSC::CodeLocationLabel(jumps[i].to));
 }
 
-/*
- * Calls have an inline path and an out-of-line path. The inline path is used
- * in the fastest case: the method has JIT'd code, and |argc == nargs|.
- * 
- * The inline path and OOL path are separated by a guard on the identity of
- * the callee object. This guard starts as NULL and always fails on the first
- * hit. On the OOL path, the callee is verified to be both a function and a
- * scripted function. If these conditions hold, |ic::Call| is invoked.
- *
- * |ic::Call| first ensures that the callee has JIT code. If it doesn't, the
- * call to |ic::Call| is patched to a slow path. If it does have JIT'd code,
- * the following cases can occur:
- *
- *   1) args != nargs: The call to |ic::Call| is patched with a dynamically
- *      generated stub. This stub inlines a path that looks like:
- *      ----
- *      push frame
- *      if (callee is not compiled) {
- *          Compile(callee);
- *      }
- *      call callee->arityLabel
- *
- *      The arity label is a special entry point for correcting frames for
- *      arity mismatches.
- *
- *   2) args == nargs, and the inline call site was not patched yet.
- *      The guard dividing the two paths is patched to guard on the given
- *      function object identity, and the proceeding call is patched to
- *      directly call the JIT code.
- *
- *   3) args == nargs, and the inline call site was patched already.
- *      A small stub is created which extends the original guard to also
- *      guard on the JSFunction lying underneath the function object.
- *
- * If the OOL path does not have a scripted function, but does have a
- * scripted native, then a small stub is generated which inlines the native
- * invocation.
- */
-class CallCompiler
+void
+ic::CallNative(JSContext *cx, JSScript *script, MICInfo &mic, JSFunction *fun, bool isNew)
 {
-    VMFrame &f;
-    JSContext *cx;
-    CallICInfo &ic;
-    Value *vp;
-    bool callingNew;
+    if (mic.u.generated) {
+        /* Already generated a MIC at this site, don't make another one. */
+        return;
+    }
+    mic.u.generated = true;
 
-  public:
-    CallCompiler(VMFrame &f, CallICInfo &ic, bool callingNew)
-      : f(f), cx(f.cx), ic(ic), vp(f.regs.sp - (ic.argc + 2)), callingNew(callingNew)
-    {
-    }
+    JS_ASSERT(fun->isNative());
+    if (isNew)
+        JS_ASSERT(fun->isConstructor());
 
-    JSC::ExecutablePool *poolForSize(size_t size, CallICInfo::PoolIndex index)
-    {
-        mjit::ThreadData *jm = &JS_METHODJIT_DATA(cx);
-        JSC::ExecutablePool *ep = jm->execPool->poolForSize(size);
-        if (!ep) {
-            js_ReportOutOfMemory(f.cx);
-            return NULL;
-        }
-        JS_ASSERT(!ic.pools[index]);
-        ic.pools[index] = ep;
-        return ep;
-    }
+    Native native = fun->u.n.native;
+
+    typedef JSC::MacroAssembler::ImmPtr ImmPtr;
+    typedef JSC::MacroAssembler::Imm32 Imm32;
+    typedef JSC::MacroAssembler::Address Address;
+    typedef JSC::MacroAssembler::Jump Jump;
 
-    inline void pushFrameFromCaller(JSObject *scopeChain, uint32 flags)
-    {
-        JSStackFrame *fp = (JSStackFrame *)f.regs.sp;
-        fp->argc = ic.argc;
-        fp->argv = vp + 2;
-        fp->flags = flags;
-        fp->setScopeChain(scopeChain);
-        fp->setThisValue(vp[1]);
-        fp->down = f.fp();
-        fp->savedPC = f.regs.pc;
-        fp->down->savedPC = f.regs.pc;
-#ifdef DEBUG
-        fp->savedPC = JSStackFrame::sInvalidPC;
-#endif
-        f.regs.fp = fp;
-    }
+    uint8 *start = (uint8*) mic.knownObject.executableAddress();
+    uint8 *stubEntry = (uint8*) mic.stubEntry.executableAddress();
+    uint8 *fallthrough = (uint8*) mic.callEnd.executableAddress();
 
-    bool generateFullCallStub(JSScript *script, uint32 flags)
-    {
-        /*
-         * Create a stub that works with arity mismatches. Like the fast-path,
-         * this allocates a frame on the caller side, but also performs extra
-         * checks for compilability. Perhaps this should be a separate, shared
-         * trampoline, but for now we generate it dynamically.
-         */
-        Assembler masm;
-        InlineFrameAssembler inlFrame(masm, cx, ic, flags);
-        RegisterID t0 = inlFrame.tempRegs.takeAnyReg();
+    NativeCallCompiler ncc;
 
-        /* Generate the inline frame creation. */
-        inlFrame.assemble();
-
-        /* funPtrReg is still valid. Check if a compilation is needed. */
-        Address scriptAddr(ic.funPtrReg, offsetof(JSFunction, u) +
-                           offsetof(JSFunction::U::Scripted, script));
-        masm.loadPtr(scriptAddr, t0);
-
-        /*
-         * Test if script->nmap is NULL - same as checking ncode, but faster
-         * here since ncode has two failure modes and we need to load out of
-         * nmap anyway.
-         */
-        masm.loadPtr(Address(t0, offsetof(JSScript, jit)), t0);
-        Jump hasCode = masm.branchTestPtr(Assembler::NonZero, t0, t0);
+    Jump differentFunction = ncc.masm.branchPtr(Assembler::NotEqual, mic.dataReg, ImmPtr(fun));
+    ncc.addLink(differentFunction, stubEntry);
 
-        /* Try and compile. On success we get back the nmap pointer. */
-        masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
-        JSC::MacroAssembler::Call tryCompile =
-            masm.stubCall(JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction),
-                          script->code, ic.frameDepth);
-
-        Jump notCompiled = masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
-                                              Registers::ReturnReg);
+    /* Manually construct the X86 stack. TODO: get a more portable way of doing this. */
 
-        masm.call(Registers::ReturnReg);
-        Jump done = masm.jump();
-
-        hasCode.linkTo(masm.label(), &masm);
-
-        /* Get nmap[ARITY], set argc, call. */
-        masm.move(Imm32(ic.argc), JSParamReg_Argc);
-        masm.loadPtr(Address(t0, offsetof(JITScript, arityCheck)), t0);
-        masm.call(t0);
-
-        /* Rejoin with the fast path. */
-        Jump rejoin = masm.jump();
+    /* Register to use for filling in the fast native's arguments. */
+    JSC::MacroAssembler::RegisterID temp = mic.dataReg;
 
-        /* Worst case - function didn't compile. */
-        notCompiled.linkTo(masm.label(), &masm);
-        masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
-        notCompiled = masm.jump();
-
-        JSC::ExecutablePool *ep = poolForSize(masm.size(), CallICInfo::Pool_ScriptStub);
-        if (!ep)
-            return false;
+    /* Store the pc, which is the same as for the current slow call. */
+    ncc.masm.storePtr(ImmPtr(cx->regs->pc),
+                      FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, pc)));
 
-        JSC::LinkBuffer buffer(&masm, ep);
-        buffer.link(rejoin, ic.funGuard.labelAtOffset(ic.joinPointOffset));
-        buffer.link(done, ic.funGuard.labelAtOffset(ic.joinPointOffset));
-        buffer.link(notCompiled, ic.slowPathStart.labelAtOffset(ic.slowJoinOffset));
-        buffer.link(tryCompile,
-                    JSC::FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction)));
-        JSC::CodeLocationLabel cs = buffer.finalizeCodeAddendum();
-
-        JaegerSpew(JSpew_PICs, "generated CALL stub %p (%d bytes)\n", cs.executableAddress(),
-                   masm.size());
-
-        JSC::CodeLocationJump oolJump = ic.slowPathStart.jumpAtOffset(ic.oolJumpOffset);
-        uint8 *start = (uint8 *)oolJump.executableAddress();
-        JSC::RepatchBuffer repatch(start - 32, 64);
-        repatch.relink(oolJump, cs);
-
-        return true;
-    }
+    /* Store sp. */
+    uint32 spOffset = sizeof(JSStackFrame) + (mic.frameDepth + mic.argc + 2) * sizeof(jsval);
+    ncc.masm.addPtr(Imm32(spOffset), JSFrameReg, temp);
+    ncc.masm.storePtr(temp, FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, sp)));
 
-    void patchInlinePath(JSScript *script, JSObject *obj)
-    {
-        /* Very fast path. */
-        uint8 *start = (uint8 *)ic.funGuard.executableAddress();
-        JSC::RepatchBuffer repatch(start - 32, 64);
-
-        ic.fastGuardedObject = obj;
-
-        repatch.repatch(ic.funGuard, obj);
-        repatch.relink(ic.funGuard.callAtOffset(ic.hotCallOffset),
-                       JSC::FunctionPtr(script->ncode));
-
-        JaegerSpew(JSpew_PICs, "patched CALL path %p (obj: %)\n", start, ic.fastGuardedObject);
-    }
-
-    bool generateStubForClosures(JSObject *obj)
-    {
-        /* Slightly less fast path - guard on fun->getFunctionPrivate() instead. */
-        Assembler masm;
-
-        Registers tempRegs;
-        tempRegs.takeReg(ic.funObjReg);
-
-        RegisterID t0 = tempRegs.takeAnyReg();
-
-        /* Guard that it's actually a function object. */
-        Jump claspGuard = masm.branchPtr(Assembler::NotEqual,
-                                         Address(ic.funObjReg, offsetof(JSObject, clasp)),
-                                         ImmPtr(&js_FunctionClass));
+    /* Make room for the three arguments on the stack, preserving stack register alignment. */
+    const uint32 stackAdjustment = 16;
+    ncc.masm.sub32(Imm32(stackAdjustment), JSC::X86Registers::esp);
 
-        /* Guard that it's the same function. */
-        JSFunction *fun = obj->getFunctionPrivate();
-        masm.loadFunctionPrivate(ic.funObjReg, t0);
-        Jump funGuard = masm.branchPtr(Assembler::NotEqual, t0, ImmPtr(fun));
-        Jump done = masm.jump();
-
-        JSC::ExecutablePool *ep = poolForSize(masm.size(), CallICInfo::Pool_ClosureStub);
-        if (!ep)
-            return false;
+    /* Compute and push vp */
+    uint32 vpOffset = sizeof(JSStackFrame) + mic.frameDepth * sizeof(jsval);
+    ncc.masm.addPtr(Imm32(vpOffset), JSFrameReg, temp);
+    ncc.masm.storePtr(temp, Address(JSC::X86Registers::esp, 0x8));
 
-        JSC::LinkBuffer buffer(&masm, ep);
-        buffer.link(claspGuard, ic.slowPathStart);
-        buffer.link(funGuard, ic.slowPathStart);
-        buffer.link(done, ic.funGuard.labelAtOffset(ic.hotPathOffset));
-        JSC::CodeLocationLabel cs = buffer.finalizeCodeAddendum();
-
-        JaegerSpew(JSpew_PICs, "generated CALL closure stub %p (%d bytes)\n",
-                   cs.executableAddress(), masm.size());
-
-        uint8 *start = (uint8 *)ic.funJump.executableAddress();
-        JSC::RepatchBuffer repatch(start - 32, 64);
-        repatch.relink(ic.funJump, cs);
-
-        /* Retarget funJump for future ICs. */
-        ic.funJump = buffer.locationOf(funGuard);
-
-        ic.hasJsFunCheck = true;
-
-        return true;
+    if (isNew) {
+        /* Mark 'this' as magic. */
+        Value magicCtorThis;
+        magicCtorThis.setMagicWithObjectOrNullPayload(NULL);
+        ncc.masm.storeValue(magicCtorThis, Address(temp, sizeof(Value)));
     }
 
-    bool generateNativeStub()
-    {
-        Value *vp = f.regs.sp - (ic.argc + 2);
-
-        JSObject *obj;
-        if (!IsFunctionObject(*vp, &obj))
-            return false;
-
-        JSFunction *fun = obj->getFunctionPrivate();
-        if ((!callingNew && !fun->isNative()) || (callingNew && !fun->isConstructor()))
-            return false;
-
-        if (callingNew)
-            vp[1].setMagicWithObjectOrNullPayload(NULL);
-
-        Native fn = fun->u.n.native;
-        if (!fn(cx, ic.argc, vp))
-            THROWV(true);
-
-        /* Right now, take slow-path for IC misses. */
-        if (ic.fastGuardedNative)
-            return true;
-
-        /* Native MIC needs to warm up first. */
-        if (!ic.hit) {
-            ic.hit = true;
-            return true;
-        }
-
-        /* Generate fast-path for calling this native. */
-        Assembler masm;
-
-        /* Guard on the function object identity, for now. */
-        Jump funGuard = masm.branchPtr(Assembler::NotEqual, ic.funObjReg, ImmPtr(obj));
-
-        Registers tempRegs;
-#ifndef JS_CPU_X86
-        tempRegs.takeReg(Registers::ArgReg0);
-        tempRegs.takeReg(Registers::ArgReg1);
-        tempRegs.takeReg(Registers::ArgReg2);
-#endif
-        RegisterID t0 = tempRegs.takeAnyReg();
-
-        /* Store pc. */
-        masm.storePtr(ImmPtr(cx->regs->pc),
-                       FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, pc)));
-
-        /* Store sp. */
-        uint32 spOffset = sizeof(JSStackFrame) + ic.frameDepth * sizeof(Value);
-        masm.addPtr(Imm32(spOffset), JSFrameReg, t0);
-        masm.storePtr(t0, FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, sp)));
+    /* Push argc */
+    ncc.masm.store32(Imm32(mic.argc), Address(JSC::X86Registers::esp, 0x4));
 
-        /* Grab cx early on to avoid stack mucking on x86. */
-#ifdef JS_CPU_X86
-        RegisterID cxReg = tempRegs.takeAnyReg();
-#else
-        RegisterID cxReg = Registers::ArgReg0;
-#endif
-        masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), cxReg);
-
-#ifdef JS_CPU_X86
-        /* x86's stack should be 16-byte aligned. */
-        masm.subPtr(Imm32(16), Assembler::stackPointerRegister);
-#endif
-
-        /* Compute vp. */
-#ifdef JS_CPU_X86
-        RegisterID vpReg = t0;
-#else
-        RegisterID vpReg = Registers::ArgReg2;
-#endif
-        
-        uint32 vpOffset = sizeof(JSStackFrame) + (ic.frameDepth - ic.argc - 2) * sizeof(Value);
-        masm.addPtr(Imm32(vpOffset), JSFrameReg, vpReg);
-
-        /* Mark vp[1] as magic for |new|. */
-        if (callingNew) {
-            Value v;
-            v.setMagicWithObjectOrNullPayload(NULL);
-            masm.storeValue(v, Address(vpReg, sizeof(Value)));
-        }
+    /* Push cx. The VMFrame is homed at the stack register, so adjust for the amount we pushed. */
+    ncc.masm.loadPtr(FrameAddress(stackAdjustment + offsetof(VMFrame, cx)), temp);
+    ncc.masm.storePtr(temp, Address(JSC::X86Registers::esp, 0));
 
-#ifdef JS_CPU_X86
-        masm.storePtr(vpReg, Address(Assembler::stackPointerRegister, 8));
-#endif
-
-        /* Push argc. */
-#ifdef JS_CPU_X86
-        masm.store32(Imm32(ic.argc), Address(Assembler::stackPointerRegister, 4));
-#else
-        masm.move(Imm32(ic.argc), Registers::ArgReg1);
-#endif
-
-        /* Push cx. */
-#ifdef JS_CPU_X86
-        masm.storePtr(cxReg, Address(Assembler::stackPointerRegister, 0));
-#endif
+    /* Do the call. */
+    ncc.masm.call(JS_FUNC_TO_DATA_PTR(void *, native));
 
-        /* Make the call. */
-        Assembler::Call call = masm.call();
-
-#ifdef JS_CPU_X86
-        masm.addPtr(Imm32(16), Assembler::stackPointerRegister);
-#endif
-#if defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)
-        // Usually JaegerThrowpoline got called from return address.
-        // So in JaegerThrowpoline without fastcall, esp was added by 8.
-        // If we just want to jump there, we need to sub esp by 8 first.
-        masm.subPtr(Imm32(8), Assembler::stackPointerRegister);
-#endif
-
-        Jump hasException = masm.branchTest32(Assembler::Zero, Registers::ReturnReg,
-                                              Registers::ReturnReg);
-        
+    /* Restore stack. */
+    ncc.masm.add32(Imm32(stackAdjustment), JSC::X86Registers::esp);
 
 #if defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)
-        // Usually JaegerThrowpoline got called from return address.
-        // So in JaegerThrowpoline without fastcall, esp was added by 8.
-        // If we just want to jump there, we need to sub esp by 8 first.
-        masm.addPtr(Imm32(8), Assembler::stackPointerRegister);
+    // Usually JaegerThrowpoline got called from return address.
+    // So in JaegerThrowpoline without fastcall, esp was added by 8.
+    // If we just want to jump there, we need to sub esp by 8 first.
+    ncc.masm.sub32(Imm32(8), JSC::X86Registers::esp);
 #endif
 
-        Jump done = masm.jump();
-        JSC::ExecutablePool *ep = poolForSize(masm.size(), CallICInfo::Pool_NativeStub);
-        if (!ep)
-            THROWV(true);
-
-        JSC::LinkBuffer buffer(&masm, ep);
-        buffer.link(done, ic.slowPathStart.labelAtOffset(ic.slowJoinOffset));
-        buffer.link(call, JSC::FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, fun->u.n.native)));
-        buffer.link(hasException, JSC::CodeLocationLabel(JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline)));
-        buffer.link(funGuard, ic.slowPathStart);
-        
-        JSC::CodeLocationLabel cs = buffer.finalizeCodeAddendum();
-
-        JaegerSpew(JSpew_PICs, "generated native CALL stub %p (%d bytes)\n",
-                   cs.executableAddress(), masm.size());
-
-        uint8 *start = (uint8 *)ic.funJump.executableAddress();
-        JSC::RepatchBuffer repatch(start - 32, 64);
-        repatch.relink(ic.funJump, cs);
-
-        ic.fastGuardedNative = obj;
-
-        /* Retarget funJump for future ICs. */
-        ic.funJump = buffer.locationOf(funGuard);
-
-        return true;
-    }
-
-    void *update()
-    {
-        JSObject *obj;
-        if (!IsFunctionObject(*vp, &obj) || !(cx->options & JSOPTION_METHODJIT)) {
-            /* Ugh. Can't do anything with this! */
-            if (callingNew)
-                stubs::SlowNew(f, ic.argc);
-            else
-                stubs::SlowCall(f, ic.argc);
-            return NULL;
-        }
-
-        JSFunction *fun = obj->getFunctionPrivate();
-        JSObject *scopeChain = obj->getParent();
-
-        /* The slow path guards against natives. */
-        JS_ASSERT(fun->isInterpreted());
-        JSScript *script = fun->u.i.script;
-
-        if (!script->ncode && !script->isEmpty()) {
-            if (mjit::TryCompile(cx, script, fun, scopeChain) == Compile_Error)
-                THROWV(NULL);
-        }
-        JS_ASSERT(script->isEmpty() || script->ncode);
+    /* Check if the call is throwing, and jump to the throwpoline. */
+    Jump hasException =
+        ncc.masm.branchTest32(Assembler::Zero, Registers::ReturnReg, Registers::ReturnReg);
+    ncc.addLink(hasException, JS_FUNC_TO_DATA_PTR(uint8 *, JaegerThrowpoline));
 
-        if (script->ncode == JS_UNJITTABLE_METHOD || script->isEmpty()) {
-            /* This should always go to a slow path, sadly. */
-            JSC::CodeLocationCall oolCall = ic.slowPathStart.callAtOffset(ic.oolCallOffset);
-            uint8 *start = (uint8 *)oolCall.executableAddress();
-            JSC::RepatchBuffer repatch(start - 32, 64);
-            JSC::FunctionPtr fptr = callingNew
-                                    ? JSC::FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, SlowNewFromIC))
-                                    : JSC::FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, SlowCallFromIC));
-            repatch.relink(oolCall, fptr);
-            if (callingNew)
-                stubs::SlowNew(f, ic.argc);
-            else
-                stubs::SlowCall(f, ic.argc);
-            return NULL;
-        }
-
-        uint32 flags = callingNew ? JSFRAME_CONSTRUCTING : 0;
-        if (callingNew)
-            stubs::NewObject(f, ic.argc);
+#if defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)
+    ncc.masm.add32(Imm32(8), JSC::X86Registers::esp);
+#endif
 
-        if (!ic.hit) {
-            if (ic.argc < fun->nargs) {
-                if (!generateFullCallStub(script, flags))
-                    THROWV(NULL);
-            } else {
-                if (!ic.fastGuardedObject) {
-                    patchInlinePath(script, obj);
-                } else if (!ic.hasJsFunCheck &&
-                           ic.fastGuardedObject->getFunctionPrivate() == fun) {
-                    if (!generateStubForClosures(obj))
-                        THROWV(NULL);
-                } else {
-                    if (!generateFullCallStub(script, flags))
-                        THROWV(NULL);
-                }
-            }
-        } else {
-            ic.hit = true;
-        }
+    /* Load *vp into the return register pair. */
+    Address rval(JSFrameReg, vpOffset);
+    ncc.masm.loadPayload(rval, JSReturnReg_Data);
+    ncc.masm.loadTypeTag(rval, JSReturnReg_Type);
 
-        /* We'll still return to the OOL path, so make sure a frame exists. */
-        pushFrameFromCaller(scopeChain, flags);
-        if (ic.argc >= fun->nargs)
-            return script->ncode;
-        return script->jit->arityCheck;
-    }
-};
-
-void * JS_FASTCALL
-ic::Call(VMFrame &f, uint32 index)
-{
-    JSScript *oldscript = f.fp()->getScript();
-    CallICInfo &ic = oldscript->callICs[index];
-    CallCompiler cc(f, ic, false);
-    return cc.update();
+    ncc.finish(script, start, fallthrough);
 }
 
-void * JS_FASTCALL
-ic::New(VMFrame &f, uint32 index)
-{
-    JSScript *oldscript = f.fp()->getScript();
-    CallICInfo &ic = oldscript->callICs[index];
-    CallCompiler cc(f, ic, true);
-    return cc.update();
-}
-
-void JS_FASTCALL
-ic::NativeCall(VMFrame &f, uint32 index)
-{
-    JSScript *oldscript = f.fp()->getScript();
-    CallICInfo &ic = oldscript->callICs[index];
-    CallCompiler cc(f, ic, false);
-    if (!cc.generateNativeStub())
-        stubs::SlowCall(f, ic.argc);
-}
-
-void JS_FASTCALL
-ic::NativeNew(VMFrame &f, uint32 index)
-{
-    JSScript *oldscript = f.fp()->getScript();
-    CallICInfo &ic = oldscript->callICs[index];
-    CallCompiler cc(f, ic, true);
-    if (!cc.generateNativeStub())
-        stubs::SlowNew(f, ic.argc);
-}
+#endif /* JS_CPU_X86 */
 
 void
 ic::PurgeMICs(JSContext *cx, JSScript *script)
 {
     /* MICs are purged during GC to handle changing shapes. */
     JS_ASSERT(cx->runtime->gcRegenShapes);
 
     uint32 nmics = script->jit->nMICs;
@@ -732,16 +344,18 @@ ic::PurgeMICs(JSContext *cx, JSScript *s
             repatch.repatch(mic.shape, int(JSObjectMap::INVALID_SHAPE));
 
             /* 
              * If the stub call was patched, leave it alone -- it probably will
              * just be invalidated again.
              */
             break;
           }
+          case ic::MICInfo::CALL:
+          case ic::MICInfo::EMPTYCALL:
           case ic::MICInfo::TRACER:
             /* Nothing to patch! */
             break;
           default:
             JS_NOT_REACHED("Unknown MIC type during purge");
             break;
         }
     }
--- a/js/src/methodjit/MonoIC.h
+++ b/js/src/methodjit/MonoIC.h
@@ -65,16 +65,18 @@ struct MICInfo {
 
     enum Kind
 #ifdef _MSC_VER
     : uint8_t
 #endif
     {
         GET,
         SET,
+        CALL,
+        EMPTYCALL,  /* placeholder call which cannot refer to a fast native */
         TRACER
     };
 
     /* Used by multiple MICs. */
     JSC::CodeLocationLabel entry;
     JSC::CodeLocationLabel stubEntry;
 
     /* TODO: use a union-like structure for the below. */
@@ -82,114 +84,88 @@ struct MICInfo {
     /* Used by GET/SET. */
     JSC::CodeLocationLabel load;
     JSC::CodeLocationDataLabel32 shape;
     JSC::CodeLocationCall stubCall;
 #if defined JS_PUNBOX64
     uint32 patchValueOffset;
 #endif
 
+    /* Used by CALL. */
+    uint32 argc;
+    uint32 frameDepth;
+    JSC::CodeLocationLabel knownObject;
+    JSC::CodeLocationLabel callEnd;
+    JSC::MacroAssembler::RegisterID dataReg;
+
     /* Used by TRACER. */
     JSC::CodeLocationJump traceHint;
     JSC::CodeLocationJump slowTraceHint;
 
     /* Used by all MICs. */
-    Kind kind : 3;
+    Kind kind : 4;
     union {
         /* Used by GET/SET. */
         struct {
             bool touched : 1;
             bool typeConst : 1;
             bool dataConst : 1;
         } name;
+        /* Used by CALL. */
+        bool generated;
         /* Used by TRACER. */
         bool hasSlowTraceHint;
     } u;
 };
 
 void JS_FASTCALL GetGlobalName(VMFrame &f, uint32 index);
 void JS_FASTCALL SetGlobalName(VMFrame &f, uint32 index);
 
-/* See MonoIC.cpp, CallCompiler for more information on call ICs. */
-struct CallICInfo {
-    typedef JSC::MacroAssembler::RegisterID RegisterID;
+#ifdef JS_CPU_X86
+
+/* Compiler for generating fast paths for a MIC'ed native call. */
+class NativeCallCompiler
+{
+    typedef JSC::MacroAssembler::Jump Jump;
 
-    enum PoolIndex {
-        Pool_ScriptStub,
-        Pool_ClosureStub,
-        Pool_NativeStub,
-        Total_Pools
+    struct Patch {
+        Patch(Jump from, uint8 *to)
+          : from(from), to(to)
+        { }
+
+        Jump from;
+        uint8 *to;
     };
 
-    JSC::ExecutablePool *pools[Total_Pools];
-
-    /* Used for rooting and reification. */
-    JSObject *fastGuardedObject;
-    JSObject *fastGuardedNative;
-    Value constantThis;
-
-    uint32 argc : 16;
-    uint32 frameDepth : 16;
-
-    /* Function object identity guard. */
-    JSC::CodeLocationDataLabelPtr funGuard;
-
-    /* Starting point for all slow call paths. */
-    JSC::CodeLocationLabel slowPathStart;
-
-    /* Inline to OOL jump, redirected by stubs. */
-    JSC::CodeLocationJump funJump;
-
-    /* Offset to inline scripted call, from funGuard. */
-    uint32 hotCallOffset   : 8;
-    uint32 joinPointOffset : 8;
-
-    /* Out of line slow call. */
-    uint32 oolCallOffset   : 8;
-
-    /* Jump to patch for out-of-line scripted calls. */
-    uint32 oolJumpOffset   : 8;
-
-    /* Offset for deep-fun check to rejoin at. */
-    uint32 hotPathOffset   : 8;
-
-    /* Join point for all slow call paths. */
-    uint32 slowJoinOffset  : 9;
-
-    RegisterID funObjReg : 5;
-    RegisterID funPtrReg : 5;
-    bool isConstantThis : 1;
-    bool hit : 1;
-    bool hasJsFunCheck : 1;
-
-    inline void reset() {
-        fastGuardedObject = NULL;
-        fastGuardedNative = NULL;
-        hit = false;
-        hasJsFunCheck = false;
-        pools[0] = pools[1] = pools[2] = NULL;
-    }
-
-    inline void releasePools() {
-        releasePool(Pool_ScriptStub);
-        releasePool(Pool_ClosureStub);
-        releasePool(Pool_NativeStub);
-    }
+  public:
+    Assembler masm;
 
   private:
-    inline void releasePool(PoolIndex index) {
-        if (pools[index])
-            pools[index]->release();
-    }
+    /* :TODO: oom check */
+    Vector<Patch, 8, SystemAllocPolicy> jumps;
+
+  public:
+    NativeCallCompiler();
+
+    size_t size() { return masm.size(); }
+    uint8 *buffer() { return masm.buffer(); }
+
+    /* Exit from the call path to target. */
+    void addLink(Jump j, uint8 *target) { jumps.append(Patch(j, target)); }
+
+    /*
+     * Finish up this native, and add an incoming jump from start
+     * and an outgoing jump to fallthrough.
+     */
+    void finish(JSScript *script, uint8 *start, uint8 *fallthrough);
 };
 
-void * JS_FASTCALL New(VMFrame &f, uint32 index);
-void * JS_FASTCALL Call(VMFrame &f, uint32 index);
-void JS_FASTCALL NativeNew(VMFrame &f, uint32 index);
-void JS_FASTCALL NativeCall(VMFrame &f, uint32 index);
+void CallNative(JSContext *cx, JSScript *script, MICInfo &mic, JSFunction *fun, bool isNew);
+
+#endif /* JS_CPU_X86 */
 
 void PurgeMICs(JSContext *cx, JSScript *script);
 
 } /* namespace ic */
 } /* namespace mjit */
 } /* namespace js */
 
 #endif /* jsjaeger_mono_ic_h__ */
--- a/js/src/methodjit/StubCalls.h
+++ b/js/src/methodjit/StubCalls.h
@@ -54,39 +54,35 @@ JSObject * JS_FASTCALL NewInitObject(VMF
 JSObject * JS_FASTCALL NewArray(VMFrame &f, uint32 len);
 void JS_FASTCALL Trap(VMFrame &f, jsbytecode *pc);
 void JS_FASTCALL Debugger(VMFrame &f, jsbytecode *pc);
 void JS_FASTCALL Interrupt(VMFrame &f, jsbytecode *pc);
 void JS_FASTCALL InitElem(VMFrame &f, uint32 last);
 void JS_FASTCALL InitProp(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL InitMethod(VMFrame &f, JSAtom *atom);
 
-void JS_FASTCALL CheckStackQuota(VMFrame &f);
-void * JS_FASTCALL CheckArity(VMFrame &f);
-void * JS_FASTCALL CompileFunction(VMFrame &f);
-void JS_FASTCALL SlowNew(VMFrame &f, uint32 argc);
-void JS_FASTCALL SlowCall(VMFrame &f, uint32 argc);
-void * JS_FASTCALL UncachedNew(VMFrame &f, uint32 argc);
-void * JS_FASTCALL UncachedCall(VMFrame &f, uint32 argc);
-
-JSBool JS_FASTCALL NewObject(VMFrame &f, uint32 argc);
+void * JS_FASTCALL Call(VMFrame &f, uint32 argc);
+void * JS_FASTCALL New(VMFrame &f, uint32 argc);
+void * JS_FASTCALL SlowNew(VMFrame &f, uint32 argc);
+void * JS_FASTCALL SlowCall(VMFrame &f, uint32 argc);
+JSObject * JS_FASTCALL NewObject(VMFrame &f);
 void JS_FASTCALL Throw(VMFrame &f);
+void * JS_FASTCALL LookupSwitch(VMFrame &f, jsbytecode *pc);
+void * JS_FASTCALL TableSwitch(VMFrame &f, jsbytecode *origPc);
 void JS_FASTCALL PutCallObject(VMFrame &f);
 void JS_FASTCALL PutArgsObject(VMFrame &f);
+void JS_FASTCALL CopyThisv(VMFrame &f);
 void JS_FASTCALL GetCallObject(VMFrame &f);
 void JS_FASTCALL WrapPrimitiveThis(VMFrame &f);
 #if JS_MONOIC
 void * JS_FASTCALL InvokeTracer(VMFrame &f, uint32 index);
 #else
 void * JS_FASTCALL InvokeTracer(VMFrame &f);
 #endif
 
-void * JS_FASTCALL LookupSwitch(VMFrame &f, jsbytecode *pc);
-void * JS_FASTCALL TableSwitch(VMFrame &f, jsbytecode *origPc);
-
 void JS_FASTCALL BindName(VMFrame &f);
 JSObject * JS_FASTCALL BindGlobalName(VMFrame &f);
 void JS_FASTCALL SetName(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL SetGlobalName(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL SetGlobalNameDumb(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL Name(VMFrame &f);
 void JS_FASTCALL GetProp(VMFrame &f);
 void JS_FASTCALL GetElem(VMFrame &f);
--- a/js/src/methodjit/TrampolineCompiler.cpp
+++ b/js/src/methodjit/TrampolineCompiler.cpp
@@ -49,23 +49,16 @@ namespace mjit {
 #define COMPILE(which, pool, how) CHECK_RESULT(compileTrampoline((void **)(&(which)), &pool, how))
 #define RELEASE(which, pool) JS_BEGIN_MACRO \
     which = NULL;                           \
     if (pool)                               \
         pool->release();                    \
     pool = NULL;                            \
 JS_END_MACRO
 
-typedef JSC::MacroAssembler::Address Address;
-typedef JSC::MacroAssembler::Label Label;
-typedef JSC::MacroAssembler::Jump Jump;
-typedef JSC::MacroAssembler::ImmPtr ImmPtr;
-typedef JSC::MacroAssembler::Imm32 Imm32;
-typedef JSC::MacroAssembler::Address Address;
-
 bool
 TrampolineCompiler::compile()
 {
 #ifdef JS_METHODJIT_SPEW
     JMCheckLogging();
 #endif
 
     COMPILE(trampolines->forceReturn, trampolines->forceReturnPool, generateForceReturn);
--- a/js/src/methodjit/TrampolineCompiler.h
+++ b/js/src/methodjit/TrampolineCompiler.h
@@ -44,16 +44,21 @@
 #include "assembler/jit/ExecutableAllocator.h"
 #include "methodjit/CodeGenIncludes.h"
 
 namespace js {
 namespace mjit {
 
 class TrampolineCompiler
 {
+    typedef Assembler::Label Label;
+    typedef Assembler::Jump Jump;
+    typedef Assembler::ImmPtr ImmPtr;
+    typedef Assembler::Imm32 Imm32;
+    typedef Assembler::Address Address;
     typedef bool (*TrampolineGenerator)(Assembler &masm);
 
 public:
     TrampolineCompiler(JSC::ExecutableAllocator *pool, Trampolines *tramps)
       : execPool(pool), trampolines(tramps)
     { }
 
     bool compile();