Example #1
0
        private CliClass(CliClass baseClass, Compiler compiler, TypeSpecTag[] argTypes)
        {
            if (!baseClass.m_isCreated)
                throw new Exception("Can't instantiate an open class that hasn't been processed");

            m_typeName = baseClass.m_typeName;
            m_parentClassSpec = (TypeSpecClassTag)baseClass.m_parentClassSpec.Instantiate(compiler.TagRepository, argTypes);
            m_parentClass = compiler.GetClosedClass(m_parentClassSpec);
            m_isSealed = baseClass.m_isSealed;
            m_isAbstract = baseClass.m_isAbstract;
            m_isStruct = baseClass.m_isStruct;
            m_typeSpec = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(new TypeSpecClassTag(m_typeName, argTypes));

            m_isCreated = baseClass.m_isCreated;

            m_numGenericParameters = baseClass.m_numGenericParameters;

            List<HighField> staticFields = new List<HighField>();
            foreach (HighField fld in baseClass.m_staticFields)
                staticFields.Add(fld.Instantiate(compiler.TagRepository, argTypes));

            m_staticFields = staticFields.ToArray();

            List<HighMethod> methods = new List<HighMethod>();
            foreach (HighMethod method in baseClass.m_methods)
                methods.Add(method.Instantiate(compiler.TagRepository, argTypes));
            m_methods = methods.ToArray();

            List<HighField> instanceFields = new List<HighField>();
            foreach (HighField fld in baseClass.m_instanceFields)
                instanceFields.Add(fld.Instantiate(compiler.TagRepository, argTypes));
            m_instanceFields = instanceFields.ToArray();

            List<CliVtableSlot> vtableSlots = new List<CliVtableSlot>();
            foreach (CliVtableSlot slot in baseClass.m_vtable)
                vtableSlots.Add(slot.Instantiate(compiler, argTypes));
            m_vtable = vtableSlots.ToArray();

            List<CliInterfaceImpl> interfaceImpls = new List<CliInterfaceImpl>();
            foreach (CliInterfaceImpl ifcImpl in baseClass.m_interfaceImpls)
                interfaceImpls.Add(ifcImpl.Instantiate(compiler, argTypes));
            m_interfaceImpls = interfaceImpls.ToArray();

            List<TypeSpecClassTag> explicitInterfaces = new List<TypeSpecClassTag>();
            foreach (TypeSpecClassTag ifc in baseClass.m_explicitInterfaceSpecs)
                explicitInterfaces.Add((TypeSpecClassTag)ifc.Instantiate(compiler.TagRepository, argTypes));
            m_explicitInterfaceSpecs = explicitInterfaces.ToArray();

            m_declTagToMethod = baseClass.m_declTagToMethod;
            m_declTagToVTableSlot = baseClass.m_declTagToVTableSlot;
            m_ifcToIfcSlot = baseClass.m_ifcToIfcSlot;
            m_nameToInstanceFieldSlot = baseClass.m_nameToInstanceFieldSlot;
            m_nameToStaticFieldSlot = baseClass.m_nameToStaticFieldSlot;
        }
Example #2
0
        public PodFlags GetClassPodFlags(Compiler compiler, CliClass cls)
        {
            PodFlags podFlags = PodFlags.None;
            foreach (HighField fld in cls.InstanceFields)
            {
                TypeSpecTag fldType = fld.Type;

                if (!compiler.TypeIsValueType(fldType))
                    return PodFlags.None;

                CliClass fldClass = compiler.GetClosedClass((TypeSpecClassTag)fldType);

                podFlags &= GetClassPodFlags(compiler, fldClass);
                if (podFlags == PodFlags.None)
                    return PodFlags.None;
            }

            return podFlags;
        }
Example #3
0
        private ConversionType ResolveClassBasedOn(CliClass cls, TypeSpecTag to)
        {
            HighTypeDef typeDef = m_compiler.GetTypeDef(cls.TypeSpec.TypeName);

            foreach (CliInterfaceImpl newIfc in cls.InterfaceImpls)
            {
                if (ResolveGenericVariantAssignableTo(newIfc.Interface, to) != ConversionType.NotConvertible)
                    return ConversionType.ClassToInterface;
            }

            if (cls.ParentClassSpec == null)
                return ConversionType.NotConvertible;

            if (cls.ParentClassSpec == to)
                return ConversionType.ClassToClass;

            return ResolveClassBasedOn(m_compiler.GetClosedClass(cls.ParentClassSpec), to);
        }
