IRBuilder.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. ///---------------------------------------------------------------------------
  7. ///
  8. /// class IRBuilder
  9. ///
  10. /// To generate IR from the Jn bytecodes.
  11. ///
  12. ///---------------------------------------------------------------------------
  13. class BranchReloc
  14. {
  15. public:
  16. BranchReloc(IR::BranchInstr * instr, uint32 branchOffset, uint32 offs)
  17. : branchInstr(instr), branchOffset(branchOffset), offset(offs), isNotBackEdge(false)
  18. { }
  19. private:
  20. IR::BranchInstr * branchInstr;
  21. uint32 offset;
  22. bool isNotBackEdge;
  23. uint32 branchOffset;
  24. public:
  25. IR::BranchInstr * GetBranchInstr()
  26. {
  27. return this->branchInstr;
  28. }
  29. uint32 GetOffset() const
  30. {
  31. return this->offset;
  32. }
  33. uint32 GetBranchOffset() const
  34. {
  35. return this->branchOffset;
  36. }
  37. bool IsNotBackEdge() const
  38. {
  39. return this->isNotBackEdge;
  40. }
  41. void SetNotBackEdge()
  42. {
  43. this->isNotBackEdge = true;
  44. }
  45. };
  46. class IRBuilder
  47. {
  48. friend struct IRBuilderSwitchAdapter;
  49. public:
  50. IRBuilder(Func * func)
  51. : m_func(func)
  52. , m_argsOnStack(0)
  53. , m_loopBodyRetIPSym(nullptr)
  54. , m_ldSlots(nullptr)
  55. , m_loopCounterSym(nullptr)
  56. , callTreeHasSomeProfileInfo(false)
  57. , m_saveLoopImplicitCallFlags(nullptr)
  58. , catchOffsetStack(nullptr)
  59. , m_switchAdapter(this)
  60. , m_switchBuilder(&m_switchAdapter)
  61. #if DBG
  62. , m_callsOnStack(0)
  63. , m_usedAsTemp(nullptr)
  64. #endif
  65. #ifdef BAILOUT_INJECTION
  66. , seenLdStackArgPtr(false)
  67. , expectApplyArg(false)
  68. , seenProfiledBeginSwitch(false)
  69. #endif
  70. #ifdef BYTECODE_BRANCH_ISLAND
  71. , longBranchMap(nullptr)
  72. #endif
  73. {
  74. auto loopCount = func->GetJnFunction()->GetLoopCount();
  75. if (loopCount > 0) {
  76. m_saveLoopImplicitCallFlags = (IR::Opnd**)func->m_alloc->Alloc(sizeof(IR::Opnd*) * loopCount);
  77. #if DBG
  78. memset(m_saveLoopImplicitCallFlags, 0, sizeof(IR::Opnd*) * loopCount);
  79. #endif
  80. }
  81. // Note: use original byte code without debugging probes, so that we don't jit BPs inserted by the user.
  82. m_functionBody = func->m_workItem->GetFunctionBody();
  83. func->m_workItem->InitializeReader(m_jnReader, m_statementReader);
  84. };
  85. ~IRBuilder() {
  86. Assert(m_func->GetJnFunction()->GetLoopCount() == 0 || m_saveLoopImplicitCallFlags);
  87. if (m_saveLoopImplicitCallFlags) {
  88. m_func->m_alloc->Free(m_saveLoopImplicitCallFlags, sizeof(IR::Opnd*) * m_func->GetJnFunction()->GetLoopCount());
  89. }
  90. }
  91. void Build();
  92. void InsertLabels();
  93. IR::LabelInstr * CreateLabel(IR::BranchInstr * branchInstr, uint& offset);
  94. private:
  95. void AddInstr(IR::Instr *instr, uint32 offset);
  96. BranchReloc * AddBranchInstr(IR::BranchInstr *instr, uint32 offset, uint32 targetOffset);
  97. #ifdef BYTECODE_BRANCH_ISLAND
  98. void ConsumeBranchIsland();
  99. void EnsureConsumeBranchIsland();
  100. uint ResolveVirtualLongBranch(IR::BranchInstr * branchInstr, uint offset);
  101. #endif
  102. BranchReloc * CreateRelocRecord(IR::BranchInstr * branchInstr, uint32 offset, uint32 targetOffset);
  103. void BuildGeneratorPreamble();
  104. void BuildConstantLoads();
  105. void BuildImplicitArgIns();
  106. #define LAYOUT_TYPE(layout) \
  107. void Build##layout(Js::OpCode newOpcode, uint32 offset);
  108. #define LAYOUT_TYPE_WMS(layout) \
  109. template <typename SizePolicy> void Build##layout(Js::OpCode newOpcode, uint32 offset);
  110. #include "ByteCode\LayoutTypes.h"
  111. void BuildReg1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0);
  112. void BuildReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::RegSlot R1, uint32 nextOffset);
  113. void BuildProfiledReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, Js::ProfileId profileId, Js::InlineCacheIndex inlineCacheIndex = Js::Constants::NoInlineCacheIndex);
  114. void BuildProfiledReg2WithICIndex(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, Js::ProfileId profileId, Js::InlineCacheIndex inlineCacheIndex);
  115. void BuildReg3(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
  116. Js::RegSlot src2RegSlot, Js::ProfileId profileId);
  117. void BuildReg3C(Js::OpCode newOpCode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
  118. Js::RegSlot src2RegSlot, Js::CacheId inlineCacheIndex);
  119. void BuildReg4(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
  120. Js::RegSlot src2RegSlot, Js::RegSlot src3RegSlot);
  121. void BuildReg2B1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, byte index);
  122. void BuildReg3B1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
  123. Js::RegSlot src2RegSlot, uint8 index);
  124. void BuildReg5(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
  125. Js::RegSlot src2RegSlot, Js::RegSlot src3RegSlot, Js::RegSlot src4RegSlot);
  126. void BuildUnsigned1(Js::OpCode newOpcode, uint32 offset, uint32 C1);
  127. void BuildReg1Unsigned1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, int32 C1);
  128. void BuildProfiledReg1Unsigned1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, int32 C1, Js::ProfileId profileId);
  129. void BuildReg2Int1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, int32 value);
  130. void BuildElementC(Js::OpCode newOpcode, uint32 offset, Js::RegSlot fieldRegSlot, Js::RegSlot regSlot,
  131. Js::PropertyIdIndexType propertyIdIndex);
  132. void BuildElementScopedC(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot,
  133. Js::PropertyIdIndexType propertyIdIndex);
  134. void BuildElementSlot(Js::OpCode newOpcode, uint32 offset, Js::RegSlot fieldRegSlot, Js::RegSlot regSlot,
  135. int32 slotId, Js::ProfileId profileId);
  136. void BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot,
  137. int32 slotId, Js::ProfileId profileId);
  138. void BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot,
  139. int32 slotId1, int32 slotId2, Js::ProfileId profileId);
  140. void BuildArgIn0(uint32 offset, Js::RegSlot R0);
  141. void BuildArg(Js::OpCode newOpcode, uint32 offset, Js::ArgSlot argument, Js::RegSlot srcRegSlot);
  142. void BuildArgIn(uint32 offset, Js::RegSlot dstRegSlot, uint16 argument);
  143. void BuildArgInRest();
  144. void BuildElementP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot, Js::CacheId inlineCacheIndex);
  145. void BuildElementCP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance, Js::RegSlot regSlot, Js::CacheId inlineCacheIndex);
  146. void BuildElementC2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instanceSlot, Js::RegSlot instance2Slot,
  147. Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex);
  148. void BuildElementScopedC2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance2Slot,
  149. Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex);
  150. void BuildElementU(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance, Js::PropertyIdIndexType propertyIdIndex);
  151. void BuildElementI(Js::OpCode newOpcode, uint32 offset, Js::RegSlot baseRegSlot, Js::RegSlot indexRegSlot,
  152. Js::RegSlot regSlot, Js::ProfileId profileId);
  153. void BuildElementUnsigned1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot baseRegSlot, uint32 index, Js::RegSlot regSlot);
  154. IR::Instr * BuildCallI_Helper(Js::OpCode newOpcode, uint32 offset, Js::RegSlot Return, Js::RegSlot Function, Js::ArgSlot ArgCount,
  155. Js::ProfileId profileId, Js::InlineCacheIndex inlineCacheIndex = Js::Constants::NoInlineCacheIndex);
  156. IR::Instr * BuildProfiledCallI(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  157. Js::ArgSlot argCount, Js::ProfileId profileId, Js::InlineCacheIndex inlineCacheIndex = Js::Constants::NoInlineCacheIndex);
  158. IR::Instr * BuildProfiledCallIExtended(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  159. Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options, uint32 spreadAuxOffset);
  160. IR::Instr * BuildProfiledCallIWithICIndex(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  161. Js::ArgSlot argCount, Js::ProfileId profileId, Js::InlineCacheIndex inlineCacheIndex);
  162. void BuildProfiledCallIExtendedFlags(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  163. Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options, uint32 spreadAuxOffset);
  164. void BuildProfiledCallIExtendedWithICIndex(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  165. Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options, uint32 spreadAuxOffset);
  166. void BuildProfiledCallIExtendedFlagsWithICIndex(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  167. Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options, uint32 spreadAuxOffset);
  168. void BuildProfiled2CallI(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  169. Js::ArgSlot argCount, Js::ProfileId profileId, Js::ProfileId profileId2);
  170. void BuildProfiled2CallIExtended(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  171. Js::ArgSlot argCount, Js::ProfileId profileId, Js::ProfileId profileId2, Js::CallIExtendedOptions options, uint32 spreadAuxOffset);
  172. void BuildLdSpreadIndices(uint32 offset, uint32 spreadAuxOffset);
  173. void BuildCallIExtended(Js::OpCode newOpcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
  174. Js::ArgSlot argCount, Js::CallIExtendedOptions options, uint32 spreadAuxOffset);
  175. void BuildCallCommon(IR::Instr *instr, StackSym *symDst, Js::ArgSlot argCount);
  176. void BuildRegexFromPattern(Js::RegSlot dstRegSlot, uint32 patternIndex, uint32 offset);
  177. void BuildClass(Js::OpCode newOpcode, uint32 offset, Js::RegSlot constructor, Js::RegSlot extends);
  178. void BuildBrReg1(Js::OpCode newOpcode, uint32 offset, uint targetOffset, Js::RegSlot srcRegSlot);
  179. void BuildBrReg2(Js::OpCode newOpcode, uint32 offset, uint targetOffset, Js::RegSlot src1RegSlot, Js::RegSlot src2RegSlot);
  180. void BuildBrBReturn(Js::OpCode newOpcode, uint32 offset, Js::RegSlot DestRegSlot, Js::RegSlot SrcRegSlot, uint32 targetOffset);
  181. IR::IndirOpnd * BuildIndirOpnd(IR::RegOpnd *baseReg, IR::RegOpnd *indexReg);
  182. IR::IndirOpnd * BuildIndirOpnd(IR::RegOpnd *baseReg, uint32 offset);
  183. #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
  184. IR::IndirOpnd * BuildIndirOpnd(IR::RegOpnd *baseReg, uint32 offset, const wchar_t *desc);
  185. #endif
  186. IR::SymOpnd * BuildFieldOpnd(Js::OpCode newOpCode, Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, PropertyKind propertyKind, uint inlineCacheIndex = -1);
  187. PropertySym * BuildFieldSym(Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, uint inlineCacheIndex, PropertyKind propertyKind);
  188. SymID BuildSrcStackSymID(Js::RegSlot regSlot);
  189. IR::RegOpnd * BuildDstOpnd(Js::RegSlot dstRegSlot, IRType type = TyVar, bool isCatchObjectSym = false);
  190. IR::RegOpnd * BuildSrcOpnd(Js::RegSlot srcRegSlot, IRType type = TyVar);
  191. IR::AddrOpnd * BuildAuxArrayOpnd(AuxArrayValue auxArrayType, uint32 offset, uint32 auxArrayOffset, uint extraSlots = 0);
  192. IR::Opnd * BuildAuxObjectLiteralTypeRefOpnd(int objectId, uint32 offset);
  193. private:
  194. uint AddStatementBoundary(uint statementIndex, uint offset);
  195. void CheckBuiltIn(PropertySym * propertySym, Js::BuiltinFunction *puBuiltInIndex);
  196. bool IsFloatFunctionCallsite(Js::BuiltinFunction index, size_t argc);
  197. IR::Instr * BuildProfiledFieldLoad(Js::OpCode loadOp, IR::RegOpnd *dstOpnd, IR::SymOpnd *srcOpnd, Js::CacheId inlineCacheIndex, bool *pUnprofiled);
  198. IR::Instr * BuildProfiledSlotLoad(Js::OpCode loadOp, IR::RegOpnd *dstOpnd, IR::SymOpnd *srcOpnd, Js::ProfileId profileId, bool *pUnprofiled);
  199. SymID GetMappedTemp(Js::RegSlot reg)
  200. {
  201. AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
  202. AssertMsg(this->tempMap, "Processing non-temp reg without a temp map?");
  203. return this->tempMap[reg - this->firstTemp];
  204. }
  205. void SetMappedTemp(Js::RegSlot reg, SymID tempId)
  206. {
  207. AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
  208. AssertMsg(this->tempMap, "Processing non-temp reg without a temp map?");
  209. this->tempMap[reg - this->firstTemp] = tempId;
  210. }
  211. BOOL GetTempUsed(Js::RegSlot reg)
  212. {
  213. AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
  214. AssertMsg(this->fbvTempUsed, "Processing non-temp reg without a used BV?");
  215. return this->fbvTempUsed->Test(reg - this->firstTemp);
  216. }
  217. void SetTempUsed(Js::RegSlot reg, BOOL used)
  218. {
  219. AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
  220. AssertMsg(this->fbvTempUsed, "Processing non-temp reg without a used BV?");
  221. if (used)
  222. {
  223. this->fbvTempUsed->Set(reg - this->firstTemp);
  224. }
  225. else
  226. {
  227. this->fbvTempUsed->Clear(reg - this->firstTemp);
  228. }
  229. }
  230. BOOL RegIsTemp(Js::RegSlot reg)
  231. {
  232. return reg >= this->firstTemp;
  233. }
  234. BOOL RegIsConstant(Js::RegSlot reg)
  235. {
  236. return reg > 0 && reg < this->m_func->GetJnFunction()->GetConstantCount();
  237. }
  238. Js::RegSlot InnerScopeIndexToRegSlot(uint32) const;
  239. Js::RegSlot GetEnvReg() const;
  240. Js::RegSlot GetEnvRegForEvalCode() const;
  241. Js::RegSlot GetEnvRegForInnerFrameDisplay() const;
  242. void AddEnvOpndForInnerFrameDisplay(IR::Instr *instr, uint offset);
  243. bool DoSlotArrayCheck(IR::SymOpnd *fieldOpnd, bool doDynamicCheck);
  244. void EmitClosureRangeChecks();
  245. void DoClosureRegCheck(Js::RegSlot reg);
  246. void BuildInitCachedScope(int auxOffset, int offset);
  247. void GenerateLoopBodySlotAccesses(uint offset);
  248. void GenerateLoopBodyStSlots(SymID loopParamSymId, uint offset);
  249. IR::Instr * GenerateLoopBodyStSlot(Js::RegSlot regSlot, uint offset = Js::Constants::NoByteCodeOffset);
  250. bool IsLoopBody() const;
  251. bool IsLoopBodyInTry() const;
  252. uint GetLoopBodyExitInstrOffset() const;
  253. IR::SymOpnd * BuildLoopBodySlotOpnd(SymID symId);
  254. void EnsureLoopBodyLoadSlot(SymID symId, bool isCatchObjectSym = false);
  255. void SetLoopBodyStSlot(SymID symID, bool isCatchObjectSym);
  256. bool IsLoopBodyOuterOffset(uint offset) const;
  257. bool IsLoopBodyReturnIPInstr(IR::Instr * instr) const;
  258. IR::Opnd * InsertLoopBodyReturnIPInstr(uint targetOffset, uint offset);
  259. IR::Instr * CreateLoopBodyReturnIPInstr(uint targetOffset, uint offset);
  260. void InsertBailOutForDebugger(uint offset, IR::BailOutKind kind, IR::Instr* insertBeforeInstr = nullptr);
  261. void InsertBailOnNoProfile(uint offset);
  262. void InsertBailOnNoProfile(IR::Instr *const insertBeforeInstr);
  263. bool DoBailOnNoProfile();
  264. void InsertIncrLoopBodyLoopCounter(IR::LabelInstr *loopTopLabelInstr);
  265. void InsertInitLoopBodyLoopCounter(uint loopNum);
  266. void InsertDoneLoopBodyLoopCounter(uint32 lastOffset);
  267. IR::RegOpnd * InsertConvPrimStr(IR::RegOpnd * srcOpnd, uint offset, bool forcePreOpBailOutIfNeeded);
  268. #ifdef BAILOUT_INJECTION
  269. void InjectBailOut(uint offset);
  270. void CheckBailOutInjection(Js::OpCode opcode);
  271. bool seenLdStackArgPtr;
  272. bool expectApplyArg;
  273. bool seenProfiledBeginSwitch;
  274. #endif
  275. JitArenaAllocator * m_tempAlloc;
  276. JitArenaAllocator * m_funcAlloc;
  277. Func * m_func;
  278. IR::Instr * m_lastInstr;
  279. IR::Instr ** m_offsetToInstruction;
  280. uint32 m_functionStartOffset;
  281. Js::ByteCodeReader m_jnReader;
  282. Js::StatementReader m_statementReader;
  283. Js::FunctionBody * m_functionBody;
  284. SList<IR::Instr *> *m_argStack;
  285. SList<BranchReloc*> *branchRelocList;
  286. SList<uint> *catchOffsetStack;
  287. SymID * tempMap;
  288. BVFixed * fbvTempUsed;
  289. Js::RegSlot firstTemp;
  290. IRBuilderSwitchAdapter m_switchAdapter;
  291. SwitchIRBuilder m_switchBuilder;
  292. BVFixed * m_ldSlots;
  293. BVFixed * m_stSlots;
  294. #if DBG
  295. BVFixed * m_usedAsTemp;
  296. #endif
  297. StackSym * m_loopBodyRetIPSym;
  298. StackSym* m_loopCounterSym;
  299. bool callTreeHasSomeProfileInfo;
  300. // Keep track of how many args we have on the stack whenever
  301. // we make a call so that the max stack used over all calls can be
  302. // used to estimate how much stack we should probe for at the
  303. // beginning of a JITted function.
  304. #if DBG
  305. uint32 m_offsetToInstructionCount;
  306. uint32 m_callsOnStack;
  307. #endif
  308. uint32 m_argsOnStack;
  309. Js::PropertyId m_loopBodyLocalsStartSlot;
  310. IR::Opnd** m_saveLoopImplicitCallFlags;
  311. #ifdef BYTECODE_BRANCH_ISLAND
  312. typedef JsUtil::BaseDictionary<uint32, uint32, JitArenaAllocator> LongBranchMap;
  313. LongBranchMap * longBranchMap;
  314. static IR::Instr * const VirtualLongBranchInstr;
  315. #endif
  316. };