Example #1
0
        protected void ScanQueue()
        {
            while (mQueue.Count > 0)
            {
                var xItem = mQueue.Dequeue();
                CompilerHelpers.Debug($"ILScanner: ScanQueue - '{xItem}'");
                // Check for MethodBase first, they are more numerous
                // and will reduce compares
                if (xItem.Item is MethodBase xMethod)
                {
                    ScanMethod(xMethod, false, xItem.SourceItem);
                }
                else if (xItem.Item is Type xType)
                {
                    ScanType(xType);

                    // Methods and fields cant exist without types, so we only update
                    // mUsedAssemblies in type branch.
                    if (!mUsedAssemblies.Contains(xType.Assembly))
                    {
                        mUsedAssemblies.Add(xType.Assembly);
                    }
                }
                else if (xItem.Item is FieldInfo)
                {
                    // todo: static fields need more processing?
                }
                else
                {
                    throw new Exception("Unknown item found in queue.");
                }
            }
        }
Example #2
0
        public void Execute(MethodBase[] aBootEntries, List <MemberInfo> aForceIncludes, IEnumerable <Assembly> plugsAssemblies)
        {
            foreach (var xBootEntry in aBootEntries)
            {
                Queue(xBootEntry.DeclaringType, null, "Boot Entry Declaring Type");
                Queue(xBootEntry, null, "Boot Entry");
            }

            foreach (var xForceInclude in aForceIncludes)
            {
                Queue(xForceInclude, null, "Force Include");
            }

            mPlugManager.FindPlugImpls(plugsAssemblies);
            // Now that we found all plugs, scan them.
            // We have to scan them after we find all plugs, because
            // plugs can use other plugs
            mPlugManager.ScanFoundPlugs();
            foreach (var xPlug in mPlugManager.PlugImpls)
            {
                CompilerHelpers.Debug($"Plug found: '{xPlug.Key.FullName}' in '{xPlug.Key.Assembly.FullName}'");
            }

            ILOp.PlugManager = mPlugManager;

            // Pull in extra implementations, GC etc.
            Queue(RuntimeEngineRefs.InitializeApplicationRef, null, "Explicit Entry");
            Queue(RuntimeEngineRefs.FinalizeApplicationRef, null, "Explicit Entry");
            Queue(VTablesImplRefs.SetMethodInfoRef, null, "Explicit Entry");
            Queue(VTablesImplRefs.IsInstanceRef, null, "Explicit Entry");
            Queue(VTablesImplRefs.SetTypeInfoRef, null, "Explicit Entry");
            Queue(VTablesImplRefs.SetInterfaceInfoRef, null, "Explicit Entry");
            Queue(VTablesImplRefs.SetInterfaceMethodInfoRef, null, "Explicit Entry");
            Queue(VTablesImplRefs.GetMethodAddressForTypeRef, null, "Explicit Entry");
            Queue(VTablesImplRefs.GetMethodAddressForInterfaceTypeRef, null, "Explicit Entry");
            Queue(GCImplementationRefs.IncRefCountRef, null, "Explicit Entry");
            Queue(GCImplementationRefs.DecRefCountRef, null, "Explicit Entry");
            Queue(GCImplementationRefs.AllocNewObjectRef, null, "Explicit Entry");
            // Pull in Array constructor
            Queue(typeof(Array).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).First(), null, "Explicit Entry");
            // Pull in MulticastDelegate.GetInvocationList, needed by the Invoke plug
            Queue(typeof(MulticastDelegate).GetMethod("GetInvocationList"), null, "Explicit Entry");
            // Exception support
            Queue(ExceptionHelperRefs.CurrentExceptionRef, null, "Explicit Entry");
            Queue(ExceptionHelperRefs.ThrowNotFiniteNumberExceptionRef, null, "Explicit Entry");

            mAsmblr.ProcessField(typeof(string).GetField("Empty", BindingFlags.Static | BindingFlags.Public));

            ScanQueue();
            UpdateAssemblies();
            Assemble();

            mAsmblr.EmitEntrypoint(null, aBootEntries);
        }
