Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / vm / JitActivation.cpp
blobd6c630458bb7e5562878211546ec9193c570ba23
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/. */
7 #include "vm/JitActivation.h"
9 #include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_RELEASE_ASSERT
11 #include <stddef.h> // size_t
12 #include <stdint.h> // uint8_t, uint32_t
13 #include <utility> // std::move
15 #include "debugger/DebugAPI.h" // js::DebugAPI
16 #include "jit/JSJitFrameIter.h" // js::jit::InlineFrameIterator
17 #include "jit/RematerializedFrame.h" // js::jit::RematerializedFrame
18 #include "js/AllocPolicy.h" // js::ReportOutOfMemory
19 #include "vm/EnvironmentObject.h" // js::DebugEnvironments
20 #include "vm/JSContext.h" // JSContext
21 #include "vm/Realm.h" // js::AutoRealmUnchecked
22 #include "wasm/WasmCode.h" // js::wasm::Code
23 #include "wasm/WasmConstants.h" // js::wasm::Trap
24 #include "wasm/WasmFrameIter.h" // js::wasm::{RegisterState,StartUnwinding,UnwindState}
25 #include "wasm/WasmInstance.h" // js::wasm::Instance
26 #include "wasm/WasmProcess.h" // js::wasm::LookupCode
28 #include "vm/Realm-inl.h" // js::~AutoRealm
30 class JS_PUBLIC_API JSTracer;
32 js::jit::JitActivation::JitActivation(JSContext* cx)
33 : Activation(cx, Jit),
34 packedExitFP_(nullptr),
35 encodedWasmExitReason_(0),
36 prevJitActivation_(cx->jitActivation),
37 ionRecovery_(cx),
38 bailoutData_(nullptr),
39 lastProfilingFrame_(nullptr),
40 lastProfilingCallSite_(nullptr) {
41 cx->jitActivation = this;
42 registerProfiling();
45 js::jit::JitActivation::~JitActivation() {
46 if (isProfiling()) {
47 unregisterProfiling();
49 cx_->jitActivation = prevJitActivation_;
51 // All reocvered value are taken from activation during the bailout.
52 MOZ_ASSERT(ionRecovery_.empty());
54 // The BailoutFrameInfo should have unregistered itself from the
55 // JitActivations.
56 MOZ_ASSERT(!bailoutData_);
58 // Traps get handled immediately.
59 MOZ_ASSERT(!isWasmTrapping());
61 clearRematerializedFrames();
64 void js::jit::JitActivation::setBailoutData(
65 jit::BailoutFrameInfo* bailoutData) {
66 MOZ_ASSERT(!bailoutData_);
67 bailoutData_ = bailoutData;
70 void js::jit::JitActivation::cleanBailoutData() {
71 MOZ_ASSERT(bailoutData_);
72 bailoutData_ = nullptr;
75 void js::jit::JitActivation::removeRematerializedFrame(uint8_t* top) {
76 if (!rematerializedFrames_) {
77 return;
80 if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
81 rematerializedFrames_->remove(p);
85 void js::jit::JitActivation::clearRematerializedFrames() {
86 if (!rematerializedFrames_) {
87 return;
90 for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty();
91 e.popFront()) {
92 e.removeFront();
96 js::jit::RematerializedFrame* js::jit::JitActivation::getRematerializedFrame(
97 JSContext* cx, const JSJitFrameIter& iter, size_t inlineDepth,
98 MaybeReadFallback::FallbackConsequence consequence) {
99 MOZ_ASSERT(iter.activation() == this);
100 MOZ_ASSERT(iter.isIonScripted());
102 if (!rematerializedFrames_) {
103 rematerializedFrames_ = cx->make_unique<RematerializedFrameTable>(cx);
104 if (!rematerializedFrames_) {
105 return nullptr;
109 uint8_t* top = iter.fp();
110 RematerializedFrameTable::AddPtr p = rematerializedFrames_->lookupForAdd(top);
111 if (!p) {
112 RematerializedFrameVector frames(cx);
114 // The unit of rematerialization is an uninlined frame and its inlined
115 // frames. Since inlined frames do not exist outside of snapshots, it
116 // is impossible to synchronize their rematerialized copies to
117 // preserve identity. Therefore, we always rematerialize an uninlined
118 // frame and all its inlined frames at once.
119 InlineFrameIterator inlineIter(cx, &iter);
120 MaybeReadFallback recover(cx, this, &iter, consequence);
122 // Frames are often rematerialized with the cx inside a Debugger's
123 // realm. To recover slots and to create CallObjects, we need to
124 // be in the script's realm.
125 AutoRealmUnchecked ar(cx, iter.script()->realm());
127 if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter,
128 recover, frames)) {
129 return nullptr;
132 if (!rematerializedFrames_->add(p, top, std::move(frames))) {
133 ReportOutOfMemory(cx);
134 return nullptr;
137 // See comment in unsetPrevUpToDateUntil.
138 DebugEnvironments::unsetPrevUpToDateUntil(cx,
139 p->value()[inlineDepth].get());
142 return p->value()[inlineDepth].get();
145 js::jit::RematerializedFrame* js::jit::JitActivation::lookupRematerializedFrame(
146 uint8_t* top, size_t inlineDepth) {
147 if (!rematerializedFrames_) {
148 return nullptr;
150 if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
151 return inlineDepth < p->value().length() ? p->value()[inlineDepth].get()
152 : nullptr;
154 return nullptr;
157 void js::jit::JitActivation::removeRematerializedFramesFromDebugger(
158 JSContext* cx, uint8_t* top) {
159 // Ion bailout can fail due to overrecursion and OOM. In such cases we
160 // cannot honor any further Debugger hooks on the frame, and need to
161 // ensure that its Debugger.Frame entry is cleaned up.
162 if (!cx->realm()->isDebuggee() || !rematerializedFrames_) {
163 return;
165 if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
166 for (uint32_t i = 0; i < p->value().length(); i++) {
167 DebugAPI::handleUnrecoverableIonBailoutError(cx, p->value()[i].get());
169 rematerializedFrames_->remove(p);
173 void js::jit::JitActivation::traceRematerializedFrames(JSTracer* trc) {
174 if (!rematerializedFrames_) {
175 return;
177 for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty();
178 e.popFront()) {
179 e.front().value().trace(trc);
183 bool js::jit::JitActivation::registerIonFrameRecovery(
184 RInstructionResults&& results) {
185 // Check that there is no entry in the vector yet.
186 MOZ_ASSERT(!maybeIonFrameRecovery(results.frame()));
187 if (!ionRecovery_.append(std::move(results))) {
188 return false;
191 return true;
194 js::jit::RInstructionResults* js::jit::JitActivation::maybeIonFrameRecovery(
195 JitFrameLayout* fp) {
196 for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end();
197 it++) {
198 if (it->frame() == fp) {
199 return it;
203 return nullptr;
206 void js::jit::JitActivation::removeIonFrameRecovery(JitFrameLayout* fp) {
207 RInstructionResults* elem = maybeIonFrameRecovery(fp);
208 if (!elem) {
209 return;
212 ionRecovery_.erase(elem);
215 void js::jit::JitActivation::traceIonRecovery(JSTracer* trc) {
216 for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end();
217 it++) {
218 it->trace(trc);
222 void js::jit::JitActivation::startWasmTrap(wasm::Trap trap,
223 uint32_t bytecodeOffset,
224 const wasm::RegisterState& state) {
225 MOZ_ASSERT(!isWasmTrapping());
227 bool unwound;
228 wasm::UnwindState unwindState;
229 MOZ_RELEASE_ASSERT(wasm::StartUnwinding(state, &unwindState, &unwound));
230 // With return calls, it is possible to not unwind when there is only an
231 // entry left on the stack, e.g. the return call trampoline that is created
232 // to restore realm before returning to the interpreter entry stub.
233 MOZ_ASSERT_IF(unwound, trap == wasm::Trap::IndirectCallBadSig);
235 void* pc = unwindState.pc;
236 const wasm::Frame* fp = wasm::Frame::fromUntaggedWasmExitFP(unwindState.fp);
238 const wasm::Code& code = wasm::GetNearestEffectiveInstance(fp)->code();
239 MOZ_RELEASE_ASSERT(&code == wasm::LookupCode(pc));
241 // If the frame was unwound, the bytecodeOffset must be recovered from the
242 // callsite so that it is accurate.
243 if (unwound) {
244 bytecodeOffset = code.lookupCallSite(pc)->lineOrBytecode();
247 setWasmExitFP(fp);
248 wasmTrapData_.emplace();
249 wasmTrapData_->resumePC =
250 ((uint8_t*)state.pc) + jit::WasmTrapInstructionLength;
251 wasmTrapData_->unwoundPC = pc;
252 wasmTrapData_->trap = trap;
253 wasmTrapData_->bytecodeOffset = bytecodeOffset;
255 MOZ_ASSERT(isWasmTrapping());
258 void js::jit::JitActivation::finishWasmTrap() {
259 MOZ_ASSERT(isWasmTrapping());
260 packedExitFP_ = nullptr;
261 wasmTrapData_.reset();
262 MOZ_ASSERT(!isWasmTrapping());