diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 3866978e7ed3..0491411995db 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -237,33 +237,47 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize) return NULL; #endif - cx = (JSContext *) malloc(sizeof *cx); + /* + * We need to initialize the new context fully before adding it to the + * runtime list. After that it can be accessed from another thread via + * js_ContextIterator. + */ + cx = (JSContext *) calloc(1, sizeof *cx); if (!cx) return NULL; - memset(cx, 0, sizeof *cx); cx->runtime = rt; js_InitOperationLimit(cx); cx->debugHooks = &rt->globalDebugHooks; #if JS_STACK_GROWTH_DIRECTION > 0 - cx->stackLimit = (jsuword)-1; + cx->stackLimit = (jsuword) -1; #endif cx->scriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA; #ifdef JS_THREADSAFE cx->gcLocalFreeLists = (JSGCFreeListSet *) &js_GCEmptyFreeListSet; - - /* - * At this point cx is not on rt->contextList. Thus we do not need to - * prevent a race against the GC when adding cx to JSThread.contextList. - */ js_InitContextThread(cx, thread); #endif + JS_STATIC_ASSERT(JSVERSION_DEFAULT == 0); + JS_ASSERT(cx->version == JSVERSION_DEFAULT); + VOUCH_DOES_NOT_REQUIRE_STACK(); + JS_INIT_ARENA_POOL(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval), + &cx->scriptStackQuota); + + JS_INIT_ARENA_POOL(&cx->tempPool, "temp", + 1024, /* FIXME: bug 421435 */ + sizeof(jsdouble), &cx->scriptStackQuota); + + js_InitRegExpStatics(cx); + JS_ASSERT(cx->resolveFlags == 0); JS_LOCK_GC(rt); for (;;) { first = (rt->contextList.next == &rt->contextList); if (rt->state == JSRTS_UP) { JS_ASSERT(!first); + + /* Ensure that it is safe to update rt->contextList below. */ + js_WaitForGC(rt); break; } if (rt->state == JSRTS_DOWN) { @@ -276,26 +290,6 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize) JS_APPEND_LINK(&cx->link, &rt->contextList); JS_UNLOCK_GC(rt); - /* - * First we do the infallible, every-time per-context initializations. - * Should a later, fallible initialization (js_InitRegExpStatics, e.g., - * or the stuff under 'if (first)' below) fail, at least the version - * and arena-pools will be valid and safe to use (say, from the last GC - * done by js_DestroyContext). - */ - cx->version = JSVERSION_DEFAULT; - VOUCH_DOES_NOT_REQUIRE_STACK(); - JS_INIT_ARENA_POOL(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval), - &cx->scriptStackQuota); - - JS_INIT_ARENA_POOL(&cx->tempPool, "temp", - 1024, /* FIXME: bug 421435 */ - sizeof(jsdouble), &cx->scriptStackQuota); - - js_InitRegExpStatics(cx); - - cx->resolveFlags = 0; - /* * If cx is the first context on this runtime, initialize well-known atoms, * keywords, numbers, and strings. If one of these steps should fail, the @@ -437,16 +431,21 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode) } } - /* Remove cx from context list first. */ JS_LOCK_GC(rt); JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING); +#ifdef JS_THREADSAFE + /* + * Typically we are called outside a request, so ensure that the GC is not + * running before removing the context from rt->contextList, see bug 477021. + */ + if (cx->requestDepth == 0) + js_WaitForGC(rt); + js_RevokeGCLocalFreeLists(cx); +#endif JS_REMOVE_LINK(&cx->link); last = (rt->contextList.next == &rt->contextList); if (last) rt->state = JSRTS_LANDING; -#ifdef JS_THREADSAFE - js_RevokeGCLocalFreeLists(cx); -#endif JS_UNLOCK_GC(rt); if (last) {