Пример #1
0
        public CppMidCompiler(CppBuilder builder, CppClass cls, CppMethod method, ExceptionHandlingRegion mainRegion, string frameVarName, VReg[] args, VReg[] locals, VReg[] temporaries)
        {
            m_builder = builder;
            m_cls = cls;
            m_method = method;
            m_mainRegion = mainRegion;
            m_args = args;
            m_locals = locals;
            m_temporaries = temporaries;
            m_frameVarName = frameVarName;

            m_instructionStream = new MemoryStream();
            m_instructionWriter = new StreamWriter(m_instructionStream);
            m_regAllocator = new CppRegisterAllocator(builder);
        }
Пример #2
0
        public CfgBuilder(ExceptionHandlingRegion region, CppBuilder builder, CppClass cls, CppMethod method, VReg[] args, VReg[] locals, IList<VReg> temporaries)
        {
            m_builder = builder;
            m_cls = cls;
            m_method = method;
            m_args = args;
            m_locals = locals;
            m_temporaries = temporaries;
            m_instrs = method.MethodDef.Method.Instructions;
            m_inClass = cls.TypeDef;
            m_inMethod = method.MethodDef;
            m_region = region;

            m_startInstr = (int)region.StartInstr;
            m_endInstr = (int)region.EndInstr;
            m_ehClusters = region.Clusters;

            LocateBranchTargets();
            ConstructCfg();
            CreateSuccessionGraph();
        }
Пример #3
0
        public static void WriteMethodCode(Clarity.Rpa.HighFileBuilder fileBuilder, BinaryWriter writer, CppBuilder builder, CppClass cls, CppMethod method)
        {
            List<VReg> args = new List<VReg>();
            if (!method.Static)
            {
                CppClass thisClass = builder.GetCachedClass(method.DeclaredInClassSpec);
                CLRTypeSpec thisTypeSpec = method.DeclaredInClassSpec;
                VType vt = new VType(thisClass.IsValueType ? VType.ValTypeEnum.ManagedPtr : VType.ValTypeEnum.ReferenceValue, thisTypeSpec);
                args.Add(new VReg(builder, "bThis", vt, args.Count, VReg.UsageEnum.Argument));
            }

            foreach (CLRMethodSignatureInstanceParam param in method.MethodSignature.ParamTypes)
            {
                CLRTypeSpec spec = param.Type;
                VType vt;
                switch (param.TypeOfType)
                {
                    case CLRSigParamOrRetType.TypeOfTypeEnum.ByRef:
                        vt = new VType(VType.ValTypeEnum.ManagedPtr, spec);
                        break;
                    case CLRSigParamOrRetType.TypeOfTypeEnum.Value:
                        vt = new VType(ValTypeForTypeSpec(builder, spec), spec);
                        break;
                    default:
                        throw new ArgumentException();
                }
                args.Add(new VReg(builder, "bParam", vt, args.Count, VReg.UsageEnum.Argument));
            }

            List<VReg> locals = new List<VReg>();

            CLRSigLocalVarSig localVarSig = method.MethodDef.Method.LocalVarSig;
            if (localVarSig != null)
            {
                foreach (CLRSigLocalVar localVar in localVarSig.LocalVars)
                {
                    if (localVar.Constraints != null && localVar.Constraints.Length > 0)
                        throw new NotSupportedException("Local var constraints are not supported");
                    if (localVar.CustomMods != null && localVar.CustomMods.Length > 0)
                        throw new NotSupportedException("Local var custom mods are not supported");

                    CLRTypeSpec localTypeSpec = builder.Assemblies.InternVagueType(localVar.Type);

                    VReg vreg = null;
                    switch (localVar.VarKind)
                    {
                        case CLRSigLocalVar.LocalVarKind.ByRef:
                            vreg = new VReg(builder, "bLocal", new VType(VType.ValTypeEnum.ManagedPtr, localTypeSpec), locals.Count, VReg.UsageEnum.Local);
                            break;
                        case CLRSigLocalVar.LocalVarKind.Default:
                            vreg = new VReg(builder, "bLocal", new VType(CppCilExporter.ValTypeForTypeSpec(builder, localTypeSpec), localTypeSpec), locals.Count, VReg.UsageEnum.Local);
                            break;
                        default:
                            throw new NotImplementedException();
                    }

                    locals.Add(vreg);
                }
            }

            foreach (VReg vReg in locals)
                vReg.Liven();
            foreach (VReg vReg in args)
                vReg.Liven();

            List<VReg> temporaries = new List<VReg>();

            ExceptionHandlingRegion mainRegion = new ExceptionHandlingRegion(null, builder, method, 0, (uint)method.MethodDef.Method.Instructions.Length - 1, null);
            {
                CfgBuilder cfgBuilder = new CfgBuilder(mainRegion, builder, cls, method, args.ToArray(), locals.ToArray(), temporaries);
                mainRegion.RootCfgNode = cfgBuilder.RootNode;
            }

            CppMidCompiler midCompiler = new CppMidCompiler(builder, cls, method, mainRegion, "bTLFrame", args.ToArray(), locals.ToArray(), temporaries.ToArray());

            midCompiler.EmitAll(fileBuilder, writer);

            //MidCompile(builder, cls, method, mainRegion, args.ToArray(), locals.ToArray(), writer.BaseStream);

            foreach (VReg vReg in locals)
            {
                if (!vReg.IsAlive || vReg.IsZombie)
                    throw new Exception("Internal error: local vreg was killed");
            }
            foreach (VReg vReg in args)
            {
                if (!vReg.IsAlive || vReg.IsZombie)
                    throw new Exception("Internal error: arg vreg was killed");
            }
        }
