EncoderMD.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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_origInlineeOffset;
  31. BYTE m_nopCount; // for AlignedLabel, how many nops do we need to be 16-byte aligned
  32. };
  33. public:
  34. void init(RelocType type, void* ptr)
  35. {
  36. m_type = type;
  37. m_ptr = ptr;
  38. if (type == RelocTypeLabel)
  39. {
  40. // preserve original PC for labels
  41. m_origPtr = (void*)((IR::LabelInstr*)ptr)->GetPC();
  42. m_nopCount = 0;
  43. }
  44. else
  45. {
  46. m_origPtr = ptr;
  47. // in case we have to revert, we need to store original offset in code buffer
  48. if (type == RelocTypeInlineeEntryOffset)
  49. {
  50. m_origInlineeOffset = *((uint32*)m_origPtr);
  51. }
  52. else if (type == RelocTypeBranch)
  53. {
  54. m_shortBrLabel = NULL;
  55. }
  56. }
  57. }
  58. void revert()
  59. {
  60. if (isLabel())
  61. {
  62. // recover old label PC and reset alignment nops
  63. // we keep aligned labels type so we align them on the second attempt.
  64. setLabelCurrPC(getLabelOrigPC());
  65. m_nopCount = 0;
  66. return;
  67. }
  68. // re-write original inlinee offset to code buffer
  69. if (m_type == RelocTypeInlineeEntryOffset)
  70. {
  71. *((uint32*)m_origPtr) = m_origInlineeOffset;
  72. }
  73. if (m_type == RelocTypeBranch)
  74. {
  75. m_shortBrLabel = NULL;
  76. }
  77. m_ptr = m_origPtr;
  78. }
  79. bool isLabel() const { return isAlignedLabel() || m_type == RelocTypeLabel; }
  80. bool isAlignedLabel() const { return m_type == RelocTypeAlignedLabel; }
  81. bool isLongBr() const { return m_type == RelocTypeBranch && m_shortBrLabel == NULL; }
  82. bool isShortBr() const { return m_type == RelocTypeBranch && m_shortBrLabel != NULL; }
  83. BYTE* getBrOpCodeByte() const {
  84. Assert(m_type == RelocTypeBranch);
  85. return (BYTE*)m_origPtr - 1;
  86. }
  87. IR::LabelInstr * getBrTargetLabel() const
  88. {
  89. Assert(m_type == RelocTypeBranch);
  90. return m_shortBrLabel == NULL ? *(IR::LabelInstr**)m_origPtr : m_shortBrLabel;
  91. }
  92. IR::LabelInstr * getLabel() const
  93. {
  94. Assert(isLabel());
  95. return (IR::LabelInstr*) m_ptr;
  96. }
  97. // get label original PC without shortening/alignment
  98. BYTE * getLabelOrigPC() const
  99. {
  100. Assert(isLabel());
  101. return ((BYTE*) m_origPtr);
  102. }
  103. // get label PC after shortening/alignment
  104. BYTE * getLabelCurrPC() const
  105. {
  106. Assert(isLabel());
  107. return getLabel()->GetPC();
  108. }
  109. BYTE getLabelNopCount() const
  110. {
  111. Assert(isAlignedLabel());
  112. return m_nopCount;
  113. }
  114. void setLabelCurrPC(BYTE* pc)
  115. {
  116. Assert(isLabel());
  117. getLabel()->SetPC(pc);
  118. }
  119. void setLabelNopCount(BYTE nopCount)
  120. {
  121. Assert(isAlignedLabel());
  122. Assert (nopCount >= 0 && nopCount < 16);
  123. m_nopCount = nopCount;
  124. }
  125. // Marks this entry as a short Br entry
  126. void setAsShortBr(IR::LabelInstr* label)
  127. {
  128. Assert(label != NULL);
  129. m_shortBrLabel = label;
  130. }
  131. // Validates if the branch is short and its target PC fits in one byte
  132. bool validateShortBrTarget() const
  133. {
  134. return isShortBr() &&
  135. m_shortBrLabel->GetPC() - ((BYTE*)m_ptr + 1) >= -128 &&
  136. m_shortBrLabel->GetPC() - ((BYTE*)m_ptr + 1) <= 127;
  137. }
  138. };
  139. ///---------------------------------------------------------------------------
  140. ///
  141. /// class EncoderMD
  142. ///
  143. ///---------------------------------------------------------------------------
  144. enum Forms : BYTE;
  145. typedef JsUtil::List<InlineeFrameRecord*, ArenaAllocator> InlineeFrameRecords;
  146. typedef JsUtil::List<EncodeRelocAndLabels, ArenaAllocator> RelocList;
  147. class EncoderMD
  148. {
  149. public:
  150. EncoderMD(Func * func) : m_func(func) { }
  151. ptrdiff_t Encode(IR::Instr * instr, BYTE *pc, BYTE* beginCodeAddress = nullptr);
  152. void Init(Encoder *encoder);
  153. void ApplyRelocs(uint32 codeBufferAddress);
  154. void EncodeInlineeCallInfo(IR::Instr *instr, uint32 offset);
  155. static bool TryConstFold(IR::Instr *instr, IR::RegOpnd *regOpnd);
  156. static bool TryFold(IR::Instr *instr, IR::RegOpnd *regOpnd);
  157. static bool SetsConditionCode(IR::Instr *instr);
  158. static bool UsesConditionCode(IR::Instr *instr);
  159. static bool IsOPEQ(IR::Instr *instr);
  160. RelocList* GetRelocList() const { return m_relocList; }
  161. int AppendRelocEntry(RelocType type, void *ptr);
  162. int FixRelocListEntry(uint32 index, int32 totalBytesSaved, BYTE *buffStart, BYTE* buffEnd);
  163. void FixMaps(uint32 brOffset, int32 bytesSaved, uint32 *inlineeFrameRecordsIndex, uint32 *inlineeFrameMapIndex, uint32 *pragmaInstToRecordOffsetIndex, uint32 *offsetBuffIndex);
  164. void UpdateRelocListWithNewBuffer(RelocList * relocList, BYTE * newBuffer, BYTE * oldBufferStart, BYTE * oldBufferEnd);
  165. #ifdef DBG
  166. void VerifyRelocList(BYTE *buffStart, BYTE *buffEnd);
  167. #endif
  168. void AddLabelReloc(BYTE* relocAddress);
  169. private:
  170. const BYTE GetOpcodeByte2(IR::Instr *instr);
  171. const BYTE * GetFormTemplate(IR::Instr *instr);
  172. static Forms GetInstrForm(IR::Instr *instr);
  173. const BYTE * GetOpbyte(IR::Instr *instr);
  174. const BYTE GetRegEncode(IR::RegOpnd *regOpnd);
  175. const uint32 GetLeadIn(IR::Instr * instr);
  176. static const uint32 GetOpdope(IR::Instr *instr);
  177. void EmitModRM(IR::Instr * instr, IR::Opnd *opnd, BYTE reg1);
  178. void EmitConst(size_t val, int size);
  179. int EmitImmed(IR::Opnd * opnd, int opSize, int sbit);
  180. void EmitCondBranch(IR::BranchInstr * branchInstr);
  181. bool FitsInByte(size_t value);
  182. BYTE GetMod(size_t offset, bool baseRegIsEBP, int * pDispSize);
  183. BYTE GetMod(IR::SymOpnd * opnd, int * pDispSize, RegNum& rmReg);
  184. BYTE GetMod(IR::IndirOpnd * opnd, int * pDispSize);
  185. private:
  186. Func * m_func;
  187. Encoder * m_encoder;
  188. BYTE * m_pc;
  189. RelocList* m_relocList;
  190. int32 m_lastLoopLabelPosition;
  191. };