Bug 607724: Minor scope chain function cleanup. (r=mrbkap)

This commit is contained in:
Chris Leary 2010-10-27 16:18:16 -07:00
Родитель 1ec7c780d5
Коммит 0083db09f1
10 изменённых файлов: 99 добавлений и 88 удалений

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

@ -1881,31 +1881,8 @@ JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
JS_PUBLIC_API(JSObject *)
JS_GetScopeChain(JSContext *cx)
{
JSStackFrame *fp;
CHECK_REQUEST(cx);
fp = js_GetTopStackFrame(cx);
if (!fp) {
/*
* There is no code active on this context. In place of an actual
* scope chain, use the context's global object, which is set in
* js_InitFunctionAndObjectClasses, and which represents the default
* scope chain for the embedding. See also js_FindClassObject.
*
* For embeddings that use the inner and outer object hooks, the inner
* object represents the ultimate global object, with the outer object
* acting as a stand-in.
*/
JSObject *obj = cx->globalObject;
if (!obj) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
return NULL;
}
OBJ_TO_INNER_OBJECT(cx, obj);
return obj;
}
return js_GetScopeChain(cx, fp);
return GetScopeChain(cx);
}
JS_PUBLIC_API(JSObject *)
@ -1918,26 +1895,8 @@ JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
JS_PUBLIC_API(JSObject *)
JS_GetGlobalForScopeChain(JSContext *cx)
{
/*
* This is essentially JS_GetScopeChain(cx)->getGlobal(), but without
* falling off trace.
*
* This use of cx->fp, possibly on trace, is deliberate:
* cx->fp->scopeChain->getGlobal() returns the same object whether we're on
* trace or not, since we do not trace calls across global objects.
*/
VOUCH_DOES_NOT_REQUIRE_STACK();
if (cx->hasfp())
return cx->fp()->scopeChain().getGlobal();
JSObject *scope = cx->globalObject;
if (!scope) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
return NULL;
}
OBJ_TO_INNER_OBJECT(cx, scope);
return scope;
CHECK_REQUEST(cx);
return GetGlobalForScopeChain(cx);
}
JS_PUBLIC_API(jsval)
@ -4172,7 +4131,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
assertSameCompartment(cx, parent); // XXX no funobj for now
if (!parent) {
if (cx->hasfp())
parent = js_GetScopeChain(cx, cx->fp());
parent = GetScopeChain(cx, cx->fp());
if (!parent)
parent = cx->globalObject;
JS_ASSERT(parent);

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

@ -48,12 +48,33 @@
#include "jsregexp.h"
#include "jsgc.h"
inline js::RegExpStatics *
JSContext::regExpStatics()
namespace js {
static inline JSObject *
GetGlobalForScopeChain(JSContext *cx)
{
JSObject *global = JS_GetGlobalForScopeChain(this);
js::RegExpStatics *res = js::RegExpStatics::extractFrom(global);
return res;
/*
* This is essentially GetScopeChain(cx)->getGlobal(), but without
* falling off trace.
*
* This use of cx->fp, possibly on trace, is deliberate:
* cx->fp->scopeChain->getGlobal() returns the same object whether we're on
* trace or not, since we do not trace calls across global objects.
*/
VOUCH_DOES_NOT_REQUIRE_STACK();
if (cx->hasfp())
return cx->fp()->scopeChain().getGlobal();
JSObject *scope = cx->globalObject;
if (!scope) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
return NULL;
}
OBJ_TO_INNER_OBJECT(cx, scope);
return scope;
}
}
inline bool
@ -80,6 +101,12 @@ JSContext::computeNextFrame(JSStackFrame *fp)
}
}
inline js::RegExpStatics *
JSContext::regExpStatics()
{
return js::RegExpStatics::extractFrom(js::GetGlobalForScopeChain(this));
}
namespace js {
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSFrameRegs *

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

@ -1187,7 +1187,7 @@ JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp)
/* Force creation of argument and call objects if not yet created */
(void) JS_GetFrameCallObject(cx, fp);
return js_GetScopeChain(cx, fp);
return GetScopeChain(cx, fp);
}
JS_PUBLIC_API(JSObject *)

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

