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/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"
39 namespace HPHP
{ namespace jit
{ namespace tc
{
43 void emitFuncPrologueImpl(Func
* func
, int argc
, TransKind kind
,
44 PrologueMetaInfo
& info
) {
45 assertx(isPrologue(kind
));
47 if (!newTranslation()) {
52 auto& transID
= info
.transID
;
54 auto& fixups
= info
.meta
;
55 const int nparams
= func
->numNonVariadicParams();
56 const int paramIndex
= argc
<= nparams
? argc
: nparams
+ 1;
59 SrcKey
{func
, func
->getEntryForNumArgs(argc
), SrcKey::PrologueTag
{}};
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
,
70 TransLocMaker
maker(codeView
);
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.
79 if (kind
== TransKind::ProfPrologue
) {
80 auto const profData
= jit::profData();
81 auto const id
= profData
->allocTransID();
82 profData
->addTransProfPrologue(id
, funcBody
, paramIndex
);
85 if (profData() && transdb::enabled()) {
86 return profData()->allocTransID();
88 return kInvalidTransID
;
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
,
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
);
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
) {
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.
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
,
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);
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
);
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
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
) {
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
);
267 * Emit and publish an OptPrologue for `rec'.
269 void emitFuncPrologueOpt(ProfTransRec
* rec
) {
272 auto codeLock
= lockCode();
273 auto metaLock
= lockMetadata();
275 PrologueMetaInfo
info(rec
);
276 emitFuncPrologueOptInternal(info
);
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
) {
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());