bug 723021 - moving native stack limits into runtime. r=luke

This commit is contained in:
Igor Bukanov 2012-01-31 23:28:22 +01:00
parent efea287c85
commit bd4db6e9ef
15 changed files with 116 additions and 102 deletions

View File

@ -866,8 +866,6 @@ nsFrameScriptExecutor::InitTabChildGlobalInternal(nsISupports* aScope)
nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
JS_SetNativeStackQuota(cx, 128 * sizeof(size_t) * 1024);
JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_PRIVATE_IS_NSISUPPORTS);
JS_SetVersion(cx, JSVERSION_LATEST);
JS_SetErrorReporter(cx, ContentScriptErrorReporter);

View File

@ -293,6 +293,8 @@ CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate)
JS_SetGCParameter(runtime, JSGC_MAX_BYTES,
aWorkerPrivate->GetJSRuntimeHeapSize());
JS_SetNativeStackQuota(runtime, WORKER_CONTEXT_NATIVE_STACK_LIMIT);
JSContext* workerCx = JS_NewContext(runtime, 0);
if (!workerCx) {
JS_DestroyRuntime(runtime);
@ -306,8 +308,6 @@ CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate)
JS_SetOperationCallback(workerCx, OperationCallback);
JS_SetNativeStackQuota(workerCx, WORKER_CONTEXT_NATIVE_STACK_LIMIT);
NS_ASSERTION((aWorkerPrivate->GetJSContextOptions() &
kRequiredJSContextOptions) == kRequiredJSContextOptions,
"Somehow we lost our required options!");

View File

