--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -151,20 +151,20 @@ enum EvalType { DIRECT_EVAL = EXECUTE_DI
//
// Evaluate call.argv[2], if it is a string, in the context of the given calling
// frame, with the provided scope chain, with the semantics of either a direct
// or indirect eval (see ES5 10.4.2). If this is an indirect eval, scopeobj
// must be a global object.
//
// 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);
if (!scopeobj->global().isRuntimeCodeGenEnabled(cx)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_EVAL);
return false;
}
@@ -182,25 +182,25 @@ EvalKernel(JSContext *cx, const CallArgs
// ES5 15.1.2.1 steps 2-8.
// Per ES5, indirect eval runs in the global scope. (eval is specified this
// way so that the compiler can make assumptions about what bindings may or
// may not exist in the current frame if it doesn't see 'eval'.)
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;
// Use the global as 'this', modulo outerization.
JSObject *thisobj = JSObject::thisObject(cx, scopeobj);
if (!thisobj)
return false;
@@ -221,17 +221,17 @@ EvalKernel(JSContext *cx, const CallArgs
//
// Don't use the JSON parser if the caller is strict mode code, because in
// strict mode object literals must not have repeated properties, and the
// JSON parser cheerfully (and correctly) accepts them. If you're parsing
// JSON with eval and using strict mode, you deserve to be slow.
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
// terminator characters U+2028 and U+2029, but strings in JSON can.
// Rather than force the JSON parser to handle this quirk when used by
// eval, we simply don't use the JSON parser when either character
// appears in the provided string. See bug 657367.
for (const jschar *cp = &chars[1], *end = &chars[length - 2]; ; cp++) {
@@ -252,18 +252,18 @@ EvalKernel(JSContext *cx, const CallArgs
}
}
}
EvalScriptGuard esg(cx);
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;
const char *filename;
JSPrincipals *originPrincipals;
CurrentScriptFileLineOrigin(cx, &filename, &lineno, &originPrincipals,
evalType == DIRECT_EVAL ? CALLED_FROM_JSOP_EVAL
: NOT_CALLED_FROM_JSOP_EVAL);
@@ -278,17 +278,17 @@ EvalKernel(JSContext *cx, const CallArgs
chars, length, stableStr, staticLevel);
if (!compiled)
return false;
esg.setNewScript(compiled);
}
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
// when evaluating the code string. Warn when such uses are seen so that
// authors will know that support for eval(s, o) has been removed.
static inline bool
WarnOnTooManyArgs(JSContext *cx, const CallArgs &args)
{
@@ -313,17 +313,17 @@ WarnOnTooManyArgs(JSContext *cx, const C
JSBool
js::IndirectEval(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!WarnOnTooManyArgs(cx, args))
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
js::DirectEval(JSContext *cx, const CallArgs &args)
{
// Direct eval can assume it was called from an interpreted frame.
StackFrame *caller = cx->fp();
JS_ASSERT(IsBuiltinEvalForScope(caller->scopeChain(), args.calleev()));
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -42,17 +42,17 @@ SetSourceMap(JSContext *cx, TokenStream
if (tokenStream.hasSourceMap()) {
if (!ss->setSourceMap(cx, tokenStream.releaseSourceMap(), script->filename))
return false;
}
return true;
}
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 */,
unsigned staticLevel /* = 0 */)
{
RootedString source(cx, source_);
class ProbesManager
@@ -101,17 +101,17 @@ frontend::CompileScript(JSContext *cx, H
parser.sct = &sct;
GlobalSharedContext globalsc(cx, scopeChain, StrictModeFromContext(cx));
ParseContext pc(&parser, &globalsc, staticLevel, /* bodyid = */ 0);
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)
return UnrootedScript(NULL);
// Global/eval script bindings are always empty (all names are added to the
// scope dynamically via JSOP_DEFFUN/VAR).
InternalHandle<Bindings*> bindings(script, &script->bindings);
@@ -124,38 +124,38 @@ frontend::CompileScript(JSContext *cx, H
JS_ASSERT_IF(globalScope, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalScope->getClass()));
BytecodeEmitter bce(/* parent = */ NULL, &parser, &globalsc, script, callerFrame, !!globalScope,
options.lineno, options.selfHostingMode);
if (!bce.init())
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) {
if (source) {
/*
* Save eval program source in script->atoms[0] for the
* eval cache (see EvalCacheLookup in jsobj.cpp).
*/
JSAtom *atom = AtomizeString(cx, source);
jsatomid _;
if (!atom || !bce.makeAtomIndex(atom, &_))
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);
bce.objectList.add(funbox);
}
}
ParseNode *pn;
@@ -212,17 +212,17 @@ frontend::CompileScript(JSContext *cx, H
*/
if (pn && onlyXML && !callerFrame) {
parser.reportError(NULL, JSMSG_XML_WHOLE_PROGRAM);
return UnrootedScript(NULL);
}
#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) {
parser.reportError(NULL, JSMSG_ARGUMENTS_AND_REST);
return UnrootedScript(NULL);
}
}
}
@@ -313,17 +313,18 @@ frontend::CompileFunctionBody(JSContext
// Reparse in strict mode.
parser.tokenStream.seek(start);
pn = parser.standaloneFunctionBody(fun, formals, script, fn, &funbox,
/* strict = */ true);
if (!pn)
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;
if (!NameFunctions(cx, pn))
return false;
if (fn->pn_body) {
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -9,17 +9,17 @@
#define BytecodeCompiler_h__
#include "frontend/Parser.h"
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);
bool
CompileFunctionBody(JSContext *cx, HandleFunction fun, CompileOptions options,
const AutoNameVector &formals, StableCharPtr chars, size_t length);
} /* namespace frontend */
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -95,17 +95,17 @@ struct frontend::StmtInfoBCE : public St
ptrdiff_t &guardJump() {
JS_ASSERT(type == STMT_TRY || type == STMT_FINALLY);
return continues;
}
};
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),
script(sc->context, script),
parser(parser),
callerFrame(callerFrame),
topStmt(NULL),
topScopeStmt(NULL),
@@ -1276,32 +1276,31 @@ BindNameToSlot(JSContext *cx, BytecodeEm
return false;
}
}
pn->setOp(op = JSOP_NAME);
}
}
if (dn->pn_cookie.isFree()) {
- StackFrame *caller = bce->callerFrame;
- if (caller) {
+ if (AbstractFramePtr caller = bce->callerFrame) {
JS_ASSERT(bce->script->compileAndGo);
/*
* Don't generate upvars on the left side of a for loop. See
* bug 470758.
*/
if (bce->emittingForInit)
return true;
/*
* 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;
}
/*
* Out of tricks, so we must rely on PICs to optimize named
* accesses from direct eval called from function code.
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -78,17 +78,17 @@ struct BytecodeEmitter
ptrdiff_t lastNoteOffset; /* code offset for last source note */
unsigned currentLine; /* line number for tree-based srcnote gen */
unsigned lastColumn; /* zero-based column index on currentLine of
last SRC_COLSPAN-annotated opcode */
} prolog, main, *current;
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 */
Rooted<StaticBlockObject *> blockChain;
/* compile time block scope chain */
OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
unsigned firstLine; /* first line, for JSScript::initFromEmitter */
@@ -121,17 +121,17 @@ struct BytecodeEmitter
global object */
const bool selfHostingMode:1; /* Emit JSOP_CALLINTRINSIC instead of JSOP_NAME
and assert that JSOP_NAME and JSOP_*GNAME
don't ever get emitted. See the comment for
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();
/*
* Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
* space above their tempMark points. This means that you cannot alloc from
* tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
* destructor call.
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5281,17 +5281,17 @@ JS::Compile(JSContext *cx, HandleObject
JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
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 *
JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options,
const char *bytes, size_t length)
{
jschar *chars;
if (options.utf8)
@@ -5634,17 +5634,17 @@ JS::Evaluate(JSContext *cx, HandleObject
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
JS_ASSERT_IF(options.principals, cx->compartment->principals == options.principals);
AutoLastFrameCheck lfc(cx);
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;
JS_ASSERT(script->getVersion() == options.version);
return Execute(cx, script, *obj, rval);
}
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -509,17 +509,17 @@ js::InvokeGetterOrSetter(JSContext *cx,
*/
JS_CHECK_RECURSION(cx, return false);
return Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval);
}
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());
if (script->isEmpty()) {
if (result)
result->setUndefined();
return true;
@@ -569,17 +569,17 @@ js::Execute(JSContext *cx, HandleScript
/* Use the scope chain as 'this', modulo outerization. */
JSObject *thisObj = JSObject::thisObject(cx, scopeChain);
if (!thisObj)
return false;
Value thisv = ObjectValue(*thisObj);
return ExecuteKernel(cx, script, *scopeChain, thisv, EXECUTE_GLOBAL,
- NULL /* evalInFrame */, rval);
+ NullFramePtr() /* evalInFrame */, rval);
}
bool
js::HasInstance(JSContext *cx, HandleObject obj, HandleValue v, JSBool *bp)
{
Class *clasp = obj->getClass();
RootedValue local(cx, v);
if (clasp->hasInstance)
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -72,17 +72,17 @@ BoxNonStrictThis(JSContext *cx, MutableH
/*
* Ensure that fp->thisValue() is the correct value of |this| for the scripted
* call represented by |fp|. ComputeThis is necessary because fp->thisValue()
* may be set to 'undefined' when 'this' should really be the global object (as
* 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,
CONSTRUCT = INITIAL_CONSTRUCT
};
extern bool
ReportIsNotFunction(JSContext *cx, const Value &v, MaybeConstruct construct = NO_CONSTRUCT);
@@ -155,17 +155,17 @@ InvokeConstructor(JSContext *cx, const V
/*
* Executes a script with the given scopeChain/this. The 'type' indicates
* whether this is eval code or global code. To support debugging, the
* evalFrame parameter can point to an arbitrary frame in the context's call
* stack to simulate executing an eval in that frame.
*/
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
Execute(JSContext *cx, HandleScript script, JSObject &scopeChain, Value *rval);
/* Flags to toggle js::Interpret() execution. */
enum InterpMode
{
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -77,35 +77,40 @@ ComputeImplicitThis(JSContext *cx, Handl
if (!nobj)
return false;
vp->setObject(*nobj);
return true;
}
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
* |this| slot. If we lazily wrap a primitive |this| in an eval function frame, the
* eval's frame will get the wrapper, but the function's frame will not. To prevent
* 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;
}
/*
* Every possible consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) (as determined
* by ScriptAnalysis::needsArgsObj) must check for these magic values and, when
* one is received, act as if the value were the function's ArgumentsObject.
* Additionally, it is possible that, after 'arguments' was copied into a
* temporary, the arguments object has been created a some other failed guard
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -3678,50 +3678,50 @@ DebuggerFrame_setOnPop(JSContext *cx, un
return true;
}
/*
* Evaluate |chars[0..length-1]| in the environment |env|, treating that
* 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()));
/*
* NB: This function breaks the assumption that the compiler can see all
* calls and properly compute a static level. In practice, any non-zero
* static level will suffice.
*/
CompileOptions options(cx);
options.setPrincipals(env->compartment()->principals)
.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
DebuggerGenericEval(JSContext *cx, const char *fullMethodName,
const Value &code, Value *bindings, MutableHandleValue vp,
Debugger *dbg, HandleObject scope, ScriptFrameIter *iter)
{
/* Either we're specifying the frame, or a global. */
@@ -3801,18 +3801,18 @@ DebuggerGenericEval(JSContext *cx, const
return false;
}
}
}
/* 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);
}
static JSBool
DebuggerFrame_eval(JSContext *cx, unsigned argc, Value *vp)
{
THIS_FRAME(cx, argc, vp, "eval", args, thisobj, iter);
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -686,15 +686,15 @@ bool
Debugger::onNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global)
{
if (JS_CLIST_IS_EMPTY(&cx->runtime->onNewGlobalObjectWatchers))
return true;
return Debugger::slowPathOnNewGlobalObject(cx, 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);
}
#endif /* Debugger_h__ */
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -876,17 +876,17 @@ js::CloneStaticBlockObject(JSContext *cx
return clone;
}
/*****************************************************************************/
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))
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
ScopeIter::ScopeIter(const ScopeIter &si, JSContext *cx
@@ -897,17 +897,17 @@ ScopeIter::ScopeIter(const ScopeIter &si
type_(si.type_),
hasScopeObject_(si.hasScopeObject_)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
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))
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
ScopeIter::ScopeIter(AbstractFramePtr frame, JSContext *cx
@@ -981,33 +981,33 @@ ScopeIter::operator++()
JS_ASSERT(!done());
switch (type_) {
case Call:
if (hasScopeObject_) {
cur_ = &cur_->asCall().enclosingScope();
if (CallObjectLambdaName(*frame_.fun()))
cur_ = &cur_->asDeclEnv().enclosingScope();
}
- frame_ = AbstractFramePtr();
+ frame_ = NullFramePtr();
break;
case Block:
block_ = block_->enclosingBlock();
if (hasScopeObject_)
cur_ = &cur_->asClonedBlock().enclosingScope();
settle();
break;
case With:
JS_ASSERT(hasScopeObject_);
cur_ = &cur_->asWith().enclosingScope();
settle();
break;
case StrictEvalScope:
if (hasScopeObject_)
cur_ = &cur_->asCall().enclosingScope();
- frame_ = AbstractFramePtr();
+ frame_ = NullFramePtr();
break;
}
return *this;
}
void
ScopeIter::settle()
{
@@ -1044,24 +1044,24 @@ ScopeIter::settle()
hasScopeObject_ = false;
}
} else if (frame_.isNonStrictDirectEvalFrame() && cur_ == frame_.evalPrev().scopeChain()) {
if (block_) {
JS_ASSERT(!block_->needsClone());
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());
JS_ASSERT_IF(block_, block_->stackDepth() < cur_->asWith().stackDepth());
type_ = With;
hasScopeObject_ = true;
} else if (block_) {
type_ = Block;
@@ -1070,17 +1070,17 @@ ScopeIter::settle()
} else if (cur_->isCall()) {
CallObject &callobj = cur_->asCall();
type_ = callobj.isForEval() ? StrictEvalScope : Call;
hasScopeObject_ = true;
JS_ASSERT_IF(type_ == Call, callobj.callee().nonLazyScript() == frame_.script());
} else {
JS_ASSERT(!cur_->isScope());
JS_ASSERT(frame_.isGlobalFrame() || frame_.isDebuggerFrame());
- frame_ = AbstractFramePtr();
+ frame_ = NullFramePtr();
}
}
/* static */ HashNumber
ScopeIterKey::hash(ScopeIterKey si)
{
/* hasScopeObject_ is determined by the other fields. */
return size_t(si.frame_.raw()) ^ size_t(si.cur_) ^ size_t(si.block_) ^ si.type_;
@@ -1954,17 +1954,17 @@ DebugScopes::updateLiveScopes(JSContext
return true;
}
AbstractFramePtr
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;
/*
* Since liveScopes is effectively a weak pointer, we need a read
* barrier. The scenario where this is necessary is:
* 1. GC starts, a suspended generator is not live
@@ -1975,17 +1975,17 @@ DebugScopes::hasLiveFrame(ScopeObject &s
* 4. GC completes, live objects may now point to values that weren't
* marked and thus may point to swept GC things
*/
if (JSGenerator *gen = frame.maybeSuspendedGenerator(scope.compartment()->rt))
JSObject::readBarrier(gen->obj);
return frame;
}
- return AbstractFramePtr();
+ return NullFramePtr();
}
/*****************************************************************************/
static JSObject *
GetDebugScope(JSContext *cx, const ScopeIter &si);
static DebugScopeObject *
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -467,17 +467,17 @@ class ScopeIter
class ScopeIterKey
{
AbstractFramePtr frame_;
JSObject *cur_;
StaticBlockObject *block_;
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_)
{}
AbstractFramePtr frame() const { return frame_; }
ScopeIter::Type type() const { return type_; }
/* For use as hash policy */
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -701,10 +701,219 @@ inline Value &
AbstractFramePtr::unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing)
{
if (isStackFrame())
return asStackFrame()->unaliasedFormal(i, checkAliasing);
JS_NOT_REACHED("Invalid frame");
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__ */
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1046,17 +1046,17 @@ ContextStack::pushInvokeFrame(JSContext
if (!pushInvokeFrame(cx, REPORT_ERROR, args, fun, initial, ifg))
return false;
return true;
}
bool
ContextStack::pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thisv,
JSObject &scopeChain, ExecuteType type,
- StackFrame *evalInFrame, ExecuteFrameGuard *efg)
+ AbstractFramePtr evalInFrame, ExecuteFrameGuard *efg)
{
AssertCanGC();
/*
* Even though global code and indirect eval do not execute in the context
* of the current frame, prev-link these to the current frame so that the
* callstack looks right to the debugger (via CAN_EXTEND). This is safe
* since the scope chain is what determines name lookup and access, not
@@ -1066,37 +1066,37 @@ ContextStack::pushExecuteFrame(JSContext
* (possibly in the middle of some previous segment). Thus pass CANT_EXTEND
* (to start a new segment) and link the frame and call chain manually
* below.
*/
CallArgsList *evalInFrameCalls = NULL; /* quell overwarning */
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;
} else {
extend = CAN_EXTEND;
}
unsigned nvars = 2 /* callee, this */ + VALUES_PER_STACK_FRAME + script->nslots;
Value *firstUnused = ensureOnTop(cx, REPORT_ERROR, nvars, extend, &efg->pushedSeg_);
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();
efg->regs_.prepareToRun(*fp, script);
/* pushRegs() below links the prev-frame; manually link the prev-call. */
if (evalInFrame && evalInFrameCalls)
seg_->pointAtCall(*evalInFrameCalls);
@@ -1757,17 +1757,17 @@ StackIter::abstractFramePtr() const
break;
case SCRIPTED:
JS_ASSERT(interpFrame());
return AbstractFramePtr(interpFrame());
case NATIVE:
break;
}
JS_NOT_REACHED("Unexpected state");
- return AbstractFramePtr();
+ return NullFramePtr();
}
void
StackIter::updatePcQuadratic()
{
switch (data_.state_) {
case DONE:
break;
@@ -2150,10 +2150,10 @@ AllFramesIter::abstractFramePtr() const
case SCRIPTED:
return AbstractFramePtr(interpFrame());
case ION:
break;
case DONE:
break;
}
JS_NOT_REACHED("Unexpected state");
- return AbstractFramePtr();
+ return NullFramePtr();
}
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -208,16 +208,119 @@ CallArgsListFromVp(unsigned argc, Value
}
/*****************************************************************************/
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,
INITIAL_CONSTRUCT = 0x20, /* == StackFrame::CONSTRUCTING, asserted below */
INITIAL_LOWERED = 0x80000 /* == StackFrame::LOWERED_CALL_APPLY, asserted below */
};
enum ExecuteType {
@@ -1587,17 +1690,17 @@ class ContextStack
/* Called by Invoke for a scripted function call. */
bool pushInvokeFrame(JSContext *cx, const CallArgs &args,
InitialFrameFlags initial, InvokeFrameGuard *ifg);
/* 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,
InvokeArgsGuard *iag);
/* Bailout for normal functions. */
StackFrame *pushBailoutFrame(JSContext *cx, const ion::IonBailoutIterator &it,
const CallArgs &args, BailoutFrameGuard *bfg);
@@ -1711,216 +1814,16 @@ class GeneratorFrameGuard : public Frame
{
friend class ContextStack;
JSGenerator *gen_;
Value *stackvp_;
public:
~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;
static js::HashNumber hash(const Lookup &key) {
return size_t(key.raw());
}