Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        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);
        }