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/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/stack-offsets.h"
23 #include "hphp/runtime/vm/jit/stub-alloc.h"
24 #include "hphp/runtime/vm/jit/tc.h"
25 #include "hphp/runtime/vm/jit/tc-internal.h"
26 #include "hphp/runtime/vm/jit/translator-inline.h"
27 #include "hphp/runtime/vm/jit/unique-stubs.h"
28 #include "hphp/runtime/vm/jit/vasm-gen.h"
29 #include "hphp/runtime/vm/jit/vasm-instr.h"
30 #include "hphp/runtime/vm/jit/vasm-unit.h"
31 #include "hphp/runtime/vm/resumable.h"
33 #include "hphp/util/arch.h"
34 #include "hphp/util/data-block.h"
35 #include "hphp/util/trace.h"
37 #include "hphp/vixl/a64/macro-assembler-a64.h"
38 #include "hphp/vixl/a64/disasm-a64.h"
40 #include <folly/Optional.h>
42 namespace HPHP
{ namespace jit
{ namespace svcreq
{
44 ///////////////////////////////////////////////////////////////////////////////
46 TRACE_SET_MOD(servicereq
);
48 ///////////////////////////////////////////////////////////////////////////////
52 ///////////////////////////////////////////////////////////////////////////////
55 * Service request stub emitter.
57 * Emit a service request stub of type `sr' at `start' in `cb'.
59 void emit_svcreq(CodeBlock
& cb
,
67 FTRACE(2, "svcreq @{} {}(spOff={}, ", start
, to_name(sr
), spOff
.offset
);
73 return tracing::Props
{}
74 .add("service_request", to_name(sr
))
75 .add("persist", persist
);
79 auto const is_reused
= start
!= cb
.frontier();
81 if (!is_reused
) cb
.assertCanEmit(stub_size());
84 auto const realAddr
= is_reused
? start
: cb
.toDestAddress(start
);
85 stub
.init(start
, realAddr
, stub_size(), "svcreq_stub");
88 Vauto vasm
{stub
, stub
, data
, meta
};
89 auto& v
= vasm
.main();
91 auto live_out
= leave_trace_regs();
93 assertx(argv
.size() <= kMaxArgs
);
95 // Pick up CondCode arguments first---vasm may optimize immediate loads
96 // into operations which clobber status flags.
97 for (auto i
= 0; i
< argv
.size(); ++i
) {
98 auto const& arg
= argv
[i
];
99 if (arg
.kind
!= Arg::Kind::CondCode
) continue;
101 FTRACE(2, "c({}), ", cc_names
[arg
.cc
]);
102 v
<< setcc
{arg
.cc
, r_svcreq_sf(), rbyte(r_svcreq_arg(i
))};
105 for (auto i
= 0; i
< argv
.size(); ++i
) {
106 auto const& arg
= argv
[i
];
107 auto const r
= r_svcreq_arg(i
);
110 case Arg::Kind::Immed
:
111 FTRACE(2, "{}, ", arg
.imm
);
112 v
<< copy
{v
.cns(arg
.imm
), r
};
114 case Arg::Kind::Address
:
115 FTRACE(2, "{}(%rip), ", arg
.imm
);
116 always_assert(deltaFits(arg
.addr
- start
, sz::dword
));
117 v
<< leap
{reg::rip
[arg
.imm
], r
};
119 case Arg::Kind::CondCode
:
124 FTRACE(2, ") : stub@");
128 v
<< copy
{v
.cns(0), r_svcreq_stub()};
130 FTRACE(2, "{}", stub
.base());
131 v
<< leap
{reg::rip
[int64_t(stub
.base())], r_svcreq_stub()};
133 v
<< copy
{v
.cns(sr
), r_svcreq_req()};
134 v
<< copy
{v
.cns(spOff
.offset
), r_svcreq_spoff()};
136 live_out
|= r_svcreq_stub();
137 live_out
|= r_svcreq_req();
138 live_out
|= r_svcreq_spoff();
140 v
<< jmpi
{tc::ustubs().handleSRHelper
, live_out
};
142 // We pad ephemeral stubs unconditionally. This is required for
143 // correctness by the x64 code relocator.
144 vasm
.unit().padding
= !persist
;
147 if (!is_reused
) cb
.skip(stub
.used());
150 ///////////////////////////////////////////////////////////////////////////////
154 ///////////////////////////////////////////////////////////////////////////////
156 TCA
emit_bindjmp_stub(CodeBlock
& cb
, DataBlock
& data
, CGMeta
& fixups
,
157 SBInvOffset spOff
, TCA jmp
, SrcKey target
) {
158 return emit_ephemeral(
162 allocTCStub(cb
, &fixups
),
170 TCA
emit_bindaddr_stub(CodeBlock
& cb
, DataBlock
& data
, CGMeta
& fixups
,
171 SBInvOffset spOff
, TCA
* addr
, SrcKey target
) {
172 // Right now it's possible that addr may not belong to the data segment,
173 // as is the case with SSwitchMap (see #10347945) and thus may not be PIC
174 // addressable. Passing a TCA generates an RIP relative address which can
175 // be handled by the relocation logic, while a TCA* will generate an immediate
176 // address which will not be remapped.
177 if (data
.contains((TCA
)addr
)) {
178 return emit_ephemeral(
182 allocTCStub(cb
, &fixups
),
185 (TCA
)addr
, // needs to be RIP relative so that we can relocate it
190 return emit_ephemeral(
194 allocTCStub(cb
, &fixups
),
202 ///////////////////////////////////////////////////////////////////////////////
205 std::atomic
<bool> s_fullForStub
{false};
208 TCA
emit_interp_no_translate_stub(SBInvOffset spOff
, SrcKey sk
) {
209 FTRACE(2, "interp_no_translate_stub @{} {}\n", showShort(sk
), spOff
.offset
);
211 // No point on trying to emit if we already failed once.
212 if (s_fullForStub
.load(std::memory_order_relaxed
)) {
213 FTRACE(4, " no space for {}, bailing\n", showShort(sk
));
218 tracing::Block _
{"emit-interp-no-translate-stub"};
220 auto codeLock
= tc::lockCode();
221 auto metaLock
= tc::lockMetadata();
223 auto view
= tc::code().view();
224 auto& cb
= view
.frozen();
225 auto& data
= view
.data();
227 auto const start
= vwrap(
230 [&] (Vout
& v
) { emitInterpReqNoTranslate(v
, sk
, spOff
); },
232 true /* nullOnFull */
235 // We passed true to nullOnFull, so if the TC was out of space, we
236 // just get a nullptr address.
238 FTRACE(4, " ran out of space while making stub for {}\n", showShort(sk
));
239 s_fullForStub
.store(true, std::memory_order_relaxed
);
241 FTRACE(4, " emitted stub {} for {}\n", start
, showShort(sk
));
245 ///////////////////////////////////////////////////////////////////////////////