Пример #4
0
        private void WriteVtableThunks(Clarity.Rpa.HighFileBuilder fileBuilder, BinaryWriter writer, CppClass cls)
        {
            uint numNewSlots = 0;
            uint numReplacedSlots = 0;

            foreach (CppMethod method in cls.Methods)
            {
                if (method.CreatesSlot != null)
                    numNewSlots++;
                else if (method.ReplacesStandardSlot != null)
                    numReplacedSlots++;
            }

            if (cls.TypeDef.Semantics == CLRTypeDefRow.TypeSemantics.Interface)
            {
                if (numReplacedSlots != 0)
                    throw new Exception();
            }
            else
            {
                writer.Write(numReplacedSlots);

                foreach (CppMethod method in cls.Methods)
                {
                    if (method.CreatesSlot == null && method.ReplacesStandardSlot != null)
                        WriteVtableThunk(fileBuilder, writer, cls, method, method.ReplacesStandardSlot);
                }
            }

            writer.Write(numNewSlots);

            foreach (CppMethod method in cls.Methods)
            {
                if (method.CreatesSlot != null)
                    WriteVtableThunk(fileBuilder, writer, cls, method, method.CreatesSlot);
            }
        }
Пример #5
0
        private void WriteVtableThunk(Clarity.Rpa.HighFileBuilder fileBuilder, BinaryWriter writer, CppClass cls, CppMethod method, CppVtableSlot slot)
        {
            CLRMethodSignatureInstance slotSig = slot.Signature;

            writer.Write(fileBuilder.IndexMethodDeclTag(slot.VtableSlotTag));
            writer.Write(fileBuilder.IndexMethodSignatureTag(RpaTagFactory.CreateMethodSignature(slot.Signature)));

            if (cls.TypeDef.Semantics != CLRTypeDefRow.TypeSemantics.Interface)
            {
                writer.Write(method.Abstract);

                if (!method.Abstract)
                {
                    if (method.NumGenericParameters == 0)
                        writer.Write(method.Final);

                    if (method.Static)
                        throw new Exception("VTable slot implemented by static method");

                    writer.Write(fileBuilder.IndexMethodDeclTag(method.VtableSlotTag));
                }
            }
        }
Пример #6
0
        private bool WriteSignatureMatchedBinding(HighFileBuilder fileBuilder, BinaryWriter writer, CppClass cls, CppVtableSlot ifcSlot, CLRTypeSpec ifcTypeSpec)
        {
            bool haveMatch = false;
            foreach (CppVtableSlot vtSlot in cls.NewImplementationVisibleVtableSlots)
            {
                if (ifcSlot.Name == vtSlot.Name && ifcSlot.Signature.Equals(vtSlot.Signature))
                {
                    if (haveMatch)
                    {
                        Console.WriteLine("WARNING: Class " + cls.FullName + " has multiple matches for the same interface implementation");
                        break;
                    }
                    haveMatch = true;

                    writer.Write(true);    // HACK - FIXME
                    WriteInterfaceBinding(fileBuilder, writer, ifcSlot, vtSlot);
                }
            }

            if (haveMatch == true)
                return true;

            CLRTypeSpec parentSpec = cls.ParentTypeSpec;
            if (parentSpec == null)
                return false;

            CppClass parentClass = GetCachedClass(parentSpec);

            // Look for prior implementations of this interface, if any are found, STOP and return no-match.
            // See TestInheritedImplementationDeprioritization.  Matches are only recorded if they're new.
            foreach (CLRTypeSpec ifc in parentClass.NewlyImplementedInterfaces)
                if (ifc.Equals(ifcTypeSpec))
                    return false;
            foreach (CLRTypeSpec ifc in parentClass.ReimplementedInterfaces)
                if (ifc.Equals(ifcTypeSpec))
                    return false;
            return WriteSignatureMatchedBinding(fileBuilder, writer, parentClass, ifcSlot, ifcTypeSpec);
        }
