Bug 832373 part 1 - Refactor eval-in-frame to use AbstractFramePtr. r=luke

This commit is contained in:
Jan de Mooij 2013-01-21 13:58:50 +01:00
parent f929fe87f0
commit 6f41fe1cad
16 changed files with 390 additions and 273 deletions

View File

@ -156,10 +156,10 @@ enum EvalType { DIRECT_EVAL = EXECUTE_DIRECT_EVAL, INDIRECT_EVAL = EXECUTE_INDIR
//
// On success, store the completion value in call.rval and return true.
static bool
EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *caller,
EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFramePtr caller,
HandleObject scopeobj)
{
JS_ASSERT((evalType == INDIRECT_EVAL) == (caller == NULL));
JS_ASSERT((evalType == INDIRECT_EVAL) == !caller);
JS_ASSERT_IF(evalType == INDIRECT_EVAL, scopeobj->isGlobal());
AssertInnerizedScopeChain(cx, *scopeobj);
@ -187,15 +187,15 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *c
unsigned staticLevel;
RootedValue thisv(cx);
if (evalType == DIRECT_EVAL) {
JS_ASSERT(!caller->runningInIon());
staticLevel = caller->script()->staticLevel + 1;
JS_ASSERT_IF(caller.isStackFrame(), !caller.asStackFrame()->runningInIon());
staticLevel = caller.script()->staticLevel + 1;
// Direct calls to eval are supposed to see the caller's |this|. If we
// haven't wrapped that yet, do so now, before we make a copy of it for
// the eval code to use.
if (!ComputeThis(cx, caller))
return false;
thisv = caller->thisValue();
thisv = caller.thisValue();
} else {
JS_ASSERT(args.callee().global() == *scopeobj);
staticLevel = 0;
@ -226,7 +226,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *c
if (length > 2 &&
((chars[0] == '[' && chars[length - 1] == ']') ||
(chars[0] == '(' && chars[length - 1] == ')')) &&
(!caller || !caller->script()->strict))
(!caller || !caller.script()->strict))
{
// Remarkably, JavaScript syntax is not a superset of JSON syntax:
// strings in JavaScript cannot contain the Unicode line and paragraph
@ -257,8 +257,8 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *c
JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
if (evalType == DIRECT_EVAL && caller->isNonEvalFunctionFrame())
esg.lookupInEvalCache(stableStr, caller->fun(), staticLevel);
if (evalType == DIRECT_EVAL && caller.isNonEvalFunctionFrame())
esg.lookupInEvalCache(stableStr, caller.fun(), staticLevel);
if (!esg.foundScript()) {
unsigned lineno;
@ -283,7 +283,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *c
}
return ExecuteKernel(cx, esg.script(), *scopeobj, thisv, ExecuteType(evalType),
NULL /* evalInFrame */, args.rval().address());
NullFramePtr() /* evalInFrame */, args.rval().address());
}
// We once supported a second argument to eval to use as the scope chain
@ -318,7 +318,7 @@ js::IndirectEval(JSContext *cx, unsigned argc, Value *vp)
return false;
Rooted<GlobalObject*> global(cx, &args.callee().global());
return EvalKernel(cx, args, INDIRECT_EVAL, NULL, global);
return EvalKernel(cx, args, INDIRECT_EVAL, NullFramePtr(), global);
}
bool

View File

