Bug 460865 - Read barrier for cx->fp. r=mrbkap, r=dmandelin.

--HG--
extra : rebase_source : 19963188b2f9f96336ce6ca28dbaefccf3a639b7
This commit is contained in:
Jason Orendorff 2008-12-09 10:38:32 -06:00
Родитель 429817d57b
Коммит c499e81946
37 изменённых файлов: 852 добавлений и 594 удалений

Просмотреть файл

@ -11,6 +11,7 @@ TREEHYDRA_MODULES = \
$(topsrcdir)/xpcom/analysis/outparams.js \
$(topsrcdir)/xpcom/analysis/stack.js \
$(topsrcdir)/xpcom/analysis/flow.js \
$(topsrcdir)/xpcom/analysis/jsstack.js \
$(NULL)
DEHYDRA_ARGS = \

Просмотреть файл

@ -6452,8 +6452,9 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
// binding a name) a new undefined property that's not already
// defined on our prototype chain. This way we can access this
// expando w/o ever getting back into XPConnect.
JSStackFrame *fp = NULL;
if ((flags & (JSRESOLVE_ASSIGNING)) &&
!(cx->fp && cx->fp->regs && (JSOp)*cx->fp->regs->pc == JSOP_BINDNAME) &&
!(JS_FrameIterator(cx, &fp) && fp->regs && (JSOp)*fp->regs->pc == JSOP_BINDNAME) &&
win->IsInnerWindow()) {
JSObject *realObj;
wrapper->GetJSObject(&realObj);

Просмотреть файл

@ -3325,7 +3325,7 @@ nsresult
nsJSContext::SetTerminationFunction(nsScriptTerminationFunc aFunc,
nsISupports* aRef)
{
NS_PRECONDITION(mContext->fp, "should be executing script");
NS_PRECONDITION(JS_IsRunning(mContext), "should be executing script");
nsJSContext::TerminationFuncClosure* newClosure =
new nsJSContext::TerminationFuncClosure(aFunc, aRef, mTerminations);

Просмотреть файл

@ -215,6 +215,7 @@ INSTALLED_HEADERS = \
jsscan.h \
jsscope.h \
jsscript.h \
jsstaticcheck.h \
jsstddef.h \
jsstr.h \
jstracer.h \

Просмотреть файл

@ -1118,7 +1118,7 @@ GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp,
uintN intarg;
JSScript *script;
*scriptp = cx->fp->down->script;
*scriptp = JS_GetScriptedCaller(cx, NULL)->script;
*ip = 0;
if (argc != 0) {
v = argv[0];
@ -1205,7 +1205,7 @@ LineToPC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
return JS_FALSE;
}
script = cx->fp->down->script;
script = JS_GetScriptedCaller(cx, NULL)->script;
if (!GetTrapArgs(cx, argc, argv, &script, &i))
return JS_FALSE;
lineno = (i == 0) ? script->lineno : (uintN)i;

Просмотреть файл

@ -79,6 +79,7 @@
#include "jsscope.h"
#include "jsscript.h"
#include "jsstr.h"
#include "jsdbgapi.h"
#include "prmjtime.h"
#include "jsstaticcheck.h"
@ -1803,7 +1804,7 @@ JS_GetScopeChain(JSContext *cx)
JSStackFrame *fp;
CHECK_REQUEST(cx);
fp = cx->fp;
fp = js_GetTopStackFrame(cx);
if (!fp) {
/*
* There is no code active on this context. In place of an actual
@ -4575,10 +4576,10 @@ js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
* Follow Function.prototype.apply and .call by using the global object as
* the 'this' param if no args.
*/
JS_ASSERT(cx->fp->argv == argv);
if (!js_ComputeThis(cx, JS_TRUE, argv))
return JS_FALSE;
cx->fp->thisp = JSVAL_TO_OBJECT(argv[-1]);
js_GetTopStackFrame(cx)->thisp = JSVAL_TO_OBJECT(argv[-1]);
JS_ASSERT(cx->fp->argv == argv);
/*
* Protect against argc underflowing. By calling js_ComputeThis, we made
@ -4725,7 +4726,7 @@ JS_CompileUCScript(JSContext *cx, JSObject *obj,
#define LAST_FRAME_CHECKS(cx,result) \
JS_BEGIN_MACRO \
if (!(cx)->fp) { \
if (!JS_IsRunning(cx)) { \
(cx)->weakRoots.lastInternalResult = JSVAL_NULL; \
LAST_FRAME_EXCEPTION_CHECK(cx, result); \
} \
@ -5324,13 +5325,19 @@ JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
JS_PUBLIC_API(JSBool)
JS_IsRunning(JSContext *cx)
{
return cx->fp != NULL;
/* The use of cx->fp below is safe: if we're on trace, it is skipped. */
VOUCH_DOES_NOT_REQUIRE_STACK();
return JS_ON_TRACE(cx) || cx->fp != NULL;
}
JS_PUBLIC_API(JSBool)
JS_IsConstructing(JSContext *cx)
{
return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING);
JSStackFrame *fp;
fp = js_GetTopStackFrame(cx);
return fp && (fp->flags & JSFRAME_CONSTRUCTING);
}
JS_FRIEND_API(JSBool)
@ -5338,8 +5345,7 @@ JS_IsAssigning(JSContext *cx)
{
JSStackFrame *fp;
for (fp = cx->fp; fp && !fp->script; fp = fp->down)
continue;
fp = js_GetScriptedCaller(cx, NULL);
if (!fp || !fp->regs)
return JS_FALSE;
return (js_CodeSpec[*fp->regs->pc].format & JOF_ASSIGNING) != 0;
@ -5359,7 +5365,7 @@ JS_SaveFrameChain(JSContext *cx)
{
JSStackFrame *fp;
fp = cx->fp;
fp = js_GetTopStackFrame(cx);
if (!fp)
return fp;
@ -5373,6 +5379,8 @@ JS_SaveFrameChain(JSContext *cx)
JS_PUBLIC_API(void)
JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
{
JS_ASSERT(!JS_ON_TRACE(cx));
VOUCH_DOES_NOT_REQUIRE_STACK();
JS_ASSERT(!cx->fp);
if (!fp)
return;
@ -5984,7 +5992,7 @@ JS_PUBLIC_API(JSBool)
JS_ThrowReportedError(JSContext *cx, const char *message,
JSErrorReport *reportp)
{
return cx->fp && js_ErrorToException(cx, message, reportp);
return JS_IsRunning(cx) && js_ErrorToException(cx, message, reportp);
}
JS_PUBLIC_API(JSBool)

Просмотреть файл

@ -3029,7 +3029,7 @@ js_Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
jsval *vector;
/* If called without new, replace obj with a new Array object. */
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
if (!JS_IsConstructing(cx)) {
obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL, 0);
if (!obj)
return JS_FALSE;

Просмотреть файл

@ -133,7 +133,7 @@ Boolean(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
bval = (argc != 0)
? BOOLEAN_TO_JSVAL(js_ValueToBoolean(argv[0]))
: JSVAL_FALSE;
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
if (!JS_IsConstructing(cx)) {
*rval = bval;
return JS_TRUE;
}

Просмотреть файл

@ -889,7 +889,7 @@ ReportError(JSContext *cx, const char *message, JSErrorReport *reportp)
* propagates out of scope. This is needed for compatability
* with the old scheme.
*/
if (!cx->fp || !js_ErrorToException(cx, message, reportp)) {
if (!JS_IsRunning(cx) || !js_ErrorToException(cx, message, reportp)) {
js_ReportErrorAgain(cx, message, reportp);
} else if (cx->debugHooks->debugErrorHook && cx->errorReporter) {
JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
@ -899,6 +899,25 @@ ReportError(JSContext *cx, const char *message, JSErrorReport *reportp)
}
}
/* The report must be initially zeroed. */
static void
PopulateReportBlame(JSContext *cx, JSErrorReport *report)
{
JSStackFrame *fp;
/*
* Walk stack until we find a frame that is associated with some script
* rather than a native frame.
*/
for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
if (fp->regs) {
report->filename = fp->script->filename;
report->lineno = js_FramePCToLineNumber(cx, fp);
break;
}
}
}
/*
* We don't post an exception in this case, since doing so runs into
* complications of pre-allocating an exception object which required
@ -909,7 +928,6 @@ ReportError(JSContext *cx, const char *message, JSErrorReport *reportp)
void
js_ReportOutOfMemory(JSContext *cx)
{
JSStackFrame *fp;
JSErrorReport report;
JSErrorReporter onError = cx->errorReporter;
@ -922,18 +940,7 @@ js_ReportOutOfMemory(JSContext *cx)
memset(&report, 0, sizeof (struct JSErrorReport));
report.flags = JSREPORT_ERROR;
report.errorNumber = JSMSG_OUT_OF_MEMORY;
/*
* Walk stack until we find a frame that is associated with some script
* rather than a native frame.
*/
for (fp = cx->fp; fp; fp = fp->down) {
if (fp->regs) {
report.filename = fp->script->filename;
report.lineno = js_FramePCToLineNumber(cx, fp);
break;
}
}
PopulateReportBlame(cx, &report);
/*
* If debugErrorHook is present then we give it a chance to veto sending
@ -979,7 +986,6 @@ js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap)
char *message;
jschar *ucmessage;
size_t messagelen;
JSStackFrame *fp;
JSErrorReport report;
JSBool warning;
@ -995,15 +1001,7 @@ js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap)
report.flags = flags;
report.errorNumber = JSMSG_USER_DEFINED_ERROR;
report.ucmessage = ucmessage = js_InflateString(cx, message, &messagelen);
/* Find the top-most active script frame, for best line number blame. */
for (fp = cx->fp; fp; fp = fp->down) {
if (fp->regs) {
report.filename = fp->script->filename;
report.lineno = js_FramePCToLineNumber(cx, fp);
break;
}
}
PopulateReportBlame(cx, &report);
warning = JSREPORT_IS_WARNING(report.flags);
if (warning && JS_HAS_WERROR_OPTION(cx)) {
@ -1193,7 +1191,6 @@ js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
void *userRef, const uintN errorNumber,
JSBool charArgs, va_list ap)
{
JSStackFrame *fp;
JSErrorReport report;
char *message;
JSBool warning;
@ -1204,18 +1201,7 @@ js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
memset(&report, 0, sizeof (struct JSErrorReport));
report.flags = flags;
report.errorNumber = errorNumber;
/*
* If we can't find out where the error was based on the current frame,
* see if the next frame has a script/pc combo we can use.
*/
for (fp = cx->fp; fp; fp = fp->down) {
if (fp->regs) {
report.filename = fp->script->filename;
report.lineno = js_FramePCToLineNumber(cx, fp);
break;
}
}
PopulateReportBlame(cx, &report);
if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
&message, &report, &warning, charArgs, ap)) {
@ -1382,6 +1368,7 @@ JSBool
js_ResetOperationCount(JSContext *cx)
{
JSScript *script;
JSStackFrame *fp;
JS_ASSERT(cx->operationCount <= 0);
JS_ASSERT(cx->operationLimit > 0);
@ -1396,9 +1383,32 @@ js_ResetOperationCount(JSContext *cx)
* the top-most frame is scripted or JSOPTION_NATIVE_BRANCH_CALLBACK
* is set.
*/
script = cx->fp ? cx->fp->script : NULL;
fp = js_GetTopStackFrame(cx);
script = fp ? fp->script : NULL;
if (script || JS_HAS_OPTION(cx, JSOPTION_NATIVE_BRANCH_CALLBACK))
return ((JSBranchCallback) cx->operationCallback)(cx, script);
}
return JS_TRUE;
}
#ifndef JS_TRACER
/* This is defined in jstracer.cpp in JS_TRACER builds. */
extern JS_FORCES_STACK JSStackFrame *
js_GetTopStackFrame(JSContext *cx)
{
return cx->fp;
}
#endif
JSStackFrame *
js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
{
if (!fp)
fp = js_GetTopStackFrame(cx);
while (fp) {
if (fp->script)
return fp;
fp = fp->down;
}
return NULL;
}

Просмотреть файл

@ -139,9 +139,11 @@ typedef struct JSTraceMonitor {
} JSTraceMonitor;
#ifdef JS_TRACER
# define JS_ON_TRACE(cx) (JS_TRACE_MONITOR(cx).onTrace)
# define JS_ON_TRACE(cx) (JS_TRACE_MONITOR(cx).onTrace)
# define JS_EXECUTING_TRACE(cx) (JS_ON_TRACE(cx) && !JS_TRACE_MONITOR(cx).recorder)
#else
# define JS_ON_TRACE(cx) JS_FALSE
# define JS_ON_TRACE(cx) JS_FALSE
# define JS_EXECUTING_TRACE(cx) JS_FALSE
#endif
#ifdef JS_THREADSAFE
@ -814,6 +816,8 @@ struct JSContext {
/* Stack arena pool and frame pointer register. */
JSArenaPool stackPool;
JS_REQUIRES_STACK
JSStackFrame *fp;
/* Temporary arena pool used while compiling and decompiling. */
@ -1251,6 +1255,18 @@ extern JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
extern JSBool
js_ResetOperationCount(JSContext *cx);
/*
* Get the current cx->fp, first lazily instantiating stack frames if needed.
* (Do not access cx->fp directly except in JS_REQUIRES_STACK code.)
*
* Defined in jstracer.cpp if JS_TRACER is defined.
*/
extern JS_FORCES_STACK JSStackFrame *
js_GetTopStackFrame(JSContext *cx);
extern JSStackFrame *
js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp);
JS_END_EXTERN_C
#endif /* jscntxt_h___ */

Просмотреть файл

@ -2104,7 +2104,7 @@ js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
jsdouble d;
/* Date called as function. */
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
if (!JS_IsConstructing(cx)) {
return date_format(cx, PRMJ_Now() / PRMJ_USEC_PER_MSEC,
FORMATSPEC_FULL, rval);
}

Просмотреть файл

@ -640,7 +640,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
frame.callee = closure;
frame.fun = fun;
frame.argv = argv + 2;
frame.down = cx->fp;
frame.down = js_GetTopStackFrame(cx);
frame.scopeChain = OBJ_GET_PARENT(cx, closure);
cx->fp = &frame;
@ -975,7 +975,7 @@ JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
JS_PUBLIC_API(JSStackFrame *)
JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
{
*iteratorp = (*iteratorp == NULL) ? cx->fp : (*iteratorp)->down;
*iteratorp = (*iteratorp == NULL) ? js_GetTopStackFrame(cx) : (*iteratorp)->down;
return *iteratorp;
}
@ -994,14 +994,7 @@ JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
JS_PUBLIC_API(JSStackFrame *)
JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
{
if (!fp)
fp = cx->fp;
while (fp) {
if (fp->script)
return fp;
fp = fp->down;
}
return NULL;
return js_GetScriptedCaller(cx, fp);
}
JS_PUBLIC_API(JSPrincipals *)
@ -1124,7 +1117,7 @@ JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
return fp->thisp;
/* js_ComputeThis gets confused if fp != cx->fp, so set it aside. */
if (cx->fp != fp) {
if (js_GetTopStackFrame(cx) != fp) {
afp = cx->fp;
if (afp) {
afp->dormantNext = cx->dormantFrameChain;
@ -1633,7 +1626,7 @@ JS_PUBLIC_API(uint32)
JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
{
if (!fp)
fp = cx->fp;
fp = js_GetTopStackFrame(cx);
while (fp) {
if (fp->script)
return JS_GetScriptFilenameFlags(fp->script);

Просмотреть файл

@ -280,7 +280,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
callerid = ATOM_KEY(cx->runtime->atomState.callerAtom);
stackDepth = 0;
valueCount = 0;
for (fp = cx->fp; fp; fp = fp->down) {
for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
if (fp->fun && fp->argv) {
v = JSVAL_NULL;
if (checkAccess &&
@ -321,7 +321,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
values = GetStackTraceValueBuffer(priv);
elem = priv->stackElems;
for (fp = cx->fp; fp != fpstop; fp = fp->down) {
for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->down) {
if (!fp->fun) {
elem->funName = NULL;
elem->argc = 0;
@ -742,7 +742,7 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSString *message, *filename;
JSStackFrame *fp;
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
if (!JS_IsConstructing(cx)) {
/*
* ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
* called as functions, without operator new. But as we do not give
@ -786,7 +786,7 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
argv[1] = STRING_TO_JSVAL(filename);
fp = NULL;
} else {
fp = JS_GetScriptedCaller(cx, NULL);
fp = js_GetScriptedCaller(cx, NULL);
if (fp) {
filename = FilenameToString(cx, fp->script->filename);
if (!filename)
@ -803,7 +803,7 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_FALSE;
} else {
if (!fp)
fp = JS_GetScriptedCaller(cx, NULL);
fp = js_GetScriptedCaller(cx, NULL);
lineno = (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0;
}

Просмотреть файл

@ -2181,7 +2181,7 @@ file_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSString *str;
JSFile *file;
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
if (!JS_IsConstructing(cx)) {
/* Replace obj with a new File object. */
obj = JS_NewObject(cx, &js_FileClass, NULL, NULL);
if (!obj)

Просмотреть файл

@ -1005,7 +1005,8 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
}
/* Find fun's top-most activation record. */
for (fp = cx->fp; fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));
for (fp = js_GetTopStackFrame(cx);
fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));
fp = fp->down) {
continue;
}
@ -1797,9 +1798,9 @@ static JSFunctionSpec function_methods[] = {
static JSBool
Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
JSStackFrame *fp, *caller;
JSFunction *fun;
JSObject *parent;
JSStackFrame *fp, *caller;
uintN i, n, lineno;
JSAtom *atom;
const char *filename;
@ -1812,8 +1813,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
size_t arg_length, args_length, old_args_length;
JSTokenType tt;
fp = cx->fp;
if (!(fp->flags & JSFRAME_CONSTRUCTING)) {
if (!JS_IsConstructing(cx)) {
obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL, 0);
if (!obj)
return JS_FALSE;
@ -1852,8 +1852,9 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
* are built for Function.prototype.call or .apply activations that invoke
* Function indirectly from a script.
*/
fp = js_GetTopStackFrame(cx);
JS_ASSERT(!fp->script && fp->fun && fp->fun->u.n.native == Function);
caller = JS_GetScriptedCaller(cx, fp);
caller = js_GetScriptedCaller(cx, fp);
if (caller) {
principals = JS_EvalFramePrincipals(cx, fp, caller);
filename = js_ComputeFilename(cx, caller, principals, &lineno);
@ -2202,7 +2203,7 @@ js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags)
return NULL;
*vp = OBJECT_TO_JSVAL(FUN_OBJECT(fun));
caller = JS_GetScriptedCaller(cx, cx->fp);
caller = js_GetScriptedCaller(cx, NULL);
if (caller) {
principals = JS_StackFramePrincipals(cx, caller);
} else {
@ -2244,7 +2245,7 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
const char *name, *source;
JSTempValueRooter tvr;
for (fp = cx->fp; fp && !fp->regs; fp = fp->down)
for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down)
continue;
name = source = NULL;
JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &tvr);

Просмотреть файл

@ -2930,7 +2930,7 @@ js_TraceContext(JSTracer *trc, JSContext *acx)
*
* (NB: see comment on this whole "dormant" thing in js_Execute.)
*/
fp = acx->fp;
fp = js_GetTopStackFrame(acx);
nextChain = acx->dormantFrameChain;
if (!fp)
goto next_chain;

Просмотреть файл

@ -109,7 +109,7 @@ js_GenerateShape(JSContext *cx, JSBool gcLocked, JSScopeProperty *sprop)
return shape;
}
void
JS_REQUIRES_STACK void
js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
uintN scopeIndex, uintN protoIndex,
JSObject *pobj, JSScopeProperty *sprop,
@ -301,7 +301,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
PCMETER(cache->fills++);
}
JSAtom *
JS_REQUIRES_STACK JSAtom *
js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
JSObject **objp, JSObject **pobjp,
JSPropCacheEntry **entryp)
@ -802,7 +802,7 @@ js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv)
* imposes a performance penalty on all js_ComputeGlobalThis calls,
* and it represents a maintenance hazard.
*/
fp = cx->fp; /* quell GCC overwarning */
fp = js_GetTopStackFrame(cx); /* quell GCC overwarning */
if (lazy) {
JS_ASSERT(fp->argv == argv);
fp->dormantNext = cx->dormantFrameChain;
@ -1262,7 +1262,7 @@ have_fun:
/* Default return value for a constructor is the new object. */
frame.rval = (flags & JSINVOKE_CONSTRUCT) ? vp[1] : JSVAL_VOID;
frame.down = cx->fp;
frame.down = js_GetTopStackFrame(cx);
frame.annotation = NULL;
frame.scopeChain = NULL; /* set below for real, after cx->fp is set */
frame.regs = NULL;
@ -1466,7 +1466,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
hook = cx->debugHooks->executeHook;
hookData = mark = NULL;
oldfp = cx->fp;
oldfp = js_GetTopStackFrame(cx);
frame.script = script;
if (down) {
/* Propagate arg state for eval and the debugger API. */
@ -1833,7 +1833,7 @@ js_InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp)
* Enter the new with scope using an object at sp[-1] and associate the depth
* of the with block with sp + stackIndex.
*/
JS_STATIC_INTERPRET JSBool
JS_STATIC_INTERPRET JS_REQUIRES_STACK JSBool
js_EnterWith(JSContext *cx, jsint stackIndex)
{
JSStackFrame *fp;
@ -1872,7 +1872,7 @@ js_EnterWith(JSContext *cx, jsint stackIndex)
return JS_TRUE;
}
JS_STATIC_INTERPRET void
JS_STATIC_INTERPRET JS_REQUIRES_STACK void
js_LeaveWith(JSContext *cx)
{
JSObject *withobj;
@ -1886,7 +1886,7 @@ js_LeaveWith(JSContext *cx)
js_EnablePropertyCache(cx);
}
JSClass *
JS_REQUIRES_STACK JSClass *
js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth)
{
JSClass *clasp;
@ -1900,7 +1900,7 @@ js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth)
return NULL;
}
JS_STATIC_INTERPRET jsint
JS_STATIC_INTERPRET JS_REQUIRES_STACK jsint
js_CountWithBlocks(JSContext *cx, JSStackFrame *fp)
{
jsint n;
@ -1921,7 +1921,7 @@ js_CountWithBlocks(JSContext *cx, JSStackFrame *fp)
* Unwind block and scope chains to match the given depth. The function sets
* fp->sp on return to stackDepth.
*/
JSBool
JS_REQUIRES_STACK JSBool
js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth,
JSBool normalUnwind)
{
@ -1991,7 +1991,7 @@ js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2)
#ifdef DEBUG
JS_STATIC_INTERPRET void
JS_STATIC_INTERPRET JS_REQUIRES_STACK void
js_TraceOpcode(JSContext *cx, jsint len)
{
FILE *tracefp;
@ -2443,7 +2443,7 @@ JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_DECNAME_LENGTH);
JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEINC_LENGTH);
JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEDEC_LENGTH);
JSBool
JS_REQUIRES_STACK JSBool
js_Interpret(JSContext *cx)
{
JSRuntime *rt;

Просмотреть файл

@ -295,7 +295,7 @@ typedef struct JSPropertyCache {
* from obj and sprop, and entry capability forged from 24-bit OBJ_SHAPE(obj),
* 4-bit scopeIndex, and 4-bit protoIndex.
*/
extern void
extern JS_REQUIRES_STACK void
js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
uintN scopeIndex, uintN protoIndex,
JSObject *pobj, JSScopeProperty *sprop,
@ -350,7 +350,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
PCMETER(cache_->misses++); \
} while (0)
extern JSAtom *
extern JS_REQUIRES_STACK JSAtom *
js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
JSObject **objp, JSObject **pobjp,
JSPropCacheEntry **entryp);
@ -473,7 +473,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
extern JSBool
js_InvokeConstructor(JSContext *cx, uintN argc, JSBool clampReturn, jsval *vp);
extern JSBool
extern JS_REQUIRES_STACK JSBool
js_Interpret(JSContext *cx);
#define JSPROP_INITIALIZER 0x100 /* NB: Not a valid property attribute. */
@ -533,13 +533,13 @@ js_FreeRawStack(JSContext *cx, void *mark);
extern JSObject *
js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv);
extern JSBool
extern JS_REQUIRES_STACK JSBool
js_EnterWith(JSContext *cx, jsint stackIndex);
extern void
extern JS_REQUIRES_STACK void
js_LeaveWith(JSContext *cx);
extern JSClass *
extern JS_REQUIRES_STACK JSClass *
js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth);
extern jsint
@ -549,7 +549,7 @@ js_CountWithBlocks(JSContext *cx, JSStackFrame *fp);
* Unwind block and scope chains to match the given depth. The function sets
* fp->sp on return to stackDepth.
*/
extern JSBool
extern JS_REQUIRES_STACK JSBool
js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth,
JSBool normalUnwind);
@ -572,7 +572,7 @@ js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2);
* Opcode tracing helper. When len is not 0, cx->fp->regs->pc[-len] gives the
* previous opcode.
*/
extern void
extern JS_REQUIRES_STACK void
js_TraceOpcode(JSContext *cx, jsint len);
/*

Просмотреть файл

@ -174,7 +174,7 @@ Iterator(JSContext *cx, JSObject *iterobj, uintN argc, jsval *argv, jsval *rval)
keyonly = js_ValueToBoolean(argv[1]);
flags = keyonly ? 0 : JSITER_FOREACH;
if (cx->fp->flags & JSFRAME_CONSTRUCTING) {
if (JS_IsConstructing(cx)) {
/* XXX work around old valueOf call hidden beneath js_ValueToObject */
if (!JSVAL_IS_PRIMITIVE(argv[0])) {
obj = JSVAL_TO_OBJECT(argv[0]);
@ -863,7 +863,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
cx->stackPool.current = arena->next = &gen->arena;
/* Push gen->frame around the interpreter activation. */
fp = cx->fp;
fp = js_GetTopStackFrame(cx);
cx->fp = &gen->frame;
gen->frame.down = fp;
ok = js_Interpret(cx);

Просмотреть файл

@ -261,7 +261,7 @@ Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
} else {
v = JSVAL_ZERO;
}
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
if (!JS_IsConstructing(cx)) {
*rval = v;
return JS_TRUE;
}

