1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/BaselineFrameInfo.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,323 @@ 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_BaselineFrameInfo_h 1.11 +#define jit_BaselineFrameInfo_h 1.12 + 1.13 +#ifdef JS_ION 1.14 + 1.15 +#include "mozilla/Alignment.h" 1.16 + 1.17 +#include "jit/BaselineFrame.h" 1.18 +#include "jit/BaselineRegisters.h" 1.19 +#include "jit/FixedList.h" 1.20 +#include "jit/IonMacroAssembler.h" 1.21 + 1.22 +namespace js { 1.23 +namespace jit { 1.24 + 1.25 +struct BytecodeInfo; 1.26 + 1.27 +// FrameInfo overview. 1.28 +// 1.29 +// FrameInfo is used by the compiler to track values stored in the frame. This 1.30 +// includes locals, arguments and stack values. Locals and arguments are always 1.31 +// fully synced. Stack values can either be synced, stored as constant, stored in 1.32 +// a Value register or refer to a local slot. Syncing a StackValue ensures it's 1.33 +// stored on the stack, e.g. kind == Stack. 1.34 +// 1.35 +// To see how this works, consider the following statement: 1.36 +// 1.37 +// var y = x + 9; 1.38 +// 1.39 +// Here two values are pushed: StackValue(LocalSlot(0)) and StackValue(Int32Value(9)). 1.40 +// Only when we reach the ADD op, code is generated to load the operands directly 1.41 +// into the right operand registers and sync all other stack values. 1.42 +// 1.43 +// For stack values, the following invariants hold (and are checked between ops): 1.44 +// 1.45 +// (1) If a value is synced (kind == Stack), all values below it must also be synced. 1.46 +// In other words, values with kind other than Stack can only appear on top of the 1.47 +// abstract stack. 1.48 +// 1.49 +// (2) When we call a stub or IC, all values still on the stack must be synced. 1.50 + 1.51 +// Represents a value pushed on the stack. Note that StackValue is not used for 1.52 +// locals or arguments since these are always fully synced. 1.53 +class StackValue 1.54 +{ 1.55 + public: 1.56 + enum Kind { 1.57 + Constant, 1.58 + Register, 1.59 + Stack, 1.60 + LocalSlot, 1.61 + ArgSlot, 1.62 + ThisSlot 1.63 +#ifdef DEBUG 1.64 + // In debug builds, assert Kind is initialized. 1.65 + , Uninitialized 1.66 +#endif 1.67 + }; 1.68 + 1.69 + private: 1.70 + Kind kind_; 1.71 + 1.72 + union { 1.73 + struct { 1.74 + Value v; 1.75 + } constant; 1.76 + struct { 1.77 + mozilla::AlignedStorage2<ValueOperand> reg; 1.78 + } reg; 1.79 + struct { 1.80 + uint32_t slot; 1.81 + } local; 1.82 + struct { 1.83 + uint32_t slot; 1.84 + } arg; 1.85 + } data; 1.86 + 1.87 + JSValueType knownType_; 1.88 + 1.89 + public: 1.90 + StackValue() { 1.91 + reset(); 1.92 + } 1.93 + 1.94 + Kind kind() const { 1.95 + return kind_; 1.96 + } 1.97 + bool hasKnownType() const { 1.98 + return knownType_ != JSVAL_TYPE_UNKNOWN; 1.99 + } 1.100 + bool hasKnownType(JSValueType type) const { 1.101 + JS_ASSERT(type != JSVAL_TYPE_UNKNOWN); 1.102 + return knownType_ == type; 1.103 + } 1.104 + bool isKnownBoolean() const { 1.105 + return hasKnownType(JSVAL_TYPE_BOOLEAN); 1.106 + } 1.107 + JSValueType knownType() const { 1.108 + JS_ASSERT(hasKnownType()); 1.109 + return knownType_; 1.110 + } 1.111 + void reset() { 1.112 +#ifdef DEBUG 1.113 + kind_ = Uninitialized; 1.114 + knownType_ = JSVAL_TYPE_UNKNOWN; 1.115 +#endif 1.116 + } 1.117 + Value constant() const { 1.118 + JS_ASSERT(kind_ == Constant); 1.119 + return data.constant.v; 1.120 + } 1.121 + ValueOperand reg() const { 1.122 + JS_ASSERT(kind_ == Register); 1.123 + return *data.reg.reg.addr(); 1.124 + } 1.125 + uint32_t localSlot() const { 1.126 + JS_ASSERT(kind_ == LocalSlot); 1.127 + return data.local.slot; 1.128 + } 1.129 + uint32_t argSlot() const { 1.130 + JS_ASSERT(kind_ == ArgSlot); 1.131 + return data.arg.slot; 1.132 + } 1.133 + 1.134 + void setConstant(const Value &v) { 1.135 + kind_ = Constant; 1.136 + data.constant.v = v; 1.137 + knownType_ = v.isDouble() ? JSVAL_TYPE_DOUBLE : v.extractNonDoubleType(); 1.138 + } 1.139 + void setRegister(const ValueOperand &val, JSValueType knownType = JSVAL_TYPE_UNKNOWN) { 1.140 + kind_ = Register; 1.141 + *data.reg.reg.addr() = val; 1.142 + knownType_ = knownType; 1.143 + } 1.144 + void setLocalSlot(uint32_t slot) { 1.145 + kind_ = LocalSlot; 1.146 + data.local.slot = slot; 1.147 + knownType_ = JSVAL_TYPE_UNKNOWN; 1.148 + } 1.149 + void setArgSlot(uint32_t slot) { 1.150 + kind_ = ArgSlot; 1.151 + data.arg.slot = slot; 1.152 + knownType_ = JSVAL_TYPE_UNKNOWN; 1.153 + } 1.154 + void setThis() { 1.155 + kind_ = ThisSlot; 1.156 + knownType_ = JSVAL_TYPE_UNKNOWN; 1.157 + } 1.158 + void setStack() { 1.159 + kind_ = Stack; 1.160 + knownType_ = JSVAL_TYPE_UNKNOWN; 1.161 + } 1.162 +}; 1.163 + 1.164 +enum StackAdjustment { AdjustStack, DontAdjustStack }; 1.165 + 1.166 +class FrameInfo 1.167 +{ 1.168 + JSScript *script; 1.169 + MacroAssembler &masm; 1.170 + 1.171 + FixedList<StackValue> stack; 1.172 + size_t spIndex; 1.173 + 1.174 + public: 1.175 + FrameInfo(JSScript *script, MacroAssembler &masm) 1.176 + : script(script), 1.177 + masm(masm), 1.178 + stack(), 1.179 + spIndex(0) 1.180 + { } 1.181 + 1.182 + bool init(TempAllocator &alloc); 1.183 + 1.184 + uint32_t nlocals() const { 1.185 + return script->nfixed(); 1.186 + } 1.187 + uint32_t nargs() const { 1.188 + return script->functionNonDelazifying()->nargs(); 1.189 + } 1.190 + 1.191 + private: 1.192 + inline StackValue *rawPush() { 1.193 + StackValue *val = &stack[spIndex++]; 1.194 + val->reset(); 1.195 + return val; 1.196 + } 1.197 + 1.198 + public: 1.199 + inline size_t stackDepth() const { 1.200 + return spIndex; 1.201 + } 1.202 + inline void setStackDepth(uint32_t newDepth) { 1.203 + if (newDepth <= stackDepth()) { 1.204 + spIndex = newDepth; 1.205 + } else { 1.206 + uint32_t diff = newDepth - stackDepth(); 1.207 + for (uint32_t i = 0; i < diff; i++) { 1.208 + StackValue *val = rawPush(); 1.209 + val->setStack(); 1.210 + } 1.211 + 1.212 + JS_ASSERT(spIndex == newDepth); 1.213 + } 1.214 + } 1.215 + inline StackValue *peek(int32_t index) const { 1.216 + JS_ASSERT(index < 0); 1.217 + return const_cast<StackValue *>(&stack[spIndex + index]); 1.218 + } 1.219 + 1.220 + inline void pop(StackAdjustment adjust = AdjustStack) { 1.221 + spIndex--; 1.222 + StackValue *popped = &stack[spIndex]; 1.223 + 1.224 + if (adjust == AdjustStack && popped->kind() == StackValue::Stack) 1.225 + masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg); 1.226 + 1.227 + // Assert when anything uses this value. 1.228 + popped->reset(); 1.229 + } 1.230 + inline void popn(uint32_t n, StackAdjustment adjust = AdjustStack) { 1.231 + uint32_t poppedStack = 0; 1.232 + for (uint32_t i = 0; i < n; i++) { 1.233 + if (peek(-1)->kind() == StackValue::Stack) 1.234 + poppedStack++; 1.235 + pop(DontAdjustStack); 1.236 + } 1.237 + if (adjust == AdjustStack && poppedStack > 0) 1.238 + masm.addPtr(Imm32(sizeof(Value) * poppedStack), BaselineStackReg); 1.239 + } 1.240 + inline void push(const Value &val) { 1.241 + StackValue *sv = rawPush(); 1.242 + sv->setConstant(val); 1.243 + } 1.244 + inline void push(const ValueOperand &val, JSValueType knownType=JSVAL_TYPE_UNKNOWN) { 1.245 + StackValue *sv = rawPush(); 1.246 + sv->setRegister(val, knownType); 1.247 + } 1.248 + inline void pushLocal(uint32_t local) { 1.249 + JS_ASSERT(local < nlocals()); 1.250 + StackValue *sv = rawPush(); 1.251 + sv->setLocalSlot(local); 1.252 + } 1.253 + inline void pushArg(uint32_t arg) { 1.254 + StackValue *sv = rawPush(); 1.255 + sv->setArgSlot(arg); 1.256 + } 1.257 + inline void pushThis() { 1.258 + StackValue *sv = rawPush(); 1.259 + sv->setThis(); 1.260 + } 1.261 + inline void pushScratchValue() { 1.262 + masm.pushValue(addressOfScratchValue()); 1.263 + StackValue *sv = rawPush(); 1.264 + sv->setStack(); 1.265 + } 1.266 + inline Address addressOfLocal(size_t local) const { 1.267 + JS_ASSERT(local < nlocals()); 1.268 + return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfLocal(local)); 1.269 + } 1.270 + Address addressOfArg(size_t arg) const { 1.271 + JS_ASSERT(arg < nargs()); 1.272 + return Address(BaselineFrameReg, BaselineFrame::offsetOfArg(arg)); 1.273 + } 1.274 + Address addressOfThis() const { 1.275 + return Address(BaselineFrameReg, BaselineFrame::offsetOfThis()); 1.276 + } 1.277 + Address addressOfCallee() const { 1.278 + return Address(BaselineFrameReg, BaselineFrame::offsetOfCalleeToken()); 1.279 + } 1.280 + Address addressOfScopeChain() const { 1.281 + return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScopeChain()); 1.282 + } 1.283 + Address addressOfFlags() const { 1.284 + return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags()); 1.285 + } 1.286 + Address addressOfEvalScript() const { 1.287 + return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfEvalScript()); 1.288 + } 1.289 + Address addressOfReturnValue() const { 1.290 + return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfReturnValue()); 1.291 + } 1.292 + Address addressOfStackValue(const StackValue *value) const { 1.293 + JS_ASSERT(value->kind() == StackValue::Stack); 1.294 + size_t slot = value - &stack[0]; 1.295 + JS_ASSERT(slot < stackDepth()); 1.296 + return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfLocal(nlocals() + slot)); 1.297 + } 1.298 + Address addressOfScratchValue() const { 1.299 + return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScratchValue()); 1.300 + } 1.301 + 1.302 + void popValue(ValueOperand dest); 1.303 + 1.304 + void sync(StackValue *val); 1.305 + void syncStack(uint32_t uses); 1.306 + uint32_t numUnsyncedSlots(); 1.307 + void popRegsAndSync(uint32_t uses); 1.308 + 1.309 + inline void assertSyncedStack() const { 1.310 + JS_ASSERT_IF(stackDepth() > 0, peek(-1)->kind() == StackValue::Stack); 1.311 + } 1.312 + 1.313 +#ifdef DEBUG 1.314 + // Assert the state is valid before excuting "pc". 1.315 + void assertValidState(const BytecodeInfo &info); 1.316 +#else 1.317 + inline void assertValidState(const BytecodeInfo &info) {} 1.318 +#endif 1.319 +}; 1.320 + 1.321 +} // namespace jit 1.322 +} // namespace js 1.323 + 1.324 +#endif // JS_ION 1.325 + 1.326 +#endif /* jit_BaselineFrameInfo_h */