Пример #7
0
        private bool ClassHasNewTraceableFields(CppClass cls)
        {
            if (cls.IsValueType == false && cls.ParentTypeSpec == null)
                return true;    // Special case for System.Object so it overrides GCObject

            foreach (CppField field in cls.Fields)
            {
                if (field.Field.Static)
                    continue;
                if (GetCachedTraceability(field.Type) != CppTraceabilityEnum.NotTraced)
                    return true;
            }
            return false;
        }
Пример #8
0
        private CppClass(CppClass baseInstance, CLRTypeSpec[] typeParams, CLRTypeSpec[] methodParams)
        {
            if (typeParams.Length != baseInstance.NumGenericParameters)
                throw new ArgumentException();

            m_methods = new List<CppMethod>();
            m_fields = new List<CppField>();
            m_allVtableSlots = new List<CppVtableSlot>();
            m_overrideVisibleVtableSlots = new List<CppVtableSlot>();
            m_newImplementationVisibleVtableSlots = new List<CppVtableSlot>();
            m_inheritedFields = new List<CppField>();
            m_reimplementedInterfaces = new List<CLRTypeSpec>();
            m_newlyImplementedInterfaces = new List<CLRTypeSpec>();
            m_explicitInterfaces = new List<CLRTypeSpec>();
            m_inheritedImplementedInterfaces = new List<CLRTypeSpec>();
            m_passiveIfcConversions = new List<CLRTypeSpec>();
            m_inheritedPassiveIfcConversions = new List<CLRTypeSpec>();
            m_genericParameters = new List<CLRTypeSpec>();

            m_typeDef = baseInstance.m_typeDef;

            Name = baseInstance.Name;
            FullName = baseInstance.FullName;
            if (baseInstance.ParentTypeSpec != null)
                ParentTypeSpec = baseInstance.ParentTypeSpec.Instantiate(typeParams, methodParams);

            NumGenericParameters = baseInstance.NumGenericParameters;
            m_genericParameters.AddRange(typeParams);

            foreach (CppMethod method in baseInstance.m_methods)
                m_methods.Add(method.Instantiate(typeParams, methodParams));
            foreach (CppField field in baseInstance.m_fields)
                m_fields.Add(field.Instantiate(typeParams, methodParams));

            foreach (CppVtableSlot vts in baseInstance.m_overrideVisibleVtableSlots)
                m_overrideVisibleVtableSlots.Add(vts.Instantiate(typeParams, methodParams));
            foreach (CppVtableSlot vts in baseInstance.m_newImplementationVisibleVtableSlots)
                m_newImplementationVisibleVtableSlots.Add(vts.Instantiate(typeParams, methodParams));
            foreach (CppVtableSlot vts in baseInstance.m_allVtableSlots)
                m_allVtableSlots.Add(vts.Instantiate(typeParams, methodParams));

            foreach (CppField field in baseInstance.m_inheritedFields)
                m_inheritedFields.Add(field.Instantiate(typeParams, methodParams));
            foreach (CLRTypeSpec impl in baseInstance.m_newlyImplementedInterfaces)
                m_newlyImplementedInterfaces.Add(impl.Instantiate(typeParams, methodParams));
            foreach (CLRTypeSpec impl in baseInstance.m_explicitInterfaces)
                m_explicitInterfaces.Add(impl.Instantiate(typeParams, methodParams));
            foreach (CLRTypeSpec impl in baseInstance.m_reimplementedInterfaces)
                m_reimplementedInterfaces.Add(impl.Instantiate(typeParams, methodParams));
            foreach (CLRTypeSpec impl in baseInstance.m_inheritedImplementedInterfaces)
                m_inheritedImplementedInterfaces.Add(impl.Instantiate(typeParams, methodParams));
            foreach (CLRTypeSpec impl in baseInstance.m_passiveIfcConversions)
                m_passiveIfcConversions.Add(impl.Instantiate(typeParams, methodParams));
            foreach (CLRTypeSpec impl in baseInstance.m_inheritedPassiveIfcConversions)
                m_inheritedPassiveIfcConversions.Add(impl.Instantiate(typeParams, methodParams));

            IsDelegate = baseInstance.IsDelegate;
            IsMulticastDelegate = baseInstance.IsMulticastDelegate;
            IsEnum = baseInstance.IsEnum;
            IsValueType = baseInstance.IsValueType;
            if (DelegateSignature != null)
                DelegateSignature = baseInstance.DelegateSignature.Instantiate(typeParams, methodParams);
            HaveNewStaticFields = baseInstance.HaveNewStaticFields;
            HaveInheritedStaticFields = baseInstance.HaveInheritedStaticFields;
            HaveAnyGenericMethods = baseInstance.HaveAnyGenericMethods;
            StubPath = null;
        }
