2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2015 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/irgen-func-prologue.h"
19 #include "hphp/runtime/base/attr.h"
20 #include "hphp/runtime/base/runtime-option.h"
21 #include "hphp/runtime/vm/bytecode.h"
22 #include "hphp/runtime/vm/func.h"
23 #include "hphp/runtime/vm/hhbc.h"
24 #include "hphp/runtime/vm/srckey.h"
26 #include "hphp/runtime/vm/jit/check.h"
27 #include "hphp/runtime/vm/jit/extra-data.h"
28 #include "hphp/runtime/vm/jit/fixup.h"
29 #include "hphp/runtime/vm/jit/ir-opcode.h"
30 #include "hphp/runtime/vm/jit/ir-unit.h"
31 #include "hphp/runtime/vm/jit/irgen.h"
32 #include "hphp/runtime/vm/jit/irgen-internal.h"
33 #include "hphp/runtime/vm/jit/irgen-state.h"
34 #include "hphp/runtime/vm/jit/mc-generator.h"
35 #include "hphp/runtime/vm/jit/prof-data.h"
36 #include "hphp/runtime/vm/jit/stack-offsets.h"
37 #include "hphp/runtime/vm/jit/translator.h"
38 #include "hphp/runtime/vm/jit/type.h"
40 namespace HPHP
{ namespace jit
{ namespace irgen
{
42 ///////////////////////////////////////////////////////////////////////////////
46 ///////////////////////////////////////////////////////////////////////////////
49 * Initialize parameters.
51 * Set un-passed parameters to Uninit (or the empty array, for the variadic
52 * capture parameter) and set up the ExtraArgs on the ActRec as needed.
54 void init_params(IRGS
& env
, uint32_t argc
) {
56 * Maximum number of default-value parameter initializations to unroll.
58 constexpr auto kMaxParamsInitUnroll
= 5;
60 auto const func
= env
.context
.func
;
61 auto const nparams
= func
->numNonVariadicParams();
64 // Too few arguments; set everything else to Uninit.
65 if (nparams
- argc
<= kMaxParamsInitUnroll
) {
66 for (auto i
= argc
; i
< nparams
; ++i
) {
67 gen(env
, StLoc
, LocalId
{i
}, fp(env
), cns(env
, TUninit
));
70 gen(env
, StLocRange
, LocalIdRange
{argc
, nparams
},
71 fp(env
), cns(env
, TUninit
));
75 if (argc
<= nparams
&& func
->hasVariadicCaptureParam()) {
76 // Need to initialize `...$args'.
77 gen(env
, StLoc
, LocalId
{nparams
}, fp(env
),
78 cns(env
, staticEmptyArray()));
81 // Null out or initialize the frame's ExtraArgs.
82 gen(env
, InitExtraArgs
, FuncEntryData
{func
, argc
}, fp(env
));
86 * Set up the closure object and class context.
88 * We swap out the Closure object stored in m_this, and replace it with the
89 * closure's bound Ctx, which may be either an object or a class context. We
90 * then teleport the object onto the stack as the first local after the params.
92 SSATmp
* juggle_closure_ctx(IRGS
& env
) {
93 auto const func
= env
.context
.func
;
95 assertx(func
->isClosureBody());
97 auto const closure_type
= Type::ExactObj(func
->implCls());
98 auto const closure
= gen(env
, LdClosure
, closure_type
, fp(env
));
100 auto const ctx
= gen(env
, LdClosureCtx
, closure
);
101 gen(env
, InitCtx
, fp(env
), ctx
);
102 // We can skip the incref for static closures, which have a Cctx.
103 if (!func
->isStatic()) gen(env
, IncRefCtx
, ctx
);
105 // Teleport the closure to the next local. There's no need to incref since
106 // it came from m_this.
107 gen(env
, StLoc
, LocalId
{func
->numParams()}, fp(env
), closure
);
112 * Copy the closure's use variables from the closure object's properties onto
115 void init_use_vars(IRGS
& env
, SSATmp
* closure
) {
116 auto const func
= env
.context
.func
;
117 auto const cls
= func
->implCls();
118 auto const nparams
= func
->numParams();
120 assertx(func
->isClosureBody());
122 // Closure object properties are the use vars followed by the static locals
123 // (which are per-instance).
124 auto const nuse
= cls
->numDeclProperties() - func
->numStaticLocals();
126 int use_var_off
= sizeof(ObjectData
) + cls
->builtinODTailSize();
128 for (auto i
= 0; i
< nuse
; ++i
, use_var_off
+= sizeof(Cell
)) {
129 auto const ty
= typeFromRAT(cls
->declPropRepoAuthType(i
));
130 auto const addr
= gen(
133 PropOffset
{ use_var_off
},
137 auto const prop
= gen(env
, LdMem
, ty
, addr
);
138 gen(env
, StLoc
, LocalId
{nparams
+ 1 + i
}, fp(env
), prop
);
139 gen(env
, IncRef
, prop
);
144 * Set locals to Uninit.
146 void init_locals(IRGS
& env
) {
148 * Maximum number of local initializations to unroll.
150 * The actual crossover point in terms of code size is 6 (just like for the
151 * params init unroll limit); 9 was determined by experiment to be the
152 * optimal point in certain benchmarks.
154 constexpr auto kMaxLocalsInitUnroll
= 9;
156 auto const func
= env
.context
.func
;
157 auto const nlocals
= func
->numLocals();
159 auto num_inited
= func
->numParams();
161 if (func
->isClosureBody()) {
162 auto const nuse
= func
->implCls()->numDeclProperties() -
163 func
->numStaticLocals();
164 num_inited
+= 1 + nuse
;
167 // We set to Uninit all locals beyond any params and any closure use vars.
168 if (num_inited
< nlocals
) {
169 if (nlocals
- num_inited
<= kMaxLocalsInitUnroll
) {
170 for (auto i
= num_inited
; i
< nlocals
; ++i
) {
171 gen(env
, StLoc
, LocalId
{i
}, fp(env
), cns(env
, TUninit
));
174 gen(env
, StLocRange
, LocalIdRange
{num_inited
, (uint32_t)nlocals
},
175 fp(env
), cns(env
, TUninit
));
181 * Emit raise-warnings for any missing arguments.
183 void warn_missing_args(IRGS
& env
, uint32_t argc
) {
184 auto const func
= env
.context
.func
;
185 auto const nparams
= func
->numNonVariadicParams();
187 if (!func
->isCPPBuiltin()) {
188 auto const& paramInfo
= func
->params();
190 for (auto i
= argc
; i
< nparams
; ++i
) {
191 if (paramInfo
[i
].funcletOff
== InvalidAbsoluteOffset
) {
192 env
.irb
->exceptionStackBoundary();
193 gen(env
, RaiseMissingArg
, FuncArgData
{ func
, argc
});
200 ///////////////////////////////////////////////////////////////////////////////
203 * How to perform our stack overflow check.
205 enum class StackCheck
{
207 Early
, // must occur before setting up locals
208 Combine
// can be delayed and combined with surprise flags check
211 StackCheck
stack_check_kind(const Func
* func
, uint32_t argc
) {
212 if (func
->attrs() & AttrPhpLeafFn
&&
213 func
->maxStackCells() < kStackCheckLeafPadding
) {
214 return StackCheck::None
;
218 * Determine how many stack slots we're going to write that the caller hasn't
219 * already checked we have space for.
221 * We don't need to worry about any of the passed parameter locals, because
222 * the caller must have checked for that in its maxStackCells(). However,
223 * we'd like to delay our stack overflow check until after we've entered our
224 * frame, so we can combine it with the surprise flag check (which must run
225 * after we've created the callee).
227 * The only things we are going to do is write uninits to the non-passed
228 * params and to the non-parameter locals, and possibly shuffle some of the
229 * locals into an ExtraArgs structure. The stack overflow code knows how to
230 * handle the possibility of an ExtraArgs structure on the ActRec, and the
231 * uninits are harmless as long as we know we aren't going to segfault while
234 * There's always sSurprisePageSize extra space at the bottom (lowest
235 * addresses) of the eval stack, so we just only do this optimization if
236 * we're sure we're going to write few enough uninits that we would be
237 * staying within that region if the locals are actually too deep.
239 auto const safeFromSEGV
= Stack::sSurprisePageSize
/ sizeof(TypedValue
);
241 return func
->numLocals() - argc
< safeFromSEGV
242 ? StackCheck::Combine
246 ///////////////////////////////////////////////////////////////////////////////
248 void emitPrologueEntry(IRGS
& env
, uint32_t argc
) {
249 auto const func
= env
.context
.func
;
252 if (Trace::moduleEnabled(Trace::ringbuffer
) && !func
->isMagic()) {
253 auto msg
= RBMsgData
{ Trace::RBTypeFuncPrologue
, func
->fullName() };
254 gen(env
, RBTraceMsg
, msg
);
256 if (RuntimeOption::EvalJitTransCounters
) {
257 gen(env
, IncTransCounter
);
260 gen(env
, EnterFrame
, fp(env
));
262 // Emit early stack overflow check if necessary.
263 if (stack_check_kind(func
, argc
) == StackCheck::Early
) {
264 env
.irb
->exceptionStackBoundary();
265 gen(env
, CheckStackOverflow
, fp(env
));
269 void emitPrologueBody(IRGS
& env
, uint32_t argc
, TransID transID
) {
270 auto const func
= env
.context
.func
;
272 // Increment profiling counter.
273 if (mcg
->tx().mode() == TransKind::Proflogue
) {
274 assertx(shouldPGOFunc(*func
));
275 auto profData
= mcg
->tx().profData();
277 gen(env
, IncProfCounter
, TransIDData
{transID
});
278 profData
->setProfiling(func
->getFuncId());
281 // Initialize params, locals, and---if we have a closure---the closure's
282 // bound class context and use vars.
283 init_params(env
, argc
);
284 if (func
->isClosureBody()) {
285 auto const closure
= juggle_closure_ctx(env
);
286 init_use_vars(env
, closure
);
289 warn_missing_args(env
, argc
);
291 // Check surprise flags in the same place as the interpreter: after setting
292 // up the callee's frame but before executing any of its code.
293 env
.irb
->exceptionStackBoundary();
294 if (stack_check_kind(func
, argc
) == StackCheck::Combine
) {
295 gen(env
, CheckSurpriseAndStack
, FuncEntryData
{ func
, argc
}, fp(env
));
297 gen(env
, CheckSurpriseFlagsEnter
, FuncEntryData
{ func
, argc
}, fp(env
));
300 // Emit the bindjmp for the function body.
305 SrcKey
{ func
, func
->getEntryForNumArgs(argc
), false },
306 FPInvOffset
{ func
->numSlotsInFrame() },
307 offsetFromIRSP(env
, BCSPOffset
{0}),
315 ///////////////////////////////////////////////////////////////////////////////
317 void emitMagicFuncPrologue(IRGS
& env
, uint32_t argc
, TransID transID
) {
318 DEBUG_ONLY
auto const func
= env
.context
.func
;
319 assertx(func
->isMagic());
320 assertx(func
->numParams() == 2);
321 assertx(!func
->hasVariadicCaptureParam());
323 Block
* two_arg_prologue
= nullptr;
325 emitPrologueEntry(env
, argc
);
327 // If someone just called __call() or __callStatic() directly, branch to a
328 // normal non-magic prologue.
332 gen(env
, CheckARMagicFlag
, taken
, fp(env
));
333 if (argc
== 2) two_arg_prologue
= taken
;
336 emitPrologueBody(env
, argc
, transID
);
340 // Pack the passed args into an array, then store it as the second param.
341 // This has to happen before we write the first param.
342 auto const args_arr
= (argc
== 0)
343 ? cns(env
, staticEmptyArray())
344 : gen(env
, PackMagicArgs
, fp(env
));
345 gen(env
, StLoc
, LocalId
{1}, fp(env
), args_arr
);
347 // Store the name of the called function to the first param, then null it out
349 auto const inv_name
= gen(env
, LdARInvName
, fp(env
));
350 gen(env
, StLoc
, LocalId
{0}, fp(env
), inv_name
);
351 gen(env
, StARInvName
, fp(env
), cns(env
, nullptr));
353 // We set m_numArgsAndFlags even if `argc == 2' in order to reset the flags.
354 gen(env
, StARNumArgsAndFlags
, fp(env
), cns(env
, 2));
356 // Jmp to the two-argument prologue, or emit it if it doesn't exist yet.
357 if (two_arg_prologue
) {
358 gen(env
, Jmp
, two_arg_prologue
);
360 emitPrologueBody(env
, 2, transID
);
364 ///////////////////////////////////////////////////////////////////////////////
368 ///////////////////////////////////////////////////////////////////////////////
370 void emitFuncPrologue(IRGS
& env
, uint32_t argc
, TransID transID
) {
371 if (env
.context
.func
->isMagic()) {
372 return emitMagicFuncPrologue(env
, argc
, transID
);
374 emitPrologueEntry(env
, argc
);
375 emitPrologueBody(env
, argc
, transID
);
378 void emitFuncBodyDispatch(IRGS
& env
, const DVFuncletsVec
& dvs
) {
379 auto const func
= env
.context
.func
;
381 // TODO(#8060661): Why don't we need to mask out the flags?
382 auto const num_args
= gen(env
, LdARNumArgsAndFlags
, fp(env
));
384 for (auto const& dv
: dvs
) {
388 auto const lte
= gen(env
, LteInt
, num_args
, cns(env
, dv
.first
));
389 gen(env
, JmpNZero
, taken
, lte
);
396 SrcKey
{ func
, dv
.second
, false },
397 FPInvOffset
{ func
->numSlotsInFrame() },
398 offsetFromIRSP(env
, BCSPOffset
{0}),
412 SrcKey
{ func
, func
->base(), false },
413 FPInvOffset
{ func
->numSlotsInFrame() },
414 offsetFromIRSP(env
, BCSPOffset
{0}),
422 ///////////////////////////////////////////////////////////////////////////////