Bug 409109: backing the checking as the tree was closed.

This commit is contained in:
igor%mir2.org 2008-01-09 15:31:13 +00:00
Родитель cd8061e363
Коммит 983023fba1
5 изменённых файлов: 63 добавлений и 80 удалений

Просмотреть файл

@ -782,19 +782,19 @@ PrintWinCodebase(nsGlobalWindow *win)
} }
#endif #endif
// The number of operation callbacks between calls to JS_MaybeGC // The number of branch callbacks between calls to JS_MaybeGC
#define MAYBE_GC_OPERATION_COUNT_MASK 0x00000fff // 4095 #define MAYBE_GC_BRANCH_COUNT_MASK 0x00000fff // 4095
// The number of operation callbacks before we even check if our start // The number of branch callbacks before we even check if our start
// timestamp is initialized. This is a fairly low number as we want to // timestamp is initialized. This is a fairly low number as we want to
// initialize the timestamp early enough to not waste much time before // initialize the timestamp early enough to not waste much time before
// we get there, but we don't want to bother doing this too early as // we get there, but we don't want to bother doing this too early as
// it's not generally necessary. // it's not generally necessary.
#define INITIALIZE_TIME_OPERATION_COUNT_MASK 0x000000ff // 255 #define INITIALIZE_TIME_BRANCH_COUNT_MASK 0x000000ff // 255
// This function is called after each JS branch execution // This function is called after each JS branch execution
JSBool JS_DLL_CALLBACK JSBool JS_DLL_CALLBACK
nsJSContext::DOMOperationCallback(JSContext *cx) nsJSContext::DOMBranchCallback(JSContext *cx, JSScript *script)
{ {
// Get the native context // Get the native context
nsJSContext *ctx = static_cast<nsJSContext *>(::JS_GetContextPrivate(cx)); nsJSContext *ctx = static_cast<nsJSContext *>(::JS_GetContextPrivate(cx));
@ -804,17 +804,17 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
return JS_TRUE; return JS_TRUE;
} }
PRUint32 callbackCount = ++ctx->mOperationCallbackCount; PRUint32 callbackCount = ++ctx->mBranchCallbackCount;
if (callbackCount & INITIALIZE_TIME_OPERATION_COUNT_MASK) { if (callbackCount & INITIALIZE_TIME_BRANCH_COUNT_MASK) {
return JS_TRUE; return JS_TRUE;
} }
if (callbackCount == INITIALIZE_TIME_OPERATION_COUNT_MASK + 1 && if (callbackCount == INITIALIZE_TIME_BRANCH_COUNT_MASK + 1 &&
LL_IS_ZERO(ctx->mOperationCallbackTime)) { LL_IS_ZERO(ctx->mBranchCallbackTime)) {
// Initialize mOperationCallbackTime to start timing how long the // Initialize mBranchCallbackTime to start timing how long the
// script has run // script has run
ctx->mOperationCallbackTime = PR_Now(); ctx->mBranchCallbackTime = PR_Now();
ctx->mIsTrackingChromeCodeTime = ctx->mIsTrackingChromeCodeTime =
::JS_IsSystemObject(cx, ::JS_GetGlobalObject(cx)); ::JS_IsSystemObject(cx, ::JS_GetGlobalObject(cx));
@ -822,22 +822,22 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
return JS_TRUE; return JS_TRUE;
} }
if (callbackCount & MAYBE_GC_OPERATION_COUNT_MASK) { if (callbackCount & MAYBE_GC_BRANCH_COUNT_MASK) {
return JS_TRUE; return JS_TRUE;
} }
// XXX Save the operation callback time so we can restore it after the GC, // XXX Save the branch callback time so we can restore it after the GC,
// because GCing can cause JS to run on our context, causing our // because GCing can cause JS to run on our context, causing our
// ScriptEvaluated to be called, and clearing our operation callback time // ScriptEvaluated to be called, and clearing our branch callback time and
// and count. See bug 302333. // count. See bug 302333.
PRTime callbackTime = ctx->mOperationCallbackTime; PRTime callbackTime = ctx->mBranchCallbackTime;
// Run the GC if we get this far. // Run the GC if we get this far.
JS_MaybeGC(cx); JS_MaybeGC(cx);
// Now restore the callback time and count, in case they got reset. // Now restore the callback time and count, in case they got reset.
ctx->mOperationCallbackTime = callbackTime; ctx->mBranchCallbackTime = callbackTime;
ctx->mOperationCallbackCount = callbackCount; ctx->mBranchCallbackCount = callbackCount;
PRTime now = PR_Now(); PRTime now = PR_Now();
@ -871,9 +871,7 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
nsresult rv; nsresult rv;
// Check if we should offer the option to debug // Check if we should offer the option to debug
JSStackFrame* fp = ::JS_GetScriptedCaller(cx, NULL); PRBool debugPossible = (cx->debugHooks->debuggerHandler != nsnull);
PRBool debugPossible = (fp != nsnull &&
cx->debugHooks->debuggerHandler != nsnull);
#ifdef MOZ_JSDEBUGGER #ifdef MOZ_JSDEBUGGER
// Get the debugger service if necessary. // Get the debugger service if necessary.
if (debugPossible) { if (debugPossible) {
@ -941,7 +939,6 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
} }
// Append file and line number information, if available // Append file and line number information, if available
JSScript *script = fp ? ::JS_GetFrameScript(cx, fp) : nsnull;
if (script) { if (script) {
const char *filename = ::JS_GetScriptFilename(cx, script); const char *filename = ::JS_GetScriptFilename(cx, script);
if (filename) { if (filename) {
@ -997,18 +994,17 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
} }
} }
ctx->mOperationCallbackTime = PR_Now(); ctx->mBranchCallbackTime = PR_Now();
return JS_TRUE; return JS_TRUE;
} }
else if ((buttonPressed == 2) && debugPossible) { else if ((buttonPressed == 2) && debugPossible) {
// Debug the script // Debug the script
jsval rval; jsval rval;
switch(cx->debugHooks->debuggerHandler(cx, script, ::JS_GetFramePC(cx, fp), switch(cx->debugHooks->debuggerHandler(cx, script, cx->fp->pc, &rval,
&rval,
cx->debugHooks-> cx->debugHooks->
debuggerHandlerData)) { debuggerHandlerData)) {
case JSTRAP_RETURN: case JSTRAP_RETURN:
fp->rval = rval; cx->fp->rval = rval;
return JS_TRUE; return JS_TRUE;
case JSTRAP_ERROR: case JSTRAP_ERROR:
cx->throwing = JS_FALSE; cx->throwing = JS_FALSE;
@ -1096,7 +1092,9 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
++sContextCount; ++sContextCount;
mDefaultJSOptions = JSOPTION_PRIVATE_IS_NSISUPPORTS | JSOPTION_ANONFUNFIX; mDefaultJSOptions = JSOPTION_PRIVATE_IS_NSISUPPORTS
| JSOPTION_NATIVE_BRANCH_CALLBACK
| JSOPTION_ANONFUNFIX;
// Let xpconnect resync its JSContext tracker. We do this before creating // Let xpconnect resync its JSContext tracker. We do this before creating
// a new JSContext just in case the heap manager recycles the JSContext // a new JSContext just in case the heap manager recycles the JSContext
@ -1115,8 +1113,7 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
JSOptionChangedCallback, JSOptionChangedCallback,
this); this);
::JS_SetOperationCallback(mContext, DOMOperationCallback, ::JS_SetBranchCallback(mContext, DOMBranchCallback);
JS_OPERATION_WEIGHT_BASE);
static JSLocaleCallbacks localeCallbacks = static JSLocaleCallbacks localeCallbacks =
{ {
@ -1132,8 +1129,8 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
mNumEvaluations = 0; mNumEvaluations = 0;
mTerminations = nsnull; mTerminations = nsnull;
mScriptsEnabled = PR_TRUE; mScriptsEnabled = PR_TRUE;
mOperationCallbackCount = 0; mBranchCallbackCount = 0;
mOperationCallbackTime = LL_ZERO; mBranchCallbackTime = LL_ZERO;
mProcessingScriptTag = PR_FALSE; mProcessingScriptTag = PR_FALSE;
mIsTrackingChromeCodeTime = PR_FALSE; mIsTrackingChromeCodeTime = PR_FALSE;
} }
@ -1170,8 +1167,8 @@ nsJSContext::Unlink()
// Clear our entry in the JSContext, bugzilla bug 66413 // Clear our entry in the JSContext, bugzilla bug 66413
::JS_SetContextPrivate(mContext, nsnull); ::JS_SetContextPrivate(mContext, nsnull);
// Clear the operation callback, bugzilla bug 238218 // Clear the branch callback, bugzilla bug 238218
::JS_ClearOperationCallback(mContext); ::JS_SetBranchCallback(mContext, nsnull);
// Unregister our "javascript.options.*" pref-changed callback. // Unregister our "javascript.options.*" pref-changed callback.
nsContentUtils::UnregisterPrefCallback(js_options_dot_str, nsContentUtils::UnregisterPrefCallback(js_options_dot_str,
@ -1479,11 +1476,9 @@ nsJSContext::EvaluateString(const nsAString& aScript,
} }
// The result of evaluation, used only if there were no errors. This need // The result of evaluation, used only if there were no errors. This need
// not be a GC root currently, provided we run the GC only from the // not be a GC root currently, provided we run the GC only from the branch
// operation callback or from ScriptEvaluated. // callback or from ScriptEvaluated. TODO: use JS_Begin/EndRequest to keep
// // the GC from racing with JS execution on any thread.
// TODO: use JS_Begin/EndRequest to keep the GC from racing with JS
// execution on any thread.
jsval val; jsval val;
nsJSContext::TerminationFuncHolder holder(this); nsJSContext::TerminationFuncHolder holder(this);
@ -1689,8 +1684,9 @@ nsJSContext::ExecuteScript(void *aScriptObject,
} }
// The result of evaluation, used only if there were no errors. This need // The result of evaluation, used only if there were no errors. This need
// not be a GC root currently, provided we run the GC only from the // not be a GC root currently, provided we run the GC only from the branch
// operation callback or from ScriptEvaluated. // callback or from ScriptEvaluated. TODO: use JS_Begin/EndRequest to keep
// the GC from racing with JS execution on any thread.
jsval val; jsval val;
JSBool ok; JSBool ok;
@ -3229,8 +3225,8 @@ nsJSContext::ScriptEvaluated(PRBool aTerminated)
} }
#endif #endif
mOperationCallbackCount = 0; mBranchCallbackCount = 0;
mOperationCallbackTime = LL_ZERO; mBranchCallbackTime = LL_ZERO;
} }
nsresult nsresult

