js/src/vm/Stack.cpp

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

mercurial