public static void FixSymbol(Dictionary <int, RegisterVMSymbol> symbol) { HashSet <Instruction> includedIns = new HashSet <Instruction>(); foreach (var i in symbol.ToArray()) { RegisterVMSymbol cur = i.Value; RegisterVMSymbolLink link = null; while (cur.ParentSymbol != null) { link = cur.ParentSymbol; cur = cur.ParentSymbol.Value; } var sm = cur.Method.Definition.DebugInformation.GetSequencePointMapping(); var sq = FindSequencePoint(cur.Instruction, sm); if (sq != null && !includedIns.Contains(sq)) { includedIns.Add(sq); cur.Instruction = sq; if (link != null) { link.Value = cur; } else { symbol[i.Key] = cur; } } } }
public static void InlineMethod(CodeBasicBlock block, ILMethod method, RegisterVMSymbolLink symbolLink, ref Dictionary <int, int[]> jumpTables, short baseRegIdx, bool hasReturn) { var ins = block.FinalInstructions; var body = method.BodyRegister; OpCodeR start = new OpCodeR(); start.Code = OpCodeREnum.InlineStart; ins.Add(start); int branchStart = ins.Count; int branchOffset = 0; List <int> reloc = new List <int>(); if (body != null) { for (int i = 0; i < body.Length; i++) { var opcode = body[i]; short r1 = 0; short r2 = 0; short r3 = 0; if (GetOpcodeSourceRegister(ref opcode, hasReturn, out r1, out r2, out r3)) { if (r1 >= 0) { ReplaceOpcodeSource(ref opcode, 0, (short)(r1 + baseRegIdx)); } if (r2 >= 0) { ReplaceOpcodeSource(ref opcode, 1, (short)(r2 + baseRegIdx)); } if (r3 >= 0) { ReplaceOpcodeSource(ref opcode, 2, (short)(r3 + baseRegIdx)); } } if (GetOpcodeDestRegister(ref opcode, out r1)) { if (r1 >= 0) { ReplaceOpcodeDest(ref opcode, (short)(r1 + baseRegIdx)); } } if (opcode.Code == OpCodeREnum.Ret) { bool needMove = hasReturn && opcode.Register1 != baseRegIdx; if (needMove) { opcode.Code = OpCodeREnum.Move; opcode.Register2 = opcode.Register1; opcode.Register1 = baseRegIdx; ins.Add(opcode); branchOffset++; } if (i < body.Length - 1) { if (needMove) { for (int j = branchStart; j < ins.Count; j++) { var op2 = ins[j]; if (IsBranching(op2.Code)) { if (op2.Operand > i) { op2.Operand++; ins[j] = op2; } } else if (IsIntermediateBranching(op2.Code)) { if (op2.Operand4 > i) { op2.Operand4++; ins[j] = op2; } } else if (op2.Code == OpCodeREnum.Switch) { var targets = jumpTables[op2.Operand]; for (int k = 0; k < targets.Length; k++) { if (targets[k] > i) { targets[k]++; } } } } } reloc.Add(ins.Count); opcode.Code = OpCodeREnum.Br; ins.Add(opcode); } continue; } if (IsBranching(opcode.Code)) { opcode.Operand += branchOffset; } if (opcode.Code == OpCodeREnum.Switch) { int[] targets = method.JumpTablesRegister[opcode.Operand]; int[] newTargets = new int[targets.Length]; for (int j = 0; j < targets.Length; j++) { newTargets[j] = targets[j] + branchOffset; } if (jumpTables == null) { jumpTables = new Dictionary <int, int[]>(); } opcode.Operand = newTargets.GetHashCode(); jumpTables.Add(opcode.Operand, newTargets); } #if DEBUG && !DISABLE_ILRUNTIME_DEBUG RegisterVMSymbol oriIns; if (method.RegisterVMSymbols.TryGetValue(i, out oriIns)) { oriIns.ParentSymbol = symbolLink; block.InstructionMapping.Add(ins.Count, oriIns); } #endif ins.Add(opcode); } } foreach (var i in reloc) { var opcode = ins[i]; opcode.Operand = ins.Count - branchStart; ins[i] = opcode; } start.Code = OpCodeREnum.InlineEnd; ins.Add(start); }
void Translate(CodeBasicBlock block, Instruction ins, short locVarRegStart, ref short baseRegIdx) { List <OpCodeR> lst = block.FinalInstructions; OpCodeR op = new OpCodeR(); var code = ins.OpCode; var token = ins.Operand; op.Code = (OpCodeREnum)code.Code; bool hasRet; switch (code.Code) { case Code.Br_S: case Code.Br: op.Operand = entryMapping[(Mono.Cecil.Cil.Instruction)token]; break; case Code.Brtrue: case Code.Brtrue_S: case Code.Brfalse: case Code.Brfalse_S: op.Register1 = --baseRegIdx; op.Operand = entryMapping[(Mono.Cecil.Cil.Instruction)token]; break; case Code.Switch: op.Register1 = --baseRegIdx; PrepareJumpTable(token); op.Operand = token.GetHashCode(); break; case Code.Blt: case Code.Blt_S: case Code.Blt_Un: case Code.Blt_Un_S: case Code.Ble: case Code.Ble_S: case Code.Ble_Un: case Code.Ble_Un_S: case Code.Bgt: case Code.Bgt_S: case Code.Bgt_Un: case Code.Bgt_Un_S: case Code.Bge: case Code.Bge_S: case Code.Bge_Un: case Code.Bge_Un_S: case Code.Beq: case Code.Beq_S: case Code.Bne_Un: case Code.Bne_Un_S: op.Register1 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 1); baseRegIdx -= 2; op.Operand = entryMapping[(Mono.Cecil.Cil.Instruction)token]; break; case Code.Ldc_I4_0: case Code.Ldc_I4_1: case Code.Ldc_I4_2: case Code.Ldc_I4_3: case Code.Ldc_I4_4: case Code.Ldc_I4_5: case Code.Ldc_I4_6: case Code.Ldc_I4_7: case Code.Ldc_I4_8: case Code.Ldc_I4_M1: case Code.Ldnull: op.Register1 = baseRegIdx++; break; case Code.Ldc_I4: op.Register1 = baseRegIdx++; op.Operand = (int)token; break; case Code.Ldc_I4_S: op.Register1 = baseRegIdx++; op.Operand = (sbyte)token; break; case Code.Ldc_I8: op.Register1 = baseRegIdx++; op.OperandLong = (long)token; break; case Code.Ldc_R4: op.Register1 = baseRegIdx++; op.OperandFloat = (float)token; break; case Code.Ldc_R8: op.Register1 = baseRegIdx++; op.OperandDouble = (double)token; break; case Code.Ldstr: op.Register1 = baseRegIdx++; op.OperandLong = appdomain.CacheString(token); break; case Code.Newobj: { bool canInline, isILMethod; ILMethod toInline; IMethod m; var pCnt = InitializeFunctionParam(ref op, token, out hasRet, out canInline, out m, out toInline, out isILMethod); int pushCnt = Math.Max(pCnt - CallRegisterParamCount, 0); for (int i = pCnt; i > pCnt - pushCnt; i--) { OpCodes.OpCodeR op2 = new OpCodes.OpCodeR(); op2.Code = OpCodes.OpCodeREnum.Push; op2.Register1 = (short)(baseRegIdx - i); lst.Add(op2); } if (pushCnt < pCnt) { switch (pCnt - pushCnt) { case 1: op.Register2 = (short)(baseRegIdx - 1); break; case 2: op.Register3 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 2); break; case 3: op.Register4 = (short)(baseRegIdx - 1); op.Register3 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 3); break; } } baseRegIdx -= (short)pCnt; op.Register1 = baseRegIdx++; } break; case Code.Call: case Code.Callvirt: { bool canInline, isILMethod; ILMethod toInline; IMethod m; var pCnt = InitializeFunctionParam(ref op, token, out hasRet, out canInline, out m, out toInline, out isILMethod); bool hasConstrained = false; int constrainIdx = -1; if (lst.Count > 0) { constrainIdx = lst.Count - 1; hasConstrained = lst[constrainIdx].Code == OpCodeREnum.Constrained; } bool needInline = canInline && !hasConstrained; if (needInline) { if (toInline.BodyRegister.Length > Optimizer.MaximalInlineInstructionCount / 2) { needInline = false; } } if (!needInline) { if (code.Code == Code.Callvirt && m is ILMethod) { ILMethod ilm = (ILMethod)m; if (!ilm.Definition.IsAbstract && !ilm.Definition.IsVirtual && !ilm.DeclearingType.IsInterface) { op.Code = OpCodeREnum.Call; } } int pushCnt = hasConstrained ? pCnt : Math.Max(pCnt - CallRegisterParamCount, 0); for (int i = pCnt; i > pCnt - pushCnt; i--) { OpCodes.OpCodeR op2 = new OpCodes.OpCodeR(); op2.Code = OpCodes.OpCodeREnum.Push; op2.Operand = isILMethod ? 1 : 0; op2.Register1 = (short)(baseRegIdx - i); lst.Add(op2); } if (pushCnt < pCnt) { switch (pCnt - pushCnt) { case 1: op.Register2 = (short)(baseRegIdx - 1); break; case 2: op.Register3 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 2); break; case 3: op.Register4 = (short)(baseRegIdx - 1); op.Register3 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 3); break; } } if (hasConstrained) { op.Operand4 = 1; var old = lst[constrainIdx]; lst.RemoveAt(constrainIdx); old.Operand2 = op.Operand2; var symbol = block.InstructionMapping[constrainIdx]; block.InstructionMapping.Remove(constrainIdx); block.InstructionMapping.Add(lst.Count, symbol); lst.Add(old); } baseRegIdx -= (short)pCnt; if (hasRet) { op.Register1 = baseRegIdx++; } else { op.Register1 = -1; } } else { baseRegIdx -= (short)pCnt; RegisterVMSymbolLink link = null; #if DEBUG && !DISABLE_ILRUNTIME_DEBUG link = new RegisterVMSymbolLink(); link.BaseRegisterIndex = baseRegIdx; link.Value.Instruction = ins; link.Value.Method = method; #endif #if DEBUG && !NO_PROFILER if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID) #if UNITY_5_5_OR_NEWER { UnityEngine.Profiling.Profiler.BeginSample("JITCompiler.InlineMethod"); } #else { UnityEngine.Profiler.BeginSample("JITCompiler.InlineMethod"); } #endif #endif Optimizer.InlineMethod(block, toInline, link, ref jumptables, baseRegIdx, hasRet); #if DEBUG && !NO_PROFILER if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID) #if UNITY_5_5_OR_NEWER { UnityEngine.Profiling.Profiler.EndSample(); } #else { UnityEngine.Profiler.EndSample(); } #endif #endif if (hasRet) { baseRegIdx++; } return; } } break; case Code.Ldsfld: case Code.Ldsflda: op.Register1 = baseRegIdx++; op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method); break; case Code.Stsfld: op.Register1 = --baseRegIdx; op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method); break; case Code.Initobj: op.Register1 = --baseRegIdx; op.Operand = method.GetTypeTokenHashCode(token); break; case Code.Ret: if (hasReturn) { op.Register1 = --baseRegIdx; } break; case Code.Throw: op.Register1 = --baseRegIdx; break; case Code.Add: case Code.Add_Ovf: case Code.Add_Ovf_Un: case Code.Sub: case Code.Sub_Ovf: case Code.Sub_Ovf_Un: case Code.Mul: case Code.Mul_Ovf: case Code.Mul_Ovf_Un: case Code.Div: case Code.Div_Un: case Code.Rem: case Code.Rem_Un: case Code.Shr: case Code.Shr_Un: case Code.Shl: case Code.Xor: case Code.Or: case Code.And: case Code.Clt: case Code.Clt_Un: case Code.Cgt: case Code.Cgt_Un: case Code.Ceq: case Code.Ldelema: case Code.Ldelem_I1: case Code.Ldelem_U1: case Code.Ldelem_I2: case Code.Ldelem_U2: case Code.Ldelem_I4: case Code.Ldelem_U4: case Code.Ldelem_I8: case Code.Ldelem_R4: case Code.Ldelem_R8: case Code.Ldelem_Any: case Code.Ldelem_Ref: op.Register1 = (short)(baseRegIdx - 2); //explicit use dest register for optimization op.Register2 = (short)(baseRegIdx - 2); op.Register3 = (short)(baseRegIdx - 1); baseRegIdx--; break; case Code.Nop: case Code.Castclass: case Code.Readonly: case Code.Volatile: case Code.Endfinally: break; case Code.Leave: case Code.Leave_S: break; case Code.Stloc_0: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = locVarRegStart; op.Register2 = --baseRegIdx; break; case Code.Stloc_1: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = (short)(locVarRegStart + 1); op.Register2 = --baseRegIdx; break; case Code.Stloc_2: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = (short)(locVarRegStart + 2); op.Register2 = --baseRegIdx; break; case Code.Stloc_3: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = (short)(locVarRegStart + 3); op.Register2 = --baseRegIdx; break; case Code.Stloc_S: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index); op.Register2 = --baseRegIdx; break; case Code.Ldloc_0: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = locVarRegStart; break; case Code.Ldloc_1: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)(locVarRegStart + 1); break; case Code.Ldloc_2: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)(locVarRegStart + 2); break; case Code.Ldloc_3: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)(locVarRegStart + 3); break; case Code.Ldloc: case Code.Ldloc_S: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index); break; case Code.Ldloca: case Code.Ldloca_S: op.Register1 = baseRegIdx++; op.Register2 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index); break; case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)(code.Code - (Code.Ldarg_0)); break; case Code.Ldarg_S: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)((ParameterDefinition)ins.Operand).Index; if (def.HasThis) { op.Register2++; } break; case Code.Ldarga: case Code.Ldarga_S: op.Register1 = baseRegIdx++; op.Register2 = (short)((ParameterDefinition)ins.Operand).Index; if (def.HasThis) { op.Register2++; } break; case Code.Starg: case Code.Starg_S: op.Code = OpCodes.OpCodeREnum.Move; op.Register2 = --baseRegIdx; op.Register1 = (short)((ParameterDefinition)ins.Operand).Index; if (def.HasThis) { op.Register1++; } break; case Code.Newarr: op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); op.Operand = method.GetTypeTokenHashCode(token); break; case Code.Dup: op.Code = OpCodes.OpCodeREnum.Move; op.Register2 = (short)(baseRegIdx - 1); op.Register1 = baseRegIdx++; break; case Code.Stelem_I: case Code.Stelem_I1: case Code.Stelem_I2: case Code.Stelem_I4: case Code.Stelem_I8: case Code.Stelem_R4: case Code.Stelem_R8: case Code.Stelem_Ref: case Code.Stelem_Any: op.Register1 = (short)(baseRegIdx - 3); op.Register2 = (short)(baseRegIdx - 2); op.Register3 = (short)(baseRegIdx - 1); baseRegIdx -= 3; break; case Code.Stind_I: case Code.Stind_I1: case Code.Stind_I2: case Code.Stind_I4: case Code.Stind_I8: case Code.Stind_R4: case Code.Stind_R8: case Code.Stind_Ref: op.Register1 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 1); baseRegIdx -= 2; break; case Code.Stobj: op.Register1 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 1); op.Operand = method.GetTypeTokenHashCode(token); baseRegIdx -= 2; break; case Code.Conv_I: case Code.Conv_I1: case Code.Conv_I2: case Code.Conv_I4: case Code.Conv_I8: case Code.Conv_Ovf_I: case Code.Conv_Ovf_I1: case Code.Conv_Ovf_I1_Un: case Code.Conv_Ovf_I2: case Code.Conv_Ovf_I2_Un: case Code.Conv_Ovf_I4: case Code.Conv_Ovf_I4_Un: case Code.Conv_Ovf_I8: case Code.Conv_Ovf_I8_Un: case Code.Conv_Ovf_I_Un: case Code.Conv_Ovf_U: case Code.Conv_Ovf_U1: case Code.Conv_Ovf_U1_Un: case Code.Conv_Ovf_U2: case Code.Conv_Ovf_U2_Un: case Code.Conv_Ovf_U4: case Code.Conv_Ovf_U4_Un: case Code.Conv_Ovf_U8: case Code.Conv_Ovf_U8_Un: case Code.Conv_Ovf_U_Un: case Code.Conv_R4: case Code.Conv_R8: case Code.Conv_R_Un: case Code.Conv_U: case Code.Conv_U1: case Code.Conv_U2: case Code.Conv_U4: case Code.Conv_U8: case Code.Ldlen: case Code.Ldind_I: case Code.Ldind_I2: case Code.Ldind_I4: case Code.Ldind_I8: case Code.Ldind_R4: case Code.Ldind_R8: case Code.Ldind_U1: case Code.Ldind_U2: case Code.Ldind_U4: case Code.Ldind_Ref: case Code.Neg: case Code.Not: op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); break; case Code.Ldobj: op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); op.Operand = method.GetTypeTokenHashCode(token); break; case Code.Ldfld: case Code.Ldflda: op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method); break; case Code.Stfld: op.Register1 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 1); op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method); baseRegIdx -= 2; break; case Code.Box: case Code.Unbox: case Code.Unbox_Any: case Code.Isinst: op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); op.Operand = method.GetTypeTokenHashCode(token); break; case Code.Constrained: op.Operand = method.GetTypeTokenHashCode(token); break; case Code.Ldtoken: op.Register1 = baseRegIdx++; if (token is FieldReference) { op.Operand = 0; op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method); } else if (token is TypeReference) { op.Operand = 1; op.OperandLong = method.GetTypeTokenHashCode(token); } else { throw new NotImplementedException(); } break; case Code.Ldftn: { op.Register1 = baseRegIdx++; bool hasReturn, canInline, isILMethod; ILMethod toInline; IMethod m; InitializeFunctionParam(ref op, token, out hasReturn, out canInline, out m, out toInline, out isILMethod); } break; case Code.Ldvirtftn: { bool hasReturn, canInline, isILMethod; ILMethod toInline; IMethod m; InitializeFunctionParam(ref op, token, out hasReturn, out canInline, out m, out toInline, out isILMethod); op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); } break; case Code.Pop: baseRegIdx--; op.Code = OpCodeREnum.Nop; break; default: throw new NotImplementedException(string.Format("Unknown Opcode:{0}", code.Code)); } RegisterVMSymbol s = new RegisterVMSymbol() { Instruction = ins, Method = method }; block.InstructionMapping.Add(lst.Count, s); lst.Add(op); }