Example #3
0
        protected void Queue(MemberInfo aItem, object aSrc, string aSrcType, string sourceItem = null)
        {
            CompilerHelpers.Debug($"Enqueing: {aItem.DeclaringType?.Name ?? ""}.{aItem.Name} from {aSrc}");
            if (aItem == null)
            {
                throw new ArgumentNullException(nameof(aItem));
            }

            //TODO: fix this, as each label/symbol should also contain an assembly specifier.

            //if ((xMemInfo != null) && (xMemInfo.DeclaringType != null)
            //    && (xMemInfo.DeclaringType.FullName == "System.ThrowHelper")
            //    && (xMemInfo.DeclaringType.Assembly.GetName().Name != "mscorlib"))
            //{
            // System.ThrowHelper exists in MS .NET twice...
            // Its an internal class that exists in both mscorlib and system assemblies.
            // They are separate types though, so normally the scanner scans both and
            // then we get conflicting labels. MS included it twice to make exception
            // throwing code smaller. They are internal though, so we cannot
            // reference them directly and only via finding them as they come along.
            // We find it here, not via QueueType so we only check it here. Later
            // we might have to checkin QueueType also.
            // So now we accept both types, but emit code for only one. This works
            // with the current Nasm assembler as we resolve by name in the assembler.
            // However with other assemblers this approach may not work.
            // If AssemblerNASM adds assembly name to the label, this will allow
            // both to exist as they do in BCL.
            // So in the future we might be able to remove this hack, or change
            // how it works.
            //
            // Do nothing
            //
            //}
            /*else*/
            if (!mItems.Contains(aItem))
            {
                if (mLogEnabled)
                {
                    LogMapPoint(aSrc, aSrcType, aItem);
                }

                mItems.Add(aItem);
                mItemsList.Add(aItem);

                if (aSrc is MethodBase xMethodBaseSrc)
                {
                    aSrc = xMethodBaseSrc.DeclaringType + "::" + aSrc;
                }

                mQueue.Enqueue(new ScannerQueueItem(aItem, aSrcType, aSrc + Environment.NewLine + sourceItem));
            }
        }
Example #4
0
        public void Execute(SysReflection.MethodBase aStartMethod)
        {
            if (aStartMethod == null)
            {
                throw new ArgumentNullException("aStartMethod");
            }
            // TODO: Investigate using MS CCI
            // Need to check license, as well as in profiler
            // http://cciast.codeplex.com/

            #region Description
            // Methodology
            //
            // Ok - we've done the scanner enough times to know it needs to be
            // documented super well so that future changes won't inadvertently
            // break undocumented and unseen requirements.
            //
            // We've tried many approaches including recursive and additive scanning.
            // They typically end up being inefficient, overly complex, or both.
            //
            // -We would like to scan all types/methods so we can plug them.
            // -But we can't scan them until we plug them, because we will scan things
            // that plugs would remove/change the paths of.
            // -Plugs may also call methods which are also plugged.
            // -We cannot resolve plugs ahead of time but must do on the fly during
            // scanning.
            // -TODO: Because we do on the fly resolution, we need to add explicit
            // checking of plug classes and err when public methods are found that
            // do not resolve. Maybe we can make a list and mark, or rescan. Can be done
            // later or as an optional auditing step.
            //
            // This why in the past we had repetitive scans.
            //
            // Now we focus on more passes, but simpler execution. In the end it should
            // be eaiser to optmize and yield overall better performance. Most of the
            // passes should be low overhead versus an integrated system which often
            // would need to reiterate over items multiple times. So we do more loops on
            // with less repetitive analysis, instead of fewer loops but more repetition.
            //
            // -Locate all plug classes
            // -Scan from entry point collecting all types and methods while checking
            // for and following plugs
            // -For each type
            //    -Include all ancestors
            //    -Include all static constructors
            // -For each virtual method
            //    -Scan overloads in descendants until IsFinal, IsSealed or end
            //    -Scan base in ancestors until top or IsAbstract
            // -Go to scan types again, until no new ones found.
            // -Because the virtual method scanning will add to the list as it goes, maintain
            //  2 lists.
            //    -Known Types and Methods
            //    -Types and Methods in Queue - to be scanned
            // -Finally, do compilation
            #endregion
            mPlugManager.FindPlugImpls();
            // Now that we found all plugs, scan them.
            // We have to scan them after we find all plugs, because
            // plugs can use other plugs
            mPlugManager.ScanFoundPlugs();
            foreach (var xPlug in mPlugManager.PlugImpls)
            {
                CompilerHelpers.Debug($"Plug found: '{xPlug.Key.FullName}'");
            }

            ILOp.mPlugManager = mPlugManager;

            // Pull in extra implementations, GC etc.
            Queue(RuntimeEngineRefs.InitializeApplicationRef, null, "Explicit Entry");
            Queue(RuntimeEngineRefs.FinalizeApplicationRef, null, "Explicit Entry");
            //Queue(typeof(CosmosAssembler).GetMethod("PrintException"), null, "Explicit Entry");
            Queue(VTablesImplRefs.SetMethodInfoRef, null, "Explicit Entry");
            Queue(VTablesImplRefs.IsInstanceRef, null, "Explicit Entry");
            Queue(VTablesImplRefs.SetTypeInfoRef, null, "Explicit Entry");
            Queue(VTablesImplRefs.GetMethodAddressForTypeRef, null, "Explicit Entry");
            Queue(GCImplementationRefs.IncRefCountRef, null, "Explicit Entry");
            Queue(GCImplementationRefs.DecRefCountRef, null, "Explicit Entry");
            Queue(GCImplementationRefs.AllocNewObjectRef, null, "Explicit Entry");
            // for now, to ease runtime exception throwing
            Queue(typeof(ExceptionHelper).GetMethod("ThrowNotImplemented", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null), null, "Explicit Entry");
            Queue(typeof(ExceptionHelper).GetMethod("ThrowOverflow", BindingFlags.Static | BindingFlags.Public, null, new Type[] { }, null), null, "Explicit Entry");
            Queue(RuntimeEngineRefs.InitializeApplicationRef, null, "Explicit Entry");
            Queue(RuntimeEngineRefs.FinalizeApplicationRef, null, "Explicit Entry");
            // register system types:
            Queue(typeof(Array), null, "Explicit Entry");
            Queue(typeof(Array).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null), null, "Explicit Entry");

            var xThrowHelper = Type.GetType("System.ThrowHelper", true);
            Queue(xThrowHelper.GetMethod("ThrowInvalidOperationException", BindingFlags.NonPublic | BindingFlags.Static), null, "Explicit Entry");

            Queue(typeof(MulticastDelegate).GetMethod("GetInvocationList"), null, "Explicit Entry");
            Queue(ExceptionHelperRefs.CurrentExceptionRef, null, "Explicit Entry");
            //System_Delegate____System_MulticastDelegate_GetInvocationList__

            // Start from entry point of this program
            Queue(aStartMethod, null, "Entry Point");

            ScanQueue();
            UpdateAssemblies();
            Assemble();

            mAsmblr.EmitEntrypoint(aStartMethod);
        }