@ -338,7 +338,25 @@ class JSAPITest
}
virtual JSRuntime * createRuntime() {
return JS_NewRuntime(8L * 1024 * 1024);
JSRuntime *rt = JS_NewRuntime(8L * 1024 * 1024);
if (!rt)
return NULL;
const size_t MAX_STACK_SIZE =
/* Assume we can't use more than 5e5 bytes of C stack by default. */
#if (defined(DEBUG) && defined(__SUNPRO_CC)) || defined(JS_CPU_SPARC)
/*
* Sun compiler uses a larger stack space for js::Interpret() with
* debug. Use a bigger gMaxStackSize to make "make check" happy.
*/
5000000
#else
500000
#endif
;
JS_SetNativeStackQuota(rt, MAX_STACK_SIZE);
return rt;
}
virtual void destroyRuntime() {
@ -358,22 +376,6 @@ class JSAPITest
JSContext *cx = JS_NewContext(rt, 8192);
if (!cx)
return NULL;
const size_t MAX_STACK_SIZE =
/* Assume we can't use more than 5e5 bytes of C stack by default. */
#if (defined(DEBUG) && defined(__SUNPRO_CC)) || defined(JS_CPU_SPARC)
/*
* Sun compiler uses a larger stack space for js::Interpret() with
* debug. Use a bigger gMaxStackSize to make "make check" happy.
*/
5000000
#else
500000
#endif
;
JS_SetNativeStackQuota(cx, MAX_STACK_SIZE);
JS_SetOptions(cx, JSOPTION_VAROBJFIX);
JS_SetVersion(cx, JSVERSION_LATEST);
JS_SetErrorReporter(cx, &reportError);
@ -432,7 +434,7 @@ class JSAPITest
/*
* A class for creating and managing one temporary file.
*
*
* We could use the ISO C temporary file functions here, but those try to
* create files in the root directory on Windows, which fails for users
* without Administrator privileges.
@ -463,7 +465,7 @@ class TempFile {
fprintf(stderr, "error opening temporary file '%s': %s\n",
fileName, strerror(errno));
exit(1);
}
}
name = fileName;
return stream;
}

View File

@ -694,8 +694,7 @@ JS_IsBuiltinFunctionConstructor(JSFunction *fun)
static JSBool js_NewRuntimeWasCalled = JS_FALSE;
JSRuntime::JSRuntime()
: interrupt(0),
atomsCompartment(NULL),
: atomsCompartment(NULL),
#ifdef JS_THREADSAFE
ownerThread_(NULL),
#endif
@ -703,6 +702,8 @@ JSRuntime::JSRuntime()
execAlloc_(NULL),
bumpAlloc_(NULL),
repCache_(NULL),
nativeStackBase(0),
nativeStackQuota(0),
interpreterFrames(NULL),
cxCallback(NULL),
compartmentCallback(NULL),
@ -795,6 +796,10 @@ JSRuntime::JSRuntime()
PodZero(&globalDebugHooks);
PodZero(&atomState);
#if JS_STACK_GROWTH_DIRECTION > 0
nativeStackLimit = UINTPTR_MAX;
#endif
}
bool
@ -834,7 +839,7 @@ JSRuntime::init(uint32_t maxbytes)
if (!stackSpace.init())
return false;
conservativeGC.nativeStackBase = GetNativeStackBase();
nativeStackBase = GetNativeStackBase();
return true;
}
@ -883,7 +888,9 @@ JSRuntime::setOwnerThread()
JS_ASSERT(ownerThread_ == (void *)0xc1ea12); /* "clear" */
JS_ASSERT(requestDepth == 0);
ownerThread_ = PR_GetCurrentThread();
conservativeGC.nativeStackBase = GetNativeStackBase();
nativeStackBase = GetNativeStackBase();
if (nativeStackQuota)
JS_SetNativeStackQuota(this, nativeStackQuota);
}
void
@ -892,7 +899,12 @@ JSRuntime::clearOwnerThread()
JS_ASSERT(onOwnerThread());
JS_ASSERT(requestDepth == 0);
ownerThread_ = (void *)0xc1ea12; /* "clear" */
conservativeGC.nativeStackBase = 0;
nativeStackBase = 0;
#if JS_STACK_GROWTH_DIRECTION > 0
nativeStackLimit = UINTPTR_MAX;
#else
nativeStackLimit = 0;
#endif
}
JS_FRIEND_API(bool)
@ -3002,33 +3014,25 @@ JS_GetExternalStringClosure(JSContext *cx, JSString *str)
}
JS_PUBLIC_API(void)
JS_SetThreadStackLimit(JSContext *cx, uintptr_t limitAddr)
{
#if JS_STACK_GROWTH_DIRECTION > 0
if (limitAddr == 0)
limitAddr = UINTPTR_MAX;
#endif
cx->stackLimit = limitAddr;
}
JS_PUBLIC_API(void)
JS_SetNativeStackQuota(JSContext *cx, size_t stackSize)
JS_SetNativeStackQuota(JSRuntime *rt, size_t stackSize)
{
rt->nativeStackQuota = stackSize;
if (!rt->nativeStackBase)
return;
#if JS_STACK_GROWTH_DIRECTION > 0
if (stackSize == 0) {
cx->stackLimit = UINTPTR_MAX;
rt->nativeStackLimit = UINTPTR_MAX;
} else {
uintptr_t stackBase = cx->runtime->nativeStackBase;
JS_ASSERT(stackBase <= size_t(-1) - stackSize);
cx->stackLimit = stackBase + stackSize - 1;
JS_ASSERT(rt->nativeStackBase <= size_t(-1) - stackSize);
rt->nativeStackLimit = rt->nativeStackBase + stackSize - 1;
}
#else
if (stackSize == 0) {
cx->stackLimit = 0;
rt->nativeStackLimit = 0;
} else {
uintptr_t stackBase = uintptr_t(cx->runtime->conservativeGC.nativeStackBase);
JS_ASSERT(stackBase >= stackSize);
cx->stackLimit = stackBase - (stackSize - 1);
JS_ASSERT(rt->nativeStackBase >= stackSize);
rt->nativeStackLimit = rt->nativeStackBase - (stackSize - 1);
}
#endif
}

View File

@ -3370,18 +3370,12 @@ JS_IsExternalString(JSContext *cx, JSString *str);
extern JS_PUBLIC_API(void *)
JS_GetExternalStringClosure(JSContext *cx, JSString *str);
/*
* Deprecated. Use JS_SetNativeStackQuoata instead.
*/
extern JS_PUBLIC_API(void)
JS_SetThreadStackLimit(JSContext *cx, uintptr_t limitAddr);
/*
* Set the size of the native stack that should not be exceed. To disable
* stack size checking pass 0.
*/
extern JS_PUBLIC_API(void)
JS_SetNativeStackQuota(JSContext *cx, size_t stackSize);
JS_SetNativeStackQuota(JSRuntime *cx, size_t stackSize);
/************************************************************************/

View File