Просмотреть файл

@ -279,8 +279,8 @@ private:
PRPackedBool mProcessingScriptTag; PRPackedBool mProcessingScriptTag;
PRPackedBool mIsTrackingChromeCodeTime; PRPackedBool mIsTrackingChromeCodeTime;
PRUint32 mOperationCallbackCount; PRUint32 mBranchCallbackCount;
PRTime mOperationCallbackTime; PRTime mBranchCallbackTime;
PRUint32 mDefaultJSOptions; PRUint32 mDefaultJSOptions;
// mGlobalWrapperRef is used only to hold a strong reference to the // mGlobalWrapperRef is used only to hold a strong reference to the
@ -292,7 +292,8 @@ private:
static int PR_CALLBACK JSOptionChangedCallback(const char *pref, void *data); static int PR_CALLBACK JSOptionChangedCallback(const char *pref, void *data);
static JSBool JS_DLL_CALLBACK DOMOperationCallback(JSContext *cx); static JSBool JS_DLL_CALLBACK DOMBranchCallback(JSContext *cx,
JSScript *script);
}; };
class nsIJSRuntimeService; class nsIJSRuntimeService;

Просмотреть файл

@ -2105,19 +2105,14 @@ JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
*/ */
#define JS_MAX_OPERATION_LIMIT ((uint32) 0x7FFFFFFF) #define JS_MAX_OPERATION_LIMIT ((uint32) 0x7FFFFFFF)
#define JS_OPERATION_WEIGHT_BASE 4096
/* /*
* Set the operation callback that the engine calls periodically after * Set the operation callback that the engine calls periodically after
* the internal operation count reaches the specified limit. * the internal operation count reaches the specified limit.
* *
* When operationLimit is JS_OPERATION_WEIGHT_BASE, the callback will be * When operationLimit is 4096, the callback will be called at least after
* called at least after each backward jump in the interpreter. To minimize * each backward jump in the interpreter. To minimize the overhead of the
* the overhead of the callback invocation we suggest at least * callback invocation we suggest at least 100*4096 as a value for
* * operationLimit.
* 100 * JS_OPERATION_WEIGHT_BASE
*
* as a value for operationLimit.
*/ */
extern JS_PUBLIC_API(void) extern JS_PUBLIC_API(void)
JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback, JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback,

