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