зеркало из https://github.com/mozilla/pjs.git
Backing out igor's fixes for bug 409109 and bug 364776 in an attempt to fix Tinderbox tgfx failures that are keeping talos red
This commit is contained in:
Родитель
310bb1bfa3
Коммит
c9f8a21e81
|
@ -782,17 +782,19 @@ PrintWinCodebase(nsGlobalWindow *win)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The operation limit before we even check if our start timestamp is
|
// The number of branch callbacks between calls to JS_MaybeGC
|
||||||
// initialized. This is a fairly low number as we want to initialize the
|
#define MAYBE_GC_BRANCH_COUNT_MASK 0x00000fff // 4095
|
||||||
// timestamp early enough to not waste much time before we get there, but we
|
|
||||||
// don't want to bother doing this too early as it's not generally necessary.
|
|
||||||
const PRUint32 INITIALIZE_TIME_OPERATION_LIMIT = 256 * 1000;
|
|
||||||
|
|
||||||
// The operation limit between calls to JS_MaybeGC
|
// The number of branch callbacks before we even check if our start
|
||||||
const PRUint32 MAYBE_GC_OPERATION_LIMIT = INITIALIZE_TIME_OPERATION_LIMIT * 16;
|
// timestamp is initialized. This is a fairly low number as we want to
|
||||||
|
// 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
|
||||||
|
// it's not generally necessary.
|
||||||
|
#define INITIALIZE_TIME_BRANCH_COUNT_MASK 0x000000ff // 255
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
@ -802,34 +804,40 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LL_IS_ZERO(ctx->mOperationCallbackTime)) {
|
PRUint32 callbackCount = ++ctx->mBranchCallbackCount;
|
||||||
// Initialize mOperationCallbackTime to start timing how long the
|
|
||||||
|
if (callbackCount & INITIALIZE_TIME_BRANCH_COUNT_MASK) {
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callbackCount == INITIALIZE_TIME_BRANCH_COUNT_MASK + 1 &&
|
||||||
|
LL_IS_ZERO(ctx->mBranchCallbackTime)) {
|
||||||
|
// 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));
|
||||||
|
|
||||||
NS_ASSERTION(::JS_GetOperationLimit(cx) == INITIALIZE_TIME_OPERATION_LIMIT,
|
|
||||||
"The operation limit must match the initialization value");
|
|
||||||
::JS_SetOperationLimit(cx, MAYBE_GC_OPERATION_LIMIT);
|
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_ASSERTION(::JS_GetOperationLimit(cx) == MAYBE_GC_OPERATION_LIMIT,
|
if (callbackCount & MAYBE_GC_BRANCH_COUNT_MASK) {
|
||||||
"The operation limit must match the long-running value");
|
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
|
||||||
// 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, in case they got reset.
|
// Now restore the callback time and count, in case they got reset.
|
||||||
ctx->mOperationCallbackTime = callbackTime;
|
ctx->mBranchCallbackTime = callbackTime;
|
||||||
|
ctx->mBranchCallbackCount = callbackCount;
|
||||||
|
|
||||||
PRTime now = PR_Now();
|
PRTime now = PR_Now();
|
||||||
|
|
||||||
|
@ -863,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) {
|
||||||
|
@ -933,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) {
|
||||||
|
@ -989,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;
|
||||||
|
@ -1088,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
|
||||||
|
@ -1107,8 +1113,7 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
|
||||||
JSOptionChangedCallback,
|
JSOptionChangedCallback,
|
||||||
this);
|
this);
|
||||||
|
|
||||||
::JS_SetOperationCallback(mContext, DOMOperationCallback,
|
::JS_SetBranchCallback(mContext, DOMBranchCallback);
|
||||||
INITIALIZE_TIME_OPERATION_LIMIT);
|
|
||||||
|
|
||||||
static JSLocaleCallbacks localeCallbacks =
|
static JSLocaleCallbacks localeCallbacks =
|
||||||
{
|
{
|
||||||
|
@ -1124,7 +1129,8 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
|
||||||
mNumEvaluations = 0;
|
mNumEvaluations = 0;
|
||||||
mTerminations = nsnull;
|
mTerminations = nsnull;
|
||||||
mScriptsEnabled = PR_TRUE;
|
mScriptsEnabled = PR_TRUE;
|
||||||
mOperationCallbackTime = LL_ZERO;
|
mBranchCallbackCount = 0;
|
||||||
|
mBranchCallbackTime = LL_ZERO;
|
||||||
mProcessingScriptTag = PR_FALSE;
|
mProcessingScriptTag = PR_FALSE;
|
||||||
mIsTrackingChromeCodeTime = PR_FALSE;
|
mIsTrackingChromeCodeTime = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1161,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,
|
||||||
|
@ -1469,12 +1475,10 @@ nsJSContext::EvaluateString(const nsAString& aScript,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
|
@ -1679,9 +1683,10 @@ nsJSContext::ExecuteScript(void *aScriptObject,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
|
@ -3220,8 +3225,8 @@ nsJSContext::ScriptEvaluated(PRBool aTerminated)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mOperationCallbackTime = LL_ZERO;
|
mBranchCallbackCount = 0;
|
||||||
::JS_SetOperationLimit(mContext, INITIALIZE_TIME_OPERATION_LIMIT);
|
mBranchCallbackTime = LL_ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
|
|
@ -279,7 +279,8 @@ private:
|
||||||
PRPackedBool mProcessingScriptTag;
|
PRPackedBool mProcessingScriptTag;
|
||||||
PRPackedBool mIsTrackingChromeCodeTime;
|
PRPackedBool mIsTrackingChromeCodeTime;
|
||||||
|
|
||||||
PRTime mOperationCallbackTime;
|
PRUint32 mBranchCallbackCount;
|
||||||
|
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
|
||||||
|
@ -291,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;
|
||||||
|
|
|
@ -904,8 +904,8 @@ JS_EndRequest(JSContext *cx)
|
||||||
* If js_DropObjectMap returns null, we held the last ref to scope.
|
* If js_DropObjectMap returns null, we held the last ref to scope.
|
||||||
* The waiting thread(s) must have been killed, after which the GC
|
* The waiting thread(s) must have been killed, after which the GC
|
||||||
* collected the object that held this scope. Unlikely, because it
|
* collected the object that held this scope. Unlikely, because it
|
||||||
* requires that the GC ran (e.g., from an operation callback)
|
* requires that the GC ran (e.g., from a branch callback) during
|
||||||
* during this request, but possible.
|
* this request, but possible.
|
||||||
*/
|
*/
|
||||||
if (js_DropObjectMap(cx, &scope->map, NULL)) {
|
if (js_DropObjectMap(cx, &scope->map, NULL)) {
|
||||||
js_InitLock(&scope->lock);
|
js_InitLock(&scope->lock);
|
||||||
|
@ -4929,79 +4929,13 @@ JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
|
||||||
JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback,
|
|
||||||
uint32 operationLimit)
|
|
||||||
{
|
|
||||||
JS_ASSERT(callback);
|
|
||||||
JS_ASSERT(operationLimit <= JS_MAX_OPERATION_LIMIT);
|
|
||||||
JS_ASSERT(operationLimit > 0);
|
|
||||||
|
|
||||||
cx->operationCount = (int32) operationLimit;
|
|
||||||
cx->operationLimit = operationLimit;
|
|
||||||
cx->operationCallbackIsSet = 1;
|
|
||||||
cx->operationCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
|
||||||
JS_ClearOperationCallback(JSContext *cx)
|
|
||||||
{
|
|
||||||
cx->operationCount = (int32) JS_MAX_OPERATION_LIMIT;
|
|
||||||
cx->operationLimit = JS_MAX_OPERATION_LIMIT;
|
|
||||||
cx->operationCallbackIsSet = 0;
|
|
||||||
cx->operationCallback = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_PUBLIC_API(JSOperationCallback)
|
|
||||||
JS_GetOperationCallback(JSContext *cx)
|
|
||||||
{
|
|
||||||
JS_ASSERT(cx->operationCallbackIsSet || !cx->operationCallback);
|
|
||||||
return cx->operationCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_PUBLIC_API(uint32)
|
|
||||||
JS_GetOperationLimit(JSContext *cx)
|
|
||||||
{
|
|
||||||
JS_ASSERT(cx->operationCallbackIsSet);
|
|
||||||
return cx->operationLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
|
||||||
JS_SetOperationLimit(JSContext *cx, uint32 operationLimit)
|
|
||||||
{
|
|
||||||
JS_ASSERT(operationLimit <= JS_MAX_OPERATION_LIMIT);
|
|
||||||
JS_ASSERT(operationLimit > 0);
|
|
||||||
JS_ASSERT(cx->operationCallbackIsSet);
|
|
||||||
|
|
||||||
cx->operationLimit = operationLimit;
|
|
||||||
if (cx->operationCount > (int32) operationLimit)
|
|
||||||
cx->operationCount = (int32) operationLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBranchCallback)
|
JS_PUBLIC_API(JSBranchCallback)
|
||||||
JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
|
JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
|
||||||
{
|
{
|
||||||
JSBranchCallback oldcb;
|
JSBranchCallback oldcb;
|
||||||
|
|
||||||
if (cx->operationCallbackIsSet) {
|
oldcb = cx->branchCallback;
|
||||||
#ifdef DEBUG
|
cx->branchCallback = cb;
|
||||||
fprintf(stderr,
|
|
||||||
"JS API usage error: call to JS_SetOperationCallback is followed by\n"
|
|
||||||
"invocation of deprecated JS_SetBranchCallback\n");
|
|
||||||
JS_ASSERT(0);
|
|
||||||
#endif
|
|
||||||
cx->operationCallbackIsSet = 0;
|
|
||||||
oldcb = NULL;
|
|
||||||
} else {
|
|
||||||
oldcb = (JSBranchCallback) cx->operationCallback;
|
|
||||||
}
|
|
||||||
if (cb) {
|
|
||||||
cx->operationCount = JSOW_SCRIPT_JUMP;
|
|
||||||
cx->operationLimit = JSOW_SCRIPT_JUMP;
|
|
||||||
cx->operationCallback = (JSOperationCallback) cb;
|
|
||||||
} else {
|
|
||||||
JS_ClearOperationCallback(cx);
|
|
||||||
}
|
|
||||||
return oldcb;
|
return oldcb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -563,10 +563,7 @@ JS_StringToVersion(const char *string);
|
||||||
JS_SetBranchCallback may be
|
JS_SetBranchCallback may be
|
||||||
called with a null script
|
called with a null script
|
||||||
parameter, by native code
|
parameter, by native code
|
||||||
that loops intensively.
|
that loops intensively */
|
||||||
Deprecated, use
|
|
||||||
JS_SetOperationCallback
|
|
||||||
instead */
|
|
||||||
#define JSOPTION_DONT_REPORT_UNCAUGHT \
|
#define JSOPTION_DONT_REPORT_UNCAUGHT \
|
||||||
JS_BIT(8) /* When returning from the
|
JS_BIT(8) /* When returning from the
|
||||||
outermost API call, prevent
|
outermost API call, prevent
|
||||||
|
@ -2097,56 +2094,6 @@ extern JS_PUBLIC_API(JSBool)
|
||||||
JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
|
JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
|
||||||
jsval *argv, jsval *rval);
|
jsval *argv, jsval *rval);
|
||||||
|
|
||||||
/*
|
|
||||||
* The maximum value of the operation limit to pass to JS_SetOperationCallback
|
|
||||||
* and JS_SetOperationLimit.
|
|
||||||
*/
|
|
||||||
#define JS_MAX_OPERATION_LIMIT ((uint32) 0x7FFFFFFF)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the operation callback that the engine calls periodically after
|
|
||||||
* the internal operation count reaches the specified limit.
|
|
||||||
*
|
|
||||||
* When operationLimit is 1000, the callback will be called at least after
|
|
||||||
* each backward jump in the interpreter. To minimize the overhead of the
|
|
||||||
* callback invocation we suggest at least 100*1000 as a value for
|
|
||||||
* operationLimit.
|
|
||||||
*/
|
|
||||||
extern JS_PUBLIC_API(void)
|
|
||||||
JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback,
|
|
||||||
uint32 operationLimit);
|
|
||||||
|
|
||||||
extern JS_PUBLIC_API(void)
|
|
||||||
JS_ClearOperationCallback(JSContext *cx);
|
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSOperationCallback)
|
|
||||||
JS_GetOperationCallback(JSContext *cx);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the operation limit associated with the operation callback. This API
|
|
||||||
* function may be called only when the result of JS_GetOperationCallback(cx)
|
|
||||||
* is not null.
|
|
||||||
*/
|
|
||||||
extern JS_PUBLIC_API(uint32)
|
|
||||||
JS_GetOperationLimit(JSContext *cx);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Change the operation limit associated with the operation callback. This API
|
|
||||||
* function may be called only when the result of JS_GetOperationCallback(cx)
|
|
||||||
* is not null.
|
|
||||||
*/
|
|
||||||
extern JS_PUBLIC_API(void)
|
|
||||||
JS_SetOperationLimit(JSContext *cx, uint32 operationLimit);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note well: JS_SetBranchCallback is deprecated. It is similar to
|
|
||||||
*
|
|
||||||
* JS_SetOperationCallback(cx, callback, 1000, NULL);
|
|
||||||
*
|
|
||||||
* except that the callback will not be called from a long-running native
|
|
||||||
* function when JSOPTION_NATIVE_BRANCH_CALLBACK is not set and the top-most
|
|
||||||
* frame is native.
|
|
||||||
*/
|
|
||||||
extern JS_PUBLIC_API(JSBranchCallback)
|
extern JS_PUBLIC_API(JSBranchCallback)
|
||||||
JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb);
|
JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb);
|
||||||
|
|
||||||
|
@ -2307,12 +2254,12 @@ JS_PUBLIC_API(JSBool)
|
||||||
JS_CStringsAreUTF8(void);
|
JS_CStringsAreUTF8(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update the value to be returned by JS_CStringsAreUTF8(). Once set, it
|
* Update the value to be returned by JS_CStringsAreUTF8(). Once set,
|
||||||
* can never be changed. This API must be called before the first call to
|
* it can not be changed. Must be called before the first call to
|
||||||
* JS_NewRuntime.
|
* JS_NewRuntime.
|
||||||
*/
|
*/
|
||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
JS_SetCStringsAreUTF8(void);
|
JS_SetCStringsAreUTF8();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Character encoding support.
|
* Character encoding support.
|
||||||
|
|
|
@ -1250,10 +1250,9 @@ array_sort(JSContext *cx, uintN argc, jsval *vp)
|
||||||
goto out;
|
goto out;
|
||||||
if (!all_strings) {
|
if (!all_strings) {
|
||||||
/*
|
/*
|
||||||
* We want to make the following loop fast and to unroot the
|
* Do not call the branch callback in the following moving loop
|
||||||
* cached results of toString invocations before the operation
|
* to make it fast and unroot the cached results of toString
|
||||||
* callback has a chance to run the GC. For this reason we do
|
* invocations before the callback has a chance to run the GC.
|
||||||
* not call JS_CHECK_OPERATION_LIMIT in the loop.
|
|
||||||
*/
|
*/
|
||||||
i = 0;
|
i = 0;
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -232,7 +232,6 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
|
||||||
memset(cx, 0, sizeof *cx);
|
memset(cx, 0, sizeof *cx);
|
||||||
|
|
||||||
cx->runtime = rt;
|
cx->runtime = rt;
|
||||||
JS_ClearOperationCallback(cx);
|
|
||||||
cx->debugHooks = &rt->globalDebugHooks;
|
cx->debugHooks = &rt->globalDebugHooks;
|
||||||
#if JS_STACK_GROWTH_DIRECTION > 0
|
#if JS_STACK_GROWTH_DIRECTION > 0
|
||||||
cx->stackLimit = (jsuword)-1;
|
cx->stackLimit = (jsuword)-1;
|
||||||
|
@ -1310,26 +1309,10 @@ js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_ResetOperationCount(JSContext *cx)
|
js_ResetOperationCounter(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSScript *script;
|
JS_ASSERT(cx->operationCounter & JSOW_BRANCH_CALLBACK);
|
||||||
|
|
||||||
JS_ASSERT(cx->operationCount <= 0);
|
cx->operationCounter = 0;
|
||||||
JS_ASSERT(cx->operationLimit > 0);
|
return !cx->branchCallback || cx->branchCallback(cx, NULL);
|
||||||
|
|
||||||
cx->operationCount = (int32) cx->operationLimit;
|
|
||||||
if (cx->operationCallbackIsSet)
|
|
||||||
return cx->operationCallback(cx);
|
|
||||||
|
|
||||||
if (cx->operationCallback) {
|
|
||||||
/*
|
|
||||||
* Invoke the deprecated branch callback. It may be called only when
|
|
||||||
* the top-most frame is scripted or JSOPTION_NATIVE_BRANCH_CALLBACK
|
|
||||||
* is set.
|
|
||||||
*/
|
|
||||||
script = cx->fp ? cx->fp->script : NULL;
|
|
||||||
if (script || JS_HAS_OPTION(cx, JSOPTION_NATIVE_BRANCH_CALLBACK))
|
|
||||||
return ((JSBranchCallback) cx->operationCallback)(cx, script);
|
|
||||||
}
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -637,11 +637,8 @@ struct JSContext {
|
||||||
/* JSRuntime contextList linkage. */
|
/* JSRuntime contextList linkage. */
|
||||||
JSCList links;
|
JSCList links;
|
||||||
|
|
||||||
/*
|
/* Counter of operations for branch callback calls. */
|
||||||
* Operation count. It is declared early in the structure as a frequently
|
uint32 operationCounter;
|
||||||
* accessed field.
|
|
||||||
*/
|
|
||||||
int32 operationCount;
|
|
||||||
|
|
||||||
#if JS_HAS_XML_SUPPORT
|
#if JS_HAS_XML_SUPPORT
|
||||||
/*
|
/*
|
||||||
|
@ -735,18 +732,10 @@ struct JSContext {
|
||||||
void *tracefp;
|
void *tracefp;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Per-context optional error reporter. */
|
/* Per-context optional user callbacks. */
|
||||||
|
JSBranchCallback branchCallback;
|
||||||
JSErrorReporter errorReporter;
|
JSErrorReporter errorReporter;
|
||||||
|
|
||||||
/*
|
|
||||||
* Flag indicating that the operation callback is set. When the flag is 0
|
|
||||||
* but operationCallback is not null, operationCallback stores the branch
|
|
||||||
* callback.
|
|
||||||
*/
|
|
||||||
uint32 operationCallbackIsSet : 1;
|
|
||||||
uint32 operationLimit : 31;
|
|
||||||
JSOperationCallback operationCallback;
|
|
||||||
|
|
||||||
/* Interpreter activation count. */
|
/* Interpreter activation count. */
|
||||||
uintN interpLevel;
|
uintN interpLevel;
|
||||||
|
|
||||||
|
@ -854,6 +843,9 @@ class JSAutoTempValueRooter
|
||||||
#define JS_HAS_XML_OPTION(cx) ((cx)->version & JSVERSION_HAS_XML || \
|
#define JS_HAS_XML_OPTION(cx) ((cx)->version & JSVERSION_HAS_XML || \
|
||||||
JSVERSION_NUMBER(cx) >= JSVERSION_1_6)
|
JSVERSION_NUMBER(cx) >= JSVERSION_1_6)
|
||||||
|
|
||||||
|
#define JS_HAS_NATIVE_BRANCH_CALLBACK_OPTION(cx) \
|
||||||
|
JS_HAS_OPTION(cx, JSOPTION_NATIVE_BRANCH_CALLBACK)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize a library-wide thread private data index, and remember that it
|
* Initialize a library-wide thread private data index, and remember that it
|
||||||
* has already been done, so that it happens only once ever. Returns true on
|
* has already been done, so that it happens only once ever. Returns true on
|
||||||
|
@ -1034,40 +1026,6 @@ extern JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
|
||||||
# define JS_CHECK_STACK_SIZE(cx, lval) ((jsuword)&(lval) > (cx)->stackLimit)
|
# define JS_CHECK_STACK_SIZE(cx, lval) ((jsuword)&(lval) > (cx)->stackLimit)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Update the operation counter according to the given weight and call the
|
|
||||||
* operation callback when we reach the operation limit. To make this
|
|
||||||
* frequently executed macro faster we decrease the counter from
|
|
||||||
* JSContext.operationLimit and compare against zero to check the limit.
|
|
||||||
*
|
|
||||||
* This macro can run the full GC. Return true if it is OK to continue and
|
|
||||||
* false otherwise.
|
|
||||||
*/
|
|
||||||
#define JS_CHECK_OPERATION_LIMIT(cx, weight) \
|
|
||||||
(JS_CHECK_OPERATION_WEIGHT(weight), \
|
|
||||||
(((cx)->operationCount -= (weight)) > 0 || js_ResetOperationCount(cx)))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A version of JS_CHECK_OPERATION_LIMIT that just updates the operation count
|
|
||||||
* without calling the operation callback or any other API. This macro resets
|
|
||||||
* the count to 0 when it becomes negative to prevent a wrap-around when the
|
|
||||||
* macro is called repeatably.
|
|
||||||
*/
|
|
||||||
#define JS_COUNT_OPERATION(cx, weight) \
|
|
||||||
((void)(JS_CHECK_OPERATION_WEIGHT(weight), \
|
|
||||||
(cx)->operationCount = ((cx)->operationCount > 0) \
|
|
||||||
? (cx)->operationCount - (weight) \
|
|
||||||
: 0))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The implementation of the above macros assumes that subtracting weights
|
|
||||||
* twice from a positive number does not wrap-around INT32_MIN.
|
|
||||||
*/
|
|
||||||
#define JS_CHECK_OPERATION_WEIGHT(weight) \
|
|
||||||
(JS_ASSERT((uint32) (weight) > 0), \
|
|
||||||
JS_ASSERT((uint32) (weight) < JS_BIT(30)))
|
|
||||||
|
|
||||||
|
|
||||||
/* Relative operations weights. */
|
/* Relative operations weights. */
|
||||||
#define JSOW_JUMP 1
|
#define JSOW_JUMP 1
|
||||||
#define JSOW_ALLOCATION 100
|
#define JSOW_ALLOCATION 100
|
||||||
|
@ -1076,15 +1034,43 @@ 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 1000
|
|
||||||
#define JSOW_SCRIPT_JUMP 1000
|
#define JSOW_BRANCH_CALLBACK JS_BIT(12)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset the operation count and call the operation callback assuming that the
|
* The implementation of JS_COUNT_OPERATION macro below assumes that
|
||||||
|
* JSOW_BRANCH_CALLBACK is a power of two to ensures that an unsigned int
|
||||||
|
* overflow does not bring the counter below JSOW_BRANCH_CALLBACK limit.
|
||||||
|
*/
|
||||||
|
JS_STATIC_ASSERT((JSOW_BRANCH_CALLBACK & (JSOW_BRANCH_CALLBACK - 1)) == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update the operation counter according the specified weight. This macro
|
||||||
|
* does not call the branch callback or any API.
|
||||||
|
*/
|
||||||
|
#define JS_COUNT_OPERATION(cx, weight) \
|
||||||
|
((void)(JS_ASSERT((weight) > 0), \
|
||||||
|
JS_ASSERT((weight) <= JSOW_BRANCH_CALLBACK), \
|
||||||
|
(cx)->operationCounter = (((cx)->operationCounter + (weight)) | \
|
||||||
|
(~(JSOW_BRANCH_CALLBACK - 1) & \
|
||||||
|
(cx)->operationCounter))))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update the operation counter and call the branch callback when it reaches
|
||||||
|
* JSOW_BRANCH_CALLBACK limit. This macro can run the full GC. Return true if
|
||||||
|
* it is OK to continue and false otherwise.
|
||||||
|
*/
|
||||||
|
#define JS_CHECK_OPERATION_LIMIT(cx, weight) \
|
||||||
|
(JS_COUNT_OPERATION(cx, weight), \
|
||||||
|
((cx)->operationCounter < JSOW_BRANCH_CALLBACK || \
|
||||||
|
js_ResetOperationCounter(cx)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset the operation counter and call branch callback assuming that the
|
||||||
* operation limit is reached.
|
* operation limit is reached.
|
||||||
*/
|
*/
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_ResetOperationCount(JSContext *cx);
|
js_ResetOperationCounter(JSContext *cx);
|
||||||
|
|
||||||
JS_END_EXTERN_C
|
JS_END_EXTERN_C
|
||||||
|
|
||||||
|
|
|
@ -268,8 +268,7 @@ typedef struct JSGCStats {
|
||||||
#endif
|
#endif
|
||||||
uint32 alloc; /* number of allocation attempts */
|
uint32 alloc; /* number of allocation attempts */
|
||||||
uint32 retry; /* allocation attempt retries after running the GC */
|
uint32 retry; /* allocation attempt retries after running the GC */
|
||||||
uint32 retryhalt; /* allocation retries halted by the operation
|
uint32 retryhalt; /* allocation retries halted by the branch callback */
|
||||||
callback */
|
|
||||||
uint32 fail; /* allocation failures */
|
uint32 fail; /* allocation failures */
|
||||||
uint32 finalfail; /* finalizer calls allocator failures */
|
uint32 finalfail; /* finalizer calls allocator failures */
|
||||||
uint32 lockborn; /* things born locked */
|
uint32 lockborn; /* things born locked */
|
||||||
|
|
|
@ -1983,10 +1983,9 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
|
||||||
*/
|
*/
|
||||||
#define CHECK_BRANCH(len) \
|
#define CHECK_BRANCH(len) \
|
||||||
JS_BEGIN_MACRO \
|
JS_BEGIN_MACRO \
|
||||||
if (len <= 0 && (cx->operationCount -= JSOW_SCRIPT_JUMP) <= 0) { \
|
if (len <= 0 && cx->branchCallback) { \
|
||||||
SAVE_SP_AND_PC(fp); \
|
SAVE_SP_AND_PC(fp); \
|
||||||
ok = js_ResetOperationCount(cx); \
|
if (!(ok = cx->branchCallback(cx, script))) \
|
||||||
if (!ok) \
|
|
||||||
goto out; \
|
goto out; \
|
||||||
} \
|
} \
|
||||||
JS_END_MACRO
|
JS_END_MACRO
|
||||||
|
@ -2324,6 +2323,9 @@ interrupt:
|
||||||
depth = (jsint) script->depth;
|
depth = (jsint) script->depth;
|
||||||
atoms = script->atomMap.vector;
|
atoms = script->atomMap.vector;
|
||||||
pc = fp->pc;
|
pc = fp->pc;
|
||||||
|
#if !JS_THREADED_INTERP
|
||||||
|
endpc = script->code + script->length;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Store the generating pc for the return value. */
|
/* Store the generating pc for the return value. */
|
||||||
vp[-depth] = (jsval)pc;
|
vp[-depth] = (jsval)pc;
|
||||||
|
@ -3771,6 +3773,9 @@ interrupt:
|
||||||
/* Push the frame and set interpreter registers. */
|
/* Push the frame and set interpreter registers. */
|
||||||
cx->fp = fp = &newifp->frame;
|
cx->fp = fp = &newifp->frame;
|
||||||
pc = script->code;
|
pc = script->code;
|
||||||
|
#if !JS_THREADED_INTERP
|
||||||
|
endpc = pc + script->length;
|
||||||
|
#endif
|
||||||
inlineCallCount++;
|
inlineCallCount++;
|
||||||
JS_RUNTIME_METER(rt, inlineCalls);
|
JS_RUNTIME_METER(rt, inlineCalls);
|
||||||
|
|
||||||
|
|
|
@ -920,7 +920,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An error, silent termination by operation callback or an exception.
|
* An error, silent termination by branch callback or an exception.
|
||||||
* Propagate the condition to the caller.
|
* Propagate the condition to the caller.
|
||||||
*/
|
*/
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
|
@ -558,8 +558,11 @@ js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap,
|
||||||
char buf[20];
|
char buf[20];
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_ENTER_SHARP))
|
if (JS_HAS_NATIVE_BRANCH_CALLBACK_OPTION(cx) &&
|
||||||
|
cx->branchCallback &&
|
||||||
|
!cx->branchCallback(cx, NULL)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set to null in case we return an early error. */
|
/* Set to null in case we return an early error. */
|
||||||
*sp = NULL;
|
*sp = NULL;
|
||||||
|
|
|
@ -643,12 +643,6 @@ typedef JSBool
|
||||||
typedef void
|
typedef void
|
||||||
(* JS_DLL_CALLBACK JSTraceDataOp)(JSTracer *trc, void *data);
|
(* JS_DLL_CALLBACK JSTraceDataOp)(JSTracer *trc, void *data);
|
||||||
|
|
||||||
typedef JSBool
|
|
||||||
(* JS_DLL_CALLBACK JSOperationCallback)(JSContext *cx);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Deprecated form of JSOperationCallback.
|
|
||||||
*/
|
|
||||||
typedef JSBool
|
typedef JSBool
|
||||||
(* JS_DLL_CALLBACK JSBranchCallback)(JSContext *cx, JSScript *script);
|
(* JS_DLL_CALLBACK JSBranchCallback)(JSContext *cx, JSScript *script);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
Загрузка…
Ссылка в новой задаче