Пример #9
0
 private void ExportGenericVariance(CppClass cls, BinaryWriter writer)
 {
     if (cls.NumGenericParameters > 0)
     {
         foreach (CLRGenericParamRow genericParam in cls.TypeDef.GenericParameters)
         {
             Clarity.Rpa.HighVariance variance;
             switch (genericParam.Variance)
             {
                 case CLRGenericParamRow.VarianceEnum.Contravariant:
                     variance = Clarity.Rpa.HighVariance.Contravariant;
                     break;
                 case CLRGenericParamRow.VarianceEnum.Covariant:
                     variance = Clarity.Rpa.HighVariance.Covariant;
                     break;
                 case CLRGenericParamRow.VarianceEnum.None:
                     variance = Clarity.Rpa.HighVariance.None;
                     break;
                 default:
                     throw new Exception();
             }
             writer.Write((byte)variance);
         }
     }
 }
Пример #10
0
        private void ExportEnum(Clarity.Rpa.HighFileBuilder fileBuilder, BinaryWriter writer, CppClass cls)
        {
            CLRTypeSpecClass underlyingType = (CLRTypeSpecClass)cls.GetEnumUnderlyingType();

            bool foundUnderlyingType = false;
            uint numLiterals = 0;
            foreach (CppField fld in cls.Fields)
            {
                CLRFieldRow fieldRow = fld.Field;
                if (fieldRow.Literal)
                    numLiterals++;
            }

            Clarity.Rpa.HighTypeDef.EnumUnderlyingType underlyingTypeSymbol;
            string typeName = underlyingType.TypeDef.TypeName;
            switch (typeName)
            {
                case "Byte":
                    underlyingTypeSymbol = Clarity.Rpa.HighTypeDef.EnumUnderlyingType.UInt8;
                    break;
                case "SByte":
                    underlyingTypeSymbol = Clarity.Rpa.HighTypeDef.EnumUnderlyingType.Int8;
                    break;
                case "Int16":
                    underlyingTypeSymbol = Clarity.Rpa.HighTypeDef.EnumUnderlyingType.Int16;
                    break;
                case "UInt16":
                    underlyingTypeSymbol = Clarity.Rpa.HighTypeDef.EnumUnderlyingType.UInt16;
                    break;
                case "Int32":
                    underlyingTypeSymbol = Clarity.Rpa.HighTypeDef.EnumUnderlyingType.Int32;
                    break;
                case "UInt32":
                    underlyingTypeSymbol = Clarity.Rpa.HighTypeDef.EnumUnderlyingType.UInt32;
                    break;
                case "Int64":
                    underlyingTypeSymbol = Clarity.Rpa.HighTypeDef.EnumUnderlyingType.Int64;
                    break;
                case "UInt64":
                    underlyingTypeSymbol = Clarity.Rpa.HighTypeDef.EnumUnderlyingType.UInt64;
                    break;
                default:
                    throw new ArgumentException();
            }

            writer.Write((byte)underlyingTypeSymbol);
            writer.Write(numLiterals);
            foreach (CppField fld in cls.Fields)
            {
                CLRFieldRow fieldRow = fld.Field;
                if (fieldRow.Literal)
                {
                    writer.Write(fileBuilder.IndexString(fld.Name));
                    ArraySegment<byte> constantValue = fieldRow.AttachedConstants[0].Value;
                    writer.Write(constantValue.Array, constantValue.Offset, constantValue.Count);
                }
            }
        }
