mirror of https://github.com/mono/CppSharp.git
c-sharpdotnetmonobindingsbridgecclangcpluspluscppsharpglueinteropparserparsingpinvokeswigsyntax-treevisitorsxamarinxamarin-bindings
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
247 lines
7.9 KiB
247 lines
7.9 KiB
// |
|
// Mono.Cxxi.Abi.ItaniumAbi.cs: An implementation of the Itanium C++ ABI |
|
// |
|
// Author: |
|
// Alexander Corrado (alexander.corrado@gmail.com) |
|
// Andreia Gaita (shana@spoiledcat.net) |
|
// |
|
// Copyright (C) 2010-2011 Alexander Corrado |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining |
|
// a copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to |
|
// permit persons to whom the Software is furnished to do so, subject to |
|
// the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be |
|
// included in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
using System; |
|
using System.Linq; |
|
using System.Text; |
|
using System.Reflection; |
|
using System.Reflection.Emit; |
|
using System.Collections.Generic; |
|
using System.Runtime.InteropServices; |
|
|
|
using Mono.Cxxi.Util; |
|
|
|
namespace Mono.Cxxi.Abi { |
|
public class ItaniumAbi : CppAbi { |
|
|
|
public static readonly ItaniumAbi Instance = new ItaniumAbi (); |
|
|
|
private ItaniumAbi () |
|
{ |
|
} |
|
|
|
public override CppTypeInfo MakeTypeInfo (CppLibrary lib, string typeName, Type interfaceType, Type layoutType/*?*/, Type/*?*/ wrapperType) |
|
{ |
|
return new ItaniumTypeInfo (lib, typeName, interfaceType, layoutType, wrapperType); |
|
} |
|
|
|
public override IEnumerable<PInvokeSignature> GetVirtualMethodSlots (CppTypeInfo typeInfo, Type interfaceType) |
|
{ |
|
foreach (var method in base.GetVirtualMethodSlots (typeInfo, interfaceType)) { |
|
if (!IsVirtual (method.OrigMethod)) |
|
continue; |
|
|
|
yield return method; |
|
|
|
// Itanium has extra slot for virt dtor |
|
if (method.Type == MethodType.NativeDtor) |
|
yield return null; |
|
} |
|
} |
|
|
|
protected override MethodBuilder DefineMethod (CppTypeInfo typeInfo, PInvokeSignature sig, ref int vtableIndex) |
|
{ |
|
var builder = base.DefineMethod (typeInfo, sig, ref vtableIndex); |
|
|
|
// increment vtableIndex an extra time for that extra vdtor slot (already incremented once in base) |
|
if (IsVirtual (sig.OrigMethod) && sig.Type == MethodType.NativeDtor) |
|
vtableIndex++; |
|
|
|
return builder; |
|
} |
|
|
|
public override CallingConvention? GetCallingConvention (MethodInfo methodInfo) |
|
{ |
|
return CallingConvention.Cdecl; |
|
} |
|
|
|
protected override string GetMangledMethodName (CppTypeInfo typeInfo, MethodInfo methodInfo) |
|
{ |
|
var compressMap = new Dictionary<string, int> (); |
|
var methodName = methodInfo.Name; |
|
var className = typeInfo.TypeName; |
|
|
|
MethodType methodType = GetMethodType (typeInfo, methodInfo); |
|
ParameterInfo [] parameters = methodInfo.GetParameters (); |
|
|
|
StringBuilder nm = new StringBuilder ("_ZN", 30); |
|
|
|
if (IsConst (methodInfo)) |
|
nm.Append ('K'); |
|
|
|
nm.Append (className.Length).Append (className); |
|
compressMap [className] = compressMap.Count; |
|
|
|
// FIXME: Implement compression completely |
|
|
|
switch (methodType) { |
|
case MethodType.NativeCtor: |
|
nm.Append ("C1"); |
|
break; |
|
|
|
case MethodType.NativeDtor: |
|
nm.Append ("D1"); |
|
break; |
|
|
|
default: |
|
nm.Append (methodName.Length).Append (methodName); |
|
break; |
|
} |
|
|
|
nm.Append ('E'); |
|
int argStart = (IsStatic (methodInfo)? 0 : 1); |
|
|
|
if (parameters.Length == argStart) // no args (other than C++ "this" object) |
|
nm.Append ('v'); |
|
else |
|
for (int i = argStart; i < parameters.Length; i++) |
|
nm.Append (GetTypeCode (GetMangleType (parameters [i], parameters [i].ParameterType), compressMap)); |
|
|
|
return nm.ToString (); |
|
} |
|
|
|
public virtual string GetTypeCode (CppType mangleType) { |
|
return GetTypeCode (mangleType, new Dictionary<string, int> ()); |
|
} |
|
|
|
string GetTypeCode (CppType mangleType, Dictionary<string, int> compressMap) |
|
{ |
|
CppTypes element = mangleType.ElementType; |
|
IEnumerable<CppModifiers> modifiers = mangleType.Modifiers; |
|
|
|
StringBuilder code = new StringBuilder (); |
|
|
|
var ptrOrRef = For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Reference); |
|
var modifierCode = modifiers.Reverse ().Transform ( |
|
For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Array).Emit ("P"), |
|
For.AnyInputIn (CppModifiers.Reference).Emit ("R"), |
|
|
|
// Itanium mangled names do not include const or volatile unless |
|
// they modify the type pointed to by pointer or reference. |
|
Choose.TopOne ( |
|
For.AllInputsIn (CppModifiers.Volatile, CppModifiers.Const).InAnyOrder ().After (ptrOrRef).Emit ("VK"), |
|
For.AnyInputIn (CppModifiers.Volatile).After (ptrOrRef).Emit ("V"), |
|
For.AnyInputIn (CppModifiers.Const).After (ptrOrRef).Emit ("K") |
|
) |
|
); |
|
code.Append (string.Join(string.Empty, modifierCode.ToArray ())); |
|
|
|
switch (element) { |
|
case CppTypes.Int: |
|
code.Append (modifiers.Transform ( |
|
For.AllInputsIn (CppModifiers.Unsigned, CppModifiers.Short).InAnyOrder ().Emit ('t') |
|
).DefaultIfEmpty ('i').ToArray ()); |
|
break; |
|
case CppTypes.Char: |
|
code.Append ('c'); |
|
break; |
|
case CppTypes.Class: |
|
case CppTypes.Struct: |
|
case CppTypes.Union: |
|
case CppTypes.Enum: { |
|
int cid; |
|
if (compressMap.TryGetValue (mangleType.ElementTypeName, out cid)) { |
|
if (cid == 0) |
|
code.Append ("S_"); |
|
else |
|
throw new NotImplementedException (); |
|
} else { |
|
code.Append (mangleType.ElementTypeName.Length); |
|
code.Append (mangleType.ElementTypeName); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
return code.ToString (); |
|
} |
|
|
|
// Section 3.1.4: |
|
// Classes with non-default copy ctors/destructors are returned using a hidden |
|
// argument |
|
bool ReturnByHiddenArgument (CppTypeInfo typeInfo, MethodInfo method) |
|
{ |
|
var iti = (ItaniumTypeInfo)typeInfo; |
|
|
|
if (!IsByVal (method.ReturnTypeCustomAttributes)) |
|
return false; |
|
|
|
if (iti.has_non_default_copy_ctor_or_dtor == null) |
|
iti.has_non_default_copy_ctor_or_dtor = GetMethods (typeInfo.InterfaceType) |
|
.Any (m => (IsCopyConstructor (m) || |
|
GetMethodType (typeInfo, m) == MethodType.NativeDtor) && |
|
!IsArtificial (m)); |
|
|
|
return iti.has_non_default_copy_ctor_or_dtor.Value; |
|
} |
|
|
|
public override PInvokeSignature GetPInvokeSignature (CppTypeInfo/*?*/ typeInfo, MethodInfo method) |
|
{ |
|
var psig = base.GetPInvokeSignature (typeInfo, method); |
|
|
|
if (ReturnByHiddenArgument (typeInfo, method)) { |
|
psig.ParameterTypes.Insert (0, typeof (IntPtr)); |
|
psig.ReturnType = typeof (void); |
|
} |
|
|
|
return psig; |
|
} |
|
|
|
protected override void EmitNativeCall (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr) |
|
{ |
|
var il = typeInfo.emit_info.current_il; |
|
var method = psig.OrigMethod; |
|
var hiddenReturnByValue = ReturnByHiddenArgument (typeInfo, method); |
|
|
|
LocalBuilder returnValue = null; |
|
|
|
if (hiddenReturnByValue) |
|
{ |
|
returnValue = il.DeclareLocal (typeof (CppInstancePtr)); |
|
|
|
if (typeof (ICppObject).IsAssignableFrom (method.ReturnType)) |
|
il.Emit (OpCodes.Ldc_I4, GetTypeInfo (method.ReturnType).NativeSize); |
|
else if (method.ReturnType.IsValueType) |
|
il.Emit (OpCodes.Ldc_I4, Marshal.SizeOf (method.ReturnType)); |
|
|
|
il.Emit (OpCodes.Newobj, cppip_fromsize); |
|
il.Emit (OpCodes.Stloc, returnValue); |
|
il.Emit (OpCodes.Ldloca, returnValue); |
|
il.Emit (OpCodes.Call, cppip_native); |
|
} |
|
|
|
base.EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr); |
|
|
|
if (hiddenReturnByValue) { |
|
EmitCreateCppObjectFromNative (il, method.ReturnType, returnValue); |
|
} |
|
} |
|
|
|
|
|
} |
|
} |