From 248278d267c148af9bfbc6745dd674875b77214b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Oct 2017 10:18:08 -0300 Subject: [PATCH] generator: Use a new AbiStruct object to handle wrapped type ABI This allows us to totally get rid of the glue as this new class handles bitfields and union properly. --- Source/generator/ClassBase.cs | 83 +++++++++----- Source/generator/CodeGenerator.cs | 15 ++- Source/generator/EnumGen.cs | 5 + Source/generator/FieldBase.cs | 10 +- Source/generator/GenBase.cs | 8 ++ Source/generator/GenerationInfo.cs | 82 ++++++++++++- Source/generator/IGeneratable.cs | 6 + Source/generator/ManualGen.cs | 19 +++- Source/generator/ObjectBase.cs | 5 +- Source/generator/ObjectGen.cs | 3 +- Source/generator/OpaqueGen.cs | 2 +- Source/generator/PropertyBase.cs | 4 +- Source/generator/SimpleBase.cs | 8 ++ Source/generator/SimpleGen.cs | 10 +- Source/generator/StructABIField.cs | 92 +++++++++++++-- Source/generator/StructBase.cs | 16 +-- Source/generator/StructField.cs | 113 ++++++++++++++---- Source/generator/StructGen.cs | 1 - Source/generator/SymbolTable.cs | 36 ++++-- Source/generator/UnionABIField.cs | 100 ++++++++++++---- Source/glib/AbiField.cs | 177 +++++++++++++++++++++++++++++ Source/glib/AbiStruct.cs | 142 +++++++++++++++++++++++ Source/glib/Cond.cs | 5 + Source/glib/HookList.cs | 114 +++++++++++++++++++ Source/glib/Mutex.cs | 5 + Source/glib/Object.cs | 53 ++++++++- Source/glib/RecMutex.cs | 7 ++ Source/glib/meson.build | 5 +- 28 files changed, 1011 insertions(+), 115 deletions(-) create mode 100644 Source/glib/AbiField.cs create mode 100644 Source/glib/AbiStruct.cs create mode 100644 Source/glib/HookList.cs diff --git a/Source/generator/ClassBase.cs b/Source/generator/ClassBase.cs index 67d22a2cb..9e037909f 100644 --- a/Source/generator/ClassBase.cs +++ b/Source/generator/ClassBase.cs @@ -71,7 +71,7 @@ namespace GtkSharp.Generation { } protected ClassBase (XmlElement ns, XmlElement elem) : base (ns, elem) { - + deprecated = elem.GetAttributeAsBoolean ("deprecated"); isabstract = elem.GetAttributeAsBoolean ("abstract"); abi_fields_valid = true; @@ -147,7 +147,7 @@ namespace GtkSharp.Generation { } } - protected virtual bool CanGenerateABIStruct(LogWriter log) { + public virtual bool CanGenerateABIStruct(LogWriter log) { return (abi_fields_valid); } @@ -165,7 +165,7 @@ namespace GtkSharp.Generation { if (parent != null) { // FIXME Add that information to ManualGen and use it. if (parent.CName == "GInitiallyUnowned" || parent.CName == "GObject") { - cs_parent_struct = "GLib.Object.GObject"; + cs_parent_struct = "GLib.Object"; } else { parent_can_generate = false; var _parent = parent as ClassBase; @@ -175,9 +175,8 @@ namespace GtkSharp.Generation { parent_can_generate = _parent.CheckABIStructParent(log, out tmp); } - if (parent_can_generate) { - cs_parent_struct = cs_parent + "._" + parent.CName + "ABI"; - } + if (parent_can_generate) + cs_parent_struct = cs_parent; } if (!parent_can_generate) { @@ -191,16 +190,6 @@ namespace GtkSharp.Generation { return parent_can_generate; } - protected virtual void WriteInstanceOffsetMethod(StreamWriter sw, - string cs_parent_struct) { - string cs_parent = SymbolTable.Table.GetCSType(Elem.GetAttribute("parent")); - - if (cs_parent_struct == "") - sw.WriteLine ("\t\tpublic static uint instance_offset { get { return 0; }}"); - else - sw.WriteLine ("\t\tpublic static new uint instance_offset {{ get {{ return ((uint) Marshal.SizeOf(typeof ({0})) + {1}.instance_offset); }} }}", cs_parent_struct, cs_parent); - } - protected void GenerateStructureABI (GenerationInfo gen_info) { string cs_parent_struct = null; @@ -213,21 +202,54 @@ namespace GtkSharp.Generation { var _new = ""; if (cs_parent_struct != "") - _new = "new"; + _new = "new "; - WriteInstanceOffsetMethod(sw, cs_parent_struct); sw.WriteLine (); - sw.WriteLine ("\t\tpublic " + _new + " unsafe uint GetFieldOffset(string field) {"); - sw.WriteLine ("\t\t\treturn (uint) (instance_offset + (uint) Marshal.OffsetOf(typeof({0}), field));", - (QualifiedName + "._" + CName + "ABI")); + sw.WriteLine ("\t\t// Internal representation of the wrapped structure ABI."); + sw.WriteLine ("\t\tstatic GLib.AbiStruct _abi_info = null;"); + sw.WriteLine ("\t\tstatic public " + _new + "GLib.AbiStruct abi_info {"); + sw.WriteLine ("\t\t\tget {"); + sw.WriteLine ("\t\t\t\tif (_abi_info == null)"); + sw.WriteLine ("\t\t\t\t\t_abi_info = new GLib.AbiStruct (new List{ "); + + // Generate Tests + if (abi_fields.Count > 0 && gen_info.CAbiWriter != null) { + gen_info.CAbiWriter.WriteLine("\tg_print(\"\\\"sizeof({0}.{1})\\\": \\\"%\" G_GOFFSET_FORMAT \"\\\"\\n\", sizeof({2}));", NS, Name, CName); + gen_info.AbiWriter.WriteLine("\t\t\tConsole.WriteLine(\"\\\"sizeof({0}.{1})\\\": \\\"\" + {0}.{1}.abi_info.Size + \"\\\"\");", NS, Name); + } + + StructABIField prev = null; + StructABIField next = null; + + StringWriter field_alignment_structures_writer = new StringWriter(); + for(int i=0; i < abi_fields.Count; i++) { + var field = abi_fields[i]; + next = abi_fields.Count > i +1 ? abi_fields[i + 1] : null; + + prev = field.Generate(gen_info, "\t\t\t\t\t", prev, next, cs_parent_struct, + field_alignment_structures_writer); + var union = field as UnionABIField; + if (union == null && gen_info.CAbiWriter != null) { + gen_info.AbiWriter.WriteLine("\t\t\tConsole.WriteLine(\"\\\"{0}.{1}.{2}\\\": \\\"\" + {0}.{1}.abi_info.GetFieldOffset(\"{2}\") + \"\\\"\");", NS, Name, field.CName); + gen_info.CAbiWriter.WriteLine("\tg_print(\"\\\"{0}.{1}.{2}\\\": \\\"%\" G_GOFFSET_FORMAT \"\\\"\\n\", G_STRUCT_OFFSET({3}, {2}));", NS, Name, field.CName, CName); + } + + } + + if (abi_fields.Count > 0 && gen_info.CAbiWriter != null) { + gen_info.AbiWriter.Flush(); + gen_info.CAbiWriter.Flush(); + } + + sw.WriteLine ("\t\t\t\t\t});"); + sw.WriteLine (); + sw.WriteLine ("\t\t\t\treturn _abi_info;"); + sw.WriteLine ("\t\t\t}"); sw.WriteLine ("\t\t}"); sw.WriteLine (); - sw.WriteLine ("\t\t[StructLayout (LayoutKind.Sequential)]"); - sw.WriteLine ("\t\tpublic struct _" + CName + "ABI" + " {"); - foreach (StructABIField field in abi_fields) - field.Generate (gen_info, "\t\t\t"); - sw.WriteLine ("\t\t}"); + sw.WriteLine (field_alignment_structures_writer.ToString()); + sw.WriteLine ("\t\t// End of the ABI representation."); sw.WriteLine (); } @@ -251,6 +273,10 @@ namespace GtkSharp.Generation { if (!abi_field.Validate(log)) abi_fields_valid = false; } + if (abi_fields_valid) + foreach (StructABIField abi_field in abi_fields) { + abi_field.SetGetOffseName(); + } ArrayList invalids = new ArrayList (); @@ -348,8 +374,9 @@ namespace GtkSharp.Generation { protected void GenFields (GenerationInfo gen_info) { - foreach (ObjectField field in fields.Values) + foreach (ObjectField field in fields.Values) { field.Generate (gen_info, "\t\t"); + } } protected void GenConstants (GenerationInfo gen_info) @@ -391,7 +418,7 @@ namespace GtkSharp.Generation { foreach (Method method in methods.Values) { if (IgnoreMethod (method, implementor)) - continue; + continue; string oname = null, oprotection = null; if (collisions != null && collisions.ContainsKey (method.Name)) { diff --git a/Source/generator/CodeGenerator.cs b/Source/generator/CodeGenerator.cs index 812126dc1..8cd7d513f 100644 --- a/Source/generator/CodeGenerator.cs +++ b/Source/generator/CodeGenerator.cs @@ -34,9 +34,13 @@ namespace GtkSharp.Generation { public static int Main (string[] args) { bool show_help = false; + bool all_opaque = true; string dir = ""; string assembly_name = ""; string gapidir = ""; + string abi_cs_usings = ""; + string abi_cs_file = ""; + string abi_c_file = ""; string glue_filename = ""; string glue_includes = ""; string gluelib_name = ""; @@ -59,6 +63,12 @@ namespace GtkSharp.Generation { (string v) => { assembly_name = v; } }, { "gapidir=", "GAPI xml data folder.", (string v) => { gapidir = v; } }, + { "abi-cs-filename=", "Filename for the generated CSharp ABI checker.", + (string v) => { abi_cs_file = v; } }, + { "abi-cs-usings=", "Namespaces to use in the CS ABI checker.", + (string v) => { abi_cs_usings = v; } }, + { "abi-c-filename=", "Filename for the generated C ABI checker.", + (string v) => { abi_c_file = v; } }, { "glue-filename=", "Filename for the generated C glue code.", (string v) => { glue_filename = v; } }, { "glue-includes=", "Content of #include directive to add in the generated C glue code.", @@ -130,7 +140,8 @@ namespace GtkSharp.Generation { GenerationInfo gen_info = null; if (dir != "" || assembly_name != "" || glue_filename != "" || glue_includes != "" || gluelib_name != "") - gen_info = new GenerationInfo (dir, assembly_name, glue_filename, glue_includes, gluelib_name); + gen_info = new GenerationInfo (dir, assembly_name, glue_filename, glue_includes, gluelib_name, + abi_c_file, abi_cs_file, abi_cs_usings); foreach (IGeneratable gen in gens) { if (gen_info == null) @@ -142,7 +153,7 @@ namespace GtkSharp.Generation { ObjectGen.GenerateMappers (); if (gen_info != null) - gen_info.CloseGlueWriter (); + gen_info.CloseWriters (); Statistics.Report(); return 0; diff --git a/Source/generator/EnumGen.cs b/Source/generator/EnumGen.cs index f7e1dc737..16081d8e2 100644 --- a/Source/generator/EnumGen.cs +++ b/Source/generator/EnumGen.cs @@ -82,6 +82,11 @@ namespace GtkSharp.Generation { { return "(" + QualifiedName + ") " + var; } + + public override string GenerateAlign () { + return null; + } + public override void Generate (GenerationInfo gen_info) { diff --git a/Source/generator/FieldBase.cs b/Source/generator/FieldBase.cs index dbe962125..9cd6c8078 100644 --- a/Source/generator/FieldBase.cs +++ b/Source/generator/FieldBase.cs @@ -27,6 +27,8 @@ namespace GtkSharp.Generation { public abstract class FieldBase : PropertyBase { public FieldBase abi_field = null; + string getterName, setterName; + protected string getOffsetName, offsetName; public FieldBase (XmlElement elem, ClassBase container_type) : base (elem, container_type) {} public FieldBase (XmlElement elem, ClassBase container_type, FieldBase abi_field) : base (elem, container_type) { @@ -97,13 +99,13 @@ namespace GtkSharp.Generation { } private bool UseABIStruct(GenerationInfo gen_info) { + if (!container_type.CanGenerateABIStruct(new LogWriter(container_type.CName))) + return false; + return (abi_field != null && abi_field.getOffsetName != null && gen_info.GlueWriter == null); } - string getterName, setterName; - protected string getOffsetName, offsetName; - void CheckGlue (GenerationInfo gen_info) { getterName = setterName = getOffsetName = null; @@ -112,7 +114,7 @@ namespace GtkSharp.Generation { if (UseABIStruct(gen_info)) { getOffsetName = abi_field.getOffsetName; - offsetName = "GetFieldOffset(\"" + ((StructField)abi_field).EqualityName + "\")"; + offsetName = "abi_info.GetFieldOffset(\"" + ((StructField)abi_field).CName + "\")"; return; } diff --git a/Source/generator/GenBase.cs b/Source/generator/GenBase.cs index d7fce7f10..b0d9f57bb 100644 --- a/Source/generator/GenBase.cs +++ b/Source/generator/GenBase.cs @@ -96,6 +96,14 @@ namespace GtkSharp.Generation { public abstract bool Validate (); + public virtual string GenerateGetSizeOf () { + return null; + } + + public virtual string GenerateAlign () { + return null; + } + public void Generate () { GenerationInfo geninfo = new GenerationInfo (ns); diff --git a/Source/generator/GenerationInfo.cs b/Source/generator/GenerationInfo.cs index 07ec9477b..3472aff2e 100644 --- a/Source/generator/GenerationInfo.cs +++ b/Source/generator/GenerationInfo.cs @@ -33,7 +33,11 @@ namespace GtkSharp.Generation { string gluelib_name; bool glue_enabled; StreamWriter sw; + StreamWriter abiwriter = null; + StreamWriter cabiwriter = null; StreamWriter glue_sw; + string abicfile = null; + string abicsfile = null; public GenerationInfo (XmlElement ns) { @@ -43,17 +47,23 @@ namespace GtkSharp.Generation { assembly_name = ns_name.ToLower () + "-sharp"; } - public GenerationInfo (string dir, string assembly_name) : this (dir, assembly_name, "", "", "") {} + public GenerationInfo (string dir, string assembly_name) : + this (dir, assembly_name, "", "", "", "", "", "") {} - public GenerationInfo (string dir, string assembly_name, string glue_filename, string glue_includes, string gluelib_name) + public GenerationInfo (string dir, string assembly_name, string glue_filename, + string glue_includes, string gluelib_name, string abi_c_file, + string abi_cs_file, string abi_cs_usings) { this.dir = dir; this.assembly_name = assembly_name; this.gluelib_name = gluelib_name; - InitializeGlue (glue_filename, glue_includes, gluelib_name); + abicfile = abi_c_file; + abicsfile = abi_cs_file; + InitializeWriters (glue_filename, glue_includes, gluelib_name, abi_cs_usings); } - void InitializeGlue (string glue_filename, string glue_includes, string gluelib_name) + void InitializeWriters (string glue_filename, string glue_includes, string gluelib_name, + string abi_cs_usings) { if (gluelib_name != String.Empty && glue_filename != String.Empty) { FileStream stream; @@ -79,6 +89,44 @@ namespace GtkSharp.Generation { } glue_enabled = true; } + + if (cabiwriter == null && abicfile != "" && abicsfile != "" && abi_cs_usings != "") { + var stream = new FileStream (abicfile, FileMode.Create, FileAccess.Write); + cabiwriter = new StreamWriter (stream); + cabiwriter.WriteLine ("// This file was generated by the Gtk# code generator."); + cabiwriter.WriteLine ("// Any changes made will be lost if regenerated."); + cabiwriter.WriteLine (); + + if (glue_includes != "") { + foreach (string header in glue_includes.Split (new char[] {',', ' '})) { + if (header != "") + cabiwriter.WriteLine ("#include <{0}>", header); + } + cabiwriter.WriteLine (""); + } + + cabiwriter.WriteLine ("int main (int argc, char *argv[]) {"); + + stream = new FileStream (abicsfile, FileMode.Create, FileAccess.Write); + abiwriter = new StreamWriter (stream); + abiwriter.WriteLine ("// This file was generated by the Gtk# code generator."); + abiwriter.WriteLine ("// Any changes made will be lost if regenerated."); + abiwriter.WriteLine (); + + var name = ""; + foreach (string _using in abi_cs_usings.Split (new char[] {',', ' '})) { + if (_using != "") { + abiwriter.WriteLine ("using {0};", _using); + if (name == "") + name = _using; + } + } + abiwriter.WriteLine ("using System;"); + abiwriter.WriteLine (); + abiwriter.WriteLine ("namespace AbiTester {"); + abiwriter.WriteLine ("\tclass ___" + name + " {"); + abiwriter.WriteLine ("\t\tpublic static void Main (string[] args) {"); + } } public string AssemblyName { @@ -87,6 +135,18 @@ namespace GtkSharp.Generation { } } + public StreamWriter AbiWriter { + get { + return abiwriter; + } + } + + public StreamWriter CAbiWriter { + get { + return cabiwriter; + } + } + public string Dir { get { return dir; @@ -120,10 +180,22 @@ namespace GtkSharp.Generation { } } - public void CloseGlueWriter () + public void CloseWriters () { if (glue_sw != null) glue_sw.Close (); + + if (cabiwriter != null) { + cabiwriter.WriteLine ("\treturn 0;"); + cabiwriter.WriteLine ("}"); + cabiwriter.Close(); + + abiwriter.WriteLine ("\t\t}"); + abiwriter.WriteLine ("\t}"); + abiwriter.WriteLine ("}"); + abiwriter.Close(); + + } } string member; diff --git a/Source/generator/IGeneratable.cs b/Source/generator/IGeneratable.cs index 5a7d9ea26..a91b5003b 100644 --- a/Source/generator/IGeneratable.cs +++ b/Source/generator/IGeneratable.cs @@ -48,6 +48,12 @@ namespace GtkSharp.Generation { // Generates an expression to convert var from MarshalType string FromNative (string var); + // Generates code to get size of the type + string GenerateGetSizeOf (); + + // Generates code to get size of the type + string GenerateAlign (); + bool Validate (); void Generate (); diff --git a/Source/generator/ManualGen.cs b/Source/generator/ManualGen.cs index b12fc73b7..78a67b67f 100644 --- a/Source/generator/ManualGen.cs +++ b/Source/generator/ManualGen.cs @@ -27,6 +27,7 @@ namespace GtkSharp.Generation { public class ManualGen : SimpleBase { string from_fmt; + string abi_type; public ManualGen (string ctype, string type) : base (ctype, type, "null") { @@ -37,13 +38,25 @@ namespace GtkSharp.Generation { { this.from_fmt = from_fmt; } - + + public ManualGen (string ctype, string type, string from_fmt, string abi_type) : base (ctype, type, "null") + { + this.from_fmt = from_fmt; + this.abi_type = abi_type; + } + public override string MarshalType { get { return "IntPtr"; } } + public string AbiType { + get { + return abi_type; + } + } + public override string CallByName (string var_name) { return var_name + " == null ? IntPtr.Zero : " + var_name + ".Handle"; @@ -53,6 +66,10 @@ namespace GtkSharp.Generation { { return String.Format (from_fmt, var); } + + public override string GenerateGetSizeOf () { + return "(uint) Marshal.SizeOf(typeof(" + abi_type + "))"; + } } } diff --git a/Source/generator/ObjectBase.cs b/Source/generator/ObjectBase.cs index dcd200d61..ebb6a9e02 100644 --- a/Source/generator/ObjectBase.cs +++ b/Source/generator/ObjectBase.cs @@ -187,7 +187,7 @@ namespace GtkSharp.Generation { } } - protected override bool CanGenerateABIStruct(LogWriter log) { + public override bool CanGenerateABIStruct(LogWriter log) { if (!abi_fields_valid) { log.Info(CName + " has invalid fields"); @@ -338,5 +338,8 @@ namespace GtkSharp.Generation { return true; } + public override string GenerateGetSizeOf () { + return NS + "." + Name + ".abi_info.GetABISize()"; + } } } diff --git a/Source/generator/ObjectGen.cs b/Source/generator/ObjectGen.cs index f355663f7..5d873d09d 100644 --- a/Source/generator/ObjectGen.cs +++ b/Source/generator/ObjectGen.cs @@ -175,7 +175,6 @@ namespace GtkSharp.Generation { sw.WriteLine (" {"); sw.WriteLine (); - GenerateStructureABI (gen_info); GenCtors (gen_info); GenProperties (gen_info, null); GenFields (gen_info); @@ -248,6 +247,7 @@ namespace GtkSharp.Generation { sw.WriteLine ("\t\t}"); } + GenerateStructureABI (gen_info); sw.WriteLine ("#endregion"); sw.WriteLine ("\t}"); @@ -426,5 +426,6 @@ namespace GtkSharp.Generation { sw.Close (); } } + } diff --git a/Source/generator/OpaqueGen.cs b/Source/generator/OpaqueGen.cs index 24fd4b3bf..c0e252620 100644 --- a/Source/generator/OpaqueGen.cs +++ b/Source/generator/OpaqueGen.cs @@ -80,7 +80,6 @@ namespace GtkSharp.Generation { sw.WriteLine (" {"); sw.WriteLine (); - GenerateStructureABI(gen_info); GenConstants (gen_info); GenFields (gen_info); GenMethods (gen_info, null, null); @@ -196,6 +195,7 @@ namespace GtkSharp.Generation { sw.WriteLine (); } + GenerateStructureABI(gen_info); sw.WriteLine ("#endregion"); sw.WriteLine ("\t}"); diff --git a/Source/generator/PropertyBase.cs b/Source/generator/PropertyBase.cs index b2cc1bb48..7f12e9a80 100644 --- a/Source/generator/PropertyBase.cs +++ b/Source/generator/PropertyBase.cs @@ -26,7 +26,7 @@ namespace GtkSharp.Generation { public abstract class PropertyBase { protected XmlElement elem; - protected ClassBase container_type; + public ClassBase container_type; public PropertyBase (XmlElement elem, ClassBase container_type) { @@ -40,7 +40,7 @@ namespace GtkSharp.Generation { } } - public string CName { + public virtual string CName { get { return elem.GetAttribute ("cname"); } diff --git a/Source/generator/SimpleBase.cs b/Source/generator/SimpleBase.cs index 4547af22c..db329e743 100644 --- a/Source/generator/SimpleBase.cs +++ b/Source/generator/SimpleBase.cs @@ -94,6 +94,14 @@ namespace GtkSharp.Generation { public void Generate (GenerationInfo gen_info) { } + + public virtual string GenerateGetSizeOf () { + return null; + } + + public virtual string GenerateAlign () { + return null; + } } } diff --git a/Source/generator/SimpleGen.cs b/Source/generator/SimpleGen.cs index 14554ab3d..209cc8089 100644 --- a/Source/generator/SimpleGen.cs +++ b/Source/generator/SimpleGen.cs @@ -24,8 +24,16 @@ namespace GtkSharp.Generation { using System; public class SimpleGen : SimpleBase { - public SimpleGen (string ctype, string type, string default_value) : base (ctype, type, default_value) {} + string size_of; + public SimpleGen (string ctype, string type, string default_value) : base (ctype, type, default_value) {} + public SimpleGen (string ctype, string type, string default_value, string size_of) : base (ctype, type, default_value) { + this.size_of = size_of; + } + + public override string GenerateGetSizeOf () { + return size_of; + } } } diff --git a/Source/generator/StructABIField.cs b/Source/generator/StructABIField.cs index 224417326..1632bb5d4 100644 --- a/Source/generator/StructABIField.cs +++ b/Source/generator/StructABIField.cs @@ -7,14 +7,23 @@ namespace GtkSharp.Generation { public class StructABIField : StructField { protected new ClassBase container_type; + public string parent_structure_name; public StructABIField (XmlElement elem, ClassBase container_type) : base (elem, container_type) { this.container_type = container_type; this.getOffsetName = null; } + public override string CName { + + get { + if (parent_structure_name != null) + return parent_structure_name + '.' + elem.GetAttribute ("cname"); + return elem.GetAttribute ("cname"); + } + } + public override void Generate (GenerationInfo gen_info, string indent) { - this.getOffsetName = "Get" + CName + "Offset"; base.Generate(gen_info, indent); } @@ -41,20 +50,89 @@ namespace GtkSharp.Generation { if (cstype == null || cstype == "") { log.Warn (" field \"" + CName + "\" has no cstype, can't generate ABI field."); - return false; } if (!base.Validate (log)) return false; - if (IsBitfield) { - log.Warn ("bitfields are not supported"); - return false; + return true; + } + + public void SetGetOffseName() { + this.getOffsetName = "Get" + CName + "Offset"; + } + + public override string GenerateGetSizeOf(string indent) { + return base.GenerateGetSizeOf(indent) + " // " + CName; + } + + public virtual StructABIField Generate (GenerationInfo gen_info, string indent, + StructABIField prev_field, StructABIField next_field, string parent_name, + TextWriter structw) { + StreamWriter sw = gen_info.Writer; + IGeneratable gen = SymbolTable.Table[CType]; + + sw.WriteLine("{0}\tnew GLib.AbiField(\"{1}\"", indent, CName); + + indent = indent + "\t\t"; + if (prev_field != null) { + sw.WriteLine(indent + ", -1"); + } else { + if (parent_name != "") + sw.WriteLine(indent + ", " + parent_name + ".abi_info.Fields"); + else + sw.WriteLine(indent + ", 0"); } - return true; + sw.WriteLine(indent + ", " + GenerateGetSizeOf("")); + + var prev_field_name = prev_field != null ? "\"" + prev_field.CName + "\"" : "null"; + sw.WriteLine(indent + ", " + prev_field_name); + + var container_name = container_type.CName.Replace(".", "_"); + var sanitized_name = CName.Replace(".", "_"); + var alig_struct_name = container_name + "_" + sanitized_name + "Align"; + var next_field_name = next_field != null ? "\"" + next_field.CName + "\"" : "null"; + sw.WriteLine(indent + ", " + next_field_name); + + if (structw != null) { + string min_align = gen != null ? gen.GenerateAlign() : null; + + // Do not generate structs if the type is a simple pointer. + if (IsCPointer()) + min_align = "(uint) Marshal.SizeOf(typeof(IntPtr))"; + + if (min_align == null) { + var tmpindent = "\t\t"; + structw.WriteLine(tmpindent + "[StructLayout(LayoutKind.Sequential)]"); + structw.WriteLine(tmpindent + "public struct " + alig_struct_name); + structw.WriteLine(tmpindent + "{"); + structw.WriteLine(tmpindent + "\tsbyte f1;"); + base.Generate(gen_info, tmpindent + "\t", true, structw); + structw.WriteLine(tmpindent + "}"); + structw.WriteLine(); + + var fieldname = SymbolTable.Table.MangleName (CName).Replace(".", "_"); + if (IsArray && IsNullTermArray) + fieldname += "Ptr"; + sw.WriteLine(indent + ", (long) Marshal.OffsetOf(typeof(" + alig_struct_name + "), \"" + fieldname + "\")"); + } else { + sw.WriteLine(indent + ", " + min_align); + } + } + + gen_info.Writer = sw; + + uint bits = 0; + var bitsstr = elem.GetAttribute("bits"); + if (bitsstr != null && bitsstr != "") + bits = (uint) Int32.Parse(bitsstr); + + sw.WriteLine(indent + ", " + bits); + sw.WriteLine(indent + "),"); + + return this; } } } - diff --git a/Source/generator/StructBase.cs b/Source/generator/StructBase.cs index 861d10faf..ad1c6b917 100644 --- a/Source/generator/StructBase.cs +++ b/Source/generator/StructBase.cs @@ -60,13 +60,6 @@ namespace GtkSharp.Generation { } } - protected override void WriteInstanceOffsetMethod(StreamWriter sw, string cs_parent_struct) { - if (cs_parent_struct == "") - sw.WriteLine ("\t\tpublic uint instance_offset { get { return 0; }}"); - else - sw.WriteLine ("\t\tpublic new uint instance_offset {{ get {{ return ((uint) Marshal.SizeOf(typeof ({0})) + base.instance_offset); }} }}", cs_parent_struct); - } - public override string DefaultValue { get { return QualifiedName + ".Zero"; @@ -134,7 +127,7 @@ namespace GtkSharp.Generation { equals.Append ("true"); foreach (StructField field in fields) { - if (field.IsPadding) + if (field.IsPadding || field.Hidden) continue; if (field.IsBitfield) { if (need_field) { @@ -217,9 +210,16 @@ namespace GtkSharp.Generation { return base.Validate (); } + public override bool CanGenerateABIStruct(LogWriter log) { + log.Info("Not generating any ABI structs for managed structures"); + + return false; + } + public override void Generate (GenerationInfo gen_info) { bool need_close = false; + if (gen_info.Writer == null) { gen_info.Writer = gen_info.OpenStream (Name, NS); need_close = true; diff --git a/Source/generator/StructField.cs b/Source/generator/StructField.cs index 3c4ed3a42..387f7c45e 100644 --- a/Source/generator/StructField.cs +++ b/Source/generator/StructField.cs @@ -41,7 +41,7 @@ namespace GtkSharp.Generation { } } - int ArrayLength { + public int ArrayLength { get { if (!IsArray) return 0; @@ -50,17 +50,17 @@ namespace GtkSharp.Generation { try { result = Int32.Parse (elem.GetAttribute("array_len")); } catch (Exception) { - LogWriter log = new LogWriter (container_type.Name + "." + Name); + LogWriter log = new LogWriter (container_type.Name + "." + Name); log.Warn("Non-numeric array_len: \"" + elem.GetAttribute("array_len") + - "\" incorrectly generated"); + "\" incorrectly generated"); result = 0; } return result; } } - bool IsNullTermArray { + public bool IsNullTermArray { get { return elem.GetAttributeAsBoolean ("null_term_array"); } } @@ -102,6 +102,54 @@ namespace GtkSharp.Generation { } } + bool IsFixedSizeArray() { + return IsArray && !IsNullTermArray && ArrayLength != 0; + } + + public bool IsCPointer() { + IGeneratable gen = SymbolTable.Table[CType]; + + return (CType.EndsWith("*") || + CType.EndsWith ("pointer") || + gen is CallbackGen || + cstype == "string" || + (CType == "guint8" && (IsArray && IsNullTermArray)) || + elem.GetAttributeAsBoolean("is_callback")); + + } + + public virtual string GenerateGetSizeOf(string indent) { + string cstype = SymbolTable.Table.GetCSType(CType, true); + string res = ""; + IGeneratable gen = SymbolTable.Table[CType]; + var is_pointer = false; + + if (IsCPointer()) { + is_pointer = true; + cstype = "IntPtr"; + } else if (gen != null) { + res = gen.GenerateGetSizeOf(); + } + + if (res != null && res != "") { + if (IsFixedSizeArray()) + res += " * " + ArrayLength; + + return indent + res; + } + + var _enum = gen as EnumGen; + if (_enum != null && !is_pointer) + res = "(uint) Marshal.SizeOf(System.Enum.GetUnderlyingType(typeof(" + cstype + ")))"; + else + res = "(uint) Marshal.SizeOf(typeof(" + cstype + "))"; + + if (IsFixedSizeArray()) + res += " * " + ArrayLength; + + return res; + } + public bool IsPadding { get { if (elem.GetAttributeAsBoolean ("is-padding")) @@ -114,7 +162,7 @@ namespace GtkSharp.Generation { public bool IsPointer { get { - return (CType.EndsWith ("*") || CType.EndsWith ("pointer")); + return IsCPointer(); } } @@ -141,60 +189,85 @@ namespace GtkSharp.Generation { public override void Generate (GenerationInfo gen_info, string indent) { - if (Hidden) + Generate(gen_info, indent, false, gen_info.Writer); + } + + public void Generate (GenerationInfo gen_info, string indent, bool use_cnames, + TextWriter sw) + { + if (Hidden && !use_cnames) return; visible = Access != "private"; - StreamWriter sw = gen_info.Writer; SymbolTable table = SymbolTable.Table; string wrapped = table.GetCSType (CType); + string wrapped_name = SymbolTable.Table.MangleName (CName); + string name = Name; + string studly_name = StudlyName; + string cstype = CSType; + IGeneratable gen = table [CType]; + if (use_cnames) { + name = studly_name = wrapped_name = SymbolTable.Table.MangleName (CName).Replace(".", "_"); + + var mangen = gen as ManualGen; + if (mangen != null) { + if (mangen.AbiType != null) + cstype = mangen.AbiType; + } + + if (IsCPointer()) + cstype = "IntPtr"; + } + if (IsArray && !IsNullTermArray) { sw.WriteLine (indent + "[MarshalAs (UnmanagedType.ByValArray, SizeConst=" + ArrayLength + ")]"); - sw.WriteLine (indent + "{0} {1} {2};", Access, CSType, StudlyName); + sw.WriteLine (indent + "{0} {1} {2};", Access, cstype, studly_name); } else if (IsArray && IsNullTermArray) { - sw.WriteLine (indent + "private {0} {1};", "IntPtr", StudlyName+ "Ptr"); + sw.WriteLine (indent + "private {0} {1};", "IntPtr", studly_name+ "Ptr"); if ((Readable || Writable) && Access == "public") { - sw.WriteLine (indent + "public {0} {1} {{", CSType, StudlyName); + sw.WriteLine (indent + "public {0} {1} {{", cstype, studly_name); if (Readable) sw.WriteLine (indent + "\tget {{ return GLib.Marshaller.StructArrayFromNullTerminatedIntPtr<{0}> ({1}); }}", - base.CSType, StudlyName + "Ptr"); + base.CSType, studly_name + "Ptr"); if (Writable) sw.WriteLine (indent + "\tset {{ {0} = GLib.Marshaller.StructArrayToNullTerminatedStructArrayIntPtr<{1}> (value); }}", - StudlyName + "Ptr", base.CSType); + studly_name + "Ptr", base.CSType); sw.WriteLine (indent + "}"); } } else if (IsBitfield) { base.Generate (gen_info, indent); } else if (gen is IAccessor) { - sw.WriteLine (indent + "private {0} {1};", gen.MarshalType, Name); + sw.WriteLine (indent + "private {0} {1};", gen.MarshalType, name); if (Access != "private") { IAccessor acc = table [CType] as IAccessor; - sw.WriteLine (indent + Access + " " + wrapped + " " + StudlyName + " {"); - acc.WriteAccessors (sw, indent + "\t", Name); + sw.WriteLine (indent + Access + " " + wrapped + " " + studly_name + " {"); + acc.WriteAccessors (sw, indent + "\t", name); sw.WriteLine (indent + "}"); } } else if (IsPointer && (gen is StructGen || gen is BoxedGen || gen is UnionGen)) { - sw.WriteLine (indent + "private {0} {1};", CSType, Name); + sw.WriteLine (indent + "private {0} {1};", cstype, name); sw.WriteLine (); if (Access != "private") { sw.WriteLine (indent + Access + " " + wrapped + " " + wrapped_name + " {"); - sw.WriteLine (indent + "\tget { return " + table.FromNative (CType, Name) + "; }"); + sw.WriteLine (indent + "\tget { return " + table.FromNative (CType, name) + "; }"); sw.WriteLine (indent + "}"); } - } else if (IsPointer && CSType != "string") { + } else if (IsPointer && cstype != "string") { // FIXME: probably some fields here which should be visible. visible = false; - sw.WriteLine (indent + "private {0} {1};", CSType, Name); + sw.WriteLine (indent + "private {0} {1};", cstype, name); } else { - sw.WriteLine (indent + "{0} {1} {2};", Access, CSType, Access == "public" ? StudlyName : Name); + sw.WriteLine (indent + "{0} {1} {2};", Access, cstype, Access == "public" ? studly_name : name); } } } } + + diff --git a/Source/generator/StructGen.cs b/Source/generator/StructGen.cs index 0be2d0a06..84c71006b 100644 --- a/Source/generator/StructGen.cs +++ b/Source/generator/StructGen.cs @@ -35,7 +35,6 @@ namespace GtkSharp.Generation { StreamWriter sw = gen_info.Writer = gen_info.OpenStream (Name, NS); base.Generate (gen_info); - GenerateStructureABI(gen_info); if (GetMethod ("GetType") == null && GetMethod ("GetGType") == null) { sw.WriteLine ("\t\tprivate static GLib.GType GType {"); sw.WriteLine ("\t\t\tget { return GLib.GType.Pointer; }"); diff --git a/Source/generator/SymbolTable.cs b/Source/generator/SymbolTable.cs index d96fff07e..e412c044d 100644 --- a/Source/generator/SymbolTable.cs +++ b/Source/generator/SymbolTable.cs @@ -128,9 +128,17 @@ namespace GtkSharp.Generation { AddType (new ManualGen ("GVariant", "GLib.Variant")); AddType (new ManualGen ("GVariantType", "GLib.VariantType")); AddType (new ManualGen ("GValueArray", "GLib.ValueArray")); - AddType (new ManualGen ("GMutex", "GLib.Mutex")); - AddType (new ManualGen ("GRecMutex", "GLib.RecMutex")); - AddType (new ManualGen ("GCond", "GLib.Cond")); + AddType (new ManualGen ("GMutex", "GLib.Mutex", + "new GLib.Mutex({0})", + "GLib.Mutex.ABI")); + + AddType (new ManualGen ("GRecMutex", + "GLib.RecMutex", + "new GLib.RecMutex({0})", + "GLib.RecMutex.ABI")); + AddType (new ManualGen ("GCond", "GLib.Cond", + "new GLib.Cond({0})", + "GLib.Cond.ABI")); AddType (new ManualGen ("GDateTime", "GLib.DateTime")); AddType (new ManualGen ("GDate", "GLib.Date")); AddType (new ManualGen ("GSource", "GLib.Source")); @@ -141,9 +149,12 @@ namespace GtkSharp.Generation { AddType (new MarshalGen ("GString", "string", "IntPtr", "new GLib.GString ({0}).Handle", "GLib.GString.PtrToString ({0})")); AddType (new MarshalGen ("GType", "GLib.GType", "IntPtr", "{0}.Val", "new GLib.GType({0})", "GLib.GType.None")); AddType (new ByRefGen ("GValue", "GLib.Value")); - AddType (new SimpleGen ("GDestroyNotify", "GLib.DestroyNotify", "null")); + AddType (new SimpleGen ("GDestroyNotify", "GLib.DestroyNotify", "null", + "(uint) Marshal.SizeOf(typeof(IntPtr))")); AddType (new SimpleGen ("GThread", "GLib.Thread", "null")); AddType (new ManualGen ("GBytes", "GLib.Bytes")); + AddType (new SimpleGen ("GHookList", "GLib.HookList", "null", + "GLib.HookList.abi_info.Size")); // FIXME: These ought to be handled properly. AddType (new SimpleGen ("GC", "IntPtr", "IntPtr.Zero")); @@ -160,6 +171,9 @@ namespace GtkSharp.Generation { AddType (new SimpleGen ("va_list", "IntPtr", "IntPtr.Zero")); AddType (new SimpleGen ("GParamSpec", "IntPtr", "IntPtr.Zero")); AddType (new SimpleGen ("gconstpointer", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GBoxedCopyFunc", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GBoxedFreeFunc", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GHookFinalizeFunc", "IntPtr", "IntPtr.Zero")); } public void AddType (IGeneratable gen) @@ -250,19 +264,19 @@ namespace GtkSharp.Generation { public string GetCSType(string c_type, bool default_pointer) { IGeneratable gen = this[c_type]; - if (gen == null) { - if (c_type.EndsWith("*") && default_pointer) - return "UintPtr"; + if (gen == null) { + if (c_type.EndsWith("*") && default_pointer) + return "IntPtr"; - return ""; - } + return ""; + } - return gen.QualifiedName; + return gen.QualifiedName; } public string GetCSType(string c_type) { - return GetCSType(c_type, false); + return GetCSType(c_type, false); } public string GetName(string c_type) diff --git a/Source/generator/UnionABIField.cs b/Source/generator/UnionABIField.cs index d51ce1212..d63189a85 100644 --- a/Source/generator/UnionABIField.cs +++ b/Source/generator/UnionABIField.cs @@ -33,27 +33,66 @@ namespace GtkSharp.Generation { } } - public void Generate(GenerationInfo gen_info, string indent){ + public string GenerateGetSize(string indent) { + var size = indent += "new List() {"; + var is_first = true; + foreach (StructABIField field in fields) { + if (!is_first) + size += ","; + is_first = false; + + size += "\"" + field.CName + "\""; + } + + return size + "}"; + } + + public void EnsureParentStructName (string parent_name) { + var name = Elem.GetAttribute("name"); + + if (!unique_field) { + parent_name = parent_name + '.' + name; + } + + StructABIField next_field = null; + foreach (var field in fields) { + field.parent_structure_name = parent_name; + } + } + + public StructField Generate(GenerationInfo gen_info, string indent, + string parent_name, StructABIField prev_field, + StructABIField next, string struct_parent_name, + TextWriter tw) + { StreamWriter sw = gen_info.Writer; var name = Elem.GetAttribute("name"); var cname = Elem.GetAttribute("cname"); - if (unique_field) { - sw.WriteLine (indent + "[FieldOffset(0)]"); - foreach (StructABIField field in fields) - field.Generate(gen_info, indent); - - return; + if (!unique_field) { + parent_name = parent_name + '.' + name; } - sw.WriteLine (indent + "struct __" + name + "{"); - foreach (StructABIField field in fields) { - field.Generate(gen_info, indent + "\t"); + StructABIField next_field = null; + sw.WriteLine(indent + "// union struct " + parent_name); + for(int i=0; i < fields.Count; i++) { + var field = fields[i]; + next_field = fields.Count > i + 1 ? fields[i + 1] : null; + + field.parent_structure_name = parent_name; + + field.Generate(gen_info, indent, prev_field, next_field, struct_parent_name, + tw); + + prev_field = field; } - sw.WriteLine (indent + "}"); - sw.WriteLine (indent + "[FieldOffset(0)]"); - sw.WriteLine (indent + "private __" + name + " " + cname + ";"); + + sw.WriteLine(indent + "// End " + parent_name); + sw.WriteLine(); + + return prev_field; } + } public class UnionABIField : StructABIField { @@ -70,18 +109,41 @@ namespace GtkSharp.Generation { } } - public override void Generate (GenerationInfo gen_info, string indent) { + public override StructABIField Generate (GenerationInfo gen_info, string indent, + StructABIField prev_field, StructABIField next_field, string parent_name, + TextWriter tw) { StreamWriter sw = gen_info.Writer; var name = Elem.GetAttribute("name"); var cname = Elem.GetAttribute("cname"); - sw.WriteLine (indent + "[StructLayout(LayoutKind.Explicit)]"); - sw.WriteLine (indent + "struct __" + name + " {"); + foreach (UnionSubstruct _struct in substructs) + _struct.EnsureParentStructName(cname); + foreach (UnionSubstruct _struct in substructs) { - _struct.Generate(gen_info, indent + "\t"); + _struct.Generate(gen_info, indent + "\t", cname, prev_field, + next_field, parent_name, tw); } - sw.WriteLine (indent + "}"); - sw.WriteLine (indent + "private __" + name + " " + cname + ";"); + + base.Generate(gen_info, indent, prev_field, next_field, parent_name, null); + + + return this; + } + + public override string GenerateGetSizeOf(string indent) { + string res = indent + "new List>() { // union " + Elem.GetAttribute("cname") + "\n"; + bool first = true; + + indent += "\t\t\t"; + foreach (UnionSubstruct _struct in substructs) { + if (!first) + res += ",\n"; + first = false; + res += _struct.GenerateGetSize(indent + "\t\t\t"); + } + res += "\n" + indent + "\t\t }"; + + return res; } public override bool Validate (LogWriter log) diff --git a/Source/glib/AbiField.cs b/Source/glib/AbiField.cs new file mode 100644 index 000000000..e02187279 --- /dev/null +++ b/Source/glib/AbiField.cs @@ -0,0 +1,177 @@ +// AbiField.cs - Utility to handle complex C structure ABI. +// +// Authors: Thibault Saunier +// +// Copyright (c) 2017 Thibault Saunier +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser GNU General +// Public License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +// Helper utility to build C structure ABI even when using complex +// packing with union and bit fields. It basically uses the same +// logic as what is done inside csharp implementation (marshal.c in +// the mono codebase) but handling more things. +namespace GLib { + + using System; + using System.Collections.Generic; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Linq; + using System.Collections.Specialized; + using System.CodeDom.Compiler; + + public class AbiField { + public string Prev_name; + public string Next_name; + public string Name; + public long Offset; + public long Align; + public uint Natural_size; + public AbiStruct container; + public OrderedDictionary Parent_fields; // field_name -> AbiField<> dictionary. + List> Union_fields; + + long End; + long Size; + public uint Bits; + + public AbiField(string name, + long offset, + uint natural_size, + string prev_fieldname, + string next_fieldname, + long align, + uint bits) + { + Name = name; + Offset = offset; + Natural_size = natural_size; + Prev_name = prev_fieldname; + Next_name = next_fieldname; + End = -1; + Size = -1; + Union_fields = null; + Align = (long) align; + Bits = bits; + + if (Bits > 0) { + var nbytes = (uint) (Math.Ceiling((double) Bits / (double) 8)); + + if (nbytes < GetSize()) + Align = 1; + else // Like if no bitfields were used. + Bits = 0; + } + } + + public AbiField(string name, + OrderedDictionary parent_fields, + uint natural_size, + string prev_fieldname, + string next_fieldname, + long align, + uint bits): this (name, -1, + natural_size, prev_fieldname, next_fieldname, align, bits) + { + Parent_fields = parent_fields; + } + + + public AbiField(string name, + long offset, + List> fields_lists, + string prev_fieldname, + string next_fieldname, uint bits): this(name, + offset, (uint) 0, prev_fieldname, next_fieldname, + -1, bits) + { + Union_fields = fields_lists; + } + + public uint GetEnd() { + if (End == -1) + End = (long) GetOffset() + GetSize(); + + return (uint) End; + } + + public uint GetOffset() { + return (uint) Offset; + } + + public bool InUnion () { + return Name.Contains("."); + } + + public uint GetAlign () { + if (Union_fields != null) { + uint align = 1; + + foreach (var fieldnames in Union_fields) { + foreach (var fieldname in fieldnames) { + var field = (AbiField) container.Fields[fieldname]; + align = Math.Max(align, field.GetAlign()); + } + } + + return align; + + } + + return (uint) Align; + } + + public uint GetUnionSize() { + uint size = 0; + + foreach (var fieldnames in Union_fields) { + + foreach (var fieldname in fieldnames) { + var field = ((AbiField) container.Fields[fieldname]); + var align = field.GetAlign(); + + if (field.Prev_name != null) { + var prev = ((AbiField)container.Fields[field.Prev_name]); + + if (!prev.InUnion()) + field.Offset = Offset; + else + field.Offset = prev.GetEnd(); + } + + field.Offset += align - 1; + field.Offset &= ~(align - 1); + + size = Math.Max(size, field.GetEnd() - (uint) Offset); + } + } + + return size; + } + + public uint GetSize() { + if (Size != -1) + return (uint) Size; + + if (Union_fields != null) { + Size = GetUnionSize(); + } else { + Size = Natural_size; + } + + return (uint) Size; + } + } +} diff --git a/Source/glib/AbiStruct.cs b/Source/glib/AbiStruct.cs new file mode 100644 index 000000000..6fec730d1 --- /dev/null +++ b/Source/glib/AbiStruct.cs @@ -0,0 +1,142 @@ +// AbiField.cs - Utility to handle complex C structure ABI. +// +// Authors: Thibault Saunier +// +// Copyright (c) 2017 Thibault Saunier +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser GNU General +// Public License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +// Helper utility to build C structure ABI even when using complex +// packing with union and bit fields. It basically uses the same +// logic as what is done inside csharp implementation (marshal.c in +// the mono codebase) but handling more things. +namespace GLib { + + using System; + using System.Collections.Generic; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Linq; + using System.Collections.Specialized; + using System.CodeDom.Compiler; + + public class AbiStruct { + public OrderedDictionary Fields = null; + + public AbiStruct(List fields) { + Fields = new OrderedDictionary(); + + foreach (var field in fields) + Fields[field.Name] = field; + + Load(); + } + + static uint GetMinAlign(OrderedDictionary fields) { + uint align = 1; + + for (var i = 0; i < fields.Count; i++) { + var field = ((GLib.AbiField) fields[i]); + + if (field.Parent_fields != null) { + align = Math.Max(align, GetMinAlign(field.Parent_fields)); + } + align = Math.Max(align, field.GetAlign()); + } + + return align; + } + + public uint Align { + get { + return GetMinAlign(Fields); + } + } + + void Load () { + long bitfields_offset = -1; + long bitfields_size = -1; + + for (var i = 0; i < Fields.Count; i++ ) { + var field = (AbiField) Fields[i]; + field.container = this; + var align = field.GetAlign(); + + if (field.InUnion()) + continue; + + if (field.Prev_name != null) { + field.Offset = ((AbiField)Fields[field.Prev_name]).GetEnd(); + } else if (field.Parent_fields != null) { + field.Offset = GetStructureSize(field.Parent_fields); + } + + field.Offset += align - 1; + field.Offset &= ~(align - 1); + + if (field.Bits > 0) { + // Pack all following bitfields into the same area. + if (bitfields_offset == -1) { + uint nbits = 0; + + bitfields_offset = field.Offset; + for (var j = i + 1; j < Fields.Count; j++ ) { + var nfield = (AbiField) Fields[j]; + if (nfield.Bits > 0) + nbits += nfield.Bits; + } + + bitfields_size = (long) (Math.Ceiling((double) field.Bits / (double) 8)); + } + + field.Offset = (uint) bitfields_offset; + field.Natural_size = (uint) bitfields_size; + } else { + bitfields_offset = bitfields_size = -1; + } + + } + } + + public uint GetFieldOffset(string field) { + return ((AbiField) Fields[field]).GetOffset(); + } + + static uint GetStructureSize(OrderedDictionary fields) { + uint size = 0; + uint min_align = GetMinAlign(fields); + + for (var i = 0; i < fields.Count; i++) { + var field = ((GLib.AbiField) fields[i]); + + if (field.InUnion()) + continue; + + var tsize = (uint) (Math.Ceiling((double) (field.GetEnd() / (double) min_align)) * (double) min_align); + + size = Math.Max(tsize, size); + } + + return size; + } + + public uint Size { + get { + + return GetStructureSize(Fields); + } + } + } +} diff --git a/Source/glib/Cond.cs b/Source/glib/Cond.cs index cc935669c..ddd28423e 100644 --- a/Source/glib/Cond.cs +++ b/Source/glib/Cond.cs @@ -10,6 +10,11 @@ namespace GLib { #region Autogenerated code public partial class Cond : GLib.Opaque { + public struct ABI { + IntPtr p; + int i1; + int i2; + } [DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)] static extern void g_cond_broadcast(IntPtr raw); diff --git a/Source/glib/HookList.cs b/Source/glib/HookList.cs new file mode 100644 index 000000000..34df11c1f --- /dev/null +++ b/Source/glib/HookList.cs @@ -0,0 +1,114 @@ +// This file was generated by the Gtk# code generator. +// Any changes made will be lost if regenerated. + +namespace GLib { + + using System; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.InteropServices; + +#region Autogenerated code + public partial class HookList : GLib.Opaque { + + // Internal representation of the wrapped ABI structure. + static public AbiStruct abi_info = new AbiStruct(new List { + new GLib.AbiField("seq_id" + , 0 + , (uint) Marshal.SizeOf(typeof(ulong)) // seq_id + , null + , "hook_size" + , (long) Marshal.OffsetOf(typeof(GHookList_seq_idAlign), "seq_id") + , 0 + ), + new GLib.AbiField("hook_size" + , -1 + , (uint) Marshal.SizeOf(typeof(uint)) // hook_size + , "seq_id" + , "is_setup" + , 1 + , 16 + ), + new GLib.AbiField("is_setup" + , -1 + , (uint) Marshal.SizeOf(typeof(bool)) // is_setup + , "hook_size" + , "hooks" + , 1 + , 1 + ), + new GLib.AbiField("hooks" + , -1 + , (uint) Marshal.SizeOf(typeof(IntPtr)) // hooks + , "is_setup" + , "dummy3" + , (long) Marshal.OffsetOf(typeof(GHookList_hooksAlign), "hooks") + , 0 + ), + new GLib.AbiField("dummy3" + , -1 + , (uint) Marshal.SizeOf(typeof(IntPtr)) // dummy3 + , "hooks" + , "finalize_hook" + , (long) Marshal.OffsetOf(typeof(GHookList_dummy3Align), "dummy3") + , 0 + ), + new GLib.AbiField("finalize_hook" + , -1 + , (uint) Marshal.SizeOf(typeof(IntPtr)) // finalize_hook + , "dummy3" + , "dummy" + , (long) Marshal.OffsetOf(typeof(GHookList_finalize_hookAlign), "finalize_hook") + , 0 + ), + new GLib.AbiField("dummy" + , -1 + , (uint) Marshal.SizeOf(typeof(IntPtr)) * 2 // dummy + , "finalize_hook" + , null + , (long) Marshal.OffsetOf(typeof(GHookList_dummyAlign), "dummy") + , 0 + ) + } + ); + + [StructLayout(LayoutKind.Sequential)] + public struct GHookList_seq_idAlign + { + sbyte f1; + private UIntPtr seq_id; + } + + [StructLayout(LayoutKind.Sequential)] + public struct GHookList_hooksAlign + { + sbyte f1; + private IntPtr hooks; + } + + [StructLayout(LayoutKind.Sequential)] + public struct GHookList_dummy3Align + { + sbyte f1; + private IntPtr dummy3; + } + + [StructLayout(LayoutKind.Sequential)] + public struct GHookList_finalize_hookAlign + { + sbyte f1; + private IntPtr finalize_hook; + } + + [StructLayout(LayoutKind.Sequential)] + public struct GHookList_dummyAlign + { + sbyte f1; + [MarshalAs (UnmanagedType.ByValArray, SizeConst=2)] + private IntPtr[] dummy; + } + // End of the ABI representation. + +#endregion + } +} diff --git a/Source/glib/Mutex.cs b/Source/glib/Mutex.cs index e91039e93..28c3274ac 100644 --- a/Source/glib/Mutex.cs +++ b/Source/glib/Mutex.cs @@ -10,6 +10,11 @@ namespace GLib { #region Autogenerated code public partial class Mutex : GLib.Opaque { + public struct ABI { + IntPtr p; + int i1; + int i2; + } [DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)] static extern void g_mutex_clear(IntPtr raw); diff --git a/Source/glib/Object.cs b/Source/glib/Object.cs index 34518b5a1..877d5b31c 100644 --- a/Source/glib/Object.cs +++ b/Source/glib/Object.cs @@ -823,8 +823,6 @@ namespace GLib { public IntPtr g_class; } - public static uint instance_offset { get { return 0; }} - public uint GetFieldOffset(string field) { throw new NotImplementedException(); return 0; } public struct GObject { public GTypeInstance type_instance; public uint ref_count; @@ -848,5 +846,56 @@ namespace GLib { if (Environment.GetEnvironmentVariable ("GTK_SHARP_DEBUG") != null) GLib.Log.SetLogHandler ("GLib-GObject", GLib.LogLevelFlags.All, new GLib.LogFunc (GLib.Log.PrintTraceLogFunction)); } + + // Internal representation of the wrapped ABI structure. + static public AbiStruct abi_info = new AbiStruct(new List { + new GLib.AbiField("g_type_instance" + , 0 + , (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance + , null + , "ref_count" + , (long) Marshal.OffsetOf(typeof(GObject_g_type_instanceAlign), "g_type_instance") + , 0 + ), + new GLib.AbiField("ref_count" + , -1 + , (uint) Marshal.SizeOf(typeof(uint)) // ref_count + , "g_type_instance" + , "qdata" + , (long) Marshal.OffsetOf(typeof(GObject_ref_countAlign), "ref_count") + , 0 + ), + new GLib.AbiField("qdata" + , -1 + , (uint) Marshal.SizeOf(typeof(IntPtr)) // qdata + , "ref_count" + , null + , (long) Marshal.OffsetOf(typeof(GObject_qdataAlign), "qdata") + , 0 + ), + } + ); + + [StructLayout(LayoutKind.Sequential)] + public struct GObject_g_type_instanceAlign + { + sbyte f1; + private IntPtr g_type_instance; + } + + [StructLayout(LayoutKind.Sequential)] + public struct GObject_ref_countAlign + { + sbyte f1; + private uint ref_count; + } + + [StructLayout(LayoutKind.Sequential)] + public struct GObject_qdataAlign + { + sbyte f1; + private IntPtr qdata; + } + // End of the ABI representation. } } diff --git a/Source/glib/RecMutex.cs b/Source/glib/RecMutex.cs index e71cf4037..dc4f68058 100644 --- a/Source/glib/RecMutex.cs +++ b/Source/glib/RecMutex.cs @@ -10,6 +10,13 @@ namespace GLib { #region Autogenerated code public partial class RecMutex : GLib.Opaque { + [StructLayout(LayoutKind.Sequential)] + public struct ABI { + IntPtr p; + int i1; + int i2; + } + [DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)] static extern void g_rec_mutex_clear(IntPtr raw); diff --git a/Source/glib/meson.build b/Source/glib/meson.build index ee8620e6e..373ea8697 100644 --- a/Source/glib/meson.build +++ b/Source/glib/meson.build @@ -21,6 +21,8 @@ policy = configure_file(input: policy_config, configuration : policy_data) sources = [ + 'AbiField.cs', + 'AbiStruct.cs', 'Argv.cs', 'Bytes.cs', 'ConnectBeforeAttribute.cs', @@ -39,6 +41,7 @@ sources = [ 'GString.cs', 'GType.cs', 'GTypeAttribute.cs', + 'HookList.cs', 'Idle.cs', 'InitiallyUnowned.cs', 'IOChannel.cs', @@ -88,7 +91,7 @@ sources = [ 'ValueArray.cs', 'Value.cs', 'Variant.cs', - 'VariantType.cs' ] + 'VariantType.cs'] glib_sharp = library(assembly_name, sources, assemblyinfo,