From 6f41fe1cad2ffcfb20be0e27e5da32fd17521ef3 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 21 Jan 2013 13:58:50 +0100 Subject: [PATCH] Bug 832373 part 1 - Refactor eval-in-frame to use AbstractFramePtr. r=luke --- js/src/builtin/Eval.cpp | 20 +- js/src/frontend/BytecodeCompiler.cpp | 15 +- js/src/frontend/BytecodeCompiler.h | 2 +- js/src/frontend/BytecodeEmitter.cpp | 7 +- js/src/frontend/BytecodeEmitter.h | 4 +- js/src/jsapi.cpp | 4 +- js/src/jsinterp.cpp | 4 +- js/src/jsinterp.h | 4 +- js/src/jsinterpinlines.h | 21 +- js/src/vm/Debugger.cpp | 26 +-- js/src/vm/Debugger.h | 2 +- js/src/vm/ScopeObject.cpp | 20 +- js/src/vm/ScopeObject.h | 2 +- js/src/vm/Stack-inl.h | 209 ++++++++++++++++++ js/src/vm/Stack.cpp | 18 +- js/src/vm/Stack.h | 305 +++++++++------------------ 16 files changed, 390 insertions(+), 273 deletions(-) diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index 5214a74f775..71b9b140e45 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -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 global(cx, &args.callee().global()); - return EvalKernel(cx, args, INDIRECT_EVAL, NULL, global); + return EvalKernel(cx, args, INDIRECT_EVAL, NullFramePtr(), global); } bool diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 58bbc3a8c3a..4c05ee609b1 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -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 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; diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index 7e7d92f7a8b..98d21200b9e 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -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); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index a7016f9c4c2..d8c57bcf31e 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -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; diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index bf946d380d9..771957ec7db 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -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(); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 0df43ffe1e4..c4c13e7779e 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -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; diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index a4cf48b5338..e80e0853355 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -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 diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index 3bb258c1d21..1edcc1b9ec0 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -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 diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h index ca6a08364f3..1a78a971457 100644 --- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -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; } /* diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 2b62321dd1e..2e70cc392fa 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -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, HandleValue thisv, StackFrame *fp, +js::EvaluateInEnv(JSContext *cx, Handle 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, 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 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); } diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 05833dd562b..ad782e60b1f 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -691,7 +691,7 @@ Debugger::onNewGlobalObject(JSContext *cx, Handle global) } extern JSBool -EvaluateInEnv(JSContext *cx, Handle env, HandleValue thisv, StackFrame *fp, +EvaluateInEnv(JSContext *cx, Handle env, HandleValue thisv, AbstractFramePtr frame, StableCharPtr chars, unsigned length, const char *filename, unsigned lineno, Value *rval); diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index d13e533991f..8aec1674674 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -881,7 +881,7 @@ js::CloneStaticBlockObject(JSContext *cx, HandleObject enclosingScope, Handle(-1)), block_(cx, reinterpret_cast(-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(-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(); } /*****************************************************************************/ diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index cbb02cdddf5..73312cf24ec 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -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_) {} diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index f92235ee2ee..59739686267 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -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__ */ diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 37353814d0a..8312160aa6f 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -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(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(); } diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 4a30d002a4d..1da8196859b 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -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(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(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 { typedef AbstractFramePtr Lookup;