2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 #include "hphp/runtime/vm/jit/ir-unit.h"
19 #include "hphp/runtime/vm/jit/block.h"
20 #include "hphp/runtime/vm/jit/cfg.h"
21 #include "hphp/runtime/vm/jit/frame-state.h"
22 #include "hphp/util/timer.h"
24 namespace HPHP
{ namespace jit
{
25 ///////////////////////////////////////////////////////////////////////////////
29 ///////////////////////////////////////////////////////////////////////////////
31 IRUnit::IRUnit(TransContext context
) : m_context(context
)
33 // Setup m_entry after property initialization, since it depends on
34 // the value of m_defHint.
35 // For Optimize translations, the entry block's profCount is
36 // adjusted later in translateRegion.
38 m_startNanos
= HPHP::Timer::GetThreadCPUTimeNanos();
41 void IRUnit::initLogEntry(const Func
* func
) {
42 if (func
? func
->shouldSampleJit() :
43 StructuredLog::coinflip(RuntimeOption::EvalJitSampleRate
)) {
48 IRInstruction
* IRUnit::defLabel(unsigned numDst
, BCContext bcctx
) {
49 IRInstruction
inst(DefLabel
, bcctx
);
50 auto const label
= clone(&inst
);
52 auto const dstsPtr
= new (m_arena
) SSATmp
*[numDst
];
53 for (unsigned i
= 0; i
< numDst
; ++i
) {
54 dstsPtr
[i
] = newSSATmp(label
);
56 label
->setDsts(numDst
, dstsPtr
);
61 void IRUnit::expandLabel(IRInstruction
* label
, unsigned extraDst
) {
62 assertx(label
->is(DefLabel
));
63 assertx(extraDst
> 0);
64 auto const dstsPtr
= new (m_arena
) SSATmp
*[extraDst
+ label
->numDsts()];
66 for (auto dst
: label
->dsts()) {
69 for (unsigned j
= 0; j
< extraDst
; j
++) {
70 dstsPtr
[i
++] = newSSATmp(label
);
72 label
->setDsts(i
, dstsPtr
);
75 void IRUnit::expandJmp(IRInstruction
* jmp
, SSATmp
* value
) {
76 assertx(jmp
->is(Jmp
));
77 auto const newSrcs
= new (m_arena
) SSATmp
*[jmp
->numSrcs() + 1];
79 for (auto src
: jmp
->srcs()) {
83 jmp
->setSrcs(i
, newSrcs
);
86 Block
* IRUnit::defBlock(uint64_t profCount
/* =1 */,
87 Block::Hint hint
/* =Neither */ ) {
88 FTRACE(2, "IRUnit defining B{}\n", m_nextBlockId
);
89 auto const block
= new (m_arena
) Block(m_nextBlockId
++, profCount
);
90 if (hint
== Block::Hint::Neither
) {
97 SSATmp
* IRUnit::cns(Type type
) {
98 assertx(type
.hasConstVal() ||
99 type
.subtypeOfAny(TUninit
, TInitNull
, TNullptr
));
100 IRInstruction
inst(DefConst
, BCContext
{});
101 inst
.setTypeParam(type
);
102 if (SSATmp
* tmp
= m_constTable
.lookup(&inst
)) {
103 assertx(tmp
->type() == type
);
106 return m_constTable
.insert(clone(&inst
)->dst());
109 ///////////////////////////////////////////////////////////////////////////////
112 * Returns true iff `block' ends the IR unit after finishing execution
113 * of the bytecode instruction at `sk'.
115 static bool endsUnitAtSrcKey(const Block
* block
, SrcKey sk
) {
116 if (!block
->isExitNoThrow()) return false;
118 const auto& inst
= block
->back();
119 const auto instSk
= inst
.marker().sk();
122 // These instructions end a unit after executing the bytecode
123 // instruction they correspond to.
128 case ThrowOutOfBounds
:
129 case ThrowInvalidArrayKey
:
130 case ThrowInvalidOperation
:
131 case ThrowArithmeticError
:
132 case ThrowDivisionByZeroError
:
133 case VerifyParamFailHard
:
134 case VerifyRetFailHard
:
137 case FatalMissingThis
:
140 // The RetCtrl is generally ending a bytecode instruction, with the
141 // exception being in an Await bytecode instruction, where we consider the
142 // end of the bytecode instruction to be the non-suspending path.
144 auto const op
= inst
.marker().sk().op();
145 return op
!= Op::Await
&& op
!= Op::AwaitAll
&& op
!= Op::FCallAwait
;
149 case AsyncFuncRetSlow
:
152 // A ReqBindJmp ends a unit and it jumps to the next instruction to
155 auto destOffset
= inst
.extra
<ReqBindJmp
>()->target
.offset();
156 return sk
.succOffsets().count(destOffset
);
164 Block
* findMainExitBlock(const IRUnit
& unit
, SrcKey lastSk
) {
165 bool unreachable
= false;
166 Block
* mainExit
= nullptr;
168 FTRACE(5, "findMainExitBlock: looking for exit at {} in unit:\n{}\n",
169 showShort(lastSk
), show(unit
));
171 for (auto block
: rpoSortCfg(unit
)) {
172 if (block
->back().is(Unreachable
)) unreachable
= true;
174 if (endsUnitAtSrcKey(block
, lastSk
)) {
175 if (mainExit
== nullptr) {
181 mainExit
->hint() == Block::Hint::Unlikely
||
182 block
->hint() == Block::Hint::Unlikely
,
183 "findMainExit: 2 likely exits found: B{} and B{}\nlastSk = {}",
184 mainExit
->id(), block
->id(), showShort(lastSk
)
187 if (mainExit
->hint() == Block::Hint::Unlikely
) mainExit
= block
;
192 mainExit
|| unreachable
,
193 "findMainExit: no exit found for lastSk = {}",
197 FTRACE(5, "findMainExitBlock: mainExit = B{}\n", mainExit
->id());
202 ///////////////////////////////////////////////////////////////////////////////