@ -358,7 +358,7 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun)
* _DBG* opcodes used by wrappers created here must cope with unresolved
* upvars and throw them as reference errors. Caveat debuggers!
*/
JSObject *scopeChain = js_GetScopeChain(cx, fp);
JSObject *scopeChain = GetScopeChain(cx, fp);
if (!scopeChain)
return NULL;
@ -2928,7 +2928,7 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen)
* Flat closures can be partial, they may need to search enclosing scope
* objects via JSOP_NAME, etc.
*/
JSObject *scopeChain = js_GetScopeChainFast(cx, cx->fp(), op, oplen);
JSObject *scopeChain = GetScopeChainFast(cx, cx->fp(), op, oplen);
if (!scopeChain)
return NULL;

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

@ -162,6 +162,33 @@ JSStackFrame::pc(JSContext *cx, JSStackFrame *next)
#endif
}
JSObject *
js::GetScopeChain(JSContext *cx)
{
JSStackFrame *fp = js_GetTopStackFrame(cx);
if (!fp) {
/*
* There is no code active on this context. In place of an actual
* scope chain, use the context's global object, which is set in
* js_InitFunctionAndObjectClasses, and which represents the default
* scope chain for the embedding. See also js_FindClassObject.
*
* For embeddings that use the inner and outer object hooks, the inner
* object represents the ultimate global object, with the outer object
* acting as a stand-in.
*/
JSObject *obj = cx->globalObject;
if (!obj) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
return NULL;
}
OBJ_TO_INNER_OBJECT(cx, obj);
return obj;
}
return GetScopeChain(cx, fp);
}
/*
* This computes the blockChain by iterating through the bytecode
* of the current script until it reaches the PC. Each time it sees
@ -170,7 +197,7 @@ JSStackFrame::pc(JSContext *cx, JSStackFrame *next)
* require bytecode scanning appears below.
*/
JSObject *
js_GetBlockChain(JSContext *cx, JSStackFrame *fp)
js::GetBlockChain(JSContext *cx, JSStackFrame *fp)
{
if (!fp->isScriptFrame())
return NULL;
@ -218,7 +245,7 @@ js_GetBlockChain(JSContext *cx, JSStackFrame *fp)
* |oplen| is the length of opcode at the current PC.
*/
JSObject *
js_GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen)
js::GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen)
{
/* Assume that we're in a script frame. */
jsbytecode *pc = fp->pc(cx);
@ -274,11 +301,11 @@ js_GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen)
* closure's scope chain. If we never close over a lexical block, we never
* place a mutable clone of it on scopeChain.
*
* This lazy cloning is implemented in js_GetScopeChain, which is also used in
* This lazy cloning is implemented in GetScopeChain, which is also used in
* some other cases --- entering 'with' blocks, for example.
*/
static JSObject *
js_GetScopeChainFull(JSContext *cx, JSStackFrame *fp, JSObject *blockChain)
GetScopeChainFull(JSContext *cx, JSStackFrame *fp, JSObject *blockChain)
{
JSObject *sharedBlock = blockChain;
@ -399,15 +426,15 @@ js_GetScopeChainFull(JSContext *cx, JSStackFrame *fp, JSObject *blockChain)
}
JSObject *
js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
js::GetScopeChain(JSContext *cx, JSStackFrame *fp)
{
return js_GetScopeChainFull(cx, fp, js_GetBlockChain(cx, fp));
return GetScopeChainFull(cx, fp, GetBlockChain(cx, fp));
}
JSObject *
js_GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen)
js::GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen)
{
return js_GetScopeChainFull(cx, fp, js_GetBlockChainFast(cx, fp, op, oplen));
return GetScopeChainFull(cx, fp, GetBlockChainFast(cx, fp, op, oplen));
}
/* Some objects (e.g., With) delegate 'this' to another object. */
@ -716,7 +743,7 @@ Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags)
*
* Compute |this|. Currently, this must happen after the frame is pushed
* and fp->scopeChain is correct because the thisObject hook may call
* JS_GetScopeChain.
* GetScopeChain.
*/
if (!(flags & JSINVOKE_CONSTRUCT)) {
Value &thisv = fp->functionThis();
@ -1348,7 +1375,7 @@ js_EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen)
sp[-1].setObject(*obj);
}
JSObject *parent = js_GetScopeChainFast(cx, fp, op, oplen);
JSObject *parent = GetScopeChainFast(cx, fp, op, oplen);
if (!parent)
return JS_FALSE;
@ -2716,7 +2743,7 @@ BEGIN_CASE(JSOP_POPN)
regs.sp -= GET_UINT16(regs.pc);
#ifdef DEBUG
JS_ASSERT(regs.fp->base() <= regs.sp);
JSObject *obj = js_GetBlockChain(cx, regs.fp);
JSObject *obj = GetBlockChain(cx, regs.fp);
JS_ASSERT_IF(obj,
OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj)
<= (size_t) (regs.sp - regs.fp->base()));
@ -4908,7 +4935,7 @@ BEGIN_CASE(JSOP_REGEXP)
* bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
* flouted by many browser-based implementations.
*
* We avoid the js_GetScopeChain call here and pass fp->scopeChain as
* We avoid the GetScopeChain call here and pass fp->scopeChain as
* js_GetClassPrototype uses the latter only to locate the global.
*/
jsatomid index = GET_FULL_INDEX(0);
@ -5368,7 +5395,7 @@ BEGIN_CASE(JSOP_DEFFUN)
} else {
JS_ASSERT(!FUN_FLAT_CLOSURE(fun));
obj2 = js_GetScopeChainFast(cx, regs.fp, JSOP_DEFFUN, JSOP_DEFFUN_LENGTH);
obj2 = GetScopeChainFast(cx, regs.fp, JSOP_DEFFUN, JSOP_DEFFUN_LENGTH);
if (!obj2)
goto error;
}
@ -5515,8 +5542,8 @@ BEGIN_CASE(JSOP_DEFLOCALFUN)
if (!obj)
goto error;
} else {
JSObject *parent = js_GetScopeChainFast(cx, regs.fp, JSOP_DEFLOCALFUN,
JSOP_DEFLOCALFUN_LENGTH);
JSObject *parent = GetScopeChainFast(cx, regs.fp, JSOP_DEFLOCALFUN,
JSOP_DEFLOCALFUN_LENGTH);
if (!parent)
goto error;
@ -5679,7 +5706,7 @@ BEGIN_CASE(JSOP_LAMBDA)
}
#endif
} else {
parent = js_GetScopeChainFast(cx, regs.fp, JSOP_LAMBDA, JSOP_LAMBDA_LENGTH);
parent = GetScopeChainFast(cx, regs.fp, JSOP_LAMBDA, JSOP_LAMBDA_LENGTH);
if (!parent)
goto error;
}

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

