public static void WriteTypeDefinitions( CodeTextWriter tw, ITypeInformation declaredType) { if (declaredType.IsPrimitive || !(declaredType.IsValueType || declaredType.IsReferenceType)) { return; } tw.WriteLine("////////////////////////////////////////////////////////////"); tw.WriteLine( "// [1] {0}", declaredType.FriendlyName); tw.SplitLine(); // IL2C vtable model case [1]: // // public class A : IB { // public int F1; // public string F2; // public virtual int Calc(int a, int b); // } // public interface IB { // int Calc(int a, int b); // } // // +----------------------+ // | IL2C_REF_HEADER | // +----------------------+ <-- this__ A_VTABLE__ // | vptr0__ | -------------> +--------------------+ // +----------------------+ | [0] | // | vptr_A_IB__ | ----------+ | ToString() | // +----------------------+ | | GetHashCode() | // | int F1 | | | Finalize() | // | string F2 | | | Equals() | // +----------------------+ | | Calc() | // | +--------------------+ // | A_IB_VTABLE__ // +--> +--------------------+ // | [offset__] | // | ToString() | // | GetHashCode() | // | Finalize() | // | Equals() | // | Calc() | // +--------------------+ var declaredOverrideMethods = declaredType.DeclaredOverrideMethods; var declaredNewslotMethods = declaredType.DeclaredNewslotMethods; var allNewslotMethods = declaredType.AllNewslotMethods; // If virtual method collection doesn't contain newslot method at this declared type: if (!declaredNewslotMethods.Any(method => method.DeclaringType.Equals(declaredType))) { // (The typedef alias contains into prototype definitions.) } // Require new VTable layout. else { if (declaredType.IsInterface) { tw.WriteLine( "// [1-2-2] {0} VTable layout", declaredType.MemberTypeName); } else { tw.WriteLine( "// [1-2-3] {0} VTable layout (Derived from {1})", declaredType.MemberTypeName, declaredType.BaseType.FriendlyName); } tw.WriteLine( "struct {0}_VTABLE_DECL___", declaredType.MangledUniqueName); tw.WriteLine("{"); using (var _ = tw.Shift()) { // This makes adjustor-thunk free VTable. tw.WriteLine("intptr_t offset__; // Adjustor offset"); // Write only visible methods because virtual method collection contains the explicitly implementation methods. var vtableMethods = allNewslotMethods. Where(method => method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly); // Rename function name if the method declareted NOT top of override. var functionDeclarationNames = new HashSet <string>(); var vtableRenamedMethods = vtableMethods. Reverse(). Select(method => functionDeclarationNames.Add(method.CLanguageFunctionName) ? method.CLanguageFunctionNamedType : method.CLanguageFunctionFullNamedType). Reverse(); // Write VTable layout. foreach (var methodName in vtableRenamedMethods) { tw.WriteLine("{0};", methodName); } } tw.WriteLine("};"); tw.SplitLine(); } // The NativeTypeAttribute doesn't write the layout structure because it aliased from the native C language type. if (declaredType.NativeType != null) { } // Delegate types doesn't write the layout structure because it's same as System.MulticastDelegate. else if (declaredType.IsDelegate) { } // Write a enum: else if (declaredType.IsEnum) { tw.WriteLine( "// [1-1-1] {0} layout", declaredType.MemberTypeName); // Emit enum values: // Unfortunately the enum type at C language doesn't have the strict underlying type. // IL2C emits the enum types using not C language syntax. foreach (var field in declaredType.Fields.Where(field => field.HasConstant)) { tw.WriteLine( "/* {0} */ static const {1} {2}_{3} = {4};", declaredType.AttributeDescription, declaredType.CLanguageTypeName, declaredType.MangledUniqueName, field.Name, Utilities.GetCLanguageExpression(field.DeclaredValue)); } tw.SplitLine(); } // Write a class/interface/struct: else { tw.WriteLine( "// [1-1-2] {0} layout", declaredType.MemberTypeName); tw.WriteLine( "/* {0} */ struct {1}", declaredType.AttributeDescription, declaredType.MangledUniqueName); tw.WriteLine("{"); using (var _ = tw.Shift()) { var tookInterfaceTypes = new HashSet <ITypeInformation>(); var fields = declaredType. Traverse(type => type.BaseType). Reverse(). SelectMany(type => { // The vptr can contain only one unique interface type. var interfaceTypes = new List <ITypeInformation>(); // Emit interface vptr (class/interface) if (declaredType.IsClass || declaredType.IsInterface) { foreach (var interfaceType in type.InterfaceTypes) { if (tookInterfaceTypes.Add(interfaceType)) { interfaceTypes.Add(interfaceType); } } } var vptrs = interfaceTypes. Select(interfaceType => new { Name = string.Format( "vptr_{0}__", interfaceType.MangledUniqueName), TypeName = string.Format( "{0}_VTABLE_DECL__*", interfaceType.MangledUniqueName), Required = true }); var thisFields = type.Fields. // It's instance field Where(field => !field.IsStatic). Select(field => new { Name = field.MangledName, TypeName = field.FieldType.CLanguageTypeName, // This field's public or at the declared type. // If not it, we have to declare the field but symbol name will be hide. // TODO: We have to calculate totally shadowing fields between base type to derived type. Required = field.IsPublic || field.IsFamily || field.IsFamilyOrAssembly || field.DeclaringType.Equals(declaredType) }); return(vptrs.Concat(thisFields)); }). Select((entry, index) => entry.Required ? new { entry.Name, entry.TypeName } : new { Name = string.Format("baseField{0}__", index), entry.TypeName }). ToArray(); // Emit vptr (class/interface) if (declaredType.IsClass || declaredType.IsInterface) { tw.WriteLine( "{0}_VTABLE_DECL__* vptr0__;", declaredType.MangledUniqueName); } if (fields.Length >= 1) { // Emit fields. foreach (var field in fields) { tw.WriteLine( "{0} {1};", field.TypeName, field.Name); } } else { // HACK: Zero-sized value type can't directly translate to the C structure. // Because ANSI C structure must have one or more fields and construct SIZED storage. // IL2C hacks for the zero-sized value type, inserts a dummy field into it. if (declaredType.IsValueType) { Debug.Assert(declaredType.InternalStaticSizeOfValue == 0); tw.WriteLine("// The struct meaning size to zero. It doesn't use anything. It has validity for C compiler."); tw.WriteLine("uint8_t dummy_for_c_compiler__;"); } } } tw.WriteLine("};"); tw.SplitLine(); } // VTable substance not required for interface type. if (!declaredType.IsInterface) { // If virtual method collection doesn't contain reuseslot and newslot method at declared types: if (!declaredOverrideMethods.Any() && !declaredNewslotMethods.Any()) { tw.WriteLine( "// [1-5-1] VTable (Same as {0})", declaredType.BaseType.FriendlyName); tw.WriteLine( "#define {0}_VTABLE__ {1}_VTABLE__", declaredType.MangledUniqueName, declaredType.BaseType.MangledUniqueName); } // Require new vtable else if (declaredType.AllOverrideMethods.All(method => !method.IsAbstract)) { tw.WriteLine( "// [1-5-2] VTable (Derived from {0})", declaredType.BaseType.FriendlyName); tw.WriteLine( "extern {0}_VTABLE_DECL__ {0}_VTABLE__;", declaredType.MangledUniqueName); } tw.SplitLine(); } tw.WriteLine( "// [1-4] Runtime type information"); tw.WriteLine( "IL2C_DECLARE_RUNTIME_TYPE({0});", declaredType.MangledUniqueName); tw.SplitLine(); }
public bool IsAssignableFrom(ITypeInformation rhs) { if (this.Equals(rhs)) { return(true); } // Class <-- untyped type // Interface <-- untyped type // Pointer <-- untyped type if ((this.IsClass || this.IsInterface || this.IsPointer) && rhs.IsUntypedReferenceType) { return(true); } // BaseClass <-- DerivedClass // BaseClass <-- DerivedArray if (this.IsClass && (rhs.IsClass || rhs.IsArray)) { return(rhs. Traverse(type => type.BaseType, true). Any(this.Equals)); } // BaseArray <-- DerivedArray (covariant) if (this.IsArray && rhs.IsArray) { return(rhs. Traverse(type => type.BaseType, true). Any(type => type.IsArray && this.ElementType.Equals(type.ElementType))); } // System.Object <-- Any if (this.IsObjectType) { return(true); } // System.ValueType <-- ValueType if (this.IsValueTypeType && rhs.IsValueType) { return(true); } // IBase <-- DerivedClass // IBase <-- IDerived if (this.IsInterface) { return(rhs. Traverse(type => type.BaseType). Any(type => type.InterfaceTypes.Any(this.Equals))); } // HACK: Special case lhs is runtime handles. if (this.MetadataContext.RuntimeFieldHandle.Equals(this) && rhs.IsUntypedReferenceType) { return(true); } return(false); }