Bug 540675: eviscerate JSStackFrame::callerVersion. (r=lw)

This commit is contained in:
Chris Leary 2010-09-13 09:38:22 -07:00
Родитель 0f3cc3cd5f
Коммит 7473b7380d
25 изменённых файлов: 425 добавлений и 316 удалений

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

@ -468,7 +468,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
// We re-use our knowledge of the implementation to reuse
// JSVERSION_HAS_XML as a safe version flag.
// If version has JSVERSION_UNKNOWN (-1), then this is still OK.
version |= JSVERSION_HAS_XML;
version |= js::VersionFlags::HAS_XML;
}
}
} else {

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

@ -1058,7 +1058,7 @@ XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
// our implementation knowledge to reuse JSVERSION_HAS_XML as a
// safe version flag. This is still OK if version is
// JSVERSION_UNKNOWN (-1),
version |= JSVERSION_HAS_XML;
version |= js::VersionFlags::HAS_XML;
nsAutoString value;
rv = parser.GetParameter("e4x", value);
@ -1067,7 +1067,7 @@ XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
return rv;
} else {
if (value.Length() == 1 && value[0] == '0')
version &= ~JSVERSION_HAS_XML;
version &= ~js::VersionFlags::HAS_XML;
}
}
}
@ -1081,7 +1081,7 @@ XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
// Even when JS version < 1.6 is specified, E4X is
// turned on in XUL.
version |= JSVERSION_HAS_XML;
version |= js::VersionFlags::HAS_XML;
}
}
aAttributes += 2;

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

