1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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/Activation-inl.h"
8 
9 #include "mozilla/Assertions.h"  // MOZ_ASSERT
10 
11 #include <stddef.h>  // size_t
12 #include <stdint.h>  // uint8_t, uint32_t
13 
14 #include "debugger/DebugAPI.h"  // js::DebugAPI
15 #include "gc/GC.h"              // js::gc::AutoSuppressGC
16 #include "jit/CalleeToken.h"  // js::jit::CalleeToken{IsFunction,To{Function,Script}}
17 #include "js/RootingAPI.h"  // JS::Rooted
18 #include "js/Value.h"       // JS::Value
19 #include "vm/JSContext.h"   // JSContext, js::TlsContext
20 #include "vm/Stack.h"       // js::InterpreterFrame
21 
22 #include "vm/Compartment-inl.h"  // JS::Compartment::wrap
23 
24 using namespace js;
25 
26 using JS::ObjectOrNullValue;
27 using JS::Rooted;
28 using JS::UndefinedValue;
29 using JS::Value;
30 
asyncStack(JSContext * cx)31 Value ActivationEntryMonitor::asyncStack(JSContext* cx) {
32   Rooted<Value> stack(cx, ObjectOrNullValue(cx->asyncStackForNewActivations()));
33   if (!cx->compartment()->wrap(cx, &stack)) {
34     cx->clearPendingException();
35     return UndefinedValue();
36   }
37   return stack;
38 }
39 
init(JSContext * cx,InterpreterFrame * entryFrame)40 void ActivationEntryMonitor::init(JSContext* cx, InterpreterFrame* entryFrame) {
41   // The InterpreterFrame is not yet part of an Activation, so it won't
42   // be traced if we trigger GC here. Suppress GC to avoid this.
43   gc::AutoSuppressGC suppressGC(cx);
44   Rooted<Value> stack(cx, asyncStack(cx));
45   const char* asyncCause = cx->asyncCauseForNewActivations;
46   if (entryFrame->isFunctionFrame()) {
47     entryMonitor_->Entry(cx, &entryFrame->callee(), stack, asyncCause);
48   } else {
49     entryMonitor_->Entry(cx, entryFrame->script(), stack, asyncCause);
50   }
51 }
52 
init(JSContext * cx,jit::CalleeToken entryToken)53 void ActivationEntryMonitor::init(JSContext* cx, jit::CalleeToken entryToken) {
54   // The CalleeToken is not traced at this point and we also don't want
55   // a GC to discard the code we're about to enter, so we suppress GC.
56   gc::AutoSuppressGC suppressGC(cx);
57   RootedValue stack(cx, asyncStack(cx));
58   const char* asyncCause = cx->asyncCauseForNewActivations;
59   if (jit::CalleeTokenIsFunction(entryToken)) {
60     entryMonitor_->Entry(cx_, jit::CalleeTokenToFunction(entryToken), stack,
61                          asyncCause);
62   } else {
63     entryMonitor_->Entry(cx_, jit::CalleeTokenToScript(entryToken), stack,
64                          asyncCause);
65   }
66 }
67 
registerProfiling()68 void Activation::registerProfiling() {
69   MOZ_ASSERT(isProfiling());
70   cx_->profilingActivation_ = this;
71 }
72 
unregisterProfiling()73 void Activation::unregisterProfiling() {
74   MOZ_ASSERT(isProfiling());
75   MOZ_ASSERT(cx_->profilingActivation_ == this);
76   cx_->profilingActivation_ = prevProfiling_;
77 }
78 
ActivationIterator(JSContext * cx)79 ActivationIterator::ActivationIterator(JSContext* cx)
80     : activation_(cx->activation_) {
81   MOZ_ASSERT(cx == TlsContext.get());
82 }
83 
operator ++()84 ActivationIterator& ActivationIterator::operator++() {
85   MOZ_ASSERT(activation_);
86   activation_ = activation_->prev();
87   return *this;
88 }
89