Пример #11
0
        private void ExportDelegate(Clarity.Rpa.HighFileBuilder fileBuilder, BinaryWriter writer, CppClass cls)
        {
            writer.Write(cls.IsMulticastDelegate);

            ExportGenericVariance(cls, writer);

            foreach (CppMethod method in cls.Methods)
            {
                if (method.Name == "Invoke")
                {
                    writer.Write(fileBuilder.IndexMethodSignatureTag(RpaTagFactory.CreateMethodSignature(method.MethodSignature)));
                    return;
                }
            }
            throw new ParseFailedException("Malformed delegate");
        }
Пример #12
0
 private void ExportClassStubs(CppClass cls)
 {
     //CppStubExporter.ExportStub(this, m_stubDir, cls);
 }
Пример #13
0
        private void ExportClassStatics(Clarity.Rpa.HighFileBuilder fileBuilder, BinaryWriter writer, CppClass cls)
        {
            if (!cls.HaveNewStaticFields)
            {
                writer.Write((uint)0);
                return;
            }

            uint numStaticFields = 0;
            foreach (CppField field in cls.Fields)
                if (field.Field.Static && !field.Field.Literal)
                    numStaticFields++;

            writer.Write(numStaticFields);
            foreach (CppField field in cls.Fields)
            {
                if (field.Field.Static && !field.Field.Literal)
                {
                    writer.Write(fileBuilder.IndexTypeSpecTag(RpaTagFactory.CreateTypeTag(field.Type)));
                    writer.Write(fileBuilder.IndexString(field.Name));
                }
            }
        }
Пример #14
0
        private void ExportClassDefinitions(Clarity.Rpa.HighFileBuilder fileBuilder, BinaryWriter writer, CppClass cls)
        {
            if (cls.IsDelegate || cls.IsEnum)
                throw new ArgumentException();

            if (cls.TypeDef.Semantics == CLRTypeDefRow.TypeSemantics.Interface)
                ExportGenericVariance(cls, writer);

            if (!cls.IsValueType && cls.TypeDef.Semantics == CLRTypeDefRow.TypeSemantics.Class)
            {
                writer.Write(cls.TypeDef.IsSealed);
                writer.Write(cls.TypeDef.IsAbstract);
                if (cls.ParentTypeSpec == null)
                    writer.Write((uint)0);
                else
                    writer.Write(1 + fileBuilder.IndexTypeSpecTag(RpaTagFactory.CreateTypeTag(cls.ParentTypeSpec)));
            }

            writer.Write((uint)cls.ExplicitInterfaces.Count);
            foreach (CLRTypeSpec typeSpec in cls.ExplicitInterfaces)
                writer.Write(fileBuilder.IndexTypeSpecTag(RpaTagFactory.CreateTypeTag(typeSpec)));

            WriteVtableThunks(fileBuilder, writer, cls);

            if (cls.TypeDef.Semantics == CLRTypeDefRow.TypeSemantics.Class)
            {
                uint numNonAbstractMethods = 0;

                foreach (CppMethod method in cls.Methods)
                {
                    if (!method.Abstract)
                        numNonAbstractMethods++;
                }

                writer.Write(numNonAbstractMethods);

                foreach (CppMethod method in cls.Methods)
                {
                    if (method.Abstract)
                        continue;

                    writer.Write(method.Static);
                    writer.Write(fileBuilder.IndexMethodSignatureTag(RpaTagFactory.CreateMethodSignature(method.MethodSignature)));
                    writer.Write(fileBuilder.IndexString(method.Name));
                    ExportMethodCode(fileBuilder, writer, cls, method);
                }

                uint numInstanceFields = 0;
                foreach (CppField field in cls.Fields)
                {
                    CLRFieldRow fieldDef = field.Field;
                    if (!fieldDef.Literal && !fieldDef.Static)
                        numInstanceFields++;
                }

                writer.Write(numInstanceFields);
                foreach (CppField field in cls.Fields)
                {
                    CLRFieldRow fieldDef = field.Field;
                    if (!fieldDef.Literal && !fieldDef.Static)
                    {
                        writer.Write(fileBuilder.IndexTypeSpecTag(RpaTagFactory.CreateTypeTag(field.Type)));
                        writer.Write(fileBuilder.IndexString(field.Name));
                    }
                }

                WriteInterfaceImplementations(fileBuilder, writer, cls);
            }
        }
