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/region-selection.h"
19 #include "hphp/runtime/vm/jit/location.h"
20 #include "hphp/runtime/vm/jit/prof-data.h"
21 #include "hphp/runtime/vm/jit/trans-cfg.h"
22 #include "hphp/runtime/vm/jit/translator-inline.h"
26 namespace HPHP
{ namespace jit
{
31 * Remove from pConds the elements that correspond to stack positions
32 * that have been popped given the current SP offset from FP.
34 static void discardPoppedTypes(TypedLocations
& pConds
,
35 FPInvOffset curSpOffset
) {
36 for (auto it
= pConds
.begin(); it
!= pConds
.end(); ) {
37 if (it
->location
.tag() == LTag::Stack
&&
38 it
->location
.stackIdx() > curSpOffset
) {
39 it
= pConds
.erase(it
);
46 static void mergePostConds(TypedLocations
& dst
,
47 const PostConditions
& src
) {
48 for (const auto &post
: src
.changed
) {
50 for (auto it
= dst
.begin(); it
!= dst
.end(); ++it
) {
51 if (post
.location
== it
->location
) {
57 dst
.emplace_back(post
);
62 RegionDescPtr
selectHotTrace(HotTransContext
& ctx
) {
63 auto region
= std::make_shared
<RegionDesc
>();
64 TransID tid
= ctx
.tid
;
65 TransID prevId
= kInvalidTransID
;
66 TransIDSet selectedSet
;
67 TypedLocations accumPostConds
;
69 // Maps from BlockIds to accumulated post conditions for that block.
70 // Used to determine if we can add branch-over edges by checking the
71 // pre-conditions of the successor block.
72 hphp_hash_map
<RegionDesc::BlockId
, TypedLocations
> blockPostConds
;
74 auto numBCInstrs
= ctx
.maxBCInstrs
;
75 FTRACE(1, "selectHotTrace: starting with maxBCInstrs = {}\n", numBCInstrs
);
77 while (!selectedSet
.count(tid
)) {
78 auto rec
= ctx
.profData
->transRec(tid
);
79 auto blockRegion
= rec
->region();
80 if (blockRegion
== nullptr) break;
82 // Break if region would be larger than the specified limit.
83 if (blockRegion
->instrSize() > numBCInstrs
) {
84 FTRACE(2, "selectHotTrace: breaking region at Translation {} because "
85 "size would exceed of maximum translation limit\n", tid
);
89 // If the debugger is attached, only allow single-block regions.
90 if (prevId
!= kInvalidTransID
&& isDebuggerAttachedProcess()) {
91 FTRACE(2, "selectHotTrace: breaking region at Translation {} "
92 "because of debugger is attached\n", tid
);
96 // Break if block is not the first and it corresponds to the main
97 // function body entry. This is to prevent creating multiple
98 // large regions containing the function body (starting at various
100 if (prevId
!= kInvalidTransID
) {
101 auto const func
= rec
->func();
102 auto const bcOffset
= rec
->startBcOff();
103 if (func
->base() == bcOffset
) {
104 FTRACE(2, "selectHotTrace: breaking region because reached the main "
105 "function body entry at Translation {} (BC offset {})\n",
111 if (prevId
!= kInvalidTransID
) {
112 auto sk
= rec
->srcKey();
113 if (ctx
.profData
->optimized(sk
)) {
114 FTRACE(2, "selectHotTrace: breaking region because next sk already "
115 "optimized, for Translation {}\n", tid
);
120 bool hasPredBlock
= !region
->empty();
121 RegionDesc::BlockId predBlockId
= (hasPredBlock
?
122 region
->blocks().back().get()->id() : 0);
123 auto const& newFirstBlock
= blockRegion
->entry();
124 auto newFirstBlockId
= newFirstBlock
->id();
126 // Add blockRegion's blocks and arcs to region.
127 region
->append(*blockRegion
);
128 numBCInstrs
-= blockRegion
->instrSize();
129 assertx(numBCInstrs
>= 0);
132 region
->addArc(predBlockId
, newFirstBlockId
);
134 selectedSet
.insert(tid
);
136 const auto lastSk
= rec
->lastSrcKey();
137 if (breaksRegion(lastSk
)) {
138 FTRACE(2, "selectHotTrace: breaking region because of last instruction "
139 "in Translation {}: {}\n", tid
, opcodeToName(lastSk
.op()));
143 auto outArcs
= ctx
.cfg
->outArcs(tid
);
144 if (outArcs
.size() == 0) {
145 FTRACE(2, "selectHotTrace: breaking region because there's no successor "
146 "for Translation {}\n", tid
);
150 auto newLastBlock
= blockRegion
->blocks().back();
151 discardPoppedTypes(accumPostConds
,
152 blockRegion
->entry()->initialSpOffset());
153 mergePostConds(accumPostConds
, newLastBlock
->postConds());
154 blockPostConds
[newLastBlock
->id()] = accumPostConds
;
156 TransCFG::ArcPtrVec possibleOutArcs
;
157 for (auto arc
: outArcs
) {
158 auto dstRec
= ctx
.profData
->transRec(arc
->dst());
159 auto possibleNext
= dstRec
->region()->entry();
160 if (preCondsAreSatisfied(possibleNext
, accumPostConds
)) {
161 possibleOutArcs
.emplace_back(arc
);
165 if (possibleOutArcs
.size() == 0) {
166 FTRACE(2, "selectHotTrace: breaking region because postcondition check "
167 "pruned all successors of Translation {}\n", tid
);
171 auto maxWeight
= std::numeric_limits
<int64_t>::min();
172 TransCFG::Arc
* maxArc
= nullptr;
173 for (auto arc
: possibleOutArcs
) {
174 if (arc
->weight() >= maxWeight
) {
175 maxWeight
= arc
->weight();
179 assertx(maxArc
!= nullptr);
184 FTRACE(3, "selectHotTrace: before chainRetransBlocks:\n{}\n", show(*region
));
185 region
->chainRetransBlocks();
186 FTRACE(3, "selectHotTrace: after chainRetransBlocks:\n{}\n", show(*region
));