Forbid JITing annotated frames (
bug 763233, r=mrbkap,jandem).
--- 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___ */