Example #4
0
        private MethodSpecTag ResolveVirtualMethod(Compiler compiler, CliClass cls, CliMethodIndex methodIndex)
        {
            uint depth = methodIndex.Depth;
            CliClass methodClass = cls;
            while (depth > 0)
            {
                methodClass = methodClass.ParentClass;
                depth--;
            }

            HighMethod method = methodClass.Methods[methodIndex.Index];
            if (method.IsStatic)
                throw new RpaCompileException("Vtable slot implementation is static");

            MethodSpecTag methodSpec = new MethodSpecTag(MethodSlotType.Instance, new TypeSpecTag[0], methodClass.TypeSpec, method.MethodDeclTag);
            return compiler.TagRepository.InternMethodSpec(methodSpec);
        }
Example #5
0
        private void ResolveTDOForClass(CliClass cls)
        {
            if (cls.ParentClass != null)
                ResolveTDOForClass(cls.ParentClass);

            foreach (CliInterfaceImpl impl in cls.InterfaceImpls)
            {
                TypeSpecClassTag ifcSpec = impl.Interface;
                if (!m_typeDeclarationOrder.ContainsKey(ifcSpec))
                    m_typeDeclarationOrder.Add(ifcSpec, (uint)m_typeDeclarationOrder.Count);
            }

            m_typeDeclarationOrder.Add(cls.TypeSpec, (uint)m_typeDeclarationOrder.Count);
        }