Example #5
0
        /// <summary>Load every refernced assemblies that have an associated FullPath property and seek for
        /// the kernel default constructor.</summary>
        /// <returns>The kernel default constructor or a null reference if either none or several such
        /// constructor could be found.</returns>
        private MethodBase LoadAssemblies()
        {
            // Try to load explicit path references.
            // These are the references of our boot project. We dont actually ever load the boot
            // project asm. Instead the references will contain plugs, and the kernel. We load
            // them then find the entry point in the kernel.
            //
            // Plugs and refs in this list will be loaded absolute (or as proj refs) only. Asm resolution
            // will not be tried on them, but will on ASMs they reference.

            string xKernelBaseName = "Cosmos.System.Kernel";

            LogMessage("Kernel Base: " + xKernelBaseName);

            Type xKernelType = null;

            foreach (string xRef in References)
            {
                LogMessage("Checking Reference: " + xRef);
                if (File.Exists(xRef))
                {
                    LogMessage("  Exists");
                    var xAssembly = AssemblyLoadContext.Default.LoadFromAssemblyCacheOrPath(xRef);

                    CompilerHelpers.Debug($"Looking for kernel in {xAssembly}");

                    foreach (var xType in xAssembly.ExportedTypes)
                    {
                        if (!xType.IsGenericTypeDefinition && !xType.IsAbstract)
                        {
                            CompilerHelpers.Debug($"Checking type {xType.FullName}");

                            // We used to resolve with this:
                            //   if (xType.IsSubclassOf(typeof(Cosmos.System.Kernel))) {
                            // But this caused a single dependency on Cosmos.System which is bad.
                            // We could use an attribute, or maybe an interface would be better in this limited case. Interface
                            // will force user to implement what is needed if replacing our core. But in the end this is a "not needed" feature
                            // and would only complicate things.
                            // So for now at least, we look by name so we dont have a dependency since the method returns a MethodBase and not a Kernel instance anyway.
                            if (xType.BaseType.FullName == xKernelBaseName)
                            {
                                if (xKernelType != null)
                                {
                                    LogError($"Two kernels found: {xType.FullName} and {xKernelType.FullName}");
                                    return(null);
                                }
                                xKernelType = xType;
                            }
                        }
                    }
                }
            }

            if (xKernelType == null)
            {
                LogError("No kernel found.");
                return(null);
            }
            var xCtor = xKernelType.GetConstructor(Type.EmptyTypes);

            if (xCtor == null)
            {
                LogError("Kernel has no public parameterless constructor.");
                return(null);
            }
            return(xCtor);
        }
