Bug 542797 - change obj_eval from JSNative to JSFastNative (r=mrbkap)

--HG--
extra : rebase_source : 5138b86418081cfa331b05947e5988c1f81065ef
This commit is contained in:
Luke Wagner 2010-02-16 17:41:39 -08:00
parent 87a5e61db3
commit df420a425b
7 changed files with 78 additions and 101 deletions

View File

@ -1123,18 +1123,17 @@ JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
return NULL;
}
JS_PUBLIC_API(JSPrincipals *)
JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
JSPrincipals *
js_EvalFramePrincipals(JSContext *cx, JSObject *callee, JSStackFrame *caller)
{
JSPrincipals *principals, *callerPrincipals;
JSSecurityCallbacks *callbacks;
callbacks = JS_GetSecurityCallbacks(cx);
if (callbacks && callbacks->findObjectPrincipals) {
principals = callbacks->findObjectPrincipals(cx, fp->callee());
} else {
if (callbacks && callbacks->findObjectPrincipals)
principals = callbacks->findObjectPrincipals(cx, callee);
else
principals = NULL;
}
if (!caller)
return principals;
callerPrincipals = JS_StackFramePrincipals(cx, caller);
@ -1144,6 +1143,12 @@ JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
: callerPrincipals;
}
JS_PUBLIC_API(JSPrincipals *)
JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
{
return js_EvalFramePrincipals(cx, fp->callee(), caller);
}
JS_PUBLIC_API(void *)
JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
{

View File

@ -195,6 +195,9 @@ JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp);
extern JS_PUBLIC_API(JSPrincipals *)
JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller);
JSPrincipals *
js_EvalFramePrincipals(JSContext *cx, JSObject *callee, JSStackFrame *caller);
extern JS_PUBLIC_API(void *)
JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp);

View File