Example #6
0
        public bool Create(Compiler compiler)
        {
            HighTypeDef typeDef = compiler.GetTypeDef(m_typeName);

            TypeSpecClassTag parentClassSpec = null;
            HighClassVtableSlot[] newSlots;
            HighClassVtableSlot[] replacedSlots;
            HighInterfaceImplementation[] typeInterfaceImpls;

            if (typeDef.Semantics == TypeSemantics.Struct || typeDef.Semantics == TypeSemantics.Class)
            {
                if (typeDef.Semantics == TypeSemantics.Struct)
                {
                    m_isStruct = true;
                    TypeNameTag valueTypeName = new TypeNameTag("mscorlib", "System", "ValueType", 0, null);
                    valueTypeName = compiler.TagRepository.InternTypeName(valueTypeName);
                    TypeSpecClassTag vtClassTag = new TypeSpecClassTag(valueTypeName, new TypeSpecTag[0]);
                    vtClassTag = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(vtClassTag);

                    parentClassSpec = vtClassTag;
                }
                else if (typeDef.Semantics == TypeSemantics.Class)
                {
                    m_isStruct = false;
                    parentClassSpec = typeDef.ParentClass;

                    RestrictedExtensionType thisRet = GetRestrictedExtensionType(m_typeName);

                    if (parentClassSpec == null)
                    {
                        if (thisRet != RestrictedExtensionType.Object)
                            throw new Exception("Parentless class is not [mscorlib]System.Object");
                    }
                    else
                    {
                        if (thisRet == RestrictedExtensionType.Object)
                            throw new Exception("[mscorlib]System.Object has a parent");

                        RestrictedExtensionType parentRet = GetRestrictedExtensionType(parentClassSpec.TypeName);

                        bool isExtensionOK = false;
                        switch (parentRet)
                        {
                            case RestrictedExtensionType.ValueType:
                                if (thisRet == RestrictedExtensionType.Enum)
                                    isExtensionOK = true;
                                break;
                            case RestrictedExtensionType.Delegate:
                                if (thisRet == RestrictedExtensionType.MulticastDelegate)
                                    isExtensionOK = true;
                                break;
                            case RestrictedExtensionType.Enum:
                            case RestrictedExtensionType.MulticastDelegate:
                            case RestrictedExtensionType.NullableSZArray:
                            case RestrictedExtensionType.RefSZArray:
                            case RestrictedExtensionType.ValueSZArray:
                                break;
                            case RestrictedExtensionType.Object:
                            case RestrictedExtensionType.None:
                                isExtensionOK = true;
                                break;
                            case RestrictedExtensionType.Array:
                                if (thisRet == RestrictedExtensionType.NullableSZArray || thisRet == RestrictedExtensionType.ValueSZArray || thisRet == RestrictedExtensionType.RefSZArray)
                                    isExtensionOK = true;
                                break;
                            default:
                                throw new ArgumentException();
                        }

                        if (!isExtensionOK)
                            throw new Exception("Invalid extension of a restricted class");
                    }
                }

                m_instanceFields = typeDef.InstanceFields;
                m_methods = typeDef.Methods;
                m_staticFields = typeDef.StaticFields;
                m_isSealed = typeDef.IsSealed;
                m_isAbstract = typeDef.IsAbstract;

                replacedSlots = typeDef.ReplacedSlots;
                newSlots = typeDef.NewSlots;
                typeInterfaceImpls = typeDef.InterfaceImpls;
            }
            else if (typeDef.Semantics == TypeSemantics.Delegate)
            {
                m_isStruct = false;

                TypeNameTag dgTypeName = new TypeNameTag("mscorlib", "System", typeDef.IsMulticastDelegate ? "MulticastDelegate" : "Delegate", 0, null);
                dgTypeName = compiler.TagRepository.InternTypeName(dgTypeName);
                TypeSpecClassTag dgClassTag = new TypeSpecClassTag(dgTypeName, new TypeSpecTag[0]);
                dgClassTag = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(dgClassTag);

                parentClassSpec = dgClassTag;

                m_instanceFields = new HighField[0];
                m_methods = new HighMethod[0];
                m_staticFields = new HighField[0];
                m_isSealed = false;
                m_isAbstract = true;

                replacedSlots = new HighClassVtableSlot[0];

                MethodDeclTag invokeTag = new MethodDeclTag("Invoke", typeDef.DelegateSignature, m_typeName);
                invokeTag = compiler.TagRepository.InternMethodDeclTag(invokeTag);

                HighClassVtableSlot invokeSlot = new HighClassVtableSlot(invokeTag, typeDef.DelegateSignature, null, true, false);

                newSlots = new HighClassVtableSlot[1] { invokeSlot };

                typeInterfaceImpls = new HighInterfaceImplementation[0];
            }
            else if (typeDef.Semantics == TypeSemantics.Enum)
            {
                m_isStruct = false;

                TypeNameTag dgTypeName = new TypeNameTag("mscorlib", "System", "Enum", 0, null);
                dgTypeName = compiler.TagRepository.InternTypeName(dgTypeName);
                TypeSpecClassTag dgClassTag = new TypeSpecClassTag(dgTypeName, new TypeSpecTag[0]);
                dgClassTag = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(dgClassTag);

                parentClassSpec = dgClassTag;

                string underlyingTypeName;
                switch (typeDef.UnderlyingType)
                {
                    case HighTypeDef.EnumUnderlyingType.Int8:
                        underlyingTypeName = "SByte";
                        break;
                    case HighTypeDef.EnumUnderlyingType.Int16:
                        underlyingTypeName = "Int16";
                        break;
                    case HighTypeDef.EnumUnderlyingType.Int32:
                        underlyingTypeName = "Int32";
                        break;
                    case HighTypeDef.EnumUnderlyingType.Int64:
                        underlyingTypeName = "Int64";
                        break;
                    case HighTypeDef.EnumUnderlyingType.UInt8:
                        underlyingTypeName = "Byte";
                        break;
                    case HighTypeDef.EnumUnderlyingType.UInt16:
                        underlyingTypeName = "Int16";
                        break;
                    case HighTypeDef.EnumUnderlyingType.UInt32:
                        underlyingTypeName = "UInt32";
                        break;
                    case HighTypeDef.EnumUnderlyingType.UInt64:
                        underlyingTypeName = "UInt64";
                        break;
                    default:
                        throw new Exception();
                }

                TypeNameTag underlyingTypeNameTag = new TypeNameTag("mscorlib", "System", underlyingTypeName);
                underlyingTypeNameTag = compiler.TagRepository.InternTypeName(underlyingTypeNameTag);

                TypeSpecClassTag underlyingTypeSpec = new TypeSpecClassTag(underlyingTypeNameTag, new TypeSpecTag[0]);
                underlyingTypeSpec = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(underlyingTypeSpec);

                HighField fld = new HighField("value__", underlyingTypeSpec);

                m_instanceFields = new HighField[1] { fld };
                m_methods = new HighMethod[0];
                m_staticFields = new HighField[0];
                m_isSealed = true;
                m_isAbstract = false;

                replacedSlots = new HighClassVtableSlot[0];
                newSlots = new HighClassVtableSlot[0];
                typeInterfaceImpls = new HighInterfaceImplementation[0];
            }
            else
                throw new ArgumentException();

            if (parentClassSpec != null)
            {
                if (compiler.GetTypeDef(parentClassSpec.TypeName).Semantics != TypeSemantics.Class)
                    throw new RpaCompileException("Can't extend class with non-class semantics");

                if (!compiler.HaveCliOpenClass(parentClassSpec.TypeName))
                    return false;

                CliClass parentClass = compiler.GetClosedClass(parentClassSpec);

                if (parentClass.m_isSealed)
                    throw new RpaCompileException("Can't extend sealed CLI class");

                m_parentClass = parentClass;
            }

            m_numGenericParameters = typeDef.NumGenericParameters;

            // Update vtable
            {
                Dictionary<MethodDeclTag, uint> declTagToMethod = new Dictionary<MethodDeclTag, uint>();
                uint methodIndex = 0;
                foreach (HighMethod method in m_methods)
                {
                    if (declTagToMethod.ContainsKey(method.MethodDeclTag))
                        throw new Exception("Duplicate method declaration");

                    declTagToMethod.Add(method.MethodDeclTag, methodIndex++);
                }
                m_declTagToMethod = declTagToMethod;
            }

            m_declTagToVTableSlot = new Dictionary<MethodDeclTag, uint>();
            m_ifcToIfcSlot = new Dictionary<TypeSpecClassTag, uint>();
            List<CliVtableSlot> slots = new List<CliVtableSlot>();

            if (m_parentClass != null)
            {
                foreach (KeyValuePair<MethodDeclTag, uint> dttvs in m_parentClass.m_declTagToVTableSlot)
                    m_declTagToVTableSlot.Add(dttvs.Key, dttvs.Value);

                foreach (CliVtableSlot parentSlot in m_parentClass.m_vtable)
                {
                    CliMethodIndex methodIndex = parentSlot.MethodIndex;

                    if (methodIndex == null)
                        slots.Add(parentSlot);
                    else
                    {
                        CliMethodIndex newIndex = new CliMethodIndex(methodIndex.Depth + 1, methodIndex.Index);
                        slots.Add(new CliVtableSlot(newIndex, parentSlot.MethodSignature, parentSlot.IsSealed));
                    }
                }
            }

            foreach (HighClassVtableSlot slot in replacedSlots)
            {
                uint index;
                if (!m_declTagToVTableSlot.TryGetValue(slot.SlotTag, out index))
                    throw new Exception("Unmatched vtable slot replacement");
                CliVtableSlot existingSlot = slots[(int)index];
                if (existingSlot.IsSealed)
                    throw new Exception("Can't replace sealed vtable slot");

                if (existingSlot.MethodSignature != slot.Signature)
                    throw new Exception("VTable slot override signature doesn't match");

                CliMethodIndex methodIndex = null;
                if (!slot.IsAbstract)
                {
                    HighMethod method;
                    methodIndex = this.FindMethod(slot.ImplementingMethodTag, out method);
                    if (method.MethodSignature != slot.Signature)
                        throw new Exception("Signature of method used by vtable slot doesn't match vtable slot's signature");
                }

                slots[(int)index] = new CliVtableSlot(methodIndex, slot.Signature, slot.IsFinal);
            }

            foreach (HighClassVtableSlot slot in newSlots)
            {
                CliMethodIndex methodIndex = null;
                if (!slot.IsAbstract)
                {
                    HighMethod method;
                    methodIndex = this.FindMethod(slot.ImplementingMethodTag, out method);
                    if (method.MethodSignature != slot.Signature)
                        throw new Exception("Signature of method used by vtable slot doesn't match vtable slot's signature");
                }

                m_declTagToVTableSlot.Add(slot.SlotTag, (uint)slots.Count);
                slots.Add(new CliVtableSlot(methodIndex, slot.Signature, slot.IsFinal));
            }

            m_vtable = slots.ToArray();

            if (!m_isAbstract)
                foreach (CliVtableSlot slot in m_vtable)
                    if (slot.MethodIndex == null)
                        throw new RpaCompileException("Non-abstract class has unoverrided abstract methods");

            m_nameToInstanceFieldSlot = new Dictionary<string, uint>();
            for (uint i = 0; i < m_instanceFields.Length; i++)
            {
                string fldName = m_instanceFields[i].Name;
                if (m_nameToInstanceFieldSlot.ContainsKey(fldName))
                    throw new RpaCompileException("Duplicate field name");
                m_nameToInstanceFieldSlot.Add(fldName, i);
            }

            m_nameToStaticFieldSlot = new Dictionary<string, uint>();
            for (uint i = 0; i < m_staticFields.Length; i++)
            {
                string fldName = m_staticFields[i].Name;
                if (m_nameToStaticFieldSlot.ContainsKey(fldName))
                    throw new RpaCompileException("Duplicate field name");
                m_nameToStaticFieldSlot.Add(fldName, i);
            }

            HashSet<TypeSpecClassTag> explicitImpls = new HashSet<TypeSpecClassTag>();
            List<CliInterfaceImpl> interfaceImpls = new List<CliInterfaceImpl>();
            foreach (HighInterfaceImplementation ifcImpl in typeInterfaceImpls)
            {
                if (!explicitImpls.Add(ifcImpl.Interface))
                    throw new Exception("Duplicate interface implementation");

                interfaceImpls.Add(ResolveInterfaceImpl(compiler, ifcImpl));
            }

            m_interfaceImpls = interfaceImpls.ToArray();
            m_parentClassSpec = parentClassSpec;

            m_explicitInterfaceSpecs = typeDef.ParentInterfaces;
            if (m_explicitInterfaceSpecs == null)
                m_explicitInterfaceSpecs = new TypeSpecClassTag[0];

            List<TypeSpecTag> thisGenericParameters = new List<TypeSpecTag>();
            for (uint i = 0; i < m_numGenericParameters; i++)
            {
                TypeSpecGenericParamTypeTag gptt = new TypeSpecGenericParamTypeTag(TypeSpecGenericParamTypeTag.Values.Var);
                TypeSpecGenericParamTag gpTag = new TypeSpecGenericParamTag(gptt, i);
                gpTag = (TypeSpecGenericParamTag)compiler.TagRepository.InternTypeSpec(gpTag);

                thisGenericParameters.Add(gpTag);
            }

            TypeSpecClassTag thisClass = new TypeSpecClassTag(m_typeName, thisGenericParameters.ToArray());
            thisClass = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(thisClass);

            m_typeSpec = thisClass;

            m_typeDeclarationOrder = new Dictionary<TypeSpecClassTag, uint>();
            ResolveTDOForClass(this);

            m_isCreated = true;

            return true;
        }
