Fix reporting of func body dispatch sizes in retranslate-all mode
[hiphop-php.git] / hphp / runtime / vm / jit / tc-prologue.cpp
blobdce6f35b45fb41e5f4604c7a3e144e3b62158ecf
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/tc.h"
18 #include "hphp/runtime/vm/jit/tc-internal.h"
19 #include "hphp/runtime/vm/jit/tc-record.h"
20 #include "hphp/runtime/vm/jit/tc-region.h"
21 #include "hphp/runtime/vm/jit/tc-relocate.h"
23 #include "hphp/runtime/vm/debug/debug.h"
24 #include "hphp/runtime/vm/jit/align.h"
25 #include "hphp/runtime/vm/jit/cg-meta.h"
26 #include "hphp/runtime/vm/jit/func-guard.h"
27 #include "hphp/runtime/vm/jit/func-prologue.h"
28 #include "hphp/runtime/vm/jit/mcgen.h"
29 #include "hphp/runtime/vm/jit/prof-data.h"
30 #include "hphp/runtime/vm/jit/smashable-instr.h"
31 #include "hphp/runtime/vm/jit/trans-db.h"
32 #include "hphp/runtime/vm/jit/vm-protect.h"
33 #include "hphp/runtime/vm/jit/vtune-jit.h"
35 #include "hphp/util/trace.h"
37 TRACE_SET_MOD(mcg);
39 namespace HPHP { namespace jit { namespace tc {
41 namespace {
43 void emitFuncPrologueImpl(Func* func, int argc, TransKind kind,
44 PrologueMetaInfo& info) {
45 assertx(isPrologue(kind));
47 if (!newTranslation()) {
48 info.start = nullptr;
49 return;
52 auto& transID = info.transID;
53 auto& loc = info.loc;
54 auto& fixups = info.meta;
55 const int nparams = func->numNonVariadicParams();
56 const int paramIndex = argc <= nparams ? argc : nparams + 1;
58 auto const funcBody =
59 SrcKey{func, func->getEntryForNumArgs(argc), SrcKey::PrologueTag{}};
61 profileSetHotFunc();
62 auto codeView = code().view(kind);
63 TCA mainOrig = codeView.main().frontier();
65 // If we're close to a cache line boundary, just burn some space to
66 // try to keep the func and its body on fewer total lines.
67 align(codeView.main(), &fixups, Alignment::CacheLineRoundUp,
68 AlignContext::Dead);
70 TransLocMaker maker(codeView);
71 maker.markStart();
73 // Careful: this isn't necessarily the real entry point. For funcIsMagic
74 // prologues, this is just a possible prologue.
75 TCA aStart = codeView.main().frontier();
77 // Give the prologue a TransID if we have profiling data.
78 transID = [&]{
79 if (kind == TransKind::ProfPrologue) {
80 auto const profData = jit::profData();
81 auto const id = profData->allocTransID();
82 profData->addTransProfPrologue(id, funcBody, paramIndex);
83 return id;
85 if (profData() && transdb::enabled()) {
86 return profData()->allocTransID();
88 return kInvalidTransID;
89 }();
91 info.start = genFuncPrologue(transID, kind, func, argc, codeView, fixups);
93 loc = maker.markEnd().loc();
95 if (RuntimeOption::EvalEnableReusableTC) {
96 TCA UNUSED ms = loc.mainStart(), me = loc.mainEnd(),
97 cs = loc.coldStart(), ce = loc.coldEnd(),
98 fs = loc.frozenStart(), fe = loc.frozenEnd(),
99 oldStart = info.start;
101 auto const did_relocate = relocateNewTranslation(loc, codeView, fixups,
102 &info.start);
104 if (did_relocate) {
105 FTRACE_MOD(Trace::reusetc, 1,
106 "Relocated prologue for func {} (id = {}) "
107 "from M[{}, {}], C[{}, {}], F[{}, {}] to M[{}, {}] "
108 "C[{}, {}] F[{}, {}] orig start @ {} new start @ {}\n",
109 func->fullName()->data(), func->getFuncId(),
110 ms, me, cs, ce, fs, fe, loc.mainStart(), loc.mainEnd(),
111 loc.coldStart(), loc.coldEnd(), loc.frozenStart(),
112 loc.frozenEnd(), oldStart, info.start);
113 } else {
114 FTRACE_MOD(Trace::reusetc, 1,
115 "Created prologue for func {} (id = {}) at "
116 "M[{}, {}], C[{}, {}], F[{}, {}] start @ {}\n",
117 func->fullName()->data(), func->getFuncId(),
118 ms, me, cs, ce, fs, fe, oldStart);
121 if (loc.mainStart() != aStart) {
122 codeView.main().setFrontier(mainOrig); // we may have shifted to align
126 info.finalView = std::make_unique<CodeCache::View>(codeView);
128 assertx(funcGuardMatches(funcGuardFromPrologue(info.start, func), func));
129 assertx(code().isValidCodeAddress(info.start));
132 void emitFuncPrologueInternal(Func* func, int argc, TransKind kind,
133 PrologueMetaInfo& info) {
134 try {
135 emitFuncPrologueImpl(func, argc, kind, info);
136 } catch (const DataBlockFull& dbFull) {
138 // Fail hard if the block isn't code.hot.
139 always_assert_flog(dbFull.name == "hot",
140 "data block = {}\nmessage: {}\n",
141 dbFull.name, dbFull.what());
143 // Otherwise, fall back to code.main and retry.
144 code().disableHot();
145 try {
146 emitFuncPrologueImpl(func, argc, kind, info);
147 } catch (const DataBlockFull& dbStillFull) {
148 always_assert_flog(0, "data block = {}\nmessage: {}\n",
149 dbStillFull.name, dbStillFull.what());
154 ////////////////////////////////////////////////////////////////////////////////
157 bool publishFuncPrologueMeta(Func* func, int nArgs, TransKind kind,
158 PrologueMetaInfo& info) {
159 assertOwnsMetadataLock();
161 const auto start = info.start;
162 if (start == nullptr) return false;
164 const auto transID = info.transID;
165 const auto& loc = info.loc;
166 auto& meta = info.meta;
168 const int nparams = func->numNonVariadicParams();
169 const int paramIndex = nArgs <= nparams ? nArgs : nparams + 1;
170 auto codeView = *info.finalView;
171 auto const funcBody = SrcKey{func, func->getEntryForNumArgs(nArgs),
172 SrcKey::PrologueTag{}};
174 if (RuntimeOption::EvalEnableReusableTC) {
175 recordFuncPrologue(func, loc);
178 if (RuntimeOption::EvalPerfRelocate) {
179 GrowableVector<IncomingBranch> incomingBranches;
180 recordPerfRelocMap(loc.mainStart(), loc.mainEnd(),
181 loc.coldCodeStart(), loc.coldEnd(),
182 funcBody, paramIndex,
183 incomingBranches,
184 meta);
186 meta.process(nullptr);
188 assertx(funcGuardMatches(funcGuardFromPrologue(start, func), func));
189 assertx(code().isValidCodeAddress(start));
190 assertx(isPrologue(kind));
192 TransRec tr{funcBody, transID, kind, loc.mainStart(), loc.mainSize(),
193 loc.coldStart(), loc.coldSize(), loc.frozenStart(), loc.frozenSize()};
194 transdb::addTranslation(tr);
195 if (RuntimeOption::EvalJitUseVtuneAPI) {
196 reportTraceletToVtune(func->unit(), func, tr);
199 recordGdbTranslation(funcBody, func, codeView.main(), loc.mainStart(),
200 loc.mainEnd(), false, true);
201 recordBCInstr(OpFuncPrologue, loc.mainStart(), loc.mainEnd(), false);
202 return true;
205 bool publishFuncPrologueCode(Func* func, int nArgs, PrologueMetaInfo& info) {
206 assertOwnsMetadataLock();
208 const auto start = info.start;
209 if (start == nullptr) return false;
211 const int nparams = func->numNonVariadicParams();
212 const int paramIndex = nArgs <= nparams ? nArgs : nparams + 1;
214 TRACE(2, "funcPrologue %s(%d) setting prologue %p\n",
215 func->fullName()->data(), nArgs, start);
216 func->setPrologue(paramIndex, start);
217 return true;
220 void smashFuncCallers(TCA start, ProfTransRec* rec) {
221 assertOwnsMetadataLock();
222 assertx(rec->isProflogue());
224 const auto func = rec->func();
225 auto lock = rec->lockCallerList();
227 for (auto toSmash : rec->mainCallers()) {
228 smashCall(toSmash, start);
231 // If the prologue has a matching guard, then smash its guard-callers as
232 // well.
233 auto const guard = funcGuardFromPrologue(start, func);
234 if (funcGuardMatches(guard, func)) {
235 for (auto toSmash : rec->guardCallers()) {
236 smashCall(toSmash, guard);
239 rec->clearAllCallers();
243 * Emit an OptPrologue for the given `info', updating it accordingly.
245 void emitFuncPrologueOptInternal(PrologueMetaInfo& info) {
246 assertOwnsCodeLock();
247 assertOwnsMetadataLock();
249 emitFuncPrologueInternal(info.transRec->func(), info.transRec->prologueArgs(),
250 TransKind::OptPrologue, info);
253 TCA emitFuncPrologue(Func* func, int argc, TransKind kind) {
254 VMProtect _;
256 auto codeLock = lockCode();
257 auto metaLock = lockMetadata();
259 PrologueMetaInfo info{nullptr};
260 emitFuncPrologueInternal(func, argc, kind, info);
261 publishFuncPrologueMeta(func, argc, kind, info);
262 publishFuncPrologueCode(func, argc, info);
263 return info.start;
267 * Emit and publish an OptPrologue for `rec'.
269 void emitFuncPrologueOpt(ProfTransRec* rec) {
270 VMProtect _;
272 auto codeLock = lockCode();
273 auto metaLock = lockMetadata();
275 PrologueMetaInfo info(rec);
276 emitFuncPrologueOptInternal(info);
277 if (info.start) {
278 publishFuncPrologueMeta(rec->func(), rec->prologueArgs(),
279 TransKind::OptPrologue, info);
280 publishFuncPrologueCode(rec->func(), rec->prologueArgs(), info);
281 smashFuncCallers(info.start, rec);
285 TCA emitFuncBodyDispatchInternal(Func* func, const DVFuncletsVec& dvs,
286 CodeCache::View view) {
287 return genFuncBodyDispatch(func, dvs, view);
290 void publishFuncBodyDispatch(Func* func, TCA start, TCA end) {
291 TRACE(2, "emitFuncBodyDispatch: emitted code for %s at %p\n",
292 func->fullName()->data(), start);
294 func->setFuncBody(start);
296 if (!RuntimeOption::EvalJitNoGdb) {
297 Debug::DebugInfo::Get()->recordStub(
298 Debug::TCRange(start, end, false),
299 Debug::lookupFunction(func, false, false, true));
301 if (RuntimeOption::EvalJitUseVtuneAPI) {
302 reportHelperToVtune(func->fullName()->data(), start, end);
304 if (RuntimeOption::EvalPerfPidMap) {
305 Debug::DebugInfo::Get()->recordPerfMap(
306 Debug::TCRange(start, end, false),
307 SrcKey{}, func, false, false);
311 TCA emitFuncBodyDispatch(Func* func, const DVFuncletsVec& dvs, TransKind kind) {
312 VMProtect _;
314 auto codeLock = lockCode();
315 auto metaLock = lockMetadata();
317 const auto& view = code().view(kind);
318 const auto tca = emitFuncBodyDispatchInternal(func, dvs, view);
319 publishFuncBodyDispatch(func, tca, view.main().frontier());
320 return tca;