Store num args instead of offset in prologue and func entry SrcKeys
[hiphop-php.git] / hphp / runtime / vm / jit / service-requests.cpp
blobd329ef7b8f66355e3e94a68a33d81be08d9a5b9c
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/service-requests.h"
19 #include "hphp/runtime/vm/jit/types.h"
20 #include "hphp/runtime/vm/jit/abi.h"
21 #include "hphp/runtime/vm/jit/align.h"
22 #include "hphp/runtime/vm/jit/func-order.h"
23 #include "hphp/runtime/vm/jit/prof-data.h"
24 #include "hphp/runtime/vm/jit/stack-offsets.h"
25 #include "hphp/runtime/vm/jit/tc.h"
26 #include "hphp/runtime/vm/jit/tc-internal.h"
27 #include "hphp/runtime/vm/jit/tc-record.h"
28 #include "hphp/runtime/vm/jit/trans-db.h"
29 #include "hphp/runtime/vm/jit/trans-rec.h"
30 #include "hphp/runtime/vm/jit/translator-inline.h"
31 #include "hphp/runtime/vm/jit/unique-stubs.h"
32 #include "hphp/runtime/vm/jit/vasm-gen.h"
33 #include "hphp/runtime/vm/jit/vasm-instr.h"
34 #include "hphp/runtime/vm/jit/vasm-unit.h"
35 #include "hphp/runtime/vm/jit/vtune-jit.h"
36 #include "hphp/runtime/vm/resumable.h"
37 #include "hphp/util/arch.h"
38 #include "hphp/util/data-block.h"
39 #include "hphp/util/hash-map.h"
40 #include "hphp/util/trace.h"
42 #include "hphp/vixl/a64/macro-assembler-a64.h"
43 #include "hphp/vixl/a64/disasm-a64.h"
45 namespace HPHP::jit::svcreq {
47 ///////////////////////////////////////////////////////////////////////////////
49 TRACE_SET_MOD(servicereq);
51 ///////////////////////////////////////////////////////////////////////////////
53 namespace {
55 uint64_t toStubKey(StubType type, SrcKey sk, SBInvOffset spOff) {
56 auto const t = static_cast<uint8_t>(type);
57 auto const bcOffOrNumArgs = sk.funcEntry() ? sk.numEntryArgs() : sk.offset();
58 assertx(t < (1 << 2));
59 assertx(0 <= bcOffOrNumArgs && bcOffOrNumArgs < (1LL << 30));
60 assertx(0 <= spOff.offset && spOff.offset < (1LL << 31));
61 return
62 (static_cast<uint64_t>(t) << 62) +
63 (static_cast<uint64_t>(sk.funcEntry()) << 61) +
64 (static_cast<uint64_t>(bcOffOrNumArgs) << 31) +
65 (static_cast<uint64_t>(spOff.offset));
68 folly_concurrent_hash_map_simd<uint64_t, TCA> s_stubMap;
70 TCA typeToHandler(StubType type) {
71 switch (type) {
72 case StubType::Translate: return tc::ustubs().handleTranslate;
73 case StubType::Retranslate: return tc::ustubs().handleRetranslate;
74 default: not_reached();
78 TCA typeToFuncEntryHandler(StubType type) {
79 switch (type) {
80 case StubType::Translate: return tc::ustubs().handleTranslateFuncEntry;
81 case StubType::Retranslate: return tc::ustubs().handleRetranslateFuncEntry;
82 default: not_reached();
86 std::string typeToName(StubType type) {
87 switch (type) {
88 case StubType::Translate: return "translate";
89 case StubType::Retranslate: return "retranslate";
90 default: not_reached();
94 std::atomic<bool> s_fullForStub{false};
96 TCA emitStub(StubType type, SrcKey sk, SBInvOffset spOff) {
97 FTRACE(2, "svcreq::emitStub {} @{} {}\n",
98 typeToName(type), showShort(sk), spOff.offset);
99 assertx(!sk.prologue());
101 if (s_fullForStub.load(std::memory_order_relaxed)) {
102 FTRACE(4, " no space for {}, bailing\n", showShort(sk));
103 return nullptr;
106 tracing::Pause _p;
107 tracing::Block _{"svcreq::emitStub"};
109 auto codeLock = tc::lockCode();
111 auto view = tc::code().view(TransKind::Anchor);
112 TCA mainStart = view.main().frontier();
113 TCA coldStart = view.cold().frontier();
114 TCA frozenStart = view.frozen().frontier();
116 auto const emit = [&] (Vout& v) {
117 assertx(!sk.funcEntry());
118 v << copy{v.cns(sk.offset()), rarg(0)};
119 v << copy{v.cns(spOff.offset), rarg(1)};
120 v << jmpi{typeToHandler(type), leave_trace_regs() | arg_regs(2)};
123 auto const emitFuncEntry = [&] (Vout& v) {
124 assertx(sk.funcEntry());
125 assertx(spOff == SBInvOffset{0});
126 v << copy{v.cns(sk.numEntryArgs()), rarg(0)};
127 v << jmpi{typeToFuncEntryHandler(type), leave_trace_regs() | arg_regs(1)};
130 auto const start = vwrap(
131 view.cold(),
132 view.data(),
133 [&] (Vout& v) {
134 if (!sk.funcEntry()) {
135 emit(v);
136 } else {
137 emitFuncEntry(v);
140 nullptr,
141 false, /* relocate */
142 true /* nullOnFull */
145 // We passed true to nullOnFull, so if the TC was out of space, we
146 // just get a nullptr address.
147 if (!start) {
148 FTRACE(4, " ran out of space while making stub for {}\n", showShort(sk));
149 s_fullForStub.store(true, std::memory_order_relaxed);
150 return nullptr;
153 assertx(view.main().frontier() == mainStart);
154 assertx(view.cold().frontier() != coldStart);
155 assertx(view.frozen().frontier() == frozenStart);
157 if (RuntimeOption::EvalDumpTCAnchors) {
158 auto metaLock = tc::lockMetadata();
159 auto const transID = profData() && transdb::enabled()
160 ? profData()->allocTransID() : kInvalidTransID;
161 TransRec tr(sk, transID, TransKind::Anchor, mainStart, 0,
162 coldStart, view.cold().frontier() - coldStart, frozenStart, 0);
163 transdb::addTranslation(tr);
164 FuncOrder::recordTranslation(tr);
165 if (RuntimeOption::EvalJitUseVtuneAPI) {
166 reportTraceletToVtune(sk.unit(), sk.func(), tr);
168 tc::recordTranslationSizes(tr);
170 assertx(!transdb::enabled() ||
171 transdb::getTransRec(coldStart)->kind == TransKind::Anchor);
174 FTRACE(4, " emitted stub {} for {}\n", start, showShort(sk));
175 return start;
180 TCA getOrEmitStub(StubType type, SrcKey sk, SBInvOffset spOff) {
181 assertx(!sk.prologue());
183 auto const key = toStubKey(type, sk, spOff);
184 auto const it = s_stubMap.find(key);
185 if (it != s_stubMap.end()) return it->second;
187 auto const stub = emitStub(type, sk, spOff);
188 if (stub == nullptr) return nullptr;
190 auto const pair = s_stubMap.insert({key, stub});
191 if (!pair.second) return pair.first->second;
192 return stub;
195 ///////////////////////////////////////////////////////////////////////////////
197 TCA emit_interp_no_translate_stub(SBInvOffset spOff, SrcKey sk) {
198 FTRACE(2, "interp_no_translate_stub @{} {}\n", showShort(sk), spOff.offset);
200 // No point on trying to emit if we already failed once.
201 if (s_fullForStub.load(std::memory_order_relaxed)) {
202 FTRACE(4, " no space for {}, bailing\n", showShort(sk));
203 return nullptr;
206 tracing::Pause _p;
207 tracing::Block _{"emit-interp-no-translate-stub"};
209 auto codeLock = tc::lockCode();
210 auto metaLock = tc::lockMetadata();
212 auto view = tc::code().view();
213 auto& cb = view.frozen();
214 auto& data = view.data();
216 auto const start = vwrap(
218 data,
219 [&] (Vout& v) { emitInterpReqNoTranslate(v, sk, spOff); },
220 nullptr,
221 false,
222 true /* nullOnFull */
225 // We passed true to nullOnFull, so if the TC was out of space, we
226 // just get a nullptr address.
227 if (!start) {
228 FTRACE(4, " ran out of space while making stub for {}\n", showShort(sk));
229 s_fullForStub.store(true, std::memory_order_relaxed);
231 FTRACE(4, " emitted stub {} for {}\n", start, showShort(sk));
232 return start;
235 ///////////////////////////////////////////////////////////////////////////////