Просмотреть файл

@ -1075,8 +1075,8 @@ extern JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
#define JSOW_SET_PROPERTY 20 #define JSOW_SET_PROPERTY 20
#define JSOW_NEW_PROPERTY 200 #define JSOW_NEW_PROPERTY 200
#define JSOW_DELETE_PROPERTY 30 #define JSOW_DELETE_PROPERTY 30
#define JSOW_ENTER_SHARP JS_OPERATION_WEIGHT_BASE #define JSOW_ENTER_SHARP 4096
#define JSOW_SCRIPT_JUMP JS_OPERATION_WEIGHT_BASE #define JSOW_SCRIPT_JUMP 4096
/* /*
* Reset the operation count and call the operation callback assuming that the * Reset the operation count and call the operation callback assuming that the

Просмотреть файл

@ -3354,9 +3354,11 @@ public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
private: private:
static JSBool JS_DLL_CALLBACK ContextHolderOperationCallback(JSContext *cx); static JSBool JS_DLL_CALLBACK ContextHolderBranchCallback(JSContext *cx,
JSScript *script);
XPCAutoJSContext mJSContext; XPCAutoJSContext mJSContext;
JSBranchCallback mOrigBranchCallback;
JSContext* mOrigCx; JSContext* mOrigCx;
}; };
@ -3364,49 +3366,38 @@ NS_IMPL_ISUPPORTS0(ContextHolder)
ContextHolder::ContextHolder(JSContext *aOuterCx, JSObject *aSandbox) ContextHolder::ContextHolder(JSContext *aOuterCx, JSObject *aSandbox)
: mJSContext(JS_NewContext(JS_GetRuntime(aOuterCx), 1024), JS_FALSE), : mJSContext(JS_NewContext(JS_GetRuntime(aOuterCx), 1024), JS_FALSE),
mOrigBranchCallback(nsnull),
mOrigCx(aOuterCx) mOrigCx(aOuterCx)
{ {
if(mJSContext) if (mJSContext) {
{
JS_SetOptions(mJSContext, JS_SetOptions(mJSContext,
JSOPTION_DONT_REPORT_UNCAUGHT | JSOPTION_DONT_REPORT_UNCAUGHT |
JSOPTION_PRIVATE_IS_NSISUPPORTS); JSOPTION_PRIVATE_IS_NSISUPPORTS);
JS_SetGlobalObject(mJSContext, aSandbox); JS_SetGlobalObject(mJSContext, aSandbox);
JS_SetContextPrivate(mJSContext, this); JS_SetContextPrivate(mJSContext, this);
if(JS_GetOperationCallback(aOuterCx)) // Now cache the original branch callback
{ mOrigBranchCallback = JS_SetBranchCallback(aOuterCx, nsnull);
JS_SetOperationCallback(mJSContext, ContextHolderOperationCallback, JS_SetBranchCallback(aOuterCx, mOrigBranchCallback);
JS_GetOperationLimit(aOuterCx));
if (mOrigBranchCallback) {
JS_SetBranchCallback(mJSContext, ContextHolderBranchCallback);
} }
} }
} }
JSBool JS_DLL_CALLBACK JSBool JS_DLL_CALLBACK
ContextHolder::ContextHolderOperationCallback(JSContext *cx) ContextHolder::ContextHolderBranchCallback(JSContext *cx, JSScript *script)
{ {
ContextHolder* thisObject = ContextHolder* thisObject =
static_cast<ContextHolder*>(JS_GetContextPrivate(cx)); static_cast<ContextHolder*>(JS_GetContextPrivate(cx));
NS_ASSERTION(thisObject, "How did that happen?"); NS_ASSERTION(thisObject, "How did that happen?");
JSContext *origCx = thisObject->mOrigCx; if (thisObject->mOrigBranchCallback) {
JSOperationCallback callback = JS_GetOperationCallback(origCx); return (thisObject->mOrigBranchCallback)(thisObject->mOrigCx, script);
JSBool ok = JS_TRUE;
if(callback)
{
ok = callback(origCx);
callback = JS_GetOperationCallback(origCx);
if(callback)
{
// If the callback is still set in the original context, reflect
// a possibly updated operation limit into cx.
JS_SetOperationLimit(cx, JS_GetOperationLimit(origCx));
return ok;
}
} }
JS_ClearOperationCallback(cx); return JS_TRUE;
return ok;
} }
/***************************************************************************/ /***************************************************************************/