1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * vim: set ts=8 sts=4 et sw=4 tw=99: 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_BaselineFrame_h 8 #define jit_BaselineFrame_h 9 10 #include "jit/JitFrames.h" 11 #include "vm/Stack.h" 12 13 namespace js { 14 namespace jit { 15 16 struct BaselineDebugModeOSRInfo; 17 18 // The stack looks like this, fp is the frame pointer: 19 // 20 // fp+y arguments 21 // fp+x JitFrameLayout (frame header) 22 // fp => saved frame pointer 23 // fp-x BaselineFrame 24 // locals 25 // stack values 26 27 class BaselineFrame { 28 public: 29 enum Flags : uint32_t { 30 // The frame has a valid return value. See also InterpreterFrame::HAS_RVAL. 31 HAS_RVAL = 1 << 0, 32 33 // An initial environment has been pushed on the environment chain for 34 // function frames that need a CallObject or eval frames that need a 35 // VarEnvironmentObject. 36 HAS_INITIAL_ENV = 1 << 2, 37 38 // Frame has an arguments object, argsObj_. 39 HAS_ARGS_OBJ = 1 << 4, 40 41 // See InterpreterFrame::PREV_UP_TO_DATE. 42 PREV_UP_TO_DATE = 1 << 5, 43 44 // Frame has execution observed by a Debugger. 45 // 46 // See comment above 'isDebuggee' in vm/JSCompartment.h for explanation 47 // of invariants of debuggee compartments, scripts, and frames. 48 DEBUGGEE = 1 << 6, 49 50 // (1 << 7 and 1 << 8 are unused) 51 52 // Frame has over-recursed on an early check. 53 OVER_RECURSED = 1 << 9, 54 55 // Frame has a BaselineRecompileInfo stashed in the scratch value 56 // slot. See PatchBaselineFramesForDebugMode. 57 HAS_DEBUG_MODE_OSR_INFO = 1 << 10, 58 59 // This flag is intended for use whenever the frame is settled on a 60 // native code address without a corresponding ICEntry. In this case, 61 // the frame contains an explicit bytecode offset for frame iterators. 62 // 63 // There can also be an override pc if the frame has had its 64 // environment chain unwound to a pc during exception handling that is 65 // different from its current pc. 66 // 67 // This flag should never be set when we're executing JIT code. 68 HAS_OVERRIDE_PC = 1 << 11, 69 70 // If set, we're handling an exception for this frame. This is set for 71 // debug mode OSR sanity checking when it handles corner cases which 72 // only arise during exception handling. 73 HANDLING_EXCEPTION = 1 << 12, 74 }; 75 76 protected: // Silence Clang warning about unused private fields. 77 // We need to split the Value into 2 fields of 32 bits, otherwise the C++ 78 // compiler may add some padding between the fields. 79 80 union { 81 struct { 82 uint32_t loScratchValue_; 83 uint32_t hiScratchValue_; 84 }; 85 BaselineDebugModeOSRInfo* debugModeOSRInfo_; 86 }; 87 uint32_t loReturnValue_; // If HAS_RVAL, the frame's return value. 88 uint32_t hiReturnValue_; 89 uint32_t frameSize_; 90 JSObject* envChain_; // Environment chain (always initialized). 91 ArgumentsObject* argsObj_; // If HAS_ARGS_OBJ, the arguments object. 92 uint32_t overrideOffset_; // If HAS_OVERRIDE_PC, the bytecode offset. 93 uint32_t flags_; 94 95 public: 96 // Distance between the frame pointer and the frame header (return address). 97 // This is the old frame pointer saved in the prologue. 98 static const uint32_t FramePointerOffset = sizeof(void*); 99 100 MOZ_MUST_USE bool initForOsr(InterpreterFrame* fp, uint32_t numStackValues); 101 frameSize()102 uint32_t frameSize() const { return frameSize_; } setFrameSize(uint32_t frameSize)103 void setFrameSize(uint32_t frameSize) { frameSize_ = frameSize; } addressOfFrameSize()104 inline uint32_t* addressOfFrameSize() { return &frameSize_; } environmentChain()105 JSObject* environmentChain() const { return envChain_; } setEnvironmentChain(JSObject * envChain)106 void setEnvironmentChain(JSObject* envChain) { envChain_ = envChain; } addressOfEnvironmentChain()107 inline JSObject** addressOfEnvironmentChain() { return &envChain_; } 108 addressOfScratchValue()109 inline Value* addressOfScratchValue() { 110 return reinterpret_cast<Value*>(&loScratchValue_); 111 } 112 113 template <typename SpecificEnvironment> 114 inline void pushOnEnvironmentChain(SpecificEnvironment& env); 115 template <typename SpecificEnvironment> 116 inline void popOffEnvironmentChain(); 117 inline void replaceInnermostEnvironment(EnvironmentObject& env); 118 calleeToken()119 CalleeToken calleeToken() const { 120 uint8_t* pointer = (uint8_t*)this + Size() + offsetOfCalleeToken(); 121 return *(CalleeToken*)pointer; 122 } replaceCalleeToken(CalleeToken token)123 void replaceCalleeToken(CalleeToken token) { 124 uint8_t* pointer = (uint8_t*)this + Size() + offsetOfCalleeToken(); 125 *(CalleeToken*)pointer = token; 126 } isConstructing()127 bool isConstructing() const { 128 return CalleeTokenIsConstructing(calleeToken()); 129 } script()130 JSScript* script() const { return ScriptFromCalleeToken(calleeToken()); } callee()131 JSFunction* callee() const { return CalleeTokenToFunction(calleeToken()); } calleev()132 Value calleev() const { return ObjectValue(*callee()); } numValueSlots()133 size_t numValueSlots() const { 134 size_t size = frameSize(); 135 136 MOZ_ASSERT(size >= 137 BaselineFrame::FramePointerOffset + BaselineFrame::Size()); 138 size -= BaselineFrame::FramePointerOffset + BaselineFrame::Size(); 139 140 MOZ_ASSERT((size % sizeof(Value)) == 0); 141 return size / sizeof(Value); 142 } valueSlot(size_t slot)143 Value* valueSlot(size_t slot) const { 144 MOZ_ASSERT(slot < numValueSlots()); 145 return (Value*)this - (slot + 1); 146 } 147 148 Value& unaliasedFormal( 149 unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { 150 MOZ_ASSERT(i < numFormalArgs()); 151 MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals() && 152 !script()->formalIsAliased(i)); 153 return argv()[i]; 154 } 155 156 Value& unaliasedActual( 157 unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { 158 MOZ_ASSERT(i < numActualArgs()); 159 MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals()); 160 MOZ_ASSERT_IF(checkAliasing && i < numFormalArgs(), 161 !script()->formalIsAliased(i)); 162 return argv()[i]; 163 } 164 unaliasedLocal(uint32_t i)165 Value& unaliasedLocal(uint32_t i) const { 166 MOZ_ASSERT(i < script()->nfixed()); 167 return *valueSlot(i); 168 } 169 numActualArgs()170 unsigned numActualArgs() const { 171 return *(size_t*)(reinterpret_cast<const uint8_t*>(this) + 172 BaselineFrame::Size() + offsetOfNumActualArgs()); 173 } numFormalArgs()174 unsigned numFormalArgs() const { 175 return script()->functionNonDelazifying()->nargs(); 176 } thisArgument()177 Value& thisArgument() const { 178 MOZ_ASSERT(isFunctionFrame()); 179 return *(Value*)(reinterpret_cast<const uint8_t*>(this) + 180 BaselineFrame::Size() + offsetOfThis()); 181 } argv()182 Value* argv() const { 183 return (Value*)(reinterpret_cast<const uint8_t*>(this) + 184 BaselineFrame::Size() + offsetOfArg(0)); 185 } 186 187 private: evalNewTargetAddress()188 Value* evalNewTargetAddress() const { 189 MOZ_ASSERT(isEvalFrame()); 190 MOZ_ASSERT(script()->isDirectEvalInFunction()); 191 return (Value*)(reinterpret_cast<const uint8_t*>(this) + 192 BaselineFrame::Size() + offsetOfEvalNewTarget()); 193 } 194 195 public: newTarget()196 Value newTarget() const { 197 if (isEvalFrame()) return *evalNewTargetAddress(); 198 MOZ_ASSERT(isFunctionFrame()); 199 if (callee()->isArrow()) 200 return callee()->getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT); 201 if (isConstructing()) { 202 return *(Value*)(reinterpret_cast<const uint8_t*>(this) + 203 BaselineFrame::Size() + 204 offsetOfArg(Max(numFormalArgs(), numActualArgs()))); 205 } 206 return UndefinedValue(); 207 } 208 hasReturnValue()209 bool hasReturnValue() const { return flags_ & HAS_RVAL; } returnValue()210 MutableHandleValue returnValue() { 211 if (!hasReturnValue()) addressOfReturnValue()->setUndefined(); 212 return MutableHandleValue::fromMarkedLocation(addressOfReturnValue()); 213 } setReturnValue(const Value & v)214 void setReturnValue(const Value& v) { 215 returnValue().set(v); 216 flags_ |= HAS_RVAL; 217 } addressOfReturnValue()218 inline Value* addressOfReturnValue() { 219 return reinterpret_cast<Value*>(&loReturnValue_); 220 } 221 hasInitialEnvironment()222 bool hasInitialEnvironment() const { return flags_ & HAS_INITIAL_ENV; } 223 224 inline CallObject& callObj() const; 225 setFlags(uint32_t flags)226 void setFlags(uint32_t flags) { flags_ = flags; } addressOfFlags()227 uint32_t* addressOfFlags() { return &flags_; } 228 229 inline MOZ_MUST_USE bool pushLexicalEnvironment(JSContext* cx, 230 Handle<LexicalScope*> scope); 231 inline MOZ_MUST_USE bool freshenLexicalEnvironment(JSContext* cx); 232 inline MOZ_MUST_USE bool recreateLexicalEnvironment(JSContext* cx); 233 234 MOZ_MUST_USE bool initFunctionEnvironmentObjects(JSContext* cx); 235 MOZ_MUST_USE bool pushVarEnvironment(JSContext* cx, HandleScope scope); 236 initArgsObjUnchecked(ArgumentsObject & argsobj)237 void initArgsObjUnchecked(ArgumentsObject& argsobj) { 238 flags_ |= HAS_ARGS_OBJ; 239 argsObj_ = &argsobj; 240 } initArgsObj(ArgumentsObject & argsobj)241 void initArgsObj(ArgumentsObject& argsobj) { 242 MOZ_ASSERT(script()->needsArgsObj()); 243 initArgsObjUnchecked(argsobj); 244 } hasArgsObj()245 bool hasArgsObj() const { return flags_ & HAS_ARGS_OBJ; } argsObj()246 ArgumentsObject& argsObj() const { 247 MOZ_ASSERT(hasArgsObj()); 248 MOZ_ASSERT(script()->needsArgsObj()); 249 return *argsObj_; 250 } 251 prevUpToDate()252 bool prevUpToDate() const { return flags_ & PREV_UP_TO_DATE; } setPrevUpToDate()253 void setPrevUpToDate() { flags_ |= PREV_UP_TO_DATE; } unsetPrevUpToDate()254 void unsetPrevUpToDate() { flags_ &= ~PREV_UP_TO_DATE; } 255 isDebuggee()256 bool isDebuggee() const { return flags_ & DEBUGGEE; } setIsDebuggee()257 void setIsDebuggee() { flags_ |= DEBUGGEE; } 258 inline void unsetIsDebuggee(); 259 isHandlingException()260 bool isHandlingException() const { return flags_ & HANDLING_EXCEPTION; } setIsHandlingException()261 void setIsHandlingException() { flags_ |= HANDLING_EXCEPTION; } unsetIsHandlingException()262 void unsetIsHandlingException() { flags_ &= ~HANDLING_EXCEPTION; } 263 overRecursed()264 bool overRecursed() const { return flags_ & OVER_RECURSED; } 265 setOverRecursed()266 void setOverRecursed() { flags_ |= OVER_RECURSED; } 267 debugModeOSRInfo()268 BaselineDebugModeOSRInfo* debugModeOSRInfo() { 269 MOZ_ASSERT(flags_ & HAS_DEBUG_MODE_OSR_INFO); 270 return debugModeOSRInfo_; 271 } 272 getDebugModeOSRInfo()273 BaselineDebugModeOSRInfo* getDebugModeOSRInfo() { 274 if (flags_ & HAS_DEBUG_MODE_OSR_INFO) return debugModeOSRInfo(); 275 return nullptr; 276 } 277 setDebugModeOSRInfo(BaselineDebugModeOSRInfo * info)278 void setDebugModeOSRInfo(BaselineDebugModeOSRInfo* info) { 279 flags_ |= HAS_DEBUG_MODE_OSR_INFO; 280 debugModeOSRInfo_ = info; 281 } 282 283 void deleteDebugModeOSRInfo(); 284 285 // See the HAS_OVERRIDE_PC comment. hasOverridePc()286 bool hasOverridePc() const { return flags_ & HAS_OVERRIDE_PC; } 287 overridePc()288 jsbytecode* overridePc() const { 289 MOZ_ASSERT(hasOverridePc()); 290 return script()->offsetToPC(overrideOffset_); 291 } 292 maybeOverridePc()293 jsbytecode* maybeOverridePc() const { 294 if (hasOverridePc()) return overridePc(); 295 return nullptr; 296 } 297 setOverridePc(jsbytecode * pc)298 void setOverridePc(jsbytecode* pc) { 299 flags_ |= HAS_OVERRIDE_PC; 300 overrideOffset_ = script()->pcToOffset(pc); 301 } 302 clearOverridePc()303 void clearOverridePc() { flags_ &= ~HAS_OVERRIDE_PC; } 304 305 void trace(JSTracer* trc, const JSJitFrameIter& frame); 306 isGlobalFrame()307 bool isGlobalFrame() const { return script()->isGlobalCode(); } isModuleFrame()308 bool isModuleFrame() const { return script()->module(); } isEvalFrame()309 bool isEvalFrame() const { return script()->isForEval(); } isStrictEvalFrame()310 bool isStrictEvalFrame() const { return isEvalFrame() && script()->strict(); } isNonStrictEvalFrame()311 bool isNonStrictEvalFrame() const { 312 return isEvalFrame() && !script()->strict(); 313 } 314 bool isNonGlobalEvalFrame() const; isNonStrictDirectEvalFrame()315 bool isNonStrictDirectEvalFrame() const { 316 return isNonStrictEvalFrame() && isNonGlobalEvalFrame(); 317 } isFunctionFrame()318 bool isFunctionFrame() const { return CalleeTokenIsFunction(calleeToken()); } isDebuggerEvalFrame()319 bool isDebuggerEvalFrame() const { return false; } 320 framePrefix()321 JitFrameLayout* framePrefix() const { 322 uint8_t* fp = (uint8_t*)this + Size() + FramePointerOffset; 323 return (JitFrameLayout*)fp; 324 } 325 326 // Methods below are used by the compiler. offsetOfCalleeToken()327 static size_t offsetOfCalleeToken() { 328 return FramePointerOffset + js::jit::JitFrameLayout::offsetOfCalleeToken(); 329 } offsetOfThis()330 static size_t offsetOfThis() { 331 return FramePointerOffset + js::jit::JitFrameLayout::offsetOfThis(); 332 } offsetOfEvalNewTarget()333 static size_t offsetOfEvalNewTarget() { 334 return FramePointerOffset + 335 js::jit::JitFrameLayout::offsetOfEvalNewTarget(); 336 } offsetOfArg(size_t index)337 static size_t offsetOfArg(size_t index) { 338 return FramePointerOffset + 339 js::jit::JitFrameLayout::offsetOfActualArg(index); 340 } offsetOfNumActualArgs()341 static size_t offsetOfNumActualArgs() { 342 return FramePointerOffset + 343 js::jit::JitFrameLayout::offsetOfNumActualArgs(); 344 } Size()345 static size_t Size() { return sizeof(BaselineFrame); } 346 347 // The reverseOffsetOf methods below compute the offset relative to the 348 // frame's base pointer. Since the stack grows down, these offsets are 349 // negative. reverseOffsetOfFrameSize()350 static int reverseOffsetOfFrameSize() { 351 return -int(Size()) + offsetof(BaselineFrame, frameSize_); 352 } reverseOffsetOfScratchValue()353 static int reverseOffsetOfScratchValue() { 354 return -int(Size()) + offsetof(BaselineFrame, loScratchValue_); 355 } reverseOffsetOfEnvironmentChain()356 static int reverseOffsetOfEnvironmentChain() { 357 return -int(Size()) + offsetof(BaselineFrame, envChain_); 358 } reverseOffsetOfArgsObj()359 static int reverseOffsetOfArgsObj() { 360 return -int(Size()) + offsetof(BaselineFrame, argsObj_); 361 } reverseOffsetOfFlags()362 static int reverseOffsetOfFlags() { 363 return -int(Size()) + offsetof(BaselineFrame, flags_); 364 } reverseOffsetOfReturnValue()365 static int reverseOffsetOfReturnValue() { 366 return -int(Size()) + offsetof(BaselineFrame, loReturnValue_); 367 } reverseOffsetOfLocal(size_t index)368 static int reverseOffsetOfLocal(size_t index) { 369 return -int(Size()) - (index + 1) * sizeof(Value); 370 } 371 }; 372 373 // Ensure the frame is 8-byte aligned (required on ARM). 374 JS_STATIC_ASSERT(((sizeof(BaselineFrame) + BaselineFrame::FramePointerOffset) % 375 8) == 0); 376 377 } // namespace jit 378 } // namespace js 379 380 #endif /* jit_BaselineFrame_h */ 381