Пример #15
0
        private void ExportMethodCode(Clarity.Rpa.HighFileBuilder fileBuilder, BinaryWriter writer, CppClass cls, CppMethod method)
        {
            if (method.Abstract)
                throw new ArgumentException("Can't export code of an abstract method");

            if (method.MethodDef.Method == null)
                writer.Write(true);
            else
            {
                writer.Write(false);

                if (!method.Abstract && method.MethodDef.Method != null)
                    CppCilExporter.WriteMethodCode(fileBuilder, writer, this, cls, method);
            }
        }
Пример #16
0
        public void ResolveInherit(CppBuilder builder, CppClass parentClass, IEnumerable<CLRTypeSpec> interfaces, CLRTypeSpec parentTypeSpec)
        {
            // There are a LOT of tricky slotting cases here.
            // See TestNewSlotImplementation, TestSlotDivergence, and TestImplementNonVirtual for some sample cases.
            //
            // Roughly how this works:
            // 1.) Override vtable slots based on matching:
            //     - If a method is ReuseSlot, then it overrides a slot no matter what
            //     - If a method is NewSlot, then it creates a slot
            // 2.) Implement MethodImpls and interfaces as cross-slot thunks
            //
            // Two notable complications with this:
            //
            // In Clarity, we only implement the specified interface once in a given class's heirarchy, but
            // reimplemented interfaces need to emit new mappings because the reimplementation can change how the
            // interface is implemented.  For example, if a parent class implements an interface method by match,
            // and then a derived class hides that method with a newslot and reimplements the interface, then the
            // interface must link to the newslot method.
            //
            // This is further complicated by the II.12.2 dispatch rules, which have errors.
            //
            // We might be able to optimize this a bit if we can detect that a method reimplementation is the
            // same as the one that already exists.
            //
            // The second complication is that Roslyn sometimes emits useless but apparently legal .override
            // directives that "override" a parent class implementation with the same method that already overrides
            // it from reuseslot matching.

            ParentTypeSpec = parentTypeSpec;

            if (parentClass != null)
            {
                m_allVtableSlots.AddRange(parentClass.m_allVtableSlots);

                List<CppVtableSlot> parentOverrideVisibleSlots = new List<CppVtableSlot>(parentClass.m_overrideVisibleVtableSlots);

                foreach (CppMethod method in m_methods)
                {
                    if (method.Virtual)
                    {
                        if (method.CreatesSlot != null)
                            RemoveOverrides(parentOverrideVisibleSlots, method.CreatesSlot);

                        if (method.Overrides)
                        {
                            List<int> overrideIndexes = FindOverrideIndexes(parentOverrideVisibleSlots, method.Name, method.MethodSignature);
                            if (overrideIndexes.Count != 1)
                                throw new ParseFailedException("Method did not override exactly one slot");
                            method.ReplacesStandardSlot = parentOverrideVisibleSlots[overrideIndexes[0]];
                        }
                    }
                }

                if (m_newImplementationVisibleVtableSlots.Count != 0)
                    throw new Exception();

                foreach (CppMethod method in m_methods)
                {
                    if (method.Virtual && method.MethodDef.MemberAccess == CLRMethodDefRow.MethodMemberAccess.Public)
                    {
                        if (method.Overrides)
                            m_newImplementationVisibleVtableSlots.Add(method.ReplacesStandardSlot);
                        else
                            m_newImplementationVisibleVtableSlots.Add(method.CreatesSlot);
                    }
                }

                m_overrideVisibleVtableSlots.AddRange(parentOverrideVisibleSlots);
            }

            if (parentClass != null)
            {
                // Remove already-implemented interfaces from this class's set, but keep reimplementations
                // to resolve them again
                List<CLRTypeSpec> dedupedInterfaces = new List<CLRTypeSpec>();
                List<CLRTypeSpec> reimplementedInterfaces = new List<CLRTypeSpec>();
                List<CLRTypeSpec> allInheritedInterfaces = new List<CLRTypeSpec>();

                allInheritedInterfaces.AddRange(parentClass.m_newlyImplementedInterfaces);
                allInheritedInterfaces.AddRange(parentClass.m_inheritedImplementedInterfaces);
                foreach (CLRTypeSpec ifc in m_newlyImplementedInterfaces)
                {
                    if (allInheritedInterfaces.Contains(ifc))
                        reimplementedInterfaces.Add(ifc);
                    else
                        dedupedInterfaces.Add(ifc);
                }

                m_newlyImplementedInterfaces = dedupedInterfaces;
                m_reimplementedInterfaces = reimplementedInterfaces;

                m_inheritedFields.AddRange(parentClass.m_inheritedFields);
                m_inheritedFields.AddRange(parentClass.m_fields);

                m_inheritedImplementedInterfaces = allInheritedInterfaces;

                m_inheritedPassiveIfcConversions.AddRange(parentClass.m_passiveIfcConversions);
                m_inheritedPassiveIfcConversions.AddRange(parentClass.m_inheritedPassiveIfcConversions);

                IsValueType = (parentClass.FullName == "System.ValueType" && this.FullName != "System.Enum") || parentClass.FullName == "System.Enum";
                IsEnum = parentClass.FullName == "System.Enum";

                IsMulticastDelegate = (parentClass.FullName == "System.MulticastDelegate");
                IsDelegate = IsMulticastDelegate || (parentClass.FullName == "System.Delegate" && this.FullName != "System.MulticastDelegate");
                HaveInheritedStaticFields = (parentClass.HaveInheritedStaticFields || parentClass.HaveNewStaticFields);

                if (IsDelegate)
                {
                    foreach (CppMethod method in m_methods)
                    {
                        if (method.Name == "Invoke")
                        {
                            DelegateSignature = method.MethodSignature;
                            break;
                        }
                    }

                    if (DelegateSignature == null)
                        throw new ParseFailedException("Malformed delegate");
                }
            }
        }
