2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2016 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/base/stats.h"
18 #include "hphp/runtime/base/strings.h"
20 #include "hphp/runtime/vm/jit/irgen-interpone.h"
21 #include "hphp/runtime/vm/jit/irgen-exit.h"
22 #include "hphp/runtime/vm/jit/irgen-internal.h"
24 namespace HPHP
{ namespace jit
{ namespace irgen
{
28 //////////////////////////////////////////////////////////////////////
30 void implAGet(IRGS
& env
, SSATmp
* classSrc
) {
31 if (classSrc
->type() <= TStr
) {
32 push(env
, ldCls(env
, classSrc
));
35 push(env
, gen(env
, LdObjClass
, classSrc
));
38 const StaticString
s_FATAL_NULL_THIS(Strings::FATAL_NULL_THIS
);
39 bool checkThis(IRGS
& env
, SSATmp
* ctx
) {
41 auto const err
= cns(env
, s_FATAL_NULL_THIS
.get());
42 gen(env
, RaiseError
, err
);
44 if (!ctx
->type().maybe(TObj
)) {
51 gen(env
, CheckCtxThis
, taken
, ctx
);
54 hint(env
, Block::Hint::Unlikely
);
61 //////////////////////////////////////////////////////////////////////
65 void emitAGetC(IRGS
& env
) {
66 auto const name
= topC(env
);
67 if (name
->type().subtypeOfAny(TObj
, TStr
)) {
72 interpOne(env
, TCls
, 1);
76 void emitAGetL(IRGS
& env
, int32_t id
) {
77 auto const ldrefExit
= makeExit(env
);
78 auto const ldPMExit
= makePseudoMainExit(env
);
79 auto const src
= ldLocInner(env
, id
, ldrefExit
, ldPMExit
, DataTypeSpecific
);
80 if (src
->type().subtypeOfAny(TObj
, TStr
)) {
87 void emitCGetL(IRGS
& env
, int32_t id
) {
88 auto const ldrefExit
= makeExit(env
);
89 auto const ldPMExit
= makePseudoMainExit(env
);
90 auto const loc
= ldLocInnerWarn(
100 void emitCGetQuietL(IRGS
& env
, int32_t id
) {
101 auto const ldrefExit
= makeExit(env
);
102 auto const ldPMExit
= makePseudoMainExit(env
);
103 auto const loc
= ldLocInner(
108 DataTypeCountnessInit
110 pushIncRef(env
, loc
);
113 void emitCUGetL(IRGS
& env
, int32_t id
) {
114 auto const ldrefExit
= makeExit(env
);
115 auto const ldPMExit
= makePseudoMainExit(env
);
116 pushIncRef(env
, ldLocInner(env
, id
, ldrefExit
, ldPMExit
, DataTypeGeneric
));
119 void emitPushL(IRGS
& env
, int32_t id
) {
120 assertTypeLocal(env
, id
, TInitCell
); // bytecode invariant
121 auto* locVal
= ldLoc(env
, id
, makeExit(env
), DataTypeGeneric
);
123 stLocRaw(env
, id
, fp(env
), cns(env
, TUninit
));
126 void emitCGetL2(IRGS
& env
, int32_t id
) {
127 auto const ldrefExit
= makeExit(env
);
128 auto const ldPMExit
= makePseudoMainExit(env
);
129 auto const oldTop
= pop(env
, DataTypeGeneric
);
130 auto const val
= ldLocInnerWarn(
135 DataTypeCountnessInit
137 pushIncRef(env
, val
);
142 SSATmp
* boxHelper(IRGS
& env
, SSATmp
* value
, F rewrite
) {
143 auto const t
= value
->type();
146 value
= cns(env
, TInitNull
);
148 value
= gen(env
, Box
, value
);
150 } else if (t
.maybe(TCell
)) {
153 auto const ret
= gen(env
, CheckType
, TBoxedInitCell
,
155 env
.irb
->constrainValue(ret
, DataTypeSpecific
);
158 [&](SSATmp
* box
) { // Next: value is Boxed
161 [&] { // Taken: value is not Boxed
162 auto const tmpType
= t
- TBoxedInitCell
;
163 assertx(tmpType
<= TCell
);
164 auto const tmp
= gen(env
, AssertType
, tmpType
, value
);
165 auto const ret
= gen(env
, Box
, tmp
);
173 void emitVGetL(IRGS
& env
, int32_t id
) {
174 auto const value
= ldLoc(env
, id
, makeExit(env
), DataTypeCountnessInit
);
175 auto const boxed
= boxHelper(
177 gen(env
, AssertType
, TCell
| TBoxedInitCell
, value
),
179 stLocRaw(env
, id
, fp(env
), v
);
182 pushIncRef(env
, boxed
);
185 void emitBox(IRGS
& env
) {
186 push(env
, gen(env
, Box
, pop(env
, DataTypeGeneric
)));
189 void emitBoxR(IRGS
& env
) {
190 auto const value
= pop(env
, DataTypeGeneric
);
191 auto const boxed
= boxHelper(
193 gen(env
, AssertType
, TCell
| TBoxedInitCell
, value
),
198 void emitUnsetL(IRGS
& env
, int32_t id
) {
199 auto const prev
= ldLoc(env
, id
, makeExit(env
), DataTypeCountness
);
200 stLocRaw(env
, id
, fp(env
), cns(env
, TUninit
));
204 void emitBindL(IRGS
& env
, int32_t id
) {
205 if (curFunc(env
)->isPseudoMain()) {
206 interpOne(env
, TBoxedInitCell
, 1);
210 auto const ldPMExit
= makePseudoMainExit(env
);
211 auto const newValue
= popV(env
);
212 // Note that the IncRef must happen first, for correctness in a
213 // pseudo-main: the destructor could decref the value again after
214 // we've stored it into the local.
215 pushIncRef(env
, newValue
);
216 auto const oldValue
= ldLoc(env
, id
, ldPMExit
, DataTypeSpecific
);
217 stLocRaw(env
, id
, fp(env
), newValue
);
218 decRef(env
, oldValue
);
221 void emitSetL(IRGS
& env
, int32_t id
) {
222 auto const ldrefExit
= makeExit(env
);
223 auto const ldPMExit
= makePseudoMainExit(env
);
225 // since we're just storing the value in a local, this function doesn't care
226 // about the type of the value. stLoc needs to IncRef the value so it may
227 // constrain it further.
228 auto const src
= popC(env
, DataTypeGeneric
);
229 pushStLoc(env
, id
, ldrefExit
, ldPMExit
, src
);
232 void emitInitThisLoc(IRGS
& env
, int32_t id
) {
233 if (!curFunc(env
)->mayHaveThis()) {
234 // Do nothing if this is null
237 auto const ldrefExit
= makeExit(env
);
238 auto const ctx
= ldCtx(env
);
240 [&] (Block
* skip
) { gen(env
, CheckCtxThis
, skip
, ctx
); },
242 auto const oldLoc
= ldLoc(env
, id
, ldrefExit
, DataTypeCountness
);
243 auto const this_
= gen(env
, CastCtxThis
, ctx
);
244 gen(env
, IncRef
, this_
);
245 stLocRaw(env
, id
, fp(env
), this_
);
250 void emitPrint(IRGS
& env
) {
251 auto const type
= topC(env
)->type();
252 if (!type
.subtypeOfAny(TInt
, TBool
, TNull
, TStr
)) {
253 interpOne(env
, TInt
, 1);
257 auto const cell
= popC(env
);
262 } else if (type
<= TInt
) {
264 } else if (type
<= TBool
) {
267 assertx(type
<= TNull
);
270 // the print helpers decref their arg, so don't decref pop'ed value
274 push(env
, cns(env
, 1));
277 void emitUnbox(IRGS
& env
) {
278 auto const exit
= makeExit(env
);
279 auto const srcBox
= popV(env
);
280 auto const unboxed
= unbox(env
, srcBox
, exit
);
281 pushIncRef(env
, unboxed
);
285 void emitThis(IRGS
& env
) {
286 auto const ctx
= ldCtx(env
);
287 if (!checkThis(env
, ctx
)) {
289 push(env
, cns(env
, TInitNull
));
292 auto const this_
= gen(env
, CastCtxThis
, ctx
);
293 pushIncRef(env
, this_
);
296 void emitCheckThis(IRGS
& env
) {
297 auto const ctx
= ldCtx(env
);
301 void emitBareThis(IRGS
& env
, BareThisOp subop
) {
302 auto const ctx
= ldCtx(env
);
303 if (!ctx
->type().maybe(TObj
)) {
304 if (subop
== BareThisOp::NoNotice
) {
305 push(env
, cns(env
, TInitNull
));
308 assertx(subop
!= BareThisOp::NeverNull
);
309 interpOne(env
, TInitNull
, 0); // will raise notice and push null
313 if (subop
== BareThisOp::NoNotice
) {
314 auto thiz
= cond(env
,
316 gen(env
, CheckCtxThis
, taken
, ctx
);
319 auto t
= gen(env
, CastCtxThis
, ctx
);
324 return cns(env
, TInitNull
);
330 if (subop
== BareThisOp::NeverNull
) {
331 env
.irb
->fs().setThisAvailable();
333 gen(env
, CheckCtxThis
, makeExitSlow(env
), ctx
);
336 pushIncRef(env
, gen(env
, CastCtxThis
, ctx
));
339 void emitClone(IRGS
& env
) {
340 if (!topC(env
)->isA(TObj
)) PUNT(Clone
-NonObj
);
341 auto const obj
= popC(env
);
342 push(env
, gen(env
, Clone
, obj
));
346 void emitLateBoundCls(IRGS
& env
) {
347 auto const clss
= curClass(env
);
349 // no static context class, so this will raise an error
350 interpOne(env
, TCls
, 0);
353 auto const ctx
= ldCtx(env
);
354 push(env
, gen(env
, LdClsCtx
, ctx
));
357 void emitSelf(IRGS
& env
) {
358 auto const clss
= curClass(env
);
359 if (clss
== nullptr) {
360 interpOne(env
, TCls
, 0);
362 push(env
, cns(env
, clss
));
366 void emitParent(IRGS
& env
) {
367 auto const clss
= curClass(env
);
368 if (clss
== nullptr || clss
->parent() == nullptr) {
369 interpOne(env
, TCls
, 0);
371 push(env
, cns(env
, clss
->parent()));
375 void emitNameA(IRGS
& env
) {
376 push(env
, gen(env
, LdClsName
, popA(env
)));
379 //////////////////////////////////////////////////////////////////////
381 void emitCastArray(IRGS
& env
) {
382 auto const src
= popC(env
);
386 if (src
->isA(TArr
)) {
393 Type::Array(ArrayData::kVecKind
),
398 [&](SSATmp
* vec
) { return gen(env
, ConvVecToArr
, vec
); },
406 Type::Array(ArrayData::kDictKind
),
411 [&](SSATmp
* dict
) { return gen(env
, ConvDictToArr
, dict
); },
417 if (src
->isA(TNull
)) return cns(env
, staticEmptyArray());
418 if (src
->isA(TBool
)) return gen(env
, ConvBoolToArr
, src
);
419 if (src
->isA(TDbl
)) return gen(env
, ConvDblToArr
, src
);
420 if (src
->isA(TInt
)) return gen(env
, ConvIntToArr
, src
);
421 if (src
->isA(TStr
)) return gen(env
, ConvStrToArr
, src
);
422 if (src
->isA(TObj
)) return gen(env
, ConvObjToArr
, src
);
423 return gen(env
, ConvCellToArr
, src
);
428 void emitCastBool(IRGS
& env
) {
429 auto const src
= popC(env
);
430 push(env
, gen(env
, ConvCellToBool
, src
));
434 void emitCastDouble(IRGS
& env
) {
435 auto const src
= popC(env
);
436 push(env
, gen(env
, ConvCellToDbl
, src
));
440 void emitCastInt(IRGS
& env
) {
441 auto const src
= popC(env
);
442 push(env
, gen(env
, ConvCellToInt
, src
));
446 void emitCastObject(IRGS
& env
) {
447 auto const src
= popC(env
);
448 push(env
, gen(env
, ConvCellToObj
, src
));
451 void emitCastString(IRGS
& env
) {
452 auto const src
= popC(env
);
453 push(env
, gen(env
, ConvCellToStr
, src
));
457 void emitIncStat(IRGS
& env
, int32_t counter
, int32_t value
) {
458 if (!Stats::enabled()) return;
459 gen(env
, IncStat
, cns(env
, counter
), cns(env
, value
), cns(env
, false));
462 //////////////////////////////////////////////////////////////////////
464 void emitPopA(IRGS
& env
) { popA(env
); }
465 void emitPopC(IRGS
& env
) { popDecRef(env
, DataTypeGeneric
); }
466 void emitPopV(IRGS
& env
) { popDecRef(env
, DataTypeGeneric
); }
467 void emitPopR(IRGS
& env
) { popDecRef(env
, DataTypeGeneric
); }
469 void emitDir(IRGS
& env
) { push(env
, cns(env
, curUnit(env
)->dirpath())); }
470 void emitFile(IRGS
& env
) { push(env
, cns(env
, curUnit(env
)->filepath())); }
472 void emitDup(IRGS
& env
) { pushIncRef(env
, topC(env
)); }
474 //////////////////////////////////////////////////////////////////////
476 void emitArray(IRGS
& env
, const ArrayData
* x
) {
477 assertx(x
->isPHPArray());
478 push(env
, cns(env
, x
));
481 void emitVec(IRGS
& env
, const ArrayData
* x
) {
482 assertx(x
->isVecArray());
483 push(env
, cns(env
, x
));
486 void emitDict(IRGS
& env
, const ArrayData
* x
) {
487 assertx(x
->isDict());
488 push(env
, cns(env
, x
));
491 void emitKeyset(IRGS
& env
, const ArrayData
* x
) {
492 assertx(x
->isKeyset());
493 push(env
, cns(env
, x
));
496 void emitString(IRGS
& env
, const StringData
* s
) { push(env
, cns(env
, s
)); }
497 void emitInt(IRGS
& env
, int64_t val
) { push(env
, cns(env
, val
)); }
498 void emitDouble(IRGS
& env
, double val
) { push(env
, cns(env
, val
)); }
499 void emitTrue(IRGS
& env
) { push(env
, cns(env
, true)); }
500 void emitFalse(IRGS
& env
) { push(env
, cns(env
, false)); }
502 void emitNull(IRGS
& env
) { push(env
, cns(env
, TInitNull
)); }
503 void emitNullUninit(IRGS
& env
) { push(env
, cns(env
, TUninit
)); }
505 //////////////////////////////////////////////////////////////////////
507 void emitNop(IRGS
&) {}
508 void emitEntryNop(IRGS
&) {}
509 void emitBoxRNop(IRGS
& env
) {
510 assertTypeStack(env
, BCSPRelOffset
{0}, TBoxedCell
);
512 void emitUnboxRNop(IRGS
& env
) {
513 assertTypeStack(env
, BCSPRelOffset
{0}, TCell
);
515 void emitRGetCNop(IRGS
&) {}
516 void emitFPassC(IRGS
&, int32_t) {}
517 void emitFPassVNop(IRGS
&, int32_t) {}
518 void emitDefClsNop(IRGS
&, Id
) {}
519 void emitBreakTraceHint(IRGS
&) {}
521 //////////////////////////////////////////////////////////////////////