Kill InitThisLoc
[hiphop-php.git] / hphp / runtime / vm / jit / irgen-interpone.cpp
blobaccf4b4c5b8fac2742494bf1f1c7bb91236c8468
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/hhbc.h"
22 #include "hphp/runtime/vm/jit/location.h"
23 #include "hphp/runtime/vm/jit/minstr-effects.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(TClsMeth)) return TClsMeth;
46 if (both.maybe(TStr)) return TCell;
47 return TInt;
50 Type arithOpOverResult(Type t1, Type t2) {
51 if (t1 <= TInt && t2 <= TInt) {
52 return TInt | TDbl;
54 return arithOpResult(t1, t2);
57 Type bitOpResult(Type t1, Type t2) {
58 if (!t1.isKnownDataType() || !t2.isKnownDataType()) {
59 return TCell;
62 auto both = t1 | t2;
63 if (both <= TStr) return TStr;
64 return TInt;
67 Type setOpResult(Type locType, Type valType, SetOpOp op) {
68 switch (op) {
69 case SetOpOp::PlusEqual:
70 case SetOpOp::MinusEqual:
71 case SetOpOp::MulEqual: return arithOpResult(locType, valType);
72 case SetOpOp::PlusEqualO:
73 case SetOpOp::MinusEqualO:
74 case SetOpOp::MulEqualO: return arithOpOverResult(locType, valType);
75 case SetOpOp::ConcatEqual: return TStr;
76 case SetOpOp::PowEqual:
77 case SetOpOp::DivEqual:
78 case SetOpOp::ModEqual: return TUncountedInit;
79 case SetOpOp::AndEqual:
80 case SetOpOp::OrEqual:
81 case SetOpOp::XorEqual: return bitOpResult(locType, valType);
82 case SetOpOp::SlEqual:
83 case SetOpOp::SrEqual: return TInt;
85 not_reached();
88 uint32_t localInputId(SrcKey sk) {
89 auto const idx = localImmIdx(sk.op());
90 auto const argu = getImm(sk.pc(), idx);
91 switch (immType(sk.op(), idx)) {
92 case ArgType::LA:
93 return argu.u_LA;
94 case ArgType::NLA:
95 return argu.u_NLA.id;
96 case ArgType::ILA:
97 return argu.u_ILA;
98 default:
99 always_assert(false);
103 folly::Optional<Type> interpOutputType(IRGS& env,
104 folly::Optional<Type>& checkTypeType) {
105 using namespace jit::InstrFlags;
106 auto const sk = curSrcKey(env);
107 auto localType = [&]{
108 auto locId = localInputId(sk);
109 static_assert(std::is_unsigned<decltype(locId)>::value,
110 "locId should be unsigned");
111 assertx(locId < curFunc(env)->numLocals());
112 return env.irb->local(locId, DataTypeSpecific).type;
115 switch (getInstrInfo(sk.op()).type) {
116 case OutNull: return TInitNull;
117 case OutNullUninit: return TUninit;
118 case OutString: return TStr;
119 case OutStringImm: return TStaticStr;
120 case OutDouble: return TDbl;
121 case OutIsTypeL:
122 case OutBoolean:
123 case OutPredBool:
124 case OutBooleanImm: return TBool;
125 case OutInt64: return TInt;
126 case OutArrayImm: return TArr; // Should be StaticArr/Vec/Dict: t2124292
127 case OutVArray: return RuntimeOption::EvalHackArrDVArrs ? TVec : TVArr;
128 case OutDArray: return RuntimeOption::EvalHackArrDVArrs ? TDict : TDArr;
129 case OutVec: return TVec;
130 case OutVecImm: return TVec;
131 case OutDict: return TDict;
132 case OutDictImm: return TDict;
133 case OutKeyset: return TKeyset;
134 case OutKeysetImm: return TKeyset;
135 case OutObject:
136 case OutThisObject: return TObj;
137 case OutRecord: return TRecord;
138 case OutResource: return TRes;
140 case OutFDesc: return folly::none;
141 case OutCns: return TCell;
143 case OutSameAsInput1: return topType(env, BCSPRelOffset{0});
144 case OutSameAsInput2: return topType(env, BCSPRelOffset{1});
145 case OutModifiedInput2: return topType(env, BCSPRelOffset{1}).modified();
146 case OutModifiedInput3: return topType(env, BCSPRelOffset{2}).modified();
148 case OutArith:
149 return arithOpResult(topType(env, BCSPRelOffset{0}),
150 topType(env, BCSPRelOffset{1}));
151 case OutArithO:
152 return arithOpOverResult(topType(env, BCSPRelOffset{0}),
153 topType(env, BCSPRelOffset{1}));
154 case OutUnknown: return TCell;
156 case OutBitOp:
157 return bitOpResult(topType(env, BCSPRelOffset{0}),
158 sk.op() == HPHP::OpBitNot ?
159 TBottom : topType(env, BCSPRelOffset{1}));
160 case OutSetOp: return setOpResult(localType(),
161 topType(env, BCSPRelOffset{0}),
162 SetOpOp(getImm(sk.pc(), 1).u_OA));
163 case OutIncDec: {
164 auto ty = localType();
165 return ty <= TDbl ? ty : TCell;
167 case OutNone: return folly::none;
169 case OutCInput: {
170 return topType(env, BCSPRelOffset{0});
173 case OutCInputL: {
174 auto ltype = localType();
175 if (ltype <= TCell) return ltype;
176 if (ltype < TInitCell) {
177 checkTypeType = ltype;
179 return TCell;
181 case OutFunc: return TFunc;
182 case OutFuncLike: return TFuncLike;
183 case OutClass: return TCls;
184 case OutClsMeth: return TClsMeth;
185 case OutClsMethLike: return TClsMethLike;
186 case OutLazyClass: return TLazyCls;
188 not_reached();
191 jit::vector<InterpOneData::LocalType>
192 interpOutputLocals(IRGS& env,
193 bool& smashesAllLocals,
194 folly::Optional<Type> pushedType) {
195 using namespace jit::InstrFlags;
196 auto const sk = curSrcKey(env);
197 auto const& info = getInstrInfo(sk.op());
198 // Anything with Local in its output or a member base input can modify a
199 // local.
200 if (!(info.out & Local) && !(info.in & MBase)) return {};
202 jit::vector<InterpOneData::LocalType> locals;
203 auto setLocType = [&](uint32_t id, Type t) {
204 // Relax the type to something guardable. For InterpOne we don't bother to
205 // keep track of specialized types or inner-ref types. (And note that for
206 // psuedomains we may in fact have to guard on the local type after this.)
207 locals.emplace_back(id, relaxToGuardable(t));
209 auto setImmLocType = [&](uint32_t id, Type t) {
210 assertx(id < kMaxHhbcImms);
211 assertx(id == localImmIdx(sk.op()));
212 setLocType(localInputId(sk), t);
215 auto const mDefine = static_cast<unsigned char>(MOpMode::Define);
217 switch (sk.op()) {
218 case OpSetOpL:
219 case OpIncDecL: {
220 assertx(pushedType.has_value());
222 auto stackType = pushedType.value();
223 setImmLocType(0, stackType);
224 break;
227 case OpSetL:
228 case OpPopL: {
229 auto stackType = topType(env, BCSPRelOffset{0});
230 setImmLocType(0, stackType);
231 break;
234 case OpUnsetL:
235 case OpPushL:
236 setImmLocType(0, TUninit);
237 break;
239 // New minstrs are handled extremely conservatively.
240 case OpQueryM:
241 case OpMemoGet:
242 case OpMemoGetEager:
243 case OpMemoSet:
244 case OpMemoSetEager:
245 break;
246 case OpDim:
247 if (getImm(sk.pc(), 0).u_OA & mDefine) smashesAllLocals = true;
248 break;
249 case OpSetM:
250 case OpIncDecM:
251 case OpSetOpM:
252 case OpUnsetM:
253 smashesAllLocals = true;
254 break;
256 case OpIterInit:
257 case OpLIterInit:
258 case OpIterNext:
259 case OpLIterNext: {
260 auto const ita = getImm(sk.pc(), 0).u_ITA;
261 setLocType(ita.valId, TCell);
262 if (ita.hasKey()) setLocType(ita.keyId, TCell);
263 break;
266 case OpVerifyParamTypeTS:
267 case OpVerifyParamType: {
268 setImmLocType(0, TCell);
269 break;
272 case OpSilence:
273 if (static_cast<SilenceOp>(getImm(sk.pc(), 1).u_OA) == SilenceOp::Start) {
274 setImmLocType(0, TInt);
276 break;
278 default:
279 always_assert_flog(
280 false, "Unknown local-modifying op {}", opcodeToName(sk.op())
284 return locals;
287 //////////////////////////////////////////////////////////////////////
291 void interpOne(IRGS& env) {
292 folly::Optional<Type> checkTypeType;
293 auto const sk = curSrcKey(env);
294 auto stackType = interpOutputType(env, checkTypeType);
295 auto popped = getStackPopped(sk.pc());
296 auto pushed = getStackPushed(sk.pc());
297 FTRACE(1, "emitting InterpOne for {}, result = {}, popped {}, pushed {}\n",
298 instrToString(sk.pc(), sk.func()),
299 stackType.has_value() ? stackType->toString() : "<none>",
300 popped, pushed);
302 InterpOneData idata { spOffBCFromIRSP(env) };
303 auto locals = interpOutputLocals(env, idata.smashesAllLocals, stackType);
304 idata.nChangedLocals = locals.size();
305 idata.changedLocals = locals.data();
307 interpOne(env, stackType, popped, pushed, idata);
308 if (checkTypeType) {
309 auto const out = getInstrInfo(sk.op()).out;
310 auto const checkIdx = BCSPRelOffset{
311 (out & InstrFlags::StackIns1) ? 1 : 0
312 }.to<FPInvOffset>(env.irb->fs().bcSPOff());
314 auto const loc = Location::Stack { checkIdx };
315 checkType(env, loc, *checkTypeType, nextBcOff(env));
319 void interpOne(IRGS& env, int popped) {
320 InterpOneData idata { spOffBCFromIRSP(env) };
321 interpOne(env, folly::none, popped, 0, idata);
324 void interpOne(IRGS& env, Type outType, int popped) {
325 InterpOneData idata { spOffBCFromIRSP(env) };
326 interpOne(env, outType, popped, 1, idata);
329 void interpOne(IRGS& env,
330 folly::Optional<Type> outType,
331 int popped,
332 int pushed,
333 InterpOneData& idata) {
334 auto const func = curFunc(env);
335 auto const op = func->getOp(bcOff(env));
337 idata.bcOff = bcOff(env);
338 idata.cellsPopped = popped;
339 idata.cellsPushed = pushed;
340 idata.opcode = op;
342 gen(
343 env,
344 opcodeChangesPC(idata.opcode) ? InterpOneCF : InterpOne,
345 outType,
346 idata,
347 sp(env),
348 fp(env)
352 //////////////////////////////////////////////////////////////////////
355 * Instructions that unconditionally are implemented with InterpOne are
356 * translated here.
359 void emitExit(IRGS& env) { interpOne(env); }
360 void emitFatal(IRGS& env, FatalOp) { interpOne(env); }
361 void emitSetOpG(IRGS& env, SetOpOp) { interpOne(env); }
362 void emitIncDecG(IRGS& env, IncDecOp) { interpOne(env); }
363 void emitUnsetG(IRGS& env) { interpOne(env); }
364 void emitIncl(IRGS& env) { interpOne(env); }
365 void emitInclOnce(IRGS& env) { interpOne(env); }
366 void emitReq(IRGS& env) { interpOne(env); }
367 void emitReqDoc(IRGS& env) { interpOne(env); }
368 void emitReqOnce(IRGS& env) { interpOne(env); }
369 void emitEval(IRGS& env) { interpOne(env); }
370 void emitChainFaults(IRGS& env) { interpOne(env); }
371 void emitContGetReturn(IRGS& env) { interpOne(env); }
372 void emitResolveClass(IRGS& env, const StringData*)
373 { interpOne(env); }
375 //////////////////////////////////////////////////////////////////////