Пример #17
0
        private void WriteInterfaceImplementations(Clarity.Rpa.HighFileBuilder fileBuilder, BinaryWriter writer, CppClass cls)
        {
            if (cls.TypeDef.Semantics != CLRTypeDefRow.TypeSemantics.Class)
                throw new ArgumentException();

            List<CppVtableSlot> requiredVTableSlots = new List<CppVtableSlot>();

            uint numNewInterfaces = (uint)cls.NewlyImplementedInterfaces.Count;
            uint numReimplementedInterfaces = (uint)cls.ReimplementedInterfaces.Count;

            List<KeyValuePair<CLRTypeSpec, bool>> reqBindings = new List<KeyValuePair<CLRTypeSpec, bool>>();

            foreach (CLRTypeSpec ts in cls.NewlyImplementedInterfaces)
                reqBindings.Add(new KeyValuePair<CLRTypeSpec, bool>(ts, false));
            foreach (CLRTypeSpec ts in cls.ReimplementedInterfaces)
                reqBindings.Add(new KeyValuePair<CLRTypeSpec, bool>(ts, true));

            writer.Write((uint)reqBindings.Count);

            List<BoundInterfaceMethodImpl> boundImpls = new List<BoundInterfaceMethodImpl>();

            foreach (CLRMethodImplRow methodImpl in cls.TypeDef.MethodImplementations)
            {
                CppVtableSlot decl = ResolveMethodImplReference(methodImpl.MethodDeclaration);
                CppVtableSlot body = ResolveMethodImplReference(methodImpl.MethodBody);
                CLRTypeSpec spec = m_assemblies.InternTypeDefOrRefOrSpec(methodImpl.Class);

                if (decl.Equals(body))
                {
                    // Roslyn sometimes emits redundant MethodImpls that override the vtable slot
                    // that the method already occupies via ReuseSlot.  We want to ignore these.
                    continue;
                }

                boundImpls.Add(new BoundInterfaceMethodImpl(spec, decl, body));
            }

            foreach (KeyValuePair<CLRTypeSpec, bool> convPair in reqBindings)
            {
                CLRTypeSpec conv = convPair.Key;
                bool isReimpl = convPair.Value;

                writer.Write(fileBuilder.IndexTypeSpecTag(RpaTagFactory.CreateTypeTag(conv)));

                CppClass ifcClass = this.GetCachedClass(conv);

                writer.Write((uint)ifcClass.Methods.Count);

                foreach (CppMethod method in ifcClass.Methods)
                {
                    CppVtableSlot slot = method.CreatesSlot;
                    if (slot == null)
                        throw new ArgumentException();

                    bool isExplicitlyBound = false;
                    for (int i = 0; i < boundImpls.Count; i++)
                    {
                        BoundInterfaceMethodImpl bimi = boundImpls[i];
                        if (bimi.InterfaceSlot.DisambigSpec.Equals(conv) &&
                            bimi.InterfaceSlot.Name == slot.Name && bimi.InterfaceSlot.Signature.Equals(slot.Signature))
                        {
                            isExplicitlyBound = true;

                            writer.Write(true);    // HACK - FIXME
                            WriteInterfaceBinding(fileBuilder, writer, bimi.InterfaceSlot, bimi.ClassSlot);
                            boundImpls.RemoveAt(i);
                            break;
                        }
                    }

                    if (!isExplicitlyBound)
                    {
                        // Look for a matching slot
                        // This should follow the rules of II.12.2
                        // Because Clarity does not support virtual generic methods, maintaining a
                        // per-slot implementation list is not necessary.  However, duplicate slots
                        // from generic type substitution are still allowed.
                        //
                        // We depend on visible vtable slots being in method declaration order already,
                        // so the only thing we really need to do is return the first one.
                        //
                        // .NET has some additional non-standardized behavior: If a reimplemented interface
                        // doesn't have a new match since the last time it was implemented, then the implementation
                        // has NO MATCHES.  This matters because since interface dispatch is done per-class,
                        // per-method, a variant interface that does have a match will take priority if it's
                        // higher in the class hierarchy.
                        //
                        // See TestInheritedImplementationDeprioritization for an example of this.
                        bool haveMatch = WriteSignatureMatchedBinding(fileBuilder, writer, cls, slot, conv);

                        // If there's no match, but this is a reimplementation, then use the old implementation
                        // Allows TestInheritedReimpl to pass.
                        if (!haveMatch)
                        {
                            if (!isReimpl)
                                throw new ParseFailedException("Unmatched interface method");

                            writer.Write(false);    // HACK - FIXME
                        }
                    }
                }
            }

            if (boundImpls.Count > 0)
                throw new NotSupportedException("Don't support non-interface override thunks yet");
        }