Example #7
0
        private uint RecursiveDevirtualizeInterfaceMethod(CliClass cls, TypeSpecClassTag ifcSpec, uint ifcSlotIndex)
        {
            // First, look for an exact match, but only on this class level
            foreach (CliInterfaceImpl impl in cls.InterfaceImpls)
            {
                if (impl.Interface == ifcSpec)
                {
                    CliInterfaceImplSlot slot = impl.IfcSlotToClassVtableSlot[ifcSlotIndex];
                    // Only use the exact match if it has a new implementation.
                    // This is non-standard, but reflects .NET's behavior.
                    // See TestInheritedImplementationDeprioritization.
                    if (slot.HaveNewImpl)
                        return slot.ClassVTableSlot;
                    break;
                }
            }

            // Otherwise, check all interfaces
            uint? bestSlotTDO = null;
            CliInterfaceImplSlot? bestSlot = null;
            foreach (CliInterfaceImpl impl in cls.InterfaceImpls)
            {
                TypeSpecClassTag implInterface = impl.Interface;

                if (m_assignabilityResolver.ResolveGenericVariantAssignableTo(ifcSpec, implInterface) == AssignabilityResolver.ConversionType.InterfaceToInterface)
                {
                    CliInterfaceImplSlot slot = impl.IfcSlotToClassVtableSlot[ifcSlotIndex];
                    if (slot.HaveNewImpl)
                    {
                        uint tdo = cls.TypeDeclarationOrder[implInterface];
                        if (bestSlotTDO.HasValue == false || tdo < bestSlotTDO)
                        {
                            bestSlotTDO = tdo;
                            bestSlot = slot;
                        }
                    }
                }
            }

            if (bestSlot.HasValue)
                return bestSlot.Value.ClassVTableSlot;

            CliClass parentClass = cls.ParentClass;
            if (parentClass == null)
                throw new Exception("Internal error: Unresolvable interface method");

            return RecursiveDevirtualizeInterfaceMethod(parentClass, ifcSpec, ifcSlotIndex);
        }
Example #8
0
        public uint DevirtualizeInterfaceMethod(CliClass cls, TypeSpecClassTag ifcSpec, uint ifcSlotIndex)
        {
            if (!cls.IsSealed)
                throw new ArgumentException("Can't devirtualize a non-sealed class");

            if (GetTypeDef(ifcSpec.TypeName).Semantics != TypeSemantics.Interface)
                throw new ArgumentException("Can't devirtualize an implementation of a non-interface");

            return RecursiveDevirtualizeInterfaceMethod(cls, ifcSpec, ifcSlotIndex);
        }