Forbid JITing annotated frames (bug 763233, r=mrbkap,jandem).
authorDavid Anderson <danderson@mozilla.com>
Thu, 16 Aug 2012 18:26:11 -0700
changeset 104440 f6c3f006b57a8136dd40d4e4b530c630300d1c0b
parent 104439 d1b17b12a472efd78831ef9f6b9f331c96c438b0
child 104441 2b38908d7d54affab185a8dcdb902324b2fd5ae6
push id1242
push userdanderson@mozilla.com
push dateFri, 17 Aug 2012 01:26:57 +0000
reviewersmrbkap, jandem
bugs763233
milestone17.0a1
Forbid JITing annotated frames (bug 763233, r=mrbkap,jandem).
caps/src/nsScriptSecurityManager.cpp
js/src/ion/Bailouts.cpp
js/src/ion/Ion.cpp
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
js/src/jsgc.h
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2655,17 +2655,17 @@ nsScriptSecurityManager::EnableCapabilit
             return rv;
 
         SetPendingException(cx, message.get());
 
         return NS_ERROR_FAILURE; // XXX better error code?
     }
     if (NS_FAILED(principal->EnableCapability(capability, &annotation)))
         return NS_ERROR_FAILURE;
-    JS_SetFrameAnnotation(cx, fp, annotation);
+    JS_SetTopFrameAnnotation(cx, annotation);
     return NS_OK;
 }
 
 ////////////////////////////////////////////////
 // Methods implementing nsIXPCSecurityManager //
 ////////////////////////////////////////////////
 
 NS_IMETHODIMP
--- a/js/src/ion/Bailouts.cpp
+++ b/js/src/ion/Bailouts.cpp
@@ -368,16 +368,17 @@ ion::Bailout(BailoutStack *sp)
 }
 
 uint32
 ion::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut)
 {
     sp->checkInvariants();
 
     JSContext *cx = GetIonContext()->cx;
+
     // We don't have an exit frame.
     cx->runtime->ionTop = NULL;
     IonActivationIterator ionActivations(cx);
     IonBailoutIterator iter(ionActivations, sp);
     IonActivation *activation = ionActivations.activation();
 
     IonSpew(IonSpew_Bailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
 
@@ -402,16 +403,24 @@ ion::InvalidationBailout(InvalidationBai
     }
 
     iter.ionScript()->decref(cx->runtime->defaultFreeOp());
 
     if (cx->runtime->hasIonReturnOverride())
         cx->regs().sp[-1] = cx->runtime->takeIonReturnOverride();
 
     if (retval != BAILOUT_RETURN_FATAL_ERROR) {
+        if (void *annotation = activation->entryfp()->annotation()) {
+            // If the entry frame has an annotation, then we invalidated and have
+            // immediately returned into this bailout. Transfer the annotation to
+            // the new topmost frame.
+            activation->entryfp()->setAnnotation(NULL);
+            cx->fp()->setAnnotation(annotation);
+        }
+
         // If invalidation was triggered inside a stub call, we may still have to
         // monitor the result, since the bailout happens before the MMonitorTypes
         // instruction is executed.
         jsbytecode *pc = activation->bailout()->bailoutPc();
 
         // If this is not a ResumeAfter bailout, there's nothing to monitor,
         // we will redo the op in the interpreter.
         bool isResumeAfter = GetNextPc(pc) == cx->regs().pc;
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -913,16 +913,21 @@ CheckFrame(StackFrame *fp)
         return false;
     }
 
     if (fp->isDebuggerFrame()) {
         IonSpew(IonSpew_Abort, "debugger frame");
         return false;
     }
 
+    if (fp->annotation()) {
+        IonSpew(IonSpew_Abort, "frame is annotated");
+        return false;
+    }
+
     // This check is to not overrun the stack. Eventually, we will want to
     // handle this when we support JSOP_ARGUMENTS or function calls.
     if (fp->isFunctionFrame() &&
         (fp->numActualArgs() >= SNAPSHOT_MAX_NARGS ||
          fp->numActualArgs() > js_IonOptions.maxStackArgs))
     {
         IonSpew(IonSpew_Abort, "too many actual args");
         return false;
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -29,16 +29,17 @@
 #include "jsstr.h"
 #include "jswatchpoint.h"
 #include "jswrapper.h"
 
 #include "gc/Marking.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
 #include "vm/Debugger.h"
+#include "ion/Ion.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsinterpinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
@@ -529,19 +530,37 @@ JS_GetFrameAnnotation(JSContext *cx, JSS
             return fp->annotation();
         }
     }
 
     return NULL;
 }
 
 JS_PUBLIC_API(void)
-JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation)
+JS_SetTopFrameAnnotation(JSContext *cx, void *annotation)
 {
-    Valueify(fp)->setAnnotation(annotation);
+    StackFrame *fp = cx->fp();
+    JS_ASSERT_IF(fp->beginsIonActivation(), !fp->annotation());
+
+    // Note that if this frame is running in Ion, the actual calling frame
+    // could be inlined or a callee and thus we won't have a correct |fp|.
+    // To account for this, ion::InvalidationBailout will transfer an
+    // annotation from the old cx->fp() to the new top frame. This works
+    // because we will never EnterIon on a frame with an annotation.
+    fp->setAnnotation(annotation);
+
+    JSScript *script = fp->maybeScript();
+    if (!script)
+        return;
+
+    ReleaseAllJITCode(cx->runtime->defaultFreeOp());
+
+    // Ensure that we'll never try to compile this again.
+    JS_ASSERT(!script->hasIonScript());
+    script->ion = ION_DISABLED_SCRIPT;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsScriptFrame(JSContext *cx, JSStackFrame *fp)
 {
     return !Valueify(fp)->isDummyFrame();
 }
 
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -240,17 +240,17 @@ JS_GetFrameScript(JSContext *cx, JSStack
 
 extern JS_PUBLIC_API(jsbytecode *)
 JS_GetFramePC(JSContext *cx, JSStackFrame *fp);
 
 extern JS_PUBLIC_API(void *)
 JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp);
 
 extern JS_PUBLIC_API(void)
-JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation);
+JS_SetTopFrameAnnotation(JSContext *cx, void *annotation);
 
 extern JS_PUBLIC_API(JSBool)
 JS_IsScriptFrame(JSContext *cx, JSStackFrame *fp);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp);
 
 extern JS_PUBLIC_API(JSObject *)
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1176,19 +1176,13 @@ MaybeVerifyBarriers(JSContext *cx, bool 
 #endif
 
 } /* namespace gc */
 
 static inline JSCompartment *
 GetObjectCompartment(JSObject *obj) { return reinterpret_cast<js::gc::Cell *>(obj)->compartment(); }
 
 void
-ReleaseAllJITCode(FreeOp *fop, JSCompartment *c, bool resetUseCounts);
-
-void
-ReleaseAllJITCode(FreeOp *fop, bool resetUseCounts);
-
-void
 PurgeJITCaches(JSCompartment *c);
 
 } /* namespace js */
 
 #endif /* jsgc_h___ */