PrologEncoder.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. #include "Backend.h"
  6. #include "PrologEncoderMD.h"
  7. void PrologEncoder::RecordNonVolRegSave()
  8. {
  9. requiredUnwindCodeNodeCount++;
  10. }
  11. void PrologEncoder::RecordXmmRegSave()
  12. {
  13. requiredUnwindCodeNodeCount += 2;
  14. }
  15. void PrologEncoder::RecordAlloca(size_t size)
  16. {
  17. Assert(size);
  18. requiredUnwindCodeNodeCount += PrologEncoderMD::GetRequiredNodeCountForAlloca(size);
  19. }
  20. DWORD PrologEncoder::SizeOfPData()
  21. {
  22. return sizeof(PData) + (sizeof(UNWIND_CODE) * requiredUnwindCodeNodeCount);
  23. }
  24. void PrologEncoder::SetPDataPtr(void *pdata)
  25. {
  26. this->pdata = static_cast<PData *>(pdata);
  27. }
  28. void PrologEncoder::EncodeSmallProlog(uint8 prologSize, size_t allocaSize)
  29. {
  30. Assert(!pdata);
  31. Assert(allocaSize <= 128);
  32. Assert(requiredUnwindCodeNodeCount == 0);
  33. // Increment requiredUnwindCodeNodeCount to ensure we do the Alloc for the correct size
  34. currentUnwindCodeNodeIndex = ++requiredUnwindCodeNodeCount;
  35. if (!pdata)
  36. {
  37. pdata = (PData *)alloc->Alloc(SizeOfPData());
  38. }
  39. currentInstrOffset = prologSize;
  40. UnwindCode* unwindCode = GetUnwindCode(1);
  41. size_t slots = (allocaSize - MachPtr) / MachPtr;
  42. uint8 unwindCodeOpInfo = TO_UNIBBLE(slots);
  43. unwindCode->SetOffset(prologSize);
  44. unwindCode->SetOp(TO_UNIBBLE(UWOP_ALLOC_SMALL));
  45. unwindCode->SetOpInfo(unwindCodeOpInfo);
  46. }
  47. void PrologEncoder::EncodeInstr(IR::Instr *instr, unsigned __int8 size)
  48. {
  49. Assert(instr);
  50. Assert(size);
  51. // We've started encoding instructions. This is a good time to initialize
  52. // pdata as we now have the final size.
  53. if (!pdata)
  54. {
  55. pdata = (PData *)alloc->Alloc(SizeOfPData());
  56. }
  57. Assert(pdata);
  58. UnwindCode *unwindCode = nullptr;
  59. unsigned __int8 unwindCodeOp = PrologEncoderMD::GetOp(instr);
  60. unsigned __int8 unwindCodeOpInfo = 0;
  61. unsigned __int16 uint16Val = 0;
  62. unsigned __int32 uint32Val = 0;
  63. if (!currentInstrOffset)
  64. currentUnwindCodeNodeIndex = requiredUnwindCodeNodeCount;
  65. Assert((currentInstrOffset + size) > currentInstrOffset);
  66. currentInstrOffset += size;
  67. switch (unwindCodeOp)
  68. {
  69. case UWOP_PUSH_NONVOL:
  70. {
  71. unwindCode = GetUnwindCode(1);
  72. unwindCodeOpInfo = PrologEncoderMD::GetNonVolRegToSave(instr);
  73. break;
  74. }
  75. case UWOP_SAVE_XMM128:
  76. {
  77. unwindCode = GetUnwindCode(2);
  78. unwindCodeOpInfo = PrologEncoderMD::GetXmmRegToSave(instr, &uint16Val);
  79. *((unsigned __int16 *)&((UNWIND_CODE *)unwindCode)[1]) = uint16Val;
  80. break;
  81. }
  82. case UWOP_ALLOC_SMALL:
  83. {
  84. unwindCode = GetUnwindCode(1);
  85. size_t allocaSize = PrologEncoderMD::GetAllocaSize(instr);
  86. Assert((allocaSize - MachPtr) % MachPtr == 0);
  87. size_t slots = (allocaSize - MachPtr) / MachPtr;
  88. Assert(IS_UNIBBLE(slots));
  89. unwindCodeOpInfo = TO_UNIBBLE(slots);
  90. break;
  91. }
  92. case UWOP_ALLOC_LARGE:
  93. {
  94. size_t allocaSize = PrologEncoderMD::GetAllocaSize(instr);
  95. Assert(allocaSize > 0x80);
  96. Assert(allocaSize % 8 == 0);
  97. Assert(IS_UNIBBLE(unwindCodeOp));
  98. size_t slots = allocaSize / MachPtr;
  99. if (allocaSize > 0x7FF8)
  100. {
  101. unwindCode = GetUnwindCode(3);
  102. uint32Val = TO_UINT32(allocaSize);
  103. unwindCodeOpInfo = 1;
  104. unwindCode->SetOp(TO_UNIBBLE(unwindCodeOp));
  105. *((unsigned __int32 *)&((UNWIND_CODE *)unwindCode)[1]) = uint32Val;
  106. }
  107. else
  108. {
  109. unwindCode = GetUnwindCode(2);
  110. uint16Val = TO_UINT16(slots);
  111. unwindCodeOpInfo = 0;
  112. unwindCode->SetOp(TO_UNIBBLE(unwindCodeOp));
  113. *((unsigned __int16 *)&((UNWIND_CODE *)unwindCode)[1]) = uint16Val;
  114. }
  115. break;
  116. }
  117. case UWOP_IGNORE:
  118. {
  119. return;
  120. }
  121. default:
  122. {
  123. AssertMsg(false, "PrologEncoderMD returned unsupported UnwindCodeOp.");
  124. }
  125. }
  126. Assert(unwindCode);
  127. unwindCode->SetOffset(currentInstrOffset);
  128. Assert(IS_UNIBBLE(unwindCodeOp));
  129. unwindCode->SetOp(TO_UNIBBLE(unwindCodeOp));
  130. Assert(IS_UNIBBLE(unwindCodeOpInfo));
  131. unwindCode->SetOpInfo(TO_UNIBBLE(unwindCodeOpInfo));
  132. }
  133. BYTE *PrologEncoder::Finalize(BYTE *functionStart,
  134. DWORD codeSize,
  135. BYTE *pdataBuffer)
  136. {
  137. Assert(pdata);
  138. Assert(pdataBuffer > functionStart);
  139. Assert((size_t)pdataBuffer % sizeof(DWORD) == 0);
  140. pdata->runtimeFunction.BeginAddress = 0;
  141. pdata->runtimeFunction.EndAddress = codeSize;
  142. pdata->runtimeFunction.UnwindData = (DWORD)((pdataBuffer + sizeof(RUNTIME_FUNCTION)) - functionStart);
  143. FinalizeUnwindInfo();
  144. return (BYTE *)&pdata->runtimeFunction;
  145. }
  146. void PrologEncoder::FinalizeUnwindInfo()
  147. {
  148. pdata->unwindInfo.Version = 1;
  149. pdata->unwindInfo.Flags = 0;
  150. pdata->unwindInfo.SizeOfProlog = currentInstrOffset;
  151. pdata->unwindInfo.CountOfCodes = requiredUnwindCodeNodeCount;
  152. // We don't use the frame pointer in the standard way, and since we don't do dynamic stack allocation, we don't change the
  153. // stack pointer except during calls. From the perspective of the unwind info, it needs to restore information relative to
  154. // the stack pointer, so don't register the frame pointer.
  155. pdata->unwindInfo.FrameRegister = 0;
  156. pdata->unwindInfo.FrameOffset = 0;
  157. AssertMsg(requiredUnwindCodeNodeCount <= 34, "We allocate 72 bytes for xdata - 34 (UnwindCodes) * 2 + 4 (UnwindInfo)");
  158. }
  159. PrologEncoder::UnwindCode *PrologEncoder::GetUnwindCode(unsigned __int8 nodeCount)
  160. {
  161. Assert(nodeCount && ((currentUnwindCodeNodeIndex - nodeCount) >= 0));
  162. currentUnwindCodeNodeIndex -= nodeCount;
  163. return static_cast<UnwindCode *>(&pdata->unwindInfo.unwindCodes[currentUnwindCodeNodeIndex]);
  164. }
  165. DWORD PrologEncoder::SizeOfUnwindInfo()
  166. {
  167. return (sizeof(UNWIND_INFO) + (sizeof(UNWIND_CODE) * requiredUnwindCodeNodeCount));
  168. }
  169. BYTE *PrologEncoder::GetUnwindInfo()
  170. {
  171. return (BYTE *)&pdata->unwindInfo;
  172. }