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