Bug 1885489 - Part 5: Add SnapshotIterator::readInt32(). r=iain
[gecko.git] / js / src / jit / BaselineFrame.h
blobf2a6811177b8c13458d39d840e7612aea1abf21c
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 #ifndef jit_BaselineFrame_h
8 #define jit_BaselineFrame_h
10 #include <algorithm>
12 #include "jit/CalleeToken.h"
13 #include "jit/JitFrames.h"
14 #include "jit/ScriptFromCalleeToken.h"
15 #include "vm/Stack.h"
17 namespace js {
18 namespace jit {
20 class ICEntry;
21 class ICScript;
22 class JSJitFrameIter;
24 // The stack looks like this, fp is the frame pointer:
26 // fp+y arguments
27 // fp => JitFrameLayout (frame header)
28 // fp-x BaselineFrame
29 // locals
30 // stack values
32 class BaselineFrame {
33 public:
34 enum Flags : uint32_t {
35 // The frame has a valid return value. See also InterpreterFrame::HAS_RVAL.
36 HAS_RVAL = 1 << 0,
38 // The frame is running in the Baseline interpreter instead of JIT.
39 RUNNING_IN_INTERPRETER = 1 << 1,
41 // An initial environment has been pushed on the environment chain for
42 // function frames that need a CallObject or eval frames that need a
43 // VarEnvironmentObject.
44 HAS_INITIAL_ENV = 1 << 2,
46 // Frame has an arguments object, argsObj_.
47 HAS_ARGS_OBJ = 1 << 4,
49 // See InterpreterFrame::PREV_UP_TO_DATE.
50 PREV_UP_TO_DATE = 1 << 5,
52 // Frame has execution observed by a Debugger.
54 // See comment above 'isDebuggee' in vm/Realm.h for explanation
55 // of invariants of debuggee compartments, scripts, and frames.
56 DEBUGGEE = 1 << 6,
59 protected: // Silence Clang warning about unused private fields.
60 // The fields below are only valid if RUNNING_IN_INTERPRETER.
61 JSScript* interpreterScript_;
62 jsbytecode* interpreterPC_;
63 ICEntry* interpreterICEntry_;
65 JSObject* envChain_; // Environment chain (always initialized).
66 ICScript* icScript_; // IC script (initialized if Warp is enabled).
67 ArgumentsObject* argsObj_; // If HAS_ARGS_OBJ, the arguments object.
69 // We need to split the Value into 2 fields of 32 bits, otherwise the C++
70 // compiler may add some padding between the fields.
71 uint32_t loScratchValue_;
72 uint32_t hiScratchValue_;
73 uint32_t flags_;
74 #ifdef DEBUG
75 // Size of the frame. Stored in DEBUG builds when calling into C++. This is
76 // BaselineFrame::Size() + the size of the local and expression stack Values.
78 // We don't store this in release builds because it's redundant with the frame
79 // size computed from the frame pointers. In debug builds it's still useful
80 // for assertions.
81 uint32_t debugFrameSize_;
82 #else
83 uint32_t unused_;
84 #endif
85 uint32_t loReturnValue_; // If HAS_RVAL, the frame's return value.
86 uint32_t hiReturnValue_;
88 public:
89 [[nodiscard]] bool initForOsr(InterpreterFrame* fp, uint32_t numStackValues);
91 #ifdef DEBUG
92 uint32_t debugFrameSize() const { return debugFrameSize_; }
93 void setDebugFrameSize(uint32_t frameSize) { debugFrameSize_ = frameSize; }
94 #endif
96 JSObject* environmentChain() const { return envChain_; }
97 void setEnvironmentChain(JSObject* envChain) { envChain_ = envChain; }
99 template <typename SpecificEnvironment>
100 inline void pushOnEnvironmentChain(SpecificEnvironment& env);
101 template <typename SpecificEnvironment>
102 inline void popOffEnvironmentChain();
103 inline void replaceInnermostEnvironment(EnvironmentObject& env);
105 CalleeToken calleeToken() const { return framePrefix()->calleeToken(); }
106 void replaceCalleeToken(CalleeToken token) {
107 framePrefix()->replaceCalleeToken(token);
109 bool isConstructing() const {
110 return CalleeTokenIsConstructing(calleeToken());
112 JSScript* script() const {
113 return MaybeForwardedScriptFromCalleeToken(calleeToken());
115 JSFunction* callee() const { return CalleeTokenToFunction(calleeToken()); }
116 Value calleev() const { return ObjectValue(*callee()); }
118 size_t numValueSlots(size_t frameSize) const {
119 MOZ_ASSERT(frameSize == debugFrameSize());
121 MOZ_ASSERT(frameSize >= BaselineFrame::Size());
122 frameSize -= BaselineFrame::Size();
124 MOZ_ASSERT((frameSize % sizeof(Value)) == 0);
125 return frameSize / sizeof(Value);
128 Value newTarget() const {
129 MOZ_ASSERT(isFunctionFrame());
130 MOZ_ASSERT(!callee()->isArrow());
132 if (isConstructing()) {
133 unsigned pushedArgs = std::max(numFormalArgs(), numActualArgs());
134 return argv()[pushedArgs];
136 return UndefinedValue();
139 #ifdef DEBUG
140 size_t debugNumValueSlots() const { return numValueSlots(debugFrameSize()); }
141 #endif
143 Value* valueSlot(size_t slot) const {
144 #ifndef ENABLE_PORTABLE_BASELINE_INTERP
145 // Assert that we're within the frame, but only if the "debug
146 // frame size" has been set. Ordinarily if we are in C++ code
147 // looking upward at a baseline frame, it will be, because it is
148 // set for the *previous* frame when we push an exit frame and
149 // call back into C++ from generated baseline code. However, the
150 // portable baseline interpreter uses accessors on BaselineFrame
151 // directly within the active frame and so the "debug frame size"
152 // hasn't been set (and it would be expensive to constantly update
153 // it). Because this is only used for assertions, and is not
154 // needed for correctness, we can disable this check below when
155 // PBL is enabled.
156 MOZ_ASSERT(slot < debugNumValueSlots());
157 #endif
158 return (Value*)this - (slot + 1);
161 static size_t frameSizeForNumValueSlots(size_t numValueSlots) {
162 return BaselineFrame::Size() + numValueSlots * sizeof(Value);
165 Value& unaliasedFormal(
166 unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
167 MOZ_ASSERT(i < numFormalArgs());
168 MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals() &&
169 !script()->formalIsAliased(i));
170 return argv()[i];
173 Value& unaliasedActual(
174 unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
175 MOZ_ASSERT(i < numActualArgs());
176 MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
177 MOZ_ASSERT_IF(checkAliasing && i < numFormalArgs(),
178 !script()->formalIsAliased(i));
179 return argv()[i];
182 Value& unaliasedLocal(uint32_t i) const {
183 MOZ_ASSERT(i < script()->nfixed());
184 return *valueSlot(i);
187 unsigned numActualArgs() const { return framePrefix()->numActualArgs(); }
188 unsigned numFormalArgs() const { return script()->function()->nargs(); }
189 Value& thisArgument() const {
190 MOZ_ASSERT(isFunctionFrame());
191 return framePrefix()->thisv();
193 Value* argv() const { return framePrefix()->actualArgs(); }
195 [[nodiscard]] bool saveGeneratorSlots(JSContext* cx, unsigned nslots,
196 ArrayObject* dest) const;
198 public:
199 void prepareForBaselineInterpreterToJitOSR() {
200 // Clearing the RUNNING_IN_INTERPRETER flag is sufficient, but we also null
201 // out the interpreter fields to ensure we don't use stale values.
202 flags_ &= ~RUNNING_IN_INTERPRETER;
203 interpreterScript_ = nullptr;
204 interpreterPC_ = nullptr;
207 private:
208 bool uninlineIsProfilerSamplingEnabled(JSContext* cx);
210 public:
211 // Switch a JIT frame on the stack to Interpreter mode. The caller is
212 // responsible for patching the return address into this frame to a location
213 // in the interpreter code. Also assert profiler sampling has been suppressed
214 // so the sampler thread doesn't see an inconsistent state while we are
215 // patching frames.
216 void switchFromJitToInterpreter(JSContext* cx, jsbytecode* pc) {
217 MOZ_ASSERT(!uninlineIsProfilerSamplingEnabled(cx));
218 MOZ_ASSERT(!runningInInterpreter());
219 flags_ |= RUNNING_IN_INTERPRETER;
220 setInterpreterFields(pc);
222 void switchFromJitToInterpreterAtPrologue(JSContext* cx) {
223 MOZ_ASSERT(!uninlineIsProfilerSamplingEnabled(cx));
224 MOZ_ASSERT(!runningInInterpreter());
225 flags_ |= RUNNING_IN_INTERPRETER;
226 setInterpreterFieldsForPrologue(script());
229 // Like switchFromJitToInterpreter, but set the interpreterICEntry_ field to
230 // nullptr. Initializing this field requires a binary search on the
231 // JitScript's ICEntry list but the exception handler never returns to this
232 // pc anyway so we can avoid the overhead.
233 void switchFromJitToInterpreterForExceptionHandler(JSContext* cx,
234 jsbytecode* pc) {
235 MOZ_ASSERT(!uninlineIsProfilerSamplingEnabled(cx));
236 MOZ_ASSERT(!runningInInterpreter());
237 flags_ |= RUNNING_IN_INTERPRETER;
238 interpreterScript_ = script();
239 interpreterPC_ = pc;
240 interpreterICEntry_ = nullptr;
243 bool runningInInterpreter() const { return flags_ & RUNNING_IN_INTERPRETER; }
245 JSScript* interpreterScript() const {
246 MOZ_ASSERT(runningInInterpreter());
247 return interpreterScript_;
250 jsbytecode* interpreterPC() const {
251 MOZ_ASSERT(runningInInterpreter());
252 return interpreterPC_;
254 jsbytecode*& interpreterPC() {
255 MOZ_ASSERT(runningInInterpreter());
256 return interpreterPC_;
259 ICEntry* interpreterICEntry() const {
260 MOZ_ASSERT(runningInInterpreter());
261 return interpreterICEntry_;
263 ICEntry*& interpreterICEntry() {
264 MOZ_ASSERT(runningInInterpreter());
265 return interpreterICEntry_;
268 void setInterpreterFields(JSScript* script, jsbytecode* pc);
270 void setInterpreterFields(jsbytecode* pc) {
271 setInterpreterFields(script(), pc);
274 // Initialize interpreter fields for resuming in the prologue (before the
275 // argument type check ICs).
276 void setInterpreterFieldsForPrologue(JSScript* script);
278 ICScript* icScript() const { return icScript_; }
279 void setICScript(ICScript* icScript) { icScript_ = icScript; }
281 // The script that owns the current ICScript.
282 JSScript* outerScript() const;
284 bool hasReturnValue() const { return flags_ & HAS_RVAL; }
285 MutableHandleValue returnValue() {
286 if (!hasReturnValue()) {
287 addressOfReturnValue()->setUndefined();
289 return MutableHandleValue::fromMarkedLocation(addressOfReturnValue());
291 void setReturnValue(const Value& v) {
292 returnValue().set(v);
293 flags_ |= HAS_RVAL;
295 inline Value* addressOfReturnValue() {
296 return reinterpret_cast<Value*>(&loReturnValue_);
299 bool hasInitialEnvironment() const { return flags_ & HAS_INITIAL_ENV; }
301 inline CallObject& callObj() const;
303 void setFlag(uint32_t flag) { flags_ |= flag; }
304 void setFlags(uint32_t flags) { flags_ = flags; }
306 [[nodiscard]] inline bool pushLexicalEnvironment(JSContext* cx,
307 Handle<LexicalScope*> scope);
308 template <bool IsDebuggee>
309 [[nodiscard]] inline bool freshenLexicalEnvironment(
310 JSContext* cx, const jsbytecode* pc = nullptr);
311 template <bool IsDebuggee>
312 [[nodiscard]] inline bool recreateLexicalEnvironment(
313 JSContext* cx, const jsbytecode* pc = nullptr);
315 [[nodiscard]] bool initFunctionEnvironmentObjects(JSContext* cx);
316 [[nodiscard]] bool pushClassBodyEnvironment(JSContext* cx,
317 Handle<ClassBodyScope*> scope);
318 [[nodiscard]] bool pushVarEnvironment(JSContext* cx, Handle<Scope*> scope);
320 void initArgsObjUnchecked(ArgumentsObject& argsobj) {
321 flags_ |= HAS_ARGS_OBJ;
322 argsObj_ = &argsobj;
324 void initArgsObj(ArgumentsObject& argsobj) {
325 MOZ_ASSERT(script()->needsArgsObj());
326 initArgsObjUnchecked(argsobj);
328 bool hasArgsObj() const { return flags_ & HAS_ARGS_OBJ; }
329 ArgumentsObject& argsObj() const {
330 MOZ_ASSERT(hasArgsObj());
331 MOZ_ASSERT(script()->needsArgsObj());
332 return *argsObj_;
335 bool prevUpToDate() const { return flags_ & PREV_UP_TO_DATE; }
336 void setPrevUpToDate() { flags_ |= PREV_UP_TO_DATE; }
337 void unsetPrevUpToDate() { flags_ &= ~PREV_UP_TO_DATE; }
339 bool isDebuggee() const { return flags_ & DEBUGGEE; }
340 void setIsDebuggee() { flags_ |= DEBUGGEE; }
341 inline void unsetIsDebuggee();
343 void trace(JSTracer* trc, const JSJitFrameIter& frame);
345 bool isGlobalFrame() const { return script()->isGlobalCode(); }
346 bool isModuleFrame() const { return script()->isModule(); }
347 bool isEvalFrame() const { return script()->isForEval(); }
348 bool isFunctionFrame() const {
349 return CalleeTokenIsFunction(calleeToken()) && !isModuleFrame();
351 bool isDebuggerEvalFrame() const { return false; }
353 JitFrameLayout* framePrefix() const {
354 uint8_t* fp = (uint8_t*)this + Size();
355 return (JitFrameLayout*)fp;
358 static size_t Size() { return sizeof(BaselineFrame); }
360 // The reverseOffsetOf methods below compute the offset relative to the
361 // frame's base pointer. Since the stack grows down, these offsets are
362 // negative.
364 #ifdef DEBUG
365 static int reverseOffsetOfDebugFrameSize() {
366 return -int(Size()) + offsetof(BaselineFrame, debugFrameSize_);
368 #endif
370 // The scratch value slot can either be used as a Value slot or as two
371 // separate 32-bit integer slots.
372 static int reverseOffsetOfScratchValueLow32() {
373 return -int(Size()) + offsetof(BaselineFrame, loScratchValue_);
375 static int reverseOffsetOfScratchValueHigh32() {
376 return -int(Size()) + offsetof(BaselineFrame, hiScratchValue_);
378 static int reverseOffsetOfScratchValue() {
379 return reverseOffsetOfScratchValueLow32();
382 static int reverseOffsetOfEnvironmentChain() {
383 return -int(Size()) + offsetof(BaselineFrame, envChain_);
385 static int reverseOffsetOfArgsObj() {
386 return -int(Size()) + offsetof(BaselineFrame, argsObj_);
388 static int reverseOffsetOfFlags() {
389 return -int(Size()) + offsetof(BaselineFrame, flags_);
391 static int reverseOffsetOfReturnValue() {
392 return -int(Size()) + offsetof(BaselineFrame, loReturnValue_);
394 static int reverseOffsetOfInterpreterScript() {
395 return -int(Size()) + offsetof(BaselineFrame, interpreterScript_);
397 static int reverseOffsetOfInterpreterPC() {
398 return -int(Size()) + offsetof(BaselineFrame, interpreterPC_);
400 static int reverseOffsetOfInterpreterICEntry() {
401 return -int(Size()) + offsetof(BaselineFrame, interpreterICEntry_);
403 static int reverseOffsetOfICScript() {
404 return -int(Size()) + offsetof(BaselineFrame, icScript_);
406 static int reverseOffsetOfLocal(size_t index) {
407 return -int(Size()) - (index + 1) * sizeof(Value);
411 // Ensure the frame is 8-byte aligned (required on ARM).
412 static_assert((sizeof(BaselineFrame) % 8) == 0, "frame must be 8-byte aligned");
414 } // namespace jit
415 } // namespace js
417 #endif /* jit_BaselineFrame_h */