Example #6
0
        protected void ScanType(Type aType)
        {
            CompilerHelpers.Debug($"ILScanner: ScanType");
            CompilerHelpers.Debug($"Type = '{aType}'");

            // Add immediate ancestor type
            // We dont need to crawl up farther, when the BaseType is scanned
            // it will add its BaseType, and so on.
            if (aType.BaseType != null)
            {
                Queue(aType.BaseType, aType, "Base Type");
            }
            // Queue static ctors
            // We always need static ctors, else the type cannot
            // be created.
            foreach (var xCctor in aType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
            {
                if (xCctor.DeclaringType == aType)
                {
                    Queue(xCctor, aType, "Static Constructor");
                }
            }

            // For each new type, we need to scan for possible new virtuals
            // in our new type if its a descendant of something in
            // mVirtuals.
            foreach (var xVirt in mVirtuals)
            {
                // See if our new type is a subclass of any virt's DeclaringTypes
                // If so our new type might have some virtuals
                if (aType.IsSubclassOf(xVirt.DeclaringType))
                {
                    var xParams     = xVirt.GetParameters();
                    var xParamTypes = new Type[xParams.Length];
                    // Dont use foreach, enum generaly keeps order but
                    // isn't guaranteed.
                    for (int i = 0; i < xParams.Length; i++)
                    {
                        xParamTypes[i] = xParams[i].ParameterType;
                    }
                    var xMethod = aType.GetMethod(xVirt.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, xParamTypes, null);
                    if (xMethod != null)
                    {
                        // We need to check IsVirtual, a non virtual could
                        // "replace" a virtual above it?
                        if (xMethod.IsVirtual)
                        {
                            Queue(xMethod, aType, "Virtual");
                        }
                    }
                }
                if (!aType.IsGenericParameter && xVirt.DeclaringType.IsInterface)
                {
                    if (!aType.IsInterface && aType.GetInterfaces().Contains(xVirt.DeclaringType))
                    {
                        var xIntfMapping = aType.GetInterfaceMap(xVirt.DeclaringType);
                        if ((xIntfMapping.InterfaceMethods != null) && (xIntfMapping.TargetMethods != null))
                        {
                            var xIdx = Array.IndexOf(xIntfMapping.InterfaceMethods, xVirt);
                            if (xIdx != -1)
                            {
                                Queue(xIntfMapping.TargetMethods[xIdx], aType, "Virtual");
                            }
                        }
                    }
                }
            }

            foreach (var xInterface in aType.GetInterfaces())
            {
                Queue(xInterface, aType, "Implemented Interface");
            }
        }
Example #7
0
        protected void ScanMethod(MethodBase aMethod, bool aIsPlug, string sourceItem)
        {
            CompilerHelpers.Debug($"ILScanner: ScanMethod");
            CompilerHelpers.Debug($"Method = '{aMethod}'");
            CompilerHelpers.Debug($"IsPlug = '{aIsPlug}'");
            CompilerHelpers.Debug($"Source = '{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.GetFullName(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 MethodInfo)
            {
                Queue(((MethodInfo)aMethod).ReturnType, aMethod, "Return Type");
            }
            // 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.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                         .Where(method => method.Name == aMethod.Name &&
                                                method.GetParameters().Select(param => param.ParameterType)
                                                .SequenceEqual(xParamTypes))
                                         .SingleOrDefault();
                        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 xType && xType != xVirtMethod.DeclaringType && !xType.IsInterface)
                        {
                            if (xType.IsSubclassOf(xVirtMethod.DeclaringType))
                            {
                                var xNewMethod = xType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                                 .Where(method => method.Name == aMethod.Name &&
                                                        method.GetParameters().Select(param => param.ParameterType).SequenceEqual(xParamTypes))
                                                 .SingleOrDefault();
                                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");
                                    }
                                }
                            }
                            else if (xVirtMethod.DeclaringType.IsInterface &&
                                     xType.GetInterfaces().Contains(xVirtMethod.DeclaringType))
                            {
                                var xInterfaceMap = xType.GetInterfaceMap(xVirtMethod.DeclaringType);
                                var xMethodIndex  = Array.IndexOf(xInterfaceMap.InterfaceMethods, xVirtMethod);

                                if (xMethodIndex != -1)
                                {
                                    var xMethod = xInterfaceMap.TargetMethods[xMethodIndex];

                                    if (xMethod.DeclaringType == xType)
                                    {
                                        Queue(xInterfaceMap.TargetMethods[xMethodIndex], aMethod, "Virtual Downscan");
                                    }
                                }
                            }
                        }
                    }
                }
            }

            #endregion Virtuals scan

            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.HasFlag(MethodImplAttributes.Native) || xImplFlags.HasFlag(MethodImplAttributes.InternalCall))
                    {
                        // native implementations cannot be compiled
                        xNeedsPlug = true;
                    }
                }
                if (xNeedsPlug)
                {
                    throw new Exception(Environment.NewLine
                                        + "Native code encountered, plug required." + Environment.NewLine
                                        + "  DO NOT REPORT THIS AS A BUG." + Environment.NewLine
                                        + "  Please see http://www.gocosmos.org/docs/plugs/missing/" + Environment.NewLine
                                        + "  Need plug for: " + LabelName.GetFullName(aMethod) + "." + Environment.NewLine
                                        + "  Called from :" + Environment.NewLine + sourceItem + Environment.NewLine);
                }

                //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 xOpField)
                        {
                            //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 xOpToken)
                        {
                            if (xOpToken.ValueIsType)
                            {
                                Queue(xOpToken.ValueType, aMethod, "OpCode Value");
                            }
                            if (xOpToken.ValueIsField)
                            {
                                Queue(xOpToken.ValueField.DeclaringType, aMethod, "OpCode Value");
                                if (xOpToken.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(xOpToken.ValueField, aMethod, "OpCode Value");
                                }
                            }
                        }
                    }
                }
            }
        }
