EncoderMD.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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. class Encoder;
  6. enum RelocType {
  7. RelocTypeBranch, // cond, uncond branch
  8. RelocTypeCallPcrel, // calls
  9. RelocTypeLabelUse, // direct use of a label
  10. RelocTypeLabel, // points to label instr
  11. RelocTypeAlignedLabel, // points to loop-top label instr that needs alignment
  12. RelocTypeInlineeEntryOffset, // points to offset immediate in buffer
  13. };
  14. ///---------------------------------------------------------------------------
  15. ///
  16. /// class EncoderReloc
  17. ///
  18. ///---------------------------------------------------------------------------
  19. class EncodeRelocAndLabels
  20. {
  21. public:
  22. RelocType m_type;
  23. void * m_ptr; // points to encoded buffer byte or labelInstr
  24. void * m_origPtr; // original offset without shortening
  25. private:
  26. // these are type specific fields
  27. union
  28. {
  29. IR::LabelInstr * m_shortBrLabel; // NULL if not a short branch
  30. uint32 m_InlineeOffset;
  31. BYTE m_nopCount; // for AlignedLabel, how many nops do we need to be 16-byte aligned
  32. };
  33. union
  34. {
  35. IR::LabelInstr * m_labelInstr;
  36. const void * m_fnAddress;
  37. };
  38. public:
  39. void init(RelocType type, void* ptr, IR::LabelInstr* labelInstr, const void * fnAddress)
  40. {
  41. m_type = type;
  42. m_ptr = ptr;
  43. m_InlineeOffset = 0;
  44. m_labelInstr = nullptr;
  45. if (type == RelocTypeLabel)
  46. {
  47. // preserve original PC for labels
  48. m_origPtr = (void*)((IR::LabelInstr*)ptr)->GetPC();
  49. m_nopCount = 0;
  50. }
  51. else
  52. {
  53. m_origPtr = ptr;
  54. if (type == RelocTypeBranch)
  55. {
  56. m_shortBrLabel = NULL;
  57. m_labelInstr = labelInstr;
  58. }
  59. else if (type == RelocTypeLabelUse)
  60. {
  61. Assert(labelInstr);
  62. m_labelInstr = labelInstr;
  63. }
  64. else if (type == RelocTypeCallPcrel)
  65. {
  66. Assert(fnAddress);
  67. m_fnAddress = fnAddress;
  68. }
  69. }
  70. }
  71. void revert()
  72. {
  73. if (isLabel())
  74. {
  75. // recover old label PC and reset alignment nops
  76. // we keep aligned labels type so we align them on the second attempt.
  77. setLabelCurrPC(getLabelOrigPC());
  78. m_nopCount = 0;
  79. return;
  80. }
  81. if (m_type == RelocTypeBranch)
  82. {
  83. m_shortBrLabel = NULL;
  84. }
  85. m_ptr = m_origPtr;
  86. }
  87. bool isLabel() const { return isAlignedLabel() || m_type == RelocTypeLabel; }
  88. bool isAlignedLabel() const { return m_type == RelocTypeAlignedLabel; }
  89. bool isLongBr() const { return m_type == RelocTypeBranch && m_shortBrLabel == NULL; }
  90. bool isShortBr() const { return m_type == RelocTypeBranch && m_shortBrLabel != NULL; }
  91. BYTE* getBrOpCodeByte() const {
  92. Assert(m_type == RelocTypeBranch);
  93. return (BYTE*)m_origPtr - 1;
  94. }
  95. IR::LabelInstr * getBrTargetLabel() const
  96. {
  97. Assert(m_type == RelocTypeBranch);
  98. return m_shortBrLabel == NULL ? m_labelInstr : m_shortBrLabel;
  99. }
  100. IR::LabelInstr * getLabel() const
  101. {
  102. Assert(isLabel());
  103. return (IR::LabelInstr*) m_ptr;
  104. }
  105. IR::LabelInstr * GetLabelInstrForRelocTypeLabelUse()
  106. {
  107. Assert(m_type == RelocTypeLabelUse && m_labelInstr);
  108. return m_labelInstr;
  109. }
  110. const void * GetFnAddress()
  111. {
  112. Assert(m_type == RelocTypeCallPcrel && m_fnAddress);
  113. return m_fnAddress;
  114. }
  115. // get label original PC without shortening/alignment
  116. BYTE * getLabelOrigPC() const
  117. {
  118. Assert(isLabel());
  119. return ((BYTE*) m_origPtr);
  120. }
  121. // get label PC after shortening/alignment
  122. BYTE * getLabelCurrPC() const
  123. {
  124. Assert(isLabel());
  125. return getLabel()->GetPC();
  126. }
  127. BYTE getLabelNopCount() const
  128. {
  129. Assert(isAlignedLabel());
  130. return m_nopCount;
  131. }
  132. void setLabelCurrPC(BYTE* pc)
  133. {
  134. Assert(isLabel());
  135. getLabel()->SetPC(pc);
  136. }
  137. void setLabelNopCount(BYTE nopCount)
  138. {
  139. Assert(isAlignedLabel());
  140. Assert (nopCount >= 0 && nopCount < 16);
  141. m_nopCount = nopCount;
  142. }
  143. // Marks this entry as a short Br entry
  144. void setAsShortBr(IR::LabelInstr* label)
  145. {
  146. Assert(label != NULL);
  147. m_shortBrLabel = label;
  148. }
  149. // Validates if the branch is short and its target PC fits in one byte
  150. bool validateShortBrTarget() const
  151. {
  152. return isShortBr() &&
  153. m_shortBrLabel->GetPC() - ((BYTE*)m_ptr + 1) >= -128 &&
  154. m_shortBrLabel->GetPC() - ((BYTE*)m_ptr + 1) <= 127;
  155. }
  156. uint32 GetInlineOffset()
  157. {
  158. return m_InlineeOffset;
  159. }
  160. void SetInlineOffset(uint32 offset)
  161. {
  162. m_InlineeOffset = offset;
  163. }
  164. };
  165. ///---------------------------------------------------------------------------
  166. ///
  167. /// class EncoderMD
  168. ///
  169. ///---------------------------------------------------------------------------
  170. enum Forms : BYTE;
  171. typedef JsUtil::List<InlineeFrameRecord*, ArenaAllocator> InlineeFrameRecords;
  172. typedef JsUtil::List<EncodeRelocAndLabels, ArenaAllocator> RelocList;
  173. class EncoderMD
  174. {
  175. public:
  176. EncoderMD(Func * func) : m_func(func) { }
  177. ptrdiff_t Encode(IR::Instr * instr, BYTE *pc, BYTE* beginCodeAddress = nullptr);
  178. void Init(Encoder *encoder);
  179. void ApplyRelocs(uint32 codeBufferAddress, size_t codeSize, uint * bufferCRC, BOOL isBrShorteningSucceeded, bool isFinalBufferValidation = false);
  180. uint GetRelocDataSize(EncodeRelocAndLabels *reloc);
  181. void EncodeInlineeCallInfo(IR::Instr *instr, uint32 offset);
  182. static bool TryConstFold(IR::Instr *instr, IR::RegOpnd *regOpnd);
  183. static bool TryFold(IR::Instr *instr, IR::RegOpnd *regOpnd);
  184. static bool SetsConditionCode(IR::Instr *instr);
  185. static bool UsesConditionCode(IR::Instr *instr);
  186. static bool IsOPEQ(IR::Instr *instr);
  187. static bool IsSHIFT(IR::Instr *instr);
  188. RelocList* GetRelocList() const { return m_relocList; }
  189. int AppendRelocEntry(RelocType type, void *ptr, IR::LabelInstr * labelInstr = nullptr, const void * fnAddress = nullptr);
  190. int FixRelocListEntry(uint32 index, int32 totalBytesSaved, BYTE *buffStart, BYTE* buffEnd);
  191. void FixMaps(uint32 brOffset, int32 bytesSaved, uint32 *inlineeFrameRecordsIndex, uint32 *inlineeFrameMapIndex, uint32 *pragmaInstToRecordOffsetIndex, uint32 *offsetBuffIndex);
  192. void UpdateRelocListWithNewBuffer(RelocList * relocList, BYTE * newBuffer, BYTE * oldBufferStart, BYTE * oldBufferEnd);
  193. #ifdef DBG
  194. void VerifyRelocList(BYTE *buffStart, BYTE *buffEnd);
  195. #endif
  196. void AddLabelReloc(BYTE* relocAddress);
  197. BYTE * GetRelocBufferAddress(EncodeRelocAndLabels * reloc);
  198. private:
  199. const BYTE GetOpcodeByte2(IR::Instr *instr);
  200. const BYTE * GetFormTemplate(IR::Instr *instr);
  201. static Forms GetInstrForm(IR::Instr *instr);
  202. const BYTE * GetOpbyte(IR::Instr *instr);
  203. const BYTE GetRegEncode(IR::RegOpnd *regOpnd);
  204. const uint32 GetLeadIn(IR::Instr * instr);
  205. static const uint32 GetOpdope(IR::Instr *instr);
  206. void EmitModRM(IR::Instr * instr, IR::Opnd *opnd, BYTE reg1);
  207. void EmitConst(size_t val, int size);
  208. int EmitImmed(IR::Opnd * opnd, int opSize, int sbit);
  209. void EmitCondBranch(IR::BranchInstr * branchInstr);
  210. bool FitsInByte(size_t value);
  211. BYTE GetMod(size_t offset, bool baseRegIsEBP, int * pDispSize);
  212. BYTE GetMod(IR::SymOpnd * opnd, int * pDispSize, RegNum& rmReg);
  213. BYTE GetMod(IR::IndirOpnd * opnd, int * pDispSize);
  214. private:
  215. Func * m_func;
  216. Encoder * m_encoder;
  217. BYTE * m_pc;
  218. RelocList* m_relocList;
  219. int32 m_lastLoopLabelPosition;
  220. };