@ -311,51 +311,6 @@ nsCCMemoryPressureObserver::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK;
}
class nsJSVersionSetter {
public:
nsJSVersionSetter(JSContext *aContext, PRUint32 aVersion);
~nsJSVersionSetter();
private:
JSContext* mContext;
uint32 mOldOptions;
JSVersion mOldVersion;
JSBool mOptionsChanged;
};
nsJSVersionSetter::nsJSVersionSetter(JSContext *aContext, PRUint32 aVersion)
: mContext(aContext)
{
// JSVERSION_HAS_XML may be set in our version mask - however, we can't
// simply pass this directly to JS_SetOptions as it masks out that bit -
// the only way to make this happen is via JS_SetOptions.
JSBool hasxml = (aVersion & JSVERSION_HAS_XML) != 0;
mOldOptions = ::JS_GetOptions(mContext);
mOptionsChanged = ((hasxml) ^ !!(mOldOptions & JSOPTION_XML));
if (mOptionsChanged) {
::JS_SetOptions(mContext,
hasxml
? mOldOptions | JSOPTION_XML
: mOldOptions & ~JSOPTION_XML);
}
// Change the version - this is cheap when the versions match, so no need
// to optimize here...
JSVersion newVer = (JSVersion)(aVersion & JSVERSION_MASK);
mOldVersion = ::JS_SetVersion(mContext, newVer);
}
nsJSVersionSetter::~nsJSVersionSetter()
{
::JS_SetVersion(mContext, mOldVersion);
if (mOptionsChanged) {
::JS_SetOptions(mContext, mOldOptions);
}
}
/****************************************************************
************************** AutoFree ****************************
****************************************************************/
@ -1529,7 +1484,6 @@ nsJSContext::EvaluateStringWithValue(const nsAString& aScript,
if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) {
JSAutoRequest ar(mContext);
nsJSVersionSetter setVersion(mContext, aVersion);
JSAutoCrossCompartmentCall accc;
if (!accc.enter(mContext, (JSObject *)aScopeObject)) {
@ -1540,14 +1494,15 @@ nsJSContext::EvaluateStringWithValue(const nsAString& aScript,
++mExecuteDepth;
ok = ::JS_EvaluateUCScriptForPrincipals(mContext,
(JSObject *)aScopeObject,
jsprin,
(jschar*)PromiseFlatString(aScript).get(),
aScript.Length(),
aURL,
aLineNo,
&val);
ok = ::JS_EvaluateUCScriptForPrincipalsVersion(mContext,
(JSObject *)aScopeObject,
jsprin,
(jschar*)PromiseFlatString(aScript).get(),
aScript.Length(),
aURL,
aLineNo,
&val,
JSVersion(aVersion));
--mExecuteDepth;
@ -1737,16 +1692,15 @@ nsJSContext::EvaluateString(const nsAString& aScript,
return NS_ERROR_FAILURE;
}
nsJSVersionSetter setVersion(mContext, aVersion);
ok = ::JS_EvaluateUCScriptForPrincipals(mContext,
(JSObject *)aScopeObject,
jsprin,
(jschar*)PromiseFlatString(aScript).get(),
aScript.Length(),
aURL,
aLineNo,
vp);
ok = ::JS_EvaluateUCScriptForPrincipalsVersion(mContext,
(JSObject *)aScopeObject,
jsprin,
(jschar*)PromiseFlatString(aScript).get(),
aScript.Length(),
aURL,
aLineNo,
vp,
JSVersion(aVersion));
if (!ok) {
// Tell XPConnect about any pending exceptions. This is needed
@ -1826,16 +1780,16 @@ nsJSContext::CompileScript(const PRUnichar* aText,
// check it isn't JSVERSION_UNKNOWN.
if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) {
JSAutoRequest ar(mContext);
nsJSVersionSetter setVersion(mContext, aVersion);
JSScript* script =
::JS_CompileUCScriptForPrincipals(mContext,
(JSObject *)aScopeObject,
jsprin,
(jschar*) aText,
aTextLength,
aURL,
aLineNo);
::JS_CompileUCScriptForPrincipalsVersion(mContext,
(JSObject *)aScopeObject,
jsprin,
(jschar*) aText,
aTextLength,
aURL,
aLineNo,
JSVersion(aVersion));
if (script) {
JSObject *scriptObject = ::JS_NewScriptObject(mContext, script);
if (scriptObject) {
@ -2032,15 +1986,14 @@ nsJSContext::CompileEventHandler(nsIAtom *aName,
// Therefore we never bother compiling with principals.
// (that probably means we should avoid JS_CompileUCFunctionForPrincipals!)
JSAutoRequest ar(mContext);
nsJSVersionSetter setVersion(mContext, aVersion);
JSFunction* fun =
::JS_CompileUCFunctionForPrincipals(mContext,
nsnull, nsnull,
nsAtomCString(aName).get(), aArgCount, aArgNames,
(jschar*)PromiseFlatString(aBody).get(),
aBody.Length(),
aURL, aLineNo);
::JS_CompileUCFunctionForPrincipalsVersion(mContext,
nsnull, nsnull,
nsAtomCString(aName).get(), aArgCount, aArgNames,
(jschar*)PromiseFlatString(aBody).get(),
aBody.Length(),
aURL, aLineNo, JSVersion(aVersion));
if (!fun) {
ReportPendingException();
@ -2095,16 +2048,16 @@ nsJSContext::CompileFunction(void* aTarget,
JSObject *target = (JSObject*)aTarget;
JSAutoRequest ar(mContext);
nsJSVersionSetter setVersion(mContext, aVersion);
JSFunction* fun =
::JS_CompileUCFunctionForPrincipals(mContext,
aShared ? nsnull : target, jsprin,
PromiseFlatCString(aName).get(),
aArgCount, aArgArray,
(jschar*)PromiseFlatString(aBody).get(),
aBody.Length(),
aURL, aLineNo);
::JS_CompileUCFunctionForPrincipalsVersion(mContext,
aShared ? nsnull : target, jsprin,
PromiseFlatCString(aName).get(),
aArgCount, aArgArray,
(jschar*)PromiseFlatString(aBody).get(),
aBody.Length(),
aURL, aLineNo,
JSVersion(aVersion));
if (jsprin)
JSPRINCIPALS_DROP(mContext, jsprin);

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

@ -108,6 +108,38 @@
using namespace js;
class AutoVersionAPI
{
JSContext * const cx;
JSVersion oldVersion;
bool oldVersionWasOverride;
uint32 oldOptions;
public:
explicit AutoVersionAPI(JSContext *cx, JSVersion newVersion)
: cx(cx), oldVersion(cx->findVersion()), oldVersionWasOverride(cx->isVersionOverridden()),
oldOptions(cx->options) {
JS_ASSERT(!VersionExtractFlags(newVersion) ||
VersionExtractFlags(newVersion) == VersionFlags::HAS_XML);
cx->options = VersionHasXML(newVersion)
? (cx->options | JSOPTION_XML)
: (cx->options & ~JSOPTION_XML);
cx->maybeOverrideVersion(newVersion);
SyncOptionsToVersion(cx);
}
~AutoVersionAPI() {
cx->options = oldOptions;
if (oldVersionWasOverride) {
JS_ALWAYS_TRUE(cx->maybeOverrideVersion(oldVersion));
} else {
cx->clearVersionOverride();
cx->setDefaultVersion(oldVersion);
}
JS_ASSERT(cx->findVersion() == oldVersion);
}
};
#ifdef HAVE_VA_LIST_AS_ARRAY
#define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
#else
@ -983,28 +1015,40 @@ JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
JS_PUBLIC_API(JSVersion)
JS_GetVersion(JSContext *cx)
{
return JSVERSION_NUMBER(cx);
return VersionNumber(cx->findVersion());
}
static void
CheckOptionVersionSync(JSContext *cx)
{
#if DEBUG
uint32 options = cx->options;
JSVersion version = cx->findVersion();
JS_ASSERT(OptionsHasXML(options) == VersionHasXML(version));
JS_ASSERT(OptionsHasAnonFunFix(options) == VersionHasAnonFunFix(version));
#endif
}
JS_PUBLIC_API(JSVersion)
JS_SetVersion(JSContext *cx, JSVersion version)
JS_SetVersion(JSContext *cx, JSVersion newVersion)
{
JSVersion oldVersion;
JS_ASSERT(VersionIsKnown(newVersion));
JS_ASSERT(!VersionHasFlags(newVersion));
JSVersion newVersionNumber = newVersion;
JS_ASSERT(version != JSVERSION_UNKNOWN);
JS_ASSERT((version & ~JSVERSION_MASK) == 0);
oldVersion = JSVERSION_NUMBER(cx);
if (version == oldVersion)
return oldVersion;
JSVersion oldVersion = cx->findVersion();
JSVersion oldVersionNumber = VersionNumber(oldVersion);
if (oldVersionNumber == newVersionNumber)
return oldVersionNumber; /* No override actually occurs! */
/* We no longer support 1.4 or below. */
if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4)
return oldVersion;
if (newVersionNumber != JSVERSION_DEFAULT && newVersionNumber <= JSVERSION_1_4)
return oldVersionNumber;
cx->version = (cx->version & ~JSVERSION_MASK) | version;
js_OnVersionChange(cx);
return oldVersion;
VersionCloneFlags(oldVersion, &newVersion);
cx->maybeOverrideVersion(newVersion);
CheckOptionVersionSync(cx);
return oldVersionNumber;
}
static struct v2smap {
@ -1051,6 +1095,11 @@ JS_StringToVersion(const char *string)
JS_PUBLIC_API(uint32)
JS_GetOptions(JSContext *cx)
{
/*
* Can't check option/version synchronization here.
* We may have been synchronized with a script version that was formerly on
* the stack, but has now been popped.
*/
return cx->options;
}
@ -1060,8 +1109,14 @@ JS_SetOptions(JSContext *cx, uint32 options)
AutoLockGC lock(cx->runtime);
uint32 oldopts = cx->options;
cx->options = options;
js_SyncOptionsToVersion(cx);
#if DEBUG
bool changedVersion =
#else
(void)
#endif
SyncOptionsToVersion(cx);
cx->updateJITEnabled();
CheckOptionVersionSync(cx);
return oldopts;
}
@ -1069,10 +1124,12 @@ JS_PUBLIC_API(uint32)
JS_ToggleOptions(JSContext *cx, uint32 options)
{
AutoLockGC lock(cx->runtime);
CheckOptionVersionSync(cx);
uint32 oldopts = cx->options;
cx->options ^= options;
js_SyncOptionsToVersion(cx);
(void) SyncOptionsToVersion(cx);
cx->updateJITEnabled();
CheckOptionVersionSync(cx);
return oldopts;
}
@ -4291,6 +4348,17 @@ JS_OPTIONS_TO_TCFLAGS(JSContext *cx)
((cx->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0);
}
extern JS_PUBLIC_API(JSScript *)
JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
JSPrincipals *principals,
const jschar *chars, size_t length,
const char *filename, uintN lineno,
JSVersion version)
{
AutoVersionAPI avi(cx, version);
return JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
}
JS_PUBLIC_API(JSScript *)
JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
const jschar *chars, size_t length,
@ -4486,6 +4554,19 @@ JS_DestroyScript(JSContext *cx, JSScript *script)
JS_ASSERT(script->u.object);
}
JS_PUBLIC_API(JSFunction *)
JS_CompileUCFunctionForPrincipalsVersion(JSContext *cx, JSObject *obj,
JSPrincipals *principals, const char *name,
uintN nargs, const char **argnames,
const jschar *chars, size_t length,
const char *filename, uintN lineno,
JSVersion version)
{
AutoVersionAPI avi(cx, version);
return JS_CompileUCFunctionForPrincipals(cx, obj, principals, name, nargs, argnames, chars,
length, filename, lineno);
}
JS_PUBLIC_API(JSFunction *)
JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
JSPrincipals *principals, const char *name,
@ -4652,6 +4733,18 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
return ok;
}
JS_PUBLIC_API(JSBool)
JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
JSPrincipals *principals,
const jschar *chars, uintN length,
const char *filename, uintN lineno,
jsval *rval, JSVersion version)
{
AutoVersionAPI avi(cx, version);
return JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno,
rval);
}
JS_PUBLIC_API(JSBool)
JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
JSPrincipals *principals,

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

@ -2371,6 +2371,13 @@ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
const jschar *chars, size_t length,
const char *filename, uintN lineno);
extern JS_PUBLIC_API(JSScript *)
JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
JSPrincipals *principals,
const jschar *chars, size_t length,
const char *filename, uintN lineno,
JSVersion version);
extern JS_PUBLIC_API(JSScript *)
JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename);
@ -2438,6 +2445,14 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
const jschar *chars, size_t length,
const char *filename, uintN lineno);
extern JS_PUBLIC_API(JSFunction *)
JS_CompileUCFunctionForPrincipalsVersion(JSContext *cx, JSObject *obj,
JSPrincipals *principals, const char *name,
uintN nargs, const char **argnames,
const jschar *chars, size_t length,
const char *filename, uintN lineno,
JSVersion version);
extern JS_PUBLIC_API(JSString *)
JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
uintN indent);
@ -2517,6 +2532,13 @@ JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
const char *filename, uintN lineno,
jsval *rval);
extern JS_PUBLIC_API(JSBool)
JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
JSPrincipals *principals,
const jschar *chars, uintN length,
const char *filename, uintN lineno,
jsval *rval, JSVersion version);
extern JS_PUBLIC_API(JSBool)
JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
JSPrincipals *principals,

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

