jscntxt.c
来自「一个基于alice开发的机器人」· C语言 代码 · 共 703 行 · 第 1/2 页
C
703 行
/* -*- 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;
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_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;
}
void
js_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);
/* 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);
}
JSBool
js_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 void
ReportError(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
js_ReportOutOfMemory(JSContext *cx, JSErrorCallback callback)
{
JSStackFrame *fp;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?