Пример #18
0
        private bool IsClassBasedOn(CppClass cls, CLRTypeSpec to)
        {
            foreach (CLRTypeSpec newIfc in cls.NewlyImplementedInterfaces)
            {
                if (IsGenericVariantAssignableTo(newIfc, to))
                    return true;
            }

            if (cls.ParentTypeSpec == null)
                return false;

            if (cls.ParentTypeSpec.Equals(to))
                return true;

            return IsClassBasedOn(m_builder.GetCachedClass(cls.ParentTypeSpec), to);
        }
Пример #19
0
        public CppClass CreateClassFromType(CLRTypeSpec typeSpec)
        {
            if (typeSpec is CLRTypeSpecClass)
            {
                // TODO: Check typedef premades
                CLRTypeSpecClass tsClass = (CLRTypeSpecClass)typeSpec;
                CLRTypeDefRow typeDef = tsClass.TypeDef;

                CppClass cls = new CppClass(tsClass);
                foreach (CLRFieldRow fieldRow in typeDef.Fields)
                    cls.AddField(m_assemblies, fieldRow);
                foreach (CLRMethodDefRow methodRow in typeDef.MethodDefs)
                    cls.AddMethod(m_assemblies, methodRow);

                CppClass parentClass = null;
                CLRTypeSpec parentTypeSpec = null;
                if (typeDef.Extends != null)
                {
                    parentTypeSpec = m_assemblies.InternTypeDefOrRefOrSpec(typeDef.Extends);
                    parentClass = GetCachedClass(parentTypeSpec);
                }

                List<CLRTypeSpec> interfaces = new List<CLRTypeSpec>();

                foreach (CLRTableRow ii in typeDef.ImplementedInterfaces)
                {
                    CLRTypeSpec ifc = m_assemblies.InternTypeDefOrRefOrSpec(ii);
                    cls.AddExplicitInterface(this, ifc);
                    interfaces.Add(ifc);
                }
                cls.ResolveInherit(this, parentClass, interfaces, parentTypeSpec);

                return cls;
            }
            else if (typeSpec is CLRTypeSpecGenericInstantiation)
            {
                CLRTypeSpecGenericInstantiation gi = (CLRTypeSpecGenericInstantiation)typeSpec;
                CppClass baseClass = GetCachedClass(gi.GenericType);
                return baseClass.Instantiate(gi.ArgTypes, null);
            }
            else
                throw new NotImplementedException();
        }