Просмотреть файл

@ -1195,8 +1195,8 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSBool setCallerVarObj = JS_FALSE;
#endif
fp = cx->fp;
caller = JS_GetScriptedCaller(cx, fp);
fp = js_GetTopStackFrame(cx);
caller = js_GetScriptedCaller(cx, fp);
indirectCall = (caller && caller->regs && *caller->regs->pc != JSOP_EVAL);
/*
@ -1385,7 +1385,7 @@ obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp,
callbacks = JS_GetSecurityCallbacks(cx);
if (callbacks && callbacks->findObjectPrincipals) {
/* Skip over any obj_watch_* frames between us and the real subject. */
caller = JS_GetScriptedCaller(cx, cx->fp);
caller = js_GetScriptedCaller(cx, NULL);
if (caller) {
/*
* Only call the watch handler if the watcher is allowed to watch
@ -1858,7 +1858,7 @@ js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
}
if (!obj) {
JS_ASSERT(!argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0]));
if (cx->fp->flags & JSFRAME_CONSTRUCTING)
if (JS_IsConstructing(cx))
return JS_TRUE;
obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0);
if (!obj)
@ -1996,7 +1996,7 @@ JSClass js_WithClass = {
0,0,0,0,0,0,0
};
JSObject *
JS_REQUIRES_STACK JSObject *
js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
{
JSObject *obj;
@ -2050,7 +2050,7 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSObject *parent,
return clone;
}
JSBool
JS_REQUIRES_STACK JSBool
js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
{
JSStackFrame *fp;
@ -2803,13 +2803,23 @@ js_SetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject *cobj)
JSBool
js_FindClassObject(JSContext *cx, JSObject *start, jsid id, jsval *vp)
{
JSStackFrame *fp;
JSObject *obj, *cobj, *pobj;
JSProtoKey key;
JSProperty *prop;
jsval v;
JSScopeProperty *sprop;
if (start || (cx->fp && (start = cx->fp->scopeChain) != NULL)) {
/*
* Find the global object. Use cx->fp directly to avoid falling off
* trace; all JIT-elided stack frames have the same global object as
* cx->fp.
*/
VOUCH_DOES_NOT_REQUIRE_STACK();
if (!start && (fp = cx->fp) != NULL)
start = fp->scopeChain;
if (start) {
/* Find the topmost object in the scope chain. */
do {
obj = start;
@ -3281,7 +3291,7 @@ bad:
* access is "object-detecting" in the sense used by web scripts, e.g., when
* checking whether document.all is defined.
*/
static JSBool
static JS_REQUIRES_STACK JSBool
Detecting(JSContext *cx, jsbytecode *pc)
{
JSScript *script;
@ -3414,16 +3424,18 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
*propp = NULL;
if (clasp->flags & JSCLASS_NEW_RESOLVE) {
JSStackFrame *fp = js_GetTopStackFrame(cx);
newresolve = (JSNewResolveOp)resolve;
if (flags == JSRESOLVE_INFER && cx->fp && cx->fp->regs) {
if (flags == JSRESOLVE_INFER && fp && fp->regs) {
flags = 0;
pc = cx->fp->regs->pc;
pc = fp->regs->pc;
cs = &js_CodeSpec[*pc];
format = cs->format;
if (JOF_MODE(format) != JOF_NAME)
flags |= JSRESOLVE_QUALIFIED;
if ((format & (JOF_SET | JOF_FOR)) ||
(cx->fp->flags & JSFRAME_ASSIGNING)) {
(fp->flags & JSFRAME_ASSIGNING)) {
flags |= JSRESOLVE_ASSIGNING;
} else {
pc += cs->length;
@ -3550,7 +3562,8 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp,
JSProperty *prop;
JSScopeProperty *sprop;
obj = cx->fp->scopeChain;
JS_ASSERT_IF(entryp, !JS_EXECUTING_TRACE(cx));
obj = js_GetTopStackFrame(cx)->scopeChain;
shape = OBJ_SHAPE(obj);
for (scopeIndex = 0; ; scopeIndex++) {
if (obj->map->ops->lookupProperty == js_LookupProperty) {
@ -3603,7 +3616,7 @@ js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
return js_FindPropertyHelper(cx, id, objp, pobjp, propp, NULL) >= 0;
}
JSObject *
JS_REQUIRES_STACK JSObject *
js_FindIdentifierBase(JSContext *cx, jsid id, JSPropCacheEntry *entry)
{
JSObject *obj, *pobj;
@ -3746,8 +3759,10 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
int protoIndex;
JSObject *obj2;
JSProperty *prop;
JSStackFrame *fp;
JSScopeProperty *sprop;
JS_ASSERT_IF(entryp, !JS_ON_TRACE(cx));
/* Convert string indices to integers if appropriate. */
CHECK_FOR_STRING_INDEX(id);
JS_COUNT_OPERATION(cx, JSOW_GET_PROPERTY);
@ -3774,11 +3789,11 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
* Give a strict warning if foo.bar is evaluated by a script for an
* object foo with no property named 'bar'.
*/
if (JSVAL_IS_VOID(*vp) && cx->fp && cx->fp->regs) {
if (JSVAL_IS_VOID(*vp) && (fp = js_GetTopStackFrame(cx)) && fp->regs) {
JSOp op;
uintN flags;
pc = cx->fp->regs->pc;
pc = fp->regs->pc;
op = (JSOp) *pc;
if (op == JSOP_GETXPROP) {
flags = JSREPORT_ERROR;
@ -3796,7 +3811,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
return JS_TRUE;
/* Kludge to allow (typeof foo == "undefined") tests. */
JS_ASSERT(cx->fp->script);
JS_ASSERT(fp->script);
pc += js_CodeSpec[op].length;
if (Detecting(cx, pc))
return JS_TRUE;
@ -3823,8 +3838,10 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
if (!js_NativeGet(cx, obj, obj2, sprop, vp))
return JS_FALSE;
if (entryp)
if (entryp) {
JS_ASSERT_NOT_EXECUTING_TRACE(cx);
js_FillPropertyCache(cx, obj, shape, 0, protoIndex, obj2, sprop, entryp);
}
JS_UNLOCK_OBJ(cx, obj2);
return JS_TRUE;
}
@ -4024,6 +4041,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
return JS_FALSE;
if (entryp) {
JS_ASSERT_NOT_EXECUTING_TRACE(cx);
if (!(attrs & JSPROP_SHARED))
js_FillPropertyCache(cx, obj, shape, 0, 0, obj, sprop, entryp);
else
@ -4638,7 +4656,7 @@ js_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
if (VALUE_IS_FUNCTION(cx, fval)) {
if (!GetCurrentExecutionContext(cx, obj, &nargv[2]))
return JS_FALSE;
args = js_GetArgsObject(cx, cx->fp);
args = js_GetArgsObject(cx, js_GetTopStackFrame(cx));
if (!args)
return JS_FALSE;
nargv[0] = OBJECT_TO_JSVAL(obj);
@ -4652,7 +4670,7 @@ js_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return ok;
}
#endif
js_ReportIsNotFunction(cx, &argv[-2], cx->fp->flags & JSFRAME_ITERATOR);
js_ReportIsNotFunction(cx, &argv[-2], js_GetTopStackFrame(cx)->flags & JSFRAME_ITERATOR);
return JS_FALSE;
}
return clasp->call(cx, obj, argc, argv, rval);
@ -4681,7 +4699,7 @@ js_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
if (VALUE_IS_FUNCTION(cx, cval)) {
if (!GetCurrentExecutionContext(cx, obj, &nargv[1]))
return JS_FALSE;
args = js_GetArgsObject(cx, cx->fp);
args = js_GetArgsObject(cx, js_GetTopStackFrame(cx));
if (!args)
return JS_FALSE;
nargv[0] = OBJECT_TO_JSVAL(args);

Просмотреть файл

@ -347,7 +347,7 @@ extern JSClass js_BlockClass;
* When popping the stack across this object's "with" statement, client code
* must call JS_SetPrivate(cx, withobj, NULL).
*/
extern JSObject *
extern JS_REQUIRES_STACK JSObject *
js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth);
/*
@ -363,7 +363,7 @@ extern JSObject *
js_CloneBlockObject(JSContext *cx, JSObject *proto, JSObject *parent,
JSStackFrame *fp);
extern JSBool
extern JS_REQUIRES_STACK JSBool
js_PutBlockObject(JSContext *cx, JSBool normalUnwind);
struct JSSharpObjectMap {
@ -584,7 +584,7 @@ extern JS_FRIEND_API(JSBool)
js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
JSProperty **propp);
extern JSObject *
extern JS_REQUIRES_STACK JSObject *
js_FindIdentifierBase(JSContext *cx, jsid id, JSPropCacheEntry *entry);
extern JSObject *

Просмотреть файл

@ -1913,8 +1913,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* the bytecode at pc, so we don't decompile more than the error
* expression.
*/
for (fp = cx->fp; fp && !fp->script; fp = fp->down)
continue;
fp = js_GetScriptedCaller(cx, NULL);
format = cs->format;
if (((fp && fp->regs && pc == fp->regs->pc) ||
(pc == startpc && cs->nuses != 0)) &&
@ -2765,7 +2764,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* object that's not a constructor, causing us to be
* called with an intervening frame on the stack.
*/
JSStackFrame *fp = cx->fp;
JSStackFrame *fp = js_GetTopStackFrame(cx);
if (fp) {
while (!(fp->flags & JSFRAME_EVAL))
fp = fp->down;

Просмотреть файл

@ -4791,7 +4791,7 @@ static JSFunctionSpec regexp_methods[] = {
static JSBool
RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
if (!JS_IsConstructing(cx)) {
/*
* If first arg is regexp and no flags are given, just return the arg.
* (regexp_compile_sub detects the regexp + flags case and throws a

Просмотреть файл

@ -230,7 +230,7 @@ script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
}
/* Compile using the caller's scope chain, which js_Invoke passes to fp. */
caller = JS_GetScriptedCaller(cx, cx->fp);
caller = js_GetScriptedCaller(cx, NULL);
JS_ASSERT(!caller || cx->fp->scopeChain == caller->scopeChain);
if (caller) {
@ -311,7 +311,7 @@ script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
JSObject *scopeobj, *parent;
JSStackFrame *fp, *caller;
JSStackFrame *caller;
JSPrincipals *principals;
JSScript *script;
JSBool ok;
@ -338,8 +338,7 @@ script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
* a lightweight function, we will need to get a Call object representing
* its frame, to act as the var object and scope chain head.
*/
fp = cx->fp;
caller = JS_GetScriptedCaller(cx, fp);
caller = js_GetScriptedCaller(cx, NULL);
if (caller && !caller->varobj) {
/* Called from a lightweight function. */
JS_ASSERT(caller->fun && !JSFUN_HEAVYWEIGHT_TEST(caller->fun->flags));
@ -903,7 +902,7 @@ static JSBool
Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
/* If not constructing, replace obj with a new Script object. */
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
if (!JS_IsConstructing(cx)) {
obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0);
if (!obj)
return JS_FALSE;
@ -1601,7 +1600,9 @@ js_DestroyScript(JSContext *cx, JSScript *script)
#endif
if (!cx->runtime->gcRunning) {
if (!(cx->fp && (cx->fp->flags & JSFRAME_EVAL))) {
JSStackFrame *fp = js_GetTopStackFrame(cx);
if (!(fp && (fp->flags & JSFRAME_EVAL))) {
#ifdef CHECK_SCRIPT_OWNER
JS_ASSERT(script->owner == cx->thread);
#endif

Просмотреть файл

@ -49,9 +49,20 @@ inline __attribute__ ((unused)) void MUST_FLOW_THROUGH(const char *label) {
/* avoid unused goto-label warnings */
#define MUST_FLOW_LABEL(label) goto label; label:
inline JS_FORCES_STACK void VOUCH_DOES_NOT_REQUIRE_STACK() {}
inline JS_FORCES_STACK void
JS_ASSERT_NOT_EXECUTING_TRACE(JSContext *cx)
{
JS_ASSERT(!JS_EXECUTING_TRACE(cx));
}
#else
#define MUST_FLOW_THROUGH(label) ((void)0)
#define MUST_FLOW_THROUGH(label) ((void) 0)
#define MUST_FLOW_LABEL(label)
#define VOUCH_DOES_NOT_REQUIRE_STACK() ((void) 0)
#define JS_ASSERT_NOT_EXECUTING_TRACE(cx) JS_ASSERT(!JS_EXECUTING_TRACE(cx))
#endif
#endif /* jsstaticcheck_h___ */

Просмотреть файл

@ -1402,7 +1402,7 @@ match_glob(JSContext *cx, jsint count, GlobData *data)
mdata = (MatchData *)data;
arrayobj = JSVAL_TO_OBJECT(*mdata->arrayval);
if (!arrayobj) {
arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
arrayobj = js_NewArrayObject(cx, 0, NULL);
if (!arrayobj)
return JS_FALSE;
*mdata->arrayval = OBJECT_TO_JSVAL(arrayobj);
@ -1442,7 +1442,7 @@ str_match(JSContext *cx, uintN argc, jsval *vp)
{
JSStackFrame *fp;
for (fp = cx->fp; fp && !fp->regs; fp = fp->down)
for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down)
JS_ASSERT(!fp->script);
return js_StringMatchHelper(cx, argc, vp, fp ? fp->regs->pc : NULL);
}
@ -2025,7 +2025,7 @@ str_split(JSContext *cx, uintN argc, jsval *vp)
NORMALIZE_THIS(cx, vp, str);
arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL);
arrayobj = js_NewArrayObject(cx, 0, NULL);
if (!arrayobj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(arrayobj);
@ -2583,7 +2583,7 @@ String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
} else {
str = cx->runtime->emptyString;
}
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
if (!JS_IsConstructing(cx)) {
*rval = STRING_TO_JSVAL(str);
return JS_TRUE;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -173,8 +173,8 @@ typedef Queue<uint16> SlotList;
class TypeMap : public Queue<uint8> {
public:
void captureGlobalTypes(JSContext* cx, SlotList& slots);
void captureStackTypes(JSContext* cx, unsigned callDepth);
JS_REQUIRES_STACK void captureGlobalTypes(JSContext* cx, SlotList& slots);
JS_REQUIRES_STACK void captureStackTypes(JSContext* cx, unsigned callDepth);
bool matches(TypeMap& other) const;
};
@ -302,74 +302,76 @@ class TraceRecorder : public avmplus::GCObject {
bool isGlobal(jsval* p) const;
ptrdiff_t nativeGlobalOffset(jsval* p) const;
ptrdiff_t nativeStackOffset(jsval* p) const;
void import(nanojit::LIns* base, ptrdiff_t offset, jsval* p, uint8& t,
const char *prefix, uintN index, JSStackFrame *fp);
void import(TreeInfo* treeInfo, nanojit::LIns* sp, unsigned ngslots, unsigned callDepth,
uint8* globalTypeMap, uint8* stackTypeMap);
JS_REQUIRES_STACK ptrdiff_t nativeStackOffset(jsval* p) const;
JS_REQUIRES_STACK void import(nanojit::LIns* base, ptrdiff_t offset, jsval* p, uint8& t,
const char *prefix, uintN index, JSStackFrame *fp);
JS_REQUIRES_STACK void import(TreeInfo* treeInfo, nanojit::LIns* sp, unsigned ngslots,
unsigned callDepth, uint8* globalTypeMap, uint8* stackTypeMap);
void trackNativeStackUse(unsigned slots);
bool lazilyImportGlobalSlot(unsigned slot);
JS_REQUIRES_STACK bool lazilyImportGlobalSlot(unsigned slot);
nanojit::LIns* guard(bool expected, nanojit::LIns* cond, ExitType exitType);
JS_REQUIRES_STACK nanojit::LIns* guard(bool expected, nanojit::LIns* cond,
ExitType exitType);
nanojit::LIns* guard(bool expected, nanojit::LIns* cond, nanojit::LIns* exit);
nanojit::LIns* addName(nanojit::LIns* ins, const char* name);
nanojit::LIns* get(jsval* p) const;
JS_REQUIRES_STACK nanojit::LIns* get(jsval* p) const;
nanojit::LIns* writeBack(nanojit::LIns* i, nanojit::LIns* base, ptrdiff_t offset);
void set(jsval* p, nanojit::LIns* l, bool initializing = false);
JS_REQUIRES_STACK void set(jsval* p, nanojit::LIns* l, bool initializing = false);
bool checkType(jsval& v, uint8 t, jsval*& stage_val, nanojit::LIns*& stage_ins,
unsigned& stage_count);
bool deduceTypeStability(nanojit::Fragment* root_peer, nanojit::Fragment** stable_peer,
unsigned* demotes);
JS_REQUIRES_STACK bool checkType(jsval& v, uint8 t, jsval*& stage_val,
nanojit::LIns*& stage_ins, unsigned& stage_count);
JS_REQUIRES_STACK bool deduceTypeStability(nanojit::Fragment* root_peer,
nanojit::Fragment** stable_peer, unsigned* demotes);
jsval& argval(unsigned n) const;
jsval& varval(unsigned n) const;
jsval& stackval(int n) const;
JS_REQUIRES_STACK jsval& argval(unsigned n) const;
JS_REQUIRES_STACK jsval& varval(unsigned n) const;
JS_REQUIRES_STACK jsval& stackval(int n) const;
nanojit::LIns* scopeChain() const;
bool activeCallOrGlobalSlot(JSObject* obj, jsval*& vp);
JS_REQUIRES_STACK nanojit::LIns* scopeChain() const;
JS_REQUIRES_STACK bool activeCallOrGlobalSlot(JSObject* obj, jsval*& vp);
nanojit::LIns* arg(unsigned n);
void arg(unsigned n, nanojit::LIns* i);
nanojit::LIns* var(unsigned n);
void var(unsigned n, nanojit::LIns* i);
nanojit::LIns* stack(int n);
void stack(int n, nanojit::LIns* i);
JS_REQUIRES_STACK nanojit::LIns* arg(unsigned n);
JS_REQUIRES_STACK void arg(unsigned n, nanojit::LIns* i);
JS_REQUIRES_STACK nanojit::LIns* var(unsigned n);
JS_REQUIRES_STACK void var(unsigned n, nanojit::LIns* i);
JS_REQUIRES_STACK nanojit::LIns* stack(int n);
JS_REQUIRES_STACK void stack(int n, nanojit::LIns* i);
nanojit::LIns* alu(nanojit::LOpcode op, jsdouble v0, jsdouble v1,
nanojit::LIns* s0, nanojit::LIns* s1);
nanojit::LIns* f2i(nanojit::LIns* f);
nanojit::LIns* makeNumberInt32(nanojit::LIns* f);
JS_REQUIRES_STACK nanojit::LIns* makeNumberInt32(nanojit::LIns* f);
nanojit::LIns* stringify(jsval& v);
bool call_imacro(jsbytecode* imacro);
bool ifop();
bool switchop();
bool inc(jsval& v, jsint incr, bool pre = true);
bool inc(jsval& v, nanojit::LIns*& v_ins, jsint incr, bool pre = true);
bool incProp(jsint incr, bool pre = true);
bool incElem(jsint incr, bool pre = true);
bool incName(jsint incr, bool pre = true);
JS_REQUIRES_STACK bool ifop();
JS_REQUIRES_STACK bool switchop();
JS_REQUIRES_STACK bool inc(jsval& v, jsint incr, bool pre = true);
JS_REQUIRES_STACK bool inc(jsval& v, nanojit::LIns*& v_ins, jsint incr, bool pre = true);
JS_REQUIRES_STACK bool incProp(jsint incr, bool pre = true);
JS_REQUIRES_STACK bool incElem(jsint incr, bool pre = true);
JS_REQUIRES_STACK bool incName(jsint incr, bool pre = true);
enum { CMP_NEGATE = 1, CMP_TRY_BRANCH_AFTER_COND = 2, CMP_CASE = 4, CMP_STRICT = 8 };
bool cmp(nanojit::LOpcode op, int flags = 0);
JS_REQUIRES_STACK bool cmp(nanojit::LOpcode op, int flags = 0);
bool unary(nanojit::LOpcode op);
bool binary(nanojit::LOpcode op);
JS_REQUIRES_STACK bool unary(nanojit::LOpcode op);
JS_REQUIRES_STACK bool binary(nanojit::LOpcode op);
bool ibinary(nanojit::LOpcode op);
bool iunary(nanojit::LOpcode op);
bool bbinary(nanojit::LOpcode op);
void demote(jsval& v, jsdouble result);
bool map_is_native(JSObjectMap* map, nanojit::LIns* map_ins, nanojit::LIns*& ops_ins,
size_t op_offset = 0);
bool test_property_cache(JSObject* obj, nanojit::LIns* obj_ins, JSObject*& obj2,
jsuword& pcval);
bool test_property_cache_direct_slot(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot);
JS_REQUIRES_STACK bool map_is_native(JSObjectMap* map, nanojit::LIns* map_ins,
nanojit::LIns*& ops_ins, size_t op_offset = 0);
JS_REQUIRES_STACK bool test_property_cache(JSObject* obj, nanojit::LIns* obj_ins,
JSObject*& obj2, jsuword& pcval);
JS_REQUIRES_STACK bool test_property_cache_direct_slot(JSObject* obj, nanojit::LIns* obj_ins,
uint32& slot);
void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot, nanojit::LIns*& dslots_ins,
nanojit::LIns* v_ins);
void stobj_set_dslot(nanojit::LIns *obj_ins, unsigned slot, nanojit::LIns*& dslots_ins,
@ -383,34 +385,37 @@ class TraceRecorder : public avmplus::GCObject {
bool native_get(nanojit::LIns* obj_ins, nanojit::LIns* pobj_ins, JSScopeProperty* sprop,
nanojit::LIns*& dslots_ins, nanojit::LIns*& v_ins);
bool name(jsval*& vp);
bool prop(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot, nanojit::LIns*& v_ins);
bool elem(jsval& oval, jsval& idx, jsval*& vp, nanojit::LIns*& v_ins, nanojit::LIns*& addr_ins);
JS_REQUIRES_STACK bool name(jsval*& vp);
JS_REQUIRES_STACK bool prop(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot,
nanojit::LIns*& v_ins);
JS_REQUIRES_STACK bool elem(jsval& oval, jsval& idx, jsval*& vp, nanojit::LIns*& v_ins,
nanojit::LIns*& addr_ins);
JS_REQUIRES_STACK bool getProp(JSObject* obj, nanojit::LIns* obj_ins);
JS_REQUIRES_STACK bool getProp(jsval& v);
JS_REQUIRES_STACK bool getThis(nanojit::LIns*& this_ins);
bool getProp(JSObject* obj, nanojit::LIns* obj_ins);
bool getProp(jsval& v);
bool getThis(nanojit::LIns*& this_ins);
bool box_jsval(jsval v, nanojit::LIns*& v_ins);
bool unbox_jsval(jsval v, nanojit::LIns*& v_ins);
bool guardClass(JSObject* obj, nanojit::LIns* obj_ins, JSClass* clasp,
ExitType exitType = MISMATCH_EXIT);
bool guardDenseArray(JSObject* obj, nanojit::LIns* obj_ins,
ExitType exitType = MISMATCH_EXIT);
bool guardDenseArrayIndex(JSObject* obj, jsint idx, nanojit::LIns* obj_ins,
nanojit::LIns* dslots_ins, nanojit::LIns* idx_ins,
ExitType exitType);
bool guardElemOp(JSObject* obj, nanojit::LIns* obj_ins, jsid id, size_t op_offset, jsval* vp);
JS_REQUIRES_STACK bool box_jsval(jsval v, nanojit::LIns*& v_ins);
JS_REQUIRES_STACK bool unbox_jsval(jsval v, nanojit::LIns*& v_ins);
JS_REQUIRES_STACK bool guardClass(JSObject* obj, nanojit::LIns* obj_ins, JSClass* clasp,
ExitType exitType = MISMATCH_EXIT);
JS_REQUIRES_STACK bool guardDenseArray(JSObject* obj, nanojit::LIns* obj_ins,
ExitType exitType = MISMATCH_EXIT);
JS_REQUIRES_STACK bool guardDenseArrayIndex(JSObject* obj, jsint idx, nanojit::LIns* obj_ins,
nanojit::LIns* dslots_ins, nanojit::LIns* idx_ins,
ExitType exitType);
JS_REQUIRES_STACK bool guardElemOp(JSObject* obj, nanojit::LIns* obj_ins, jsid id,
size_t op_offset, jsval* vp);
void clearFrameSlotsFromCache();
bool guardCallee(jsval& callee);
bool getClassPrototype(JSObject* ctor, nanojit::LIns*& proto_ins);
bool newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* vp);
bool interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, bool constructing);
bool functionCall(bool constructing, uintN argc);
JS_REQUIRES_STACK bool guardCallee(jsval& callee);
JS_REQUIRES_STACK bool getClassPrototype(JSObject* ctor, nanojit::LIns*& proto_ins);
JS_REQUIRES_STACK bool newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* vp);
JS_REQUIRES_STACK bool interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc,
bool constructing);
JS_REQUIRES_STACK bool functionCall(bool constructing, uintN argc);
void trackCfgMerges(jsbytecode* pc);
void flipIf(jsbytecode* pc, bool& cond);
void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
JS_REQUIRES_STACK void trackCfgMerges(jsbytecode* pc);
JS_REQUIRES_STACK void flipIf(jsbytecode* pc, bool& cond);
JS_REQUIRES_STACK void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
bool hasMethod(JSObject* obj, jsid id);
bool hasToStringMethod(JSObject* obj);
@ -430,40 +435,45 @@ class TraceRecorder : public avmplus::GCObject {
}
public:
friend bool js_MonitorRecording(TraceRecorder* tr);
friend JS_REQUIRES_STACK bool js_MonitorRecording(TraceRecorder* tr);
JS_REQUIRES_STACK
TraceRecorder(JSContext* cx, VMSideExit*, nanojit::Fragment*, TreeInfo*,
unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap,
unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap,
VMSideExit* expectedInnerExit, nanojit::Fragment* outerToBlacklist);
~TraceRecorder();
uint8 determineSlotType(jsval* vp) const;
nanojit::LIns* snapshot(ExitType exitType);
JS_REQUIRES_STACK uint8 determineSlotType(jsval* vp) const;
JS_REQUIRES_STACK nanojit::LIns* snapshot(ExitType exitType);
nanojit::Fragment* getFragment() const { return fragment; }
bool isLoopHeader(JSContext* cx) const;
void compile(nanojit::Fragmento* fragmento);
bool closeLoop(nanojit::Fragmento* fragmento, bool& demote, unsigned *demotes);
void endLoop(nanojit::Fragmento* fragmento);
void joinEdgesToEntry(nanojit::Fragmento* fragmento, nanojit::Fragment* peer_root);
JS_REQUIRES_STACK bool isLoopHeader(JSContext* cx) const;
JS_REQUIRES_STACK void compile(nanojit::Fragmento* fragmento);
JS_REQUIRES_STACK bool closeLoop(nanojit::Fragmento* fragmento, bool& demote,
unsigned *demotes);
JS_REQUIRES_STACK void endLoop(nanojit::Fragmento* fragmento);
JS_REQUIRES_STACK void joinEdgesToEntry(nanojit::Fragmento* fragmento,
nanojit::Fragment* peer_root);
void blacklist() { fragment->blacklist(); }
bool adjustCallerTypes(nanojit::Fragment* f, unsigned* demote_slots, bool& trash);
nanojit::Fragment* findNestedCompatiblePeer(nanojit::Fragment* f, nanojit::Fragment** empty);
void prepareTreeCall(nanojit::Fragment* inner);
void emitTreeCall(nanojit::Fragment* inner, VMSideExit* exit);
JS_REQUIRES_STACK bool adjustCallerTypes(nanojit::Fragment* f, unsigned* demote_slots,
bool& trash);
JS_REQUIRES_STACK nanojit::Fragment* findNestedCompatiblePeer(nanojit::Fragment* f,
nanojit::Fragment** empty);
JS_REQUIRES_STACK void prepareTreeCall(nanojit::Fragment* inner);
JS_REQUIRES_STACK void emitTreeCall(nanojit::Fragment* inner, VMSideExit* exit);
unsigned getCallDepth() const;
void pushAbortStack();
void popAbortStack();
void removeFragmentoReferences();
bool record_EnterFrame();
bool record_LeaveFrame();
bool record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop);
bool record_SetPropMiss(JSPropCacheEntry* entry);
bool record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
bool record_FastNativeCallComplete();
bool record_IteratorNextComplete();
bool record_ApplyComplete(uintN argc);
JS_REQUIRES_STACK bool record_EnterFrame();
JS_REQUIRES_STACK bool record_LeaveFrame();
JS_REQUIRES_STACK bool record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop);
JS_REQUIRES_STACK bool record_SetPropMiss(JSPropCacheEntry* entry);
JS_REQUIRES_STACK bool record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
JS_REQUIRES_STACK bool record_FastNativeCallComplete();
JS_REQUIRES_STACK bool record_IteratorNextComplete();
JS_REQUIRES_STACK bool record_ApplyComplete(uintN argc);
nanojit::Fragment* getOuterToBlacklist() { return outerToBlacklist; }
void deepAbort() { deepAborted = true; }
bool wasDeepAborted() { return deepAborted; }
@ -472,11 +482,10 @@ public:
TreeInfo* getTreeInfo() { return treeInfo; }
#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
bool record_##op();
JS_REQUIRES_STACK bool record_##op();
# include "jsopcode.tbl"
#undef OPDEF
};
#define TRACING_ENABLED(cx) JS_HAS_OPTION(cx, JSOPTION_JIT)
#define TRACE_RECORDER(cx) (JS_TRACE_MONITOR(cx).recorder)
#define SET_TRACE_RECORDER(cx,tr) (JS_TRACE_MONITOR(cx).recorder = (tr))
@ -529,13 +538,13 @@ public:
#define TRACE_1(x,a) TRACE_ARGS(x, (a))
#define TRACE_2(x,a,b) TRACE_ARGS(x, (a, b))
extern bool
extern JS_REQUIRES_STACK bool
js_MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount);
extern bool
extern JS_REQUIRES_STACK bool
js_MonitorRecording(TraceRecorder *tr);
extern void
extern JS_REQUIRES_STACK void
js_AbortRecording(JSContext* cx, const char* reason);
extern void

Просмотреть файл

@ -188,6 +188,20 @@
# endif
#endif
#ifdef NS_STATIC_CHECKING
/*
* Attributes for static analysis. Functions declared with JS_REQUIRES_STACK
* always have a valid cx->fp and can access it freely. Other functions can
* access cx->fp only after calling a function that "forces" the stack
* (i.e. lazily instantiates it as needed).
*/
# define JS_REQUIRES_STACK __attribute__((user("JS_REQUIRES_STACK")))
# define JS_FORCES_STACK __attribute__((user("JS_FORCES_STACK")))
#else
# define JS_REQUIRES_STACK
# define JS_FORCES_STACK
#endif
/***********************************************************************
** MACROS: JS_BEGIN_MACRO
** JS_END_MACRO

Просмотреть файл

@ -680,7 +680,7 @@ static JSBool
Namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
return NamespaceHelper(cx,
(cx->fp->flags & JSFRAME_CONSTRUCTING) ? obj : NULL,
JS_IsConstructing(cx) ? obj : NULL,
argc, argv, rval);
}
@ -814,7 +814,7 @@ out:
static JSBool
QName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
return QNameHelper(cx, (cx->fp->flags & JSFRAME_CONSTRUCTING) ? obj : NULL,
return QNameHelper(cx, JS_IsConstructing(cx) ? obj : NULL,
&js_QNameClass.base, argc, argv, rval);
}
@ -822,7 +822,7 @@ static JSBool
AttributeName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
return QNameHelper(cx, (cx->fp->flags & JSFRAME_CONSTRUCTING) ? obj : NULL,
return QNameHelper(cx, JS_IsConstructing(cx) ? obj : NULL,
&js_AttributeNameClass, argc, argv, rval);
}
@ -1873,7 +1873,7 @@ ParseXMLSource(JSContext *cx, JSString *src)
chars [offset + dstlen] = 0;
xml = NULL;
for (fp = cx->fp; fp && !fp->regs; fp = fp->down)
for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down)
JS_ASSERT(!fp->script);
filename = NULL;
lineno = 1;
@ -1892,7 +1892,8 @@ ParseXMLSource(JSContext *cx, JSString *src)
if (!js_InitParseContext(cx, &pc, NULL, NULL, chars, length, NULL,
filename, lineno))
goto out;
pn = js_ParseXMLText(cx, cx->fp->scopeChain, &pc, JS_FALSE);
pn = js_ParseXMLText(cx, js_GetTopStackFrame(cx)->scopeChain, &pc,
JS_FALSE);
if (pn && XMLArrayInit(cx, &nsarray, 1)) {
if (GetXMLSettingFlags(cx, &flags))
xml = ParseNodeToXML(cx, &pc, pn, &nsarray, flags);
@ -7263,7 +7264,7 @@ XML(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
*rval = OBJECT_TO_JSVAL(xobj);
xml = (JSXML *) JS_GetPrivate(cx, xobj);
if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && !JSVAL_IS_PRIMITIVE(v)) {
if (JS_IsConstructing(cx) && !JSVAL_IS_PRIMITIVE(v)) {
vobj = JSVAL_TO_OBJECT(v);
clasp = OBJ_GET_CLASS(cx, vobj);
if (clasp == &js_XMLClass ||
@ -7291,7 +7292,7 @@ XMLList(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v))
v = STRING_TO_JSVAL(cx->runtime->emptyString);
if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && !JSVAL_IS_PRIMITIVE(v)) {
if (JS_IsConstructing(cx) && !JSVAL_IS_PRIMITIVE(v)) {
vobj = JSVAL_TO_OBJECT(v);
if (OBJECT_IS_XML(cx, vobj)) {
xml = (JSXML *) JS_GetPrivate(cx, vobj);
@ -7710,7 +7711,7 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp)
JSObject *ns, *obj, *tmp;
jsval v;
fp = cx->fp;
fp = js_GetTopStackFrame(cx);
ns = fp->xmlNamespace;
if (ns) {
*vp = OBJECT_TO_JSVAL(ns);
@ -7758,7 +7759,7 @@ js_SetDefaultXMLNamespace(JSContext *cx, jsval v)
return JS_FALSE;
v = OBJECT_TO_JSVAL(ns);
fp = cx->fp;
fp = js_GetTopStackFrame(cx);
varobj = fp->varobj;
if (varobj) {
if (!OBJ_DEFINE_PROPERTY(cx, varobj, JS_DEFAULT_XML_NAMESPACE_ID, v,
@ -7950,7 +7951,7 @@ js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp)
if (!IsFunctionQName(cx, qn, &funid))
return JS_FALSE;
obj = cx->fp->scopeChain;
obj = js_GetTopStackFrame(cx)->scopeChain;
do {
/* Skip any With object that can wrap XML. */
target = obj;
@ -8163,7 +8164,7 @@ js_StepXMLListFilter(JSContext *cx, JSBool initialized)
JSXML *xml, *list;
JSXMLFilter *filter;
sp = cx->fp->regs->sp;
sp = js_GetTopStackFrame(cx)->regs->sp;
if (!initialized) {
/*
* We haven't iterated yet, so initialize the filter based on the

Просмотреть файл

@ -58,6 +58,7 @@
#include "jsfun.h"
#include "jscntxt.h" /* For js_ReportErrorAgain().*/
#include "jsscript.h"
#include "jsstaticcheck.h"
#include "netscape_javascript_JSObject.h" /* javah-generated headers */
#include "nsISecurityContext.h"
@ -161,20 +162,10 @@ AutoPushJSContext::AutoPushJSContext(nsISupports* aSecuritySupports,
{
// See if there are any scripts on the stack.
// If not, we need to add a dummy frame with a principal.
JSStackFrame* tempFP = JS_GetScriptedCaller(cx, NULL);
JS_ASSERT_NOT_ON_TRACE(cx);
PRBool hasScript = PR_FALSE;
JSStackFrame* tempFP = cx->fp;
while (tempFP)
{
if (tempFP->script)
{
hasScript = PR_TRUE;
break;
}
tempFP = tempFP->down;
};
if (!hasScript)
if (!tempFP)
{
JSPrincipals* jsprinc;
principal->GetJSPrincipals(cx, &jsprinc);
@ -214,6 +205,8 @@ AutoPushJSContext::~AutoPushJSContext()
if (mFrame.argsobj)
js_PutArgsObject(mContext, &mFrame);
JS_ClearPendingException(mContext);
VOUCH_DOES_NOT_REQUIRE_STACK();
if (mFrame.script)
mContext->fp = mFrame.down;

Просмотреть файл

@ -144,12 +144,8 @@ ShouldBypassNativeWrapper(JSContext *cx, JSObject *obj)
return JS_FALSE;
// Check what the script calling us looks like
JSScript *script = nsnull;
JSStackFrame *fp = cx->fp;
while(!script && fp) {
script = fp->script;
fp = fp->down;
}
JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
JSScript *script = fp ? fp->script : NULL;
// If there's no script, bypass for now because that's what the old code did.
// XXX FIXME: bug 341477 covers figuring out what we _should_ do.

Просмотреть файл

@ -345,7 +345,7 @@ XPCCallContext::~XPCCallContext()
// Don't clear newborns if JS frames (compilation or execution)
// are active! Doing so violates ancient invariants in the JS
// engine, and it's not necessary to fix JS component leaks.
if(!mJSContext->fp)
if(!JS_IsRunning(mJSContext))
JS_ClearNewbornRoots(mJSContext);
}
}

Просмотреть файл

@ -1148,16 +1148,11 @@ XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
// JSObject to said JS, so look for the script we want on
// the stack.
JSContext* cx = ccx;
JSStackFrame* fp = cx->fp;
while(fp)
JSStackFrame* fp = JS_GetScriptedCaller(cx, NULL);
if(fp)
{
script = fp->script;
if(script)
{
callee = fp->callee;
break;
}
fp = fp->down;
callee = fp->callee;
}
}
else if(ccx.GetXPCContext()->CallerTypeIsNative())

Просмотреть файл

@ -81,10 +81,13 @@ private:
nsresult
XPCJSStack::CreateStack(JSContext* cx, nsIStackFrame** stack)
{
if(!cx || !cx->fp)
if(!cx)
return NS_ERROR_FAILURE;
return XPCJSStackFrame::CreateStack(cx, cx->fp, (XPCJSStackFrame**) stack);
JSStackFrame *fp = NULL;
if (!JS_FrameIterator(cx, &fp))
return NS_ERROR_FAILURE;
return XPCJSStackFrame::CreateStack(cx, fp, (XPCJSStackFrame**) stack);
}
// static

167
xpcom/analysis/jsstack.js Normal file
Просмотреть файл

@ -0,0 +1,167 @@
/*
* Check that only JS_REQUIRES_STACK/JS_FORCES_STACK functions, and functions
* that have called a JS_FORCES_STACK function, access cx->fp directly or
* indirectly.
*/
require({ after_gcc_pass: 'cfg' });
include('gcc_util.js');
include('unstable/adts.js');
include('unstable/analysis.js');
include('unstable/lazy_types.js');
include('unstable/esp.js');
var Zero_NonZero = {};
include('unstable/zero_nonzero.js', Zero_NonZero);
// Tell MapFactory we don't need multimaps (a speed optimization).
MapFactory.use_injective = true;
/*
* There are two regions in the program: RED and GREEN. Functions and member
* variables may be declared RED in the C++ source. GREEN is the default.
*
* RED signals danger. A GREEN part of a function must not call a RED function
* or access a RED member.
*
* The body of a RED function is all red. The body of a GREEN function is all
* GREEN by default, but parts dominated by a call to a TURN_RED function are
* red. This way GREEN functions can safely access RED stuff by calling a
* TURN_RED function as preparation.
*
* The analysis does not attempt to prove anything about the body of a TURN_RED
* function. (Both annotations are trusted; only unannotated code is checked
* for errors.)
*/
const RED = 'JS_REQUIRES_STACK';
const TURN_RED = 'JS_FORCES_STACK';
function attrs(tree) {
let a = DECL_P(tree) ? DECL_ATTRIBUTES(tree) : TYPE_ATTRIBUTES(TREE_TYPE(tree));
return translate_attributes(a);
}
function hasUserAttribute(tree, attrname) {
let attributes = attrs(tree);
if (attributes) {
for (let i = 0; i < attributes.length; i++) {
let attr = attributes[i];
if (attr.name == 'user' && attr.value.length == 1 && attr.value[0] == attrname)
return true;
}
}
return false;
}
/*
* x is an expression or decl. These functions assume that
*/
function isRed(x) { return hasUserAttribute(x, RED); }
function isTurnRed(x) { return hasUserAttribute(x, TURN_RED); }
function process_tree(fndecl)
{
if (!(isRed(fndecl) || isTurnRed(fndecl))) {
// Ordinarily a user of ESP runs the analysis, then generates output based
// on the results. But in our case (a) we need sub-basic-block resolution,
// which ESP doesn't keep; (b) it so happens that even though ESP can
// iterate over blocks multiple times, in our case that won't cause
// spurious output. (It could cause us to the same error message each time
// through--but that's easily avoided.) Therefore we generate the output
// while the ESP analysis is running.
let a = new RedGreenCheck(fndecl, 0);
if (a.hasRed)
a.run();
}
}
function RedGreenCheck(fndecl, trace) {
//print("RedGreenCheck: " + fndecl.toCString());
this._fndecl = fndecl;
// Tell ESP that fndecl is a "property variable". This makes ESP track it in
// a flow-sensitive way. The variable will be 1 in RED regions and "don't
// know" in GREEN regions. (We are technically lying to ESP about fndecl
// being a variable--what we really want is a synthetic variable indicating
// RED/GREEN state, but ESP operates on GCC decl nodes.)
this._state_var_decl = fndecl;
let state_var = new ESP.PropVarSpec(this._state_var_decl, true, undefined);
// Call base class constructor.
let cfg = function_decl_cfg(fndecl);
ESP.Analysis.apply(this, [cfg, [state_var], Zero_NonZero.meet, trace]);
this.join = Zero_NonZero.join;
// Preprocess all instructions in the cfg to determine whether this analysis
// is necessary and gather some information we'll use later.
//
// Each isn may include a function call, an assignment, and/or some reads.
// Using walk_tree to walk the isns is a little crazy but robust.
//
this.hasRed = false;
for (let bb in cfg_bb_iterator(cfg)) {
for (let isn in bb_isn_iterator(bb)) {
walk_tree(isn, function(t, stack) {
switch (TREE_CODE(t)) {
case FIELD_DECL:
if (isRed(t)) {
let varName = dehydra_convert(t).name;
// location_of(t) is the location of the declaration.
isn.redInfo = ["cannot access JS_REQUIRES_STACK variable " + varName,
location_of(stack[stack.length - 1])];
this.hasRed = true;
}
break;
case CALL_EXPR:
{
let callee = call_function_decl(t);
if (callee) {
if (isRed(callee)) {
let calleeName = dehydra_convert(callee).name;
isn.redInfo = ["cannot call JS_REQUIRES_STACK function " + calleeName,
location_of(t)];
this.hasRed = true;
} else if (isTurnRed(callee)) {
isn.turnRed = true;
}
}
}
break;
}
});
}
}
// Initialize mixin for infeasible-path elimination.
this._zeroNonzero = new Zero_NonZero.Zero_NonZero();
}
RedGreenCheck.prototype = new ESP.Analysis;
RedGreenCheck.prototype.flowStateCond = function(isn, truth, state) {
// forward event to mixin
this._zeroNonzero.flowStateCond(isn, truth, state);
};
RedGreenCheck.prototype.flowState = function(isn, state) {
// forward event to mixin
//try { // The try/catch here is a workaround for some baffling bug in zero_nonzero.
this._zeroNonzero.flowState(isn, state);
//} catch (exc) {
// warning(exc, location_of(isn));
// warning("(Remove the workaround in jsstack.js and recompile to get a JS stack trace.)",
// location_of(isn));
//}
let green = (state.get(this._state_var_decl) != 1);
let redInfo = isn.redInfo;
if (green && redInfo) {
error(redInfo[0], redInfo[1]);
delete isn.redInfo; // avoid duplicate messages about this instruction
}
// If we call a TURNS_RED function, it doesn't take effect until after the
// whole isn finishes executing (the most conservative rule).
if (isn.turnRed)
state.assignValue(this._state_var_decl, 1, isn);
};