internal IMethod GetMethod(object token, ILType contextType, ILMethod contextMethod, out bool invalidToken) { string methodname = null; string typename = null; List <IType> paramList = null; int hashCode = token.GetHashCode(); IMethod method; IType[] genericArguments = null; IType returnType; invalidToken = false; bool isConstructor = false; if (mapMethod.TryGetValue(hashCode, out method)) { return(method); } IType type = null; if (token is Mono.Cecil.MethodReference) { Mono.Cecil.MethodReference _ref = (token as Mono.Cecil.MethodReference); if (_ref.FullName == "System.Void System.Object::.ctor()") { mapMethod[hashCode] = null; return(null); } if (_ref.FullName == "System.Void System.Attribute::.ctor()") { mapMethod[hashCode] = null; return(null); } methodname = _ref.Name; var typeDef = _ref.DeclaringType; type = GetType(typeDef, contextType, contextMethod); if (type == null) { throw new KeyNotFoundException("Cannot find type:" + typename); } if (token is Mono.Cecil.MethodDefinition) { var def = _ref as MethodDefinition; isConstructor = def.IsConstructor; } else { isConstructor = methodname == ".ctor"; } if (_ref.IsGenericInstance) { GenericInstanceMethod gim = (GenericInstanceMethod)_ref; genericArguments = new IType[gim.GenericArguments.Count]; for (int i = 0; i < genericArguments.Length; i++) { if (gim.GenericArguments[i].IsGenericParameter) { invalidToken = true; } var gt = GetType(gim.GenericArguments[i], contextType, contextMethod); if (gt == null) { gt = contextMethod.FindGenericArgument(gim.GenericArguments[i].Name); if (gt == null)//This means it contains unresolved generic arguments, which means it's not searching the generic instance { genericArguments = null; break; } else { genericArguments[i] = gt; } } else { genericArguments[i] = gt; } } } paramList = _ref.GetParamList(this, contextType, contextMethod, genericArguments); returnType = GetType(_ref.ReturnType, contextType, null); } else { throw new NotImplementedException(); //Mono.Cecil.GenericInstanceMethod gmethod = _def as Mono.Cecil.GenericInstanceMethod; //genlist = new MethodParamList(environment, gmethod); } if (isConstructor) { method = type.GetConstructor(paramList); } else { method = type.GetMethod(methodname, paramList, genericArguments, returnType); if (method != null && method.IsGenericInstance) { mapMethod[method.GetHashCode()] = method; } } if (method == null) { if (isConstructor && contextType.FirstCLRBaseType != null && contextType.FirstCLRBaseType is CrossBindingAdaptor && type.TypeForCLR == ((CrossBindingAdaptor)contextType.FirstCLRBaseType).BaseCLRType) { method = contextType.BaseType.GetConstructor(paramList); if (method == null) { throw new KeyNotFoundException("Cannot find method:" + methodname); } invalidToken = true; mapMethod[method.GetHashCode()] = method; } else { throw new KeyNotFoundException("Cannot find method:" + methodname); } } if (!invalidToken) { mapMethod[hashCode] = method; } return(method); }
public OpCodeR[] Compile(out int stackRegisterCnt, out Dictionary <int, int[]> switchTargets, Dictionary <Instruction, int> addr, out Dictionary <int, RegisterVMSymbol> symbols) { #if DEBUG && !NO_PROFILER if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID) #if UNITY_5_5_OR_NEWER { UnityEngine.Profiling.Profiler.BeginSample("JITCompiler.Compile"); } #else { UnityEngine.Profiler.BeginSample("JITCompiler.Compile"); } #endif #endif method.Compiling = true; symbols = new Dictionary <int, RegisterVMSymbol>(); var body = def.Body; short locVarRegStart = (short)def.Parameters.Count; if (!def.IsStatic) { locVarRegStart++; } short baseRegIdx = (short)(locVarRegStart + body.Variables.Count); short baseRegStart = baseRegIdx; var blocks = CodeBasicBlock.BuildBasicBlocks(body, out entryMapping); foreach (var i in blocks) { baseRegIdx = baseRegStart; if (IsCatchHandler(i, body)) { baseRegIdx++; } else { if (i.PreviousBlocks.Count > 0) { foreach (var j in i.PreviousBlocks) { if (j.EndRegister >= 0) { baseRegIdx = j.EndRegister; break; } } } } foreach (var ins in i.Instructions) { Translate(i, ins, locVarRegStart, ref baseRegIdx); } i.EndRegister = baseRegIdx; } //Append init local var first = blocks[0]; int idx = 0; int appendIdx = 0; HashSet <CodeBasicBlock> visitedBlocks = body.Variables.Count > 0 ? new HashSet <CodeBasicBlock>() : null; for (short r = locVarRegStart; r < locVarRegStart + body.Variables.Count; r++) { visitedBlocks.Clear(); foreach (var b in blocks) { if (b.PreviousBlocks.Count == 0) { var lt = def.Body.Variables[r - locVarRegStart]; bool needInitOjb = false; if (lt.VariableType.IsGenericParameter) { var gt = method.FindGenericArgument(lt.VariableType.Name); needInitOjb = gt.IsValueType && !gt.IsPrimitive; } else { needInitOjb = lt.VariableType.IsValueType && !lt.VariableType.IsPrimitive; } if (needInitOjb || CheckNeedInitObj(b, r, method.ReturnType != method.AppDomain.VoidType, visitedBlocks)) { OpCodeR code = new OpCodeR(); code.Code = OpCodeREnum.Initobj; code.Register1 = r; code.Operand = method.GetTypeTokenHashCode(body.Variables[idx].VariableType); code.Operand2 = 1; first.FinalInstructions.Insert(appendIdx++, code); break; } } } idx++; } for (idx = first.FinalInstructions.Count - 1; idx >= 0; idx--) { if (idx >= appendIdx) { RegisterVMSymbol symbol; if (first.InstructionMapping.TryGetValue(idx - appendIdx, out symbol)) { first.InstructionMapping[idx] = first.InstructionMapping[idx - appendIdx]; } } else { first.InstructionMapping.Remove(idx); } } #if OUTPUT_JIT_RESULT int cnt = 1; Console.WriteLine($"JIT Results for {method}:"); foreach (var b in blocks) { Console.WriteLine($"Block {cnt++}, Instructions:{b.FinalInstructions.Count}"); for (int i = 0; i < b.FinalInstructions.Count; i++) { Console.WriteLine($" {i}:{b.FinalInstructions[i].ToString(appdomain)}"); } } #endif Optimizer.ForwardCopyPropagation(blocks, hasReturn, baseRegStart); Optimizer.BackwardsCopyPropagation(blocks, hasReturn, baseRegStart); Optimizer.ForwardCopyPropagation(blocks, hasReturn, baseRegStart); Optimizer.EliminateConstantLoad(blocks, hasReturn); #if OUTPUT_JIT_RESULT cnt = 1; Console.WriteLine($"Optimizer Results for {method}:"); foreach (var b in blocks) { Console.WriteLine($"Block {cnt++}, Instructions:{b.FinalInstructions.Count}"); for (int i = 0; i < b.FinalInstructions.Count; i++) { string canRemove = b.CanRemove.Contains(i) ? "(x)" : ""; Console.WriteLine($" {i}:{canRemove}{b.FinalInstructions[i].ToString(appdomain)}"); } } #endif List <OpCodeR> res = new List <OpCodeR>(); Dictionary <int, int> jumpTargets = new Dictionary <int, int>(); int bIdx = 0; HashSet <int> inlinedBranches = new HashSet <int>(); int curIndex = 0; foreach (var b in blocks) { jumpTargets[bIdx++] = res.Count; bool isInline = false; int inlineOffset = 0; bool inlineAddressSet = false; for (idx = 0; idx < b.FinalInstructions.Count; idx++) { RegisterVMSymbol oriIns; bool hasOri = b.InstructionMapping.TryGetValue(idx, out oriIns); if (hasOri) { if (isInline) { if (!inlineAddressSet) { while (oriIns.ParentSymbol != null) { oriIns = oriIns.ParentSymbol.Value; } addr[oriIns.Instruction] = curIndex; inlineAddressSet = true; } } else { addr[oriIns.Instruction] = curIndex; } } if (b.CanRemove.Contains(idx)) { if (isInline) { inlineOffset--; } continue; } var ins = b.FinalInstructions[idx]; if (ins.Code == OpCodeREnum.InlineStart) { inlineAddressSet = false; isInline = true; inlineOffset = res.Count; } else if (ins.Code == OpCodeREnum.InlineEnd) { isInline = false; } else { if (isInline) { if (Optimizer.IsBranching(ins.Code)) { ins.Operand += inlineOffset; inlinedBranches.Add(res.Count); } else if (Optimizer.IsIntermediateBranching(ins.Code)) { ins.Operand4 += inlineOffset; inlinedBranches.Add(res.Count); } else if (ins.Code == OpCodeREnum.Switch) { int[] targets = jumptables[ins.Operand]; for (int j = 0; j < targets.Length; j++) { targets[j] = targets[j] + inlineOffset; } inlinedBranches.Add(res.Count); } } if (hasOri) { symbols.Add(res.Count, oriIns); } curIndex++; res.Add(ins); } } } for (int i = 0; i < res.Count; i++) { var op = res[i]; if (Optimizer.IsBranching(op.Code) && !inlinedBranches.Contains(i)) { op.Operand = jumpTargets[op.Operand]; res[i] = op; } else if (Optimizer.IsIntermediateBranching(op.Code) && !inlinedBranches.Contains(i)) { op.Operand4 = jumpTargets[op.Operand4]; res[i] = op; } else if (op.Code == OpCodeREnum.Switch && !inlinedBranches.Contains(i)) { int[] targets = jumptables[op.Operand]; for (int j = 0; j < targets.Length; j++) { targets[j] = jumpTargets[targets[j]]; } } else if (op.Code == OpCodeREnum.Leave || op.Code == OpCodeREnum.Leave_S) { var oriIns = symbols[i]; op.Operand = addr[(Instruction)oriIns.Instruction.Operand]; res[i] = op; } } #if DEBUG && !DISABLE_ILRUNTIME_DEBUG //FixSymbol(symbols); #else symbols = null; #endif switchTargets = jumptables; var totalRegCnt = Optimizer.CleanupRegister(res, locVarRegStart, hasReturn); stackRegisterCnt = totalRegCnt - baseRegStart; #if OUTPUT_JIT_RESULT Console.WriteLine($"Final Results for {method}:"); for (int i = 0; i < res.Count; i++) { Console.WriteLine($" {i}:{res[i].ToString(appdomain)}"); } #endif method.Compiling = false; var arr = res.ToArray(); #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 return(arr); }