📄 jscntxt.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** 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 "jsscript.h"#include "jsstr.h"JSContext *js_NewContext(JSRuntime *rt, size_t stackChunkSize){ JSContext *cx; JSBool ok, first; 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_InitContextForLocking(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; cx->caseSensitive = JS_TRUE; JS_InitArenaPool(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval)); JS_InitArenaPool(&cx->tempPool, "temp", 1024, sizeof(jsdouble));#if JS_HAS_REGEXPS if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) { js_DestroyContext(cx, JS_NO_GC); return NULL; }#endif#if JS_HAS_EXCEPTIONS cx->throwing = JS_FALSE;#endif /* * 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) { ok = (rt->atomState.liveAtoms == 0) ? js_InitAtomState(cx, &rt->atomState) : js_InitPinnedAtoms(cx, &rt->atomState); if (ok) ok = js_InitScanner(cx); if (ok) ok = js_InitRuntimeNumberState(cx); if (ok) ok = js_InitRuntimeScriptState(cx); if (ok) ok = js_InitRuntimeStringState(cx); if (!ok) { js_DestroyContext(cx, JS_NO_GC); return NULL; } JS_LOCK_GC(rt); rt->state = JSRTS_UP; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); JS_UNLOCK_GC(rt); } return cx;}voidjs_DestroyContext(JSContext *cx, JSGCMode gcmode){ JSRuntime *rt; JSBool last; JSArgumentFormatMap *map; rt = cx->runtime; /* 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); }#if JS_HAS_REGEXPS /* * 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);#endif#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) { /* Always force, so we wait for any racing GC to finish. */ js_ForceGC(cx, GC_LAST_CONTEXT); /* Iterate until no finalizer removes a GC root or lock. */ while (rt->gcPoke) 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); /* Now after the last GC can we free the script filename table. */ js_FinishRuntimeScriptState(cx); /* 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 (gcmode == JS_FORCE_GC) js_ForceGC(cx, 0); else if (gcmode == JS_MAYBE_GC) JS_MaybeGC(cx); } /* Free the stuff hanging off of cx. */ JS_FinishArenaPool(&cx->stackPool); JS_FinishArenaPool(&cx->tempPool); if (cx->lastMessage) free(cx->lastMessage); /* Remove any argument formatters. */ map = cx->argumentFormatMap; while (map) { JSArgumentFormatMap *temp = map; map = map->next; JS_free(cx, temp); } /* Destroy the resolve recursion damper. */ if (cx->resolvingTable) { JS_DHashTableDestroy(cx->resolvingTable); cx->resolvingTable = NULL; } /* Finally, free cx itself. */ free(cx);}JSBooljs_ValidContextPointer(JSRuntime *rt, JSContext *cx){ JSCList *cl; for (cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next) { if (cl == &cx->links) return JS_TRUE; } JS_RUNTIME_METER(rt, deadContexts); return JS_FALSE;}JSContext *js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp){ JSContext *cx = *iterp; if (unlocked) JS_LOCK_GC(rt); if (!cx) cx = (JSContext *)&rt->contextList; cx = (JSContext *)cx->links.next; if (&cx->links == &rt->contextList) cx = NULL; *iterp = cx; if (unlocked) JS_UNLOCK_GC(rt); return cx;}static voidReportError(JSContext *cx, const char *message, JSErrorReport *reportp){ /* * Check the error report, and set a JavaScript-catchable exception * if the error is defined to have an associated exception. If an * exception is thrown, then the JSREPORT_EXCEPTION flag will be set * on the error report, and exception-aware hosts should ignore it. */ if (reportp && reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION) reportp->flags |= JSREPORT_EXCEPTION;#if JS_HAS_ERROR_EXCEPTIONS /* * Call the error reporter only if an exception wasn't raised. * * If an exception was raised, then we call the debugErrorHook * (if present) to give it a chance to see the error before it * propagates out of scope. This is needed for compatability * with the old scheme. */ if (!js_ErrorToException(cx, message, reportp)) { js_ReportErrorAgain(cx, message, reportp); } else if (cx->runtime->debugErrorHook && cx->errorReporter) { JSDebugErrorHook hook = cx->runtime->debugErrorHook; /* test local in case debugErrorHook changed on another thread */ if (hook) hook(cx, message, reportp, cx->runtime->debugErrorHookData); }#else js_ReportErrorAgain(cx, message, reportp);#endif}/* * We don't post an exception in this case, since doing so runs into * complications of pre-allocating an exception object which required * running the Exception class initializer early etc. * Instead we just invoke the errorReporter with an "Out Of Memory" * type message, and then hope the process ends swiftly. */void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -