codemod 2010-2016 to 2010-present
[hiphop-php.git] / hphp / runtime / vm / jit / irgen-interpone.cpp
blob83e63d5a168f5660872648e1b71a7ac4472f2de6
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/irgen-interpone.h"
19 #include <cstdlib>
21 #include "hphp/runtime/vm/jit/location.h"
22 #include "hphp/runtime/vm/jit/minstr-effects.h"
23 #include "hphp/runtime/vm/jit/normalized-instruction.h"
25 #include "hphp/runtime/vm/jit/irgen-exit.h"
26 #include "hphp/runtime/vm/jit/irgen-internal.h"
28 namespace HPHP { namespace jit { namespace irgen {
30 namespace {
32 //////////////////////////////////////////////////////////////////////
34 Type arithOpResult(Type t1, Type t2) {
35 if (!t1.isKnownDataType() || !t2.isKnownDataType()) {
36 return TCell;
39 auto both = t1 | t2;
40 if (both.maybe(TDbl)) return TDbl;
41 if (both.maybe(TArr)) return TArr;
42 if (both.maybe(TVec)) return TVec;
43 if (both.maybe(TDict)) return TDict;
44 if (both.maybe(TKeyset)) return TKeyset;
45 if (both.maybe(TStr)) return TCell;
46 return TInt;
49 Type arithOpOverResult(Type t1, Type t2) {
50 if (t1 <= TInt && t2 <= TInt) {
51 return TInt | TDbl;
53 return arithOpResult(t1, t2);
56 Type bitOpResult(Type t1, Type t2) {
57 if (!t1.isKnownDataType() || !t2.isKnownDataType()) {
58 return TCell;
61 auto both = t1 | t2;
62 if (both <= TStr) return TStr;
63 return TInt;
66 Type setOpResult(Type locType, Type valType, SetOpOp op) {
67 switch (op) {
68 case SetOpOp::PlusEqual:
69 case SetOpOp::MinusEqual:
70 case SetOpOp::MulEqual: return arithOpResult(locType.unbox(), valType);
71 case SetOpOp::PlusEqualO:
72 case SetOpOp::MinusEqualO:
73 case SetOpOp::MulEqualO: return arithOpOverResult(locType.unbox(), valType);
74 case SetOpOp::ConcatEqual: return TStr;
75 case SetOpOp::PowEqual:
76 case SetOpOp::DivEqual:
77 case SetOpOp::ModEqual: return TUncountedInit;
78 case SetOpOp::AndEqual:
79 case SetOpOp::OrEqual:
80 case SetOpOp::XorEqual: return bitOpResult(locType.unbox(), valType);
81 case SetOpOp::SlEqual:
82 case SetOpOp::SrEqual: return TInt;
84 not_reached();
87 uint32_t localInputId(const NormalizedInstruction& inst) {
88 return inst.imm[localImmIdx(inst.op())].u_LA;
91 folly::Optional<Type> interpOutputType(IRGS& env,
92 const NormalizedInstruction& inst,
93 folly::Optional<Type>& checkTypeType) {
94 using namespace jit::InstrFlags;
95 auto localType = [&]{
96 auto locId = localInputId(inst);
97 static_assert(std::is_unsigned<decltype(locId)>::value,
98 "locId should be unsigned");
99 assertx(locId < curFunc(env)->numLocals());
100 return env.irb->local(locId, DataTypeSpecific).type;
103 auto boxed = [&] (Type t) -> Type {
104 if (t == TGen) return TBoxedInitCell;
105 assertx(t <= TCell || t <= TBoxedCell);
106 checkTypeType = t <= TBoxedCell ? t : boxType(t);
107 return TBoxedInitCell;
110 auto outFlag = getInstrInfo(inst.op()).type;
111 if (outFlag == OutFInputL) {
112 outFlag = inst.preppedByRef ? OutVInputL : OutCInputL;
113 } else if (outFlag == OutFInputR) {
114 outFlag = inst.preppedByRef ? OutVInput : OutCInput;
117 switch (outFlag) {
118 case OutNull: return TInitNull;
119 case OutNullUninit: return TUninit;
120 case OutString: return TStr;
121 case OutStringImm: return TStaticStr;
122 case OutDouble: return TDbl;
123 case OutIsTypeL:
124 case OutBoolean:
125 case OutPredBool:
126 case OutBooleanImm: return TBool;
127 case OutInt64: return TInt;
128 case OutArray: return TArr;
129 case OutArrayImm: return TArr; // Should be StaticArr/Vec/Dict: t2124292
130 case OutVec: return TVec;
131 case OutVecImm: return TVec;
132 case OutDict: return TDict;
133 case OutDictImm: return TDict;
134 case OutKeyset: return TKeyset;
135 case OutKeysetImm: return TKeyset;
136 case OutObject:
137 case OutThisObject: return TObj;
138 case OutResource: return TRes;
140 case OutFDesc: return folly::none;
141 case OutCns: return TCell;
142 case OutVUnknown: return TBoxedInitCell;
144 case OutSameAsInput1: return topType(env, BCSPRelOffset{0});
145 case OutSameAsInput2: return topType(env, BCSPRelOffset{1});
146 case OutSameAsInput3: return topType(env, BCSPRelOffset{2});
147 case OutVInput: return boxed(topType(env, BCSPRelOffset{0}));
148 case OutVInputL: return boxed(localType());
149 case OutFInputL:
150 case OutFInputR: not_reached();
152 case OutArith:
153 return arithOpResult(topType(env, BCSPRelOffset{0}),
154 topType(env, BCSPRelOffset{1}));
155 case OutArithO:
156 return arithOpOverResult(topType(env, BCSPRelOffset{0}),
157 topType(env, BCSPRelOffset{1}));
158 case OutUnknown: {
159 if (isFPassStar(inst.op())) {
160 return inst.preppedByRef ? TBoxedInitCell : TCell;
162 return TGen;
164 case OutBitOp:
165 return bitOpResult(topType(env, BCSPRelOffset{0}),
166 inst.op() == HPHP::OpBitNot ?
167 TBottom : topType(env, BCSPRelOffset{1}));
168 case OutSetOp: return setOpResult(localType(),
169 topType(env, BCSPRelOffset{0}),
170 SetOpOp(inst.imm[1].u_OA));
171 case OutIncDec: {
172 auto ty = localType().unbox();
173 return ty <= TDbl ? ty : TCell;
175 case OutClassRef: return TCls;
176 case OutFPushCufSafe: return folly::none;
178 case OutNone: return folly::none;
180 case OutCInput: {
181 auto ttype = topType(env, BCSPRelOffset{0});
182 if (ttype <= TCell) return ttype;
183 // All instructions that are OutCInput or OutCInputL cannot push uninit or
184 // a ref, so only specific inner types need to be checked.
185 if (ttype.unbox() < TInitCell) {
186 checkTypeType = ttype.unbox();
188 return TCell;
191 case OutCInputL: {
192 auto ltype = localType();
193 if (ltype <= TCell) return ltype;
194 if (ltype.unbox() < TInitCell) {
195 checkTypeType = ltype.unbox();
197 return TCell;
200 not_reached();
203 jit::vector<InterpOneData::LocalType>
204 interpOutputLocals(IRGS& env,
205 const NormalizedInstruction& inst,
206 bool& smashesAllLocals,
207 folly::Optional<Type> pushedType) {
208 using namespace jit::InstrFlags;
209 auto const& info = getInstrInfo(inst.op());
210 // Anything with Local in its output or a member base input can modify a
211 // local.
212 if (!(info.out & Local) && !(info.in & MBase)) return {};
214 jit::vector<InterpOneData::LocalType> locals;
215 auto setLocType = [&](uint32_t id, Type t) {
216 // Relax the type to something guardable. For InterpOne we don't bother to
217 // keep track of specialized types or inner-ref types. (And note that for
218 // psuedomains we may in fact have to guard on the local type after this.)
219 locals.emplace_back(id, relaxToGuardable(t));
221 auto setImmLocType = [&](uint32_t id, Type t) {
222 setLocType(inst.imm[id].u_LA, t);
224 auto handleBoxiness = [&] (Type testTy, Type useTy) {
225 return testTy <= TBoxedCell ? TBoxedInitCell :
226 testTy.maybe(TBoxedCell) ? TGen :
227 useTy;
230 auto const mDefine = static_cast<unsigned char>(MOpMode::Define);
232 switch (inst.op()) {
233 case OpSetN:
234 case OpSetOpN:
235 case OpIncDecN:
236 case OpBindN:
237 case OpVGetN:
238 case OpUnsetN:
239 smashesAllLocals = true;
240 break;
242 case OpSetOpL:
243 case OpIncDecL: {
244 assertx(pushedType.hasValue());
245 auto locType = env.irb->local(localInputId(inst), DataTypeSpecific).type;
246 assertx(locType < TGen || curFunc(env)->isPseudoMain());
248 auto stackType = pushedType.value();
249 setImmLocType(0, handleBoxiness(locType, stackType));
250 break;
253 case OpStaticLocInit:
254 setImmLocType(0, TBoxedInitCell);
255 break;
257 case OpInitThisLoc:
258 setImmLocType(0, TCell);
259 break;
261 case OpSetL: {
262 auto locType = env.irb->local(localInputId(inst), DataTypeSpecific).type;
263 auto stackType = topType(env, BCSPRelOffset{0});
264 // SetL preserves reffiness of a local.
265 setImmLocType(0, handleBoxiness(locType, stackType));
266 break;
268 case OpVGetL:
269 case OpBindL: {
270 assertx(pushedType.hasValue());
271 assertx(*pushedType <= TBoxedCell);
272 setImmLocType(0, pushedType.value());
273 break;
276 case OpUnsetL:
277 case OpPushL:
278 setImmLocType(0, TUninit);
279 break;
281 // New minstrs are handled extremely conservatively.
282 case OpQueryM:
283 break;
284 case OpDim:
285 if (inst.imm[0].u_OA & mDefine) smashesAllLocals = true;
286 break;
287 case OpFPassDim:
288 case OpFPassM:
289 case OpVGetM:
290 case OpSetM:
291 case OpIncDecM:
292 case OpSetOpM:
293 case OpBindM:
294 case OpUnsetM:
295 case OpSetWithRefLML:
296 case OpSetWithRefRML:
297 smashesAllLocals = true;
298 break;
300 case OpMIterInitK:
301 case OpMIterNextK:
302 setImmLocType(3, TCell);
303 /* fallthrough */
304 case OpMIterInit:
305 case OpMIterNext:
306 setImmLocType(2, TBoxedInitCell);
307 break;
309 case OpIterInitK:
310 case OpWIterInitK:
311 case OpIterNextK:
312 case OpWIterNextK:
313 setImmLocType(3, TCell);
314 /* fallthrough */
315 case OpIterInit:
316 case OpWIterInit:
317 case OpIterNext:
318 case OpWIterNext:
319 setImmLocType(2, TGen);
320 break;
322 case OpVerifyParamType: {
323 auto locType = env.irb->local(localInputId(inst), DataTypeSpecific).type;
324 setImmLocType(0, handleBoxiness(locType, TCell));
325 break;
328 case OpSilence:
329 if (static_cast<SilenceOp>(inst.imm[0].u_OA) == SilenceOp::Start) {
330 setImmLocType(inst.imm[0].u_LA, TInt);
332 break;
334 default:
335 always_assert_flog(
336 false, "Unknown local-modifying op {}", opcodeToName(inst.op())
340 return locals;
343 //////////////////////////////////////////////////////////////////////
347 void interpOne(IRGS& env, const NormalizedInstruction& inst) {
348 folly::Optional<Type> checkTypeType;
349 auto stackType = interpOutputType(env, inst, checkTypeType);
350 auto popped = getStackPopped(inst.pc());
351 auto pushed = getStackPushed(inst.pc());
352 FTRACE(1, "emitting InterpOne for {}, result = {}, popped {}, pushed {}\n",
353 inst.toString(),
354 stackType.hasValue() ? stackType->toString() : "<none>",
355 popped, pushed);
357 InterpOneData idata { spOffBCFromIRSP(env) };
358 auto locals = interpOutputLocals(env, inst, idata.smashesAllLocals,
359 stackType);
360 idata.nChangedLocals = locals.size();
361 idata.changedLocals = locals.data();
363 interpOne(env, stackType, popped, pushed, idata);
364 if (checkTypeType) {
365 auto const out = getInstrInfo(inst.op()).out;
366 auto const checkIdx = BCSPRelOffset{
367 (out & InstrFlags::StackIns2) ? 2 :
368 (out & InstrFlags::StackIns1) ? 1 : 0
369 }.to<FPInvOffset>(env.irb->fs().bcSPOff());
371 checkType(env, Location::Stack { checkIdx }, *checkTypeType,
372 inst.nextSk().offset(), true /* outerOnly */);
376 void interpOne(IRGS& env, int popped) {
377 InterpOneData idata { spOffBCFromIRSP(env) };
378 interpOne(env, folly::none, popped, 0, idata);
381 void interpOne(IRGS& env, Type outType, int popped) {
382 InterpOneData idata { spOffBCFromIRSP(env) };
383 interpOne(env, outType, popped, 1, idata);
386 void interpOne(IRGS& env,
387 folly::Optional<Type> outType,
388 int popped,
389 int pushed,
390 InterpOneData& idata) {
391 auto const unit = curUnit(env);
392 auto const op = unit->getOp(bcOff(env));
394 idata.bcOff = bcOff(env);
395 idata.cellsPopped = popped;
396 idata.cellsPushed = pushed;
397 idata.opcode = op;
399 gen(
400 env,
401 opcodeChangesPC(idata.opcode) ? InterpOneCF : InterpOne,
402 outType,
403 idata,
404 sp(env),
405 fp(env)
409 //////////////////////////////////////////////////////////////////////
412 * Instructions that unconditionally are implemented with InterpOne are
413 * translated here.
416 #define INTERP interpOne(env, *env.currentNormalizedInstruction);
418 void emitFPushObjMethod(IRGS& env, int32_t, ObjMethodOp) { INTERP }
420 void emitLowInvalid(IRGS& env) { std::abort(); }
421 void emitCGetL3(IRGS& env, int32_t) { INTERP }
422 void emitAddElemV(IRGS& env) { INTERP }
423 void emitAddNewElemV(IRGS& env) { INTERP }
424 void emitExit(IRGS& env) { INTERP }
425 void emitFatal(IRGS& env, FatalOp) { INTERP }
426 void emitUnwind(IRGS& env) { INTERP }
427 void emitThrow(IRGS& env) { INTERP }
428 void emitCGetN(IRGS& env) { INTERP }
429 void emitCGetQuietN(IRGS& env) { INTERP }
430 void emitVGetN(IRGS& env) { INTERP }
431 void emitIssetN(IRGS& env) { INTERP }
432 void emitEmptyN(IRGS& env) { INTERP }
433 void emitSetN(IRGS& env) { INTERP }
434 void emitSetOpN(IRGS& env, SetOpOp) { INTERP }
435 void emitSetOpG(IRGS& env, SetOpOp) { INTERP }
436 void emitSetOpS(IRGS& env, SetOpOp) { INTERP }
437 void emitIncDecN(IRGS& env, IncDecOp) { INTERP }
438 void emitIncDecG(IRGS& env, IncDecOp) { INTERP }
439 void emitBindN(IRGS& env) { INTERP }
440 void emitUnsetN(IRGS& env) { INTERP }
441 void emitUnsetG(IRGS& env) { INTERP }
442 void emitFPassN(IRGS& env, int32_t) { INTERP }
443 void emitCufSafeArray(IRGS& env) { INTERP }
444 void emitCufSafeReturn(IRGS& env) { INTERP }
445 void emitIncl(IRGS& env) { INTERP }
446 void emitInclOnce(IRGS& env) { INTERP }
447 void emitReq(IRGS& env) { INTERP }
448 void emitReqDoc(IRGS& env) { INTERP }
449 void emitReqOnce(IRGS& env) { INTERP }
450 void emitEval(IRGS& env) { INTERP }
451 void emitDefTypeAlias(IRGS& env, int32_t) { INTERP }
452 void emitDefCns(IRGS& env, const StringData*) { INTERP }
453 void emitDefCls(IRGS& env, int32_t) { INTERP }
454 void emitDefFunc(IRGS& env, int32_t) { INTERP }
455 void emitCatch(IRGS& env) { INTERP }
456 void emitContGetReturn(IRGS& env) { INTERP }
457 void emitContAssignDelegate(IRGS& env, int32_t)
458 { INTERP }
459 void emitContEnterDelegate(IRGS& env) { INTERP }
460 void emitYieldFromDelegate(IRGS& env, int32_t, int32_t)
461 { INTERP }
462 void emitContUnsetDelegate(IRGS& env, int32_t, int32_t)
463 { INTERP }
464 void emitHighInvalid(IRGS& env) { std::abort(); }
466 //////////////////////////////////////////////////////////////////////