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); }
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(); }
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"); } }
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); } }
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)); } } }
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); }
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; }
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; }
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); } } }
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); } } }
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"); }
private void ExportClassStubs(CppClass cls) { //CppStubExporter.ExportStub(this, m_stubDir, cls); }
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)); } } }
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); } }
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); } }
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"); } } }
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"); }
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); }
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(); }