js/src/vm/Stack.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "vm/Stack-inl.h"
michael@0 8
michael@0 9 #include "mozilla/PodOperations.h"
michael@0 10
michael@0 11 #include "jscntxt.h"
michael@0 12
michael@0 13 #include "gc/Marking.h"
michael@0 14 #ifdef JS_ION
michael@0 15 #include "jit/AsmJSModule.h"
michael@0 16 #include "jit/BaselineFrame.h"
michael@0 17 #include "jit/JitCompartment.h"
michael@0 18 #endif
michael@0 19 #include "js/GCAPI.h"
michael@0 20 #include "vm/Opcodes.h"
michael@0 21
michael@0 22 #include "jit/JitFrameIterator-inl.h"
michael@0 23 #include "vm/Interpreter-inl.h"
michael@0 24 #include "vm/Probes-inl.h"
michael@0 25 #include "vm/ScopeObject-inl.h"
michael@0 26
michael@0 27 using namespace js;
michael@0 28
michael@0 29 using mozilla::PodCopy;
michael@0 30
michael@0 31 /*****************************************************************************/
michael@0 32
michael@0 33 void
michael@0 34 InterpreterFrame::initExecuteFrame(JSContext *cx, JSScript *script, AbstractFramePtr evalInFramePrev,
michael@0 35 const Value &thisv, JSObject &scopeChain, ExecuteType type)
michael@0 36 {
michael@0 37 /*
michael@0 38 * See encoding of ExecuteType. When GLOBAL isn't set, we are executing a
michael@0 39 * script in the context of another frame and the frame type is determined
michael@0 40 * by the context.
michael@0 41 */
michael@0 42 flags_ = type | HAS_SCOPECHAIN;
michael@0 43
michael@0 44 JSObject *callee = nullptr;
michael@0 45 if (!(flags_ & (GLOBAL))) {
michael@0 46 if (evalInFramePrev) {
michael@0 47 JS_ASSERT(evalInFramePrev.isFunctionFrame() || evalInFramePrev.isGlobalFrame());
michael@0 48 if (evalInFramePrev.isFunctionFrame()) {
michael@0 49 callee = evalInFramePrev.callee();
michael@0 50 flags_ |= FUNCTION;
michael@0 51 } else {
michael@0 52 flags_ |= GLOBAL;
michael@0 53 }
michael@0 54 } else {
michael@0 55 FrameIter iter(cx);
michael@0 56 JS_ASSERT(iter.isFunctionFrame() || iter.isGlobalFrame());
michael@0 57 JS_ASSERT(!iter.isAsmJS());
michael@0 58 if (iter.isFunctionFrame()) {
michael@0 59 callee = iter.callee();
michael@0 60 flags_ |= FUNCTION;
michael@0 61 } else {
michael@0 62 flags_ |= GLOBAL;
michael@0 63 }
michael@0 64 }
michael@0 65 }
michael@0 66
michael@0 67 Value *dstvp = (Value *)this - 2;
michael@0 68 dstvp[1] = thisv;
michael@0 69
michael@0 70 if (isFunctionFrame()) {
michael@0 71 dstvp[0] = ObjectValue(*callee);
michael@0 72 exec.fun = &callee->as<JSFunction>();
michael@0 73 u.evalScript = script;
michael@0 74 } else {
michael@0 75 JS_ASSERT(isGlobalFrame());
michael@0 76 dstvp[0] = NullValue();
michael@0 77 exec.script = script;
michael@0 78 #ifdef DEBUG
michael@0 79 u.evalScript = (JSScript *)0xbad;
michael@0 80 #endif
michael@0 81 }
michael@0 82
michael@0 83 scopeChain_ = &scopeChain;
michael@0 84 prev_ = nullptr;
michael@0 85 prevpc_ = nullptr;
michael@0 86 prevsp_ = nullptr;
michael@0 87
michael@0 88 JS_ASSERT_IF(evalInFramePrev, isDebuggerFrame());
michael@0 89 evalInFramePrev_ = evalInFramePrev;
michael@0 90
michael@0 91 #ifdef DEBUG
michael@0 92 Debug_SetValueRangeToCrashOnTouch(&rval_, 1);
michael@0 93 hookData_ = (void *)0xbad;
michael@0 94 #endif
michael@0 95 }
michael@0 96
michael@0 97 template <InterpreterFrame::TriggerPostBarriers doPostBarrier>
michael@0 98 void
michael@0 99 InterpreterFrame::copyFrameAndValues(JSContext *cx, Value *vp, InterpreterFrame *otherfp,
michael@0 100 const Value *othervp, Value *othersp)
michael@0 101 {
michael@0 102 JS_ASSERT(othervp == otherfp->generatorArgsSnapshotBegin());
michael@0 103 JS_ASSERT(othersp >= otherfp->slots());
michael@0 104 JS_ASSERT(othersp <= otherfp->generatorSlotsSnapshotBegin() + otherfp->script()->nslots());
michael@0 105
michael@0 106 /* Copy args, InterpreterFrame, and slots. */
michael@0 107 const Value *srcend = otherfp->generatorArgsSnapshotEnd();
michael@0 108 Value *dst = vp;
michael@0 109 for (const Value *src = othervp; src < srcend; src++, dst++) {
michael@0 110 *dst = *src;
michael@0 111 if (doPostBarrier)
michael@0 112 HeapValue::writeBarrierPost(*dst, dst);
michael@0 113 }
michael@0 114
michael@0 115 *this = *otherfp;
michael@0 116 argv_ = vp + 2;
michael@0 117 unsetPushedSPSFrame();
michael@0 118 if (doPostBarrier)
michael@0 119 writeBarrierPost();
michael@0 120
michael@0 121 srcend = othersp;
michael@0 122 dst = slots();
michael@0 123 for (const Value *src = otherfp->slots(); src < srcend; src++, dst++) {
michael@0 124 *dst = *src;
michael@0 125 if (doPostBarrier)
michael@0 126 HeapValue::writeBarrierPost(*dst, dst);
michael@0 127 }
michael@0 128 }
michael@0 129
michael@0 130 /* Note: explicit instantiation for js_NewGenerator located in jsiter.cpp. */
michael@0 131 template
michael@0 132 void InterpreterFrame::copyFrameAndValues<InterpreterFrame::NoPostBarrier>(
michael@0 133 JSContext *, Value *, InterpreterFrame *, const Value *, Value *);
michael@0 134 template
michael@0 135 void InterpreterFrame::copyFrameAndValues<InterpreterFrame::DoPostBarrier>(
michael@0 136 JSContext *, Value *, InterpreterFrame *, const Value *, Value *);
michael@0 137
michael@0 138 void
michael@0 139 InterpreterFrame::writeBarrierPost()
michael@0 140 {
michael@0 141 /* This needs to follow the same rules as in InterpreterFrame::mark. */
michael@0 142 if (scopeChain_)
michael@0 143 JSObject::writeBarrierPost(scopeChain_, (void *)&scopeChain_);
michael@0 144 if (flags_ & HAS_ARGS_OBJ)
michael@0 145 JSObject::writeBarrierPost(argsObj_, (void *)&argsObj_);
michael@0 146 if (isFunctionFrame()) {
michael@0 147 JSFunction::writeBarrierPost(exec.fun, (void *)&exec.fun);
michael@0 148 if (isEvalFrame())
michael@0 149 JSScript::writeBarrierPost(u.evalScript, (void *)&u.evalScript);
michael@0 150 } else {
michael@0 151 JSScript::writeBarrierPost(exec.script, (void *)&exec.script);
michael@0 152 }
michael@0 153 if (hasReturnValue())
michael@0 154 HeapValue::writeBarrierPost(rval_, &rval_);
michael@0 155 }
michael@0 156
michael@0 157 bool
michael@0 158 InterpreterFrame::copyRawFrameSlots(AutoValueVector *vec)
michael@0 159 {
michael@0 160 if (!vec->resize(numFormalArgs() + script()->nfixed()))
michael@0 161 return false;
michael@0 162 PodCopy(vec->begin(), argv(), numFormalArgs());
michael@0 163 PodCopy(vec->begin() + numFormalArgs(), slots(), script()->nfixed());
michael@0 164 return true;
michael@0 165 }
michael@0 166
michael@0 167 JSObject *
michael@0 168 InterpreterFrame::createRestParameter(JSContext *cx)
michael@0 169 {
michael@0 170 JS_ASSERT(fun()->hasRest());
michael@0 171 unsigned nformal = fun()->nargs() - 1, nactual = numActualArgs();
michael@0 172 unsigned nrest = (nactual > nformal) ? nactual - nformal : 0;
michael@0 173 Value *restvp = argv() + nformal;
michael@0 174 JSObject *obj = NewDenseCopiedArray(cx, nrest, restvp, nullptr);
michael@0 175 if (!obj)
michael@0 176 return nullptr;
michael@0 177 types::FixRestArgumentsType(cx, obj);
michael@0 178 return obj;
michael@0 179 }
michael@0 180
michael@0 181 static inline void
michael@0 182 AssertDynamicScopeMatchesStaticScope(JSContext *cx, JSScript *script, JSObject *scope)
michael@0 183 {
michael@0 184 #ifdef DEBUG
michael@0 185 RootedObject enclosingScope(cx, script->enclosingStaticScope());
michael@0 186 for (StaticScopeIter<NoGC> i(enclosingScope); !i.done(); i++) {
michael@0 187 if (i.hasDynamicScopeObject()) {
michael@0 188 switch (i.type()) {
michael@0 189 case StaticScopeIter<NoGC>::BLOCK:
michael@0 190 JS_ASSERT(&i.block() == scope->as<ClonedBlockObject>().staticScope());
michael@0 191 scope = &scope->as<ClonedBlockObject>().enclosingScope();
michael@0 192 break;
michael@0 193 case StaticScopeIter<NoGC>::WITH:
michael@0 194 JS_ASSERT(&i.staticWith() == scope->as<DynamicWithObject>().staticScope());
michael@0 195 scope = &scope->as<DynamicWithObject>().enclosingScope();
michael@0 196 break;
michael@0 197 case StaticScopeIter<NoGC>::FUNCTION:
michael@0 198 JS_ASSERT(scope->as<CallObject>().callee().nonLazyScript() == i.funScript());
michael@0 199 scope = &scope->as<CallObject>().enclosingScope();
michael@0 200 break;
michael@0 201 case StaticScopeIter<NoGC>::NAMED_LAMBDA:
michael@0 202 scope = &scope->as<DeclEnvObject>().enclosingScope();
michael@0 203 break;
michael@0 204 }
michael@0 205 }
michael@0 206 }
michael@0 207
michael@0 208 /*
michael@0 209 * Ideally, we'd JS_ASSERT(!scope->is<ScopeObject>()) but the enclosing
michael@0 210 * lexical scope chain stops at eval() boundaries. See StaticScopeIter
michael@0 211 * comment.
michael@0 212 */
michael@0 213 #endif
michael@0 214 }
michael@0 215
michael@0 216 bool
michael@0 217 InterpreterFrame::initFunctionScopeObjects(JSContext *cx)
michael@0 218 {
michael@0 219 CallObject *callobj = CallObject::createForFunction(cx, this);
michael@0 220 if (!callobj)
michael@0 221 return false;
michael@0 222 pushOnScopeChain(*callobj);
michael@0 223 flags_ |= HAS_CALL_OBJ;
michael@0 224 return true;
michael@0 225 }
michael@0 226
michael@0 227 bool
michael@0 228 InterpreterFrame::prologue(JSContext *cx)
michael@0 229 {
michael@0 230 RootedScript script(cx, this->script());
michael@0 231
michael@0 232 JS_ASSERT(!isGeneratorFrame());
michael@0 233 JS_ASSERT(cx->interpreterRegs().pc == script->code());
michael@0 234
michael@0 235 if (isEvalFrame()) {
michael@0 236 if (script->strict()) {
michael@0 237 CallObject *callobj = CallObject::createForStrictEval(cx, this);
michael@0 238 if (!callobj)
michael@0 239 return false;
michael@0 240 pushOnScopeChain(*callobj);
michael@0 241 flags_ |= HAS_CALL_OBJ;
michael@0 242 }
michael@0 243 return probes::EnterScript(cx, script, nullptr, this);
michael@0 244 }
michael@0 245
michael@0 246 if (isGlobalFrame())
michael@0 247 return probes::EnterScript(cx, script, nullptr, this);
michael@0 248
michael@0 249 JS_ASSERT(isNonEvalFunctionFrame());
michael@0 250 AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
michael@0 251
michael@0 252 if (fun()->isHeavyweight() && !initFunctionScopeObjects(cx))
michael@0 253 return false;
michael@0 254
michael@0 255 if (isConstructing()) {
michael@0 256 RootedObject callee(cx, &this->callee());
michael@0 257 JSObject *obj = CreateThisForFunction(cx, callee,
michael@0 258 useNewType() ? SingletonObject : GenericObject);
michael@0 259 if (!obj)
michael@0 260 return false;
michael@0 261 functionThis() = ObjectValue(*obj);
michael@0 262 }
michael@0 263
michael@0 264 return probes::EnterScript(cx, script, script->functionNonDelazifying(), this);
michael@0 265 }
michael@0 266
michael@0 267 void
michael@0 268 InterpreterFrame::epilogue(JSContext *cx)
michael@0 269 {
michael@0 270 JS_ASSERT(!isYielding());
michael@0 271
michael@0 272 RootedScript script(cx, this->script());
michael@0 273 probes::ExitScript(cx, script, script->functionNonDelazifying(), hasPushedSPSFrame());
michael@0 274
michael@0 275 if (isEvalFrame()) {
michael@0 276 if (isStrictEvalFrame()) {
michael@0 277 JS_ASSERT_IF(hasCallObj(), scopeChain()->as<CallObject>().isForEval());
michael@0 278 if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
michael@0 279 DebugScopes::onPopStrictEvalScope(this);
michael@0 280 } else if (isDirectEvalFrame()) {
michael@0 281 if (isDebuggerFrame())
michael@0 282 JS_ASSERT(!scopeChain()->is<ScopeObject>());
michael@0 283 } else {
michael@0 284 /*
michael@0 285 * Debugger.Object.prototype.evalInGlobal creates indirect eval
michael@0 286 * frames scoped to the given global;
michael@0 287 * Debugger.Object.prototype.evalInGlobalWithBindings creates
michael@0 288 * indirect eval frames scoped to an object carrying the introduced
michael@0 289 * bindings.
michael@0 290 */
michael@0 291 if (isDebuggerFrame()) {
michael@0 292 JS_ASSERT(scopeChain()->is<GlobalObject>() ||
michael@0 293 scopeChain()->enclosingScope()->is<GlobalObject>());
michael@0 294 } else {
michael@0 295 JS_ASSERT(scopeChain()->is<GlobalObject>());
michael@0 296 }
michael@0 297 }
michael@0 298 return;
michael@0 299 }
michael@0 300
michael@0 301 if (isGlobalFrame()) {
michael@0 302 JS_ASSERT(!scopeChain()->is<ScopeObject>());
michael@0 303 return;
michael@0 304 }
michael@0 305
michael@0 306 JS_ASSERT(isNonEvalFunctionFrame());
michael@0 307
michael@0 308 if (fun()->isHeavyweight())
michael@0 309 JS_ASSERT_IF(hasCallObj(),
michael@0 310 scopeChain()->as<CallObject>().callee().nonLazyScript() == script);
michael@0 311 else
michael@0 312 AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
michael@0 313
michael@0 314 if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
michael@0 315 DebugScopes::onPopCall(this, cx);
michael@0 316
michael@0 317 if (isConstructing() && thisValue().isObject() && returnValue().isPrimitive())
michael@0 318 setReturnValue(ObjectValue(constructorThis()));
michael@0 319 }
michael@0 320
michael@0 321 bool
michael@0 322 InterpreterFrame::pushBlock(JSContext *cx, StaticBlockObject &block)
michael@0 323 {
michael@0 324 JS_ASSERT (block.needsClone());
michael@0 325
michael@0 326 Rooted<StaticBlockObject *> blockHandle(cx, &block);
michael@0 327 ClonedBlockObject *clone = ClonedBlockObject::create(cx, blockHandle, this);
michael@0 328 if (!clone)
michael@0 329 return false;
michael@0 330
michael@0 331 pushOnScopeChain(*clone);
michael@0 332
michael@0 333 return true;
michael@0 334 }
michael@0 335
michael@0 336 void
michael@0 337 InterpreterFrame::popBlock(JSContext *cx)
michael@0 338 {
michael@0 339 JS_ASSERT(scopeChain_->is<ClonedBlockObject>());
michael@0 340 popOffScopeChain();
michael@0 341 }
michael@0 342
michael@0 343 void
michael@0 344 InterpreterFrame::popWith(JSContext *cx)
michael@0 345 {
michael@0 346 if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
michael@0 347 DebugScopes::onPopWith(this);
michael@0 348
michael@0 349 JS_ASSERT(scopeChain()->is<DynamicWithObject>());
michael@0 350 popOffScopeChain();
michael@0 351 }
michael@0 352
michael@0 353 void
michael@0 354 InterpreterFrame::mark(JSTracer *trc)
michael@0 355 {
michael@0 356 /*
michael@0 357 * Normally we would use MarkRoot here, except that generators also take
michael@0 358 * this path. However, generators use a special write barrier when the stack
michael@0 359 * frame is copied to the floating frame. Therefore, no barrier is needed.
michael@0 360 */
michael@0 361 if (flags_ & HAS_SCOPECHAIN)
michael@0 362 gc::MarkObjectUnbarriered(trc, &scopeChain_, "scope chain");
michael@0 363 if (flags_ & HAS_ARGS_OBJ)
michael@0 364 gc::MarkObjectUnbarriered(trc, &argsObj_, "arguments");
michael@0 365 if (isFunctionFrame()) {
michael@0 366 gc::MarkObjectUnbarriered(trc, &exec.fun, "fun");
michael@0 367 if (isEvalFrame())
michael@0 368 gc::MarkScriptUnbarriered(trc, &u.evalScript, "eval script");
michael@0 369 } else {
michael@0 370 gc::MarkScriptUnbarriered(trc, &exec.script, "script");
michael@0 371 }
michael@0 372 if (IS_GC_MARKING_TRACER(trc))
michael@0 373 script()->compartment()->zone()->active = true;
michael@0 374 gc::MarkValueUnbarriered(trc, returnValue().address(), "rval");
michael@0 375 }
michael@0 376
michael@0 377 void
michael@0 378 InterpreterFrame::markValues(JSTracer *trc, unsigned start, unsigned end)
michael@0 379 {
michael@0 380 if (start < end)
michael@0 381 gc::MarkValueRootRange(trc, end - start, slots() + start, "vm_stack");
michael@0 382 }
michael@0 383
michael@0 384 void
michael@0 385 InterpreterFrame::markValues(JSTracer *trc, Value *sp, jsbytecode *pc)
michael@0 386 {
michael@0 387 JS_ASSERT(sp >= slots());
michael@0 388
michael@0 389 NestedScopeObject *staticScope;
michael@0 390
michael@0 391 staticScope = script()->getStaticScope(pc);
michael@0 392 while (staticScope && !staticScope->is<StaticBlockObject>())
michael@0 393 staticScope = staticScope->enclosingNestedScope();
michael@0 394
michael@0 395 size_t nfixed = script()->nfixed();
michael@0 396 size_t nlivefixed;
michael@0 397
michael@0 398 if (staticScope) {
michael@0 399 StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>();
michael@0 400 nlivefixed = blockObj.localOffset() + blockObj.numVariables();
michael@0 401 } else {
michael@0 402 nlivefixed = script()->nfixedvars();
michael@0 403 }
michael@0 404
michael@0 405 if (nfixed == nlivefixed) {
michael@0 406 // All locals are live.
michael@0 407 markValues(trc, 0, sp - slots());
michael@0 408 } else {
michael@0 409 // Mark operand stack.
michael@0 410 markValues(trc, nfixed, sp - slots());
michael@0 411
michael@0 412 // Clear dead locals.
michael@0 413 while (nfixed > nlivefixed)
michael@0 414 unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setUndefined();
michael@0 415
michael@0 416 // Mark live locals.
michael@0 417 markValues(trc, 0, nlivefixed);
michael@0 418 }
michael@0 419
michael@0 420 if (hasArgs()) {
michael@0 421 // Mark callee, |this| and arguments.
michael@0 422 unsigned argc = Max(numActualArgs(), numFormalArgs());
michael@0 423 gc::MarkValueRootRange(trc, argc + 2, argv_ - 2, "fp argv");
michael@0 424 } else {
michael@0 425 // Mark callee and |this|
michael@0 426 gc::MarkValueRootRange(trc, 2, ((Value *)this) - 2, "stack callee and this");
michael@0 427 }
michael@0 428 }
michael@0 429
michael@0 430 static void
michael@0 431 MarkInterpreterActivation(JSTracer *trc, InterpreterActivation *act)
michael@0 432 {
michael@0 433 for (InterpreterFrameIterator frames(act); !frames.done(); ++frames) {
michael@0 434 InterpreterFrame *fp = frames.frame();
michael@0 435 fp->markValues(trc, frames.sp(), frames.pc());
michael@0 436 fp->mark(trc);
michael@0 437 }
michael@0 438 }
michael@0 439
michael@0 440 void
michael@0 441 js::MarkInterpreterActivations(JSRuntime *rt, JSTracer *trc)
michael@0 442 {
michael@0 443 for (ActivationIterator iter(rt); !iter.done(); ++iter) {
michael@0 444 Activation *act = iter.activation();
michael@0 445 if (act->isInterpreter())
michael@0 446 MarkInterpreterActivation(trc, act->asInterpreter());
michael@0 447 }
michael@0 448
michael@0 449 }
michael@0 450
michael@0 451 /*****************************************************************************/
michael@0 452
michael@0 453 // Unlike the other methods of this calss, this method is defined here so that
michael@0 454 // we don't have to #include jsautooplen.h in vm/Stack.h.
michael@0 455 void
michael@0 456 InterpreterRegs::setToEndOfScript()
michael@0 457 {
michael@0 458 JSScript *script = fp()->script();
michael@0 459 sp = fp()->base();
michael@0 460 pc = script->codeEnd() - JSOP_RETRVAL_LENGTH;
michael@0 461 JS_ASSERT(*pc == JSOP_RETRVAL);
michael@0 462 }
michael@0 463
michael@0 464 /*****************************************************************************/
michael@0 465
michael@0 466 InterpreterFrame *
michael@0 467 InterpreterStack::pushInvokeFrame(JSContext *cx, const CallArgs &args, InitialFrameFlags initial)
michael@0 468 {
michael@0 469 LifoAlloc::Mark mark = allocator_.mark();
michael@0 470
michael@0 471 RootedFunction fun(cx, &args.callee().as<JSFunction>());
michael@0 472 RootedScript script(cx, fun->nonLazyScript());
michael@0 473
michael@0 474 InterpreterFrame::Flags flags = ToFrameFlags(initial);
michael@0 475 Value *argv;
michael@0 476 InterpreterFrame *fp = getCallFrame(cx, args, script, &flags, &argv);
michael@0 477 if (!fp)
michael@0 478 return nullptr;
michael@0 479
michael@0 480 fp->mark_ = mark;
michael@0 481 fp->initCallFrame(cx, nullptr, nullptr, nullptr, *fun, script, argv, args.length(), flags);
michael@0 482 return fp;
michael@0 483 }
michael@0 484
michael@0 485 InterpreterFrame *
michael@0 486 InterpreterStack::pushExecuteFrame(JSContext *cx, HandleScript script, const Value &thisv,
michael@0 487 HandleObject scopeChain, ExecuteType type,
michael@0 488 AbstractFramePtr evalInFrame)
michael@0 489 {
michael@0 490 LifoAlloc::Mark mark = allocator_.mark();
michael@0 491
michael@0 492 unsigned nvars = 2 /* callee, this */ + script->nslots();
michael@0 493 uint8_t *buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvars * sizeof(Value));
michael@0 494 if (!buffer)
michael@0 495 return nullptr;
michael@0 496
michael@0 497 InterpreterFrame *fp = reinterpret_cast<InterpreterFrame *>(buffer + 2 * sizeof(Value));
michael@0 498 fp->mark_ = mark;
michael@0 499 fp->initExecuteFrame(cx, script, evalInFrame, thisv, *scopeChain, type);
michael@0 500 fp->initVarsToUndefined();
michael@0 501
michael@0 502 return fp;
michael@0 503 }
michael@0 504
michael@0 505 /*****************************************************************************/
michael@0 506
michael@0 507 /* MSVC PGO causes xpcshell startup crashes. */
michael@0 508 #if defined(_MSC_VER)
michael@0 509 # pragma optimize("g", off)
michael@0 510 #endif
michael@0 511
michael@0 512 void
michael@0 513 FrameIter::popActivation()
michael@0 514 {
michael@0 515 ++data_.activations_;
michael@0 516 settleOnActivation();
michael@0 517 }
michael@0 518
michael@0 519 void
michael@0 520 FrameIter::popInterpreterFrame()
michael@0 521 {
michael@0 522 JS_ASSERT(data_.state_ == INTERP);
michael@0 523
michael@0 524 ++data_.interpFrames_;
michael@0 525
michael@0 526 if (data_.interpFrames_.done())
michael@0 527 popActivation();
michael@0 528 else
michael@0 529 data_.pc_ = data_.interpFrames_.pc();
michael@0 530 }
michael@0 531
michael@0 532 void
michael@0 533 FrameIter::settleOnActivation()
michael@0 534 {
michael@0 535 while (true) {
michael@0 536 if (data_.activations_.done()) {
michael@0 537 data_.state_ = DONE;
michael@0 538 return;
michael@0 539 }
michael@0 540
michael@0 541 Activation *activation = data_.activations_.activation();
michael@0 542
michael@0 543 // If JS_SaveFrameChain was called, stop iterating here (unless
michael@0 544 // GO_THROUGH_SAVED is set).
michael@0 545 if (data_.savedOption_ == STOP_AT_SAVED && activation->hasSavedFrameChain()) {
michael@0 546 data_.state_ = DONE;
michael@0 547 return;
michael@0 548 }
michael@0 549
michael@0 550 // Skip activations from another context if needed.
michael@0 551 JS_ASSERT(activation->cx());
michael@0 552 JS_ASSERT(data_.cx_);
michael@0 553 if (data_.contextOption_ == CURRENT_CONTEXT && activation->cx() != data_.cx_) {
michael@0 554 ++data_.activations_;
michael@0 555 continue;
michael@0 556 }
michael@0 557
michael@0 558 // If the caller supplied principals, only show activations which are subsumed (of the same
michael@0 559 // origin or of an origin accessible) by these principals.
michael@0 560 if (data_.principals_) {
michael@0 561 if (JSSubsumesOp subsumes = data_.cx_->runtime()->securityCallbacks->subsumes) {
michael@0 562 JS::AutoAssertNoGC nogc;
michael@0 563 if (!subsumes(data_.principals_, activation->compartment()->principals)) {
michael@0 564 ++data_.activations_;
michael@0 565 continue;
michael@0 566 }
michael@0 567 }
michael@0 568 }
michael@0 569
michael@0 570 #ifdef JS_ION
michael@0 571 if (activation->isJit()) {
michael@0 572 data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
michael@0 573
michael@0 574 // Stop at the first scripted frame.
michael@0 575 while (!data_.jitFrames_.isScripted() && !data_.jitFrames_.done())
michael@0 576 ++data_.jitFrames_;
michael@0 577
michael@0 578 // It's possible to have an JitActivation with no scripted frames,
michael@0 579 // for instance if we hit an over-recursion during bailout.
michael@0 580 if (data_.jitFrames_.done()) {
michael@0 581 ++data_.activations_;
michael@0 582 continue;
michael@0 583 }
michael@0 584
michael@0 585 nextJitFrame();
michael@0 586 data_.state_ = JIT;
michael@0 587 return;
michael@0 588 }
michael@0 589
michael@0 590 if (activation->isAsmJS()) {
michael@0 591 data_.asmJSFrames_ = AsmJSFrameIterator(data_.activations_->asAsmJS());
michael@0 592
michael@0 593 if (data_.asmJSFrames_.done()) {
michael@0 594 ++data_.activations_;
michael@0 595 continue;
michael@0 596 }
michael@0 597
michael@0 598 data_.state_ = ASMJS;
michael@0 599 return;
michael@0 600 }
michael@0 601
michael@0 602 // ForkJoin activations don't contain iterable frames, so skip them.
michael@0 603 if (activation->isForkJoin()) {
michael@0 604 ++data_.activations_;
michael@0 605 continue;
michael@0 606 }
michael@0 607 #endif
michael@0 608
michael@0 609 JS_ASSERT(activation->isInterpreter());
michael@0 610
michael@0 611 InterpreterActivation *interpAct = activation->asInterpreter();
michael@0 612 data_.interpFrames_ = InterpreterFrameIterator(interpAct);
michael@0 613
michael@0 614 // If we OSR'ed into JIT code, skip the interpreter frame so that
michael@0 615 // the same frame is not reported twice.
michael@0 616 if (data_.interpFrames_.frame()->runningInJit()) {
michael@0 617 ++data_.interpFrames_;
michael@0 618 if (data_.interpFrames_.done()) {
michael@0 619 ++data_.activations_;
michael@0 620 continue;
michael@0 621 }
michael@0 622 }
michael@0 623
michael@0 624 JS_ASSERT(!data_.interpFrames_.frame()->runningInJit());
michael@0 625 data_.pc_ = data_.interpFrames_.pc();
michael@0 626 data_.state_ = INTERP;
michael@0 627 return;
michael@0 628 }
michael@0 629 }
michael@0 630
michael@0 631 FrameIter::Data::Data(JSContext *cx, SavedOption savedOption, ContextOption contextOption,
michael@0 632 JSPrincipals *principals)
michael@0 633 : cx_(cx),
michael@0 634 savedOption_(savedOption),
michael@0 635 contextOption_(contextOption),
michael@0 636 principals_(principals),
michael@0 637 pc_(nullptr),
michael@0 638 interpFrames_(nullptr),
michael@0 639 activations_(cx->runtime())
michael@0 640 #ifdef JS_ION
michael@0 641 , jitFrames_((uint8_t *)nullptr, SequentialExecution)
michael@0 642 , ionInlineFrameNo_(0)
michael@0 643 , asmJSFrames_(nullptr)
michael@0 644 #endif
michael@0 645 {
michael@0 646 }
michael@0 647
michael@0 648 FrameIter::Data::Data(const FrameIter::Data &other)
michael@0 649 : cx_(other.cx_),
michael@0 650 savedOption_(other.savedOption_),
michael@0 651 contextOption_(other.contextOption_),
michael@0 652 principals_(other.principals_),
michael@0 653 state_(other.state_),
michael@0 654 pc_(other.pc_),
michael@0 655 interpFrames_(other.interpFrames_),
michael@0 656 activations_(other.activations_)
michael@0 657 #ifdef JS_ION
michael@0 658 , jitFrames_(other.jitFrames_)
michael@0 659 , ionInlineFrameNo_(other.ionInlineFrameNo_)
michael@0 660 , asmJSFrames_(other.asmJSFrames_)
michael@0 661 #endif
michael@0 662 {
michael@0 663 }
michael@0 664
michael@0 665 FrameIter::FrameIter(JSContext *cx, SavedOption savedOption)
michael@0 666 : data_(cx, savedOption, CURRENT_CONTEXT, nullptr)
michael@0 667 #ifdef JS_ION
michael@0 668 , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
michael@0 669 #endif
michael@0 670 {
michael@0 671 // settleOnActivation can only GC if principals are given.
michael@0 672 JS::AutoAssertNoGC nogc;
michael@0 673 settleOnActivation();
michael@0 674 }
michael@0 675
michael@0 676 FrameIter::FrameIter(JSContext *cx, ContextOption contextOption,
michael@0 677 SavedOption savedOption, JSPrincipals *principals)
michael@0 678 : data_(cx, savedOption, contextOption, principals)
michael@0 679 #ifdef JS_ION
michael@0 680 , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
michael@0 681 #endif
michael@0 682 {
michael@0 683 settleOnActivation();
michael@0 684 }
michael@0 685
michael@0 686 FrameIter::FrameIter(const FrameIter &other)
michael@0 687 : data_(other.data_)
michael@0 688 #ifdef JS_ION
michael@0 689 , ionInlineFrames_(other.data_.cx_,
michael@0 690 data_.jitFrames_.isIonJS() ? &other.ionInlineFrames_ : nullptr)
michael@0 691 #endif
michael@0 692 {
michael@0 693 }
michael@0 694
michael@0 695 FrameIter::FrameIter(const Data &data)
michael@0 696 : data_(data)
michael@0 697 #ifdef JS_ION
michael@0 698 , ionInlineFrames_(data.cx_, data_.jitFrames_.isIonJS() ? &data_.jitFrames_ : nullptr)
michael@0 699 #endif
michael@0 700 {
michael@0 701 JS_ASSERT(data.cx_);
michael@0 702
michael@0 703 #ifdef JS_ION
michael@0 704 if (data_.jitFrames_.isIonJS()) {
michael@0 705 while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_)
michael@0 706 ++ionInlineFrames_;
michael@0 707 }
michael@0 708 #endif
michael@0 709 }
michael@0 710
michael@0 711 #ifdef JS_ION
michael@0 712 void
michael@0 713 FrameIter::nextJitFrame()
michael@0 714 {
michael@0 715 if (data_.jitFrames_.isIonJS()) {
michael@0 716 ionInlineFrames_.resetOn(&data_.jitFrames_);
michael@0 717 data_.pc_ = ionInlineFrames_.pc();
michael@0 718 } else {
michael@0 719 JS_ASSERT(data_.jitFrames_.isBaselineJS());
michael@0 720 data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
michael@0 721 }
michael@0 722 }
michael@0 723
michael@0 724 void
michael@0 725 FrameIter::popJitFrame()
michael@0 726 {
michael@0 727 JS_ASSERT(data_.state_ == JIT);
michael@0 728
michael@0 729 if (data_.jitFrames_.isIonJS() && ionInlineFrames_.more()) {
michael@0 730 ++ionInlineFrames_;
michael@0 731 data_.pc_ = ionInlineFrames_.pc();
michael@0 732 return;
michael@0 733 }
michael@0 734
michael@0 735 ++data_.jitFrames_;
michael@0 736 while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted())
michael@0 737 ++data_.jitFrames_;
michael@0 738
michael@0 739 if (!data_.jitFrames_.done()) {
michael@0 740 nextJitFrame();
michael@0 741 return;
michael@0 742 }
michael@0 743
michael@0 744 popActivation();
michael@0 745 }
michael@0 746
michael@0 747 void
michael@0 748 FrameIter::popAsmJSFrame()
michael@0 749 {
michael@0 750 JS_ASSERT(data_.state_ == ASMJS);
michael@0 751
michael@0 752 ++data_.asmJSFrames_;
michael@0 753 if (data_.asmJSFrames_.done())
michael@0 754 popActivation();
michael@0 755 }
michael@0 756 #endif
michael@0 757
michael@0 758 FrameIter &
michael@0 759 FrameIter::operator++()
michael@0 760 {
michael@0 761 switch (data_.state_) {
michael@0 762 case DONE:
michael@0 763 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 764 case INTERP:
michael@0 765 if (interpFrame()->isDebuggerFrame() && interpFrame()->evalInFramePrev()) {
michael@0 766 AbstractFramePtr eifPrev = interpFrame()->evalInFramePrev();
michael@0 767 MOZ_ASSERT(!eifPrev.isRematerializedFrame());
michael@0 768
michael@0 769 // Eval-in-frame can cross contexts and works across saved frame
michael@0 770 // chains.
michael@0 771 ContextOption prevContextOption = data_.contextOption_;
michael@0 772 SavedOption prevSavedOption = data_.savedOption_;
michael@0 773 data_.contextOption_ = ALL_CONTEXTS;
michael@0 774 data_.savedOption_ = GO_THROUGH_SAVED;
michael@0 775
michael@0 776 popInterpreterFrame();
michael@0 777
michael@0 778 while (isIon() || abstractFramePtr() != eifPrev) {
michael@0 779 if (data_.state_ == JIT) {
michael@0 780 #ifdef JS_ION
michael@0 781 popJitFrame();
michael@0 782 #else
michael@0 783 MOZ_ASSUME_UNREACHABLE("Invalid state");
michael@0 784 #endif
michael@0 785 } else {
michael@0 786 popInterpreterFrame();
michael@0 787 }
michael@0 788 }
michael@0 789
michael@0 790 data_.contextOption_ = prevContextOption;
michael@0 791 data_.savedOption_ = prevSavedOption;
michael@0 792 data_.cx_ = data_.activations_->cx();
michael@0 793 break;
michael@0 794 }
michael@0 795 popInterpreterFrame();
michael@0 796 break;
michael@0 797 #ifdef JS_ION
michael@0 798 case JIT:
michael@0 799 popJitFrame();
michael@0 800 break;
michael@0 801 case ASMJS:
michael@0 802 popAsmJSFrame();
michael@0 803 break;
michael@0 804 #else
michael@0 805 default:
michael@0 806 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 807 #endif
michael@0 808 }
michael@0 809 return *this;
michael@0 810 }
michael@0 811
michael@0 812 FrameIter::Data *
michael@0 813 FrameIter::copyData() const
michael@0 814 {
michael@0 815 Data *data = data_.cx_->new_<Data>(data_);
michael@0 816 #ifdef JS_ION
michael@0 817 JS_ASSERT(data_.state_ != ASMJS);
michael@0 818 if (data && data_.jitFrames_.isIonJS())
michael@0 819 data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
michael@0 820 #endif
michael@0 821 return data;
michael@0 822 }
michael@0 823
michael@0 824 AbstractFramePtr
michael@0 825 FrameIter::copyDataAsAbstractFramePtr() const
michael@0 826 {
michael@0 827 AbstractFramePtr frame;
michael@0 828 if (Data *data = copyData())
michael@0 829 frame.ptr_ = uintptr_t(data);
michael@0 830 return frame;
michael@0 831 }
michael@0 832
michael@0 833 JSCompartment *
michael@0 834 FrameIter::compartment() const
michael@0 835 {
michael@0 836 switch (data_.state_) {
michael@0 837 case DONE:
michael@0 838 break;
michael@0 839 case INTERP:
michael@0 840 case JIT:
michael@0 841 case ASMJS:
michael@0 842 return data_.activations_->compartment();
michael@0 843 }
michael@0 844 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 845 }
michael@0 846
michael@0 847 bool
michael@0 848 FrameIter::isFunctionFrame() const
michael@0 849 {
michael@0 850 switch (data_.state_) {
michael@0 851 case DONE:
michael@0 852 break;
michael@0 853 case INTERP:
michael@0 854 return interpFrame()->isFunctionFrame();
michael@0 855 case JIT:
michael@0 856 #ifdef JS_ION
michael@0 857 JS_ASSERT(data_.jitFrames_.isScripted());
michael@0 858 if (data_.jitFrames_.isBaselineJS())
michael@0 859 return data_.jitFrames_.isFunctionFrame();
michael@0 860 return ionInlineFrames_.isFunctionFrame();
michael@0 861 #else
michael@0 862 break;
michael@0 863 #endif
michael@0 864 case ASMJS:
michael@0 865 return true;
michael@0 866 }
michael@0 867 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 868 }
michael@0 869
michael@0 870 bool
michael@0 871 FrameIter::isGlobalFrame() const
michael@0 872 {
michael@0 873 switch (data_.state_) {
michael@0 874 case DONE:
michael@0 875 break;
michael@0 876 case INTERP:
michael@0 877 return interpFrame()->isGlobalFrame();
michael@0 878 case JIT:
michael@0 879 #ifdef JS_ION
michael@0 880 if (data_.jitFrames_.isBaselineJS())
michael@0 881 return data_.jitFrames_.baselineFrame()->isGlobalFrame();
michael@0 882 JS_ASSERT(!script()->isForEval());
michael@0 883 return !script()->functionNonDelazifying();
michael@0 884 #else
michael@0 885 break;
michael@0 886 #endif
michael@0 887 case ASMJS:
michael@0 888 return false;
michael@0 889 }
michael@0 890 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 891 }
michael@0 892
michael@0 893 bool
michael@0 894 FrameIter::isEvalFrame() const
michael@0 895 {
michael@0 896 switch (data_.state_) {
michael@0 897 case DONE:
michael@0 898 break;
michael@0 899 case INTERP:
michael@0 900 return interpFrame()->isEvalFrame();
michael@0 901 case JIT:
michael@0 902 #ifdef JS_ION
michael@0 903 if (data_.jitFrames_.isBaselineJS())
michael@0 904 return data_.jitFrames_.baselineFrame()->isEvalFrame();
michael@0 905 JS_ASSERT(!script()->isForEval());
michael@0 906 return false;
michael@0 907 #else
michael@0 908 break;
michael@0 909 #endif
michael@0 910 case ASMJS:
michael@0 911 return false;
michael@0 912 }
michael@0 913 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 914 }
michael@0 915
michael@0 916 bool
michael@0 917 FrameIter::isNonEvalFunctionFrame() const
michael@0 918 {
michael@0 919 JS_ASSERT(!done());
michael@0 920 switch (data_.state_) {
michael@0 921 case DONE:
michael@0 922 break;
michael@0 923 case INTERP:
michael@0 924 return interpFrame()->isNonEvalFunctionFrame();
michael@0 925 case JIT:
michael@0 926 return !isEvalFrame() && isFunctionFrame();
michael@0 927 case ASMJS:
michael@0 928 return true;
michael@0 929 }
michael@0 930 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 931 }
michael@0 932
michael@0 933 bool
michael@0 934 FrameIter::isGeneratorFrame() const
michael@0 935 {
michael@0 936 switch (data_.state_) {
michael@0 937 case DONE:
michael@0 938 break;
michael@0 939 case INTERP:
michael@0 940 return interpFrame()->isGeneratorFrame();
michael@0 941 case JIT:
michael@0 942 return false;
michael@0 943 case ASMJS:
michael@0 944 return false;
michael@0 945 }
michael@0 946 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 947 }
michael@0 948
michael@0 949 JSAtom *
michael@0 950 FrameIter::functionDisplayAtom() const
michael@0 951 {
michael@0 952 JS_ASSERT(isNonEvalFunctionFrame());
michael@0 953
michael@0 954 switch (data_.state_) {
michael@0 955 case DONE:
michael@0 956 break;
michael@0 957 case INTERP:
michael@0 958 case JIT:
michael@0 959 return callee()->displayAtom();
michael@0 960 case ASMJS: {
michael@0 961 #ifdef JS_ION
michael@0 962 return data_.asmJSFrames_.functionDisplayAtom();
michael@0 963 #else
michael@0 964 break;
michael@0 965 #endif
michael@0 966 }
michael@0 967 }
michael@0 968
michael@0 969 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 970 }
michael@0 971
michael@0 972 ScriptSource *
michael@0 973 FrameIter::scriptSource() const
michael@0 974 {
michael@0 975 switch (data_.state_) {
michael@0 976 case DONE:
michael@0 977 break;
michael@0 978 case INTERP:
michael@0 979 case JIT:
michael@0 980 return script()->scriptSource();
michael@0 981 case ASMJS:
michael@0 982 #ifdef JS_ION
michael@0 983 return data_.activations_->asAsmJS()->module().scriptSource();
michael@0 984 #else
michael@0 985 break;
michael@0 986 #endif
michael@0 987 }
michael@0 988
michael@0 989 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 990 }
michael@0 991
michael@0 992 const char *
michael@0 993 FrameIter::scriptFilename() const
michael@0 994 {
michael@0 995 switch (data_.state_) {
michael@0 996 case DONE:
michael@0 997 break;
michael@0 998 case INTERP:
michael@0 999 case JIT:
michael@0 1000 return script()->filename();
michael@0 1001 case ASMJS:
michael@0 1002 #ifdef JS_ION
michael@0 1003 return data_.activations_->asAsmJS()->module().scriptSource()->filename();
michael@0 1004 #else
michael@0 1005 break;
michael@0 1006 #endif
michael@0 1007 }
michael@0 1008
michael@0 1009 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1010 }
michael@0 1011
michael@0 1012 unsigned
michael@0 1013 FrameIter::computeLine(uint32_t *column) const
michael@0 1014 {
michael@0 1015 switch (data_.state_) {
michael@0 1016 case DONE:
michael@0 1017 break;
michael@0 1018 case INTERP:
michael@0 1019 case JIT:
michael@0 1020 return PCToLineNumber(script(), pc(), column);
michael@0 1021 case ASMJS:
michael@0 1022 #ifdef JS_ION
michael@0 1023 return data_.asmJSFrames_.computeLine(column);
michael@0 1024 #else
michael@0 1025 break;
michael@0 1026 #endif
michael@0 1027 }
michael@0 1028
michael@0 1029 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1030 }
michael@0 1031
michael@0 1032 JSPrincipals *
michael@0 1033 FrameIter::originPrincipals() const
michael@0 1034 {
michael@0 1035 switch (data_.state_) {
michael@0 1036 case DONE:
michael@0 1037 break;
michael@0 1038 case INTERP:
michael@0 1039 case JIT:
michael@0 1040 return script()->originPrincipals();
michael@0 1041 case ASMJS: {
michael@0 1042 #ifdef JS_ION
michael@0 1043 return data_.activations_->asAsmJS()->module().scriptSource()->originPrincipals();
michael@0 1044 #else
michael@0 1045 break;
michael@0 1046 #endif
michael@0 1047 }
michael@0 1048 }
michael@0 1049
michael@0 1050 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1051 }
michael@0 1052
michael@0 1053 bool
michael@0 1054 FrameIter::isConstructing() const
michael@0 1055 {
michael@0 1056 switch (data_.state_) {
michael@0 1057 case DONE:
michael@0 1058 case ASMJS:
michael@0 1059 break;
michael@0 1060 case JIT:
michael@0 1061 #ifdef JS_ION
michael@0 1062 if (data_.jitFrames_.isIonJS())
michael@0 1063 return ionInlineFrames_.isConstructing();
michael@0 1064 JS_ASSERT(data_.jitFrames_.isBaselineJS());
michael@0 1065 return data_.jitFrames_.isConstructing();
michael@0 1066 #else
michael@0 1067 break;
michael@0 1068 #endif
michael@0 1069 case INTERP:
michael@0 1070 return interpFrame()->isConstructing();
michael@0 1071 }
michael@0 1072 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1073 }
michael@0 1074
michael@0 1075 bool
michael@0 1076 FrameIter::ensureHasRematerializedFrame()
michael@0 1077 {
michael@0 1078 #ifdef JS_ION
michael@0 1079 MOZ_ASSERT(isIon());
michael@0 1080 return !!activation()->asJit()->getRematerializedFrame(activation()->cx(), data_.jitFrames_);
michael@0 1081 #else
michael@0 1082 return true;
michael@0 1083 #endif
michael@0 1084 }
michael@0 1085
michael@0 1086 bool
michael@0 1087 FrameIter::hasUsableAbstractFramePtr() const
michael@0 1088 {
michael@0 1089 switch (data_.state_) {
michael@0 1090 case DONE:
michael@0 1091 case ASMJS:
michael@0 1092 return false;
michael@0 1093 case JIT:
michael@0 1094 #ifdef JS_ION
michael@0 1095 if (data_.jitFrames_.isBaselineJS())
michael@0 1096 return true;
michael@0 1097
michael@0 1098 MOZ_ASSERT(data_.jitFrames_.isIonJS());
michael@0 1099 return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
michael@0 1100 ionInlineFrames_.frameNo());
michael@0 1101 #endif
michael@0 1102 break;
michael@0 1103 case INTERP:
michael@0 1104 return true;
michael@0 1105 }
michael@0 1106 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1107 }
michael@0 1108
michael@0 1109 AbstractFramePtr
michael@0 1110 FrameIter::abstractFramePtr() const
michael@0 1111 {
michael@0 1112 MOZ_ASSERT(hasUsableAbstractFramePtr());
michael@0 1113 switch (data_.state_) {
michael@0 1114 case DONE:
michael@0 1115 case ASMJS:
michael@0 1116 break;
michael@0 1117 case JIT: {
michael@0 1118 #ifdef JS_ION
michael@0 1119 if (data_.jitFrames_.isBaselineJS())
michael@0 1120 return data_.jitFrames_.baselineFrame();
michael@0 1121
michael@0 1122 MOZ_ASSERT(data_.jitFrames_.isIonJS());
michael@0 1123 return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
michael@0 1124 ionInlineFrames_.frameNo());
michael@0 1125 #endif
michael@0 1126 break;
michael@0 1127 }
michael@0 1128 case INTERP:
michael@0 1129 JS_ASSERT(interpFrame());
michael@0 1130 return AbstractFramePtr(interpFrame());
michael@0 1131 }
michael@0 1132 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1133 }
michael@0 1134
michael@0 1135 void
michael@0 1136 FrameIter::updatePcQuadratic()
michael@0 1137 {
michael@0 1138 switch (data_.state_) {
michael@0 1139 case DONE:
michael@0 1140 case ASMJS:
michael@0 1141 break;
michael@0 1142 case INTERP: {
michael@0 1143 InterpreterFrame *frame = interpFrame();
michael@0 1144 InterpreterActivation *activation = data_.activations_->asInterpreter();
michael@0 1145
michael@0 1146 // Look for the current frame.
michael@0 1147 data_.interpFrames_ = InterpreterFrameIterator(activation);
michael@0 1148 while (data_.interpFrames_.frame() != frame)
michael@0 1149 ++data_.interpFrames_;
michael@0 1150
michael@0 1151 // Update the pc.
michael@0 1152 JS_ASSERT(data_.interpFrames_.frame() == frame);
michael@0 1153 data_.pc_ = data_.interpFrames_.pc();
michael@0 1154 return;
michael@0 1155 }
michael@0 1156 case JIT:
michael@0 1157 #ifdef JS_ION
michael@0 1158 if (data_.jitFrames_.isBaselineJS()) {
michael@0 1159 jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame();
michael@0 1160 jit::JitActivation *activation = data_.activations_->asJit();
michael@0 1161
michael@0 1162 // ActivationIterator::ionTop_ may be invalid, so create a new
michael@0 1163 // activation iterator.
michael@0 1164 data_.activations_ = ActivationIterator(data_.cx_->runtime());
michael@0 1165 while (data_.activations_.activation() != activation)
michael@0 1166 ++data_.activations_;
michael@0 1167
michael@0 1168 // Look for the current frame.
michael@0 1169 data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
michael@0 1170 while (!data_.jitFrames_.isBaselineJS() || data_.jitFrames_.baselineFrame() != frame)
michael@0 1171 ++data_.jitFrames_;
michael@0 1172
michael@0 1173 // Update the pc.
michael@0 1174 JS_ASSERT(data_.jitFrames_.baselineFrame() == frame);
michael@0 1175 data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
michael@0 1176 return;
michael@0 1177 }
michael@0 1178 #endif
michael@0 1179 break;
michael@0 1180 }
michael@0 1181 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1182 }
michael@0 1183
michael@0 1184 JSFunction *
michael@0 1185 FrameIter::callee() const
michael@0 1186 {
michael@0 1187 switch (data_.state_) {
michael@0 1188 case DONE:
michael@0 1189 case ASMJS:
michael@0 1190 break;
michael@0 1191 case INTERP:
michael@0 1192 JS_ASSERT(isFunctionFrame());
michael@0 1193 return &interpFrame()->callee();
michael@0 1194 case JIT:
michael@0 1195 #ifdef JS_ION
michael@0 1196 if (data_.jitFrames_.isBaselineJS())
michael@0 1197 return data_.jitFrames_.callee();
michael@0 1198 JS_ASSERT(data_.jitFrames_.isIonJS());
michael@0 1199 return ionInlineFrames_.callee();
michael@0 1200 #else
michael@0 1201 break;
michael@0 1202 #endif
michael@0 1203 }
michael@0 1204 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1205 }
michael@0 1206
michael@0 1207 Value
michael@0 1208 FrameIter::calleev() const
michael@0 1209 {
michael@0 1210 switch (data_.state_) {
michael@0 1211 case DONE:
michael@0 1212 case ASMJS:
michael@0 1213 break;
michael@0 1214 case INTERP:
michael@0 1215 JS_ASSERT(isFunctionFrame());
michael@0 1216 return interpFrame()->calleev();
michael@0 1217 case JIT:
michael@0 1218 #ifdef JS_ION
michael@0 1219 return ObjectValue(*callee());
michael@0 1220 #else
michael@0 1221 break;
michael@0 1222 #endif
michael@0 1223 }
michael@0 1224 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1225 }
michael@0 1226
michael@0 1227 unsigned
michael@0 1228 FrameIter::numActualArgs() const
michael@0 1229 {
michael@0 1230 switch (data_.state_) {
michael@0 1231 case DONE:
michael@0 1232 case ASMJS:
michael@0 1233 break;
michael@0 1234 case INTERP:
michael@0 1235 JS_ASSERT(isFunctionFrame());
michael@0 1236 return interpFrame()->numActualArgs();
michael@0 1237 case JIT:
michael@0 1238 #ifdef JS_ION
michael@0 1239 if (data_.jitFrames_.isIonJS())
michael@0 1240 return ionInlineFrames_.numActualArgs();
michael@0 1241
michael@0 1242 JS_ASSERT(data_.jitFrames_.isBaselineJS());
michael@0 1243 return data_.jitFrames_.numActualArgs();
michael@0 1244 #else
michael@0 1245 break;
michael@0 1246 #endif
michael@0 1247 }
michael@0 1248 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1249 }
michael@0 1250
michael@0 1251 unsigned
michael@0 1252 FrameIter::numFormalArgs() const
michael@0 1253 {
michael@0 1254 return script()->functionNonDelazifying()->nargs();
michael@0 1255 }
michael@0 1256
michael@0 1257 Value
michael@0 1258 FrameIter::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const
michael@0 1259 {
michael@0 1260 return abstractFramePtr().unaliasedActual(i, checkAliasing);
michael@0 1261 }
michael@0 1262
michael@0 1263 JSObject *
michael@0 1264 FrameIter::scopeChain() const
michael@0 1265 {
michael@0 1266 switch (data_.state_) {
michael@0 1267 case DONE:
michael@0 1268 case ASMJS:
michael@0 1269 break;
michael@0 1270 case JIT:
michael@0 1271 #ifdef JS_ION
michael@0 1272 if (data_.jitFrames_.isIonJS())
michael@0 1273 return ionInlineFrames_.scopeChain();
michael@0 1274 return data_.jitFrames_.baselineFrame()->scopeChain();
michael@0 1275 #else
michael@0 1276 break;
michael@0 1277 #endif
michael@0 1278 case INTERP:
michael@0 1279 return interpFrame()->scopeChain();
michael@0 1280 }
michael@0 1281 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1282 }
michael@0 1283
michael@0 1284 CallObject &
michael@0 1285 FrameIter::callObj() const
michael@0 1286 {
michael@0 1287 JS_ASSERT(callee()->isHeavyweight());
michael@0 1288
michael@0 1289 JSObject *pobj = scopeChain();
michael@0 1290 while (!pobj->is<CallObject>())
michael@0 1291 pobj = pobj->enclosingScope();
michael@0 1292 return pobj->as<CallObject>();
michael@0 1293 }
michael@0 1294
michael@0 1295 bool
michael@0 1296 FrameIter::hasArgsObj() const
michael@0 1297 {
michael@0 1298 return abstractFramePtr().hasArgsObj();
michael@0 1299 }
michael@0 1300
michael@0 1301 ArgumentsObject &
michael@0 1302 FrameIter::argsObj() const
michael@0 1303 {
michael@0 1304 MOZ_ASSERT(hasArgsObj());
michael@0 1305 return abstractFramePtr().argsObj();
michael@0 1306 }
michael@0 1307
michael@0 1308 bool
michael@0 1309 FrameIter::computeThis(JSContext *cx) const
michael@0 1310 {
michael@0 1311 JS_ASSERT(!done() && !isAsmJS());
michael@0 1312 assertSameCompartment(cx, scopeChain());
michael@0 1313 return ComputeThis(cx, abstractFramePtr());
michael@0 1314 }
michael@0 1315
michael@0 1316 Value
michael@0 1317 FrameIter::computedThisValue() const
michael@0 1318 {
michael@0 1319 return abstractFramePtr().thisValue();
michael@0 1320 }
michael@0 1321
michael@0 1322 Value
michael@0 1323 FrameIter::thisv() const
michael@0 1324 {
michael@0 1325 switch (data_.state_) {
michael@0 1326 case DONE:
michael@0 1327 case ASMJS:
michael@0 1328 break;
michael@0 1329 case JIT:
michael@0 1330 #ifdef JS_ION
michael@0 1331 if (data_.jitFrames_.isIonJS())
michael@0 1332 return ionInlineFrames_.thisValue();
michael@0 1333 return data_.jitFrames_.baselineFrame()->thisValue();
michael@0 1334 #else
michael@0 1335 break;
michael@0 1336 #endif
michael@0 1337 case INTERP:
michael@0 1338 return interpFrame()->thisValue();
michael@0 1339 }
michael@0 1340 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1341 }
michael@0 1342
michael@0 1343 Value
michael@0 1344 FrameIter::returnValue() const
michael@0 1345 {
michael@0 1346 switch (data_.state_) {
michael@0 1347 case DONE:
michael@0 1348 case ASMJS:
michael@0 1349 break;
michael@0 1350 case JIT:
michael@0 1351 #ifdef JS_ION
michael@0 1352 if (data_.jitFrames_.isBaselineJS())
michael@0 1353 return data_.jitFrames_.baselineFrame()->returnValue();
michael@0 1354 #endif
michael@0 1355 break;
michael@0 1356 case INTERP:
michael@0 1357 return interpFrame()->returnValue();
michael@0 1358 }
michael@0 1359 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1360 }
michael@0 1361
michael@0 1362 void
michael@0 1363 FrameIter::setReturnValue(const Value &v)
michael@0 1364 {
michael@0 1365 switch (data_.state_) {
michael@0 1366 case DONE:
michael@0 1367 case ASMJS:
michael@0 1368 break;
michael@0 1369 case JIT:
michael@0 1370 #ifdef JS_ION
michael@0 1371 if (data_.jitFrames_.isBaselineJS()) {
michael@0 1372 data_.jitFrames_.baselineFrame()->setReturnValue(v);
michael@0 1373 return;
michael@0 1374 }
michael@0 1375 #endif
michael@0 1376 break;
michael@0 1377 case INTERP:
michael@0 1378 interpFrame()->setReturnValue(v);
michael@0 1379 return;
michael@0 1380 }
michael@0 1381 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1382 }
michael@0 1383
michael@0 1384 size_t
michael@0 1385 FrameIter::numFrameSlots() const
michael@0 1386 {
michael@0 1387 switch (data_.state_) {
michael@0 1388 case DONE:
michael@0 1389 case ASMJS:
michael@0 1390 break;
michael@0 1391 case JIT: {
michael@0 1392 #ifdef JS_ION
michael@0 1393 if (data_.jitFrames_.isIonJS()) {
michael@0 1394 return ionInlineFrames_.snapshotIterator().numAllocations() -
michael@0 1395 ionInlineFrames_.script()->nfixed();
michael@0 1396 }
michael@0 1397 jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame();
michael@0 1398 return frame->numValueSlots() - data_.jitFrames_.script()->nfixed();
michael@0 1399 #else
michael@0 1400 break;
michael@0 1401 #endif
michael@0 1402 }
michael@0 1403 case INTERP:
michael@0 1404 JS_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
michael@0 1405 return data_.interpFrames_.sp() - interpFrame()->base();
michael@0 1406 }
michael@0 1407 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1408 }
michael@0 1409
michael@0 1410 Value
michael@0 1411 FrameIter::frameSlotValue(size_t index) const
michael@0 1412 {
michael@0 1413 switch (data_.state_) {
michael@0 1414 case DONE:
michael@0 1415 case ASMJS:
michael@0 1416 break;
michael@0 1417 case JIT:
michael@0 1418 #ifdef JS_ION
michael@0 1419 if (data_.jitFrames_.isIonJS()) {
michael@0 1420 jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
michael@0 1421 index += ionInlineFrames_.script()->nfixed();
michael@0 1422 return si.maybeReadAllocByIndex(index);
michael@0 1423 }
michael@0 1424
michael@0 1425 index += data_.jitFrames_.script()->nfixed();
michael@0 1426 return *data_.jitFrames_.baselineFrame()->valueSlot(index);
michael@0 1427 #else
michael@0 1428 break;
michael@0 1429 #endif
michael@0 1430 case INTERP:
michael@0 1431 return interpFrame()->base()[index];
michael@0 1432 }
michael@0 1433 MOZ_ASSUME_UNREACHABLE("Unexpected state");
michael@0 1434 }
michael@0 1435
michael@0 1436 #if defined(_MSC_VER)
michael@0 1437 # pragma optimize("", on)
michael@0 1438 #endif
michael@0 1439
michael@0 1440 #ifdef DEBUG
michael@0 1441 bool
michael@0 1442 js::SelfHostedFramesVisible()
michael@0 1443 {
michael@0 1444 static bool checked = false;
michael@0 1445 static bool visible = false;
michael@0 1446 if (!checked) {
michael@0 1447 checked = true;
michael@0 1448 char *env = getenv("MOZ_SHOW_ALL_JS_FRAMES");
michael@0 1449 visible = !!env;
michael@0 1450 }
michael@0 1451 return visible;
michael@0 1452 }
michael@0 1453 #endif
michael@0 1454
michael@0 1455 void
michael@0 1456 NonBuiltinFrameIter::settle()
michael@0 1457 {
michael@0 1458 if (!SelfHostedFramesVisible()) {
michael@0 1459 while (!done() && hasScript() && script()->selfHosted())
michael@0 1460 FrameIter::operator++();
michael@0 1461 }
michael@0 1462 }
michael@0 1463
michael@0 1464 void
michael@0 1465 NonBuiltinScriptFrameIter::settle()
michael@0 1466 {
michael@0 1467 if (!SelfHostedFramesVisible()) {
michael@0 1468 while (!done() && script()->selfHosted())
michael@0 1469 ScriptFrameIter::operator++();
michael@0 1470 }
michael@0 1471 }
michael@0 1472
michael@0 1473 /*****************************************************************************/
michael@0 1474
michael@0 1475 JSObject *
michael@0 1476 AbstractFramePtr::evalPrevScopeChain(JSContext *cx) const
michael@0 1477 {
michael@0 1478 // Eval frames are not compiled by Ion, though their caller might be.
michael@0 1479 AllFramesIter iter(cx);
michael@0 1480 while (iter.isIon() || iter.abstractFramePtr() != *this)
michael@0 1481 ++iter;
michael@0 1482 ++iter;
michael@0 1483 return iter.scopeChain();
michael@0 1484 }
michael@0 1485
michael@0 1486 bool
michael@0 1487 AbstractFramePtr::hasPushedSPSFrame() const
michael@0 1488 {
michael@0 1489 if (isInterpreterFrame())
michael@0 1490 return asInterpreterFrame()->hasPushedSPSFrame();
michael@0 1491 #ifdef JS_ION
michael@0 1492 return asBaselineFrame()->hasPushedSPSFrame();
michael@0 1493 #else
michael@0 1494 MOZ_ASSUME_UNREACHABLE("Invalid frame");
michael@0 1495 #endif
michael@0 1496 }
michael@0 1497
michael@0 1498 #ifdef DEBUG
michael@0 1499 void
michael@0 1500 js::CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, uint32_t i)
michael@0 1501 {
michael@0 1502 if (!checkAliasing)
michael@0 1503 return;
michael@0 1504
michael@0 1505 JS_ASSERT(i < script->nfixed());
michael@0 1506 if (i < script->bindings.numVars()) {
michael@0 1507 JS_ASSERT(!script->varIsAliased(i));
michael@0 1508 } else {
michael@0 1509 // FIXME: The callers of this function do not easily have the PC of the
michael@0 1510 // current frame, and so they do not know the block scope.
michael@0 1511 }
michael@0 1512 }
michael@0 1513 #endif
michael@0 1514
michael@0 1515 jit::JitActivation::JitActivation(JSContext *cx, bool firstFrameIsConstructing, bool active)
michael@0 1516 : Activation(cx, Jit),
michael@0 1517 firstFrameIsConstructing_(firstFrameIsConstructing),
michael@0 1518 active_(active)
michael@0 1519 #ifdef JS_ION
michael@0 1520 , rematerializedFrames_(cx)
michael@0 1521 #endif
michael@0 1522 {
michael@0 1523 if (active) {
michael@0 1524 prevIonTop_ = cx->mainThread().ionTop;
michael@0 1525 prevJitJSContext_ = cx->mainThread().jitJSContext;
michael@0 1526 cx->mainThread().jitJSContext = cx;
michael@0 1527 } else {
michael@0 1528 prevIonTop_ = nullptr;
michael@0 1529 prevJitJSContext_ = nullptr;
michael@0 1530 }
michael@0 1531 }
michael@0 1532
michael@0 1533 jit::JitActivation::~JitActivation()
michael@0 1534 {
michael@0 1535 if (active_) {
michael@0 1536 cx_->mainThread().ionTop = prevIonTop_;
michael@0 1537 cx_->mainThread().jitJSContext = prevJitJSContext_;
michael@0 1538 }
michael@0 1539
michael@0 1540 #ifdef JS_ION
michael@0 1541 clearRematerializedFrames();
michael@0 1542 #endif
michael@0 1543 }
michael@0 1544
michael@0 1545 // setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
michael@0 1546 // changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
michael@0 1547 // and disable activation instruction sequences.
michael@0 1548 void
michael@0 1549 jit::JitActivation::setActive(JSContext *cx, bool active)
michael@0 1550 {
michael@0 1551 // Only allowed to deactivate/activate if activation is top.
michael@0 1552 // (Not tested and will probably fail in other situations.)
michael@0 1553 JS_ASSERT(cx->mainThread().activation_ == this);
michael@0 1554 JS_ASSERT(active != active_);
michael@0 1555 active_ = active;
michael@0 1556
michael@0 1557 if (active) {
michael@0 1558 prevIonTop_ = cx->mainThread().ionTop;
michael@0 1559 prevJitJSContext_ = cx->mainThread().jitJSContext;
michael@0 1560 cx->mainThread().jitJSContext = cx;
michael@0 1561 } else {
michael@0 1562 cx->mainThread().ionTop = prevIonTop_;
michael@0 1563 cx->mainThread().jitJSContext = prevJitJSContext_;
michael@0 1564 }
michael@0 1565 }
michael@0 1566
michael@0 1567 #ifdef JS_ION
michael@0 1568
michael@0 1569 void
michael@0 1570 jit::JitActivation::freeRematerializedFramesInVector(RematerializedFrameVector &frames)
michael@0 1571 {
michael@0 1572 for (size_t i = 0; i < frames.length(); i++) {
michael@0 1573 RematerializedFrame *f = frames[i];
michael@0 1574 f->RematerializedFrame::~RematerializedFrame();
michael@0 1575 js_free(f);
michael@0 1576 }
michael@0 1577 frames.clear();
michael@0 1578 }
michael@0 1579
michael@0 1580 void
michael@0 1581 jit::JitActivation::removeRematerializedFrame(uint8_t *top)
michael@0 1582 {
michael@0 1583 if (!rematerializedFrames_.initialized())
michael@0 1584 return;
michael@0 1585
michael@0 1586 if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top)) {
michael@0 1587 freeRematerializedFramesInVector(p->value());
michael@0 1588 rematerializedFrames_.remove(p);
michael@0 1589 }
michael@0 1590 }
michael@0 1591
michael@0 1592 void
michael@0 1593 jit::JitActivation::clearRematerializedFrames()
michael@0 1594 {
michael@0 1595 if (!rematerializedFrames_.initialized())
michael@0 1596 return;
michael@0 1597
michael@0 1598 for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) {
michael@0 1599 freeRematerializedFramesInVector(e.front().value());
michael@0 1600 e.removeFront();
michael@0 1601 }
michael@0 1602 }
michael@0 1603
michael@0 1604 jit::RematerializedFrame *
michael@0 1605 jit::JitActivation::getRematerializedFrame(JSContext *cx, JitFrameIterator &iter,
michael@0 1606 size_t inlineDepth)
michael@0 1607 {
michael@0 1608 MOZ_ASSERT(iter.activation() == this);
michael@0 1609 MOZ_ASSERT(iter.isIonJS());
michael@0 1610
michael@0 1611 if (!rematerializedFrames_.initialized() && !rematerializedFrames_.init())
michael@0 1612 return nullptr;
michael@0 1613
michael@0 1614 // The unit of rematerialization is an uninlined frame and its inlined
michael@0 1615 // frames. Since inlined frames do not exist outside of snapshots, it is
michael@0 1616 // impossible to synchronize their rematerialized copies to preserve
michael@0 1617 // identity. Therefore, we always rematerialize an uninlined frame and all
michael@0 1618 // its inlined frames at once.
michael@0 1619
michael@0 1620 uint8_t *top = iter.fp();
michael@0 1621 RematerializedFrameTable::AddPtr p = rematerializedFrames_.lookupForAdd(top);
michael@0 1622 if (!p) {
michael@0 1623 RematerializedFrameVector empty(cx);
michael@0 1624 if (!rematerializedFrames_.add(p, top, Move(empty)))
michael@0 1625 return nullptr;
michael@0 1626
michael@0 1627 InlineFrameIterator inlineIter(cx, &iter);
michael@0 1628 if (!p->value().resize(inlineIter.frameCount()))
michael@0 1629 return nullptr;
michael@0 1630
michael@0 1631 while (true) {
michael@0 1632 size_t frameNo = inlineIter.frameNo();
michael@0 1633 p->value()[frameNo] = RematerializedFrame::New(cx, top, inlineIter);
michael@0 1634 if (!p->value()[frameNo])
michael@0 1635 return nullptr;
michael@0 1636
michael@0 1637 if (!inlineIter.more())
michael@0 1638 break;
michael@0 1639 ++inlineIter;
michael@0 1640 }
michael@0 1641 }
michael@0 1642
michael@0 1643 return p->value()[inlineDepth];
michael@0 1644 }
michael@0 1645
michael@0 1646 jit::RematerializedFrame *
michael@0 1647 jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth)
michael@0 1648 {
michael@0 1649 if (!rematerializedFrames_.initialized())
michael@0 1650 return nullptr;
michael@0 1651 if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top))
michael@0 1652 return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr;
michael@0 1653 return nullptr;
michael@0 1654 }
michael@0 1655
michael@0 1656 void
michael@0 1657 jit::JitActivation::markRematerializedFrames(JSTracer *trc)
michael@0 1658 {
michael@0 1659 if (!rematerializedFrames_.initialized())
michael@0 1660 return;
michael@0 1661 for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) {
michael@0 1662 RematerializedFrameVector &frames = e.front().value();
michael@0 1663 for (size_t i = 0; i < frames.length(); i++)
michael@0 1664 frames[i]->mark(trc);
michael@0 1665 }
michael@0 1666 }
michael@0 1667
michael@0 1668 #endif // JS_ION
michael@0 1669
michael@0 1670 AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module)
michael@0 1671 : Activation(cx, AsmJS),
michael@0 1672 module_(module),
michael@0 1673 errorRejoinSP_(nullptr),
michael@0 1674 profiler_(nullptr),
michael@0 1675 resumePC_(nullptr),
michael@0 1676 exitSP_(nullptr)
michael@0 1677 {
michael@0 1678 if (cx->runtime()->spsProfiler.enabled()) {
michael@0 1679 // Use a profiler string that matches jsMatch regex in
michael@0 1680 // browser/devtools/profiler/cleopatra/js/parserWorker.js.
michael@0 1681 // (For now use a single static string to avoid further slowing down
michael@0 1682 // calls into asm.js.)
michael@0 1683 profiler_ = &cx->runtime()->spsProfiler;
michael@0 1684 profiler_->enterNative("asm.js code :0", this);
michael@0 1685 }
michael@0 1686
michael@0 1687 prevAsmJS_ = cx_->runtime()->mainThread.asmJSActivationStack_;
michael@0 1688
michael@0 1689 JSRuntime::AutoLockForInterrupt lock(cx_->runtime());
michael@0 1690 cx_->runtime()->mainThread.asmJSActivationStack_ = this;
michael@0 1691
michael@0 1692 (void) errorRejoinSP_; // squelch GCC warning
michael@0 1693 }
michael@0 1694
michael@0 1695 AsmJSActivation::~AsmJSActivation()
michael@0 1696 {
michael@0 1697 if (profiler_)
michael@0 1698 profiler_->exitNative();
michael@0 1699
michael@0 1700 JS_ASSERT(cx_->runtime()->mainThread.asmJSActivationStack_ == this);
michael@0 1701
michael@0 1702 JSRuntime::AutoLockForInterrupt lock(cx_->runtime());
michael@0 1703 cx_->runtime()->mainThread.asmJSActivationStack_ = prevAsmJS_;
michael@0 1704 }
michael@0 1705
michael@0 1706 InterpreterFrameIterator &
michael@0 1707 InterpreterFrameIterator::operator++()
michael@0 1708 {
michael@0 1709 JS_ASSERT(!done());
michael@0 1710 if (fp_ != activation_->entryFrame_) {
michael@0 1711 pc_ = fp_->prevpc();
michael@0 1712 sp_ = fp_->prevsp();
michael@0 1713 fp_ = fp_->prev();
michael@0 1714 } else {
michael@0 1715 pc_ = nullptr;
michael@0 1716 sp_ = nullptr;
michael@0 1717 fp_ = nullptr;
michael@0 1718 }
michael@0 1719 return *this;
michael@0 1720 }
michael@0 1721
michael@0 1722 ActivationIterator::ActivationIterator(JSRuntime *rt)
michael@0 1723 : jitTop_(rt->mainThread.ionTop),
michael@0 1724 activation_(rt->mainThread.activation_)
michael@0 1725 {
michael@0 1726 settle();
michael@0 1727 }
michael@0 1728
michael@0 1729 ActivationIterator &
michael@0 1730 ActivationIterator::operator++()
michael@0 1731 {
michael@0 1732 JS_ASSERT(activation_);
michael@0 1733 if (activation_->isJit() && activation_->asJit()->isActive())
michael@0 1734 jitTop_ = activation_->asJit()->prevIonTop();
michael@0 1735 activation_ = activation_->prev();
michael@0 1736 settle();
michael@0 1737 return *this;
michael@0 1738 }
michael@0 1739
michael@0 1740 void
michael@0 1741 ActivationIterator::settle()
michael@0 1742 {
michael@0 1743 // Stop at the next active activation. No need to update jitTop_, since
michael@0 1744 // we don't iterate over an active jit activation.
michael@0 1745 while (!done() && activation_->isJit() && !activation_->asJit()->isActive())
michael@0 1746 activation_ = activation_->prev();
michael@0 1747 }

mercurial