1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/BaselineFrame.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,415 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jit_BaselineFrame_h 1.11 +#define jit_BaselineFrame_h 1.12 + 1.13 +#ifdef JS_ION 1.14 + 1.15 +#include "jit/IonFrames.h" 1.16 +#include "vm/Stack.h" 1.17 + 1.18 +namespace js { 1.19 +namespace jit { 1.20 + 1.21 +struct BaselineDebugModeOSRInfo; 1.22 + 1.23 +// The stack looks like this, fp is the frame pointer: 1.24 +// 1.25 +// fp+y arguments 1.26 +// fp+x IonJSFrameLayout (frame header) 1.27 +// fp => saved frame pointer 1.28 +// fp-x BaselineFrame 1.29 +// locals 1.30 +// stack values 1.31 + 1.32 +// Eval frames 1.33 +// 1.34 +// Like js::InterpreterFrame, every BaselineFrame is either a global frame 1.35 +// or a function frame. Both global and function frames can optionally 1.36 +// be "eval frames". The callee token for eval function frames is the 1.37 +// enclosing function. BaselineFrame::evalScript_ stores the eval script 1.38 +// itself. 1.39 +class BaselineFrame 1.40 +{ 1.41 + public: 1.42 + enum Flags { 1.43 + // The frame has a valid return value. See also InterpreterFrame::HAS_RVAL. 1.44 + HAS_RVAL = 1 << 0, 1.45 + 1.46 + // A call object has been pushed on the scope chain. 1.47 + HAS_CALL_OBJ = 1 << 2, 1.48 + 1.49 + // Frame has an arguments object, argsObj_. 1.50 + HAS_ARGS_OBJ = 1 << 4, 1.51 + 1.52 + // See InterpreterFrame::PREV_UP_TO_DATE. 1.53 + PREV_UP_TO_DATE = 1 << 5, 1.54 + 1.55 + // Eval frame, see the "eval frames" comment. 1.56 + EVAL = 1 << 6, 1.57 + 1.58 + // Frame has hookData_ set. 1.59 + HAS_HOOK_DATA = 1 << 7, 1.60 + 1.61 + // Frame has profiler entry pushed. 1.62 + HAS_PUSHED_SPS_FRAME = 1 << 8, 1.63 + 1.64 + // Frame has over-recursed on an early check. 1.65 + OVER_RECURSED = 1 << 9, 1.66 + 1.67 + // Frame has a BaselineRecompileInfo stashed in the scratch value 1.68 + // slot. See PatchBaselineFramesForDebugMOde. 1.69 + HAS_DEBUG_MODE_OSR_INFO = 1 << 10 1.70 + }; 1.71 + 1.72 + protected: // Silence Clang warning about unused private fields. 1.73 + // We need to split the Value into 2 fields of 32 bits, otherwise the C++ 1.74 + // compiler may add some padding between the fields. 1.75 + uint32_t loScratchValue_; 1.76 + uint32_t hiScratchValue_; 1.77 + uint32_t loReturnValue_; // If HAS_RVAL, the frame's return value. 1.78 + uint32_t hiReturnValue_; 1.79 + uint32_t frameSize_; 1.80 + JSObject *scopeChain_; // Scope chain (always initialized). 1.81 + JSScript *evalScript_; // If isEvalFrame(), the current eval script. 1.82 + ArgumentsObject *argsObj_; // If HAS_ARGS_OBJ, the arguments object. 1.83 + void *hookData_; // If HAS_HOOK_DATA, debugger call hook data. 1.84 + uint32_t flags_; 1.85 +#if JS_BITS_PER_WORD == 32 1.86 + uint32_t padding_; // Pad to 8-byte alignment. 1.87 +#endif 1.88 + 1.89 + public: 1.90 + // Distance between the frame pointer and the frame header (return address). 1.91 + // This is the old frame pointer saved in the prologue. 1.92 + static const uint32_t FramePointerOffset = sizeof(void *); 1.93 + 1.94 + bool initForOsr(InterpreterFrame *fp, uint32_t numStackValues); 1.95 + 1.96 + uint32_t frameSize() const { 1.97 + return frameSize_; 1.98 + } 1.99 + void setFrameSize(uint32_t frameSize) { 1.100 + frameSize_ = frameSize; 1.101 + } 1.102 + inline uint32_t *addressOfFrameSize() { 1.103 + return &frameSize_; 1.104 + } 1.105 + JSObject *scopeChain() const { 1.106 + return scopeChain_; 1.107 + } 1.108 + void setScopeChain(JSObject *scopeChain) { 1.109 + scopeChain_ = scopeChain; 1.110 + } 1.111 + inline JSObject **addressOfScopeChain() { 1.112 + return &scopeChain_; 1.113 + } 1.114 + 1.115 + inline Value *addressOfScratchValue() { 1.116 + return reinterpret_cast<Value *>(&loScratchValue_); 1.117 + } 1.118 + 1.119 + inline void pushOnScopeChain(ScopeObject &scope); 1.120 + inline void popOffScopeChain(); 1.121 + 1.122 + inline void popWith(JSContext *cx); 1.123 + 1.124 + CalleeToken calleeToken() const { 1.125 + uint8_t *pointer = (uint8_t *)this + Size() + offsetOfCalleeToken(); 1.126 + return *(CalleeToken *)pointer; 1.127 + } 1.128 + void replaceCalleeToken(CalleeToken token) { 1.129 + uint8_t *pointer = (uint8_t *)this + Size() + offsetOfCalleeToken(); 1.130 + *(CalleeToken *)pointer = token; 1.131 + } 1.132 + JSScript *script() const { 1.133 + if (isEvalFrame()) 1.134 + return evalScript(); 1.135 + return ScriptFromCalleeToken(calleeToken()); 1.136 + } 1.137 + JSFunction *fun() const { 1.138 + return CalleeTokenToFunction(calleeToken()); 1.139 + } 1.140 + JSFunction *maybeFun() const { 1.141 + return isFunctionFrame() ? fun() : nullptr; 1.142 + } 1.143 + JSFunction *callee() const { 1.144 + return CalleeTokenToFunction(calleeToken()); 1.145 + } 1.146 + Value calleev() const { 1.147 + return ObjectValue(*callee()); 1.148 + } 1.149 + size_t numValueSlots() const { 1.150 + size_t size = frameSize(); 1.151 + 1.152 + JS_ASSERT(size >= BaselineFrame::FramePointerOffset + BaselineFrame::Size()); 1.153 + size -= BaselineFrame::FramePointerOffset + BaselineFrame::Size(); 1.154 + 1.155 + JS_ASSERT((size % sizeof(Value)) == 0); 1.156 + return size / sizeof(Value); 1.157 + } 1.158 + Value *valueSlot(size_t slot) const { 1.159 + JS_ASSERT(slot < numValueSlots()); 1.160 + return (Value *)this - (slot + 1); 1.161 + } 1.162 + 1.163 + Value &unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { 1.164 + JS_ASSERT(i < script()->nfixedvars()); 1.165 + JS_ASSERT_IF(checkAliasing, !script()->varIsAliased(i)); 1.166 + return *valueSlot(i); 1.167 + } 1.168 + 1.169 + Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { 1.170 + JS_ASSERT(i < numFormalArgs()); 1.171 + JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals() && 1.172 + !script()->formalIsAliased(i)); 1.173 + return argv()[i]; 1.174 + } 1.175 + 1.176 + Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { 1.177 + JS_ASSERT(i < numActualArgs()); 1.178 + JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals()); 1.179 + JS_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i)); 1.180 + return argv()[i]; 1.181 + } 1.182 + 1.183 + Value &unaliasedLocal(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { 1.184 + JS_ASSERT(i < script()->nfixed()); 1.185 +#ifdef DEBUG 1.186 + CheckLocalUnaliased(checkAliasing, script(), i); 1.187 +#endif 1.188 + return *valueSlot(i); 1.189 + } 1.190 + 1.191 + unsigned numActualArgs() const { 1.192 + return *(size_t *)(reinterpret_cast<const uint8_t *>(this) + 1.193 + BaselineFrame::Size() + 1.194 + offsetOfNumActualArgs()); 1.195 + } 1.196 + unsigned numFormalArgs() const { 1.197 + return script()->functionNonDelazifying()->nargs(); 1.198 + } 1.199 + Value &thisValue() const { 1.200 + return *(Value *)(reinterpret_cast<const uint8_t *>(this) + 1.201 + BaselineFrame::Size() + 1.202 + offsetOfThis()); 1.203 + } 1.204 + Value *argv() const { 1.205 + return (Value *)(reinterpret_cast<const uint8_t *>(this) + 1.206 + BaselineFrame::Size() + 1.207 + offsetOfArg(0)); 1.208 + } 1.209 + 1.210 + bool copyRawFrameSlots(AutoValueVector *vec) const; 1.211 + 1.212 + bool hasReturnValue() const { 1.213 + return flags_ & HAS_RVAL; 1.214 + } 1.215 + MutableHandleValue returnValue() { 1.216 + return MutableHandleValue::fromMarkedLocation(reinterpret_cast<Value *>(&loReturnValue_)); 1.217 + } 1.218 + void setReturnValue(const Value &v) { 1.219 + flags_ |= HAS_RVAL; 1.220 + returnValue().set(v); 1.221 + } 1.222 + inline Value *addressOfReturnValue() { 1.223 + return reinterpret_cast<Value *>(&loReturnValue_); 1.224 + } 1.225 + 1.226 + bool hasCallObj() const { 1.227 + return flags_ & HAS_CALL_OBJ; 1.228 + } 1.229 + 1.230 + inline CallObject &callObj() const; 1.231 + 1.232 + void setFlags(uint32_t flags) { 1.233 + flags_ = flags; 1.234 + } 1.235 + uint32_t *addressOfFlags() { 1.236 + return &flags_; 1.237 + } 1.238 + 1.239 + inline bool pushBlock(JSContext *cx, Handle<StaticBlockObject *> block); 1.240 + inline void popBlock(JSContext *cx); 1.241 + 1.242 + bool strictEvalPrologue(JSContext *cx); 1.243 + bool heavyweightFunPrologue(JSContext *cx); 1.244 + bool initFunctionScopeObjects(JSContext *cx); 1.245 + 1.246 + void initArgsObjUnchecked(ArgumentsObject &argsobj) { 1.247 + flags_ |= HAS_ARGS_OBJ; 1.248 + argsObj_ = &argsobj; 1.249 + } 1.250 + void initArgsObj(ArgumentsObject &argsobj) { 1.251 + JS_ASSERT(script()->needsArgsObj()); 1.252 + initArgsObjUnchecked(argsobj); 1.253 + } 1.254 + bool hasArgsObj() const { 1.255 + return flags_ & HAS_ARGS_OBJ; 1.256 + } 1.257 + ArgumentsObject &argsObj() const { 1.258 + JS_ASSERT(hasArgsObj()); 1.259 + JS_ASSERT(script()->needsArgsObj()); 1.260 + return *argsObj_; 1.261 + } 1.262 + 1.263 + bool prevUpToDate() const { 1.264 + return flags_ & PREV_UP_TO_DATE; 1.265 + } 1.266 + void setPrevUpToDate() { 1.267 + flags_ |= PREV_UP_TO_DATE; 1.268 + } 1.269 + 1.270 + JSScript *evalScript() const { 1.271 + JS_ASSERT(isEvalFrame()); 1.272 + return evalScript_; 1.273 + } 1.274 + 1.275 + bool hasHookData() const { 1.276 + return flags_ & HAS_HOOK_DATA; 1.277 + } 1.278 + 1.279 + void *maybeHookData() const { 1.280 + return hasHookData() ? hookData_ : nullptr; 1.281 + } 1.282 + 1.283 + void setHookData(void *v) { 1.284 + hookData_ = v; 1.285 + flags_ |= HAS_HOOK_DATA; 1.286 + } 1.287 + 1.288 + bool hasPushedSPSFrame() const { 1.289 + return flags_ & HAS_PUSHED_SPS_FRAME; 1.290 + } 1.291 + 1.292 + void setPushedSPSFrame() { 1.293 + flags_ |= HAS_PUSHED_SPS_FRAME; 1.294 + } 1.295 + 1.296 + void unsetPushedSPSFrame() { 1.297 + flags_ &= ~HAS_PUSHED_SPS_FRAME; 1.298 + } 1.299 + 1.300 + bool overRecursed() const { 1.301 + return flags_ & OVER_RECURSED; 1.302 + } 1.303 + 1.304 + void setOverRecursed() { 1.305 + flags_ |= OVER_RECURSED; 1.306 + } 1.307 + 1.308 + BaselineDebugModeOSRInfo *debugModeOSRInfo() { 1.309 + MOZ_ASSERT(flags_ & HAS_DEBUG_MODE_OSR_INFO); 1.310 + return *reinterpret_cast<BaselineDebugModeOSRInfo **>(&loScratchValue_); 1.311 + } 1.312 + 1.313 + BaselineDebugModeOSRInfo *getDebugModeOSRInfo() { 1.314 + if (flags_ & HAS_DEBUG_MODE_OSR_INFO) 1.315 + return debugModeOSRInfo(); 1.316 + return nullptr; 1.317 + } 1.318 + 1.319 + void setDebugModeOSRInfo(BaselineDebugModeOSRInfo *info) { 1.320 + flags_ |= HAS_DEBUG_MODE_OSR_INFO; 1.321 + *reinterpret_cast<BaselineDebugModeOSRInfo **>(&loScratchValue_) = info; 1.322 + } 1.323 + 1.324 + void deleteDebugModeOSRInfo(); 1.325 + 1.326 + void trace(JSTracer *trc, JitFrameIterator &frame); 1.327 + 1.328 + bool isFunctionFrame() const { 1.329 + return CalleeTokenIsFunction(calleeToken()); 1.330 + } 1.331 + bool isGlobalFrame() const { 1.332 + return !CalleeTokenIsFunction(calleeToken()); 1.333 + } 1.334 + bool isEvalFrame() const { 1.335 + return flags_ & EVAL; 1.336 + } 1.337 + bool isStrictEvalFrame() const { 1.338 + return isEvalFrame() && script()->strict(); 1.339 + } 1.340 + bool isNonStrictEvalFrame() const { 1.341 + return isEvalFrame() && !script()->strict(); 1.342 + } 1.343 + bool isDirectEvalFrame() const { 1.344 + return isEvalFrame() && script()->staticLevel() > 0; 1.345 + } 1.346 + bool isNonStrictDirectEvalFrame() const { 1.347 + return isNonStrictEvalFrame() && isDirectEvalFrame(); 1.348 + } 1.349 + bool isNonEvalFunctionFrame() const { 1.350 + return isFunctionFrame() && !isEvalFrame(); 1.351 + } 1.352 + bool isDebuggerFrame() const { 1.353 + return false; 1.354 + } 1.355 + bool isGeneratorFrame() const { 1.356 + return false; 1.357 + } 1.358 + 1.359 + IonJSFrameLayout *framePrefix() const { 1.360 + uint8_t *fp = (uint8_t *)this + Size() + FramePointerOffset; 1.361 + return (IonJSFrameLayout *)fp; 1.362 + } 1.363 + 1.364 + // Methods below are used by the compiler. 1.365 + static size_t offsetOfCalleeToken() { 1.366 + return FramePointerOffset + js::jit::IonJSFrameLayout::offsetOfCalleeToken(); 1.367 + } 1.368 + static size_t offsetOfThis() { 1.369 + return FramePointerOffset + js::jit::IonJSFrameLayout::offsetOfThis(); 1.370 + } 1.371 + static size_t offsetOfArg(size_t index) { 1.372 + return FramePointerOffset + js::jit::IonJSFrameLayout::offsetOfActualArg(index); 1.373 + } 1.374 + static size_t offsetOfNumActualArgs() { 1.375 + return FramePointerOffset + js::jit::IonJSFrameLayout::offsetOfNumActualArgs(); 1.376 + } 1.377 + static size_t Size() { 1.378 + return sizeof(BaselineFrame); 1.379 + } 1.380 + 1.381 + // The reverseOffsetOf methods below compute the offset relative to the 1.382 + // frame's base pointer. Since the stack grows down, these offsets are 1.383 + // negative. 1.384 + static int reverseOffsetOfFrameSize() { 1.385 + return -int(Size()) + offsetof(BaselineFrame, frameSize_); 1.386 + } 1.387 + static int reverseOffsetOfScratchValue() { 1.388 + return -int(Size()) + offsetof(BaselineFrame, loScratchValue_); 1.389 + } 1.390 + static int reverseOffsetOfScopeChain() { 1.391 + return -int(Size()) + offsetof(BaselineFrame, scopeChain_); 1.392 + } 1.393 + static int reverseOffsetOfArgsObj() { 1.394 + return -int(Size()) + offsetof(BaselineFrame, argsObj_); 1.395 + } 1.396 + static int reverseOffsetOfFlags() { 1.397 + return -int(Size()) + offsetof(BaselineFrame, flags_); 1.398 + } 1.399 + static int reverseOffsetOfEvalScript() { 1.400 + return -int(Size()) + offsetof(BaselineFrame, evalScript_); 1.401 + } 1.402 + static int reverseOffsetOfReturnValue() { 1.403 + return -int(Size()) + offsetof(BaselineFrame, loReturnValue_); 1.404 + } 1.405 + static int reverseOffsetOfLocal(size_t index) { 1.406 + return -int(Size()) - (index + 1) * sizeof(Value); 1.407 + } 1.408 +}; 1.409 + 1.410 +// Ensure the frame is 8-byte aligned (required on ARM). 1.411 +JS_STATIC_ASSERT(((sizeof(BaselineFrame) + BaselineFrame::FramePointerOffset) % 8) == 0); 1.412 + 1.413 +} // namespace jit 1.414 +} // namespace js 1.415 + 1.416 +#endif // JS_ION 1.417 + 1.418 +#endif /* jit_BaselineFrame_h */