@ -1567,7 +1567,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
* CallStack of |down|. If |down == cx->fp|, the callstack is simply
* the context's active callstack, so we can use |down->varobj(cx)|.
* When |down != cx->fp|, we need to do a slow linear search. Luckily,
* this only happens with eval and JS_EvaluateInStackFrame.
* this only happens with indirect eval and JS_EvaluateInStackFrame.
*/
if (down == cx->fp) {
callStack.setInitialVarObj(down->varobj(cx));

View File

@ -1244,33 +1244,21 @@ EvalCacheHash(JSContext *cx, JSString *str)
}
static JSBool
obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
obj_eval(JSContext *cx, uintN argc, jsval *vp)
{
JSStackFrame *fp, *caller, *callerFrame;
JSBool indirectCall;
JSPrincipals *principals;
const char *file;
uintN line;
JSString *str;
JSScript *script;
JSBool ok;
JSScript **bucket = NULL; /* avoid GCC warning with early decl&init */
#if JS_HAS_EVAL_THIS_SCOPE
JSObject *callerScopeChain = NULL;
JSBool setCallerScopeChain = JS_FALSE;
JSTempValueRooter scopetvr;
#endif
JSObject *withObject = NULL;
if (argc < 1) {
*vp = JSVAL_VOID;
return JS_TRUE;
}
fp = js_GetTopStackFrame(cx);
caller = js_GetScriptedCaller(cx, fp);
JSStackFrame *caller = js_GetTopStackFrame(cx);
if (!caller) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_INDIRECT_CALL, js_eval_str);
return JS_FALSE;
}
indirectCall = (caller->regs && *caller->regs->pc != JSOP_EVAL);
bool indirectCall = (caller->regs && *caller->regs->pc != JSOP_EVAL);
/*
* This call to js_GetWrappedObject is safe because of the security checks
@ -1281,6 +1269,10 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
* we're guaranteed to be allowed to access) then we do a security
* check.
*/
jsval *argv = JS_ARGV(cx, vp);
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
obj = js_GetWrappedObject(cx, obj);
/*
@ -1303,7 +1295,7 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
}
if (!JSVAL_IS_STRING(argv[0])) {
*rval = argv[0];
*vp = argv[0];
return JS_TRUE;
}
@ -1323,6 +1315,13 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
argv[1] = OBJECT_TO_JSVAL(scopeobj);
}
/* Guard for conditionally-created with object below. */
struct WithGuard {
JSObject *obj;
WithGuard() : obj(NULL) {}
~WithGuard() { if (obj) obj->setPrivate(NULL); }
} withGuard;
/* From here on, control must exit through label out with ok set. */
MUST_FLOW_THROUGH("out");
uintN staticLevel = caller->script->staticLevel + 1;
@ -1331,11 +1330,9 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
* Bring fp->scopeChain up to date. We're either going to use
* it (direct call) or save it and restore it (indirect call).
*/
callerScopeChain = js_GetScopeChain(cx, caller);
if (!callerScopeChain) {
ok = JS_FALSE;
goto out;
}
JSObject *callerScopeChain = js_GetScopeChain(cx, caller);
if (!callerScopeChain)
return JS_FALSE;
#if JS_HAS_EVAL_THIS_SCOPE
/*
@ -1348,24 +1345,18 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
staticLevel = 0;
OBJ_TO_INNER_OBJECT(cx, obj);
if (!obj) {
ok = JS_FALSE;
goto out;
}
if (!obj)
return JS_FALSE;
ok = js_CheckPrincipalsAccess(cx, obj,
if (!js_CheckPrincipalsAccess(cx, obj,
JS_StackFramePrincipals(cx, caller),
cx->runtime->atomState.evalAtom);
if (!ok)
goto out;
cx->runtime->atomState.evalAtom)) {
return JS_FALSE;
}
/* NB: We know obj is a global object here. */
JS_ASSERT(!OBJ_GET_PARENT(cx, obj));
caller->scopeChain = scopeobj = obj;
/* Remember scopeobj so we can null its private when done. */
setCallerScopeChain = JS_TRUE;
JS_PUSH_TEMP_ROOT_OBJECT(cx, callerScopeChain, &scopetvr);
scopeobj = obj;
} else {
/*
* Compile using the caller's current scope object.
@ -1379,33 +1370,27 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
} else {
scopeobj = js_GetWrappedObject(cx, scopeobj);
OBJ_TO_INNER_OBJECT(cx, scopeobj);
if (!scopeobj) {
ok = JS_FALSE;
goto out;
}
if (!scopeobj)
return JS_FALSE;
ok = js_CheckPrincipalsAccess(cx, scopeobj,
if (!js_CheckPrincipalsAccess(cx, scopeobj,
JS_StackFramePrincipals(cx, caller),
cx->runtime->atomState.evalAtom);
if (!ok)
goto out;
cx->runtime->atomState.evalAtom))
return JS_FALSE;
/*
* If scopeobj is not a global object, then we need to wrap it in a
* with object to maintain invariants in the engine (see bug 520164).
*/
if (scopeobj->getParent()) {
withObject = js_NewWithObject(cx, scopeobj,
JS_GetGlobalForObject(cx, scopeobj),
0);
if (!withObject) {
ok = JS_FALSE;
goto out;
}
scopeobj = withObject;
JSObject *global = JS_GetGlobalForObject(cx, scopeobj);
withGuard.obj = js_NewWithObject(cx, scopeobj, global, 0);
if (!withGuard.obj)
return JS_FALSE;
scopeobj = withGuard.obj;
JS_ASSERT(argc >= 2);
argv[1] = OBJECT_TO_JSVAL(scopeobj);
argv[1] = OBJECT_TO_JSVAL(withGuard.obj);
}
/* We're pretending that we're in global code. */
@ -1413,17 +1398,18 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
}
/* Ensure we compile this eval with the right object in the scope chain. */
scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_eval_str);
if (!scopeobj) {
ok = JS_FALSE;
goto out;
}
JSObject *result = js_CheckScopeChainValidity(cx, scopeobj, js_eval_str);
JS_ASSERT_IF(result, result == scopeobj);
if (!result)
return JS_FALSE;
principals = JS_EvalFramePrincipals(cx, fp, caller);
file = js_ComputeFilename(cx, caller, principals, &line);
JSObject *callee = JSVAL_TO_OBJECT(vp[0]);
JSPrincipals *principals = js_EvalFramePrincipals(cx, callee, caller);
uintN line;
const char *file = js_ComputeFilename(cx, caller, principals, &line);
str = JSVAL_TO_STRING(argv[0]);
script = NULL;
JSString *str = JSVAL_TO_STRING(argv[0]);
JSScript *script = NULL;
/*
* Cache local eval scripts indexed by source qualified by scope.
@ -1434,7 +1420,7 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
* eval was called, whose strictness doesn't change. Scripts produced by
* calls to eval from global code are not cached.
*/
bucket = EvalCacheHash(cx, str);
JSScript **bucket = EvalCacheHash(cx, str);
if (!indirectCall && caller->fun) {
uintN count = 0;
JSScript **scriptp = bucket;
@ -1506,32 +1492,24 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
* global code. This includes indirect eval and direct eval called with a
* scope object parameter.
*/
callerFrame = (staticLevel != 0) ? caller : NULL;
JSStackFrame *callerFrame = (staticLevel != 0) ? caller : NULL;
if (!script) {
script = JSCompiler::compileScript(cx, scopeobj, callerFrame,
principals,
TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT,
str->chars(), str->length(),
NULL, file, line, str, staticLevel);
if (!script) {
ok = JS_FALSE;
goto out;
}
}
if (argc < 2) {
/* Execute using caller's new scope object (might be a Call object). */
scopeobj = caller->scopeChain;
if (!script)
return JS_FALSE;
}
/*
* Belt-and-braces: check that the lesser of eval's principals and the
* caller's principals has access to scopeobj.
*/
ok = js_CheckPrincipalsAccess(cx, scopeobj, principals,
cx->runtime->atomState.evalAtom);
if (ok)
ok = js_Execute(cx, scopeobj, script, callerFrame, JSFRAME_EVAL, rval);
JSBool ok = js_CheckPrincipalsAccess(cx, scopeobj, principals,
cx->runtime->atomState.evalAtom) &&
js_Execute(cx, scopeobj, script, callerFrame, JSFRAME_EVAL, vp);
script->u.nextToGC = *bucket;
*bucket = script;
@ -1539,16 +1517,6 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
script->owner = NULL;
#endif
out:
#if JS_HAS_EVAL_THIS_SCOPE
/* Restore OBJ_GET_PARENT(scopeobj) not callerScopeChain in case of Call. */
if (setCallerScopeChain) {
caller->scopeChain = callerScopeChain;
JS_POP_TEMP_ROOT(cx, &scopetvr);
}
#endif
if (withObject)
withObject->setPrivate(NULL);
return ok;
}
@ -3703,7 +3671,8 @@ js_InitEval(JSContext *cx, JSObject *obj)
{
/* ECMA (15.1.2.1) says 'eval' is a property of the global object. */
if (!js_DefineFunction(cx, obj, cx->runtime->atomState.evalAtom,
obj_eval, 1, 0)) {
(JSNative)obj_eval, 1,
JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS)) {
return NULL;
}

