📄 jscntxt.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sw=4 et tw=80: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//* * JS execution context. */#include "jsstddef.h"#include <stdarg.h>#include <stdlib.h>#include <string.h>#include "jstypes.h"#include "jsarena.h" /* Added by JSIFY */#include "jsutil.h" /* Added by JSIFY */#include "jsclist.h"#include "jsprf.h"#include "jsatom.h"#include "jscntxt.h"#include "jsconfig.h"#include "jsdbgapi.h"#include "jsexn.h"#include "jsgc.h"#include "jslock.h"#include "jsnum.h"#include "jsobj.h"#include "jsopcode.h"#include "jsscan.h"#include "jsscope.h"#include "jsscript.h"#include "jsstr.h"#ifdef JS_THREADSAFE/* * Callback function to delete a JSThread info when the thread that owns it * is destroyed. */void JS_DLL_CALLBACKjs_ThreadDestructorCB(void *ptr){ JSThread *thread = (JSThread *)ptr; if (!thread) return; while (!JS_CLIST_IS_EMPTY(&thread->contextList)) { /* NB: use a temporary, as the macro evaluates its args many times. */ JSCList *link = thread->contextList.next; JS_REMOVE_AND_INIT_LINK(link); } GSN_CACHE_CLEAR(&thread->gsnCache); free(thread);}/* * Get current thread-local JSThread info, creating one if it doesn't exist. * Each thread has a unique JSThread pointer. * * Since we are dealing with thread-local data, no lock is needed. * * Return a pointer to the thread local info, NULL if the system runs out * of memory, or it failed to set thread private data (neither case is very * likely; both are probably due to out-of-memory). It is up to the caller * to report an error, if possible. */JSThread *js_GetCurrentThread(JSRuntime *rt){ JSThread *thread; thread = (JSThread *)PR_GetThreadPrivate(rt->threadTPIndex); if (!thread) { thread = (JSThread *) calloc(1, sizeof(JSThread)); if (!thread) return NULL; if (PR_FAILURE == PR_SetThreadPrivate(rt->threadTPIndex, thread)) { free(thread); return NULL; } JS_INIT_CLIST(&thread->contextList); thread->id = js_CurrentThreadId(); /* js_SetContextThread initialize gcFreeLists as necessary. */#ifdef DEBUG memset(thread->gcFreeLists, JS_FREE_PATTERN, sizeof(thread->gcFreeLists));#endif } return thread;}/* * Sets current thread as owning thread of a context by assigning the * thread-private info to the context. If the current thread doesn't have * private JSThread info, create one. */JSBooljs_SetContextThread(JSContext *cx){ JSThread *thread = js_GetCurrentThread(cx->runtime); if (!thread) { JS_ReportOutOfMemory(cx); return JS_FALSE; } /* * Clear gcFreeLists on each transition from 0 to 1 context active on the * current thread. See bug 351602. */ if (JS_CLIST_IS_EMPTY(&thread->contextList)) memset(thread->gcFreeLists, 0, sizeof(thread->gcFreeLists)); cx->thread = thread; JS_REMOVE_LINK(&cx->threadLinks); JS_APPEND_LINK(&cx->threadLinks, &thread->contextList); return JS_TRUE;}/* Remove the owning thread info of a context. */voidjs_ClearContextThread(JSContext *cx){ JS_REMOVE_AND_INIT_LINK(&cx->threadLinks);#ifdef DEBUG if (JS_CLIST_IS_EMPTY(&cx->thread->contextList)) { memset(cx->thread->gcFreeLists, JS_FREE_PATTERN, sizeof(cx->thread->gcFreeLists)); }#endif cx->thread = NULL;}#endif /* JS_THREADSAFE */voidjs_OnVersionChange(JSContext *cx){#ifdef DEBUG JSVersion version = JSVERSION_NUMBER(cx); JS_ASSERT(version == JSVERSION_DEFAULT || version >= JSVERSION_ECMA_3);#endif}voidjs_SetVersion(JSContext *cx, JSVersion version){ cx->version = version; js_OnVersionChange(cx);}JSContext *js_NewContext(JSRuntime *rt, size_t stackChunkSize){ JSContext *cx; JSBool ok, first; JSContextCallback cxCallback; cx = (JSContext *) malloc(sizeof *cx); if (!cx) return NULL; memset(cx, 0, sizeof *cx); cx->runtime = rt;#if JS_STACK_GROWTH_DIRECTION > 0 cx->stackLimit = (jsuword)-1;#endif#ifdef JS_THREADSAFE JS_INIT_CLIST(&cx->threadLinks); js_SetContextThread(cx);#endif JS_LOCK_GC(rt); for (;;) { first = (rt->contextList.next == &rt->contextList); if (rt->state == JSRTS_UP) { JS_ASSERT(!first); break; } if (rt->state == JSRTS_DOWN) { JS_ASSERT(first); rt->state = JSRTS_LAUNCHING; break; } JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT); } JS_APPEND_LINK(&cx->links, &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; cx->jsop_eq = JSOP_EQ; cx->jsop_ne = JSOP_NE; JS_InitArenaPool(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval)); JS_InitArenaPool(&cx->tempPool, "temp", 1024, sizeof(jsdouble)); if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) { js_DestroyContext(cx, JSDCM_NEW_FAILED); return NULL; } /* * 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 * runtime will be left in a partially initialized state, with zeroes and * nulls stored in the default-initialized remainder of the struct. We'll * clean the runtime up under js_DestroyContext, because cx will be "last" * as well as "first". */ if (first) {#ifdef JS_THREADSAFE JS_BeginRequest(cx);#endif /* * Both atomState and the scriptFilenameTable may be left over from a * previous episode of non-zero contexts alive in rt, so don't re-init * either table if it's not necessary. Just repopulate atomState with * well-known internal atoms, and with the reserved identifiers added * by the scanner. */ ok = (rt->atomState.liveAtoms == 0) ? js_InitAtomState(cx, &rt->atomState) : js_InitPinnedAtoms(cx, &rt->atomState); if (ok && !rt->scriptFilenameTable) ok = js_InitRuntimeScriptState(rt); if (ok) ok = js_InitRuntimeNumberState(cx); if (ok) ok = js_InitRuntimeStringState(cx);#ifdef JS_THREADSAFE JS_EndRequest(cx);#endif if (!ok) { js_DestroyContext(cx, JSDCM_NEW_FAILED); return NULL; } JS_LOCK_GC(rt); rt->state = JSRTS_UP; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); JS_UNLOCK_GC(rt); } cxCallback = rt->cxCallback; if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) { js_DestroyContext(cx, JSDCM_NEW_FAILED); return NULL; } return cx;}voidjs_DestroyContext(JSContext *cx, JSDestroyContextMode mode){ JSRuntime *rt; JSContextCallback cxCallback; JSBool last; JSArgumentFormatMap *map; JSLocalRootStack *lrs; JSLocalRootChunk *lrc; rt = cx->runtime; if (mode != JSDCM_NEW_FAILED) { cxCallback = rt->cxCallback; if (cxCallback) { /* * JSCONTEXT_DESTROY callback is not allowed to fail and must * return true. */#ifdef DEBUG JSBool callbackStatus =#endif cxCallback(cx, JSCONTEXT_DESTROY); JS_ASSERT(callbackStatus); } } /* Remove cx from context list first. */ JS_LOCK_GC(rt); JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING); JS_REMOVE_LINK(&cx->links); last = (rt->contextList.next == &rt->contextList); if (last) rt->state = JSRTS_LANDING; JS_UNLOCK_GC(rt); if (last) {#ifdef JS_THREADSAFE /* * If cx is not in a request already, begin one now so that we wait * for any racing GC started on a not-last context to finish, before * we plow ahead and unpin atoms. Note that even though we begin a * request here if necessary, we end all requests on cx below before * forcing a final GC. This lets any not-last context destruction * racing in another thread try to force or maybe run the GC, but by * that point, rt->state will not be JSRTS_UP, and that GC attempt * will return early. */ if (cx->requestDepth == 0) JS_BeginRequest(cx);#endif /* Unpin all pinned atoms before final GC. */ js_UnpinPinnedAtoms(&rt->atomState); /* Unlock and clear GC things held by runtime pointers. */ js_FinishRuntimeNumberState(cx); js_FinishRuntimeStringState(cx); /* Clear debugging state to remove GC roots. */ JS_ClearAllTraps(cx); JS_ClearAllWatchPoints(cx); } /* * Remove more GC roots in regExpStatics, then collect garbage. * XXX anti-modularity alert: we rely on the call to js_RemoveRoot within * XXX this function call to wait for any racing GC to complete, in the * XXX case where JS_DestroyContext is called outside of a request on cx */ js_FreeRegExpStatics(cx, &cx->regExpStatics);#ifdef JS_THREADSAFE /* * Destroying a context implicitly calls JS_EndRequest(). Also, we must * end our request here in case we are "last" -- in that event, another * js_DestroyContext that was not last might be waiting in the GC for our * request to end. We'll let it run below, just before we do the truly * final GC and then free atom state. * * At this point, cx must be inaccessible to other threads. It's off the * rt->contextList, and it should not be reachable via any object private * data structure. */ while (cx->requestDepth != 0) JS_EndRequest(cx);#endif if (last) { js_GC(cx, GC_LAST_CONTEXT); /* Try to free atom state, now that no unrooted scripts survive. */ if (rt->atomState.liveAtoms == 0) js_FreeAtomState(cx, &rt->atomState); /* Also free the script filename table if it exists and is empty. */ if (rt->scriptFilenameTable && rt->scriptFilenameTable->nentries == 0) js_FinishRuntimeScriptState(rt); /* * Free the deflated string cache, but only after the last GC has * collected all unleaked strings. */ js_FinishDeflatedStringCache(rt); /* Take the runtime down, now that it has no contexts or atoms. */ JS_LOCK_GC(rt); rt->state = JSRTS_DOWN; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); JS_UNLOCK_GC(rt); } else { if (mode == JSDCM_FORCE_GC) js_GC(cx, GC_NORMAL); else if (mode == JSDCM_MAYBE_GC)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -