1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/Stack.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1747 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "vm/Stack-inl.h" 1.11 + 1.12 +#include "mozilla/PodOperations.h" 1.13 + 1.14 +#include "jscntxt.h" 1.15 + 1.16 +#include "gc/Marking.h" 1.17 +#ifdef JS_ION 1.18 +#include "jit/AsmJSModule.h" 1.19 +#include "jit/BaselineFrame.h" 1.20 +#include "jit/JitCompartment.h" 1.21 +#endif 1.22 +#include "js/GCAPI.h" 1.23 +#include "vm/Opcodes.h" 1.24 + 1.25 +#include "jit/JitFrameIterator-inl.h" 1.26 +#include "vm/Interpreter-inl.h" 1.27 +#include "vm/Probes-inl.h" 1.28 +#include "vm/ScopeObject-inl.h" 1.29 + 1.30 +using namespace js; 1.31 + 1.32 +using mozilla::PodCopy; 1.33 + 1.34 +/*****************************************************************************/ 1.35 + 1.36 +void 1.37 +InterpreterFrame::initExecuteFrame(JSContext *cx, JSScript *script, AbstractFramePtr evalInFramePrev, 1.38 + const Value &thisv, JSObject &scopeChain, ExecuteType type) 1.39 +{ 1.40 + /* 1.41 + * See encoding of ExecuteType. When GLOBAL isn't set, we are executing a 1.42 + * script in the context of another frame and the frame type is determined 1.43 + * by the context. 1.44 + */ 1.45 + flags_ = type | HAS_SCOPECHAIN; 1.46 + 1.47 + JSObject *callee = nullptr; 1.48 + if (!(flags_ & (GLOBAL))) { 1.49 + if (evalInFramePrev) { 1.50 + JS_ASSERT(evalInFramePrev.isFunctionFrame() || evalInFramePrev.isGlobalFrame()); 1.51 + if (evalInFramePrev.isFunctionFrame()) { 1.52 + callee = evalInFramePrev.callee(); 1.53 + flags_ |= FUNCTION; 1.54 + } else { 1.55 + flags_ |= GLOBAL; 1.56 + } 1.57 + } else { 1.58 + FrameIter iter(cx); 1.59 + JS_ASSERT(iter.isFunctionFrame() || iter.isGlobalFrame()); 1.60 + JS_ASSERT(!iter.isAsmJS()); 1.61 + if (iter.isFunctionFrame()) { 1.62 + callee = iter.callee(); 1.63 + flags_ |= FUNCTION; 1.64 + } else { 1.65 + flags_ |= GLOBAL; 1.66 + } 1.67 + } 1.68 + } 1.69 + 1.70 + Value *dstvp = (Value *)this - 2; 1.71 + dstvp[1] = thisv; 1.72 + 1.73 + if (isFunctionFrame()) { 1.74 + dstvp[0] = ObjectValue(*callee); 1.75 + exec.fun = &callee->as<JSFunction>(); 1.76 + u.evalScript = script; 1.77 + } else { 1.78 + JS_ASSERT(isGlobalFrame()); 1.79 + dstvp[0] = NullValue(); 1.80 + exec.script = script; 1.81 +#ifdef DEBUG 1.82 + u.evalScript = (JSScript *)0xbad; 1.83 +#endif 1.84 + } 1.85 + 1.86 + scopeChain_ = &scopeChain; 1.87 + prev_ = nullptr; 1.88 + prevpc_ = nullptr; 1.89 + prevsp_ = nullptr; 1.90 + 1.91 + JS_ASSERT_IF(evalInFramePrev, isDebuggerFrame()); 1.92 + evalInFramePrev_ = evalInFramePrev; 1.93 + 1.94 +#ifdef DEBUG 1.95 + Debug_SetValueRangeToCrashOnTouch(&rval_, 1); 1.96 + hookData_ = (void *)0xbad; 1.97 +#endif 1.98 +} 1.99 + 1.100 +template <InterpreterFrame::TriggerPostBarriers doPostBarrier> 1.101 +void 1.102 +InterpreterFrame::copyFrameAndValues(JSContext *cx, Value *vp, InterpreterFrame *otherfp, 1.103 + const Value *othervp, Value *othersp) 1.104 +{ 1.105 + JS_ASSERT(othervp == otherfp->generatorArgsSnapshotBegin()); 1.106 + JS_ASSERT(othersp >= otherfp->slots()); 1.107 + JS_ASSERT(othersp <= otherfp->generatorSlotsSnapshotBegin() + otherfp->script()->nslots()); 1.108 + 1.109 + /* Copy args, InterpreterFrame, and slots. */ 1.110 + const Value *srcend = otherfp->generatorArgsSnapshotEnd(); 1.111 + Value *dst = vp; 1.112 + for (const Value *src = othervp; src < srcend; src++, dst++) { 1.113 + *dst = *src; 1.114 + if (doPostBarrier) 1.115 + HeapValue::writeBarrierPost(*dst, dst); 1.116 + } 1.117 + 1.118 + *this = *otherfp; 1.119 + argv_ = vp + 2; 1.120 + unsetPushedSPSFrame(); 1.121 + if (doPostBarrier) 1.122 + writeBarrierPost(); 1.123 + 1.124 + srcend = othersp; 1.125 + dst = slots(); 1.126 + for (const Value *src = otherfp->slots(); src < srcend; src++, dst++) { 1.127 + *dst = *src; 1.128 + if (doPostBarrier) 1.129 + HeapValue::writeBarrierPost(*dst, dst); 1.130 + } 1.131 +} 1.132 + 1.133 +/* Note: explicit instantiation for js_NewGenerator located in jsiter.cpp. */ 1.134 +template 1.135 +void InterpreterFrame::copyFrameAndValues<InterpreterFrame::NoPostBarrier>( 1.136 + JSContext *, Value *, InterpreterFrame *, const Value *, Value *); 1.137 +template 1.138 +void InterpreterFrame::copyFrameAndValues<InterpreterFrame::DoPostBarrier>( 1.139 + JSContext *, Value *, InterpreterFrame *, const Value *, Value *); 1.140 + 1.141 +void 1.142 +InterpreterFrame::writeBarrierPost() 1.143 +{ 1.144 + /* This needs to follow the same rules as in InterpreterFrame::mark. */ 1.145 + if (scopeChain_) 1.146 + JSObject::writeBarrierPost(scopeChain_, (void *)&scopeChain_); 1.147 + if (flags_ & HAS_ARGS_OBJ) 1.148 + JSObject::writeBarrierPost(argsObj_, (void *)&argsObj_); 1.149 + if (isFunctionFrame()) { 1.150 + JSFunction::writeBarrierPost(exec.fun, (void *)&exec.fun); 1.151 + if (isEvalFrame()) 1.152 + JSScript::writeBarrierPost(u.evalScript, (void *)&u.evalScript); 1.153 + } else { 1.154 + JSScript::writeBarrierPost(exec.script, (void *)&exec.script); 1.155 + } 1.156 + if (hasReturnValue()) 1.157 + HeapValue::writeBarrierPost(rval_, &rval_); 1.158 +} 1.159 + 1.160 +bool 1.161 +InterpreterFrame::copyRawFrameSlots(AutoValueVector *vec) 1.162 +{ 1.163 + if (!vec->resize(numFormalArgs() + script()->nfixed())) 1.164 + return false; 1.165 + PodCopy(vec->begin(), argv(), numFormalArgs()); 1.166 + PodCopy(vec->begin() + numFormalArgs(), slots(), script()->nfixed()); 1.167 + return true; 1.168 +} 1.169 + 1.170 +JSObject * 1.171 +InterpreterFrame::createRestParameter(JSContext *cx) 1.172 +{ 1.173 + JS_ASSERT(fun()->hasRest()); 1.174 + unsigned nformal = fun()->nargs() - 1, nactual = numActualArgs(); 1.175 + unsigned nrest = (nactual > nformal) ? nactual - nformal : 0; 1.176 + Value *restvp = argv() + nformal; 1.177 + JSObject *obj = NewDenseCopiedArray(cx, nrest, restvp, nullptr); 1.178 + if (!obj) 1.179 + return nullptr; 1.180 + types::FixRestArgumentsType(cx, obj); 1.181 + return obj; 1.182 +} 1.183 + 1.184 +static inline void 1.185 +AssertDynamicScopeMatchesStaticScope(JSContext *cx, JSScript *script, JSObject *scope) 1.186 +{ 1.187 +#ifdef DEBUG 1.188 + RootedObject enclosingScope(cx, script->enclosingStaticScope()); 1.189 + for (StaticScopeIter<NoGC> i(enclosingScope); !i.done(); i++) { 1.190 + if (i.hasDynamicScopeObject()) { 1.191 + switch (i.type()) { 1.192 + case StaticScopeIter<NoGC>::BLOCK: 1.193 + JS_ASSERT(&i.block() == scope->as<ClonedBlockObject>().staticScope()); 1.194 + scope = &scope->as<ClonedBlockObject>().enclosingScope(); 1.195 + break; 1.196 + case StaticScopeIter<NoGC>::WITH: 1.197 + JS_ASSERT(&i.staticWith() == scope->as<DynamicWithObject>().staticScope()); 1.198 + scope = &scope->as<DynamicWithObject>().enclosingScope(); 1.199 + break; 1.200 + case StaticScopeIter<NoGC>::FUNCTION: 1.201 + JS_ASSERT(scope->as<CallObject>().callee().nonLazyScript() == i.funScript()); 1.202 + scope = &scope->as<CallObject>().enclosingScope(); 1.203 + break; 1.204 + case StaticScopeIter<NoGC>::NAMED_LAMBDA: 1.205 + scope = &scope->as<DeclEnvObject>().enclosingScope(); 1.206 + break; 1.207 + } 1.208 + } 1.209 + } 1.210 + 1.211 + /* 1.212 + * Ideally, we'd JS_ASSERT(!scope->is<ScopeObject>()) but the enclosing 1.213 + * lexical scope chain stops at eval() boundaries. See StaticScopeIter 1.214 + * comment. 1.215 + */ 1.216 +#endif 1.217 +} 1.218 + 1.219 +bool 1.220 +InterpreterFrame::initFunctionScopeObjects(JSContext *cx) 1.221 +{ 1.222 + CallObject *callobj = CallObject::createForFunction(cx, this); 1.223 + if (!callobj) 1.224 + return false; 1.225 + pushOnScopeChain(*callobj); 1.226 + flags_ |= HAS_CALL_OBJ; 1.227 + return true; 1.228 +} 1.229 + 1.230 +bool 1.231 +InterpreterFrame::prologue(JSContext *cx) 1.232 +{ 1.233 + RootedScript script(cx, this->script()); 1.234 + 1.235 + JS_ASSERT(!isGeneratorFrame()); 1.236 + JS_ASSERT(cx->interpreterRegs().pc == script->code()); 1.237 + 1.238 + if (isEvalFrame()) { 1.239 + if (script->strict()) { 1.240 + CallObject *callobj = CallObject::createForStrictEval(cx, this); 1.241 + if (!callobj) 1.242 + return false; 1.243 + pushOnScopeChain(*callobj); 1.244 + flags_ |= HAS_CALL_OBJ; 1.245 + } 1.246 + return probes::EnterScript(cx, script, nullptr, this); 1.247 + } 1.248 + 1.249 + if (isGlobalFrame()) 1.250 + return probes::EnterScript(cx, script, nullptr, this); 1.251 + 1.252 + JS_ASSERT(isNonEvalFunctionFrame()); 1.253 + AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain()); 1.254 + 1.255 + if (fun()->isHeavyweight() && !initFunctionScopeObjects(cx)) 1.256 + return false; 1.257 + 1.258 + if (isConstructing()) { 1.259 + RootedObject callee(cx, &this->callee()); 1.260 + JSObject *obj = CreateThisForFunction(cx, callee, 1.261 + useNewType() ? SingletonObject : GenericObject); 1.262 + if (!obj) 1.263 + return false; 1.264 + functionThis() = ObjectValue(*obj); 1.265 + } 1.266 + 1.267 + return probes::EnterScript(cx, script, script->functionNonDelazifying(), this); 1.268 +} 1.269 + 1.270 +void 1.271 +InterpreterFrame::epilogue(JSContext *cx) 1.272 +{ 1.273 + JS_ASSERT(!isYielding()); 1.274 + 1.275 + RootedScript script(cx, this->script()); 1.276 + probes::ExitScript(cx, script, script->functionNonDelazifying(), hasPushedSPSFrame()); 1.277 + 1.278 + if (isEvalFrame()) { 1.279 + if (isStrictEvalFrame()) { 1.280 + JS_ASSERT_IF(hasCallObj(), scopeChain()->as<CallObject>().isForEval()); 1.281 + if (MOZ_UNLIKELY(cx->compartment()->debugMode())) 1.282 + DebugScopes::onPopStrictEvalScope(this); 1.283 + } else if (isDirectEvalFrame()) { 1.284 + if (isDebuggerFrame()) 1.285 + JS_ASSERT(!scopeChain()->is<ScopeObject>()); 1.286 + } else { 1.287 + /* 1.288 + * Debugger.Object.prototype.evalInGlobal creates indirect eval 1.289 + * frames scoped to the given global; 1.290 + * Debugger.Object.prototype.evalInGlobalWithBindings creates 1.291 + * indirect eval frames scoped to an object carrying the introduced 1.292 + * bindings. 1.293 + */ 1.294 + if (isDebuggerFrame()) { 1.295 + JS_ASSERT(scopeChain()->is<GlobalObject>() || 1.296 + scopeChain()->enclosingScope()->is<GlobalObject>()); 1.297 + } else { 1.298 + JS_ASSERT(scopeChain()->is<GlobalObject>()); 1.299 + } 1.300 + } 1.301 + return; 1.302 + } 1.303 + 1.304 + if (isGlobalFrame()) { 1.305 + JS_ASSERT(!scopeChain()->is<ScopeObject>()); 1.306 + return; 1.307 + } 1.308 + 1.309 + JS_ASSERT(isNonEvalFunctionFrame()); 1.310 + 1.311 + if (fun()->isHeavyweight()) 1.312 + JS_ASSERT_IF(hasCallObj(), 1.313 + scopeChain()->as<CallObject>().callee().nonLazyScript() == script); 1.314 + else 1.315 + AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain()); 1.316 + 1.317 + if (MOZ_UNLIKELY(cx->compartment()->debugMode())) 1.318 + DebugScopes::onPopCall(this, cx); 1.319 + 1.320 + if (isConstructing() && thisValue().isObject() && returnValue().isPrimitive()) 1.321 + setReturnValue(ObjectValue(constructorThis())); 1.322 +} 1.323 + 1.324 +bool 1.325 +InterpreterFrame::pushBlock(JSContext *cx, StaticBlockObject &block) 1.326 +{ 1.327 + JS_ASSERT (block.needsClone()); 1.328 + 1.329 + Rooted<StaticBlockObject *> blockHandle(cx, &block); 1.330 + ClonedBlockObject *clone = ClonedBlockObject::create(cx, blockHandle, this); 1.331 + if (!clone) 1.332 + return false; 1.333 + 1.334 + pushOnScopeChain(*clone); 1.335 + 1.336 + return true; 1.337 +} 1.338 + 1.339 +void 1.340 +InterpreterFrame::popBlock(JSContext *cx) 1.341 +{ 1.342 + JS_ASSERT(scopeChain_->is<ClonedBlockObject>()); 1.343 + popOffScopeChain(); 1.344 +} 1.345 + 1.346 +void 1.347 +InterpreterFrame::popWith(JSContext *cx) 1.348 +{ 1.349 + if (MOZ_UNLIKELY(cx->compartment()->debugMode())) 1.350 + DebugScopes::onPopWith(this); 1.351 + 1.352 + JS_ASSERT(scopeChain()->is<DynamicWithObject>()); 1.353 + popOffScopeChain(); 1.354 +} 1.355 + 1.356 +void 1.357 +InterpreterFrame::mark(JSTracer *trc) 1.358 +{ 1.359 + /* 1.360 + * Normally we would use MarkRoot here, except that generators also take 1.361 + * this path. However, generators use a special write barrier when the stack 1.362 + * frame is copied to the floating frame. Therefore, no barrier is needed. 1.363 + */ 1.364 + if (flags_ & HAS_SCOPECHAIN) 1.365 + gc::MarkObjectUnbarriered(trc, &scopeChain_, "scope chain"); 1.366 + if (flags_ & HAS_ARGS_OBJ) 1.367 + gc::MarkObjectUnbarriered(trc, &argsObj_, "arguments"); 1.368 + if (isFunctionFrame()) { 1.369 + gc::MarkObjectUnbarriered(trc, &exec.fun, "fun"); 1.370 + if (isEvalFrame()) 1.371 + gc::MarkScriptUnbarriered(trc, &u.evalScript, "eval script"); 1.372 + } else { 1.373 + gc::MarkScriptUnbarriered(trc, &exec.script, "script"); 1.374 + } 1.375 + if (IS_GC_MARKING_TRACER(trc)) 1.376 + script()->compartment()->zone()->active = true; 1.377 + gc::MarkValueUnbarriered(trc, returnValue().address(), "rval"); 1.378 +} 1.379 + 1.380 +void 1.381 +InterpreterFrame::markValues(JSTracer *trc, unsigned start, unsigned end) 1.382 +{ 1.383 + if (start < end) 1.384 + gc::MarkValueRootRange(trc, end - start, slots() + start, "vm_stack"); 1.385 +} 1.386 + 1.387 +void 1.388 +InterpreterFrame::markValues(JSTracer *trc, Value *sp, jsbytecode *pc) 1.389 +{ 1.390 + JS_ASSERT(sp >= slots()); 1.391 + 1.392 + NestedScopeObject *staticScope; 1.393 + 1.394 + staticScope = script()->getStaticScope(pc); 1.395 + while (staticScope && !staticScope->is<StaticBlockObject>()) 1.396 + staticScope = staticScope->enclosingNestedScope(); 1.397 + 1.398 + size_t nfixed = script()->nfixed(); 1.399 + size_t nlivefixed; 1.400 + 1.401 + if (staticScope) { 1.402 + StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>(); 1.403 + nlivefixed = blockObj.localOffset() + blockObj.numVariables(); 1.404 + } else { 1.405 + nlivefixed = script()->nfixedvars(); 1.406 + } 1.407 + 1.408 + if (nfixed == nlivefixed) { 1.409 + // All locals are live. 1.410 + markValues(trc, 0, sp - slots()); 1.411 + } else { 1.412 + // Mark operand stack. 1.413 + markValues(trc, nfixed, sp - slots()); 1.414 + 1.415 + // Clear dead locals. 1.416 + while (nfixed > nlivefixed) 1.417 + unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setUndefined(); 1.418 + 1.419 + // Mark live locals. 1.420 + markValues(trc, 0, nlivefixed); 1.421 + } 1.422 + 1.423 + if (hasArgs()) { 1.424 + // Mark callee, |this| and arguments. 1.425 + unsigned argc = Max(numActualArgs(), numFormalArgs()); 1.426 + gc::MarkValueRootRange(trc, argc + 2, argv_ - 2, "fp argv"); 1.427 + } else { 1.428 + // Mark callee and |this| 1.429 + gc::MarkValueRootRange(trc, 2, ((Value *)this) - 2, "stack callee and this"); 1.430 + } 1.431 +} 1.432 + 1.433 +static void 1.434 +MarkInterpreterActivation(JSTracer *trc, InterpreterActivation *act) 1.435 +{ 1.436 + for (InterpreterFrameIterator frames(act); !frames.done(); ++frames) { 1.437 + InterpreterFrame *fp = frames.frame(); 1.438 + fp->markValues(trc, frames.sp(), frames.pc()); 1.439 + fp->mark(trc); 1.440 + } 1.441 +} 1.442 + 1.443 +void 1.444 +js::MarkInterpreterActivations(JSRuntime *rt, JSTracer *trc) 1.445 +{ 1.446 + for (ActivationIterator iter(rt); !iter.done(); ++iter) { 1.447 + Activation *act = iter.activation(); 1.448 + if (act->isInterpreter()) 1.449 + MarkInterpreterActivation(trc, act->asInterpreter()); 1.450 + } 1.451 + 1.452 +} 1.453 + 1.454 +/*****************************************************************************/ 1.455 + 1.456 +// Unlike the other methods of this calss, this method is defined here so that 1.457 +// we don't have to #include jsautooplen.h in vm/Stack.h. 1.458 +void 1.459 +InterpreterRegs::setToEndOfScript() 1.460 +{ 1.461 + JSScript *script = fp()->script(); 1.462 + sp = fp()->base(); 1.463 + pc = script->codeEnd() - JSOP_RETRVAL_LENGTH; 1.464 + JS_ASSERT(*pc == JSOP_RETRVAL); 1.465 +} 1.466 + 1.467 +/*****************************************************************************/ 1.468 + 1.469 +InterpreterFrame * 1.470 +InterpreterStack::pushInvokeFrame(JSContext *cx, const CallArgs &args, InitialFrameFlags initial) 1.471 +{ 1.472 + LifoAlloc::Mark mark = allocator_.mark(); 1.473 + 1.474 + RootedFunction fun(cx, &args.callee().as<JSFunction>()); 1.475 + RootedScript script(cx, fun->nonLazyScript()); 1.476 + 1.477 + InterpreterFrame::Flags flags = ToFrameFlags(initial); 1.478 + Value *argv; 1.479 + InterpreterFrame *fp = getCallFrame(cx, args, script, &flags, &argv); 1.480 + if (!fp) 1.481 + return nullptr; 1.482 + 1.483 + fp->mark_ = mark; 1.484 + fp->initCallFrame(cx, nullptr, nullptr, nullptr, *fun, script, argv, args.length(), flags); 1.485 + return fp; 1.486 +} 1.487 + 1.488 +InterpreterFrame * 1.489 +InterpreterStack::pushExecuteFrame(JSContext *cx, HandleScript script, const Value &thisv, 1.490 + HandleObject scopeChain, ExecuteType type, 1.491 + AbstractFramePtr evalInFrame) 1.492 +{ 1.493 + LifoAlloc::Mark mark = allocator_.mark(); 1.494 + 1.495 + unsigned nvars = 2 /* callee, this */ + script->nslots(); 1.496 + uint8_t *buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvars * sizeof(Value)); 1.497 + if (!buffer) 1.498 + return nullptr; 1.499 + 1.500 + InterpreterFrame *fp = reinterpret_cast<InterpreterFrame *>(buffer + 2 * sizeof(Value)); 1.501 + fp->mark_ = mark; 1.502 + fp->initExecuteFrame(cx, script, evalInFrame, thisv, *scopeChain, type); 1.503 + fp->initVarsToUndefined(); 1.504 + 1.505 + return fp; 1.506 +} 1.507 + 1.508 +/*****************************************************************************/ 1.509 + 1.510 +/* MSVC PGO causes xpcshell startup crashes. */ 1.511 +#if defined(_MSC_VER) 1.512 +# pragma optimize("g", off) 1.513 +#endif 1.514 + 1.515 +void 1.516 +FrameIter::popActivation() 1.517 +{ 1.518 + ++data_.activations_; 1.519 + settleOnActivation(); 1.520 +} 1.521 + 1.522 +void 1.523 +FrameIter::popInterpreterFrame() 1.524 +{ 1.525 + JS_ASSERT(data_.state_ == INTERP); 1.526 + 1.527 + ++data_.interpFrames_; 1.528 + 1.529 + if (data_.interpFrames_.done()) 1.530 + popActivation(); 1.531 + else 1.532 + data_.pc_ = data_.interpFrames_.pc(); 1.533 +} 1.534 + 1.535 +void 1.536 +FrameIter::settleOnActivation() 1.537 +{ 1.538 + while (true) { 1.539 + if (data_.activations_.done()) { 1.540 + data_.state_ = DONE; 1.541 + return; 1.542 + } 1.543 + 1.544 + Activation *activation = data_.activations_.activation(); 1.545 + 1.546 + // If JS_SaveFrameChain was called, stop iterating here (unless 1.547 + // GO_THROUGH_SAVED is set). 1.548 + if (data_.savedOption_ == STOP_AT_SAVED && activation->hasSavedFrameChain()) { 1.549 + data_.state_ = DONE; 1.550 + return; 1.551 + } 1.552 + 1.553 + // Skip activations from another context if needed. 1.554 + JS_ASSERT(activation->cx()); 1.555 + JS_ASSERT(data_.cx_); 1.556 + if (data_.contextOption_ == CURRENT_CONTEXT && activation->cx() != data_.cx_) { 1.557 + ++data_.activations_; 1.558 + continue; 1.559 + } 1.560 + 1.561 + // If the caller supplied principals, only show activations which are subsumed (of the same 1.562 + // origin or of an origin accessible) by these principals. 1.563 + if (data_.principals_) { 1.564 + if (JSSubsumesOp subsumes = data_.cx_->runtime()->securityCallbacks->subsumes) { 1.565 + JS::AutoAssertNoGC nogc; 1.566 + if (!subsumes(data_.principals_, activation->compartment()->principals)) { 1.567 + ++data_.activations_; 1.568 + continue; 1.569 + } 1.570 + } 1.571 + } 1.572 + 1.573 +#ifdef JS_ION 1.574 + if (activation->isJit()) { 1.575 + data_.jitFrames_ = jit::JitFrameIterator(data_.activations_); 1.576 + 1.577 + // Stop at the first scripted frame. 1.578 + while (!data_.jitFrames_.isScripted() && !data_.jitFrames_.done()) 1.579 + ++data_.jitFrames_; 1.580 + 1.581 + // It's possible to have an JitActivation with no scripted frames, 1.582 + // for instance if we hit an over-recursion during bailout. 1.583 + if (data_.jitFrames_.done()) { 1.584 + ++data_.activations_; 1.585 + continue; 1.586 + } 1.587 + 1.588 + nextJitFrame(); 1.589 + data_.state_ = JIT; 1.590 + return; 1.591 + } 1.592 + 1.593 + if (activation->isAsmJS()) { 1.594 + data_.asmJSFrames_ = AsmJSFrameIterator(data_.activations_->asAsmJS()); 1.595 + 1.596 + if (data_.asmJSFrames_.done()) { 1.597 + ++data_.activations_; 1.598 + continue; 1.599 + } 1.600 + 1.601 + data_.state_ = ASMJS; 1.602 + return; 1.603 + } 1.604 + 1.605 + // ForkJoin activations don't contain iterable frames, so skip them. 1.606 + if (activation->isForkJoin()) { 1.607 + ++data_.activations_; 1.608 + continue; 1.609 + } 1.610 +#endif 1.611 + 1.612 + JS_ASSERT(activation->isInterpreter()); 1.613 + 1.614 + InterpreterActivation *interpAct = activation->asInterpreter(); 1.615 + data_.interpFrames_ = InterpreterFrameIterator(interpAct); 1.616 + 1.617 + // If we OSR'ed into JIT code, skip the interpreter frame so that 1.618 + // the same frame is not reported twice. 1.619 + if (data_.interpFrames_.frame()->runningInJit()) { 1.620 + ++data_.interpFrames_; 1.621 + if (data_.interpFrames_.done()) { 1.622 + ++data_.activations_; 1.623 + continue; 1.624 + } 1.625 + } 1.626 + 1.627 + JS_ASSERT(!data_.interpFrames_.frame()->runningInJit()); 1.628 + data_.pc_ = data_.interpFrames_.pc(); 1.629 + data_.state_ = INTERP; 1.630 + return; 1.631 + } 1.632 +} 1.633 + 1.634 +FrameIter::Data::Data(JSContext *cx, SavedOption savedOption, ContextOption contextOption, 1.635 + JSPrincipals *principals) 1.636 + : cx_(cx), 1.637 + savedOption_(savedOption), 1.638 + contextOption_(contextOption), 1.639 + principals_(principals), 1.640 + pc_(nullptr), 1.641 + interpFrames_(nullptr), 1.642 + activations_(cx->runtime()) 1.643 +#ifdef JS_ION 1.644 + , jitFrames_((uint8_t *)nullptr, SequentialExecution) 1.645 + , ionInlineFrameNo_(0) 1.646 + , asmJSFrames_(nullptr) 1.647 +#endif 1.648 +{ 1.649 +} 1.650 + 1.651 +FrameIter::Data::Data(const FrameIter::Data &other) 1.652 + : cx_(other.cx_), 1.653 + savedOption_(other.savedOption_), 1.654 + contextOption_(other.contextOption_), 1.655 + principals_(other.principals_), 1.656 + state_(other.state_), 1.657 + pc_(other.pc_), 1.658 + interpFrames_(other.interpFrames_), 1.659 + activations_(other.activations_) 1.660 +#ifdef JS_ION 1.661 + , jitFrames_(other.jitFrames_) 1.662 + , ionInlineFrameNo_(other.ionInlineFrameNo_) 1.663 + , asmJSFrames_(other.asmJSFrames_) 1.664 +#endif 1.665 +{ 1.666 +} 1.667 + 1.668 +FrameIter::FrameIter(JSContext *cx, SavedOption savedOption) 1.669 + : data_(cx, savedOption, CURRENT_CONTEXT, nullptr) 1.670 +#ifdef JS_ION 1.671 + , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr) 1.672 +#endif 1.673 +{ 1.674 + // settleOnActivation can only GC if principals are given. 1.675 + JS::AutoAssertNoGC nogc; 1.676 + settleOnActivation(); 1.677 +} 1.678 + 1.679 +FrameIter::FrameIter(JSContext *cx, ContextOption contextOption, 1.680 + SavedOption savedOption, JSPrincipals *principals) 1.681 + : data_(cx, savedOption, contextOption, principals) 1.682 +#ifdef JS_ION 1.683 + , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr) 1.684 +#endif 1.685 +{ 1.686 + settleOnActivation(); 1.687 +} 1.688 + 1.689 +FrameIter::FrameIter(const FrameIter &other) 1.690 + : data_(other.data_) 1.691 +#ifdef JS_ION 1.692 + , ionInlineFrames_(other.data_.cx_, 1.693 + data_.jitFrames_.isIonJS() ? &other.ionInlineFrames_ : nullptr) 1.694 +#endif 1.695 +{ 1.696 +} 1.697 + 1.698 +FrameIter::FrameIter(const Data &data) 1.699 + : data_(data) 1.700 +#ifdef JS_ION 1.701 + , ionInlineFrames_(data.cx_, data_.jitFrames_.isIonJS() ? &data_.jitFrames_ : nullptr) 1.702 +#endif 1.703 +{ 1.704 + JS_ASSERT(data.cx_); 1.705 + 1.706 +#ifdef JS_ION 1.707 + if (data_.jitFrames_.isIonJS()) { 1.708 + while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_) 1.709 + ++ionInlineFrames_; 1.710 + } 1.711 +#endif 1.712 +} 1.713 + 1.714 +#ifdef JS_ION 1.715 +void 1.716 +FrameIter::nextJitFrame() 1.717 +{ 1.718 + if (data_.jitFrames_.isIonJS()) { 1.719 + ionInlineFrames_.resetOn(&data_.jitFrames_); 1.720 + data_.pc_ = ionInlineFrames_.pc(); 1.721 + } else { 1.722 + JS_ASSERT(data_.jitFrames_.isBaselineJS()); 1.723 + data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_); 1.724 + } 1.725 +} 1.726 + 1.727 +void 1.728 +FrameIter::popJitFrame() 1.729 +{ 1.730 + JS_ASSERT(data_.state_ == JIT); 1.731 + 1.732 + if (data_.jitFrames_.isIonJS() && ionInlineFrames_.more()) { 1.733 + ++ionInlineFrames_; 1.734 + data_.pc_ = ionInlineFrames_.pc(); 1.735 + return; 1.736 + } 1.737 + 1.738 + ++data_.jitFrames_; 1.739 + while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted()) 1.740 + ++data_.jitFrames_; 1.741 + 1.742 + if (!data_.jitFrames_.done()) { 1.743 + nextJitFrame(); 1.744 + return; 1.745 + } 1.746 + 1.747 + popActivation(); 1.748 +} 1.749 + 1.750 +void 1.751 +FrameIter::popAsmJSFrame() 1.752 +{ 1.753 + JS_ASSERT(data_.state_ == ASMJS); 1.754 + 1.755 + ++data_.asmJSFrames_; 1.756 + if (data_.asmJSFrames_.done()) 1.757 + popActivation(); 1.758 +} 1.759 +#endif 1.760 + 1.761 +FrameIter & 1.762 +FrameIter::operator++() 1.763 +{ 1.764 + switch (data_.state_) { 1.765 + case DONE: 1.766 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.767 + case INTERP: 1.768 + if (interpFrame()->isDebuggerFrame() && interpFrame()->evalInFramePrev()) { 1.769 + AbstractFramePtr eifPrev = interpFrame()->evalInFramePrev(); 1.770 + MOZ_ASSERT(!eifPrev.isRematerializedFrame()); 1.771 + 1.772 + // Eval-in-frame can cross contexts and works across saved frame 1.773 + // chains. 1.774 + ContextOption prevContextOption = data_.contextOption_; 1.775 + SavedOption prevSavedOption = data_.savedOption_; 1.776 + data_.contextOption_ = ALL_CONTEXTS; 1.777 + data_.savedOption_ = GO_THROUGH_SAVED; 1.778 + 1.779 + popInterpreterFrame(); 1.780 + 1.781 + while (isIon() || abstractFramePtr() != eifPrev) { 1.782 + if (data_.state_ == JIT) { 1.783 +#ifdef JS_ION 1.784 + popJitFrame(); 1.785 +#else 1.786 + MOZ_ASSUME_UNREACHABLE("Invalid state"); 1.787 +#endif 1.788 + } else { 1.789 + popInterpreterFrame(); 1.790 + } 1.791 + } 1.792 + 1.793 + data_.contextOption_ = prevContextOption; 1.794 + data_.savedOption_ = prevSavedOption; 1.795 + data_.cx_ = data_.activations_->cx(); 1.796 + break; 1.797 + } 1.798 + popInterpreterFrame(); 1.799 + break; 1.800 +#ifdef JS_ION 1.801 + case JIT: 1.802 + popJitFrame(); 1.803 + break; 1.804 + case ASMJS: 1.805 + popAsmJSFrame(); 1.806 + break; 1.807 +#else 1.808 + default: 1.809 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.810 +#endif 1.811 + } 1.812 + return *this; 1.813 +} 1.814 + 1.815 +FrameIter::Data * 1.816 +FrameIter::copyData() const 1.817 +{ 1.818 + Data *data = data_.cx_->new_<Data>(data_); 1.819 +#ifdef JS_ION 1.820 + JS_ASSERT(data_.state_ != ASMJS); 1.821 + if (data && data_.jitFrames_.isIonJS()) 1.822 + data->ionInlineFrameNo_ = ionInlineFrames_.frameNo(); 1.823 +#endif 1.824 + return data; 1.825 +} 1.826 + 1.827 +AbstractFramePtr 1.828 +FrameIter::copyDataAsAbstractFramePtr() const 1.829 +{ 1.830 + AbstractFramePtr frame; 1.831 + if (Data *data = copyData()) 1.832 + frame.ptr_ = uintptr_t(data); 1.833 + return frame; 1.834 +} 1.835 + 1.836 +JSCompartment * 1.837 +FrameIter::compartment() const 1.838 +{ 1.839 + switch (data_.state_) { 1.840 + case DONE: 1.841 + break; 1.842 + case INTERP: 1.843 + case JIT: 1.844 + case ASMJS: 1.845 + return data_.activations_->compartment(); 1.846 + } 1.847 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.848 +} 1.849 + 1.850 +bool 1.851 +FrameIter::isFunctionFrame() const 1.852 +{ 1.853 + switch (data_.state_) { 1.854 + case DONE: 1.855 + break; 1.856 + case INTERP: 1.857 + return interpFrame()->isFunctionFrame(); 1.858 + case JIT: 1.859 +#ifdef JS_ION 1.860 + JS_ASSERT(data_.jitFrames_.isScripted()); 1.861 + if (data_.jitFrames_.isBaselineJS()) 1.862 + return data_.jitFrames_.isFunctionFrame(); 1.863 + return ionInlineFrames_.isFunctionFrame(); 1.864 +#else 1.865 + break; 1.866 +#endif 1.867 + case ASMJS: 1.868 + return true; 1.869 + } 1.870 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.871 +} 1.872 + 1.873 +bool 1.874 +FrameIter::isGlobalFrame() const 1.875 +{ 1.876 + switch (data_.state_) { 1.877 + case DONE: 1.878 + break; 1.879 + case INTERP: 1.880 + return interpFrame()->isGlobalFrame(); 1.881 + case JIT: 1.882 +#ifdef JS_ION 1.883 + if (data_.jitFrames_.isBaselineJS()) 1.884 + return data_.jitFrames_.baselineFrame()->isGlobalFrame(); 1.885 + JS_ASSERT(!script()->isForEval()); 1.886 + return !script()->functionNonDelazifying(); 1.887 +#else 1.888 + break; 1.889 +#endif 1.890 + case ASMJS: 1.891 + return false; 1.892 + } 1.893 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.894 +} 1.895 + 1.896 +bool 1.897 +FrameIter::isEvalFrame() const 1.898 +{ 1.899 + switch (data_.state_) { 1.900 + case DONE: 1.901 + break; 1.902 + case INTERP: 1.903 + return interpFrame()->isEvalFrame(); 1.904 + case JIT: 1.905 +#ifdef JS_ION 1.906 + if (data_.jitFrames_.isBaselineJS()) 1.907 + return data_.jitFrames_.baselineFrame()->isEvalFrame(); 1.908 + JS_ASSERT(!script()->isForEval()); 1.909 + return false; 1.910 +#else 1.911 + break; 1.912 +#endif 1.913 + case ASMJS: 1.914 + return false; 1.915 + } 1.916 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.917 +} 1.918 + 1.919 +bool 1.920 +FrameIter::isNonEvalFunctionFrame() const 1.921 +{ 1.922 + JS_ASSERT(!done()); 1.923 + switch (data_.state_) { 1.924 + case DONE: 1.925 + break; 1.926 + case INTERP: 1.927 + return interpFrame()->isNonEvalFunctionFrame(); 1.928 + case JIT: 1.929 + return !isEvalFrame() && isFunctionFrame(); 1.930 + case ASMJS: 1.931 + return true; 1.932 + } 1.933 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.934 +} 1.935 + 1.936 +bool 1.937 +FrameIter::isGeneratorFrame() const 1.938 +{ 1.939 + switch (data_.state_) { 1.940 + case DONE: 1.941 + break; 1.942 + case INTERP: 1.943 + return interpFrame()->isGeneratorFrame(); 1.944 + case JIT: 1.945 + return false; 1.946 + case ASMJS: 1.947 + return false; 1.948 + } 1.949 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.950 +} 1.951 + 1.952 +JSAtom * 1.953 +FrameIter::functionDisplayAtom() const 1.954 +{ 1.955 + JS_ASSERT(isNonEvalFunctionFrame()); 1.956 + 1.957 + switch (data_.state_) { 1.958 + case DONE: 1.959 + break; 1.960 + case INTERP: 1.961 + case JIT: 1.962 + return callee()->displayAtom(); 1.963 + case ASMJS: { 1.964 +#ifdef JS_ION 1.965 + return data_.asmJSFrames_.functionDisplayAtom(); 1.966 +#else 1.967 + break; 1.968 +#endif 1.969 + } 1.970 + } 1.971 + 1.972 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.973 +} 1.974 + 1.975 +ScriptSource * 1.976 +FrameIter::scriptSource() const 1.977 +{ 1.978 + switch (data_.state_) { 1.979 + case DONE: 1.980 + break; 1.981 + case INTERP: 1.982 + case JIT: 1.983 + return script()->scriptSource(); 1.984 + case ASMJS: 1.985 +#ifdef JS_ION 1.986 + return data_.activations_->asAsmJS()->module().scriptSource(); 1.987 +#else 1.988 + break; 1.989 +#endif 1.990 + } 1.991 + 1.992 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.993 +} 1.994 + 1.995 +const char * 1.996 +FrameIter::scriptFilename() const 1.997 +{ 1.998 + switch (data_.state_) { 1.999 + case DONE: 1.1000 + break; 1.1001 + case INTERP: 1.1002 + case JIT: 1.1003 + return script()->filename(); 1.1004 + case ASMJS: 1.1005 +#ifdef JS_ION 1.1006 + return data_.activations_->asAsmJS()->module().scriptSource()->filename(); 1.1007 +#else 1.1008 + break; 1.1009 +#endif 1.1010 + } 1.1011 + 1.1012 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1013 +} 1.1014 + 1.1015 +unsigned 1.1016 +FrameIter::computeLine(uint32_t *column) const 1.1017 +{ 1.1018 + switch (data_.state_) { 1.1019 + case DONE: 1.1020 + break; 1.1021 + case INTERP: 1.1022 + case JIT: 1.1023 + return PCToLineNumber(script(), pc(), column); 1.1024 + case ASMJS: 1.1025 +#ifdef JS_ION 1.1026 + return data_.asmJSFrames_.computeLine(column); 1.1027 +#else 1.1028 + break; 1.1029 +#endif 1.1030 + } 1.1031 + 1.1032 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1033 +} 1.1034 + 1.1035 +JSPrincipals * 1.1036 +FrameIter::originPrincipals() const 1.1037 +{ 1.1038 + switch (data_.state_) { 1.1039 + case DONE: 1.1040 + break; 1.1041 + case INTERP: 1.1042 + case JIT: 1.1043 + return script()->originPrincipals(); 1.1044 + case ASMJS: { 1.1045 +#ifdef JS_ION 1.1046 + return data_.activations_->asAsmJS()->module().scriptSource()->originPrincipals(); 1.1047 +#else 1.1048 + break; 1.1049 +#endif 1.1050 + } 1.1051 + } 1.1052 + 1.1053 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1054 +} 1.1055 + 1.1056 +bool 1.1057 +FrameIter::isConstructing() const 1.1058 +{ 1.1059 + switch (data_.state_) { 1.1060 + case DONE: 1.1061 + case ASMJS: 1.1062 + break; 1.1063 + case JIT: 1.1064 +#ifdef JS_ION 1.1065 + if (data_.jitFrames_.isIonJS()) 1.1066 + return ionInlineFrames_.isConstructing(); 1.1067 + JS_ASSERT(data_.jitFrames_.isBaselineJS()); 1.1068 + return data_.jitFrames_.isConstructing(); 1.1069 +#else 1.1070 + break; 1.1071 +#endif 1.1072 + case INTERP: 1.1073 + return interpFrame()->isConstructing(); 1.1074 + } 1.1075 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1076 +} 1.1077 + 1.1078 +bool 1.1079 +FrameIter::ensureHasRematerializedFrame() 1.1080 +{ 1.1081 +#ifdef JS_ION 1.1082 + MOZ_ASSERT(isIon()); 1.1083 + return !!activation()->asJit()->getRematerializedFrame(activation()->cx(), data_.jitFrames_); 1.1084 +#else 1.1085 + return true; 1.1086 +#endif 1.1087 +} 1.1088 + 1.1089 +bool 1.1090 +FrameIter::hasUsableAbstractFramePtr() const 1.1091 +{ 1.1092 + switch (data_.state_) { 1.1093 + case DONE: 1.1094 + case ASMJS: 1.1095 + return false; 1.1096 + case JIT: 1.1097 +#ifdef JS_ION 1.1098 + if (data_.jitFrames_.isBaselineJS()) 1.1099 + return true; 1.1100 + 1.1101 + MOZ_ASSERT(data_.jitFrames_.isIonJS()); 1.1102 + return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(), 1.1103 + ionInlineFrames_.frameNo()); 1.1104 +#endif 1.1105 + break; 1.1106 + case INTERP: 1.1107 + return true; 1.1108 + } 1.1109 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1110 +} 1.1111 + 1.1112 +AbstractFramePtr 1.1113 +FrameIter::abstractFramePtr() const 1.1114 +{ 1.1115 + MOZ_ASSERT(hasUsableAbstractFramePtr()); 1.1116 + switch (data_.state_) { 1.1117 + case DONE: 1.1118 + case ASMJS: 1.1119 + break; 1.1120 + case JIT: { 1.1121 +#ifdef JS_ION 1.1122 + if (data_.jitFrames_.isBaselineJS()) 1.1123 + return data_.jitFrames_.baselineFrame(); 1.1124 + 1.1125 + MOZ_ASSERT(data_.jitFrames_.isIonJS()); 1.1126 + return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(), 1.1127 + ionInlineFrames_.frameNo()); 1.1128 +#endif 1.1129 + break; 1.1130 + } 1.1131 + case INTERP: 1.1132 + JS_ASSERT(interpFrame()); 1.1133 + return AbstractFramePtr(interpFrame()); 1.1134 + } 1.1135 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1136 +} 1.1137 + 1.1138 +void 1.1139 +FrameIter::updatePcQuadratic() 1.1140 +{ 1.1141 + switch (data_.state_) { 1.1142 + case DONE: 1.1143 + case ASMJS: 1.1144 + break; 1.1145 + case INTERP: { 1.1146 + InterpreterFrame *frame = interpFrame(); 1.1147 + InterpreterActivation *activation = data_.activations_->asInterpreter(); 1.1148 + 1.1149 + // Look for the current frame. 1.1150 + data_.interpFrames_ = InterpreterFrameIterator(activation); 1.1151 + while (data_.interpFrames_.frame() != frame) 1.1152 + ++data_.interpFrames_; 1.1153 + 1.1154 + // Update the pc. 1.1155 + JS_ASSERT(data_.interpFrames_.frame() == frame); 1.1156 + data_.pc_ = data_.interpFrames_.pc(); 1.1157 + return; 1.1158 + } 1.1159 + case JIT: 1.1160 +#ifdef JS_ION 1.1161 + if (data_.jitFrames_.isBaselineJS()) { 1.1162 + jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame(); 1.1163 + jit::JitActivation *activation = data_.activations_->asJit(); 1.1164 + 1.1165 + // ActivationIterator::ionTop_ may be invalid, so create a new 1.1166 + // activation iterator. 1.1167 + data_.activations_ = ActivationIterator(data_.cx_->runtime()); 1.1168 + while (data_.activations_.activation() != activation) 1.1169 + ++data_.activations_; 1.1170 + 1.1171 + // Look for the current frame. 1.1172 + data_.jitFrames_ = jit::JitFrameIterator(data_.activations_); 1.1173 + while (!data_.jitFrames_.isBaselineJS() || data_.jitFrames_.baselineFrame() != frame) 1.1174 + ++data_.jitFrames_; 1.1175 + 1.1176 + // Update the pc. 1.1177 + JS_ASSERT(data_.jitFrames_.baselineFrame() == frame); 1.1178 + data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_); 1.1179 + return; 1.1180 + } 1.1181 +#endif 1.1182 + break; 1.1183 + } 1.1184 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1185 +} 1.1186 + 1.1187 +JSFunction * 1.1188 +FrameIter::callee() const 1.1189 +{ 1.1190 + switch (data_.state_) { 1.1191 + case DONE: 1.1192 + case ASMJS: 1.1193 + break; 1.1194 + case INTERP: 1.1195 + JS_ASSERT(isFunctionFrame()); 1.1196 + return &interpFrame()->callee(); 1.1197 + case JIT: 1.1198 +#ifdef JS_ION 1.1199 + if (data_.jitFrames_.isBaselineJS()) 1.1200 + return data_.jitFrames_.callee(); 1.1201 + JS_ASSERT(data_.jitFrames_.isIonJS()); 1.1202 + return ionInlineFrames_.callee(); 1.1203 +#else 1.1204 + break; 1.1205 +#endif 1.1206 + } 1.1207 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1208 +} 1.1209 + 1.1210 +Value 1.1211 +FrameIter::calleev() const 1.1212 +{ 1.1213 + switch (data_.state_) { 1.1214 + case DONE: 1.1215 + case ASMJS: 1.1216 + break; 1.1217 + case INTERP: 1.1218 + JS_ASSERT(isFunctionFrame()); 1.1219 + return interpFrame()->calleev(); 1.1220 + case JIT: 1.1221 +#ifdef JS_ION 1.1222 + return ObjectValue(*callee()); 1.1223 +#else 1.1224 + break; 1.1225 +#endif 1.1226 + } 1.1227 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1228 +} 1.1229 + 1.1230 +unsigned 1.1231 +FrameIter::numActualArgs() const 1.1232 +{ 1.1233 + switch (data_.state_) { 1.1234 + case DONE: 1.1235 + case ASMJS: 1.1236 + break; 1.1237 + case INTERP: 1.1238 + JS_ASSERT(isFunctionFrame()); 1.1239 + return interpFrame()->numActualArgs(); 1.1240 + case JIT: 1.1241 +#ifdef JS_ION 1.1242 + if (data_.jitFrames_.isIonJS()) 1.1243 + return ionInlineFrames_.numActualArgs(); 1.1244 + 1.1245 + JS_ASSERT(data_.jitFrames_.isBaselineJS()); 1.1246 + return data_.jitFrames_.numActualArgs(); 1.1247 +#else 1.1248 + break; 1.1249 +#endif 1.1250 + } 1.1251 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1252 +} 1.1253 + 1.1254 +unsigned 1.1255 +FrameIter::numFormalArgs() const 1.1256 +{ 1.1257 + return script()->functionNonDelazifying()->nargs(); 1.1258 +} 1.1259 + 1.1260 +Value 1.1261 +FrameIter::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const 1.1262 +{ 1.1263 + return abstractFramePtr().unaliasedActual(i, checkAliasing); 1.1264 +} 1.1265 + 1.1266 +JSObject * 1.1267 +FrameIter::scopeChain() const 1.1268 +{ 1.1269 + switch (data_.state_) { 1.1270 + case DONE: 1.1271 + case ASMJS: 1.1272 + break; 1.1273 + case JIT: 1.1274 +#ifdef JS_ION 1.1275 + if (data_.jitFrames_.isIonJS()) 1.1276 + return ionInlineFrames_.scopeChain(); 1.1277 + return data_.jitFrames_.baselineFrame()->scopeChain(); 1.1278 +#else 1.1279 + break; 1.1280 +#endif 1.1281 + case INTERP: 1.1282 + return interpFrame()->scopeChain(); 1.1283 + } 1.1284 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1285 +} 1.1286 + 1.1287 +CallObject & 1.1288 +FrameIter::callObj() const 1.1289 +{ 1.1290 + JS_ASSERT(callee()->isHeavyweight()); 1.1291 + 1.1292 + JSObject *pobj = scopeChain(); 1.1293 + while (!pobj->is<CallObject>()) 1.1294 + pobj = pobj->enclosingScope(); 1.1295 + return pobj->as<CallObject>(); 1.1296 +} 1.1297 + 1.1298 +bool 1.1299 +FrameIter::hasArgsObj() const 1.1300 +{ 1.1301 + return abstractFramePtr().hasArgsObj(); 1.1302 +} 1.1303 + 1.1304 +ArgumentsObject & 1.1305 +FrameIter::argsObj() const 1.1306 +{ 1.1307 + MOZ_ASSERT(hasArgsObj()); 1.1308 + return abstractFramePtr().argsObj(); 1.1309 +} 1.1310 + 1.1311 +bool 1.1312 +FrameIter::computeThis(JSContext *cx) const 1.1313 +{ 1.1314 + JS_ASSERT(!done() && !isAsmJS()); 1.1315 + assertSameCompartment(cx, scopeChain()); 1.1316 + return ComputeThis(cx, abstractFramePtr()); 1.1317 +} 1.1318 + 1.1319 +Value 1.1320 +FrameIter::computedThisValue() const 1.1321 +{ 1.1322 + return abstractFramePtr().thisValue(); 1.1323 +} 1.1324 + 1.1325 +Value 1.1326 +FrameIter::thisv() const 1.1327 +{ 1.1328 + switch (data_.state_) { 1.1329 + case DONE: 1.1330 + case ASMJS: 1.1331 + break; 1.1332 + case JIT: 1.1333 +#ifdef JS_ION 1.1334 + if (data_.jitFrames_.isIonJS()) 1.1335 + return ionInlineFrames_.thisValue(); 1.1336 + return data_.jitFrames_.baselineFrame()->thisValue(); 1.1337 +#else 1.1338 + break; 1.1339 +#endif 1.1340 + case INTERP: 1.1341 + return interpFrame()->thisValue(); 1.1342 + } 1.1343 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1344 +} 1.1345 + 1.1346 +Value 1.1347 +FrameIter::returnValue() const 1.1348 +{ 1.1349 + switch (data_.state_) { 1.1350 + case DONE: 1.1351 + case ASMJS: 1.1352 + break; 1.1353 + case JIT: 1.1354 +#ifdef JS_ION 1.1355 + if (data_.jitFrames_.isBaselineJS()) 1.1356 + return data_.jitFrames_.baselineFrame()->returnValue(); 1.1357 +#endif 1.1358 + break; 1.1359 + case INTERP: 1.1360 + return interpFrame()->returnValue(); 1.1361 + } 1.1362 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1363 +} 1.1364 + 1.1365 +void 1.1366 +FrameIter::setReturnValue(const Value &v) 1.1367 +{ 1.1368 + switch (data_.state_) { 1.1369 + case DONE: 1.1370 + case ASMJS: 1.1371 + break; 1.1372 + case JIT: 1.1373 +#ifdef JS_ION 1.1374 + if (data_.jitFrames_.isBaselineJS()) { 1.1375 + data_.jitFrames_.baselineFrame()->setReturnValue(v); 1.1376 + return; 1.1377 + } 1.1378 +#endif 1.1379 + break; 1.1380 + case INTERP: 1.1381 + interpFrame()->setReturnValue(v); 1.1382 + return; 1.1383 + } 1.1384 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1385 +} 1.1386 + 1.1387 +size_t 1.1388 +FrameIter::numFrameSlots() const 1.1389 +{ 1.1390 + switch (data_.state_) { 1.1391 + case DONE: 1.1392 + case ASMJS: 1.1393 + break; 1.1394 + case JIT: { 1.1395 +#ifdef JS_ION 1.1396 + if (data_.jitFrames_.isIonJS()) { 1.1397 + return ionInlineFrames_.snapshotIterator().numAllocations() - 1.1398 + ionInlineFrames_.script()->nfixed(); 1.1399 + } 1.1400 + jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame(); 1.1401 + return frame->numValueSlots() - data_.jitFrames_.script()->nfixed(); 1.1402 +#else 1.1403 + break; 1.1404 +#endif 1.1405 + } 1.1406 + case INTERP: 1.1407 + JS_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base()); 1.1408 + return data_.interpFrames_.sp() - interpFrame()->base(); 1.1409 + } 1.1410 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1411 +} 1.1412 + 1.1413 +Value 1.1414 +FrameIter::frameSlotValue(size_t index) const 1.1415 +{ 1.1416 + switch (data_.state_) { 1.1417 + case DONE: 1.1418 + case ASMJS: 1.1419 + break; 1.1420 + case JIT: 1.1421 +#ifdef JS_ION 1.1422 + if (data_.jitFrames_.isIonJS()) { 1.1423 + jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator()); 1.1424 + index += ionInlineFrames_.script()->nfixed(); 1.1425 + return si.maybeReadAllocByIndex(index); 1.1426 + } 1.1427 + 1.1428 + index += data_.jitFrames_.script()->nfixed(); 1.1429 + return *data_.jitFrames_.baselineFrame()->valueSlot(index); 1.1430 +#else 1.1431 + break; 1.1432 +#endif 1.1433 + case INTERP: 1.1434 + return interpFrame()->base()[index]; 1.1435 + } 1.1436 + MOZ_ASSUME_UNREACHABLE("Unexpected state"); 1.1437 +} 1.1438 + 1.1439 +#if defined(_MSC_VER) 1.1440 +# pragma optimize("", on) 1.1441 +#endif 1.1442 + 1.1443 +#ifdef DEBUG 1.1444 +bool 1.1445 +js::SelfHostedFramesVisible() 1.1446 +{ 1.1447 + static bool checked = false; 1.1448 + static bool visible = false; 1.1449 + if (!checked) { 1.1450 + checked = true; 1.1451 + char *env = getenv("MOZ_SHOW_ALL_JS_FRAMES"); 1.1452 + visible = !!env; 1.1453 + } 1.1454 + return visible; 1.1455 +} 1.1456 +#endif 1.1457 + 1.1458 +void 1.1459 +NonBuiltinFrameIter::settle() 1.1460 +{ 1.1461 + if (!SelfHostedFramesVisible()) { 1.1462 + while (!done() && hasScript() && script()->selfHosted()) 1.1463 + FrameIter::operator++(); 1.1464 + } 1.1465 +} 1.1466 + 1.1467 +void 1.1468 +NonBuiltinScriptFrameIter::settle() 1.1469 +{ 1.1470 + if (!SelfHostedFramesVisible()) { 1.1471 + while (!done() && script()->selfHosted()) 1.1472 + ScriptFrameIter::operator++(); 1.1473 + } 1.1474 +} 1.1475 + 1.1476 +/*****************************************************************************/ 1.1477 + 1.1478 +JSObject * 1.1479 +AbstractFramePtr::evalPrevScopeChain(JSContext *cx) const 1.1480 +{ 1.1481 + // Eval frames are not compiled by Ion, though their caller might be. 1.1482 + AllFramesIter iter(cx); 1.1483 + while (iter.isIon() || iter.abstractFramePtr() != *this) 1.1484 + ++iter; 1.1485 + ++iter; 1.1486 + return iter.scopeChain(); 1.1487 +} 1.1488 + 1.1489 +bool 1.1490 +AbstractFramePtr::hasPushedSPSFrame() const 1.1491 +{ 1.1492 + if (isInterpreterFrame()) 1.1493 + return asInterpreterFrame()->hasPushedSPSFrame(); 1.1494 +#ifdef JS_ION 1.1495 + return asBaselineFrame()->hasPushedSPSFrame(); 1.1496 +#else 1.1497 + MOZ_ASSUME_UNREACHABLE("Invalid frame"); 1.1498 +#endif 1.1499 +} 1.1500 + 1.1501 +#ifdef DEBUG 1.1502 +void 1.1503 +js::CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, uint32_t i) 1.1504 +{ 1.1505 + if (!checkAliasing) 1.1506 + return; 1.1507 + 1.1508 + JS_ASSERT(i < script->nfixed()); 1.1509 + if (i < script->bindings.numVars()) { 1.1510 + JS_ASSERT(!script->varIsAliased(i)); 1.1511 + } else { 1.1512 + // FIXME: The callers of this function do not easily have the PC of the 1.1513 + // current frame, and so they do not know the block scope. 1.1514 + } 1.1515 +} 1.1516 +#endif 1.1517 + 1.1518 +jit::JitActivation::JitActivation(JSContext *cx, bool firstFrameIsConstructing, bool active) 1.1519 + : Activation(cx, Jit), 1.1520 + firstFrameIsConstructing_(firstFrameIsConstructing), 1.1521 + active_(active) 1.1522 +#ifdef JS_ION 1.1523 + , rematerializedFrames_(cx) 1.1524 +#endif 1.1525 +{ 1.1526 + if (active) { 1.1527 + prevIonTop_ = cx->mainThread().ionTop; 1.1528 + prevJitJSContext_ = cx->mainThread().jitJSContext; 1.1529 + cx->mainThread().jitJSContext = cx; 1.1530 + } else { 1.1531 + prevIonTop_ = nullptr; 1.1532 + prevJitJSContext_ = nullptr; 1.1533 + } 1.1534 +} 1.1535 + 1.1536 +jit::JitActivation::~JitActivation() 1.1537 +{ 1.1538 + if (active_) { 1.1539 + cx_->mainThread().ionTop = prevIonTop_; 1.1540 + cx_->mainThread().jitJSContext = prevJitJSContext_; 1.1541 + } 1.1542 + 1.1543 +#ifdef JS_ION 1.1544 + clearRematerializedFrames(); 1.1545 +#endif 1.1546 +} 1.1547 + 1.1548 +// setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so 1.1549 +// changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable 1.1550 +// and disable activation instruction sequences. 1.1551 +void 1.1552 +jit::JitActivation::setActive(JSContext *cx, bool active) 1.1553 +{ 1.1554 + // Only allowed to deactivate/activate if activation is top. 1.1555 + // (Not tested and will probably fail in other situations.) 1.1556 + JS_ASSERT(cx->mainThread().activation_ == this); 1.1557 + JS_ASSERT(active != active_); 1.1558 + active_ = active; 1.1559 + 1.1560 + if (active) { 1.1561 + prevIonTop_ = cx->mainThread().ionTop; 1.1562 + prevJitJSContext_ = cx->mainThread().jitJSContext; 1.1563 + cx->mainThread().jitJSContext = cx; 1.1564 + } else { 1.1565 + cx->mainThread().ionTop = prevIonTop_; 1.1566 + cx->mainThread().jitJSContext = prevJitJSContext_; 1.1567 + } 1.1568 +} 1.1569 + 1.1570 +#ifdef JS_ION 1.1571 + 1.1572 +void 1.1573 +jit::JitActivation::freeRematerializedFramesInVector(RematerializedFrameVector &frames) 1.1574 +{ 1.1575 + for (size_t i = 0; i < frames.length(); i++) { 1.1576 + RematerializedFrame *f = frames[i]; 1.1577 + f->RematerializedFrame::~RematerializedFrame(); 1.1578 + js_free(f); 1.1579 + } 1.1580 + frames.clear(); 1.1581 +} 1.1582 + 1.1583 +void 1.1584 +jit::JitActivation::removeRematerializedFrame(uint8_t *top) 1.1585 +{ 1.1586 + if (!rematerializedFrames_.initialized()) 1.1587 + return; 1.1588 + 1.1589 + if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top)) { 1.1590 + freeRematerializedFramesInVector(p->value()); 1.1591 + rematerializedFrames_.remove(p); 1.1592 + } 1.1593 +} 1.1594 + 1.1595 +void 1.1596 +jit::JitActivation::clearRematerializedFrames() 1.1597 +{ 1.1598 + if (!rematerializedFrames_.initialized()) 1.1599 + return; 1.1600 + 1.1601 + for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) { 1.1602 + freeRematerializedFramesInVector(e.front().value()); 1.1603 + e.removeFront(); 1.1604 + } 1.1605 +} 1.1606 + 1.1607 +jit::RematerializedFrame * 1.1608 +jit::JitActivation::getRematerializedFrame(JSContext *cx, JitFrameIterator &iter, 1.1609 + size_t inlineDepth) 1.1610 +{ 1.1611 + MOZ_ASSERT(iter.activation() == this); 1.1612 + MOZ_ASSERT(iter.isIonJS()); 1.1613 + 1.1614 + if (!rematerializedFrames_.initialized() && !rematerializedFrames_.init()) 1.1615 + return nullptr; 1.1616 + 1.1617 + // The unit of rematerialization is an uninlined frame and its inlined 1.1618 + // frames. Since inlined frames do not exist outside of snapshots, it is 1.1619 + // impossible to synchronize their rematerialized copies to preserve 1.1620 + // identity. Therefore, we always rematerialize an uninlined frame and all 1.1621 + // its inlined frames at once. 1.1622 + 1.1623 + uint8_t *top = iter.fp(); 1.1624 + RematerializedFrameTable::AddPtr p = rematerializedFrames_.lookupForAdd(top); 1.1625 + if (!p) { 1.1626 + RematerializedFrameVector empty(cx); 1.1627 + if (!rematerializedFrames_.add(p, top, Move(empty))) 1.1628 + return nullptr; 1.1629 + 1.1630 + InlineFrameIterator inlineIter(cx, &iter); 1.1631 + if (!p->value().resize(inlineIter.frameCount())) 1.1632 + return nullptr; 1.1633 + 1.1634 + while (true) { 1.1635 + size_t frameNo = inlineIter.frameNo(); 1.1636 + p->value()[frameNo] = RematerializedFrame::New(cx, top, inlineIter); 1.1637 + if (!p->value()[frameNo]) 1.1638 + return nullptr; 1.1639 + 1.1640 + if (!inlineIter.more()) 1.1641 + break; 1.1642 + ++inlineIter; 1.1643 + } 1.1644 + } 1.1645 + 1.1646 + return p->value()[inlineDepth]; 1.1647 +} 1.1648 + 1.1649 +jit::RematerializedFrame * 1.1650 +jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth) 1.1651 +{ 1.1652 + if (!rematerializedFrames_.initialized()) 1.1653 + return nullptr; 1.1654 + if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top)) 1.1655 + return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr; 1.1656 + return nullptr; 1.1657 +} 1.1658 + 1.1659 +void 1.1660 +jit::JitActivation::markRematerializedFrames(JSTracer *trc) 1.1661 +{ 1.1662 + if (!rematerializedFrames_.initialized()) 1.1663 + return; 1.1664 + for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) { 1.1665 + RematerializedFrameVector &frames = e.front().value(); 1.1666 + for (size_t i = 0; i < frames.length(); i++) 1.1667 + frames[i]->mark(trc); 1.1668 + } 1.1669 +} 1.1670 + 1.1671 +#endif // JS_ION 1.1672 + 1.1673 +AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module) 1.1674 + : Activation(cx, AsmJS), 1.1675 + module_(module), 1.1676 + errorRejoinSP_(nullptr), 1.1677 + profiler_(nullptr), 1.1678 + resumePC_(nullptr), 1.1679 + exitSP_(nullptr) 1.1680 +{ 1.1681 + if (cx->runtime()->spsProfiler.enabled()) { 1.1682 + // Use a profiler string that matches jsMatch regex in 1.1683 + // browser/devtools/profiler/cleopatra/js/parserWorker.js. 1.1684 + // (For now use a single static string to avoid further slowing down 1.1685 + // calls into asm.js.) 1.1686 + profiler_ = &cx->runtime()->spsProfiler; 1.1687 + profiler_->enterNative("asm.js code :0", this); 1.1688 + } 1.1689 + 1.1690 + prevAsmJS_ = cx_->runtime()->mainThread.asmJSActivationStack_; 1.1691 + 1.1692 + JSRuntime::AutoLockForInterrupt lock(cx_->runtime()); 1.1693 + cx_->runtime()->mainThread.asmJSActivationStack_ = this; 1.1694 + 1.1695 + (void) errorRejoinSP_; // squelch GCC warning 1.1696 +} 1.1697 + 1.1698 +AsmJSActivation::~AsmJSActivation() 1.1699 +{ 1.1700 + if (profiler_) 1.1701 + profiler_->exitNative(); 1.1702 + 1.1703 + JS_ASSERT(cx_->runtime()->mainThread.asmJSActivationStack_ == this); 1.1704 + 1.1705 + JSRuntime::AutoLockForInterrupt lock(cx_->runtime()); 1.1706 + cx_->runtime()->mainThread.asmJSActivationStack_ = prevAsmJS_; 1.1707 +} 1.1708 + 1.1709 +InterpreterFrameIterator & 1.1710 +InterpreterFrameIterator::operator++() 1.1711 +{ 1.1712 + JS_ASSERT(!done()); 1.1713 + if (fp_ != activation_->entryFrame_) { 1.1714 + pc_ = fp_->prevpc(); 1.1715 + sp_ = fp_->prevsp(); 1.1716 + fp_ = fp_->prev(); 1.1717 + } else { 1.1718 + pc_ = nullptr; 1.1719 + sp_ = nullptr; 1.1720 + fp_ = nullptr; 1.1721 + } 1.1722 + return *this; 1.1723 +} 1.1724 + 1.1725 +ActivationIterator::ActivationIterator(JSRuntime *rt) 1.1726 + : jitTop_(rt->mainThread.ionTop), 1.1727 + activation_(rt->mainThread.activation_) 1.1728 +{ 1.1729 + settle(); 1.1730 +} 1.1731 + 1.1732 +ActivationIterator & 1.1733 +ActivationIterator::operator++() 1.1734 +{ 1.1735 + JS_ASSERT(activation_); 1.1736 + if (activation_->isJit() && activation_->asJit()->isActive()) 1.1737 + jitTop_ = activation_->asJit()->prevIonTop(); 1.1738 + activation_ = activation_->prev(); 1.1739 + settle(); 1.1740 + return *this; 1.1741 +} 1.1742 + 1.1743 +void 1.1744 +ActivationIterator::settle() 1.1745 +{ 1.1746 + // Stop at the next active activation. No need to update jitTop_, since 1.1747 + // we don't iterate over an active jit activation. 1.1748 + while (!done() && activation_->isJit() && !activation_->asJit()->isActive()) 1.1749 + activation_ = activation_->prev(); 1.1750 +}