TransformContext.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. #pragma once
  2. #include <unordered_set>
  3. #include <set>
  4. #include "TemporaryMemoryArena.h"
  5. #include "../metadata/Image.h"
  6. #include "../interpreter/Instruction.h"
  7. #include "../interpreter/Engine.h"
  8. #include "../metadata/MetadataUtil.h"
  9. #include "../metadata/Opcodes.h"
  10. #include "../metadata/MetadataModule.h"
  11. #include "../interpreter/Instruction.h"
  12. #include "../interpreter/Interpreter.h"
  13. #include "../interpreter/InterpreterModule.h"
  14. #include "Transform.h"
  15. namespace hybridclr
  16. {
  17. namespace transform
  18. {
  19. using namespace hybridclr::metadata;
  20. using namespace hybridclr::interpreter;
  21. struct IRBasicBlock
  22. {
  23. bool visited;
  24. bool inPending;
  25. uint32_t ilOffset;
  26. uint32_t codeOffset;
  27. std::vector<interpreter::IRCommon*> insts;
  28. };
  29. struct ArgVarInfo
  30. {
  31. const Il2CppType* type;
  32. Il2CppClass* klass;
  33. int32_t argOffset; // StackObject index
  34. int32_t argLocOffset;
  35. };
  36. struct LocVarInfo
  37. {
  38. const Il2CppType* type;
  39. Il2CppClass* klass;
  40. int32_t locOffset;
  41. };
  42. enum class EvalStackReduceDataType
  43. {
  44. I4,
  45. I8,
  46. R4,
  47. R8,
  48. Other,
  49. };
  50. struct EvalStackVarInfo
  51. {
  52. EvalStackReduceDataType reduceType;
  53. int32_t byteSize;
  54. int32_t locOffset;
  55. };
  56. #if HYBRIDCLR_ARCH_64
  57. #define NATIVE_INT_OP opI8
  58. constexpr EvalStackReduceDataType NATIVE_INT_REDUCE_TYPE = EvalStackReduceDataType::I8;
  59. #else
  60. #define NATIVE_INT_OP opI4
  61. constexpr EvalStackReduceDataType NATIVE_INT_REDUCE_TYPE = EvalStackReduceDataType::I4;
  62. #endif
  63. #define CreateIR(varName, typeName) IR##typeName* varName = pool.AllocIR<IR##typeName>(); varName->type = HiOpcodeEnum::typeName;
  64. #define CreateAddIR(varName, typeName) IR##typeName* varName = pool.AllocIR<IR##typeName>(); varName->type = HiOpcodeEnum::typeName; curbb->insts.push_back(varName); if (ir2offsetMap) { ir2offsetMap->add(varName, ipOffset); }
  65. enum class LocationDescType
  66. {
  67. I1,
  68. U1,
  69. I2,
  70. U2,
  71. I4,
  72. I8,
  73. Ref,
  74. S,
  75. StructContainsRef,
  76. };
  77. #if HYBRIDCLR_ARCH_64
  78. #define NATIVE_INT_DESC_TYPE LocationDescType::I8
  79. #define ARCH_ARGUMENT(x32, x64) x64
  80. #else
  81. #define NATIVE_INT_DESC_TYPE LocationDescType::I4
  82. #define ARCH_ARGUMENT(x32, x64) x32
  83. #endif
  84. struct LocationDescInfo
  85. {
  86. LocationDescType type;
  87. int32_t size;
  88. };
  89. struct FlowInfo
  90. {
  91. uint32_t curStackSize;
  92. uint32_t offset;
  93. il2cpp::utils::dynamic_array<EvalStackVarInfo> evalStack;
  94. };
  95. typedef Il2CppHashMap<IRCommon*, uint32_t, il2cpp::utils::PointerHash<IRCommon>> IR2OffsetMap;
  96. LocationDescInfo ComputLocationDescInfo(const Il2CppType* type);
  97. class TransformContext
  98. {
  99. private:
  100. metadata::Image* image;
  101. const MethodInfo* methodInfo;
  102. metadata::MethodBody& body;
  103. TemporaryMemoryArena& pool;
  104. const Il2CppGenericContext* genericContext;
  105. const Il2CppGenericContainer* klassContainer;
  106. const Il2CppGenericContainer* methodContainer;
  107. int32_t actualParamCount;
  108. std::set<uint32_t> splitOffsets;
  109. IRBasicBlock** ip2bb;
  110. IRBasicBlock* curbb;
  111. ArgVarInfo* args;
  112. LocVarInfo* locals;
  113. EvalStackVarInfo* evalStack;
  114. int32_t evalStackTop;
  115. int32_t evalStackBaseOffset;
  116. il2cpp::utils::dynamic_array<uint64_t>& resolveDatas;
  117. Il2CppHashMap<uint32_t, uint32_t, il2cpp::utils::PassThroughHash<uint32_t>> token2DataIdxs;
  118. Il2CppHashMap<const void*, uint32_t, il2cpp::utils::PassThroughHash<const void*>> ptr2DataIdxs;
  119. std::vector<int32_t*> relocationOffsets;
  120. std::vector<std::pair<int32_t, int32_t>> switchOffsetsInResolveData;
  121. std::vector<FlowInfo*> pendingFlows;
  122. int32_t nextFlowIdx;
  123. int32_t maxStackSize;
  124. int32_t curStackSize;
  125. const byte* ipBase;
  126. const byte* ip;
  127. uint32_t ipOffset;
  128. IR2OffsetMap* ir2offsetMap;
  129. int32_t prefixFlags;
  130. const MethodInfo* shareMethod;
  131. std::vector<IRBasicBlock*> irbbs;
  132. il2cpp::utils::dynamic_array<InterpExceptionClause> exClauses;
  133. uint32_t totalIRSize;
  134. int32_t totalArgSize;
  135. int32_t totalArgLocalSize;
  136. bool initLocals;
  137. public:
  138. TransformContext(hybridclr::metadata::Image* image, const MethodInfo* methodInfo, metadata::MethodBody& body, TemporaryMemoryArena& pool, il2cpp::utils::dynamic_array<uint64_t>& resolveDatas);
  139. static void InitializeInstinctHandlers();
  140. uint32_t GetOrAddResolveDataIndex(const void* ptr);
  141. TemporaryMemoryArena& GetPool() const
  142. {
  143. return pool;
  144. }
  145. int32_t GetEvalStackTop() const
  146. {
  147. return evalStackTop;
  148. }
  149. IRBasicBlock* GetCurbb() const
  150. {
  151. return curbb;
  152. }
  153. uint32_t GetIpOffset() const
  154. {
  155. return ipOffset;
  156. }
  157. IR2OffsetMap* GetIr2offsetMap() const
  158. {
  159. return ir2offsetMap;
  160. }
  161. int32_t GetArgOffset(int32_t idx) const
  162. {
  163. return args[idx].argOffset;
  164. }
  165. int32_t GetArgLocOffset(int32_t idx) const
  166. {
  167. return args[idx].argLocOffset;
  168. }
  169. int32_t GetLocOffset(int32_t idx) const
  170. {
  171. return locals[idx].locOffset;
  172. }
  173. int32_t GetEvalStackOffset(int32_t idx) const
  174. {
  175. return idx < evalStackTop ? evalStack[idx].locOffset : curStackSize;
  176. }
  177. int32_t GetEvalStackTopOffset() const
  178. {
  179. return evalStackTop > 0 ? evalStack[evalStackTop - 1].locOffset : curStackSize;
  180. }
  181. int32_t GetEvalStackNewTopOffset() const
  182. {
  183. return curStackSize;
  184. }
  185. int32_t GetEvalStackOffset_5() const
  186. {
  187. return evalStack[evalStackTop - 5].locOffset;
  188. }
  189. int32_t GetEvalStackOffset_4() const
  190. {
  191. return evalStack[evalStackTop - 4].locOffset;
  192. }
  193. int32_t GetEvalStackOffset_3() const
  194. {
  195. return evalStack[evalStackTop - 3].locOffset;
  196. }
  197. int32_t GetEvalStackOffset_2() const
  198. {
  199. return evalStack[evalStackTop - 2].locOffset;
  200. }
  201. int32_t GetEvalStackOffset_1() const
  202. {
  203. return evalStack[evalStackTop - 1].locOffset;
  204. }
  205. void PushStackByType(const Il2CppType* type);
  206. void PushStackByReduceType(EvalStackReduceDataType t);
  207. void DuplicateStack();
  208. void PopStack();
  209. void PopStackN(int32_t n);
  210. void PopAllStack();
  211. void InsertMemoryBarrier();
  212. void ResetPrefixFlags();
  213. void Add_ldind(HiOpcodeEnum opCode, EvalStackReduceDataType dataType);
  214. void Add_stind(HiOpcodeEnum opCode);
  215. void PushOffset(int32_t* offsetPtr);
  216. void PushBranch(int32_t targetOffset);
  217. bool FindNextFlow();
  218. void AddInst(IRCommon* ir);
  219. void AddInst_ldarg(int32_t argIdx);
  220. bool IsCreateNotNullObjectInstrument(IRCommon* ir);
  221. IRCommon* GetLastInstrument()
  222. {
  223. return curbb->insts.empty() ? nullptr : curbb->insts.back();
  224. }
  225. void RemoveLastInstrument();
  226. void AddInst_ldarga(int32_t argIdx);
  227. void AddInst_starg(int32_t argIdx);
  228. void CreateAddInst_ldloc(int32_t locIdx);
  229. void CreateAddInst_stloc(int32_t locIdx);
  230. void CreateAddInst_ldloca(int32_t locIdx);
  231. void CreateAddInst_ldc4(int32_t c, EvalStackReduceDataType rtype);
  232. void CreateAddInst_ldc8(int64_t c, EvalStackReduceDataType rtype);
  233. void Add_brtruefalse(bool c, int32_t targetOffset);
  234. void Add_bc(int32_t ipOffset, int32_t brOffset, int32_t opSize, HiOpcodeEnum opI4, HiOpcodeEnum opI8, HiOpcodeEnum opR4, HiOpcodeEnum opR8);
  235. void Add_conv(int32_t dstTypeSize, EvalStackReduceDataType dstReduceType, HiOpcodeEnum opI4, HiOpcodeEnum opI8, HiOpcodeEnum opR4, HiOpcodeEnum opR8);
  236. void Add_conv_ovf(int32_t dstTypeSize, EvalStackReduceDataType dstReduceType, HiOpcodeEnum opI4, HiOpcodeEnum opI8, HiOpcodeEnum opR4, HiOpcodeEnum opR8);
  237. void Add_binop(HiOpcodeEnum opI4, HiOpcodeEnum opI8, HiOpcodeEnum opR4, HiOpcodeEnum opR8);
  238. void Add_shiftop(HiOpcodeEnum opI4I4, HiOpcodeEnum opI4I8, HiOpcodeEnum opI8I4, HiOpcodeEnum opI8I8);
  239. void Add_compare(HiOpcodeEnum opI4, HiOpcodeEnum opI8, HiOpcodeEnum opR4, HiOpcodeEnum opR8);
  240. void Add_ldelem(EvalStackReduceDataType resultType, HiOpcodeEnum opI4);
  241. void Add_stelem(HiOpcodeEnum opI4);
  242. bool FindFirstLeaveHandlerIndex(const std::vector<ExceptionClause>& exceptionClauses, uint32_t leaveOffset, uint32_t targetOffset, uint16_t& index);
  243. bool IsLeaveInTryBlock(const std::vector<ExceptionClause>& exceptionClauses, uint32_t leaveOffset);
  244. void Add_leave(uint32_t targetOffset);
  245. uint16_t FindFirstThrowHandlerIndex(const std::vector<ExceptionClause>& exceptionClauses, uint32_t throwOffset);
  246. bool TryAddInstinctInstruments(const MethodInfo* method)
  247. {
  248. return TryAddInstinctInstrumentsByName(method) || TryAddArrayInstinctInstruments(method);
  249. }
  250. bool TryAddInstinctInstrumentsByName(const MethodInfo* method);
  251. bool TryAddArrayInstinctInstruments(const MethodInfo* method);
  252. bool TryAddInstinctCtorInstruments(const MethodInfo* method);
  253. bool TryAddCallCommonInstruments(const MethodInfo* method, uint32_t methodDataIndex)
  254. {
  255. bool resolvedIsInstanceMethod = IsInstanceMethod(method);
  256. bool add = resolvedIsInstanceMethod ? TryAddCallCommonInstanceInstruments(method, methodDataIndex)
  257. : TryAddCallCommonStaticInstruments(method, methodDataIndex);
  258. if (add)
  259. {
  260. int32_t resolvedTotalArgNum = method->parameters_count + resolvedIsInstanceMethod;
  261. PopStackN(resolvedTotalArgNum);
  262. if (method->return_type->type != IL2CPP_TYPE_VOID)
  263. {
  264. PushStackByType(method->return_type);
  265. }
  266. return true;
  267. }
  268. return false;
  269. }
  270. bool TryAddCallCommonInstanceInstruments(const MethodInfo* method, uint32_t methodDataIndex);
  271. bool TryAddCallCommonStaticInstruments(const MethodInfo* method, uint32_t methodDataIndex);
  272. HiOpcodeEnum CalcGetMdArrElementVarVarOpcode(const Il2CppType* type);
  273. void TransformBody(int32_t depth, int32_t localVarOffset, interpreter::InterpMethodInfo& result);
  274. private:
  275. void TransformBodyImpl(int32_t depth, int32_t localVarOffset);
  276. void BuildInterpMethodInfo(interpreter::InterpMethodInfo& result);
  277. static bool TransformSubMethodBody(TransformContext& callingCtx, const MethodInfo* subMethod, int32_t depth, int32_t localVarOffset);
  278. };
  279. }
  280. }