Bug 844253 - Change useNewType to be a flag on StackFrame instead of an explicitly passed argument. r=bhackett
authorKannan Vijayan <kvijayan@mozilla.com>
Mon, 25 Feb 2013 15:15:38 -0500
changeset 122939 5b26fb5a22b9a85e8d1c00c22d37fb15b2c3ca16
parent 122938 a5c64a47becfe3b375f3d311026de03ecb18c2a1
child 122940 cade02c975dbe3eb2e75d832efe7edb54cba8b9b
push id1387
push userphilringnalda@gmail.com
push dateTue, 26 Feb 2013 22:32:56 +0000
treeherderfx-team@ad4cc4e97774 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs844253
milestone22.0a1
Bug 844253 - Change useNewType to be a flag on StackFrame instead of an explicitly passed argument. r=bhackett
js/src/ion/Ion.cpp
js/src/ion/Ion.h
js/src/jsinterp.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/StubCalls.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -1467,18 +1467,17 @@ ion::CanEnterAtBranch(JSContext *cx, JSS
 
     if (script->ion && script->ion->osrPc() != pc)
         return Method_Skipped;
 
     return Method_Compiled;
 }
 
 MethodStatus
-ion::CanEnter(JSContext *cx, JSScript *script, AbstractFramePtr fp,
-              bool isConstructing, bool newType)
+ion::CanEnter(JSContext *cx, JSScript *script, AbstractFramePtr fp, bool isConstructing)
 {
     JS_ASSERT(ion::IsEnabled(cx));
 
     // Skip if the script has been disabled.
     if (script->ion == ION_DISABLED_SCRIPT)
         return Method_Skipped;
 
     // Skip if the script is being compiled off thread.
@@ -1490,17 +1489,17 @@ ion::CanEnter(JSContext *cx, JSScript *s
         return Method_Skipped;
 
     // If constructing, allocate a new |this| object before building Ion.
     // Creating |this| is done before building Ion because it may change the
     // type information and invalidate compilation results.
     if (isConstructing && fp.thisValue().isPrimitive()) {
         RootedScript scriptRoot(cx, script);
         RootedObject callee(cx, &fp.callee());
-        RootedObject obj(cx, CreateThisForFunction(cx, callee, newType));
+        RootedObject obj(cx, CreateThisForFunction(cx, callee, fp.useNewType()));
         if (!obj)
             return Method_Skipped;
         fp.thisValue().setObject(*obj);
         script = scriptRoot;
     }
 
     // Mark as forbidden if frame can't be handled.
     if (!CheckFrame(fp)) {
--- a/js/src/ion/Ion.h
+++ b/js/src/ion/Ion.h
@@ -256,18 +256,17 @@ bool InitializeIon();
 
 // Get and set the current Ion context.
 IonContext *GetIonContext();
 
 bool SetIonContext(IonContext *ctx);
 
 MethodStatus CanEnterAtBranch(JSContext *cx, JSScript *script,
                               AbstractFramePtr fp, jsbytecode *pc, bool isConstructing);
-MethodStatus CanEnter(JSContext *cx, JSScript *script, AbstractFramePtr fp,
-                      bool isConstructing, bool newType);
+MethodStatus CanEnter(JSContext *cx, JSScript *script, AbstractFramePtr fp, bool isConstructing);
 MethodStatus CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numActualArgs);
 
 enum IonExecStatus
 {
     // The method call had to be aborted due to a stack limit check. This
     // error indicates that Ion never attempted to clean up frames.
     IonExec_Aborted,
 
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -271,16 +271,32 @@ js::RunScript(JSContext *cx, StackFrame 
     JS_ASSERT_IF(!fp->isGeneratorFrame(), cx->regs().pc == script->code);
     JS_ASSERT_IF(fp->isEvalFrame(), script->isActiveEval);
 #ifdef JS_METHODJIT_SPEW
     JMCheckLogging();
 #endif
 
     JS_CHECK_RECURSION(cx, return false);
 
+    // Check to see if useNewType flag should be set for this frame.
+    if (fp->isFunctionFrame() && fp->isConstructing() && !fp->isGeneratorFrame() &&
+        cx->typeInferenceEnabled())
+    {
+        StackIter iter(cx);
+        if (!iter.done()) {
+            ++iter;
+            if (iter.isScript()) {
+                RawScript script = iter.script();
+                jsbytecode *pc = iter.pc();
+                if (UseNewType(cx, script, pc))
+                    fp->setUseNewType();
+            }
+        }
+    }
+
 #ifdef DEBUG
     struct CheckStackBalance {
         JSContext *cx;
         StackFrame *fp;
         CheckStackBalance(JSContext *cx)
           : cx(cx), fp(cx->fp())
         {}
         ~CheckStackBalance() {
@@ -289,17 +305,17 @@ js::RunScript(JSContext *cx, StackFrame 
     } check(cx);
 #endif
 
     SPSEntryMarker marker(cx->runtime);
 
 #ifdef JS_ION
     if (ion::IsEnabled(cx)) {
         ion::MethodStatus status = ion::CanEnter(cx, script, AbstractFramePtr(fp),
-                                                 fp->isConstructing(), false);
+                                                 fp->isConstructing());
         if (status == ion::Method_Error)
             return false;
         if (status == ion::Method_Compiled) {
             ion::IonExecStatus status = ion::Cannon(cx, fp);
 
             // Note that if we bailed out, new inline frames may have been
             // pushed, so we interpret with the current fp.
             if (status == ion::IonExec_Bailout)
@@ -1154,17 +1170,17 @@ js::Interpret(JSContext *cx, StackFrame 
 
     /* State communicated between non-local jumps: */
     bool interpReturnOK;
 
     /* Don't call the script prologue if executing between Method and Trace JIT. */
     if (interpMode == JSINTERP_NORMAL) {
         StackFrame *fp = regs.fp();
         if (!fp->isGeneratorFrame()) {
-            if (!fp->prologue(cx, UseNewTypeAtEntry(cx, fp)))
+            if (!fp->prologue(cx))
                 goto error;
         } else {
             Probes::enterScript(cx, script, script->function(), fp);
         }
         if (cx->compartment->debugMode()) {
             JSTrapStatus status = ScriptDebugPrologue(cx, fp);
             switch (status) {
               case JSTRAP_CONTINUE:
@@ -2356,26 +2372,29 @@ BEGIN_CASE(JSOP_FUNCALL)
     if (!TypeMonitorCall(cx, args, construct))
         goto error;
 
     InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
     bool newType = cx->typeInferenceEnabled() && UseNewType(cx, script, regs.pc);
     funScript = fun->nonLazyScript();
     if (!cx->stack.pushInlineFrame(cx, regs, args, fun, funScript, initial))
         goto error;
+ 
+    if (newType)
+        regs.fp()->setUseNewType();
 
     SET_SCRIPT(regs.fp()->script());
 #ifdef JS_METHODJIT
     script->resetLoopCount();
 #endif
 
 #ifdef JS_ION
     if (!newType && ion::IsEnabled(cx)) {
         ion::MethodStatus status = ion::CanEnter(cx, script, AbstractFramePtr(regs.fp()),
-                                                 regs.fp()->isConstructing(), newType);
+                                                 regs.fp()->isConstructing());
         if (status == ion::Method_Error)
             goto error;
         if (status == ion::Method_Compiled) {
             ion::IonExecStatus exec = ion::Cannon(cx, regs.fp());
             CHECK_BRANCH();
             if (exec == ion::IonExec_Bailout) {
                 SET_SCRIPT(regs.fp()->script());
                 op = JSOp(*regs.pc);
@@ -2400,17 +2419,17 @@ BEGIN_CASE(JSOP_FUNCALL)
             mjit::JaegerStatus status = mjit::JaegerShot(cx, true);
             CHECK_PARTIAL_METHODJIT(status);
             interpReturnOK = mjit::JaegerStatusToSuccess(status);
             goto jit_return;
         }
     }
 #endif
 
-    if (!regs.fp()->prologue(cx, newType))
+    if (!regs.fp()->prologue(cx))
         goto error;
     if (cx->compartment->debugMode()) {
         switch (ScriptDebugPrologue(cx, regs.fp())) {
           case JSTRAP_CONTINUE:
             break;
           case JSTRAP_RETURN:
             interpReturnOK = true;
             goto forced_return;
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -935,17 +935,19 @@ js_InternalInterpret(void *returnData, v
        * Each of these cases indicates a point of progress through
        * generatePrologue. Execute the rest of the prologue here.
        */
       case REJOIN_CHECK_ARGUMENTS:
         if (!CheckStackQuota(f))
             return js_InternalThrow(f);
         fp->initVarsToUndefined();
         fp->scopeChain();
-        if (!fp->prologue(cx, types::UseNewTypeAtEntry(cx, fp)))
+        if (types::UseNewTypeAtEntry(cx, fp))
+            fp->setUseNewType();
+        if (!fp->prologue(cx))
             return js_InternalThrow(f);
 
         /*
          * We would normally call ScriptDebugPrologue here. But in debug mode,
          * we only use JITted functions' invokeEntry entry point, whereas
          * CheckArgumentTypes (REJOIN_CHECK_ARGUMENTS) is only reachable via
          * the other entry points.
          *
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -803,18 +803,17 @@ stubs::TriggerIonCompile(VMFrame &f)
         if (*osrPC != JSOP_LOOPENTRY)
             osrPC = NULL;
 
         ion::MethodStatus compileStatus;
         if (osrPC) {
             compileStatus = ion::CanEnterAtBranch(f.cx, script, f.cx->fp(), osrPC,
                                                   f.fp()->isConstructing());
         } else {
-            compileStatus = ion::CanEnter(f.cx, script, f.cx->fp(), f.fp()->isConstructing(),
-                                          /* newType = */ false);
+            compileStatus = ion::CanEnter(f.cx, script, f.cx->fp(), f.fp()->isConstructing());
         }
 
         if (compileStatus != ion::Method_Compiled) {
             if (f.cx->isExceptionPending())
                 THROW();
         }
 
         return;
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -733,16 +733,23 @@ inline bool
 AbstractFramePtr::hasCallObj() const
 {
     if (isStackFrame())
         return asStackFrame()->hasCallObj();
     JS_NOT_REACHED("Invalid frame");
     return false;
 }
 inline bool
+AbstractFramePtr::useNewType() const
+{
+    if (isStackFrame())
+        return asStackFrame()->useNewType();
+    return false;
+}
+inline bool
 AbstractFramePtr::isGeneratorFrame() const
 {
     if (isStackFrame())
         return asStackFrame()->isGeneratorFrame();
     return false;
 }
 inline bool
 AbstractFramePtr::isYielding() const
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -302,17 +302,17 @@ StackFrame::initFunctionScopeObjects(JSC
     if (!callobj)
         return false;
     pushOnScopeChain(*callobj);
     flags_ |= HAS_CALL_OBJ;
     return true;
 }
 
 bool
-StackFrame::prologue(JSContext *cx, bool newType)
+StackFrame::prologue(JSContext *cx)
 {
     RootedScript script(cx, this->script());
 
     JS_ASSERT(!isGeneratorFrame());
     JS_ASSERT(cx->regs().pc == script->code);
 
     if (isEvalFrame()) {
         if (script->strict) {
@@ -334,17 +334,17 @@ StackFrame::prologue(JSContext *cx, bool
     JS_ASSERT(isNonEvalFunctionFrame());
     AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
 
     if (fun()->isHeavyweight() && !initFunctionScopeObjects(cx))
         return false;
 
     if (isConstructing()) {
         RootedObject callee(cx, &this->callee());
-        JSObject *obj = CreateThisForFunction(cx, callee, newType);
+        JSObject *obj = CreateThisForFunction(cx, callee, useNewType());
         if (!obj)
             return false;
         functionThis() = ObjectValue(*obj);
     }
 
     Probes::enterScript(cx, script, script->function(), this);
     return true;
 }
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -292,16 +292,17 @@ class AbstractFramePtr
     inline unsigned numFormalArgs() const;
 
     inline Value *formals() const;
     inline Value *actuals() const;
 
     inline bool hasArgsObj() const;
     inline ArgumentsObject &argsObj() const;
     inline void initArgsObj(ArgumentsObject &argsobj) const;
+    inline bool useNewType() const;
 
     inline bool copyRawFrameSlots(AutoValueVector *vec) const;
 
     inline Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     inline Value &unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     inline Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
 
@@ -384,20 +385,23 @@ class StackFrame
 
         /* Debugger state */
         PREV_UP_TO_DATE    =    0x80000,  /* see DebugScopes::updateLiveScopes */
 
         /* Used in tracking calls and profiling (see vm/SPSProfiler.cpp) */
         HAS_PUSHED_SPS_FRAME = 0x100000,  /* SPS was notified of enty */
 
         /* Ion frame state */
-        RUNNING_IN_ION       = 0x200000,  /* frame is running in Ion */
-        CALLING_INTO_ION     = 0x400000,  /* frame is calling into Ion */
+        RUNNING_IN_ION     =   0x200000,  /* frame is running in Ion */
+        CALLING_INTO_ION   =   0x400000,  /* frame is calling into Ion */
 
-        JIT_REVISED_STACK    = 0x800000   /* sp was revised by JIT for lowered apply */
+        JIT_REVISED_STACK  =   0x800000,  /* sp was revised by JIT for lowered apply */
+
+        /* Miscellaneous state. */
+        USE_NEW_TYPE       =  0x1000000   /* Use new type for constructed |this| object. */
     };
 
   private:
     mutable uint32_t    flags_;         /* bits described by Flags */
     union {                             /* describes what code is executing in a */
         RawScript       script;         /*   global frame */
         JSFunction      *fun;           /*   function frame, pre GetScopeChain */
     } exec;
@@ -484,22 +488,19 @@ class StackFrame
      * frame but do *not* call the prologue/epilogue. That means Interpret
      * must call the prologue/epilogue for the entry frame. This scheme
      * simplifies jit compilation.
      *
      * An important corner case is what happens when an error occurs (OOM,
      * over-recursed) after pushing the stack frame but before 'prologue' is
      * called or completes fully. To simplify usage, 'epilogue' does not assume
      * 'prologue' has completed and handles all the intermediate state details.
-     *
-     * The 'newType' option indicates whether the constructed 'this' value (if
-     * there is one) should be given a new singleton type.
      */
 
-    bool prologue(JSContext *cx, bool newType);
+    bool prologue(JSContext *cx);
     void epilogue(JSContext *cx);
 
     /* Subsets of 'prologue' called from jit code. */
     inline bool jitHeavyweightFunctionPrologue(JSContext *cx);
     bool jitStrictEvalPrologue(JSContext *cx);
 
     /* Called from IonMonkey to transition from bailouts. */
     void initFromBailout(JSContext *cx, ion::SnapshotIterator &iter);
@@ -1047,16 +1048,25 @@ class StackFrame
         return flags_ & HAS_CALL_OBJ;
     }
 
     bool hasArgsObj() const {
         JS_ASSERT(script()->needsArgsObj());
         return flags_ & HAS_ARGS_OBJ;
     }
 
+    void setUseNewType() {
+        JS_ASSERT(isConstructing());
+        flags_ |= USE_NEW_TYPE;
+    }
+    bool useNewType() const {
+        JS_ASSERT(isConstructing());
+        return flags_ & USE_NEW_TYPE;
+    }
+
     /*
      * The method JIT call/apply optimization can erase Function.{call,apply}
      * invocations from the stack and push the callee frame directly. The base
      * of these frames will be offset by one value, however, which the
      * interpreter needs to account for if it ends up popping the frame.
      */
     bool loweredCallOrApply() const {
         return !!(flags_ & LOWERED_CALL_APPLY);