js/src/jit/BaselineFrameInfo.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef jit_BaselineFrameInfo_h
michael@0 8 #define jit_BaselineFrameInfo_h
michael@0 9
michael@0 10 #ifdef JS_ION
michael@0 11
michael@0 12 #include "mozilla/Alignment.h"
michael@0 13
michael@0 14 #include "jit/BaselineFrame.h"
michael@0 15 #include "jit/BaselineRegisters.h"
michael@0 16 #include "jit/FixedList.h"
michael@0 17 #include "jit/IonMacroAssembler.h"
michael@0 18
michael@0 19 namespace js {
michael@0 20 namespace jit {
michael@0 21
michael@0 22 struct BytecodeInfo;
michael@0 23
michael@0 24 // FrameInfo overview.
michael@0 25 //
michael@0 26 // FrameInfo is used by the compiler to track values stored in the frame. This
michael@0 27 // includes locals, arguments and stack values. Locals and arguments are always
michael@0 28 // fully synced. Stack values can either be synced, stored as constant, stored in
michael@0 29 // a Value register or refer to a local slot. Syncing a StackValue ensures it's
michael@0 30 // stored on the stack, e.g. kind == Stack.
michael@0 31 //
michael@0 32 // To see how this works, consider the following statement:
michael@0 33 //
michael@0 34 // var y = x + 9;
michael@0 35 //
michael@0 36 // Here two values are pushed: StackValue(LocalSlot(0)) and StackValue(Int32Value(9)).
michael@0 37 // Only when we reach the ADD op, code is generated to load the operands directly
michael@0 38 // into the right operand registers and sync all other stack values.
michael@0 39 //
michael@0 40 // For stack values, the following invariants hold (and are checked between ops):
michael@0 41 //
michael@0 42 // (1) If a value is synced (kind == Stack), all values below it must also be synced.
michael@0 43 // In other words, values with kind other than Stack can only appear on top of the
michael@0 44 // abstract stack.
michael@0 45 //
michael@0 46 // (2) When we call a stub or IC, all values still on the stack must be synced.
michael@0 47
michael@0 48 // Represents a value pushed on the stack. Note that StackValue is not used for
michael@0 49 // locals or arguments since these are always fully synced.
michael@0 50 class StackValue
michael@0 51 {
michael@0 52 public:
michael@0 53 enum Kind {
michael@0 54 Constant,
michael@0 55 Register,
michael@0 56 Stack,
michael@0 57 LocalSlot,
michael@0 58 ArgSlot,
michael@0 59 ThisSlot
michael@0 60 #ifdef DEBUG
michael@0 61 // In debug builds, assert Kind is initialized.
michael@0 62 , Uninitialized
michael@0 63 #endif
michael@0 64 };
michael@0 65
michael@0 66 private:
michael@0 67 Kind kind_;
michael@0 68
michael@0 69 union {
michael@0 70 struct {
michael@0 71 Value v;
michael@0 72 } constant;
michael@0 73 struct {
michael@0 74 mozilla::AlignedStorage2<ValueOperand> reg;
michael@0 75 } reg;
michael@0 76 struct {
michael@0 77 uint32_t slot;
michael@0 78 } local;
michael@0 79 struct {
michael@0 80 uint32_t slot;
michael@0 81 } arg;
michael@0 82 } data;
michael@0 83
michael@0 84 JSValueType knownType_;
michael@0 85
michael@0 86 public:
michael@0 87 StackValue() {
michael@0 88 reset();
michael@0 89 }
michael@0 90
michael@0 91 Kind kind() const {
michael@0 92 return kind_;
michael@0 93 }
michael@0 94 bool hasKnownType() const {
michael@0 95 return knownType_ != JSVAL_TYPE_UNKNOWN;
michael@0 96 }
michael@0 97 bool hasKnownType(JSValueType type) const {
michael@0 98 JS_ASSERT(type != JSVAL_TYPE_UNKNOWN);
michael@0 99 return knownType_ == type;
michael@0 100 }
michael@0 101 bool isKnownBoolean() const {
michael@0 102 return hasKnownType(JSVAL_TYPE_BOOLEAN);
michael@0 103 }
michael@0 104 JSValueType knownType() const {
michael@0 105 JS_ASSERT(hasKnownType());
michael@0 106 return knownType_;
michael@0 107 }
michael@0 108 void reset() {
michael@0 109 #ifdef DEBUG
michael@0 110 kind_ = Uninitialized;
michael@0 111 knownType_ = JSVAL_TYPE_UNKNOWN;
michael@0 112 #endif
michael@0 113 }
michael@0 114 Value constant() const {
michael@0 115 JS_ASSERT(kind_ == Constant);
michael@0 116 return data.constant.v;
michael@0 117 }
michael@0 118 ValueOperand reg() const {
michael@0 119 JS_ASSERT(kind_ == Register);
michael@0 120 return *data.reg.reg.addr();
michael@0 121 }
michael@0 122 uint32_t localSlot() const {
michael@0 123 JS_ASSERT(kind_ == LocalSlot);
michael@0 124 return data.local.slot;
michael@0 125 }
michael@0 126 uint32_t argSlot() const {
michael@0 127 JS_ASSERT(kind_ == ArgSlot);
michael@0 128 return data.arg.slot;
michael@0 129 }
michael@0 130
michael@0 131 void setConstant(const Value &v) {
michael@0 132 kind_ = Constant;
michael@0 133 data.constant.v = v;
michael@0 134 knownType_ = v.isDouble() ? JSVAL_TYPE_DOUBLE : v.extractNonDoubleType();
michael@0 135 }
michael@0 136 void setRegister(const ValueOperand &val, JSValueType knownType = JSVAL_TYPE_UNKNOWN) {
michael@0 137 kind_ = Register;
michael@0 138 *data.reg.reg.addr() = val;
michael@0 139 knownType_ = knownType;
michael@0 140 }
michael@0 141 void setLocalSlot(uint32_t slot) {
michael@0 142 kind_ = LocalSlot;
michael@0 143 data.local.slot = slot;
michael@0 144 knownType_ = JSVAL_TYPE_UNKNOWN;
michael@0 145 }
michael@0 146 void setArgSlot(uint32_t slot) {
michael@0 147 kind_ = ArgSlot;
michael@0 148 data.arg.slot = slot;
michael@0 149 knownType_ = JSVAL_TYPE_UNKNOWN;
michael@0 150 }
michael@0 151 void setThis() {
michael@0 152 kind_ = ThisSlot;
michael@0 153 knownType_ = JSVAL_TYPE_UNKNOWN;
michael@0 154 }
michael@0 155 void setStack() {
michael@0 156 kind_ = Stack;
michael@0 157 knownType_ = JSVAL_TYPE_UNKNOWN;
michael@0 158 }
michael@0 159 };
michael@0 160
michael@0 161 enum StackAdjustment { AdjustStack, DontAdjustStack };
michael@0 162
michael@0 163 class FrameInfo
michael@0 164 {
michael@0 165 JSScript *script;
michael@0 166 MacroAssembler &masm;
michael@0 167
michael@0 168 FixedList<StackValue> stack;
michael@0 169 size_t spIndex;
michael@0 170
michael@0 171 public:
michael@0 172 FrameInfo(JSScript *script, MacroAssembler &masm)
michael@0 173 : script(script),
michael@0 174 masm(masm),
michael@0 175 stack(),
michael@0 176 spIndex(0)
michael@0 177 { }
michael@0 178
michael@0 179 bool init(TempAllocator &alloc);
michael@0 180
michael@0 181 uint32_t nlocals() const {
michael@0 182 return script->nfixed();
michael@0 183 }
michael@0 184 uint32_t nargs() const {
michael@0 185 return script->functionNonDelazifying()->nargs();
michael@0 186 }
michael@0 187
michael@0 188 private:
michael@0 189 inline StackValue *rawPush() {
michael@0 190 StackValue *val = &stack[spIndex++];
michael@0 191 val->reset();
michael@0 192 return val;
michael@0 193 }
michael@0 194
michael@0 195 public:
michael@0 196 inline size_t stackDepth() const {
michael@0 197 return spIndex;
michael@0 198 }
michael@0 199 inline void setStackDepth(uint32_t newDepth) {
michael@0 200 if (newDepth <= stackDepth()) {
michael@0 201 spIndex = newDepth;
michael@0 202 } else {
michael@0 203 uint32_t diff = newDepth - stackDepth();
michael@0 204 for (uint32_t i = 0; i < diff; i++) {
michael@0 205 StackValue *val = rawPush();
michael@0 206 val->setStack();
michael@0 207 }
michael@0 208
michael@0 209 JS_ASSERT(spIndex == newDepth);
michael@0 210 }
michael@0 211 }
michael@0 212 inline StackValue *peek(int32_t index) const {
michael@0 213 JS_ASSERT(index < 0);
michael@0 214 return const_cast<StackValue *>(&stack[spIndex + index]);
michael@0 215 }
michael@0 216
michael@0 217 inline void pop(StackAdjustment adjust = AdjustStack) {
michael@0 218 spIndex--;
michael@0 219 StackValue *popped = &stack[spIndex];
michael@0 220
michael@0 221 if (adjust == AdjustStack && popped->kind() == StackValue::Stack)
michael@0 222 masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
michael@0 223
michael@0 224 // Assert when anything uses this value.
michael@0 225 popped->reset();
michael@0 226 }
michael@0 227 inline void popn(uint32_t n, StackAdjustment adjust = AdjustStack) {
michael@0 228 uint32_t poppedStack = 0;
michael@0 229 for (uint32_t i = 0; i < n; i++) {
michael@0 230 if (peek(-1)->kind() == StackValue::Stack)
michael@0 231 poppedStack++;
michael@0 232 pop(DontAdjustStack);
michael@0 233 }
michael@0 234 if (adjust == AdjustStack && poppedStack > 0)
michael@0 235 masm.addPtr(Imm32(sizeof(Value) * poppedStack), BaselineStackReg);
michael@0 236 }
michael@0 237 inline void push(const Value &val) {
michael@0 238 StackValue *sv = rawPush();
michael@0 239 sv->setConstant(val);
michael@0 240 }
michael@0 241 inline void push(const ValueOperand &val, JSValueType knownType=JSVAL_TYPE_UNKNOWN) {
michael@0 242 StackValue *sv = rawPush();
michael@0 243 sv->setRegister(val, knownType);
michael@0 244 }
michael@0 245 inline void pushLocal(uint32_t local) {
michael@0 246 JS_ASSERT(local < nlocals());
michael@0 247 StackValue *sv = rawPush();
michael@0 248 sv->setLocalSlot(local);
michael@0 249 }
michael@0 250 inline void pushArg(uint32_t arg) {
michael@0 251 StackValue *sv = rawPush();
michael@0 252 sv->setArgSlot(arg);
michael@0 253 }
michael@0 254 inline void pushThis() {
michael@0 255 StackValue *sv = rawPush();
michael@0 256 sv->setThis();
michael@0 257 }
michael@0 258 inline void pushScratchValue() {
michael@0 259 masm.pushValue(addressOfScratchValue());
michael@0 260 StackValue *sv = rawPush();
michael@0 261 sv->setStack();
michael@0 262 }
michael@0 263 inline Address addressOfLocal(size_t local) const {
michael@0 264 JS_ASSERT(local < nlocals());
michael@0 265 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfLocal(local));
michael@0 266 }
michael@0 267 Address addressOfArg(size_t arg) const {
michael@0 268 JS_ASSERT(arg < nargs());
michael@0 269 return Address(BaselineFrameReg, BaselineFrame::offsetOfArg(arg));
michael@0 270 }
michael@0 271 Address addressOfThis() const {
michael@0 272 return Address(BaselineFrameReg, BaselineFrame::offsetOfThis());
michael@0 273 }
michael@0 274 Address addressOfCallee() const {
michael@0 275 return Address(BaselineFrameReg, BaselineFrame::offsetOfCalleeToken());
michael@0 276 }
michael@0 277 Address addressOfScopeChain() const {
michael@0 278 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScopeChain());
michael@0 279 }
michael@0 280 Address addressOfFlags() const {
michael@0 281 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags());
michael@0 282 }
michael@0 283 Address addressOfEvalScript() const {
michael@0 284 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfEvalScript());
michael@0 285 }
michael@0 286 Address addressOfReturnValue() const {
michael@0 287 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfReturnValue());
michael@0 288 }
michael@0 289 Address addressOfStackValue(const StackValue *value) const {
michael@0 290 JS_ASSERT(value->kind() == StackValue::Stack);
michael@0 291 size_t slot = value - &stack[0];
michael@0 292 JS_ASSERT(slot < stackDepth());
michael@0 293 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfLocal(nlocals() + slot));
michael@0 294 }
michael@0 295 Address addressOfScratchValue() const {
michael@0 296 return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScratchValue());
michael@0 297 }
michael@0 298
michael@0 299 void popValue(ValueOperand dest);
michael@0 300
michael@0 301 void sync(StackValue *val);
michael@0 302 void syncStack(uint32_t uses);
michael@0 303 uint32_t numUnsyncedSlots();
michael@0 304 void popRegsAndSync(uint32_t uses);
michael@0 305
michael@0 306 inline void assertSyncedStack() const {
michael@0 307 JS_ASSERT_IF(stackDepth() > 0, peek(-1)->kind() == StackValue::Stack);
michael@0 308 }
michael@0 309
michael@0 310 #ifdef DEBUG
michael@0 311 // Assert the state is valid before excuting "pc".
michael@0 312 void assertValidState(const BytecodeInfo &info);
michael@0 313 #else
michael@0 314 inline void assertValidState(const BytecodeInfo &info) {}
michael@0 315 #endif
michael@0 316 };
michael@0 317
michael@0 318 } // namespace jit
michael@0 319 } // namespace js
michael@0 320
michael@0 321 #endif // JS_ION
michael@0 322
michael@0 323 #endif /* jit_BaselineFrameInfo_h */

mercurial