Пример #1
0
 private static string BuildMethodKeyName(MethodBase m)
 {
     return(LabelName.GenerateFullName(m));
 }
Пример #2
0
        protected void ScanMethod(MethodBase aMethod, bool aIsPlug, string sourceItem)
        {
            var xParams     = aMethod.GetParameters();
            var xParamTypes = new Type[xParams.Length];

            // Dont use foreach, enum generaly keeps order but
            // isn't guaranteed.
            //string xMethodFullName = LabelName.GenerateFullName(aMethod);

            for (int i = 0; i < xParams.Length; i++)
            {
                xParamTypes[i] = xParams[i].ParameterType;
                Queue(xParamTypes[i], aMethod, "Parameter");
            }
            var xIsDynamicMethod = aMethod.DeclaringType == null;

            // Queue Types directly related to method
            if (!aIsPlug)
            {
                // Don't queue declaring types of plugs
                if (!xIsDynamicMethod)
                {
                    // dont queue declaring types of dynamic methods either, those dont have a declaring type
                    Queue(aMethod.DeclaringType, aMethod, "Declaring Type");
                }
            }
            if (aMethod is SysReflection.MethodInfo)
            {
                Queue(((SysReflection.MethodInfo)aMethod).ReturnType, aMethod, "Return Type");
            }
            if (aMethod.GetFullName().IndexOf("CreateComparer", StringComparison.OrdinalIgnoreCase) != -1)
            {
                ;
            }
            // Scan virtuals
            #region Virtuals scan
            if (!xIsDynamicMethod && aMethod.IsVirtual)
            {
                // For virtuals we need to climb up the type tree
                // and find the top base method. We then add that top
                // node to the mVirtuals list. We don't need to add the
                // types becuase adding DeclaringType will already cause
                // all ancestor types to be added.

                var        xVirtMethod = aMethod;
                var        xVirtType   = aMethod.DeclaringType;
                MethodBase xNewVirtMethod;
                while (true)
                {
                    xVirtType = xVirtType.BaseType;
                    if (xVirtType == null)
                    {
                        // We've reached object, can't go farther
                        xNewVirtMethod = null;
                    }
                    else
                    {
                        xNewVirtMethod = xVirtType.GetMethod(aMethod.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, xParamTypes, null);
                        if (xNewVirtMethod != null)
                        {
                            if (!xNewVirtMethod.IsVirtual)
                            {
                                // This can happen if a virtual "replaces" a non virtual
                                // above it that is not virtual.
                                xNewVirtMethod = null;
                            }
                        }
                    }
                    // We dont bother to add these to Queue, because we have to do a
                    // full downlevel scan if its a new base virtual anyways.
                    if (xNewVirtMethod == null)
                    {
                        // If its already in the list, we mark it null
                        // so we dont do a full downlevel scan.
                        if (mVirtuals.Contains(xVirtMethod))
                        {
                            xVirtMethod = null;
                        }
                        break;
                    }
                    xVirtMethod = xNewVirtMethod;
                }

                // New virtual base found, we need to downscan it
                // If it was already in mVirtuals, then ScanType will take
                // care of new additions.
                if (xVirtMethod != null)
                {
                    Queue(xVirtMethod, aMethod, "Virtual Base");
                    mVirtuals.Add(xVirtMethod);

                    // List changes as we go, cant be foreach
                    for (int i = 0; i < mItemsList.Count; i++)
                    {
                        if (mItemsList[i] is Type)
                        {
                            var xType = (Type)mItemsList[i];
                            if ((xType.IsSubclassOf(xVirtMethod.DeclaringType)) || ((xVirtMethod.DeclaringType.IsInterface) && (xVirtMethod.DeclaringType.IsAssignableFrom(xType))))
                            {
                                var xNewMethod = xType.GetMethod(aMethod.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, xParamTypes, null);
                                if (xNewMethod != null)
                                {
                                    // We need to check IsVirtual, a non virtual could
                                    // "replace" a virtual above it?
                                    if (xNewMethod.IsVirtual)
                                    {
                                        Queue(xNewMethod, aMethod, "Virtual Downscan");
                                    }
                                }
                            }
                        }
                    }
                }
            }
            #endregion

            MethodBase xPlug = null;
            // Plugs may use plugs, but plugs won't be plugged over themself
            var inl = aMethod.GetCustomAttribute <InlineAttribute>();
            if (!aIsPlug && !xIsDynamicMethod)
            {
                // Check to see if method is plugged, if it is we don't scan body

                xPlug = mPlugManager.ResolvePlug(aMethod, xParamTypes);
                if (xPlug != null)
                {
                    //ScanMethod(xPlug, true, "Plug method");
                    if (inl == null)
                    {
                        Queue(xPlug, aMethod, "Plug method");
                    }
                }
            }

            if (xPlug == null)
            {
                bool xNeedsPlug = false;
                if ((aMethod.Attributes & MethodAttributes.PinvokeImpl) != 0)
                {
                    // pinvoke methods dont have an embedded implementation
                    xNeedsPlug = true;
                }
                else
                {
                    var xImplFlags = aMethod.GetMethodImplementationFlags();
                    // todo: prob even more
                    if ((xImplFlags & MethodImplAttributes.Native) != 0 ||
                        (xImplFlags & MethodImplAttributes.InternalCall) != 0)
                    {
                        // native implementations cannot be compiled
                        xNeedsPlug = true;
                    }
                }
                if (xNeedsPlug)
                {
                    throw new Exception("Native code encountered, plug required. Please see https://github.com/CosmosOS/Cosmos/wiki/Plugs). " + LabelName.GenerateFullName(aMethod) + "." + Environment.NewLine + " Called from :" + Environment.NewLine + sourceItem);
                }

                //TODO: As we scan each method, we could update or put in a new list
                // that has the resolved plug so we don't have to reresolve it again
                // later for compilation.

                // Scan the method body for more type and method refs
                //TODO: Dont queue new items if they are plugged
                // or do we need to queue them with a resolved ref in a new list?

                if (inl != null)
                {
                    return;     // cancel inline
                }
                List <ILOpCode> xOpCodes;
                xOpCodes = mReader.ProcessMethod(aMethod);
                if (xOpCodes != null)
                {
                    ProcessInstructions(xOpCodes);
                    foreach (var xOpCode in xOpCodes)
                    {
                        if (xOpCode is ILOpCodes.OpMethod)
                        {
                            Queue(((ILOpCodes.OpMethod)xOpCode).Value, aMethod, "Call", sourceItem);
                        }
                        else if (xOpCode is ILOpCodes.OpType)
                        {
                            Queue(((ILOpCodes.OpType)xOpCode).Value, aMethod, "OpCode Value");
                        }
                        else if (xOpCode is ILOpCodes.OpField)
                        {
                            var xOpField = (ILOpCodes.OpField)xOpCode;
                            //TODO: Need to do this? Will we get a ILOpCodes.OpType as well?
                            Queue(xOpField.Value.DeclaringType, aMethod, "OpCode Value");
                            if (xOpField.Value.IsStatic)
                            {
                                //TODO: Why do we add static fields, but not instance?
                                // AW: instance fields are "added" always, as part of a type, but for static fields, we need to emit a datamember
                                Queue(xOpField.Value, aMethod, "OpCode Value");
                            }
                        }
                        else if (xOpCode is ILOpCodes.OpToken)
                        {
                            var xTokenOp = (ILOpCodes.OpToken)xOpCode;
                            if (xTokenOp.ValueIsType)
                            {
                                Queue(xTokenOp.ValueType, aMethod, "OpCode Value");
                            }
                            if (xTokenOp.ValueIsField)
                            {
                                Queue(xTokenOp.ValueField.DeclaringType, aMethod, "OpCode Value");
                                if (xTokenOp.ValueField.IsStatic)
                                {
                                    //TODO: Why do we add static fields, but not instance?
                                    // AW: instance fields are "added" always, as part of a type, but for static fields, we need to emit a datamember
                                    Queue(xTokenOp.ValueField, aMethod, "OpCode Value");
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #3
0
        private MethodBase ResolvePlug(Type aTargetType, List <Type> aImpls, MethodBase aMethod, Type[] aParamTypes)
        {
            //TODO: This method is "reversed" from old - remember that when porting
            MethodBase xResult = null;

            // Setup param types for search
            Type[] xParamTypes;
            if (aMethod.IsStatic)
            {
                xParamTypes = aParamTypes;
            }
            else
            {
                // If its an instance method, we have to add this to the ParamTypes to search
                xParamTypes = new Type[aParamTypes.Length + 1];
                if (aParamTypes.Length > 0)
                {
                    aParamTypes.CopyTo(xParamTypes, 1);
                }
                xParamTypes[0] = aTargetType;
            }

            PlugMethodAttribute xAttrib = null;

            foreach (var xImpl in aImpls)
            {
                // TODO: cleanup this loop, next statement shouldnt be neccessary
                if (xResult != null)
                {
                    break;
                }
                // Plugs methods must be static, and public
                // Search for non signature matches first since signature searches are slower
                xResult = xImpl.GetMethod(aMethod.Name, BindingFlags.Static | BindingFlags.Public
                                          , null, xParamTypes, null);
                if (xResult == null && aMethod.Name == ".ctor")
                {
                    xResult = xImpl.GetMethod("Ctor", BindingFlags.Static | BindingFlags.Public
                                              , null, xParamTypes, null);
                }
                if (xResult == null && aMethod.Name == ".cctor")
                {
                    xResult = xImpl.GetMethod("CCtor", BindingFlags.Static | BindingFlags.Public
                                              , null, xParamTypes, null);
                }

                if (xResult == null)
                {
                    // Search by signature
                    foreach (var xSigMethod in xImpl.GetMethods(BindingFlags.Static | BindingFlags.Public))
                    {
                        // TODO: Only allow one, but this code for now takes the last one
                        // if there is more than one
                        xAttrib = null;
                        foreach (PlugMethodAttribute x in xSigMethod.GetCustomAttributes(typeof(PlugMethodAttribute), false))
                        {
                            xAttrib = x;
                        }

                        if (xAttrib != null && (xAttrib.IsWildcard && !xAttrib.WildcardMatchParameters))
                        {
                            MethodBase xTargetMethod = null;
                            if (String.Compare(xSigMethod.Name, "Ctor", true) == 0 ||
                                String.Compare(xSigMethod.Name, "Cctor", true) == 0)
                            {
                                xTargetMethod = aTargetType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).SingleOrDefault();
                            }
                            else
                            {
                                xTargetMethod = (from item in aTargetType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance)
                                                 where item.Name == xSigMethod.Name
                                                 select item).SingleOrDefault();
                            }
                            if (xTargetMethod == aMethod)
                            {
                                xResult = xSigMethod;
                            }
                        }
                        else
                        {
                            var xParams = xSigMethod.GetParameters();
                            //TODO: Static method plugs dont seem to be separated
                            // from instance ones, so the only way seems to be to try
                            // to match instance first, and if no match try static.
                            // I really don't like this and feel we need to find
                            // an explicit way to determine or mark the method
                            // implementations.
                            //
                            // Plug implementations take "this" as first argument
                            // so when matching we don't include it in the search
                            Type[] xTypesInst        = null;
                            var    xActualParamCount = xParams.Length;
                            foreach (var xParam in xParams)
                            {
                                if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0)
                                {
                                    xActualParamCount--;
                                }
                            }
                            Type[] xTypesStatic = new Type[xActualParamCount];
                            // If 0 params, has to be a static plug so we skip
                            // any copying and leave xTypesInst = null
                            // If 1 params, xTypesInst must be converted to Type[0]
                            if (xActualParamCount == 1)
                            {
                                xTypesInst = new Type[0];

                                var xReplaceType = xParams[0].GetCustomAttributes(typeof(FieldTypeAttribute), false);
                                if (xReplaceType.Length == 1)
                                {
                                    xTypesStatic[0] = Type.GetType(((FieldTypeAttribute)xReplaceType[0]).Name, true);
                                }
                                else
                                {
                                    xTypesStatic[0] = xParams[0].ParameterType;
                                }
                            }
                            else if (xActualParamCount > 1)
                            {
                                xTypesInst = new Type[xActualParamCount - 1];
                                var xCurIdx = 0;
                                foreach (var xParam in xParams.Skip(1))
                                {
                                    if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0)
                                    {
                                        continue;
                                    }

                                    var xReplaceType = xParam.GetCustomAttributes(typeof(FieldTypeAttribute), false);
                                    if (xReplaceType.Length == 1)
                                    {
                                        xTypesInst[xCurIdx] = Type.GetType(((FieldTypeAttribute)xReplaceType[0]).Name, true);
                                    }
                                    else
                                    {
                                        xTypesInst[xCurIdx] = xParam.ParameterType;
                                    }

                                    xCurIdx++;
                                }
                                xCurIdx = 0;
                                foreach (var xParam in xParams)
                                {
                                    if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0)
                                    {
                                        xCurIdx++;
                                        continue;
                                    }
                                    if (xCurIdx >= xTypesStatic.Length)
                                    {
                                        break;
                                    }
                                    xTypesStatic[xCurIdx] = xParam.ParameterType;
                                    xCurIdx++;
                                }
                            }
                            SysReflection.MethodBase xTargetMethod = null;
                            // TODO: In future make rule that all ctor plugs are called
                            // ctor by name, or use a new attrib
                            //TODO: Document all the plug stuff in a document on website
                            //TODO: To make inclusion of plugs easy, we can make a plugs master
                            // that references the other default plugs so user exes only
                            // need to reference that one.
                            // TODO: Skip FieldAccessAttribute if in impl
                            if (xTypesInst != null)
                            {
                                if (string.Compare(xSigMethod.Name, "ctor", true) == 0)
                                {
                                    xTargetMethod = aTargetType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesInst, null);
                                }
                                else
                                {
                                    xTargetMethod = aTargetType.GetMethod(xSigMethod.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesInst, null);
                                }
                            }
                            // Not an instance method, try static
                            if (xTargetMethod == null)
                            {
                                if (string.Compare(xSigMethod.Name, "cctor", true) == 0 ||
                                    string.Compare(xSigMethod.Name, "ctor", true) == 0)
                                {
                                    xTargetMethod = aTargetType.GetConstructor(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesStatic, null);
                                }
                                else
                                {
                                    xTargetMethod = aTargetType.GetMethod(xSigMethod.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesStatic, null);
                                }
                            }
                            if (xTargetMethod == aMethod)
                            {
                                xResult = xSigMethod;
                                break;
                            }
                            //if (aMethod.DeclaringType.IsGenericTypeDefinition)
                            //{
                            //    if (xTargetMethod.GetF)
                            //}
                            if (xAttrib != null && xAttrib.Signature != null)
                            {
                                var xName = DataMember.FilterStringForIncorrectChars(LabelName.GenerateFullName(aMethod));
                                if (string.Compare(xName, xAttrib.Signature, true) == 0)
                                {
                                    xResult = xSigMethod;
                                    break;
                                }
                            }
                            xAttrib = null;
                        }
                    }
                }
                else
                {
                    // check if signatur is equal
                    var xResPara     = xResult.GetParameters();
                    var xAMethodPara = aMethod.GetParameters();
                    if (aMethod.IsStatic)
                    {
                        if (xResPara.Length != xAMethodPara.Length)
                        {
                            return(null);
                        }
                    }
                    else
                    {
                        if (xResPara.Length - 1 != xAMethodPara.Length)
                        {
                            return(null);
                        }
                    }
                    for (int i = 0; i < xAMethodPara.Length; i++)
                    {
                        int correctIndex = aMethod.IsStatic ? i : i + 1;
                        if (xResPara[correctIndex].ParameterType != xAMethodPara[i].ParameterType)
                        {
                            return(null);
                        }
                    }
                    if (xResult.Name == "Ctor" && aMethod.Name == ".ctor")
                    {
                    }
                    else if (xResult.Name == "CCtor" && aMethod.Name == ".cctor")
                    {
                    }
                    else if (xResult.Name != aMethod.Name)
                    {
                        return(null);
                    }
                }
            }
            if (xResult == null)
            {
                return(null);
            }

            // If we found a matching method, check for attributes
            // that might disable it.
            //TODO: For signature ones, we could cache the attrib. Thats
            // why we check for null here
            if (xAttrib == null)
            {
                // TODO: Only allow one, but this code for now takes the last one
                // if there is more than one
                foreach (PlugMethodAttribute x in xResult.GetCustomAttributes(typeof(PlugMethodAttribute), false))
                {
                    xAttrib = x;
                }
            }

            // See if we need to disable this plug
            if (xAttrib != null)
            {
                if (!xAttrib.Enabled)
                {
                    //xResult = null;
                    return(null);
                }
                else if (xAttrib.IsMonoOnly)
                {
                    //TODO: Check this against build options
                    //TODO: Two exclusive IsOnly's dont make sense
                    // refactor these as a positive rather than negative
                    // Same thing at type plug level
                    //xResult = null;
                    return(null);
                }
                //else if (xAttrib.Signature != null) {
                //  var xName = DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GenerateFullName(xResult));
                //  if (string.Compare(xName, xAttrib.Signature, true) != 0) {
                //    xResult = null;
                //  }
                //}
            }

            //if (xAttrib != null && xAttrib.Signature != null)
            //{
            //    var xTargetMethods = aTargetType.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
            //    //System_Void__Indy_IL2CPU_Assembler_Assembler__cctor__
            //    //If signature exists, the search is slow. Signatures
            //    //are infrequent though, so for now we just go slow method
            //    //and have not optimized or cached this info. When we
            //    //redo the plugs, we can fix this.
            //    bool xEnabled=true;
            //    foreach (var xTargetMethod in xTargetMethods)
            //    {
            //        string sName = DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GenerateFullName(xTargetMethod));
            //        if (string.Compare(sName, xAttrib.Signature, true) == 0)
            //        {
            //            //uint xUID = QueueMethod(xPlugImpl.Plug, "Plug", xMethod, true);
            //            //mMethodPlugs.Add(xTargetMethod, new PlugInfo(xUID, xAttrib.Assembler));
            //            // Mark as disabled, because we already handled it
            //            xEnabled = false;
            //            break;
            //        }
            //    }
            //    // if still enabled, we didn't find our method
            //    if (xEnabled)
            //    {
            //        // todo: more precise error: imagine having a 100K line project, and this error happens...
            //        throw new Exception("Plug target method not found.");
            //    }
            //}
            return(xResult);
        }