Remove SpillFrame, merge its memory effects into CallEffects and InlineEnterEffects
[hiphop-php.git] / hphp / runtime / vm / jit / cg-meta.cpp
blob0bb2a2ddafdd24a21660d20f3b64c584d752317e
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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 {
30 TRACE_SET_MOD(mcg);
32 namespace {
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) {
61 auto& f = frames[i];
62 auto newFrame = IFrame{f.func, f.callOff, f.parent + start};
63 s_inlineFrames.exchange(start + i, newFrame);
66 return start;
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);
81 void insertStacks(
82 IFrameID start, const std::vector<std::pair<TCA,IStack>>& stacks
83 ) {
84 for (auto& stk : stacks) {
85 if (!stk.second.nframes) continue;
86 auto off = stackAddrToOffset(stk.first);
87 auto val = stk.second;
88 val.frame += start;
89 if (auto pos = s_inlineStacks.find(off)) {
90 *pos = val;
91 } else {
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;
110 return folly::none;
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);
134 return *it;
136 return nullptr;
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);
152 return folly::none;
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,
160 bool smashable) {
161 meta.literalsToPool.emplace_back(
162 CGMeta::PoolLiteralMeta {
163 val,
164 cb.frontier(),
165 smashable,
166 width
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);
189 clear();
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
197 continue;
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);
213 fixups.clear();
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)) {
223 *pos = val;
224 } else {
225 s_catchTraceMap.insert(key, val);
228 catches.clear();
230 if (auto profData = jit::profData()) {
231 for (auto const& elm : jmpTransIDs) {
232 profData->setJmpTransID(elm.first, elm.second);
235 jmpTransIDs.clear();
237 for (auto const& pair : trapReasons) {
238 auto addr = tc::addrToOffset(pair.first);
239 if (auto r = s_trapReasonMap.find(addr)) {
240 *r = pair.second;
241 } else {
242 s_trapReasonMap.insert(addr, pair.second);
245 trapReasons.clear();
247 process_literals();
249 if (inProgressTailBranches) {
250 inProgressTailJumps.swap(*inProgressTailBranches);
252 assertx(inProgressTailJumps.empty());
254 for (auto& stub : reusedStubs) {
255 Debug::DebugInfo::Get()->recordRelocMap(stub, nullptr, "NewStub");
257 reusedStubs.clear();
260 void CGMeta::clear() {
261 watchpoints.clear();
262 fixups.clear();
263 catches.clear();
264 inlineFrames.clear();
265 inlineStacks.clear();
266 jmpTransIDs.clear();
267 literalsToPool.clear();
268 literalAddrs.clear();
269 veneers.clear();
270 alignments.clear();
271 reusedStubs.clear();
272 addressImmediates.clear();
273 fallthru.clear();
274 codePointers.clear();
275 inProgressTailJumps.clear();
276 bcMap.clear();
277 smashableCallData.clear();
278 smashableJumpData.clear();
281 bool CGMeta::empty() const {
282 return
283 watchpoints.empty() &&
284 fixups.empty() &&
285 catches.empty() &&
286 inlineFrames.empty() &&
287 inlineStacks.empty() &&
288 jmpTransIDs.empty() &&
289 literalsToPool.empty() &&
290 literalAddrs.empty() &&
291 veneers.empty() &&
292 alignments.empty() &&
293 reusedStubs.empty() &&
294 addressImmediates.empty() &&
295 !fallthru.hasValue() &&
296 codePointers.empty() &&
297 inProgressTailJumps.empty() &&
298 bcMap.empty() &&
299 smashableCallData.empty() &&
300 smashableJumpData.empty();