generator: Use a AbiStruct for Class structures

Not for interfaces as it won't should not be required.
This commit is contained in:
Thibault Saunier 2017-10-03 21:13:35 -03:00
parent 248278d267
commit 1d88acfbe7
12 changed files with 293 additions and 70 deletions

View File

@ -39,7 +39,7 @@ namespace GtkSharp.Generation {
protected IList<string> managed_interfaces = new List<string>();
protected IList<Ctor> ctors = new List<Ctor>();
protected IList<StructABIField> abi_fields = new List<StructABIField> ();
protected List<StructABIField> abi_fields = new List<StructABIField> ();
protected bool abi_fields_valid; // false if the instance structure contains a bitfield or fields of unknown types
private bool ctors_initted = false;
@ -87,11 +87,11 @@ namespace GtkSharp.Generation {
if (node.Name == "field") {
num_abi_fields += 1;
if (num_abi_fields != 1 || !has_parent) { // Skip instance parent struct
abi_field = new StructABIField (member, this);
abi_field = new StructABIField (member, this, "abi_info");
abi_fields.Add (abi_field);
}
} else if (node.Name == "union") {
abi_field = new UnionABIField (member, this);
abi_field = new UnionABIField (member, this, "abi_info");
abi_fields.Add (abi_field);
}
@ -190,10 +190,18 @@ namespace GtkSharp.Generation {
return parent_can_generate;
}
protected void GenerateStructureABI (GenerationInfo gen_info)
protected void GenerateStructureABI (GenerationInfo gen_info) {
GenerateStructureABI(gen_info, null, "abi_info", CName);
}
protected void GenerateStructureABI (GenerationInfo gen_info, List<StructABIField> _fields,
string info_name, string structname)
{
string cs_parent_struct = null;
if (_fields == null)
_fields = abi_fields;
LogWriter log = new LogWriter (QualifiedName);
if (!CheckABIStructParent (log, out cs_parent_struct))
return;
@ -206,44 +214,44 @@ namespace GtkSharp.Generation {
sw.WriteLine ();
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\tstatic GLib.AbiStruct _" + info_name + " = null;");
sw.WriteLine ("\t\tstatic public " + _new + "GLib.AbiStruct " + info_name + " {");
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<GLib.AbiField>{ ");
sw.WriteLine ("\t\t\t\tif (_" + info_name + " == null)");
sw.WriteLine ("\t\t\t\t\t_" + info_name + " = new GLib.AbiStruct (new List<GLib.AbiField>{ ");
// 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);
if (_fields.Count > 0 && gen_info.CAbiWriter != null) {
gen_info.CAbiWriter.WriteLine("\tg_print(\"\\\"sizeof({0})\\\": \\\"%\" G_GOFFSET_FORMAT \"\\\"\\n\", sizeof({0}));", structname);
gen_info.AbiWriter.WriteLine("\t\t\tConsole.WriteLine(\"\\\"sizeof({0})\\\": \\\"\" + {1}.{2}." + info_name + ".Size + \"\\\"\");", structname, 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;
for(int i=0; i < _fields.Count; i++) {
var field = _fields[i];
next = _fields.Count > i +1 ? _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 (union == null && gen_info.CAbiWriter != null && !field.IsBitfield) {
gen_info.AbiWriter.WriteLine("\t\t\tConsole.WriteLine(\"\\\"{0}.{3}\\\": \\\"\" + {1}.{2}." + info_name + ".GetFieldOffset(\"{3}\") + \"\\\"\");", structname, NS, Name, field.CName);
gen_info.CAbiWriter.WriteLine("\tg_print(\"\\\"{0}.{1}\\\": \\\"%\" G_GOFFSET_FORMAT \"\\\"\\n\", G_STRUCT_OFFSET({0}, {1}));", structname, field.CName);
}
}
if (abi_fields.Count > 0 && gen_info.CAbiWriter != null) {
if (_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\treturn _" + info_name + ";");
sw.WriteLine ("\t\t\t}");
sw.WriteLine ("\t\t}");
sw.WriteLine ();

View File

@ -114,7 +114,7 @@ namespace GtkSharp.Generation {
if (UseABIStruct(gen_info)) {
getOffsetName = abi_field.getOffsetName;
offsetName = "abi_info.GetFieldOffset(\"" + ((StructField)abi_field).CName + "\")";
offsetName = ((StructABIField) abi_field).abi_info_name + ".GetFieldOffset(\"" + ((StructField)abi_field).CName + "\")";
return;
}

View File

@ -174,10 +174,11 @@ namespace GtkSharp.Generation {
{
GenerateOverrideBody (sw);
// Override VM; class_offset var is generated by object generatable
sw.WriteLine ("\t\t\t{0} class_iface = GetClassStruct (gtype, false);", class_struct_name);
sw.WriteLine ("\t\t\tclass_iface.{0} = callback;", this.Name);
sw.WriteLine ("\t\t\tOverrideClassStruct (gtype, class_iface);");
sw.WriteLine ("\t\t}");
sw.WriteLine("\t\t\tunsafe {");
sw.WriteLine("\t\t\t\tIntPtr* raw_ptr = (IntPtr*)(((long) gtype.GetClassPtr()) + (long) class_abi.GetFieldOffset(\"{0}\"));", CName);
sw.WriteLine("\t\t\t\t*raw_ptr = Marshal.GetFunctionPointerForDelegate((Delegate) callback);");
sw.WriteLine("\t\t\t}");
sw.WriteLine("\t\t}");
sw.WriteLine ();
}
@ -206,7 +207,11 @@ namespace GtkSharp.Generation {
this.GenerateMethodBody (sw, null);
// Find the first unmanaged ancestor
sw.WriteLine ("\t\t\t{0}NativeDelegate unmanaged = GetClassStruct (this.LookupGType ().GetThresholdType (), true).{0};", this.Name);
sw.WriteLine ("\t\t\t{0}NativeDelegate unmanaged = null;", Name);
sw.WriteLine ("\t\t\tunsafe {");
sw.WriteLine ("\t\t\t\tIntPtr* raw_ptr = (IntPtr*)(((long) this.LookupGType().GetThresholdType().GetClassPtr()) + (long) class_abi.GetFieldOffset(\"{0}\"));", CName);
sw.WriteLine ("\t\t\t\tunmanaged = ({0}NativeDelegate) Marshal.GetDelegateForFunctionPointer(*raw_ptr, typeof({0}NativeDelegate));", this.Name);
sw.WriteLine ("\t\t\t}");
sw.Write ("\t\t\tif (unmanaged == null) ");
if (parms.HasOutParam)
sw.WriteLine ("throw new InvalidOperationException (\"No base method to invoke\");");

View File

@ -0,0 +1,56 @@
namespace GtkSharp.Generation {
using System;
using System.Collections;
using System.IO;
using System.Xml;
using System.Collections.Generic;
public class MethodABIField : StructABIField {
bool is_valid;
XmlElement Elem;
public MethodABIField (XmlElement elem, ClassBase container_type, string info_name) :
base (elem, container_type, info_name) {
Elem = elem;
is_valid = true;
}
public override string CType {
get {
return "gpointer";
}
}
public override bool IsCPointer() {
return true;
}
public new string Name {
get {
var name = elem.GetAttribute("vm");
if (name == null || name == "")
name = elem.GetAttribute("signal_vm");
return name;
}
}
public override string StudlyName {
get {
return Name;
}
}
public override string CName {
get {
if (parent_structure_name != null)
return parent_structure_name + '.' + Name;
return Name;
}
}
}
}

View File

@ -32,7 +32,11 @@ namespace GtkSharp.Generation {
bool is_interface;
protected string class_struct_name = null;
bool class_fields_valid; // false if the class structure contains a bitfield or fields of unknown types
ArrayList class_members = new ArrayList ();
protected List<StructABIField> abi_class_members = new List<StructABIField> ();
bool class_abi_valid = true;
protected IList<ClassField> class_fields = new List<ClassField> ();
// The default handlers of these signals need to be overridden with g_signal_override_class_closure
protected IList<GObjectVM> virtual_methods = new List<GObjectVM> ();
@ -85,13 +89,32 @@ namespace GtkSharp.Generation {
}
if (class_elem == null) return;
if (class_elem.GetAttributeAsBoolean("private")) {
class_abi_valid = false;
return;
}
class_struct_name = class_elem.GetAttribute ("cname");
int num_abi_fields = 0;
for (int node_idx = 0; node_idx < class_elem.ChildNodes.Count; node_idx++) {
XmlNode node = class_elem.ChildNodes [node_idx];
if (!(node is XmlElement)) continue;
XmlElement member = (XmlElement) node;
// Make sure ABI fields are taken into account, even when hidden.
if (node.Name == "field") {
num_abi_fields += 1;
if (num_abi_fields != 1) { // Skip instance parent struct
abi_class_members.Add (new StructABIField (member, this, "class_abi"));
}
} else if (node.Name == "union") {
abi_class_members.Add (new UnionABIField (member, this, "class_abi"));
} else if (node.Name == "method") {
abi_class_members.Add (new MethodABIField (member, this, "class_abi"));
}
switch (member.Name) {
case "method":
string vm_name;
@ -183,7 +206,7 @@ namespace GtkSharp.Generation {
* as they may contain class fields which don't appear in the old (version 1) API files. There are also cases in which the order of the
* <signal> and <virtual_method> elements do not match the struct layout.
*/
return (is_interface || this.ParserVersion >= 2) && (class_fields_valid || class_struct_name == "GtkWidgetClass");
return (is_interface || this.ParserVersion >= 2) && (class_abi_valid || class_struct_name == "GtkWidgetClass");
}
}
@ -301,6 +324,10 @@ namespace GtkSharp.Generation {
foreach (ClassField field in class_fields)
if (!field.Validate (log))
class_fields_valid = false;
foreach (StructABIField field in abi_class_members)
if (!field.Validate (log))
class_abi_valid = false;
foreach (InterfaceVM vm in interface_vms)
if (!vm.Validate (log))
@ -339,7 +366,7 @@ namespace GtkSharp.Generation {
return true;
}
public override string GenerateGetSizeOf () {
return NS + "." + Name + ".abi_info.GetABISize()";
return NS + "." + Name + ".abi_info.Size";
}
}
}

View File

@ -311,38 +311,7 @@ namespace GtkSharp.Generation {
void GenClassMembers (GenerationInfo gen_info, string cs_parent)
{
GenVirtualMethods (gen_info, null);
if (class_struct_name == null || !CanGenerateClassStruct) return;
StreamWriter sw = gen_info.Writer;
GenerateClassStruct (gen_info);
if (cs_parent == "")
sw.WriteLine ("\t\tstatic uint class_offset = 0;");
else
sw.WriteLine ("\t\tstatic uint class_offset = ((GLib.GType) typeof ({0})).GetClassSize ();", cs_parent);
sw.WriteLine ("\t\tstatic Dictionary<GLib.GType, {0}> class_structs;", class_struct_name);
sw.WriteLine ();
sw.WriteLine ("\t\tstatic {0} GetClassStruct (GLib.GType gtype, bool use_cache)", class_struct_name);
sw.WriteLine ("\t\t{");
sw.WriteLine ("\t\t\tif (class_structs == null)");
sw.WriteLine ("\t\t\t\tclass_structs = new Dictionary<GLib.GType, {0}> ();", class_struct_name);
sw.WriteLine ();
sw.WriteLine ("\t\t\tif (use_cache && class_structs.ContainsKey (gtype))");
sw.WriteLine ("\t\t\t\treturn class_structs [gtype];");
sw.WriteLine ("\t\t\telse {");
sw.WriteLine ("\t\t\t\tIntPtr class_ptr = new IntPtr (gtype.GetClassPtr ().ToInt64 () + class_offset);");
sw.WriteLine ("\t\t\t\t{0} class_struct = ({0}) Marshal.PtrToStructure (class_ptr, typeof ({0}));", class_struct_name);
sw.WriteLine ("\t\t\t\tif (use_cache)");
sw.WriteLine ("\t\t\t\t\tclass_structs.Add (gtype, class_struct);");
sw.WriteLine ("\t\t\t\treturn class_struct;");
sw.WriteLine ("\t\t\t}");
sw.WriteLine ("\t\t}");
sw.WriteLine ();
sw.WriteLine ("\t\tstatic void OverrideClassStruct (GLib.GType gtype, {0} class_struct)", class_struct_name);
sw.WriteLine ("\t\t{");
sw.WriteLine ("\t\t\tIntPtr class_ptr = new IntPtr (gtype.GetClassPtr ().ToInt64 () + class_offset);");
sw.WriteLine ("\t\t\tMarshal.StructureToPtr (class_struct, class_ptr, false);");
sw.WriteLine ("\t\t}");
sw.WriteLine ();
GenerateStructureABI(gen_info, abi_class_members, "class_abi", ClassStructName);
}
/* Keep this in sync with the one in glib/GType.cs */

View File

@ -47,7 +47,7 @@ namespace GtkSharp.Generation {
}
protected string ctype;
public string CType {
public virtual string CType {
get {
if (ctype == null) {
if (elem.GetAttribute("bits") == "1")

View File

@ -8,10 +8,13 @@ namespace GtkSharp.Generation {
public class StructABIField : StructField {
protected new ClassBase container_type;
public string parent_structure_name;
public string abi_info_name;
public StructABIField (XmlElement elem, ClassBase container_type) : base (elem, container_type) {
public StructABIField (XmlElement elem, ClassBase container_type,
string info_name) : base (elem, container_type) {
this.container_type = container_type;
this.getOffsetName = null;
this.abi_info_name = info_name;
}
public override string CName {
@ -80,7 +83,7 @@ namespace GtkSharp.Generation {
sw.WriteLine(indent + ", -1");
} else {
if (parent_name != "")
sw.WriteLine(indent + ", " + parent_name + ".abi_info.Fields");
sw.WriteLine(indent + ", " + parent_name + "." + abi_info_name + ".Fields");
else
sw.WriteLine(indent + ", 0");
}
@ -103,6 +106,9 @@ namespace GtkSharp.Generation {
if (IsCPointer())
min_align = "(uint) Marshal.SizeOf(typeof(IntPtr))";
if (IsBitfield)
min_align = "1";
if (min_align == null) {
var tmpindent = "\t\t";
structw.WriteLine(tmpindent + "[StructLayout(LayoutKind.Sequential)]");

View File

@ -106,7 +106,7 @@ namespace GtkSharp.Generation {
return IsArray && !IsNullTermArray && ArrayLength != 0;
}
public bool IsCPointer() {
public virtual bool IsCPointer() {
IGeneratable gen = SymbolTable.Table[CType];
return (CType.EndsWith("*") ||
@ -177,11 +177,11 @@ namespace GtkSharp.Generation {
}
}
public string StudlyName {
public virtual string StudlyName {
get {
string studly = base.Name;
if (studly == "")
throw new Exception ("API file must be regenerated with a current version of the GAPI parser. It is incompatible with this version of the GAPI code generator.");
throw new Exception (CName + "API file must be regenerated with a current version of the GAPI parser. It is incompatible with this version of the GAPI code generator.");
return studly;
}

View File

@ -11,8 +11,9 @@ namespace GtkSharp.Generation {
XmlElement Elem;
bool is_valid;
bool unique_field;
public string abi_info_name;
public UnionSubstruct(XmlElement elem, ClassBase container_type) {
public UnionSubstruct(XmlElement elem, ClassBase container_type, string abi_info_name) {
fields = new List<StructABIField> ();
Elem = elem;
is_valid = true;
@ -25,10 +26,10 @@ namespace GtkSharp.Generation {
continue;
}
fields.Add(new StructABIField (child_field, container_type));
fields.Add(new StructABIField (child_field, container_type, abi_info_name));
}
} else if (Elem.Name == "field") {
fields.Add(new StructABIField (Elem, container_type));
fields.Add(new StructABIField (Elem, container_type, abi_info_name));
unique_field = true;
}
}
@ -101,11 +102,12 @@ namespace GtkSharp.Generation {
protected List<UnionSubstruct> substructs = new List<UnionSubstruct> ();
public UnionABIField (XmlElement elem, ClassBase container_type) : base (elem, container_type) {
public UnionABIField (XmlElement elem, ClassBase container_type, string info_name) :
base (elem, container_type, info_name) {
Elem = elem;
is_valid = true;
foreach (XmlElement union_child in elem.ChildNodes) {
substructs.Add(new UnionSubstruct(union_child, container_type));
substructs.Add(new UnionSubstruct(union_child, container_type, abi_info_name));
}
}

View File

@ -36,6 +36,7 @@ gapi_codegen = executable('gapi_codegen',
'ManagedCallString.cs',
'ManualGen.cs',
'MarshalGen.cs',
'MethodABIField.cs',
'MethodBase.cs',
'MethodBody.cs',
'Method.cs',

View File

@ -875,6 +875,155 @@ namespace GLib {
),
}
);
//
// Internal representation of the wrapped ABI structure.
static public AbiStruct class_abi = new AbiStruct(new List<AbiField> {
new GLib.AbiField("type_class"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, null
, "construct_props"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("construct_props"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "type_class"
, "constructor_cb"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("constructor_cb"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "construct_props"
, "set_prop_cb"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("set_prop_cb"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "constructor_cb"
, "get_prop_cb"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("get_prop_cb"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "set_prop_cb"
, "dispose"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("dispose"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "get_prop_cb"
, "finalize"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("finalize"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "dispose"
, "dispatch_properties_changed"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("dispatch_properties_changed"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "finalize"
, "notify"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("notify"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "dispatch_properties_changed"
, "constructed"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("constructed"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "notify"
, "dummy1"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("dummy1"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "constructed"
, "dummy2"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("dummy2"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "dummy1"
, "dummy3"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("dummy3"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "dummy2"
, "dummy4"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("dummy3"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "dummy2"
, "dummy4"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("dummy4"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "dummy3"
, "dummy5"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("dummy5"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "dummy4"
, "dummy6"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("dummy6"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "dummy5"
, "dummy7"
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
new GLib.AbiField("dummy7"
, 0
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, "dummy6"
, null
, (uint) Marshal.SizeOf(typeof(IntPtr)) // g_type_instance
, 0
),
}
);
[StructLayout(LayoutKind.Sequential)]
public struct GObject_g_type_instanceAlign