RematerializedFrame.h (7432B)
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 #ifndef jit_RematerializedFrame_h 8 #define jit_RematerializedFrame_h 9 10 #include "mozilla/Assertions.h" 11 12 #include <algorithm> 13 #include <stddef.h> 14 #include <stdint.h> 15 16 #include "jstypes.h" 17 18 #include "jit/JitFrames.h" 19 #include "jit/ScriptFromCalleeToken.h" 20 #include "js/GCVector.h" 21 #include "js/TypeDecls.h" 22 #include "js/UniquePtr.h" 23 #include "js/Value.h" 24 #include "vm/JSFunction.h" 25 #include "vm/JSScript.h" 26 #include "vm/Stack.h" 27 28 class JS_PUBLIC_API JSTracer; 29 30 namespace js { 31 32 class ArgumentsObject; 33 class CallObject; 34 35 namespace jit { 36 37 class InlineFrameIterator; 38 struct MaybeReadFallback; 39 40 // RematerializedFrame: An optimized frame that has been rematerialized with 41 // values read out of Snapshots. 42 // 43 // If the Debugger API tries to inspect or modify an IonMonkey frame, much of 44 // the information it expects to find in a frame is missing: function calls may 45 // have been inlined, variables may have been optimized out, and so on. So when 46 // this happens, SpiderMonkey builds one or more Rematerialized frames from the 47 // IonMonkey frame, using the snapshot metadata built by Ion to reconstruct the 48 // missing parts. The Rematerialized frames are now the authority on the state 49 // of those frames, and the Ion frame is ignored: stack iterators ignore the Ion 50 // frame, producing the Rematerialized frames in their stead; and when control 51 // returns to the Ion frame, we pop it, rebuild Baseline frames from the 52 // Rematerialized frames, and resume execution in Baseline. 53 class RematerializedFrame { 54 // See DebugScopes::updateLiveScopes. 55 bool prevUpToDate_; 56 57 // Propagated to the Baseline frame once this is popped. 58 bool isDebuggee_; 59 60 // Has an initial environment has been pushed on the environment chain for 61 // function frames that need a CallObject or eval frames that need a 62 // VarEnvironmentObject? 63 bool hasInitialEnv_; 64 65 // Is this frame constructing? 66 bool isConstructing_; 67 68 // If true, this frame has been on the stack when 69 // |js::SavedStacks::saveCurrentStack| was called, and so there is a 70 // |js::SavedFrame| object cached for this frame. 71 bool hasCachedSavedFrame_; 72 73 // The fp of the top frame associated with this possibly inlined frame. 74 uint8_t* top_; 75 76 // The bytecode at the time of rematerialization. 77 jsbytecode* pc_; 78 79 size_t frameNo_; 80 unsigned numActualArgs_; 81 82 JSScript* script_; 83 JSObject* envChain_; 84 JSFunction* callee_; 85 ArgumentsObject* argsObj_; 86 87 Value returnValue_; 88 Value thisArgument_; 89 Value slots_[1]; 90 91 RematerializedFrame(JSContext* cx, uint8_t* top, unsigned numActualArgs, 92 InlineFrameIterator& iter, MaybeReadFallback& fallback); 93 94 public: 95 static RematerializedFrame* New(JSContext* cx, uint8_t* top, 96 InlineFrameIterator& iter, 97 MaybeReadFallback& fallback); 98 99 // RematerializedFrame are allocated on non-GC heap, so use GCVector and 100 // UniquePtr to ensure they are traced and cleaned up correctly. 101 using RematerializedFrameVector = GCVector<UniquePtr<RematerializedFrame>>; 102 103 // Rematerialize all remaining frames pointed to by |iter| into |frames| 104 // in older-to-younger order, e.g., frames[0] is the oldest frame. 105 [[nodiscard]] static bool RematerializeInlineFrames( 106 JSContext* cx, uint8_t* top, InlineFrameIterator& iter, 107 MaybeReadFallback& fallback, RematerializedFrameVector& frames); 108 109 bool prevUpToDate() const { return prevUpToDate_; } 110 void setPrevUpToDate() { prevUpToDate_ = true; } 111 void unsetPrevUpToDate() { prevUpToDate_ = false; } 112 113 bool isDebuggee() const { return isDebuggee_; } 114 void setIsDebuggee() { isDebuggee_ = true; } 115 inline void unsetIsDebuggee(); 116 117 uint8_t* top() const { return top_; } 118 JSScript* outerScript() const { 119 JitFrameLayout* jsFrame = (JitFrameLayout*)top_; 120 return ScriptFromCalleeToken(jsFrame->calleeToken()); 121 } 122 jsbytecode* pc() const { return pc_; } 123 size_t frameNo() const { return frameNo_; } 124 bool inlined() const { return frameNo_ > 0; } 125 126 JSObject* environmentChain() const { return envChain_; } 127 128 template <typename SpecificEnvironment> 129 void pushOnEnvironmentChain(SpecificEnvironment& env) { 130 MOZ_ASSERT(*environmentChain() == env.enclosingEnvironment()); 131 envChain_ = &env; 132 if (IsFrameInitialEnvironment(this, env)) { 133 hasInitialEnv_ = true; 134 } 135 } 136 137 template <typename SpecificEnvironment> 138 void popOffEnvironmentChain() { 139 MOZ_ASSERT(envChain_->is<SpecificEnvironment>()); 140 envChain_ = &envChain_->as<SpecificEnvironment>().enclosingEnvironment(); 141 } 142 143 [[nodiscard]] bool initFunctionEnvironmentObjects(JSContext* cx); 144 [[nodiscard]] bool pushVarEnvironment(JSContext* cx, Handle<Scope*> scope); 145 146 bool hasInitialEnvironment() const { return hasInitialEnv_; } 147 CallObject& callObj() const; 148 149 bool hasArgsObj() const { return !!argsObj_; } 150 ArgumentsObject& argsObj() const { 151 MOZ_ASSERT(hasArgsObj()); 152 MOZ_ASSERT(script()->needsArgsObj()); 153 return *argsObj_; 154 } 155 156 bool isFunctionFrame() const { return script_->isFunction(); } 157 bool isGlobalFrame() const { return script_->isGlobalCode(); } 158 bool isModuleFrame() const { return script_->isModule(); } 159 160 JSScript* script() const { return script_; } 161 JSFunction* callee() const { 162 MOZ_ASSERT(isFunctionFrame()); 163 MOZ_ASSERT(callee_); 164 return callee_; 165 } 166 Value calleev() const { return ObjectValue(*callee()); } 167 Value& thisArgument() { return thisArgument_; } 168 169 bool isConstructing() const { return isConstructing_; } 170 171 bool hasCachedSavedFrame() const { return hasCachedSavedFrame_; } 172 173 void setHasCachedSavedFrame() { hasCachedSavedFrame_ = true; } 174 175 void clearHasCachedSavedFrame() { hasCachedSavedFrame_ = false; } 176 177 unsigned numFormalArgs() const { 178 return isFunctionFrame() ? callee()->nargs() : 0; 179 } 180 unsigned numActualArgs() const { return numActualArgs_; } 181 unsigned numArgSlots() const { 182 return (std::max)(numFormalArgs(), numActualArgs()); 183 } 184 185 Value* argv() { return slots_; } 186 Value* locals() { return slots_ + numArgSlots(); } 187 188 Value& unaliasedLocal(unsigned i) { 189 MOZ_ASSERT(i < script()->nfixed()); 190 return locals()[i]; 191 } 192 Value& unaliasedFormal(unsigned i, 193 MaybeCheckAliasing checkAliasing = CHECK_ALIASING) { 194 MOZ_ASSERT(i < numFormalArgs()); 195 MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals() && 196 !script()->formalIsAliased(i)); 197 return argv()[i]; 198 } 199 Value& unaliasedActual(unsigned i, 200 MaybeCheckAliasing checkAliasing = CHECK_ALIASING) { 201 MOZ_ASSERT(i < numActualArgs()); 202 MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals()); 203 MOZ_ASSERT_IF(checkAliasing && i < numFormalArgs(), 204 !script()->formalIsAliased(i)); 205 return argv()[i]; 206 } 207 208 void setReturnValue(const Value& value) { returnValue_ = value; } 209 210 Value& returnValue() { 211 MOZ_ASSERT(!script()->noScriptRval()); 212 return returnValue_; 213 } 214 215 void trace(JSTracer* trc); 216 void dump(); 217 }; 218 219 } // namespace jit 220 } // namespace js 221 222 #endif // jit_RematerializedFrame_h