Bug 460865 - Read barrier for cx->fp. r=mrbkap, r=dmandelin.
--HG-- extra : rebase_source : 19963188b2f9f96336ce6ca28dbaefccf3a639b7
This commit is contained in:
Родитель
429817d57b
Коммит
c499e81946
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
Загрузка…
Ссылка в новой задаче