Use RATs from HHBBC in init_use_vars
[hiphop-php.git] / hphp / runtime / vm / jit / irgen-func-prologue.cpp
blob8ff74d601a0cdeb292c84d3124ecca87581f2953
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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 ///////////////////////////////////////////////////////////////////////////////
44 namespace {
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();
63 if (argc < nparams) {
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));
69 } else {
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);
108 return closure;
112 * Copy the closure's use variables from the closure object's properties onto
113 * the stack.
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(
131 env,
132 LdPropAddr,
133 PropOffset { use_var_off },
134 ty.ptr(Ptr::Prop),
135 closure
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));
173 } else {
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 });
194 break;
200 ///////////////////////////////////////////////////////////////////////////////
203 * How to perform our stack overflow check.
205 enum class StackCheck {
206 None, // not needed
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
232 * we write them.
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
243 : StackCheck::Early;
246 ///////////////////////////////////////////////////////////////////////////////
248 void emitPrologueEntry(IRGS& env, uint32_t argc) {
249 auto const func = env.context.func;
251 // Emit debug code.
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);
288 init_locals(env);
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));
296 } else {
297 gen(env, CheckSurpriseFlagsEnter, FuncEntryData { func, argc }, fp(env));
300 // Emit the bindjmp for the function body.
301 gen(
302 env,
303 ReqBindJmp,
304 ReqBindJmpData {
305 SrcKey { func, func->getEntryForNumArgs(argc), false },
306 FPInvOffset { func->numSlotsInFrame() },
307 offsetFromIRSP(env, BCSPOffset{0}),
308 TransFlags{}
310 sp(env),
311 fp(env)
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.
329 ifThen(
330 env,
331 [&] (Block* taken) {
332 gen(env, CheckARMagicFlag, taken, fp(env));
333 if (argc == 2) two_arg_prologue = taken;
335 [&] {
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
348 // on the ActRec.
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);
359 } else {
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) {
385 ifThen(
386 env,
387 [&] (Block* taken) {
388 auto const lte = gen(env, LteInt, num_args, cns(env, dv.first));
389 gen(env, JmpNZero, taken, lte);
391 [&] {
392 gen(
393 env,
394 ReqBindJmp,
395 ReqBindJmpData {
396 SrcKey { func, dv.second, false },
397 FPInvOffset { func->numSlotsInFrame() },
398 offsetFromIRSP(env, BCSPOffset{0}),
399 TransFlags{}
401 sp(env),
402 fp(env)
408 gen(
409 env,
410 ReqBindJmp,
411 ReqBindJmpData {
412 SrcKey { func, func->base(), false },
413 FPInvOffset { func->numSlotsInFrame() },
414 offsetFromIRSP(env, BCSPOffset{0}),
415 TransFlags{}
417 sp(env),
418 fp(env)
422 ///////////////////////////////////////////////////////////////////////////////