View File

@ -806,7 +806,7 @@ XPC_SJOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
if (STOBJ_GET_CLASS(objToWrap) == &js_ScriptClass ||
(::JS_ObjectIsFunction(cx, objToWrap) &&
::JS_GetFunctionNative(cx, ::JS_ValueToFunction(cx, argv[0])) ==
::JS_GetFunctionFastNative(cx, ::JS_ValueToFunction(cx, argv[0])) ==
XPCWrapper::sEvalNative)) {
return ThrowException(NS_ERROR_INVALID_ARG, cx);
}

View File

@ -48,7 +48,7 @@ namespace XPCWrapper {
const PRUint32 sWrappedObjSlot = 1;
const PRUint32 sFlagsSlot = 0;
const PRUint32 sNumSlots = 2;
JSNative sEvalNative = nsnull;
JSFastNative sEvalNative = nsnull;
const PRUint32 FLAG_RESOLVING = 0x1;
const PRUint32 LAST_FLAG = FLAG_RESOLVING;

View File

@ -204,7 +204,7 @@ extern const PRUint32 sNumSlots;
* Cross origin wrappers and safe JSObject wrappers both need to know
* which native is 'eval' for various purposes.
*/
extern JSNative sEvalNative;
extern JSFastNative sEvalNative;
enum FunctionObjectSlot {
eWrappedFunctionSlot = 0,
@ -245,7 +245,7 @@ FindEval(XPCCallContext &ccx, JSObject *obj)
}
sEvalNative =
::JS_GetFunctionNative(ccx, ::JS_ValueToFunction(ccx, eval_val));
::JS_GetFunctionFastNative(ccx, ::JS_ValueToFunction(ccx, eval_val));
if (!sEvalNative) {
return DoThrowException(NS_ERROR_UNEXPECTED, ccx);