PageRenderTime 50ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/vm/jit/ir-instruction.cpp

https://gitlab.com/alvinahmadov2/hhvm
C++ | 409 lines | 310 code | 65 blank | 34 comment | 57 complexity | 4c1bfca9df7f35e9ef5b8e69cdd1d2e2 MD5 | raw file
  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. +----------------------------------------------------------------------+
  15. */
  16. #include "hphp/runtime/vm/jit/ir-instruction.h"
  17. #include "hphp/runtime/base/repo-auth-type.h"
  18. #include "hphp/runtime/base/repo-auth-type-array.h"
  19. #include "hphp/runtime/vm/func.h"
  20. #include "hphp/runtime/vm/jit/block.h"
  21. #include "hphp/runtime/vm/jit/edge.h"
  22. #include "hphp/runtime/vm/jit/extra-data.h"
  23. #include "hphp/runtime/vm/jit/ir-instr-table.h"
  24. #include "hphp/runtime/vm/jit/ir-opcode.h"
  25. #include "hphp/runtime/vm/jit/minstr-effects.h"
  26. #include "hphp/runtime/vm/jit/print.h"
  27. #include "hphp/runtime/vm/jit/ssa-tmp.h"
  28. #include "hphp/runtime/vm/jit/type.h"
  29. #include "hphp/util/arena.h"
  30. #include "hphp/runtime/ext/asio/ext_async-function-wait-handle.h"
  31. #include "hphp/runtime/ext/asio/ext_static-wait-handle.h"
  32. #include <folly/Range.h>
  33. #include <algorithm>
  34. #include <sstream>
  35. namespace HPHP { namespace jit {
  36. //////////////////////////////////////////////////////////////////////
  37. IRInstruction::IRInstruction(Arena& arena, const IRInstruction* inst, Id id)
  38. : m_typeParam(inst->m_typeParam)
  39. , m_op(inst->m_op)
  40. , m_numSrcs(inst->m_numSrcs)
  41. , m_numDsts(inst->m_numDsts)
  42. , m_hasTypeParam{inst->m_hasTypeParam}
  43. , m_marker(inst->m_marker)
  44. , m_id(id)
  45. , m_srcs(m_numSrcs ? new (arena) SSATmp*[m_numSrcs] : nullptr)
  46. , m_dest(nullptr)
  47. , m_block(nullptr)
  48. , m_extra(inst->m_extra ? cloneExtra(op(), inst->m_extra, arena)
  49. : nullptr)
  50. {
  51. assertx(!isTransient());
  52. std::copy(inst->m_srcs, inst->m_srcs + inst->m_numSrcs, m_srcs);
  53. if (hasEdges()) {
  54. m_edges = new (arena) Edge[2];
  55. m_edges[0].setInst(this);
  56. m_edges[0].setTo(inst->next());
  57. m_edges[1].setInst(this);
  58. m_edges[1].setTo(inst->taken());
  59. } else {
  60. m_edges = nullptr;
  61. }
  62. }
  63. std::string IRInstruction::toString() const {
  64. std::ostringstream str;
  65. print(str, this);
  66. return str.str();
  67. }
  68. ///////////////////////////////////////////////////////////////////////////////
  69. void IRInstruction::convertToNop() {
  70. if (hasEdges()) clearEdges();
  71. IRInstruction nop(Nop, marker());
  72. m_op = nop.m_op;
  73. m_typeParam = nop.m_typeParam;
  74. m_numSrcs = nop.m_numSrcs;
  75. m_srcs = nop.m_srcs;
  76. m_numDsts = nop.m_numDsts;
  77. m_hasTypeParam = nop.m_hasTypeParam;
  78. m_dest = nop.m_dest;
  79. m_extra = nullptr;
  80. }
  81. void IRInstruction::become(IRUnit& unit, const IRInstruction* other) {
  82. assertx(other->isTransient() || m_numDsts == other->m_numDsts);
  83. auto& arena = unit.arena();
  84. if (hasEdges()) clearEdges();
  85. m_op = other->m_op;
  86. m_typeParam = other->m_typeParam;
  87. m_hasTypeParam = other->m_hasTypeParam;
  88. m_numSrcs = other->m_numSrcs;
  89. m_extra = other->m_extra ? cloneExtra(m_op, other->m_extra, arena) : nullptr;
  90. m_srcs = new (arena) SSATmp*[m_numSrcs];
  91. std::copy(other->m_srcs, other->m_srcs + m_numSrcs, m_srcs);
  92. if (hasEdges()) {
  93. assertx(other->hasEdges()); // m_op is from other now
  94. m_edges = new (arena) Edge[2];
  95. m_edges[0].setInst(this);
  96. m_edges[1].setInst(this);
  97. setNext(other->next());
  98. setTaken(other->taken());
  99. }
  100. }
  101. ///////////////////////////////////////////////////////////////////////////////
  102. bool IRInstruction::consumesReference(int srcNo) const {
  103. if (!consumesReferences()) {
  104. return false;
  105. }
  106. switch (op()) {
  107. case ConcatStrStr:
  108. case ConcatStrInt:
  109. case ConcatStr3:
  110. case ConcatStr4:
  111. // Call a helper that decrefs the first argument
  112. return srcNo == 0;
  113. case StRef:
  114. case StClosureArg:
  115. case StClosureCtx:
  116. case StContArValue:
  117. case StContArKey:
  118. case StRetVal:
  119. case StLoc:
  120. case AFWHBlockOn:
  121. // Consume the value being stored, not the thing it's being stored into
  122. return srcNo == 1;
  123. case StMem:
  124. // StMem <base>, <value>
  125. return srcNo == 1;
  126. case ArraySet:
  127. case ArraySetRef:
  128. // Only consumes the reference to its input array
  129. return srcNo == 0;
  130. case SpillFrame:
  131. // Consumes the $this/Class field of the ActRec
  132. return srcNo == 2;
  133. case MapAddElemC:
  134. // value at index 2
  135. return srcNo == 2;
  136. case ColAddNewElemC:
  137. // value at index 1
  138. return srcNo == 1;
  139. case CheckNullptr:
  140. return srcNo == 0;
  141. case CreateAFWH:
  142. case CreateAFWHNoVV:
  143. return srcNo == 4;
  144. case InitPackedArray:
  145. return srcNo == 1;
  146. case InitPackedArrayLoop:
  147. return srcNo > 0;
  148. default:
  149. return true;
  150. }
  151. }
  152. ///////////////////////////////////////////////////////////////////////////////
  153. void IRInstruction::setOpcode(Opcode newOpc) {
  154. assertx(hasEdges() || !jit::hasEdges(newOpc)); // cannot allocate new edges
  155. if (hasEdges() && !jit::hasEdges(newOpc)) {
  156. clearEdges();
  157. }
  158. m_op = newOpc;
  159. }
  160. SSATmp* IRInstruction::dst(unsigned i) const {
  161. if (i == 0 && m_numDsts == 0) return nullptr;
  162. assertx(i < m_numDsts);
  163. assertx(naryDst() || i == 0);
  164. return hasDst() ? dst() : m_dsts[i];
  165. }
  166. ///////////////////////////////////////////////////////////////////////////////
  167. // outputType().
  168. namespace {
  169. Type unboxPtr(Type t) {
  170. auto const pcell = t & TPtrToCell;
  171. auto const pref = t & TPtrToBoxedInitCell;
  172. return pref.deref().inner().ptr(Ptr::Ref) | pcell;
  173. }
  174. Type boxPtr(Type t) {
  175. auto const rawBoxed = t.deref().unbox().box();
  176. auto const noNull = rawBoxed - TBoxedUninit;
  177. return noNull.ptr(t.ptrKind() - Ptr::Ref);
  178. }
  179. Type allocObjReturn(const IRInstruction* inst) {
  180. switch (inst->op()) {
  181. case ConstructInstance:
  182. return Type::ExactObj(inst->extra<ConstructInstance>()->cls);
  183. case NewInstanceRaw:
  184. return Type::ExactObj(inst->extra<NewInstanceRaw>()->cls);
  185. case AllocObj:
  186. return inst->src(0)->hasConstVal()
  187. ? Type::ExactObj(inst->src(0)->clsVal())
  188. : TObj;
  189. case CreateSSWH:
  190. return Type::ExactObj(c_StaticWaitHandle::classof());
  191. case CreateAFWH:
  192. case CreateAFWHNoVV:
  193. return Type::ExactObj(c_AsyncFunctionWaitHandle::classof());
  194. default:
  195. always_assert(false && "Invalid opcode returning AllocObj");
  196. }
  197. }
  198. Type arrElemReturn(const IRInstruction* inst) {
  199. assertx(inst->is(LdStructArrayElem, ArrayGet));
  200. assertx(!inst->hasTypeParam() || inst->typeParam() <= TGen);
  201. auto resultType = inst->hasTypeParam() ? inst->typeParam() : TGen;
  202. if (inst->is(ArrayGet)) {
  203. resultType &= TInit;
  204. }
  205. // Elements of a noncounted array are uncounted
  206. if (inst->src(0)->isA(TPersistentArr)) {
  207. resultType &= TUncountedInit;
  208. }
  209. auto const arrTy = inst->src(0)->type().arrSpec().type();
  210. if (!arrTy) return resultType;
  211. using T = RepoAuthType::Array::Tag;
  212. using E = RepoAuthType::Array::Empty;
  213. switch (arrTy->tag()) {
  214. case T::Packed:
  215. {
  216. auto const idx = inst->src(1);
  217. if (idx->hasConstVal(TInt) &&
  218. idx->intVal() >= 0 &&
  219. idx->intVal() < arrTy->size()) {
  220. resultType &= typeFromRAT(arrTy->packedElem(idx->intVal()));
  221. }
  222. break;
  223. }
  224. case T::PackedN:
  225. resultType &= typeFromRAT(arrTy->elemType());
  226. break;
  227. }
  228. if (arrTy->emptiness() == E::Maybe) {
  229. resultType |= TInitNull;
  230. }
  231. return resultType;
  232. }
  233. Type thisReturn(const IRInstruction* inst) {
  234. auto const func = inst->marker().func();
  235. // If the function is a cloned closure which may have a re-bound $this which
  236. // is not a subclass of the context return an unspecialized type.
  237. if (func->hasForeignThis()) return TObj;
  238. if (auto const cls = func->cls()) {
  239. return Type::SubObj(cls);
  240. }
  241. return TObj;
  242. }
  243. Type ctxReturn(const IRInstruction* inst) {
  244. return thisReturn(inst) | TCctx;
  245. }
  246. Type setElemReturn(const IRInstruction* inst) {
  247. assertx(inst->op() == SetElem);
  248. auto baseType = inst->src(minstrBaseIdx(inst->op()))->type().strip();
  249. // If the base is a Str, the result will always be a CountedStr (or
  250. // an exception). If the base might be a str, the result wil be
  251. // CountedStr or Nullptr. Otherwise, the result is always Nullptr.
  252. if (baseType <= TStr) {
  253. return TCountedStr;
  254. } else if (baseType.maybe(TStr)) {
  255. return TCountedStr | TNullptr;
  256. }
  257. return TNullptr;
  258. }
  259. Type newColReturn(const IRInstruction* inst) {
  260. assertx(inst->is(NewCol, NewColFromArray));
  261. auto getColClassType = [&](CollectionType ct) -> Type {
  262. auto name = collections::typeToString(ct);
  263. auto cls = Unit::lookupClassOrUniqueClass(name);
  264. if (cls == nullptr) return TObj;
  265. return Type::ExactObj(cls);
  266. };
  267. if (inst->is(NewCol)) {
  268. return getColClassType(inst->extra<NewCol>()->type);
  269. }
  270. return getColClassType(inst->extra<NewColFromArray>()->type);
  271. }
  272. Type builtinReturn(const IRInstruction* inst) {
  273. assertx(inst->op() == CallBuiltin);
  274. Type t = inst->typeParam();
  275. if (t.isSimpleType() || t == TCell) {
  276. return t;
  277. }
  278. if (t.isReferenceType() || t == TBoxedCell) {
  279. return t | TInitNull;
  280. }
  281. not_reached();
  282. }
  283. } // namespace
  284. Type outputType(const IRInstruction* inst, int dstId) {
  285. using namespace TypeNames;
  286. using TypeNames::TCA;
  287. #define ND assertx(0 && "outputType requires HasDest or NaryDest");
  288. #define D(type) return type;
  289. #define DofS(n) return inst->src(n)->type();
  290. #define DRefineS(n) return inst->src(n)->type() & inst->typeParam();
  291. #define DParamMayRelax return inst->typeParam();
  292. #define DParam return inst->typeParam();
  293. #define DParamPtr(k) assertx(inst->typeParam() <= TGen.ptr(Ptr::k)); \
  294. return inst->typeParam();
  295. #define DLdObjCls { \
  296. if (auto spec = inst->src(0)->type().clsSpec()) { \
  297. auto const cls = spec.cls(); \
  298. return spec.exact() ? Type::ExactCls(cls) : Type::SubCls(cls); \
  299. } \
  300. return TCls; \
  301. }
  302. #define DUnboxPtr return unboxPtr(inst->src(0)->type());
  303. #define DBoxPtr return boxPtr(inst->src(0)->type());
  304. #define DAllocObj return allocObjReturn(inst);
  305. #define DArrElem return arrElemReturn(inst);
  306. #define DArrPacked return Type::Array(ArrayData::kPackedKind);
  307. #define DCol return newColReturn(inst);
  308. #define DThis return thisReturn(inst);
  309. #define DCtx return ctxReturn(inst);
  310. #define DMulti return TBottom;
  311. #define DSetElem return setElemReturn(inst);
  312. #define DBuiltin return builtinReturn(inst);
  313. #define DSubtract(n, t) return inst->src(n)->type() - t;
  314. #define DCns return TUninit | TInitNull | TBool | \
  315. TInt | TDbl | TStr | TRes;
  316. #define O(name, dstinfo, srcinfo, flags) case name: dstinfo not_reached();
  317. switch (inst->op()) {
  318. IR_OPCODES
  319. default: not_reached();
  320. }
  321. #undef O
  322. #undef ND
  323. #undef D
  324. #undef DofS
  325. #undef DRefineS
  326. #undef DParamMayRelax
  327. #undef DParam
  328. #undef DParamPtr
  329. #undef DLdObjCls
  330. #undef DUnboxPtr
  331. #undef DBoxPtr
  332. #undef DAllocObj
  333. #undef DArrElem
  334. #undef DArrPacked
  335. #undef DCol
  336. #undef DThis
  337. #undef DCtx
  338. #undef DMulti
  339. #undef DSetElem
  340. #undef DBuiltin
  341. #undef DSubtract
  342. #undef DCns
  343. }
  344. }}