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/cg-meta.h"
19 #include "hphp/runtime/vm/debug/debug.h"
20 #include "hphp/runtime/vm/jit/code-cache.h"
21 #include "hphp/runtime/vm/jit/fixup.h"
22 #include "hphp/runtime/vm/jit/prof-data.h"
23 #include "hphp/runtime/vm/jit/tc.h"
24 #include "hphp/runtime/vm/tread-hash-map.h"
26 #include "hphp/util/atomic-vector.h"
28 namespace HPHP
{ namespace jit
{
34 std::atomic
<IFrameID
> s_nextFrameKey
;
36 // Map from integral literals to their location in the TC data section.
37 using LiteralMap
= TreadHashMap
<uint64_t,const uint64_t*,std::hash
<uint64_t>>;
38 LiteralMap s_literals
{128};
40 // Landingpads for TC catch traces; used by the unwinder.
41 using CatchTraceMap
= TreadHashMap
<uint32_t, uint32_t, std::hash
<uint32_t>>;
42 CatchTraceMap s_catchTraceMap
{128};
44 using AbortReasonMap
= TreadHashMap
<uint32_t, Reason
, std::hash
<uint32_t>>;
45 AbortReasonMap s_trapReasonMap
{128};
47 using InlineStackMap
= TreadHashMap
<uint32_t, IStack
, std::hash
<uint32_t>>;
48 InlineStackMap s_inlineStacks
{1024};
50 using InlineFrameVec
= AtomicVector
<IFrame
>;
51 InlineFrameVec s_inlineFrames
{4096,IFrame
{}};
53 constexpr uint32_t kInvalidCatchTrace
= 0x0;
54 constexpr uint32_t kInvalidFrameID
= -1;
56 IFrameID
insertFrames(const std::vector
<IFrame
>& frames
) {
57 auto const start
= s_nextFrameKey
.fetch_add(frames
.size());
58 s_inlineFrames
.ensureSize(start
+ frames
.size());
60 for (IFrameID i
= 0; i
< frames
.size(); ++i
) {
62 auto newFrame
= IFrame
{f
.func
, f
.callOff
, f
.parent
+ start
};
63 s_inlineFrames
.exchange(start
+ i
, newFrame
);
69 bool isFakeAddr(CTCA addr
) {
70 return (int64_t)addr
< 0;
73 Offset
fromFakeAddr(CTCA addr
) {
74 return (int32_t)reinterpret_cast<int64_t>(addr
);
77 Offset
stackAddrToOffset(CTCA addr
) {
78 return isFakeAddr(addr
) ? fromFakeAddr(addr
) : tc::addrToOffset(addr
);
82 IFrameID start
, const std::vector
<std::pair
<TCA
,IStack
>>& stacks
84 for (auto& stk
: stacks
) {
85 if (!stk
.second
.nframes
) continue;
86 auto off
= stackAddrToOffset(stk
.first
);
87 auto val
= stk
.second
;
89 if (auto pos
= s_inlineStacks
.find(off
)) {
92 s_inlineStacks
.insert(off
, val
);
97 void processInlineFrames(const CGMeta
& cm
) {
98 auto const start
= insertFrames(cm
.inlineFrames
);
99 insertStacks(start
, cm
.inlineStacks
);
104 folly::Optional
<IStack
> inlineStackAt(CTCA addr
) {
105 if (!addr
) return folly::none
;
106 auto off
= stackAddrToOffset(addr
);
107 if (auto pos
= s_inlineStacks
.find(off
)) {
108 if (pos
->frame
!= kInvalidFrameID
) return *pos
;
113 IFrame
getInlineFrame(IFrameID id
) {
114 return s_inlineFrames
[id
];
117 void eraseInlineStack(CTCA addr
) {
118 if (auto stk
= s_inlineStacks
.find(tc::addrToOffset(addr
))) {
119 stk
->frame
= kInvalidFrameID
;
123 void eraseInlineStacksInRange(CTCA start
, CTCA end
) {
124 auto const start_offset
= tc::addrToOffset(start
);
125 auto const end_offset
= tc::addrToOffset(end
);
126 s_inlineStacks
.filter_keys([&](const uint32_t offset
) {
127 return start_offset
<= offset
&& offset
< end_offset
;
131 const uint64_t* addrForLiteral(uint64_t val
) {
132 if (auto it
= s_literals
.find(val
)) {
133 assertx(**it
== val
);
139 size_t numCatchTraces() {
140 return s_catchTraceMap
.size();
143 void eraseCatchTrace(CTCA addr
) {
144 if (auto ct
= s_catchTraceMap
.find(tc::addrToOffset(addr
))) {
145 *ct
= kInvalidCatchTrace
;
149 folly::Optional
<TCA
> getCatchTrace(CTCA ip
) {
150 auto const found
= s_catchTraceMap
.find(tc::addrToOffset(ip
));
151 if (found
&& *found
!= kInvalidCatchTrace
) return tc::offsetToAddr(*found
);
155 Reason
* getTrapReason(CTCA addr
) {
156 return s_trapReasonMap
.find(tc::addrToOffset(addr
));
159 void poolLiteral(CodeBlock
& cb
, CGMeta
& meta
, uint64_t val
, uint8_t width
,
161 meta
.literalsToPool
.emplace_back(
162 CGMeta::PoolLiteralMeta
{
171 void addVeneer(CGMeta
& meta
, TCA source
, TCA target
) {
172 FTRACE(5, "addVeneer: source = {}, target = {}\n", source
, target
);
173 meta
.veneers
.emplace_back(CGMeta::VeneerData
{source
, target
});
176 ////////////////////////////////////////////////////////////////////////////////
178 void CGMeta::setJmpTransID(TCA jmp
, TransID transID
, TransKind kind
) {
179 if (kind
!= TransKind::Profile
) return;
181 FTRACE(5, "setJmpTransID: adding {} => {}\n", jmp
, transID
);
182 jmpTransIDs
.emplace_back(jmp
, transID
);
185 void CGMeta::process(
186 GrowableVector
<IncomingBranch
>* inProgressTailBranches
188 process_only(inProgressTailBranches
);
192 void CGMeta::process_literals() {
193 assertx(literalsToPool
.empty());
194 for (auto& pair
: literalAddrs
) {
195 if (s_literals
.find(pair
.first
)) {
196 // TreadHashMap doesn't allow re-inserting existing keys
199 s_literals
.insert(pair
.first
, pair
.second
);
201 literalAddrs
.clear();
204 void CGMeta::process_only(
205 GrowableVector
<IncomingBranch
>* inProgressTailBranches
207 tc::assertOwnsMetadataLock();
209 for (auto const& pair
: fixups
) {
210 assertx(tc::isValidCodeAddress(pair
.first
));
211 FixupMap::recordFixup(pair
.first
, pair
.second
);
215 processInlineFrames(*this);
216 inlineFrames
.clear();
217 inlineStacks
.clear();
219 for (auto const& ct
: catches
) {
220 auto const key
= tc::addrToOffset(ct
.first
);
221 auto const val
= tc::addrToOffset(ct
.second
);
222 if (auto pos
= s_catchTraceMap
.find(key
)) {
225 s_catchTraceMap
.insert(key
, val
);
230 if (auto profData
= jit::profData()) {
231 for (auto const& elm
: jmpTransIDs
) {
232 profData
->setJmpTransID(elm
.first
, elm
.second
);
237 for (auto const& pair
: trapReasons
) {
238 auto addr
= tc::addrToOffset(pair
.first
);
239 if (auto r
= s_trapReasonMap
.find(addr
)) {
242 s_trapReasonMap
.insert(addr
, pair
.second
);
249 if (inProgressTailBranches
) {
250 inProgressTailJumps
.swap(*inProgressTailBranches
);
252 assertx(inProgressTailJumps
.empty());
254 for (auto& stub
: reusedStubs
) {
255 Debug::DebugInfo::Get()->recordRelocMap(stub
, nullptr, "NewStub");
260 void CGMeta::clear() {
264 inlineFrames
.clear();
265 inlineStacks
.clear();
267 literalsToPool
.clear();
268 literalAddrs
.clear();
272 addressImmediates
.clear();
274 codePointers
.clear();
275 inProgressTailJumps
.clear();
277 smashableCallData
.clear();
278 smashableJumpData
.clear();
281 bool CGMeta::empty() const {
283 watchpoints
.empty() &&
286 inlineFrames
.empty() &&
287 inlineStacks
.empty() &&
288 jmpTransIDs
.empty() &&
289 literalsToPool
.empty() &&
290 literalAddrs
.empty() &&
292 alignments
.empty() &&
293 reusedStubs
.empty() &&
294 addressImmediates
.empty() &&
295 !fallthru
.hasValue() &&
296 codePointers
.empty() &&
297 inProgressTailJumps
.empty() &&
299 smashableCallData
.empty() &&
300 smashableJumpData
.empty();