@ -783,14 +783,14 @@ namespace js {
static const size_t VALUES_PER_STACK_FRAME = sizeof(JSStackFrame) / sizeof(Value);
} /* namespace js */
extern JSObject *
GetBlockChain(JSContext *cx, JSStackFrame *fp);
extern JSObject *
js_GetBlockChain(JSContext *cx, JSStackFrame *fp);
GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen);
extern JSObject *
js_GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen);
GetScopeChain(JSContext *cx);
/*
* Refresh and return fp->scopeChain. It may be stale if block scopes are
@ -800,12 +800,10 @@ js_GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen);
* must reflect at runtime.
*/
extern JSObject *
js_GetScopeChain(JSContext *cx, JSStackFrame *fp);
GetScopeChain(JSContext *cx, JSStackFrame *fp);
extern JSObject *
js_GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen);
namespace js {
GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen);
/*
* Report an error that the this value passed as |this| in the given arguments

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

@ -1155,8 +1155,8 @@ eval(JSContext *cx, uintN argc, Value *vp)
if (directCall) {
/* Compile using the caller's current scope object. */
staticLevel = caller->script()->staticLevel + 1;
scopeobj = js_GetScopeChainFast(cx, caller, JSOP_EVAL,
JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH);
scopeobj = GetScopeChainFast(cx, caller, JSOP_EVAL,
JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH);
if (!scopeobj)
return false;

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

