Clean up irgen.h a bit
[hiphop-php.git] / hphp / runtime / vm / jit / frame-state.h
blobf0c74672d8b51787abc03670d0a30b89b0198282
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2016 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_JIT_FRAME_STATE_H_
18 #define incl_HPHP_JIT_FRAME_STATE_H_
20 #include "hphp/runtime/vm/jit/cfg.h"
21 #include "hphp/runtime/vm/jit/state-vector.h"
22 #include "hphp/runtime/vm/jit/type-source.h"
24 #include <boost/dynamic_bitset.hpp>
25 #include <folly/Optional.h>
27 #include <memory>
28 #include <vector>
30 namespace HPHP {
32 struct Func;
34 namespace jit {
36 struct BlocksWithIds;
37 struct IRInstruction;
38 struct SSATmp;
40 //////////////////////////////////////////////////////////////////////
42 struct FPIInfo {
43 SSATmp* returnSP;
44 FPInvOffset returnSPOff; // return's logical sp offset; stkptr might differ
45 SSATmp* ctx;
46 Op fpushOpc; // bytecode for FPush*
47 const Func* func;
48 bool interp;
49 bool spansCall;
52 //////////////////////////////////////////////////////////////////////
55 * SlotState stores information about either a local variable or a stack slot
56 * in the current function, for FrameState. LocalState and StackState are the
57 * concrete versions of this struct, which differ only by the default type they
58 * use.
60 template<bool Stack>
61 struct SlotState {
62 static constexpr Type default_type() {
63 return Stack ? TStkElem : TGen;
67 * The current value of the or stack slot.
69 SSATmp* value{nullptr};
72 * The current type of the local or stack slot. We may have a
73 * tracked type even if we don't have an available value. This
74 * happens across PHP-level calls, for example, or at some joint
75 * points where we couldn't find the same available value for all
76 * incoming edges. However, whenever we have a value, the type of
77 * the SSATmp must match this `type' field.
79 Type type{default_type()};
82 * Prediction for the type of a local or stack slot, if it's boxed or if
83 * we're in a pseudomain. Otherwise it will be the same as `type'.
85 * Invariants:
86 * always a subtype of `type'
88 Type predictedType{default_type()};
91 * The sources of the currently known type. They may be values. If the value
92 * is unavailable, we won't hold onto it in the value field, but we'll keep
93 * it around in typeSrcs for guard relaxation.
95 TypeSourceSet typeSrcs{};
98 * Whether or not the local or stack element may have changed since
99 * the entry of the unit. This is only used for post-conditions.
101 bool maybeChanged{false};
104 using LocalState = SlotState<false>;
105 using StackState = SlotState<true>;
107 //////////////////////////////////////////////////////////////////////
110 * State related to a particular frame. These state structures are stored in a
111 * stack, that we push and pop as we enter and leave inlined frames.
113 struct FrameState {
115 * Current Func, VM stack pointer, VM frame pointer, offset between sp and
116 * fp, and bytecode position.
118 const Func* curFunc;
119 SSATmp* fpValue{nullptr};
122 * Tracking of in-memory state of the evaluation stack.
124 SSATmp* spValue{nullptr};
125 FPInvOffset spOffset; // delta from vmfp to spvalue
128 * Here we keep track of the raw pointer value of the member base register,
129 * the type of the pointer, as well as the value it points to, which we often
130 * know after simple base operations like BaseH or BaseL. These are used for
131 * some gen-time load elimination to preserve important information about the
132 * base.
134 struct {
135 SSATmp* ptr{nullptr};
136 Type ptrType{TPtrToGen};
137 SSATmp* value{nullptr};
139 void reset() {
140 ptr = nullptr;
141 ptrType = TPtrToGen;
142 value = nullptr;
144 } mbase;
147 * Tracks whether we will need to ratchet tvRef and tvRef2 after emitting an
148 * intermediate member instruction.
150 bool needRatchet{false};
153 * m_thisAvailable tracks whether the current frame is known to have a
154 * non-null $this pointer.
156 bool thisAvailable{false};
159 * frameMaySpan is true iff a Call instruction has been seen on any path
160 * since the definition of the current frame pointer.
162 bool frameMaySpanCall{false};
165 * syncedSpLevel indicates the depth of the in-memory eval stack.
167 FPInvOffset syncedSpLevel{0};
170 * stackModified is reset to false by exceptionStackBoundary() and set to
171 * true by anything that modifies the eval stack. It's used to verify that
172 * the stack is not modified between the beginning of a bytecode's
173 * translation and creation of any catch traces, unless
174 * exceptionStackBoundary() is explicitly called.
176 bool stackModified{false};
179 * The FPI stack is used for inlining---when we start inlining at an FCall,
180 * we look in here to find a definition of the StkPtr,offset that can be used
181 * after the inlined callee "returns".
183 jit::deque<FPIInfo> fpiStack;
186 * The values in the eval stack in memory, either above or below the current
187 * spValue pointer. These are indexed relative to the base of the eval stack
188 * for the whole function.
190 jit::vector<StackState> stack;
193 * Vector of local variable inforation; sized for numLocals on the curFunc
194 * (if the state is initialized).
196 jit::vector<LocalState> locals;
199 * Predicted types for values that lived in a local or stack slot at one
200 * point. Used to preserve predictions for values that move between different
201 * slots.
203 jit::hash_map<SSATmp*, Type> predictedTypes;
206 //////////////////////////////////////////////////////////////////////
209 * FrameStateMgr tracks state about the VM stack frame in the function currently
210 * being translated. It is responsible for both storing the state and updating
211 * it appropriately as instructions and blocks are processed.
213 * The types of state tracked by FrameStateMgr include:
215 * - value availability for values stored in locals, or the $this pointer
217 * Used for value propagation.
219 * - local types and values
221 * We track the current view of these types as we link in new instructions
222 * that mutate them.
224 * - current frame and stack pointers
226 * - current function and bytecode offset
228 struct FrameStateMgr final {
229 explicit FrameStateMgr(BCMarker);
231 FrameStateMgr(const FrameStateMgr&) = delete;
232 FrameStateMgr(FrameStateMgr&&) = default;
233 FrameStateMgr& operator=(const FrameStateMgr&) = delete;
234 FrameStateMgr& operator=(FrameStateMgr&&) = default;
237 * Update state by computing the effects of an instruction.
239 void update(const IRInstruction*);
241 /////////////////////////////////////////////////////////////////////////////
242 // Per-block state.
245 * Whether we have state saved for the given block.
247 bool hasStateFor(Block*) const;
250 * Starts tracking state for a block and reloads any previously saved state.
252 * `hasUnprocessedPred' is set to indicate that the given block has a
253 * predecessor in the region that might not yet be linked into the IR CFG.
255 void startBlock(Block* b, bool hasUnprocessedPred);
258 * Finish tracking state for a block and save the current state to any
259 * successors.
261 * Returns true iff the out-state for the block has changed.
263 bool finishBlock(Block*);
266 * Save current state of a block so we can resume processing it after working
267 * on another.
269 * Leaves the current state for this FrameStateMgr untouched: if you
270 * startBlock something new it'll keep using it. Right now we rely on this
271 * for exit and catch traces (relevant: TODO(#4323657)).
273 void pauseBlock(Block*);
276 * Resumes processing a block that was stopped by pauseBlock.
278 void unpauseBlock(Block*);
281 * Returns the post-conditions associated with `exitBlock'
283 const PostConditions& postConds(Block* exitBlock) const;
286 * set an override for the next fpi regions fpushOp
288 void setFPushOverride(Op op) { m_fpushOverride = op; }
289 bool hasFPushOverride() const { return m_fpushOverride.hasValue(); }
290 /////////////////////////////////////////////////////////////////////////////
293 * FrameState accessors.
295 * In the presence of inlining, these return state for the most-inlined
296 * frame.
298 const Func* func() const { return cur().curFunc; }
299 SSATmp* fp() const { return cur().fpValue; }
300 SSATmp* sp() const { return cur().spValue; }
301 FPInvOffset spOffset() const { return cur().spOffset; }
302 SSATmp* memberBasePtr() const { return cur().mbase.ptr; }
303 Type memberBasePtrType() const { return cur().mbase.ptrType; }
304 SSATmp* memberBaseValue() const { return cur().mbase.value; }
305 bool needRatchet() const { return cur().needRatchet; }
306 bool thisAvailable() const { return cur().thisAvailable; }
307 bool frameMaySpanCall() const { return cur().frameMaySpanCall; }
308 FPInvOffset syncedSpLevel() const { return cur().syncedSpLevel; }
309 bool stackModified() const { return cur().stackModified; }
310 const jit::deque<FPIInfo>& fpiStack() const { return cur().fpiStack; }
313 * FrameState modifiers.
315 * In the presence of inlining, these modify state for the most-inlined
316 * frame.
318 void setMemberBaseValue(SSATmp* base) { cur().mbase.value = base; }
319 void setNeedRatchet(bool b) { cur().needRatchet = b; }
320 void setThisAvailable() { cur().thisAvailable = true; }
321 void resetStackModified() { cur().stackModified = false; }
322 void setSyncedSpLevel(FPInvOffset o) { cur().syncedSpLevel = o; }
323 void incSyncedSpLevel(int32_t n = 1) { cur().syncedSpLevel += n; }
324 void decSyncedSpLevel(int32_t n = 1) { cur().syncedSpLevel -= n; }
326 * Current inlining depth (not including the toplevel frame).
328 unsigned inlineDepth() const { return m_stack.size() - 1; }
331 * Return the SlotState for local `id' or stack element at `off' in the
332 * most-inlined frame.
334 const LocalState& local(uint32_t id) const;
335 const StackState& stack(IRSPOffset off) const;
338 * Update the `predictedType' in the SlotState for the given local variable
339 * or stack value.
341 void refineLocalPredictedType(uint32_t id, Type type);
342 void refineStackPredictedType(IRSPOffset, Type);
344 private:
345 struct BlockState {
346 jit::vector<FrameState> in;
347 folly::Optional<jit::vector<FrameState>> paused;
350 private:
351 bool checkInvariants() const;
352 bool save(Block*);
353 jit::vector<LocalState>& locals(unsigned inlineIdx);
354 void trackDefInlineFP(const IRInstruction* inst);
355 void trackInlineReturn();
356 void clearForUnprocessedPred();
357 StackState& stackState(IRSPOffset offset);
358 const StackState& stackState(IRSPOffset offset) const;
359 void collectPostConds(Block* exitBlock);
360 void updateMInstr(const IRInstruction*);
361 void refinePredictedTmpType(SSATmp*, Type);
363 private:
364 FrameState& cur() {
365 assertx(!m_stack.empty());
366 return m_stack.back();
368 const FrameState& cur() const {
369 return const_cast<FrameStateMgr*>(this)->cur();
372 template<bool Stack>
373 void syncPrediction(SlotState<Stack>&);
376 * refine(Local|Stack)Type() are used when the value of a slot hasn't changed
377 * but we have more information about its type, from a guard or type assert.
379 * set(Local|Stack)Type() are used to change the type of a slot when we have
380 * a brand new type because the value might have changed. These operations
381 * clear the typeSrcs of the slot, so new type may not be derived from the
382 * old type in any way.
384 * widen(Local|Stack)Type() are used to change the type of a slot, as a
385 * result of an operation that might change the value. These operations
386 * preserve the typeSrcs of the slot, so the new type may be derived from the
387 * old type.
389 private: // local tracking helpers
390 void setLocalValue(uint32_t id, SSATmp* value);
391 void refineLocalValues(SSATmp* oldVal, SSATmp* newVal);
392 void dropLocalRefsInnerTypes();
393 void killLocalsForCall(bool);
394 void refineLocalType(uint32_t id, Type type, TypeSource typeSrc);
395 void setLocalPredictedType(uint32_t id, Type type);
396 void setLocalType(uint32_t id, Type type);
397 void widenLocalType(uint32_t id, Type type);
398 void setBoxedLocalPrediction(uint32_t id, Type type);
399 void updateLocalRefPredictions(SSATmp*, SSATmp*);
400 void setLocalTypeSource(uint32_t id, TypeSource typeSrc);
401 void clearLocals();
403 private: // stack tracking helpers
404 void setStackValue(IRSPOffset, SSATmp*);
405 void setStackType(IRSPOffset, Type);
406 void widenStackType(IRSPOffset, Type);
407 void refineStackValues(SSATmp* oldval, SSATmp* newVal);
408 void refineStackType(IRSPOffset, Type, TypeSource typeSrc);
409 void clearStackForCall();
410 void setBoxedStkPrediction(IRSPOffset, Type type);
411 void spillFrameStack(IRSPOffset, FPInvOffset, const IRInstruction*);
413 private:
415 * Stack of states. We push and pop frames as we enter and leave inlined
416 * calls.
418 jit::vector<FrameState> m_stack;
421 * Saved snapshots of the incoming and outgoing state of blocks.
423 jit::hash_map<Block*,BlockState> m_states;
426 * Post-conditions for exit blocks.
428 jit::hash_map<Block*,PostConditions> m_exitPostConds;
431 * Override for the current fpush* bytecode so we can convert bytecodes
432 * to php calls.
434 folly::Optional<Op> m_fpushOverride;
437 //////////////////////////////////////////////////////////////////////
440 * Debug stringification.
442 std::string show(const FrameStateMgr&);
444 //////////////////////////////////////////////////////////////////////
448 #endif