Example #8
0
        public 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 (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;
                //  }
                //}
            }

            InlineAttribute xInlineAttrib = null;

            foreach (InlineAttribute inli in xResult.GetCustomAttributes(typeof(InlineAttribute), false))
            {
                xInlineAttrib = inli;
            }

            if (xInlineAttrib == null)
            {
                if (Queue != null)
                {
                    CompilerHelpers.Debug("Queueing Plug:", xResult.DeclaringType, "::", xResult.Name);
                    Queue(xResult, null, "Plug Method");
                }
            }

            //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);
        }
Example #9
0
        /// <summary>Load every refernced assemblies that have an associated FullPath property and seek for
        /// the kernel default constructor.</summary>
        /// <returns>The kernel default constructor or a null reference if either none or several such
        /// constructor could be found.</returns>
        private MethodBase LoadAssemblies()
        {
            // Try to load explicit path references.
            // These are the references of our boot project. We dont actually ever load the boot
            // project asm. Instead the references will contain plugs, and the kernel. We load
            // them then find the entry point in the kernel.
            //
            // Plugs and refs in this list will be loaded absolute (or as proj refs) only. Asm resolution
            // will not be tried on them, but will on ASMs they reference.
            //

            AssemblyLoadContext.Default.Resolving += Default_Resolving;
            mLoadedExtensions = new List <CompilerExtensionBase>();
            Type xKernelType = null;

            foreach (string xReference in References)
            {
                if (File.Exists(xReference))
                {
                    var xAssembly = AssemblyLoadContext.Default.LoadFromAssemblyCacheOrPath(xReference);

                    CompilerHelpers.Debug($"Looking for kernel in '{xAssembly}'");

                    foreach (var xType in xAssembly.ExportedTypes)
                    {
                        if (!xType.GetTypeInfo().IsGenericTypeDefinition&& !xType.GetTypeInfo().IsAbstract)
                        {
                            CompilerHelpers.Debug($"Checking type '{xType.FullName}'");

                            if (xType.GetTypeInfo().IsSubclassOf(typeof(Cosmos.System.Kernel)))
                            {
                                // found kernel?
                                if (xKernelType != null)
                                {
                                    // already a kernel found, which is not supported.
                                    LogError($"Two kernels found! '{xType.AssemblyQualifiedName}' and '{xKernelType.AssemblyQualifiedName}'");
                                    return(null);
                                }

                                xKernelType = xType;
                            }
                        }
                    }

                    var xCompilerExtensionsMetas = xAssembly.GetCustomAttributes <CompilerExtensionAttribute>();
                    foreach (var xMeta in xCompilerExtensionsMetas)
                    {
                        mLoadedExtensions.Add((CompilerExtensionBase)Activator.CreateInstance(xMeta.Type));
                    }
                }
            }

            if (xKernelType == null)
            {
                LogError("No Kernel found!");
                return(null);
            }
            var xCtor = xKernelType.GetTypeInfo().GetConstructor(Type.EmptyTypes);

            if (xCtor == null)
            {
                LogError("Kernel has no public default constructor");
                return(null);
            }
            return(xCtor);
        }