@ -15468,7 +15468,7 @@ TraceRecorder::record_JSOP_LAMBDA()
return ARECORD_CONTINUE;
}
if (js_GetBlockChainFast(cx, cx->fp(), JSOP_LAMBDA, JSOP_LAMBDA_LENGTH))
if (GetBlockChainFast(cx, cx->fp(), JSOP_LAMBDA, JSOP_LAMBDA_LENGTH))
RETURN_STOP_A("Unable to trace creating lambda in let");
LIns *proto_ins;
@ -15494,7 +15494,7 @@ TraceRecorder::record_JSOP_LAMBDA_FC()
if (FUN_OBJECT(fun)->getParent() != globalObj)
return ARECORD_STOP;
if (js_GetBlockChainFast(cx, cx->fp(), JSOP_LAMBDA_FC, JSOP_LAMBDA_FC_LENGTH))
if (GetBlockChainFast(cx, cx->fp(), JSOP_LAMBDA_FC, JSOP_LAMBDA_FC_LENGTH))
RETURN_STOP_A("Unable to trace creating lambda in let");
LIns* args[] = {

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

@ -1763,7 +1763,7 @@ ParseXMLSource(JSContext *cx, JSString *src)
{
Parser parser(cx);
if (parser.init(chars, length, NULL, filename, lineno)) {
JSObject *scopeChain = JS_GetScopeChain(cx);
JSObject *scopeChain = GetScopeChain(cx);
if (!scopeChain)
return NULL;
JSParseNode *pn = parser.parseXMLText(scopeChain, false);
@ -7210,7 +7210,7 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp)
JSObject *ns, *obj, *tmp;
jsval v;
JSObject *scopeChain = JS_GetScopeChain(cx);
JSObject *scopeChain = GetScopeChain(cx);
obj = NULL;
for (tmp = scopeChain; tmp; tmp = tmp->getParent()) {

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

@ -817,7 +817,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
} else {
JS_ASSERT(!FUN_FLAT_CLOSURE(fun));
obj2 = js_GetScopeChainFast(cx, fp, JSOP_DEFFUN, JSOP_DEFFUN_LENGTH);
obj2 = GetScopeChainFast(cx, fp, JSOP_DEFFUN, JSOP_DEFFUN_LENGTH);
if (!obj2)
THROW();
}
@ -1467,8 +1467,8 @@ stubs::DefLocalFun(VMFrame &f, JSFunction *fun)
if (!obj)
THROWV(NULL);
} else {
JSObject *parent = js_GetScopeChainFast(f.cx, f.fp(), JSOP_DEFLOCALFUN,
JSOP_DEFLOCALFUN_LENGTH);
JSObject *parent = GetScopeChainFast(f.cx, f.fp(), JSOP_DEFLOCALFUN,
JSOP_DEFLOCALFUN_LENGTH);
if (!parent)
THROWV(NULL);
@ -1499,7 +1499,7 @@ stubs::RegExp(VMFrame &f, JSObject *regex)
* bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
* flouted by many browser-based implementations.
*
* We avoid the js_GetScopeChain call here and pass fp->scopeChain() as
* We avoid the GetScopeChain call here and pass fp->scopeChain() as
* js_GetClassPrototype uses the latter only to locate the global.
*/
JSObject *proto;
@ -1597,7 +1597,7 @@ stubs::Lambda(VMFrame &f, JSFunction *fun)
if (FUN_NULL_CLOSURE(fun)) {
parent = &f.fp()->scopeChain();
} else {
parent = js_GetScopeChainFast(f.cx, f.fp(), JSOP_LAMBDA, JSOP_LAMBDA_LENGTH);
parent = GetScopeChainFast(f.cx, f.fp(), JSOP_LAMBDA, JSOP_LAMBDA_LENGTH);
if (!parent)
THROWV(NULL);
}