@ -726,54 +726,20 @@ js_PurgeThreads(JSContext *cx)
#endif
}
/*
* JSOPTION_XML and JSOPTION_ANONFUNFIX must be part of the JS version
* associated with scripts, so in addition to storing them in cx->options we
* duplicate them in cx->version (script->version, etc.) and ensure each bit
* remains synchronized between the two through these two functions.
*/
void
js_SyncOptionsToVersion(JSContext* cx)
bool
js::SyncOptionsToVersion(JSContext* cx)
{
if (cx->options & JSOPTION_XML)
cx->version |= JSVERSION_HAS_XML;
else
cx->version &= ~JSVERSION_HAS_XML;
if (cx->options & JSOPTION_ANONFUNFIX)
cx->version |= JSVERSION_ANONFUNFIX;
else
cx->version &= ~JSVERSION_ANONFUNFIX;
}
inline void
js_SyncVersionToOptions(JSContext* cx)
{
if (cx->version & JSVERSION_HAS_XML)
cx->options |= JSOPTION_XML;
else
cx->options &= ~JSOPTION_XML;
if (cx->version & JSVERSION_ANONFUNFIX)
cx->options |= JSOPTION_ANONFUNFIX;
else
cx->options &= ~JSOPTION_ANONFUNFIX;
}
void
js_OnVersionChange(JSContext *cx)
{
#ifdef DEBUG
JSVersion version = JSVERSION_NUMBER(cx);
JS_ASSERT(version == JSVERSION_DEFAULT || version >= JSVERSION_ECMA_3);
#endif
}
void
js_SetVersion(JSContext *cx, JSVersion version)
{
cx->version = version;
js_SyncVersionToOptions(cx);
js_OnVersionChange(cx);
JSVersion version = cx->findVersion();
uint32 options = cx->options;
if (OptionsHasXML(options) == VersionHasXML(version) &&
OptionsHasAnonFunFix(options) == VersionHasAnonFunFix(version)) {
/* No need to override. */
return false;
}
VersionSetXML(&version, OptionsHasXML(options));
VersionSetAnonFunFix(&version, OptionsHasAnonFunFix(options));
cx->maybeOverrideVersion(version);
return true;
}
JSContext *
@ -799,7 +765,7 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
#endif
cx->scriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA;
JS_STATIC_ASSERT(JSVERSION_DEFAULT == 0);
JS_ASSERT(cx->version == JSVERSION_DEFAULT);
JS_ASSERT(cx->findVersion() == JSVERSION_DEFAULT);
VOUCH_DOES_NOT_REQUIRE_STACK();
JS_InitArenaPool(&cx->tempPool, "temp", TEMP_POOL_CHUNK_SIZE, sizeof(jsdouble),

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

@ -2019,6 +2019,97 @@ class RegExpStatics
void getRightContext(JSSubString *out) const;
};
#define JS_HAS_OPTION(cx,option) (((cx)->options & (option)) != 0)
#define JS_HAS_STRICT_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_STRICT)
#define JS_HAS_WERROR_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_WERROR)
#define JS_HAS_COMPILE_N_GO_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_COMPILE_N_GO)
#define JS_HAS_ATLINE_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_ATLINE)
static inline bool
OptionsHasXML(uint32 options)
{
return !!(options & JSOPTION_XML);
}
static inline bool
OptionsHasAnonFunFix(uint32 options)
{
return !!(options & JSOPTION_ANONFUNFIX);
}
static inline bool
OptionsSameVersionFlags(uint32 self, uint32 other)
{
static const uint32 mask = JSOPTION_XML | JSOPTION_ANONFUNFIX;
return !((self & mask) ^ (other & mask));
}
namespace VersionFlags {
static const uint32 MASK = 0x0FFF; /* see JSVersion in jspubtd.h */
static const uint32 HAS_XML = 0x1000; /* flag induced by XML option */
static const uint32 ANONFUNFIX = 0x2000; /* see jsapi.h comment on JSOPTION_ANONFUNFIX */
}
static inline bool
VersionHasXML(JSVersion version)
{
return !!(version & VersionFlags::HAS_XML);
}
static inline bool
VersionHasAnonFunFix(JSVersion version)
{
return !!(version & VersionFlags::ANONFUNFIX);
}
static inline void
VersionSetXML(JSVersion *version, bool enable)
{
if (enable)
*version = JSVersion(uint32(*version) | VersionFlags::HAS_XML);
else
*version = JSVersion(uint32(*version) & ~VersionFlags::HAS_XML);
}
static inline void
VersionSetAnonFunFix(JSVersion *version, bool enable)
{
if (enable)
*version = JSVersion(uint32(*version) | VersionFlags::ANONFUNFIX);
else
*version = JSVersion(uint32(*version) & ~VersionFlags::ANONFUNFIX);
}
static inline JSVersion
VersionExtractFlags(JSVersion version)
{
return JSVersion(uint32(version) & ~VersionFlags::MASK);
}
static inline bool
VersionHasFlags(JSVersion version)
{
return !!VersionExtractFlags(version);
}
static inline JSVersion
VersionNumber(JSVersion version)
{
return JSVersion(uint32(version) & VersionFlags::MASK);
}
static inline bool
VersionIsKnown(JSVersion version)
{
return VersionNumber(version) != JSVERSION_UNKNOWN;
}
static inline void
VersionCloneFlags(JSVersion src, JSVersion *dst)
{
*dst = JSVersion(uint32(VersionNumber(*dst)) | uint32(VersionExtractFlags(src)));
}
} /* namespace js */
struct JSContext
@ -2028,9 +2119,13 @@ struct JSContext
/* JSRuntime contextList linkage. */
JSCList link;
/* Runtime version control identifier. */
uint16 version;
private:
/* See JSContext::findVersion. */
JSVersion defaultVersion; /* script compilation version */
JSVersion versionOverride; /* supercedes defaultVersion when valid */
bool hasVersionOverride;
public:
/* Per-context options. */
uint32 options; /* see jsapi.h for JSOPTION_* */
@ -2189,11 +2284,9 @@ struct JSContext
*/
js::StackSegment *containingSegment(const JSStackFrame *target);
/*
* Search the call stack for the nearest frame with static level targetLevel.
*/
JSStackFrame *findFrameAtLevel(uintN targetLevel) {
JSStackFrame *fp = this->regs->fp;
/* Search the call stack for the nearest frame with static level targetLevel. */
JSStackFrame *findFrameAtLevel(uintN targetLevel) const {
JSStackFrame *fp = regs->fp;
while (true) {
JS_ASSERT(fp && fp->isScriptFrame());
if (fp->script()->staticLevel == targetLevel)
@ -2203,6 +2296,64 @@ struct JSContext
return fp;
}
private:
/*
* The default script compilation version can be set iff there is no code running.
* This typically occurs via the JSAPI right after a context is constructed.
*/
bool canSetDefaultVersion() const { return !regs && !hasVersionOverride; }
/* Force a version for future script compilation. */
void overrideVersion(JSVersion newVersion) {
JS_ASSERT(!canSetDefaultVersion());
versionOverride = newVersion;
hasVersionOverride = true;
}
public:
void clearVersionOverride() { hasVersionOverride = false; }
bool isVersionOverridden() const { return hasVersionOverride; }
/* Set the default script compilation version. */
void setDefaultVersion(JSVersion version) { defaultVersion = version; }
/*
* Set the default version if possible; otherwise, force the version.
* Return whether an override occurred.
*/
bool maybeOverrideVersion(JSVersion newVersion) {
if (canSetDefaultVersion()) {
setDefaultVersion(newVersion);
return false;
}
overrideVersion(newVersion);
return true;
}
/*
* Return:
* - The override version, if there is an override version.
* - The newest scripted frame's version, if there is such a frame.
* - The default verion.
*
* @note If this ever shows up in a profile, just add caching!
*/
JSVersion findVersion() const {
if (hasVersionOverride)
return versionOverride;
if (regs) {
/* There may be a scripted function somewhere on the stack! */
JSStackFrame *fp = regs->fp;
while (fp && !fp->isScriptFrame())
fp = fp->prev();
if (fp)
return fp->script()->getVersion();
}
return defaultVersion;
}
#ifdef JS_THREADSAFE
JSThread *thread;
unsigned outstandingRequests;/* number of JS_BeginRequest calls
@ -2950,49 +3101,6 @@ class JSAutoResolveFlags
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/*
* Slightly more readable macros for testing per-context option settings (also
* to hide bitset implementation detail).
*
* JSOPTION_XML must be handled specially in order to propagate from compile-
* to run-time (from cx->options to script->version/cx->version). To do that,
* we copy JSOPTION_XML from cx->options into cx->version as JSVERSION_HAS_XML
* whenever options are set, and preserve this XML flag across version number
* changes done via the JS_SetVersion API.
*
* But when executing a script or scripted function, the interpreter changes
* cx->version, including the XML flag, to script->version. Thus JSOPTION_XML
* is a compile-time option that causes a run-time version change during each
* activation of the compiled script. That version change has the effect of
* changing JS_HAS_XML_OPTION, so that any compiling done via eval enables XML
* support. If an XML-enabled script or function calls a non-XML function,
* the flag bit will be cleared during the callee's activation.
*
* Note that JS_SetVersion API calls never pass JSVERSION_HAS_XML or'd into
* that API's version parameter.
*
* Note also that script->version must contain this XML option flag in order
* for XDR'ed scripts to serialize and deserialize with that option preserved
* for detection at run-time. We can't copy other compile-time options into
* script->version because that would break backward compatibility (certain
* other options, e.g. JSOPTION_VAROBJFIX, are analogous to JSOPTION_XML).
*/
#define JS_HAS_OPTION(cx,option) (((cx)->options & (option)) != 0)
#define JS_HAS_STRICT_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_STRICT)
#define JS_HAS_WERROR_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_WERROR)
#define JS_HAS_COMPILE_N_GO_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_COMPILE_N_GO)
#define JS_HAS_ATLINE_OPTION(cx) JS_HAS_OPTION(cx, JSOPTION_ATLINE)
#define JSVERSION_MASK 0x0FFF /* see JSVersion in jspubtd.h */
#define JSVERSION_HAS_XML 0x1000 /* flag induced by XML option */
#define JSVERSION_ANONFUNFIX 0x2000 /* see jsapi.h, the comments
for JSOPTION_ANONFUNFIX */
#define JSVERSION_NUMBER(cx) ((JSVersion)((cx)->version & \
JSVERSION_MASK))
#define JS_HAS_XML_OPTION(cx) ((cx)->version & JSVERSION_HAS_XML || \
JSVERSION_NUMBER(cx) >= JSVERSION_1_6)
extern JSThreadData *
js_CurrentThreadData(JSRuntime *rt);
@ -3046,30 +3154,16 @@ class ThreadDataIter
#endif /* !JS_THREADSAFE */
/*
* If necessary, push the option flags that affect script compilation to the current version.
* Note this may cause a version override -- see JSContext::overrideVersion.
* Return whether a version change occurred.
*/
extern bool
SyncOptionsToVersion(JSContext *cx);
} /* namespace js */
/*
* Ensures the JSOPTION_XML and JSOPTION_ANONFUNFIX bits of cx->options are
* reflected in cx->version, since each bit must travel with a script that has
* it set.
*/
extern void
js_SyncOptionsToVersion(JSContext *cx);
/*
* Common subroutine of JS_SetVersion and js_SetVersion, to update per-context
* data that depends on version.
*/
extern void
js_OnVersionChange(JSContext *cx);
/*
* Unlike the JS_SetVersion API, this function stores JSVERSION_HAS_XML and
* any future non-version-number flags induced by compiler options.
*/
extern void
js_SetVersion(JSContext *cx, JSVersion version);
/*
* Create and destroy functions for JSContext, which is manually allocated
* and exclusively owned.

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

@ -1303,7 +1303,7 @@ JS_GetScriptLineExtent(JSContext *cx, JSScript *script)
JS_PUBLIC_API(JSVersion)
JS_GetScriptVersion(JSContext *cx, JSScript *script)
{
return (JSVersion) (script->version & JSVERSION_MASK);
return VersionNumber(script->getVersion());
}
/***************************************************************************/
@ -1789,6 +1789,12 @@ JS_MakeSystemObject(JSContext *cx, JSObject *obj)
/************************************************************************/
JS_FRIEND_API(void)
js_RevertVersion(JSContext *cx)
{
cx->clearVersionOverride();
}
JS_PUBLIC_API(const JSDebugHooks *)
JS_GetGlobalDebugHooks(JSRuntime *rt)
{

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

@ -492,6 +492,9 @@ JS_MakeSystemObject(JSContext *cx, JSObject *obj);
/************************************************************************/
extern JS_FRIEND_API(void)
js_RevertVersion(JSContext *cx);
extern JS_PUBLIC_API(const JSDebugHooks *)
JS_GetGlobalDebugHooks(JSRuntime *rt);

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

@ -474,7 +474,7 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun)
wscript->savedCallerFun = script->savedCallerFun;
wscript->hasSharps = script->hasSharps;
wscript->strictModeCode = script->strictModeCode;
wscript->version = script->version;
wscript->setVersion(script->getVersion());
wscript->nfixed = script->nfixed;
wscript->filename = script->filename;
wscript->lineno = script->lineno;
@ -2738,7 +2738,7 @@ Function(JSContext *cx, uintN argc, Value *vp)
/* Initialize a tokenstream that reads from the given string. */
TokenStream ts(cx);
if (!ts.init(collected_args, args_length, NULL, filename, lineno)) {
if (!ts.init(cx->findVersion(), collected_args, args_length, NULL, filename, lineno)) {
JS_ARENA_RELEASE(&cx->tempPool, mark);
return JS_FALSE;
}

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

@ -2097,7 +2097,6 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, uintN
script = regs.fp->script(); \
argv = regs.fp->maybeFormalArgs(); \
atoms = FrameAtomBase(cx, regs.fp); \
currentVersion = (JSVersion) script->version; \
JS_ASSERT(cx->regs == &regs); \
if (cx->throwing) \
goto error; \
@ -2213,20 +2212,6 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, uintN
if (!entryFrame)
entryFrame = regs.fp;
/*
* Optimized Get and SetVersion for proper script language versioning.
*
* If any native method or a Class ObjectOps hook calls js_SetVersion
* and changes cx->version, the effect will "stick" and we will stop
* maintaining currentVersion. This is relied upon by testsuites, for
* the most part -- web browsers select version before compiling and not
* at run-time.
*/
JSVersion currentVersion = (JSVersion) script->version;
JSVersion originalVersion = (JSVersion) cx->version;
if (currentVersion != originalVersion)
js_SetVersion(cx, currentVersion);
/*
* Initialize the index segment register used by LOAD_ATOM and
* GET_FULL_INDEX macros below. As a register we use a pointer based on
@ -2537,13 +2522,6 @@ BEGIN_CASE(JSOP_STOP)
Probes::exitJSFun(cx, regs.fp->maybeFun());
/* Restore context version only if callee hasn't set version. */
if (JS_LIKELY(cx->version == currentVersion)) {
currentVersion = regs.fp->callerVersion();
if (currentVersion != cx->version)
js_SetVersion(cx, currentVersion);
}
/*
* If inline-constructing, replace primitive rval with the new object
* passed in via |this|, and instrument this constructor invocation.
@ -4445,14 +4423,6 @@ BEGIN_CASE(JSOP_APPLY)
newfp->initCallFrame(cx, *callee, newfun, argc, flags);
SetValueRangeToUndefined(newfp->slots(), newscript->nfixed);
/* Switch version if currentVersion wasn't overridden. */
newfp->setCallerVersion((JSVersion) cx->version);
if (JS_LIKELY(cx->version == currentVersion)) {
currentVersion = (JSVersion) newscript->version;
if (JS_UNLIKELY(currentVersion != cx->version))
js_SetVersion(cx, currentVersion);
}
/* Officially push the frame. */
stack.pushInlineFrame(cx, newscript, newfp, &regs);
@ -6753,9 +6723,6 @@ END_CASE(JSOP_ARRAYPUSH)
JS_ASSERT_IF(!regs.fp->isGeneratorFrame(), !regs.fp->hasBlockChain());
JS_ASSERT_IF(!regs.fp->isGeneratorFrame(), !js_IsActiveWithOrBlock(cx, &regs.fp->scopeChain(), 0));
/* Undo the remaining effects committed on entry to Interpret. */
if (cx->version == currentVersion && currentVersion != originalVersion)
js_SetVersion(cx, originalVersion);
--cx->interpLevel;
return interpReturnOK;

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

@ -126,7 +126,6 @@ struct JSStackFrame
/* TODO: remove */
void *ncode_; /* bug 535912 */
JSVersion callerVersion_; /* bug 535912 */
JSObject *blockChain_; /* bug 540675 */
#if JS_BITS_PER_WORD == 32
@ -553,16 +552,6 @@ struct JSStackFrame
flags_ |= JSFRAME_HAS_HOOK_DATA;
}
/* Version */
JSVersion callerVersion() const {
return callerVersion_;
}
void setCallerVersion(JSVersion version) {
callerVersion_ = version;
}
/* Return value */
const js::Value& returnValue() {
@ -740,10 +729,6 @@ struct JSStackFrame
return offsetof(JSStackFrame, ncode_);
}
static size_t offsetOfCallerVersion() {
return offsetof(JSStackFrame, callerVersion_);
}
static size_t offsetOfBlockChain() {
return offsetof(JSStackFrame, blockChain_);
}

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

