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; }
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; }
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); }
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); }
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); }
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; }
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); }
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); }