@ -963,7 +963,8 @@ DSTOffsetCache::DSTOffsetCache()
}
JSContext::JSContext(JSRuntime *rt)
: defaultVersion(JSVERSION_DEFAULT),
: ContextFriendFields(rt),
defaultVersion(JSVERSION_DEFAULT),
hasVersionOverride(false),
throwing(false),
exception(UndefinedValue()),
@ -972,12 +973,6 @@ JSContext::JSContext(JSRuntime *rt)
localeCallbacks(NULL),
resolvingList(NULL),
generatingError(false),
#if JS_STACK_GROWTH_DIRECTION > 0
stackLimit(UINTPTR_MAX),
#else
stackLimit(0),
#endif
runtime(rt),
compartment(NULL),
stack(thisDuringConstruction()), /* depends on cx->thread_ */
parseMapPool_(NULL),

View File

@ -127,9 +127,6 @@ typedef Vector<ScriptOpcodeCountsPair, 0, SystemAllocPolicy> ScriptOpcodeCountsV
struct ConservativeGCData
{
/* Base address of the native stack for the current thread. */
uintptr_t *nativeStackBase;
/*
* The GC scans conservatively between ThreadData::nativeStackBase and
* nativeStackTop unless the latter is NULL.
@ -149,7 +146,7 @@ struct ConservativeGCData
unsigned requestThreshold;
ConservativeGCData()
: nativeStackBase(NULL), nativeStackTop(NULL), requestThreshold(0)
: nativeStackTop(NULL), requestThreshold(0)
{}
~ConservativeGCData() {
@ -180,14 +177,8 @@ struct ConservativeGCData
} /* namespace js */
struct JSRuntime
struct JSRuntime : js::RuntimeFriendFields
{
/*
* If non-zero, we were been asked to call the operation callback as soon
* as possible.
*/
volatile int32_t interrupt;
/* Default compartment. */
JSCompartment *atomsCompartment;
@ -243,6 +234,12 @@ struct JSRuntime
return repCache_ ? repCache_ : createRegExpPrivateCache(cx);
}
/* Base address of the native stack for the current thread. */
uintptr_t nativeStackBase;
/* The native stack size limit that runtime should not exceed. */
size_t nativeStackQuota;
/*
* Frames currently running in js::Interpret. See InterpreterFrames for
* details.
@ -428,7 +425,7 @@ struct JSRuntime
bool hasContexts() const {
return !JS_CLIST_IS_EMPTY(&contextList);
}
/* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */
JSDebugHooks globalDebugHooks;
@ -764,7 +761,7 @@ typedef HashSet<JSObject *,
} /* namespace js */
struct JSContext
struct JSContext : js::ContextFriendFields
{
explicit JSContext(JSRuntime *rt);
JSContext *thisDuringConstruction() { return this; }
@ -800,12 +797,6 @@ struct JSContext
*/
JSPackedBool generatingError;
/* Limit pointer for checking native stack consumption during recursion. */
uintptr_t stackLimit;
/* Data shared by contexts and compartments in an address space. */
JSRuntime *const runtime;
/* GC heap compartment. */
JSCompartment *compartment;

View File

@ -645,12 +645,6 @@ GetRuntimeCompartments(JSRuntime *rt)
return rt->compartments;
}
JS_FRIEND_API(uintptr_t)
GetContextStackLimit(const JSContext *cx)
{
return cx->stackLimit;
}
JS_FRIEND_API(size_t)
SizeOfJSContext()
{

View File

@ -156,6 +156,42 @@ struct PRLock;
namespace js {
struct ContextFriendFields {
JSRuntime *const runtime;
ContextFriendFields(JSRuntime *rt)
: runtime(rt) { }
static const ContextFriendFields *get(const JSContext *cx) {
return reinterpret_cast<const ContextFriendFields *>(cx);
}
};
struct RuntimeFriendFields {
/*
* If non-zero, we were been asked to call the operation callback as soon
* as possible.
*/
volatile int32_t interrupt;
/* Limit pointer for checking native stack consumption. */
uintptr_t nativeStackLimit;
RuntimeFriendFields()
: interrupt(0),
nativeStackLimit(0) { }
static const RuntimeFriendFields *get(const JSRuntime *rt) {
return reinterpret_cast<const RuntimeFriendFields *>(rt);
}
};
inline JSRuntime *
GetRuntime(const JSContext *cx)
{
return ContextFriendFields::get(cx)->runtime;
}
typedef bool
(* PreserveWrapperCallback)(JSContext *cx, JSObject *obj);
@ -228,7 +264,7 @@ struct WeakMapTracer {
JSContext *context;
WeakMapTraceCallback callback;
WeakMapTracer(JSContext *cx, WeakMapTraceCallback cb)
WeakMapTracer(JSContext *cx, WeakMapTraceCallback cb)
: context(cx), callback(cb) {}
};
@ -440,8 +476,11 @@ IsObjectInContextCompartment(const JSObject *obj, const JSContext *cx);
#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */
#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */
JS_FRIEND_API(uintptr_t)
GetContextStackLimit(const JSContext *cx);
inline uintptr_t
GetContextStackLimit(const JSContext *cx)
{
return RuntimeFriendFields::get(GetRuntime(cx))->nativeStackLimit;
}
#define JS_CHECK_RECURSION(cx, onerror) \
JS_BEGIN_MACRO \

View File

@ -1092,11 +1092,11 @@ MarkConservativeStackRoots(JSTracer *trc, JSRuntime *rt)
uintptr_t *stackMin, *stackEnd;
#if JS_STACK_GROWTH_DIRECTION > 0
stackMin = rt->conservativeGC.nativeStackBase;
stackMin = rt->nativeStackBase;
stackEnd = cgcd->nativeStackTop;
#else
stackMin = cgcd->nativeStackTop + 1;
stackEnd = rt->conservativeGC.nativeStackBase;
stackEnd = reinterpret_cast<uintptr_t *>(rt->nativeStackBase);
#endif
JS_ASSERT(stackMin <= stackEnd);

View File

@ -47,12 +47,12 @@ namespace js {
extern void *
GetNativeStackBaseImpl();
inline uintptr_t *
inline uintptr_t
GetNativeStackBase()
{
void *stackBase = GetNativeStackBaseImpl();
JS_ASSERT(reinterpret_cast<uintptr_t>(stackBase) % sizeof(void *) == 0);
return static_cast<uintptr_t *>(stackBase);
uintptr_t stackBase = reinterpret_cast<uintptr_t>(GetNativeStackBaseImpl());
JS_ASSERT(stackBase % sizeof(void *) == 0);
return stackBase;
}
} /* namespace js */

View File

@ -1332,7 +1332,7 @@ ParseNodeToXML(Parser *parser, ParseNode *pn,
JSXMLClass xml_class;
int stackDummy;
if (!JS_CHECK_STACK_SIZE(cx->stackLimit, &stackDummy)) {
if (!JS_CHECK_STACK_SIZE(cx->runtime->nativeStackLimit, &stackDummy)) {
ReportCompileErrorNumber(cx, &parser->tokenStream, pn, JSREPORT_ERROR,
JSMSG_OVER_RECURSED);
return NULL;

View File

@ -388,7 +388,6 @@ ShellOperationCallback(JSContext *cx)
static void
SetContextOptions(JSContext *cx)
{
JS_SetNativeStackQuota(cx, gMaxStackSize);
JS_SetOperationCallback(cx, ShellOperationCallback);
}
@ -5445,6 +5444,8 @@ main(int argc, char **argv, char **envp)
JS_SetTrustedPrincipals(rt, &shellTrustedPrincipals);
JS_SetRuntimeSecurityCallbacks(rt, &securityCallbacks);
JS_SetNativeStackQuota(rt, gMaxStackSize);
if (!InitWatchdog(rt))
return 1;

View File

@ -446,9 +446,6 @@ mozJSComponentLoader::ReallyInit()
// Always use the latest js version
JS_SetVersion(mContext, JSVERSION_LATEST);
// Limit C stack consumption to a reasonable 512K
JS_SetNativeStackQuota(mContext, 512 * 1024);
nsCOMPtr<nsIScriptSecurityManager> secman =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
if (!secman)

View File

@ -1966,6 +1966,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
// to cause period, and we hope hygienic, last-ditch GCs from within
// the GC's allocator.
JS_SetGCParameter(mJSRuntime, JSGC_MAX_BYTES, 0xffffffff);
JS_SetNativeStackQuota(mJSRuntime, 128 * sizeof(size_t) * 1024);
JS_SetContextCallback(mJSRuntime, ContextCallback);
JS_SetCompartmentCallback(mJSRuntime, CompartmentCallback);
JS_SetGCCallbackRT(mJSRuntime, GCCallback);
@ -2090,8 +2091,6 @@ XPCJSRuntime::OnJSContextNew(JSContext *cx)
if (!xpc)
return false;
JS_SetNativeStackQuota(cx, 128 * sizeof(size_t) * 1024);
// we want to mark the global object ourselves since we use a different color
JS_ToggleOptions(cx, JSOPTION_UNROOTED_GLOBAL);