@ -47,7 +47,7 @@ SetSourceMap(JSContext *cx, TokenStream &tokenStream, ScriptSource *ss, Unrooted
}
UnrootedScript
frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *callerFrame,
frontend::CompileScript(JSContext *cx, HandleObject scopeChain, AbstractFramePtr callerFrame,
const CompileOptions &options,
StableCharPtr chars, size_t length,
JSString *source_ /* = NULL */,
@ -106,7 +106,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call
if (!pc.init())
return UnrootedScript(NULL);
bool savedCallerFun = options.compileAndGo && callerFrame && callerFrame->isFunctionFrame();
bool savedCallerFun = options.compileAndGo && callerFrame && callerFrame.isFunctionFrame();
Rooted<JSScript*> script(cx, JSScript::Create(cx, NullPtr(), savedCallerFun,
options, staticLevel, ss, 0, length));
if (!script)
@ -129,7 +129,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call
return UnrootedScript(NULL);
/* If this is a direct call to eval, inherit the caller's strictness. */
if (callerFrame && callerFrame->script()->strict)
if (callerFrame && callerFrame.script()->strict)
globalsc.strict = true;
if (options.compileAndGo) {
@ -144,13 +144,13 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call
return UnrootedScript(NULL);
}
if (callerFrame && callerFrame->isFunctionFrame()) {
if (callerFrame && callerFrame.isFunctionFrame()) {
/*
* An eval script in a caller frame needs to have its enclosing
* function captured in case it refers to an upvar, and someone
* wishes to decompile it while it's running.
*/
JSFunction *fun = callerFrame->fun();
JSFunction *fun = callerFrame.fun();
ObjectBox *funbox = parser.newFunctionBox(fun, &pc, fun->strict());
if (!funbox)
return UnrootedScript(NULL);
@ -217,7 +217,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call
#endif
// It's an error to use |arguments| in a function that has a rest parameter.
if (callerFrame && callerFrame->isFunctionFrame() && callerFrame->fun()->hasRest()) {
if (callerFrame && callerFrame.isFunctionFrame() && callerFrame.fun()->hasRest()) {
HandlePropertyName arguments = cx->names().arguments;
for (AtomDefnRange r = pc.lexdeps->all(); !r.empty(); r.popFront()) {
if (r.front().key() == arguments) {
@ -318,7 +318,8 @@ frontend::CompileFunctionBody(JSContext *cx, HandleFunction fun, CompileOptions
return false;
}
BytecodeEmitter funbce(/* parent = */ NULL, &parser, funbox, script, /* callerFrame = */ NULL,
BytecodeEmitter funbce(/* parent = */ NULL, &parser, funbox, script,
/* callerFrame = */ NullFramePtr(),
/* hasGlobalScope = */ false, options.lineno);
if (!funbce.init())
return false;

View File

@ -14,7 +14,7 @@ namespace js {
namespace frontend {
UnrootedScript
CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *callerFrame,
CompileScript(JSContext *cx, HandleObject scopeChain, AbstractFramePtr callerFrame,
const CompileOptions &options, StableCharPtr chars, size_t length,
JSString *source_ = NULL, unsigned staticLevel = 0);

View File

@ -100,7 +100,7 @@ struct frontend::StmtInfoBCE : public StmtInfoBase
};
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent, Parser *parser, SharedContext *sc,
HandleScript script, StackFrame *callerFrame, bool hasGlobalScope,
HandleScript script, AbstractFramePtr callerFrame, bool hasGlobalScope,
unsigned lineno, bool selfHostingMode)
: sc(sc),
parent(parent),
@ -1281,8 +1281,7 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
}
if (dn->pn_cookie.isFree()) {
StackFrame *caller = bce->callerFrame;
if (caller) {
if (AbstractFramePtr caller = bce->callerFrame) {
JS_ASSERT(bce->script->compileAndGo);
/*
@ -1296,7 +1295,7 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* If this is an eval in the global scope, then unbound variables
* must be globals, so try to use GNAME ops.
*/
if (caller->isGlobalFrame() && TryConvertToGname(bce, pn, &op)) {
if (caller.isGlobalFrame() && TryConvertToGname(bce, pn, &op)) {
pn->setOp(op);
pn->pn_dflags |= PND_BOUND;
return true;

View File

@ -83,7 +83,7 @@ struct BytecodeEmitter
Parser *const parser; /* the parser */
StackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */
AbstractFramePtr callerFrame; /* scripted caller frame for eval and dbgapi */
StmtInfoBCE *topStmt; /* top of statement info stack */
StmtInfoBCE *topScopeStmt; /* top lexical scope statement */
@ -126,7 +126,7 @@ struct BytecodeEmitter
the field |selfHostingMode| in Parser.h for details. */
BytecodeEmitter(BytecodeEmitter *parent, Parser *parser, SharedContext *sc,
HandleScript script, StackFrame *callerFrame, bool hasGlobalScope,
HandleScript script, AbstractFramePtr callerFrame, bool hasGlobalScope,
unsigned lineno, bool selfHostingMode = false);
bool init();

View File

@ -5286,7 +5286,7 @@ JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options,
JS_ASSERT_IF(options.principals, cx->compartment->principals == options.principals);
AutoLastFrameCheck lfc(cx);
return frontend::CompileScript(cx, obj, NULL, options, StableCharPtr(chars, length), length);
return frontend::CompileScript(cx, obj, NullFramePtr(), options, StableCharPtr(chars, length), length);
}
JSScript *
@ -5639,7 +5639,7 @@ JS::Evaluate(JSContext *cx, HandleObject obj, CompileOptions options,
options.setCompileAndGo(true);
options.setNoScriptRval(!rval);
RootedScript script(cx, frontend::CompileScript(cx, obj, NULL, options,
RootedScript script(cx, frontend::CompileScript(cx, obj, NullFramePtr(), options,
StableCharPtr(chars, length), length));
if (!script)
return false;

View File

@ -514,7 +514,7 @@ js::InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, unsign
bool
js::ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChain, const Value &thisv,
ExecuteType type, StackFrame *evalInFrame, Value *result)
ExecuteType type, AbstractFramePtr evalInFrame, Value *result)
{
JS_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG);
JS_ASSERT_IF(type == EXECUTE_GLOBAL, !scopeChain.isScope());
@ -574,7 +574,7 @@ js::Execute(JSContext *cx, HandleScript script, JSObject &scopeChainArg, Value *
Value thisv = ObjectValue(*thisObj);
return ExecuteKernel(cx, script, *scopeChain, thisv, EXECUTE_GLOBAL,
NULL /* evalInFrame */, rval);
NullFramePtr() /* evalInFrame */, rval);
}
bool

View File

@ -77,7 +77,7 @@ BoxNonStrictThis(JSContext *cx, MutableHandleValue thisv, bool *modified);
* an optimization to avoid global-this computation).
*/
inline bool
ComputeThis(JSContext *cx, StackFrame *fp);
ComputeThis(JSContext *cx, AbstractFramePtr frame);
enum MaybeConstruct {
NO_CONSTRUCT = INITIAL_NONE,
@ -160,7 +160,7 @@ InvokeConstructor(JSContext *cx, const Value &fval, unsigned argc, Value *argv,
*/
extern bool
ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChain, const Value &thisv,
ExecuteType type, StackFrame *evalInFrame, Value *result);
ExecuteType type, AbstractFramePtr evalInFrame, Value *result);
/* Execute a script with the given scopeChain as global code. */
extern bool

View File

@ -82,14 +82,14 @@ ComputeImplicitThis(JSContext *cx, HandleObject obj, Value *vp)
}
inline bool
ComputeThis(JSContext *cx, StackFrame *fp)
ComputeThis(JSContext *cx, AbstractFramePtr frame)
{
JS_ASSERT(!fp->runningInIon());
Value &thisv = fp->thisValue();
if (thisv.isObject())
JS_ASSERT_IF(frame.isStackFrame(), !frame.asStackFrame()->runningInIon());
if (frame.thisValue().isObject())
return true;
if (fp->isFunctionFrame()) {
if (fp->fun()->strict() || fp->fun()->isSelfHostedBuiltin())
RootedValue thisv(cx, frame.thisValue());
if (frame.isFunctionFrame()) {
if (frame.fun()->strict() || frame.fun()->isSelfHostedBuiltin())
return true;
/*
* Eval function frames have their own |this| slot, which is a copy of the function's
@ -98,9 +98,14 @@ ComputeThis(JSContext *cx, StackFrame *fp)
* this, we always wrap a function's |this| before pushing an eval frame, and should
* thus never see an unwrapped primitive in a non-strict eval function frame.
*/
JS_ASSERT(!fp->isEvalFrame());
JS_ASSERT(!frame.isEvalFrame());
}
return BoxNonStrictThis(cx, fp->callReceiver());
bool modified;
if (!BoxNonStrictThis(cx, &thisv, &modified))
return false;
frame.thisValue() = thisv;
return true;
}
/*

View File

@ -3683,18 +3683,18 @@ DebuggerFrame_setOnPop(JSContext *cx, unsigned argc, Value *vp)
* source as appearing starting at |lineno| in |filename|. Store the return
* value in |*rval|. Use |thisv| as the 'this' value.
*
* If |fp| is non-NULL, evaluate as for a direct eval in that frame; |env|
* must be either |fp|'s DebugScopeObject, or some extension of that
* environment; either way, |fp|'s scope is where newly declared variables
* go. In this case, |fp| must have a computed 'this' value, equal to |thisv|.
* If |frame| is non-NULL, evaluate as for a direct eval in that frame; |env|
* must be either |frame|'s DebugScopeObject, or some extension of that
* environment; either way, |frame|'s scope is where newly declared variables
* go. In this case, |frame| must have a computed 'this' value, equal to |thisv|.
*/
JSBool
js::EvaluateInEnv(JSContext *cx, Handle<Env*> env, HandleValue thisv, StackFrame *fp,
js::EvaluateInEnv(JSContext *cx, Handle<Env*> env, HandleValue thisv, AbstractFramePtr frame,
StableCharPtr chars, unsigned length, const char *filename, unsigned lineno,
Value *rval)
{
assertSameCompartment(cx, env, fp);
JS_ASSERT_IF(fp, thisv.get() == fp->thisValue());
assertSameCompartment(cx, env, frame);
JS_ASSERT_IF(frame, thisv.get() == frame.thisValue());
JS_ASSERT(!IsPoisonedPtr(chars.get()));
@ -3708,15 +3708,15 @@ js::EvaluateInEnv(JSContext *cx, Handle<Env*> env, HandleValue thisv, StackFrame
.setCompileAndGo(true)
.setNoScriptRval(false)
.setFileAndLine(filename, lineno);
RootedScript script(cx, frontend::CompileScript(cx, env, fp, options, chars, length,
RootedScript script(cx, frontend::CompileScript(cx, env, frame, options, chars, length,
/* source = */ NULL,
/* staticLevel = */ fp ? 1 : 0));
/* staticLevel = */ frame ? 1 : 0));
if (!script)
return false;
script->isActiveEval = true;
ExecuteType type = !fp && env->isGlobal() ? EXECUTE_DEBUG_GLOBAL : EXECUTE_DEBUG;
return ExecuteKernel(cx, script, *env, thisv, type, fp, rval);
ExecuteType type = !frame && env->isGlobal() ? EXECUTE_DEBUG_GLOBAL : EXECUTE_DEBUG;
return ExecuteKernel(cx, script, *env, thisv, type, frame, rval);
}
static JSBool
@ -3806,8 +3806,8 @@ DebuggerGenericEval(JSContext *cx, const char *fullMethodName,
/* Run the code and produce the completion value. */
Value rval;
JS::Anchor<JSString *> anchor(stable);
StackFrame *fp = iter ? iter->interpFrame() : NULL;
bool ok = EvaluateInEnv(cx, env, thisv, fp, stable->chars(), stable->length(),
AbstractFramePtr frame = iter ? iter->abstractFramePtr() : NullFramePtr();
bool ok = EvaluateInEnv(cx, env, thisv, frame, stable->chars(), stable->length(),
"debugger eval code", 1, &rval);
return dbg->receiveCompletionValue(ac, ok, rval, vp);
}

View File

@ -691,7 +691,7 @@ Debugger::onNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global)
}
extern JSBool
EvaluateInEnv(JSContext *cx, Handle<Env*> env, HandleValue thisv, StackFrame *fp,
EvaluateInEnv(JSContext *cx, Handle<Env*> env, HandleValue thisv, AbstractFramePtr frame,
StableCharPtr chars, unsigned length, const char *filename, unsigned lineno,
Value *rval);

View File

@ -881,7 +881,7 @@ js::CloneStaticBlockObject(JSContext *cx, HandleObject enclosingScope, Handle<St
ScopeIter::ScopeIter(JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: frame_(),
: frame_(NullFramePtr()),
cur_(cx, reinterpret_cast<JSObject *>(-1)),
block_(cx, reinterpret_cast<StaticBlockObject *>(-1)),
type_(Type(-1))
@ -902,7 +902,7 @@ ScopeIter::ScopeIter(const ScopeIter &si, JSContext *cx
ScopeIter::ScopeIter(JSObject &enclosingScope, JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: frame_(),
: frame_(NullFramePtr()),
cur_(cx, &enclosingScope),
block_(cx, reinterpret_cast<StaticBlockObject *>(-1)),
type_(Type(-1))
@ -986,7 +986,7 @@ ScopeIter::operator++()
if (CallObjectLambdaName(*frame_.fun()))
cur_ = &cur_->asDeclEnv().enclosingScope();
}
frame_ = AbstractFramePtr();
frame_ = NullFramePtr();
break;
case Block:
block_ = block_->enclosingBlock();
@ -1002,7 +1002,7 @@ ScopeIter::operator++()
case StrictEvalScope:
if (hasScopeObject_)
cur_ = &cur_->asCall().enclosingScope();
frame_ = AbstractFramePtr();
frame_ = NullFramePtr();
break;
}
return *this;
@ -1049,14 +1049,14 @@ ScopeIter::settle()
type_ = Block;
hasScopeObject_ = false;
} else {
frame_ = AbstractFramePtr();
frame_ = NullFramePtr();
}
} else if (frame_.isNonEvalFunctionFrame() && !frame_.hasCallObj()) {
JS_ASSERT(cur_ == frame_.fun()->environment());
frame_ = AbstractFramePtr();
frame_ = NullFramePtr();
} else if (frame_.isStrictEvalFrame() && !frame_.hasCallObj()) {
JS_ASSERT(cur_ == frame_.evalPrev().scopeChain());
frame_ = AbstractFramePtr();
frame_ = NullFramePtr();
} else if (cur_->isWith()) {
JS_ASSERT_IF(frame_.isFunctionFrame(), frame_.fun()->isHeavyweight());
JS_ASSERT_IF(block_, block_->needsClone());
@ -1075,7 +1075,7 @@ ScopeIter::settle()
} else {
JS_ASSERT(!cur_->isScope());
JS_ASSERT(frame_.isGlobalFrame() || frame_.isDebuggerFrame());
frame_ = AbstractFramePtr();
frame_ = NullFramePtr();
}
}
@ -1959,7 +1959,7 @@ DebugScopes::hasLiveFrame(ScopeObject &scope)
{
DebugScopes *scopes = scope.compartment()->debugScopes;
if (!scopes)
return AbstractFramePtr();
return NullFramePtr();
if (LiveScopeMap::Ptr p = scopes->liveScopes.lookup(&scope)) {
AbstractFramePtr frame = p->value;
@ -1980,7 +1980,7 @@ DebugScopes::hasLiveFrame(ScopeObject &scope)
return frame;
}
return AbstractFramePtr();
return NullFramePtr();
}
/*****************************************************************************/

View File

@ -472,7 +472,7 @@ class ScopeIterKey
ScopeIter::Type type_;
public:
ScopeIterKey() : frame_(), cur_(NULL), block_(NULL), type_() {}
ScopeIterKey() : frame_(NullFramePtr()), cur_(NULL), block_(NULL), type_() {}
ScopeIterKey(const ScopeIter &si)
: frame_(si.frame_), cur_(si.cur_), block_(si.block_), type_(si.type_)
{}

View File

@ -706,5 +706,214 @@ AbstractFramePtr::unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing)
return asStackFrame()->unaliasedFormal(i);
}
inline JSGenerator *
AbstractFramePtr::maybeSuspendedGenerator(JSRuntime *rt) const
{
if (isStackFrame())
return asStackFrame()->maybeSuspendedGenerator(rt);
return NULL;
}
inline StaticBlockObject *
AbstractFramePtr::maybeBlockChain() const
{
if (isStackFrame())
return asStackFrame()->maybeBlockChain();
return NULL;
}
inline bool
AbstractFramePtr::hasCallObj() const
{
if (isStackFrame())
return asStackFrame()->hasCallObj();
JS_NOT_REACHED("Invalid frame");
return false;
}
inline bool
AbstractFramePtr::isGeneratorFrame() const
{
if (isStackFrame())
return asStackFrame()->isGeneratorFrame();
return false;
}
inline bool
AbstractFramePtr::isYielding() const
{
if (isStackFrame())
return asStackFrame()->isYielding();
return false;
}
inline bool
AbstractFramePtr::isFunctionFrame() const
{
if (isStackFrame())
return asStackFrame()->isFunctionFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
inline bool
AbstractFramePtr::isGlobalFrame() const
{
if (isStackFrame())
return asStackFrame()->isGlobalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
inline bool
AbstractFramePtr::isEvalFrame() const
{
if (isStackFrame())
return asStackFrame()->isEvalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
inline bool
AbstractFramePtr::isFramePushedByExecute() const
{
return isGlobalFrame() || isEvalFrame();
}
inline bool
AbstractFramePtr::isDebuggerFrame() const
{
if (isStackFrame())
return asStackFrame()->isDebuggerFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
inline UnrootedScript
AbstractFramePtr::script() const
{
if (isStackFrame())
return asStackFrame()->script();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
inline JSFunction *
AbstractFramePtr::fun() const
{
if (isStackFrame())
return asStackFrame()->fun();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
inline JSFunction &
AbstractFramePtr::callee() const
{
if (isStackFrame())
return asStackFrame()->callee();
JS_NOT_REACHED("Invalid frame");
return asStackFrame()->callee();
}
inline bool
AbstractFramePtr::isNonEvalFunctionFrame() const
{
if (isStackFrame())
return asStackFrame()->isNonEvalFunctionFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
inline bool
AbstractFramePtr::isNonStrictDirectEvalFrame() const
{
if (isStackFrame())
return asStackFrame()->isNonStrictDirectEvalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
inline bool
AbstractFramePtr::isStrictEvalFrame() const
{
if (isStackFrame())
return asStackFrame()->isStrictEvalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
inline Value *
AbstractFramePtr::formals() const
{
if (isStackFrame())
return asStackFrame()->formals();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
inline Value *
AbstractFramePtr::actuals() const
{
if (isStackFrame())
return asStackFrame()->actuals();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
inline bool
AbstractFramePtr::hasArgsObj() const
{
if (isStackFrame())
return asStackFrame()->hasArgsObj();
JS_NOT_REACHED("Invalid frame");
return false;
}
inline ArgumentsObject &
AbstractFramePtr::argsObj() const
{
if (isStackFrame())
return asStackFrame()->argsObj();
JS_NOT_REACHED("Invalid frame");
return asStackFrame()->argsObj();
}
inline void
AbstractFramePtr::initArgsObj(ArgumentsObject &argsobj) const
{
if (isStackFrame()) {
asStackFrame()->initArgsObj(argsobj);
return;
}
JS_NOT_REACHED("Invalid frame");
}
inline bool
AbstractFramePtr::copyRawFrameSlots(AutoValueVector *vec) const
{
if (isStackFrame())
return asStackFrame()->copyRawFrameSlots(vec);
JS_NOT_REACHED("Invalid frame");
return false;
}
inline bool
AbstractFramePtr::prevUpToDate() const
{
if (isStackFrame())
return asStackFrame()->prevUpToDate();
JS_NOT_REACHED("Invalid frame");
return false;
}
inline void
AbstractFramePtr::setPrevUpToDate() const
{
if (isStackFrame()) {
asStackFrame()->setPrevUpToDate();
return;
}
JS_NOT_REACHED("Invalid frame");
}
inline AbstractFramePtr
AbstractFramePtr::evalPrev() const
{
JS_ASSERT(isEvalFrame());
if (isStackFrame())
return AbstractFramePtr(asStackFrame()->prev());
JS_NOT_REACHED("Invalid frame");
return NullFramePtr();
}
inline Value &
AbstractFramePtr::thisValue() const
{
if (isStackFrame())
return asStackFrame()->thisValue();
JS_NOT_REACHED("Invalid frame");
return asStackFrame()->thisValue();
}
} /* namespace js */
#endif /* Stack_inl_h__ */

View File

@ -1051,7 +1051,7 @@ ContextStack::pushInvokeFrame(JSContext *cx, const CallArgs &args,
bool
ContextStack::pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thisv,
JSObject &scopeChain, ExecuteType type,
StackFrame *evalInFrame, ExecuteFrameGuard *efg)
AbstractFramePtr evalInFrame, ExecuteFrameGuard *efg)
{
AssertCanGC();
@ -1071,14 +1071,14 @@ ContextStack::pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thi
MaybeExtend extend;
if (evalInFrame) {
/* Though the prev-frame is given, need to search for prev-call. */
StackSegment &seg = cx->stack.space().containingSegment(evalInFrame);
StackSegment &seg = cx->stack.space().containingSegment(evalInFrame.asStackFrame());
StackIter iter(cx->runtime, seg);
/* Debug-mode currently disables Ion compilation. */
JS_ASSERT(!evalInFrame->runningInIon());
JS_ASSERT_IF(evalInFrame->compartment() == iter.compartment(), !iter.isIon());
while (!iter.isScript() || iter.isIon() || iter.interpFrame() != evalInFrame) {
JS_ASSERT(!evalInFrame.asStackFrame()->runningInIon());
JS_ASSERT_IF(evalInFrame.compartment() == iter.compartment(), !iter.isIon());
while (!iter.isScript() || iter.isIon() || iter.abstractFramePtr() != evalInFrame) {
++iter;
JS_ASSERT_IF(evalInFrame->compartment() == iter.compartment(), !iter.isIon());
JS_ASSERT_IF(evalInFrame.compartment() == iter.compartment(), !iter.isIon());
}
evalInFrameCalls = iter.data_.calls_;
extend = CANT_EXTEND;
@ -1091,7 +1091,7 @@ ContextStack::pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thi
if (!firstUnused)
return false;
StackFrame *prev = evalInFrame ? evalInFrame : maybefp();
StackFrame *prev = evalInFrame ? evalInFrame.asStackFrame() : maybefp();
StackFrame *fp = reinterpret_cast<StackFrame *>(firstUnused + 2);
fp->initExecuteFrame(script, prev, seg_->maybeRegs(), thisv, scopeChain, type);
fp->initVarsToUndefined();
@ -1762,7 +1762,7 @@ StackIter::abstractFramePtr() const
break;
}
JS_NOT_REACHED("Unexpected state");
return AbstractFramePtr();
return NullFramePtr();
}
void
@ -2155,5 +2155,5 @@ AllFramesIter::abstractFramePtr() const
break;
}
JS_NOT_REACHED("Unexpected state");
return AbstractFramePtr();
return NullFramePtr();
}

View File

@ -213,6 +213,109 @@ enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false };
/*****************************************************************************/
class BaselineFrame;
/* Pointer to either a StackFrame or a baseline JIT frame. */
class AbstractFramePtr
{
uintptr_t ptr_;
protected:
AbstractFramePtr()
: ptr_(0)
{}
public:
AbstractFramePtr(StackFrame *fp)
: ptr_(fp ? uintptr_t(fp) | 0x1 : 0)
{
JS_ASSERT((uintptr_t(fp) & 1) == 0);
}
AbstractFramePtr(BaselineFrame *fp)
: ptr_(uintptr_t(fp))
{
JS_ASSERT((uintptr_t(fp) & 1) == 0);
}
bool isStackFrame() const {
return ptr_ & 0x1;
}
StackFrame *asStackFrame() const {
JS_ASSERT(isStackFrame());
StackFrame *res = (StackFrame *)(ptr_ & ~0x1);
JS_ASSERT(res);
return res;
}
void *raw() const { return reinterpret_cast<void *>(ptr_); }
bool operator ==(const AbstractFramePtr &other) const { return ptr_ == other.ptr_; }
bool operator !=(const AbstractFramePtr &other) const { return ptr_ != other.ptr_; }
operator bool() const { return !!ptr_; }
inline JSGenerator *maybeSuspendedGenerator(JSRuntime *rt) const;
inline UnrootedObject scopeChain() const;
inline CallObject &callObj() const;
inline JSCompartment *compartment() const;
inline StaticBlockObject *maybeBlockChain() const;
inline bool hasCallObj() const;
inline bool isGeneratorFrame() const;
inline bool isYielding() const;
inline bool isFunctionFrame() const;
inline bool isGlobalFrame() const;
inline bool isEvalFrame() const;
inline bool isFramePushedByExecute() const;
inline bool isDebuggerFrame() const;
inline UnrootedScript script() const;
inline JSFunction *fun() const;
inline JSFunction &callee() const;
inline Value &thisValue() const;
inline bool isNonEvalFunctionFrame() const;
inline bool isNonStrictDirectEvalFrame() const;
inline bool isStrictEvalFrame() const;
inline unsigned numActualArgs() const;
inline unsigned numFormalArgs() const;
inline Value *formals() const;
inline Value *actuals() const;
inline bool hasArgsObj() const;
inline ArgumentsObject &argsObj() const;
inline void initArgsObj(ArgumentsObject &argsobj) const;
inline bool copyRawFrameSlots(AutoValueVector *vec) const;
inline Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
inline Value &unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
inline bool prevUpToDate() const;
inline void setPrevUpToDate() const;
inline AbstractFramePtr evalPrev() const;
inline void *maybeHookData() const;
inline void setHookData(void *data) const;
inline void setReturnValue(const Value &rval) const;
};
class NullFramePtr : public AbstractFramePtr
{
public:
NullFramePtr()
: AbstractFramePtr()
{ }
};
/*****************************************************************************/
/* Flags specified for a frame as it is constructed. */
enum InitialFrameFlags {
INITIAL_NONE = 0,
@ -1592,7 +1695,7 @@ class ContextStack
/* Called by Execute for execution of eval or global code. */
bool pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thisv,
JSObject &scopeChain, ExecuteType type,
StackFrame *evalInFrame, ExecuteFrameGuard *efg);
AbstractFramePtr evalInFrame, ExecuteFrameGuard *efg);
/* Allocate actual argument space for the bailed frame */
bool pushBailoutArgs(JSContext *cx, const ion::IonBailoutIterator &it,
@ -1716,206 +1819,6 @@ class GeneratorFrameGuard : public FrameGuard
~GeneratorFrameGuard() { if (pushed()) stack_->popGeneratorFrame(*this); }
};
/* Pointer to either a StackFrame or a baseline JIT frame. */
class AbstractFramePtr
{
uintptr_t ptr_;
public:
AbstractFramePtr()
: ptr_(0)
{}
AbstractFramePtr(StackFrame *fp)
: ptr_(uintptr_t(fp) | 0x1)
{
JS_ASSERT(fp);
}
bool isStackFrame() const {
return ptr_ & 0x1;
}
StackFrame *asStackFrame() const {
JS_ASSERT(isStackFrame());
StackFrame *res = (StackFrame *)(ptr_ & ~0x1);
JS_ASSERT(res);
return res;
}
void *raw() const { return reinterpret_cast<void *>(ptr_); }
bool operator ==(const AbstractFramePtr &other) const { return ptr_ == other.ptr_; }
bool operator !=(const AbstractFramePtr &other) const { return ptr_ != other.ptr_; }
operator bool() const { return !!ptr_; }
JSGenerator *maybeSuspendedGenerator(JSRuntime *rt) const {
if (isStackFrame())
return asStackFrame()->maybeSuspendedGenerator(rt);
return NULL;
}
inline UnrootedObject scopeChain() const;
inline CallObject &callObj() const;
inline JSCompartment *compartment() const;
StaticBlockObject *maybeBlockChain() const {
if (isStackFrame())
return asStackFrame()->maybeBlockChain();
return NULL;
}
bool hasCallObj() const {
if (isStackFrame())
return asStackFrame()->hasCallObj();
JS_NOT_REACHED("Invalid frame");
return false;
}
bool isGeneratorFrame() const {
if (isStackFrame())
return asStackFrame()->isGeneratorFrame();
return false;
}
bool isYielding() const {
if (isStackFrame())
return asStackFrame()->isYielding();
return false;
}
bool isFunctionFrame() const {
if (isStackFrame())
return asStackFrame()->isFunctionFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
bool isGlobalFrame() const {
if (isStackFrame())
return asStackFrame()->isGlobalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
bool isEvalFrame() const {
if (isStackFrame())
return asStackFrame()->isEvalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
bool isFramePushedByExecute() const {
return isGlobalFrame() || isEvalFrame();
}
bool isDebuggerFrame() const {
if (isStackFrame())
return asStackFrame()->isDebuggerFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
JSScript *script() const {
if (isStackFrame())
return asStackFrame()->script();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
UnrootedFunction fun() const {
if (isStackFrame())
return asStackFrame()->fun();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
JSFunction &callee() const {
if (isStackFrame())
return asStackFrame()->callee();
JS_NOT_REACHED("Invalid frame");
return asStackFrame()->callee();
}
bool isNonEvalFunctionFrame() const {
if (isStackFrame())
return asStackFrame()->isNonEvalFunctionFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
bool isNonStrictDirectEvalFrame() const {
if (isStackFrame())
return asStackFrame()->isNonStrictDirectEvalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
bool isStrictEvalFrame() const {
if (isStackFrame())
return asStackFrame()->isStrictEvalFrame();
JS_NOT_REACHED("Invalid frame");
return false;
}
inline unsigned numActualArgs() const;
inline unsigned numFormalArgs() const;
Value *formals() const {
if (isStackFrame())
return asStackFrame()->formals();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
Value *actuals() const {
if (isStackFrame())
return asStackFrame()->actuals();
JS_NOT_REACHED("Invalid frame");
return NULL;
}
bool hasArgsObj() const {
if (isStackFrame())
return asStackFrame()->hasArgsObj();
JS_NOT_REACHED("Invalid frame");
return false;
}
ArgumentsObject &argsObj() const {
if (isStackFrame())
return asStackFrame()->argsObj();
JS_NOT_REACHED("Invalid frame");
return asStackFrame()->argsObj();
}
void initArgsObj(ArgumentsObject &argsobj) const {
if (isStackFrame()) {
asStackFrame()->initArgsObj(argsobj);
return;
}
JS_NOT_REACHED("Invalid frame");
}
bool copyRawFrameSlots(AutoValueVector *vec) const {
if (isStackFrame())
return asStackFrame()->copyRawFrameSlots(vec);
JS_NOT_REACHED("Invalid frame");
return false;
}
inline Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
inline Value &unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
bool prevUpToDate() const {
if (isStackFrame())
return asStackFrame()->prevUpToDate();
JS_NOT_REACHED("Invalid frame");
return false;
}
void setPrevUpToDate() const {
if (isStackFrame()) {
asStackFrame()->setPrevUpToDate();
return;
}
JS_NOT_REACHED("Invalid frame");
}
AbstractFramePtr evalPrev() const {
JS_ASSERT(isEvalFrame());
if (isStackFrame())
return AbstractFramePtr(asStackFrame()->prev());
JS_NOT_REACHED("Invalid frame");
return AbstractFramePtr();
}
inline void *maybeHookData() const;
inline void setHookData(void *data) const;
inline void setReturnValue(const Value &rval) const;
};
template <>
struct DefaultHasher<AbstractFramePtr> {
typedef AbstractFramePtr Lookup;