@ -113,7 +113,6 @@ JSStackFrame::initCallFrameLatePrologue()
{
rval_.setUndefined();
blockChain_ = NULL;
callerVersion_ = prev_->callerVersion_; // WRONG
SetValueRangeToUndefined(slots(), script()->nfixed);
}

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

@ -1168,10 +1168,11 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
JSScript **scriptp = bucket;
EVAL_CACHE_METER(probe);
JSVersion version = cx->findVersion();
while ((script = *scriptp) != NULL) {
if (script->savedCallerFun &&
script->staticLevel == staticLevel &&
script->version == cx->version &&
script->version == version &&
(script->principals == principals ||
(principals->subsume(principals, script->principals) &&
script->principals->subsume(script->principals, principals)))) {

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

@ -193,9 +193,10 @@ Parser::init(const jschar *base, size_t length,
FILE *fp, const char *filename, uintN lineno)
{
JSContext *cx = context;
version = cx->findVersion();
tempPoolMark = JS_ARENA_MARK(&cx->tempPool);
if (!tokenStream.init(base, length, fp, filename, lineno)) {
if (!tokenStream.init(version, base, length, fp, filename, lineno)) {
JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
return false;
}
@ -4921,7 +4922,7 @@ Parser::statement()
PopStatement(tc);
pn->pn_pos.end = pn2->pn_pos.end;
pn->pn_right = pn2;
if (JSVERSION_NUMBER(context) != JSVERSION_ECMA_3) {
if (VersionNumber(version) != JSVERSION_ECMA_3) {
/*
* All legacy and extended versions must do automatic semicolon
* insertion after do-while. See the testcase and discussion in
@ -5024,7 +5025,7 @@ Parser::statement()
if (TokenKindIsDecl(tt)
? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST
#if JS_HAS_DESTRUCTURING
|| (JSVERSION_NUMBER(context) == JSVERSION_1_7 &&
|| (VersionNumber(version) == JSVERSION_1_7 &&
pn->pn_op == JSOP_ITER &&
!(pn->pn_iflags & JSITER_FOREACH) &&
(pn1->pn_head->pn_type == TOK_RC ||
@ -5038,7 +5039,7 @@ Parser::statement()
: (pn1->pn_type != TOK_NAME &&
pn1->pn_type != TOK_DOT &&
#if JS_HAS_DESTRUCTURING
((JSVERSION_NUMBER(context) == JSVERSION_1_7 &&
((VersionNumber(version) == JSVERSION_1_7 &&
pn->pn_op == JSOP_ITER &&
!(pn->pn_iflags & JSITER_FOREACH))
? (pn1->pn_type != TOK_RB || pn1->pn_count != 2)
@ -5175,7 +5176,7 @@ Parser::statement()
if (pn1 == pn2 && !CheckDestructuring(context, NULL, pn2, NULL, tc))
return NULL;
if (JSVERSION_NUMBER(context) == JSVERSION_1_7) {
if (VersionNumber(version) == JSVERSION_1_7) {
/*
* Destructuring for-in requires [key, value] enumeration
* in JS1.7.
@ -6878,7 +6879,7 @@ Parser::comprehensionTail(JSParseNode *kid, uintN blockid,
if (!CheckDestructuring(context, &data, pn3, NULL, tc))
return NULL;
if (JSVERSION_NUMBER(context) == JSVERSION_1_7) {
if (VersionNumber(version) == JSVERSION_1_7) {
/* Destructuring requires [key, value] enumeration in JS1.7. */
if (pn3->pn_type != TOK_RB || pn3->pn_count != 2) {
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE);
@ -7896,8 +7897,16 @@ Parser::xmlElementOrListRoot(JSBool allowList)
* that don't recognize <script>).
*/
oldopts = JS_SetOptions(context, context->options | JSOPTION_XML);
version = context->findVersion();
tokenStream.setVersion(version);
JS_ASSERT(VersionHasXML(version));
pn = xmlElementOrList(allowList);
JS_SetOptions(context, oldopts);
version = context->findVersion();
tokenStream.setVersion(version);
JS_ASSERT(!!(oldopts & JSOPTION_XML) == VersionHasXML(version));
return pn;
}

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

@ -994,6 +994,7 @@ struct Parser : private js::AutoGCRooter
uint32 functionCount; /* number of functions in current unit */
JSObjectBox *traceListHead; /* list of parsed object for GC tracing */
JSTreeContext *tc; /* innermost tree context (stack-allocated) */
JSVersion version; /* cached version to avoid repeated lookups */
/* Root atoms and objects allocated for the parsed tree. */
js::AutoKeepAtoms keepAtoms;

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

@ -185,15 +185,16 @@ TokenStream::TokenStream(JSContext *cx)
#endif
bool
TokenStream::init(const jschar *base, size_t length, FILE *fp, const char *fn, uintN ln)
TokenStream::init(JSVersion version, const jschar *base, size_t length, FILE *fp,
const char *fn, uintN ln)
{
jschar *buf;
this->version = version;
JS_ASSERT_IF(fp, !base);
JS_ASSERT_IF(!base, length == 0);
size_t nb = fp
? (UNGET_LIMIT + 2 * LINE_LIMIT) * sizeof(jschar) /* see below */
: (UNGET_LIMIT + 1 * LINE_LIMIT) * sizeof(jschar);
jschar *buf;
JS_ARENA_ALLOCATE_CAST(buf, jschar *, &cx->tempPool, nb);
if (!buf) {
js_ReportOutOfScriptQuota(cx);
@ -1102,7 +1103,7 @@ TokenStream::getTokenInternal()
JSMSG_RESERVED_ID, kw->chars)) {
goto error;
}
} else if (kw->version <= JSVERSION_NUMBER(cx)) {
} else if (kw->version <= VersionNumber(version)) {
tt = kw->tokentype;
tp->t_op = (JSOp) kw->op;
goto out;
@ -1438,7 +1439,7 @@ TokenStream::getTokenInternal()
* The check for this is in jsparse.cpp, Compiler::compileScript.
*/
if ((flags & TSF_OPERAND) &&
(JS_HAS_XML_OPTION(cx) || peekChar() != '!')) {
(VersionHasXML(version) || peekChar() != '!')) {
/* Check for XML comment or CDATA section. */
if (matchChar('!')) {
tokenbuf.clear();

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

@ -320,7 +320,8 @@ class TokenStream
* Create a new token stream, either from an input buffer or from a file.
* Return false on file-open or memory-allocation failure.
*/
bool init(const jschar *base, size_t length, FILE *fp, const char *filename, uintN lineno);
bool init(JSVersion version, const jschar *base, size_t length, FILE *fp,
const char *filename, uintN lineno);
void close();
~TokenStream() {}
@ -441,6 +442,8 @@ class TokenStream
return JS_FALSE;
}
void setVersion(JSVersion newVersion) { version = newVersion; }
private:
typedef struct TokenBuf {
jschar *base; /* base of line or stream buffer */
@ -511,6 +514,7 @@ class TokenStream
JSCharBuffer tokenbuf; /* current token string buffer */
bool maybeEOL[256]; /* probabilistic EOL lookup table */
bool maybeStrSpecial[256];/* speeds up string scanning */
JSVersion version; /* cached version number for scan */
};
} /* namespace js */

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

@ -163,7 +163,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
if (!script)
return JS_FALSE;
script->version = JSVERSION_DEFAULT;
script->setVersion(JSVERSION_DEFAULT);
script->noScriptRval = true;
script->code[0] = JSOP_STOP;
script->code[1] = SRC_NULL;
@ -177,8 +177,8 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
if (xdr->mode == JSXDR_ENCODE) {
prologLength = script->main - script->code;
JS_ASSERT((int16)script->version != JSVERSION_UNKNOWN);
version = (uint32)script->version | (script->nfixed << 16);
JS_ASSERT(script->getVersion() != JSVERSION_UNKNOWN);
version = (uint32)script->getVersion() | (script->nfixed << 16);
lineno = (uint32)script->lineno;
nslots = (uint32)script->nslots;
nslots = (uint32)((script->staticLevel << 16) | script->nslots);
@ -236,7 +236,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
return JS_FALSE;
script->main += prologLength;
script->version = JSVersion(version & 0xffff);
script->setVersion(JSVersion(version & 0xffff));
script->nfixed = uint16(version >> 16);
/* If we know nsrcnotes, we allocated space for notes in script. */
@ -881,7 +881,7 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
PodZero(script);
script->length = length;
script->version = cx->version;
script->setVersion(cx->findVersion());
cursor = (uint8 *)script + sizeof(JSScript);
if (nobjects != 0) {

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

@ -326,6 +326,15 @@ struct JSScript {
return getAtom(arr->vector[index].atomIndex);
}
JSVersion getVersion() const {
return JSVersion(version);
}
void setVersion(JSVersion newVersion) {
JS_ASSERT((newVersion & JS_BITMASK(16)) == uint32(newVersion));
version = newVersion;
}
inline JSFunction *getFunction(size_t index);
inline JSObject *getRegExp(size_t index);

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

@ -5717,12 +5717,6 @@ SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee)
newfp->setScopeChainNoCallObj(*JSStackFrame::sInvalidScopeChain);
#endif
/*
* Note that fp->script is still the caller's script; set the callee
* inline frame's idea of caller version from its version.
*/
newfp->setCallerVersion((JSVersion) fp->script()->version);
/* Officially push the frame. */
stack.pushInlineFrame(cx, newscript, newfp, cx->regs);

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

@ -271,9 +271,6 @@ mjit::Compiler::generatePrologue()
masm.storeValue(UndefinedValue(), Address(JSFrameReg, JSStackFrame::offsetOfReturnValue()));
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetOfBlockChain()));
/* :TODO: This is entirely wrong. */
masm.store32(Imm32(cx->version), Address(JSFrameReg, JSStackFrame::offsetOfCallerVersion()));
/* Set cx->fp */
masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), Registers::ReturnReg);

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

@ -213,8 +213,6 @@ InlineReturn(VMFrame &f, JSBool ok)
PutActivationObjects(cx, fp);
/* :TODO: version stuff */
if (fp->isConstructing() && fp->returnValue().isPrimitive())
fp->setReturnValue(fp->thisValue());
@ -433,9 +431,6 @@ UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
newfp->initCallFrame(cx, callee, newfun, argc, flags);
SetValueRangeToUndefined(newfp->slots(), newscript->nfixed);
/* :TODO: Switch version if currentVersion wasn't overridden. */
newfp->setCallerVersion((JSVersion)cx->version);
/* Officially push the frame. */
stack.pushInlineFrame(cx, newscript, newfp, &f.regs);
JS_ASSERT(newfp == f.regs.fp);

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

@ -875,6 +875,14 @@ Version(JSContext *cx, uintN argc, jsval *vp)
return JS_TRUE;
}
static JSBool
RevertVersion(JSContext *cx, uintN argc, jsval *vp)
{
js_RevertVersion(cx);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
static JSBool
Options(JSContext *cx, uintN argc, jsval *vp)
{
@ -4086,6 +4094,7 @@ Wrap(JSContext *cx, uintN argc, jsval *vp)
/* We use a mix of JS_FS and JS_FN to test both kinds of natives. */
static JSFunctionSpec shell_functions[] = {
JS_FN("version", Version, 0,0),
JS_FN("revertVersion", RevertVersion, 0,0),
JS_FN("options", Options, 0,0),
JS_FN("load", Load, 1,0),
JS_FN("readline", ReadLine, 0,0),
@ -4185,7 +4194,8 @@ static const char shell_help_header[] =
"======= ===========\n";
static const char *const shell_help_messages[] = {
"version([number]) Get or set JavaScript version number",
"version([number]) Get or force a script compilation version number",
"revertVersion() Revert previously set version number",
"options([option ...]) Get or toggle JavaScript options",
"load(['foo.js' ...]) Load files named by string arguments",
"readline() Read a single line from stdin",

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

@ -209,11 +209,11 @@ function test()
{
var v = version(150);
f = new Function("return version(arguments[0])");
version(v);
revertVersion();
expect(150, f());
//expect(150, eval("f()"));
expect(150, eval("f()"));
expect(0, eval("f(0); f()"));
version(v);
revertVersion();
}
print("End of Tests");