JITCompiler.cs 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using ILRuntime.Mono.Cecil;
  6. using ILRuntime.Mono.Cecil.Cil;
  7. using ILRuntime.CLR.TypeSystem;
  8. using ILRuntime.CLR.Method;
  9. using ILRuntime.Runtime.Intepreter.OpCodes;
  10. namespace ILRuntime.Runtime.Intepreter.RegisterVM
  11. {
  12. struct JITCompiler
  13. {
  14. public const int CallRegisterParamCount = 3;
  15. Enviorment.AppDomain appdomain;
  16. ILType declaringType;
  17. ILMethod method;
  18. MethodDefinition def;
  19. bool hasReturn;
  20. Dictionary<Instruction, int> entryMapping;
  21. Dictionary<int, int[]> jumptables;
  22. public JITCompiler(Enviorment.AppDomain appDomain, ILType declaringType, ILMethod method)
  23. {
  24. this.appdomain = appDomain;
  25. this.declaringType = declaringType;
  26. this.method = method;
  27. def = method.Definition;
  28. hasReturn = method.ReturnType != appdomain.VoidType;
  29. entryMapping = null;
  30. jumptables = null;
  31. }
  32. bool CheckNeedInitObj(CodeBasicBlock block, short reg, bool hasReturn, HashSet<CodeBasicBlock> visited)
  33. {
  34. if (visited.Contains(block))
  35. return false;
  36. visited.Add(block);
  37. for (int i = 0; i < block.FinalInstructions.Count; i++)
  38. {
  39. var ins = block.FinalInstructions[i];
  40. short r1, r2, r3, rw;
  41. Optimizer.GetOpcodeDestRegister(ref ins, out rw);
  42. if (Optimizer.GetOpcodeSourceRegister(ref ins, hasReturn, out r1, out r2, out r3))
  43. {
  44. if (r1 == reg || r2 == reg || r3 == reg)
  45. {
  46. if (ins.Code == OpCodeREnum.Ldloca || ins.Code == OpCodeREnum.Ldloca_S)
  47. {
  48. if (i < block.FinalInstructions.Count - 1)
  49. {
  50. var next = block.FinalInstructions[i + 1];
  51. if (next.Code == OpCodeREnum.Initobj && next.Register1 == rw)
  52. return false;
  53. }
  54. return true;
  55. }
  56. else
  57. return rw != reg;
  58. }
  59. }
  60. if (rw == reg)
  61. return false;
  62. }
  63. if (block.NextBlocks != null && block.NextBlocks.Count > 0)
  64. {
  65. foreach (var i in block.NextBlocks)
  66. {
  67. if (CheckNeedInitObj(i, reg, hasReturn, visited))
  68. return true;
  69. }
  70. }
  71. return false;
  72. }
  73. bool IsCatchHandler(CodeBasicBlock block, MethodBody body)
  74. {
  75. if (body.HasExceptionHandlers)
  76. {
  77. var firstIns = block.Instructions[0];
  78. foreach(var eh in body.ExceptionHandlers)
  79. {
  80. if(eh.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Catch)
  81. {
  82. if (eh.HandlerStart == firstIns)
  83. return true;
  84. }
  85. }
  86. return false;
  87. }
  88. else
  89. return false;
  90. }
  91. public OpCodeR[] Compile(out int stackRegisterCnt, out Dictionary<int, int[]> switchTargets, Dictionary<Instruction, int> addr, out Dictionary<int, RegisterVMSymbol> symbols)
  92. {
  93. #if DEBUG && !NO_PROFILER
  94. if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID)
  95. #if UNITY_5_5_OR_NEWER
  96. UnityEngine.Profiling.Profiler.BeginSample("JITCompiler.Compile");
  97. #else
  98. UnityEngine.Profiler.BeginSample("JITCompiler.Compile");
  99. #endif
  100. #endif
  101. method.Compiling = true;
  102. symbols = new Dictionary<int, RegisterVMSymbol>();
  103. var body = def.Body;
  104. short locVarRegStart = (short)def.Parameters.Count;
  105. if (!def.IsStatic)
  106. locVarRegStart++;
  107. short baseRegIdx = (short)(locVarRegStart + body.Variables.Count);
  108. short baseRegStart = baseRegIdx;
  109. var blocks = CodeBasicBlock.BuildBasicBlocks(body, out entryMapping);
  110. foreach (var i in blocks)
  111. {
  112. baseRegIdx = baseRegStart;
  113. if (IsCatchHandler(i, body))
  114. baseRegIdx++;
  115. else
  116. {
  117. if (i.PreviousBlocks.Count > 0)
  118. {
  119. foreach (var j in i.PreviousBlocks)
  120. {
  121. if (j.EndRegister >= 0)
  122. {
  123. baseRegIdx = j.EndRegister;
  124. break;
  125. }
  126. }
  127. }
  128. }
  129. foreach (var ins in i.Instructions)
  130. {
  131. Translate(i, ins, locVarRegStart, ref baseRegIdx);
  132. }
  133. i.EndRegister = baseRegIdx;
  134. }
  135. //Append init local
  136. var first = blocks[0];
  137. int idx = 0;
  138. int appendIdx = 0;
  139. HashSet<CodeBasicBlock> visitedBlocks = body.Variables.Count > 0 ? new HashSet<CodeBasicBlock>() : null;
  140. for (short r = locVarRegStart; r < locVarRegStart + body.Variables.Count; r++)
  141. {
  142. visitedBlocks.Clear();
  143. foreach (var b in blocks)
  144. {
  145. if (b.PreviousBlocks.Count == 0)
  146. {
  147. if (CheckNeedInitObj(b, r, method.ReturnType != method.AppDomain.VoidType, visitedBlocks))
  148. {
  149. OpCodeR code = new OpCodeR();
  150. code.Code = OpCodeREnum.Initobj;
  151. code.Register1 = r;
  152. code.Operand = method.GetTypeTokenHashCode(body.Variables[idx].VariableType);
  153. code.Operand2 = 1;
  154. first.FinalInstructions.Insert(appendIdx++, code);
  155. break;
  156. }
  157. }
  158. }
  159. idx++;
  160. }
  161. for (idx = first.FinalInstructions.Count - 1; idx >= 0; idx--)
  162. {
  163. if (idx >= appendIdx)
  164. {
  165. RegisterVMSymbol symbol;
  166. if (first.InstructionMapping.TryGetValue(idx - appendIdx, out symbol))
  167. {
  168. first.InstructionMapping[idx] = first.InstructionMapping[idx - appendIdx];
  169. }
  170. }
  171. else
  172. first.InstructionMapping.Remove(idx);
  173. }
  174. #if OUTPUT_JIT_RESULT
  175. int cnt = 1;
  176. Console.WriteLine($"JIT Results for {method}:");
  177. foreach (var b in blocks)
  178. {
  179. Console.WriteLine($"Block {cnt++}, Instructions:{b.FinalInstructions.Count}");
  180. for (int i = 0; i < b.FinalInstructions.Count; i++)
  181. {
  182. Console.WriteLine($" {i}:{b.FinalInstructions[i].ToString(appdomain)}");
  183. }
  184. }
  185. #endif
  186. Optimizer.ForwardCopyPropagation(blocks, hasReturn, baseRegStart);
  187. Optimizer.BackwardsCopyPropagation(blocks, hasReturn, baseRegStart);
  188. Optimizer.ForwardCopyPropagation(blocks, hasReturn, baseRegStart);
  189. Optimizer.EliminateConstantLoad(blocks, hasReturn);
  190. #if OUTPUT_JIT_RESULT
  191. cnt = 1;
  192. Console.WriteLine($"Optimizer Results for {method}:");
  193. foreach (var b in blocks)
  194. {
  195. Console.WriteLine($"Block {cnt++}, Instructions:{b.FinalInstructions.Count}");
  196. for (int i = 0; i < b.FinalInstructions.Count; i++)
  197. {
  198. string canRemove = b.CanRemove.Contains(i) ? "(x)" : "";
  199. Console.WriteLine($" {i}:{canRemove}{b.FinalInstructions[i].ToString(appdomain)}");
  200. }
  201. }
  202. #endif
  203. List<OpCodeR> res = new List<OpCodeR>();
  204. Dictionary<int, int> jumpTargets = new Dictionary<int, int>();
  205. int bIdx = 0;
  206. HashSet<int> inlinedBranches = new HashSet<int>();
  207. int curIndex = 0;
  208. foreach (var b in blocks)
  209. {
  210. jumpTargets[bIdx++] = res.Count;
  211. bool isInline = false;
  212. int inlineOffset = 0;
  213. bool inlineAddressSet = false;
  214. for (idx = 0; idx < b.FinalInstructions.Count; idx++)
  215. {
  216. RegisterVMSymbol oriIns;
  217. bool hasOri = b.InstructionMapping.TryGetValue(idx, out oriIns);
  218. if (hasOri)
  219. {
  220. if (isInline)
  221. {
  222. if (!inlineAddressSet)
  223. {
  224. while (oriIns.ParentSymbol != null)
  225. oriIns = oriIns.ParentSymbol.Value;
  226. addr[oriIns.Instruction] = curIndex;
  227. inlineAddressSet = true;
  228. }
  229. }
  230. else
  231. addr[oriIns.Instruction] = curIndex;
  232. }
  233. if (b.CanRemove.Contains(idx))
  234. {
  235. if (isInline)
  236. inlineOffset--;
  237. continue;
  238. }
  239. var ins = b.FinalInstructions[idx];
  240. if (ins.Code == OpCodeREnum.InlineStart)
  241. {
  242. inlineAddressSet = false;
  243. isInline = true;
  244. inlineOffset = res.Count;
  245. }
  246. else if (ins.Code == OpCodeREnum.InlineEnd)
  247. {
  248. isInline = false;
  249. }
  250. else
  251. {
  252. if (isInline)
  253. {
  254. if (Optimizer.IsBranching(ins.Code))
  255. {
  256. ins.Operand += inlineOffset;
  257. inlinedBranches.Add(res.Count);
  258. }
  259. else if (Optimizer.IsIntermediateBranching(ins.Code))
  260. {
  261. ins.Operand4 += inlineOffset;
  262. inlinedBranches.Add(res.Count);
  263. }
  264. else if (ins.Code == OpCodeREnum.Switch)
  265. {
  266. int[] targets = jumptables[ins.Operand];
  267. for (int j = 0; j < targets.Length; j++)
  268. {
  269. targets[j] = targets[j] + inlineOffset;
  270. }
  271. inlinedBranches.Add(res.Count);
  272. }
  273. }
  274. if (hasOri)
  275. symbols.Add(res.Count, oriIns);
  276. curIndex++;
  277. res.Add(ins);
  278. }
  279. }
  280. }
  281. for (int i = 0; i < res.Count; i++)
  282. {
  283. var op = res[i];
  284. if (Optimizer.IsBranching(op.Code) && !inlinedBranches.Contains(i))
  285. {
  286. op.Operand = jumpTargets[op.Operand];
  287. res[i] = op;
  288. }
  289. else if (Optimizer.IsIntermediateBranching(op.Code) && !inlinedBranches.Contains(i))
  290. {
  291. op.Operand4 = jumpTargets[op.Operand4];
  292. res[i] = op;
  293. }
  294. else if (op.Code == OpCodeREnum.Switch && !inlinedBranches.Contains(i))
  295. {
  296. int[] targets = jumptables[op.Operand];
  297. for (int j = 0; j < targets.Length; j++)
  298. {
  299. targets[j] = jumpTargets[targets[j]];
  300. }
  301. }
  302. else if(op.Code == OpCodeREnum.Leave || op.Code == OpCodeREnum.Leave_S)
  303. {
  304. var oriIns = symbols[i];
  305. op.Operand = addr[(Instruction)oriIns.Instruction.Operand];
  306. res[i] = op;
  307. }
  308. }
  309. #if DEBUG && !DISABLE_ILRUNTIME_DEBUG
  310. //FixSymbol(symbols);
  311. #else
  312. symbols = null;
  313. #endif
  314. switchTargets = jumptables;
  315. var totalRegCnt = Optimizer.CleanupRegister(res, locVarRegStart, hasReturn);
  316. stackRegisterCnt = totalRegCnt - baseRegStart;
  317. #if OUTPUT_JIT_RESULT
  318. Console.WriteLine($"Final Results for {method}:");
  319. for (int i = 0; i < res.Count; i++)
  320. {
  321. Console.WriteLine($" {i}:{res[i].ToString(appdomain)}");
  322. }
  323. #endif
  324. method.Compiling = false;
  325. var arr = res.ToArray();
  326. #if DEBUG && !NO_PROFILER
  327. if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID)
  328. #if UNITY_5_5_OR_NEWER
  329. UnityEngine.Profiling.Profiler.EndSample();
  330. #else
  331. UnityEngine.Profiler.EndSample();
  332. #endif
  333. #endif
  334. return arr;
  335. }
  336. void PrepareJumpTable(object token)
  337. {
  338. int hashCode = token.GetHashCode();
  339. if (jumptables == null)
  340. jumptables = new Dictionary<int, int[]>();
  341. if (jumptables.ContainsKey(hashCode))
  342. return;
  343. Mono.Cecil.Cil.Instruction[] e = token as Mono.Cecil.Cil.Instruction[];
  344. int[] addrs = new int[e.Length];
  345. for (int i = 0; i < e.Length; i++)
  346. {
  347. addrs[i] = entryMapping[e[i]];
  348. }
  349. jumptables[hashCode] = addrs;
  350. }
  351. public static void FixSymbol(Dictionary<int, RegisterVMSymbol> symbol)
  352. {
  353. HashSet<Instruction> includedIns = new HashSet<Instruction>();
  354. foreach(var i in symbol.ToArray())
  355. {
  356. RegisterVMSymbol cur = i.Value;
  357. RegisterVMSymbolLink link = null;
  358. while (cur.ParentSymbol != null)
  359. {
  360. link = cur.ParentSymbol;
  361. cur = cur.ParentSymbol.Value;
  362. }
  363. var sm = cur.Method.Definition.DebugInformation.GetSequencePointMapping();
  364. var sq = FindSequencePoint(cur.Instruction, sm);
  365. if(sq != null && !includedIns.Contains(sq))
  366. {
  367. includedIns.Add(sq);
  368. cur.Instruction = sq;
  369. if (link != null)
  370. link.Value = cur;
  371. else
  372. {
  373. symbol[i.Key] = cur;
  374. }
  375. }
  376. }
  377. }
  378. static Instruction FindSequencePoint(Instruction ins, IDictionary<Instruction, SequencePoint> seqMapping)
  379. {
  380. Mono.Cecil.Cil.Instruction cur = ins;
  381. Mono.Cecil.Cil.SequencePoint sp;
  382. while (!seqMapping.TryGetValue(cur, out sp) && cur.Previous != null)
  383. cur = cur.Previous;
  384. return cur;
  385. }
  386. void Translate(CodeBasicBlock block, Instruction ins, short locVarRegStart, ref short baseRegIdx)
  387. {
  388. List<OpCodeR> lst = block.FinalInstructions;
  389. OpCodeR op = new OpCodeR();
  390. var code = ins.OpCode;
  391. var token = ins.Operand;
  392. op.Code = (OpCodeREnum)code.Code;
  393. bool hasRet;
  394. switch (code.Code)
  395. {
  396. case Code.Br_S:
  397. case Code.Br:
  398. op.Operand = entryMapping[(Mono.Cecil.Cil.Instruction)token];
  399. break;
  400. case Code.Brtrue:
  401. case Code.Brtrue_S:
  402. case Code.Brfalse:
  403. case Code.Brfalse_S:
  404. op.Register1 = --baseRegIdx;
  405. op.Operand = entryMapping[(Mono.Cecil.Cil.Instruction)token];
  406. break;
  407. case Code.Switch:
  408. op.Register1 = --baseRegIdx;
  409. PrepareJumpTable(token);
  410. op.Operand = token.GetHashCode();
  411. break;
  412. case Code.Blt:
  413. case Code.Blt_S:
  414. case Code.Blt_Un:
  415. case Code.Blt_Un_S:
  416. case Code.Ble:
  417. case Code.Ble_S:
  418. case Code.Ble_Un:
  419. case Code.Ble_Un_S:
  420. case Code.Bgt:
  421. case Code.Bgt_S:
  422. case Code.Bgt_Un:
  423. case Code.Bgt_Un_S:
  424. case Code.Bge:
  425. case Code.Bge_S:
  426. case Code.Bge_Un:
  427. case Code.Bge_Un_S:
  428. case Code.Beq:
  429. case Code.Beq_S:
  430. case Code.Bne_Un:
  431. case Code.Bne_Un_S:
  432. op.Register1 = (short)(baseRegIdx - 2);
  433. op.Register2 = (short)(baseRegIdx - 1);
  434. baseRegIdx -= 2;
  435. op.Operand = entryMapping[(Mono.Cecil.Cil.Instruction)token];
  436. break;
  437. case Code.Ldc_I4_0:
  438. case Code.Ldc_I4_1:
  439. case Code.Ldc_I4_2:
  440. case Code.Ldc_I4_3:
  441. case Code.Ldc_I4_4:
  442. case Code.Ldc_I4_5:
  443. case Code.Ldc_I4_6:
  444. case Code.Ldc_I4_7:
  445. case Code.Ldc_I4_8:
  446. case Code.Ldc_I4_M1:
  447. case Code.Ldnull:
  448. op.Register1 = baseRegIdx++;
  449. break;
  450. case Code.Ldc_I4:
  451. op.Register1 = baseRegIdx++;
  452. op.Operand = (int)token;
  453. break;
  454. case Code.Ldc_I4_S:
  455. op.Register1 = baseRegIdx++;
  456. op.Operand = (sbyte)token;
  457. break;
  458. case Code.Ldc_I8:
  459. op.Register1 = baseRegIdx++;
  460. op.OperandLong = (long)token;
  461. break;
  462. case Code.Ldc_R4:
  463. op.Register1 = baseRegIdx++;
  464. op.OperandFloat = (float)token;
  465. break;
  466. case Code.Ldc_R8:
  467. op.Register1 = baseRegIdx++;
  468. op.OperandDouble = (double)token;
  469. break;
  470. case Code.Ldstr:
  471. op.Register1 = baseRegIdx++;
  472. op.OperandLong = appdomain.CacheString(token);
  473. break;
  474. case Code.Newobj:
  475. {
  476. bool canInline, isILMethod;
  477. ILMethod toInline;
  478. IMethod m;
  479. var pCnt = InitializeFunctionParam(ref op, token, out hasRet, out canInline, out m, out toInline, out isILMethod);
  480. int pushCnt = Math.Max(pCnt - CallRegisterParamCount, 0);
  481. for (int i = pCnt; i > pCnt - pushCnt; i--)
  482. {
  483. OpCodes.OpCodeR op2 = new OpCodes.OpCodeR();
  484. op2.Code = OpCodes.OpCodeREnum.Push;
  485. op2.Register1 = (short)(baseRegIdx - i);
  486. lst.Add(op2);
  487. }
  488. if (pushCnt < pCnt)
  489. {
  490. switch (pCnt - pushCnt)
  491. {
  492. case 1:
  493. op.Register2 = (short)(baseRegIdx - 1);
  494. break;
  495. case 2:
  496. op.Register3 = (short)(baseRegIdx - 1);
  497. op.Register2 = (short)(baseRegIdx - 2);
  498. break;
  499. case 3:
  500. op.Register4 = (short)(baseRegIdx - 1);
  501. op.Register3 = (short)(baseRegIdx - 2);
  502. op.Register2 = (short)(baseRegIdx - 3);
  503. break;
  504. }
  505. }
  506. baseRegIdx -= (short)pCnt;
  507. op.Register1 = baseRegIdx++;
  508. }
  509. break;
  510. case Code.Call:
  511. case Code.Callvirt:
  512. {
  513. bool canInline, isILMethod;
  514. ILMethod toInline;
  515. IMethod m;
  516. var pCnt = InitializeFunctionParam(ref op, token, out hasRet, out canInline, out m, out toInline, out isILMethod);
  517. bool hasConstrained = false;
  518. int constrainIdx = -1;
  519. if (lst.Count > 0)
  520. {
  521. constrainIdx = lst.Count - 1;
  522. hasConstrained = lst[constrainIdx].Code == OpCodeREnum.Constrained;
  523. }
  524. bool needInline = canInline && !hasConstrained;
  525. if (needInline)
  526. {
  527. if (toInline.BodyRegister.Length > Optimizer.MaximalInlineInstructionCount / 2)
  528. needInline = false;
  529. }
  530. if (!needInline)
  531. {
  532. if (code.Code == Code.Callvirt && m is ILMethod)
  533. {
  534. ILMethod ilm = (ILMethod)m;
  535. if (!ilm.Definition.IsAbstract && !ilm.Definition.IsVirtual && !ilm.DeclearingType.IsInterface)
  536. op.Code = OpCodeREnum.Call;
  537. }
  538. int pushCnt = hasConstrained ? pCnt : Math.Max(pCnt - CallRegisterParamCount, 0);
  539. for (int i = pCnt; i > pCnt - pushCnt; i--)
  540. {
  541. OpCodes.OpCodeR op2 = new OpCodes.OpCodeR();
  542. op2.Code = OpCodes.OpCodeREnum.Push;
  543. op2.Operand = isILMethod ? 1 : 0;
  544. op2.Register1 = (short)(baseRegIdx - i);
  545. lst.Add(op2);
  546. }
  547. if (pushCnt < pCnt)
  548. {
  549. switch(pCnt - pushCnt)
  550. {
  551. case 1:
  552. op.Register2 = (short)(baseRegIdx - 1);
  553. break;
  554. case 2:
  555. op.Register3 = (short)(baseRegIdx - 1);
  556. op.Register2 = (short)(baseRegIdx - 2);
  557. break;
  558. case 3:
  559. op.Register4 = (short)(baseRegIdx - 1);
  560. op.Register3 = (short)(baseRegIdx - 2);
  561. op.Register2 = (short)(baseRegIdx - 3);
  562. break;
  563. }
  564. }
  565. if (hasConstrained)
  566. {
  567. op.Operand4 = 1;
  568. var old = lst[constrainIdx];
  569. lst.RemoveAt(constrainIdx);
  570. old.Operand2 = op.Operand2;
  571. var symbol = block.InstructionMapping[constrainIdx];
  572. block.InstructionMapping.Remove(constrainIdx);
  573. block.InstructionMapping.Add(lst.Count, symbol);
  574. lst.Add(old);
  575. }
  576. baseRegIdx -= (short)pCnt;
  577. if (hasRet)
  578. op.Register1 = baseRegIdx++;
  579. else
  580. op.Register1 = -1;
  581. }
  582. else
  583. {
  584. baseRegIdx -= (short)pCnt;
  585. RegisterVMSymbolLink link = null;
  586. #if DEBUG && !DISABLE_ILRUNTIME_DEBUG
  587. link = new RegisterVMSymbolLink();
  588. link.BaseRegisterIndex = baseRegIdx;
  589. link.Value.Instruction = ins;
  590. link.Value.Method = method;
  591. #else
  592. RegisterVMSymbol vmS = new RegisterVMSymbol()
  593. {
  594. Instruction = ins,
  595. Method = method
  596. };
  597. block.InstructionMapping.Add(lst.Count,vmS);
  598. #endif
  599. #if DEBUG && !NO_PROFILER
  600. if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID)
  601. #if UNITY_5_5_OR_NEWER
  602. UnityEngine.Profiling.Profiler.BeginSample("JITCompiler.InlineMethod");
  603. #else
  604. UnityEngine.Profiler.BeginSample("JITCompiler.InlineMethod");
  605. #endif
  606. #endif
  607. Optimizer.InlineMethod(block, toInline, link, ref jumptables, baseRegIdx, hasRet);
  608. #if DEBUG && !NO_PROFILER
  609. if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID)
  610. #if UNITY_5_5_OR_NEWER
  611. UnityEngine.Profiling.Profiler.EndSample();
  612. #else
  613. UnityEngine.Profiler.EndSample();
  614. #endif
  615. #endif
  616. if (hasRet)
  617. baseRegIdx++;
  618. return;
  619. }
  620. }
  621. break;
  622. case Code.Ldsfld:
  623. case Code.Ldsflda:
  624. op.Register1 = baseRegIdx++;
  625. op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method);
  626. break;
  627. case Code.Stsfld:
  628. op.Register1 = --baseRegIdx;
  629. op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method);
  630. break;
  631. case Code.Initobj:
  632. op.Register1 = --baseRegIdx;
  633. op.Operand = method.GetTypeTokenHashCode(token);
  634. break;
  635. case Code.Ret:
  636. if (hasReturn)
  637. op.Register1 = --baseRegIdx;
  638. break;
  639. case Code.Throw:
  640. op.Register1 = --baseRegIdx;
  641. break;
  642. case Code.Add:
  643. case Code.Add_Ovf:
  644. case Code.Add_Ovf_Un:
  645. case Code.Sub:
  646. case Code.Sub_Ovf:
  647. case Code.Sub_Ovf_Un:
  648. case Code.Mul:
  649. case Code.Mul_Ovf:
  650. case Code.Mul_Ovf_Un:
  651. case Code.Div:
  652. case Code.Div_Un:
  653. case Code.Rem:
  654. case Code.Rem_Un:
  655. case Code.Shr:
  656. case Code.Shr_Un:
  657. case Code.Shl:
  658. case Code.Xor:
  659. case Code.Or:
  660. case Code.And:
  661. case Code.Clt:
  662. case Code.Clt_Un:
  663. case Code.Cgt:
  664. case Code.Cgt_Un:
  665. case Code.Ceq:
  666. case Code.Ldelema:
  667. case Code.Ldelem_I1:
  668. case Code.Ldelem_U1:
  669. case Code.Ldelem_I2:
  670. case Code.Ldelem_U2:
  671. case Code.Ldelem_I4:
  672. case Code.Ldelem_U4:
  673. case Code.Ldelem_I8:
  674. case Code.Ldelem_R4:
  675. case Code.Ldelem_R8:
  676. case Code.Ldelem_Any:
  677. case Code.Ldelem_Ref:
  678. op.Register1 = (short)(baseRegIdx - 2); //explicit use dest register for optimization
  679. op.Register2 = (short)(baseRegIdx - 2);
  680. op.Register3 = (short)(baseRegIdx - 1);
  681. baseRegIdx--;
  682. break;
  683. case Code.Nop:
  684. case Code.Castclass:
  685. case Code.Readonly:
  686. case Code.Volatile:
  687. case Code.Endfinally:
  688. case Code.Rethrow:
  689. break;
  690. case Code.Leave:
  691. case Code.Leave_S:
  692. break;
  693. case Code.Stloc_0:
  694. op.Code = OpCodes.OpCodeREnum.Move;
  695. op.Register1 = locVarRegStart;
  696. op.Register2 = --baseRegIdx;
  697. break;
  698. case Code.Stloc_1:
  699. op.Code = OpCodes.OpCodeREnum.Move;
  700. op.Register1 = (short)(locVarRegStart + 1);
  701. op.Register2 = --baseRegIdx;
  702. break;
  703. case Code.Stloc_2:
  704. op.Code = OpCodes.OpCodeREnum.Move;
  705. op.Register1 = (short)(locVarRegStart + 2);
  706. op.Register2 = --baseRegIdx;
  707. break;
  708. case Code.Stloc_3:
  709. op.Code = OpCodes.OpCodeREnum.Move;
  710. op.Register1 = (short)(locVarRegStart + 3);
  711. op.Register2 = --baseRegIdx;
  712. break;
  713. case Code.Stloc_S:
  714. op.Code = OpCodes.OpCodeREnum.Move;
  715. op.Register1 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index);
  716. op.Register2 = --baseRegIdx;
  717. break;
  718. case Code.Ldloc_0:
  719. op.Code = OpCodes.OpCodeREnum.Move;
  720. op.Register1 = baseRegIdx++;
  721. op.Register2 = locVarRegStart;
  722. break;
  723. case Code.Ldloc_1:
  724. op.Code = OpCodes.OpCodeREnum.Move;
  725. op.Register1 = baseRegIdx++;
  726. op.Register2 = (short)(locVarRegStart + 1);
  727. break;
  728. case Code.Ldloc_2:
  729. op.Code = OpCodes.OpCodeREnum.Move;
  730. op.Register1 = baseRegIdx++;
  731. op.Register2 = (short)(locVarRegStart + 2);
  732. break;
  733. case Code.Ldloc_3:
  734. op.Code = OpCodes.OpCodeREnum.Move;
  735. op.Register1 = baseRegIdx++;
  736. op.Register2 = (short)(locVarRegStart + 3);
  737. break;
  738. case Code.Ldloc:
  739. case Code.Ldloc_S:
  740. op.Code = OpCodes.OpCodeREnum.Move;
  741. op.Register1 = baseRegIdx++;
  742. op.Register2 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index);
  743. break;
  744. case Code.Ldloca:
  745. case Code.Ldloca_S:
  746. op.Register1 = baseRegIdx++;
  747. op.Register2 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index);
  748. break;
  749. case Code.Ldarg_0:
  750. case Code.Ldarg_1:
  751. case Code.Ldarg_2:
  752. case Code.Ldarg_3:
  753. op.Code = OpCodes.OpCodeREnum.Move;
  754. op.Register1 = baseRegIdx++;
  755. op.Register2 = (short)(code.Code - (Code.Ldarg_0));
  756. break;
  757. case Code.Ldarg_S:
  758. op.Code = OpCodes.OpCodeREnum.Move;
  759. op.Register1 = baseRegIdx++;
  760. op.Register2 = (short)((ParameterDefinition)ins.Operand).Index;
  761. if (def.HasThis)
  762. {
  763. op.Register2++;
  764. }
  765. break;
  766. case Code.Ldarga:
  767. case Code.Ldarga_S:
  768. op.Register1 = baseRegIdx++;
  769. op.Register2 = (short)((ParameterDefinition)ins.Operand).Index;
  770. if (def.HasThis)
  771. {
  772. op.Register2++;
  773. }
  774. break;
  775. case Code.Starg:
  776. case Code.Starg_S:
  777. op.Code = OpCodes.OpCodeREnum.Move;
  778. op.Register2 = --baseRegIdx;
  779. op.Register1 = (short)((ParameterDefinition)ins.Operand).Index;
  780. if (def.HasThis)
  781. {
  782. op.Register1++;
  783. }
  784. break;
  785. case Code.Newarr:
  786. op.Register1 = (short)(baseRegIdx - 1);
  787. op.Register2 = (short)(baseRegIdx - 1);
  788. op.Operand = method.GetTypeTokenHashCode(token);
  789. break;
  790. case Code.Dup:
  791. op.Code = OpCodes.OpCodeREnum.Move;
  792. op.Register2 = (short)(baseRegIdx - 1);
  793. op.Register1 = baseRegIdx++;
  794. break;
  795. case Code.Stelem_I:
  796. case Code.Stelem_I1:
  797. case Code.Stelem_I2:
  798. case Code.Stelem_I4:
  799. case Code.Stelem_I8:
  800. case Code.Stelem_R4:
  801. case Code.Stelem_R8:
  802. case Code.Stelem_Ref:
  803. case Code.Stelem_Any:
  804. op.Register1 = (short)(baseRegIdx - 3);
  805. op.Register2 = (short)(baseRegIdx - 2);
  806. op.Register3 = (short)(baseRegIdx - 1);
  807. baseRegIdx -= 3;
  808. break;
  809. case Code.Stind_I:
  810. case Code.Stind_I1:
  811. case Code.Stind_I2:
  812. case Code.Stind_I4:
  813. case Code.Stind_I8:
  814. case Code.Stind_R4:
  815. case Code.Stind_R8:
  816. case Code.Stind_Ref:
  817. op.Register1 = (short)(baseRegIdx - 2);
  818. op.Register2 = (short)(baseRegIdx - 1);
  819. baseRegIdx -= 2;
  820. break;
  821. case Code.Stobj:
  822. op.Register1 = (short)(baseRegIdx - 2);
  823. op.Register2 = (short)(baseRegIdx - 1);
  824. op.Operand = method.GetTypeTokenHashCode(token);
  825. baseRegIdx -= 2;
  826. break;
  827. case Code.Conv_I:
  828. case Code.Conv_I1:
  829. case Code.Conv_I2:
  830. case Code.Conv_I4:
  831. case Code.Conv_I8:
  832. case Code.Conv_Ovf_I:
  833. case Code.Conv_Ovf_I1:
  834. case Code.Conv_Ovf_I1_Un:
  835. case Code.Conv_Ovf_I2:
  836. case Code.Conv_Ovf_I2_Un:
  837. case Code.Conv_Ovf_I4:
  838. case Code.Conv_Ovf_I4_Un:
  839. case Code.Conv_Ovf_I8:
  840. case Code.Conv_Ovf_I8_Un:
  841. case Code.Conv_Ovf_I_Un:
  842. case Code.Conv_Ovf_U:
  843. case Code.Conv_Ovf_U1:
  844. case Code.Conv_Ovf_U1_Un:
  845. case Code.Conv_Ovf_U2:
  846. case Code.Conv_Ovf_U2_Un:
  847. case Code.Conv_Ovf_U4:
  848. case Code.Conv_Ovf_U4_Un:
  849. case Code.Conv_Ovf_U8:
  850. case Code.Conv_Ovf_U8_Un:
  851. case Code.Conv_Ovf_U_Un:
  852. case Code.Conv_R4:
  853. case Code.Conv_R8:
  854. case Code.Conv_R_Un:
  855. case Code.Conv_U:
  856. case Code.Conv_U1:
  857. case Code.Conv_U2:
  858. case Code.Conv_U4:
  859. case Code.Conv_U8:
  860. case Code.Ldlen:
  861. case Code.Ldind_I:
  862. case Code.Ldind_I2:
  863. case Code.Ldind_I4:
  864. case Code.Ldind_I8:
  865. case Code.Ldind_R4:
  866. case Code.Ldind_R8:
  867. case Code.Ldind_U1:
  868. case Code.Ldind_U2:
  869. case Code.Ldind_U4:
  870. case Code.Ldind_Ref:
  871. case Code.Neg:
  872. case Code.Not:
  873. op.Register1 = (short)(baseRegIdx - 1);
  874. op.Register2 = (short)(baseRegIdx - 1);
  875. break;
  876. case Code.Ldobj:
  877. op.Register1 = (short)(baseRegIdx - 1);
  878. op.Register2 = (short)(baseRegIdx - 1);
  879. op.Operand = method.GetTypeTokenHashCode(token);
  880. break;
  881. case Code.Ldfld:
  882. case Code.Ldflda:
  883. op.Register1 = (short)(baseRegIdx - 1);
  884. op.Register2 = (short)(baseRegIdx - 1);
  885. op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method);
  886. break;
  887. case Code.Stfld:
  888. op.Register1 = (short)(baseRegIdx - 2);
  889. op.Register2 = (short)(baseRegIdx - 1);
  890. op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method);
  891. baseRegIdx -= 2;
  892. break;
  893. case Code.Box:
  894. case Code.Unbox:
  895. case Code.Unbox_Any:
  896. case Code.Isinst:
  897. op.Register1 = (short)(baseRegIdx - 1);
  898. op.Register2 = (short)(baseRegIdx - 1);
  899. op.Operand = method.GetTypeTokenHashCode(token);
  900. break;
  901. case Code.Constrained:
  902. op.Operand = method.GetTypeTokenHashCode(token);
  903. break;
  904. case Code.Ldtoken:
  905. op.Register1 = baseRegIdx++;
  906. if (token is FieldReference)
  907. {
  908. op.Operand = 0;
  909. op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method);
  910. }
  911. else if (token is TypeReference)
  912. {
  913. op.Operand = 1;
  914. op.OperandLong = method.GetTypeTokenHashCode(token);
  915. }
  916. else
  917. throw new NotImplementedException();
  918. break;
  919. case Code.Ldftn:
  920. {
  921. op.Register1 = baseRegIdx++;
  922. bool hasReturn, canInline, isILMethod;
  923. ILMethod toInline;
  924. IMethod m;
  925. InitializeFunctionParam(ref op, token, out hasReturn, out canInline, out m, out toInline, out isILMethod);
  926. }
  927. break;
  928. case Code.Ldvirtftn:
  929. {
  930. bool hasReturn, canInline, isILMethod;
  931. ILMethod toInline;
  932. IMethod m;
  933. InitializeFunctionParam(ref op, token, out hasReturn, out canInline, out m, out toInline, out isILMethod);
  934. op.Register1 = (short)(baseRegIdx - 1);
  935. op.Register2 = (short)(baseRegIdx - 1);
  936. }
  937. break;
  938. case Code.Pop:
  939. baseRegIdx--;
  940. op.Code = OpCodeREnum.Nop;
  941. break;
  942. default:
  943. throw new NotImplementedException(string.Format("Unknown Opcode:{0}", code.Code));
  944. }
  945. RegisterVMSymbol s = new RegisterVMSymbol()
  946. {
  947. Instruction = ins,
  948. Method = method
  949. };
  950. block.InstructionMapping.Add(lst.Count, s);
  951. lst.Add(op);
  952. if (!block.NeedLoadConstantElimination)
  953. block.NeedLoadConstantElimination = Optimizer.IsLoadConstant(op.Code);
  954. }
  955. int InitializeFunctionParam(ref OpCodes.OpCodeR op, object token, out bool hasReturn, out bool canInline, out IMethod m, out ILMethod toInline, out bool isILMethod)
  956. {
  957. bool invalidToken;
  958. int pCnt = 0;
  959. m = appdomain.GetMethod(token, declaringType, method, out invalidToken);
  960. toInline = null;
  961. canInline = false;
  962. op.Register2 = -1;
  963. op.Register3 = -1;
  964. op.Register4 = -1;
  965. if (m != null)
  966. {
  967. if (invalidToken)
  968. op.Operand2 = m.GetHashCode();
  969. else
  970. op.Operand2 = token.GetHashCode();
  971. pCnt = m.ParameterCount;
  972. if (!m.IsStatic && op.Code != OpCodeREnum.Newobj)
  973. pCnt++;
  974. hasReturn = m.ReturnType != appdomain.VoidType;
  975. if (m is ILMethod)
  976. {
  977. isILMethod = !m.IsDelegateInvoke;
  978. var ilm = (ILMethod)m;
  979. bool noJIT = (ilm.JITFlags & ILRuntimeJITFlags.NoJIT) != ILRuntimeJITFlags.None;
  980. bool forceInline = (ilm.JITFlags & ILRuntimeJITFlags.ForceInline) != ILRuntimeJITFlags.None;
  981. bool hasExceptionHandler = ilm.Definition.HasBody && ilm.Definition.Body.HasExceptionHandlers;
  982. if (!ilm.IsDelegateInvoke && !ilm.IsVirtual && !noJIT && !hasExceptionHandler && !ilm.Compiling)
  983. {
  984. var def = ilm.Definition;
  985. if (!def.HasBody || forceInline)
  986. {
  987. canInline = true;
  988. toInline = ilm;
  989. }
  990. else
  991. {
  992. bool codeSizeOK = ilm.IsRegisterBodyReady ? ilm.BodyRegister.Length <= Optimizer.MaximalInlineInstructionCount / 2 : def.Body.Instructions.Count <= Optimizer.MaximalInlineInstructionCount;
  993. if(codeSizeOK)
  994. {
  995. canInline = true;
  996. toInline = ilm;
  997. }
  998. }
  999. }
  1000. }
  1001. else
  1002. isILMethod = false;
  1003. }
  1004. else
  1005. {
  1006. isILMethod = false;
  1007. //Cannot find method or the method is dummy
  1008. MethodReference _ref = (MethodReference)token;
  1009. pCnt = _ref.HasParameters ? _ref.Parameters.Count : 0;
  1010. if (_ref.HasThis && op.Code != OpCodeREnum.Newobj)
  1011. pCnt++;
  1012. op.Operand3 = pCnt;
  1013. hasReturn = false;
  1014. }
  1015. return pCnt;
  1016. }
  1017. }
  1018. }