private Func <TypeDefinition[]> DefineClrHandleStructInternal(ClangStructInfo structInfo, int?bits = null) { if (structInfo.Size > 0) { throw new NotImplementedException(); } var structName = structInfo.Name; if (TypeRedirects.TryGetValue(structName, out var rename)) { structName = rename; } if (Module.GetType(structName)?.Resolve() != null) { return(null); } // handle type var handleDef = Module.DefineType(structName, PublicSealedStructTypeAttributes, size: 0); handleDef.SetCustomAttribute(() => new BinderGeneratedAttribute()); //handleDef.SetCustomAttribute(StructLayoutSequentialAttributeInfo); var handleInterface = IHandleGtd.MakeGenericInstanceType(handleDef); handleDef.AddInterfaceImplementation(handleInterface); var handlePointerType = handleDef.MakePointerType(); var inputTypes = bits == null ? TypeArrayOfSingularVoidPointer : bits == 64 ? TypeArrayOfSingularULong : TypeArrayOfSingularUInt; var castMethod = handleDef.DefineMethod("Cast", PublicStaticMethodAttributes, handlePointerType, inputTypes); SetMethodInliningAttributes(castMethod); castMethod.GenerateIL(il => { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ret); }); var handleType = handleDef.CreateType(); return(() => new[] { handleType }); }
private Func <TypeDefinition[]> DefineClrType(ClangEnumInfo enumInfo) { var underlyingTypeInfo = ResolveParameter(enumInfo.UnderlyingType); var underlyingType = underlyingTypeInfo.Type; var name = enumInfo.Name; Debug.WriteLine($"Defining enumeration {name}"); if (TypeRedirects.TryGetValue(name, out var renamed)) { name = renamed; } var enumTypeDef = Module.GetType(name); if (enumTypeDef == null) { enumTypeDef = Module.DefineEnum(name, TypeAttributes.Public, underlyingType); enumTypeDef.SetCustomAttribute(() => new BinderGeneratedAttribute()); } else { enumTypeDef.ChangeUnderlyingType(underlyingType); } //enumTypeDef.SetCustomAttribute(FlagsAttributeInfo); foreach (var enumDef in enumInfo.Definitions) { enumTypeDef.DefineLiteral(enumDef.Name, Convert.ChangeType(enumDef.Value, underlyingType.GetRuntimeType())); } var enumType = enumTypeDef.CreateType(); return(() => new[] { enumType }); }
private ParameterInfo ResolveParameter(CXType originalType, string name = null, int index = 0) { string renamed; var type = originalType; if (type.kind == CXTypeKind.CXType_FunctionProto) { throw new NotImplementedException(); } if (type.kind == CXTypeKind.CXType_FunctionNoProto) { throw new NotImplementedException(); } var typeKind = CanonizeType(ref type, out var typeDeclCursor); if (typeKind == CXTypeKind.CXType_Pointer) { var pointeeType = clang.getPointeeType(type); if (clang.getFunctionTypeCallingConv(pointeeType) != CXCallingConv.CXCallingConv_Invalid) { var delegateTypeName = originalType.ToString(); var possibleDelegateType = Module.GetType(delegateTypeName); if (possibleDelegateType != null) { return(new ParameterInfo(name, possibleDelegateType, index)); } return(new ParameterInfo(name, IncompleteTypeReference.Get(Module, null, delegateTypeName), index)); } var resolvedParameter = ResolveParameter(pointeeType); return(new ParameterInfo(name, resolvedParameter.Type.MakePointerType(), index)); } if (typeKind == CXTypeKind.CXType_DependentSizedArray) { throw new NotImplementedException(); } if (typeKind == CXTypeKind.CXType_ConstantArray) { var arraySize = (int)clang.getArraySize(type); var elementType = clang.getArrayElementType(type); var resolvedParameter = ResolveParameter(elementType, name); var clrElementType = resolvedParameter.Type; if (clrElementType.IsPointer) { clrElementType = Module.TypeSystem.IntPtr; } var arrayType = resolvedParameter.Type.MakeArrayType(); if (!PrimitiveUnmanagedTypeMap.TryGetValue(clrElementType.GetRuntimeType(), out var unmanagedType)) { throw new NotImplementedException(); } return(new ParameterInfo(name, arrayType, index, ParameterAttributes.None, arraySize)); } if (PrimitiveTypeMap.TryGetValue(typeKind, out var primitiveType)) { if (primitiveType == null) { throw new NotImplementedException(); } var originalTypeName = originalType.ToString(); var typeName = originalTypeName; if (TypeRedirects.TryGetValue(originalTypeName, out renamed)) { typeName = renamed; } if (originalType.kind == CXTypeKind.CXType_Typedef) { if (KnownTypes.ContainsKey(typeName)) { var knownType = Module.GetType(typeName) ?? Module.GetType(originalTypeName) ?? throw new NotImplementedException(); return(new ParameterInfo(name, knownType, index)); } } else { var found = Module.GetType(typeName); if (found != null) { return(new ParameterInfo(name, found, index)); } } return(new ParameterInfo(name, primitiveType.Import(Module), index)); } var typeDeclName = typeDeclCursor.ToString(); if (TypeRedirects.TryGetValue(typeDeclName, out renamed)) { typeDeclName = renamed; } var possibleType = Module.GetType(typeDeclName); if (possibleType != null) { return(new ParameterInfo(name, possibleType, index)); } return(new ParameterInfo(name, IncompleteTypeReference.Get(Module, null, typeDeclName), index)); }
private IClangType ParseTypeDef(CXCursor cursor) { var originalType = clang.getCursorType(cursor); var canonType = clang.getCanonicalType(originalType); var typeDeclCursor = clang.getTypeDeclaration(canonType); if (IsCursorInSystemHeader(typeDeclCursor)) { return(null); } var name = cursor.ToString(); if (typeDeclCursor.kind == CXCursorKind.CXCursor_NoDeclFound) { if (canonType.kind != CXTypeKind.CXType_Pointer) { // likely simple type alias if (TypeRedirects.TryGetValue(name, out var renamed)) { name = renamed; } if (KnownTypes.TryGetValue(name, out var knownType)) { if (PrimitiveTypeMap.TryGetValue(canonType.kind, out var primitiveType)) { var existingType = Module.GetType(name); if (existingType == null) { throw new NotImplementedException(); } switch (knownType) { case KnownType.Bitmask: case KnownType.Enum: { existingType.ChangeUnderlyingType(primitiveType.Import(Module)); break; } default: break; } IncrementStatistic("typedefs"); } else { throw new NotImplementedException(); } } return(null); } var pointeeType = clang.getPointeeType(canonType); var callConv = clang.getFunctionTypeCallingConv(pointeeType); if (callConv == CXCallingConv.CXCallingConv_Invalid) { // likely a pointer type alias return(null); } return(ParseDelegate(cursor, callConv)); } switch (typeDeclCursor.kind) { case CXCursorKind.CXCursor_UnionDecl: case CXCursorKind.CXCursor_StructDecl: { var typeName = typeDeclCursor.ToString(); if (name == typeName) { return(null); } throw new NotImplementedException(); } case CXCursorKind.CXCursor_EnumDecl: { if (TypeRedirects.TryGetValue(name, out var renamed)) { name = renamed; } if (KnownTypes.TryGetValue(name, out var knownType)) { var existingType = Module.GetType(name); if (existingType != null) { return(null); } switch (knownType) { case KnownType.Enum: { throw new NotImplementedException(); } case KnownType.Bitmask: { throw new NotImplementedException(); } default: throw new NotImplementedException(); } } throw new NotImplementedException(); } } IncrementStatistic("typedefs"); throw new NotImplementedException(); }
private Func <TypeDefinition[]> DefineClrType(ClangFunctionInfoBase funcInfo) { var funcName = funcInfo.Name; Debug.WriteLine($"Defining function {funcName}"); if (TypeRedirects.TryGetValue(funcName, out var rename)) { funcName = rename; } var funcRef = Module.GetType(funcName, true); var funcDef = funcRef.Resolve(); if (funcDef != null) { return(null); } funcDef = Module.DefineType(funcName, DelegateTypeAttributes, MulticastDelegateType); funcDef.SetCustomAttribute(() => new BinderGeneratedAttribute()); var umfpDef = new TypeDefinition(funcDef.Namespace, funcDef.Name + "Unmanaged", TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit | TypeAttributes.SequentialLayout | TypeAttributes.Public, Module.TypeSystem.ValueType); Module.Types.Add(umfpDef); var umfpRef = Module.ImportReference(umfpDef); var iumfpGtd = IUnmanagedFunctionPointerGtd.MakeGenericInstanceType(funcDef); var iumfpRef = iumfpGtd.Import(Module); umfpDef.AddInterfaceImplementation(iumfpRef); // todo: add implicit conversion ops using Marshal var retParam = ResolveParameter(funcInfo.ReturnType); /* todo: figure out why the attribute is jacked up * if (!CallingConventionMap.TryGetValue(funcInfo.CallConvention, out var callConv)) * throw new NotImplementedException(); * if (!ClrCallingConventionAttributeMap.TryGetValue(callConv, out var callConvAttr)) * throw new NotImplementedException(); */ var argParams = new LinkedList <ParameterInfo>(funcInfo.Parameters.Select(p => ResolveParameter(p.Type, p.Name, (int)p.Index))); return(() => { retParam.Complete(TypeRedirects, true); var retType = retParam.Type; foreach (var argParam in argParams) { argParam.Complete(TypeRedirects, true); } Debug.WriteLine($"Completed dependencies for function {funcName}"); var umfpValue = umfpDef.DefineField("Value", Module.TypeSystem.IntPtr, FieldAttributes.Public | FieldAttributes.InitOnly); var umfpValueRef = Module.ImportReference(umfpValue); var getDelegateForFpMethodDef = Module.ImportReference( new GenericInstanceMethod(GetDelegateForFpMethodGtd) { GenericArguments = { funcDef } }); var getFpForDelegateMethodDef = Module.ImportReference( new GenericInstanceMethod(GetFpForDelegateMethodGtd) { GenericArguments = { funcDef } }); var umfpDlgt = umfpDef.DefineMethod("op_Implicit", PublicStaticMethodAttributes | MethodAttributes.SpecialName, funcDef, umfpRef); umfpDlgt.GenerateIL(il => { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, umfpValueRef); il.Emit(OpCodes.Call, getDelegateForFpMethodDef); il.Emit(OpCodes.Ret); }); var dlgtUmfp = umfpDef.DefineMethod("op_Implicit", PublicStaticMethodAttributes | MethodAttributes.SpecialName, umfpRef, funcDef); var dlgtUmfpV0 = new VariableDefinition(umfpRef); dlgtUmfp.Body.Variables.Add(dlgtUmfpV0); dlgtUmfp.Body.InitLocals = true; dlgtUmfp.GenerateIL(il => { il.Emit(OpCodes.Ldloca_S, dlgtUmfpV0); il.Emit(OpCodes.Initobj, umfpRef); il.Emit(OpCodes.Ldloca_S, dlgtUmfpV0); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, getFpForDelegateMethodDef); il.Emit(OpCodes.Stfld, umfpValueRef); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); }); var umfpPtr = umfpDef.DefineMethod("op_Implicit", PublicStaticMethodAttributes | MethodAttributes.SpecialName, Module.TypeSystem.IntPtr, umfpRef); umfpPtr.GenerateIL(il => { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, umfpValueRef); il.Emit(OpCodes.Ret); }); var ptrUmfp = umfpDef.DefineMethod("op_Implicit", PublicStaticMethodAttributes | MethodAttributes.SpecialName, umfpRef, Module.TypeSystem.IntPtr); var ptrUmfpV0 = new VariableDefinition(umfpRef); ptrUmfp.Body.Variables.Add(ptrUmfpV0); ptrUmfp.Body.InitLocals = true; ptrUmfp.GenerateIL(il => { var argNull = default(CecilLabel); if (EmitNullChecks) { argNull = il.DefineLabel(); } il.Emit(OpCodes.Ldloca_S, ptrUmfpV0); il.Emit(OpCodes.Initobj, umfpRef); il.Emit(OpCodes.Ldloca_S, ptrUmfpV0); il.Emit(OpCodes.Ldarg_0); if (EmitNullChecks) { il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse, argNull); } il.Emit(OpCodes.Stfld, umfpValueRef); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); if (EmitNullChecks) { il.MarkLabel(argNull); il.Emit(OpCodes.Newobj, ArgumentNullCtor); il.Emit(OpCodes.Throw); // ReSharper disable once PossibleNullReferenceException argNull.Cleanup(); } }); var argTypes = argParams.Select(p => p.Type).ToArray(); var retTypeDef = retType.Resolve(); if (retTypeDef.BaseType != null && retTypeDef.BaseType.Is(MulticastDelegateType)) { // todo: marshalas umfp marshaller var ufpSpecTypeRef = Module.GetType(retTypeDef.FullName + "Unmanaged"); Debug.Assert(ufpSpecTypeRef != null); retType = ufpSpecTypeRef; } for (var i = 0; i < argTypes.Length; i++) { var argType = argTypes[i]; var argTypeDef = argType.Resolve(); if (argType.IsPointer) { var interiorArgType = argType.GetInteriorType(out var transforms); if (interiorArgType.Resolve().IsInterface) { if (!argType.Name.StartsWith("I")) { throw new NotImplementedException(); } var argTypeNameBase = interiorArgType.Name.Substring(1); if (!MarshallableSplitPointers.TryGetValue(argTypeNameBase, out var marshallable)) { TypeReference splitPtrTypeRef; if (_splitPointerDefs.TryGetValue(interiorArgType.FullName, out var splitPtrType)) { splitPtrTypeRef = splitPtrType; } else { var argType32 = Module.GetType(interiorArgType.Namespace, argTypeNameBase + "32"); Debug.Assert(argType32 != null); var argType64 = Module.GetType(interiorArgType.Namespace, argTypeNameBase + "64"); Debug.Assert(argType64 != null); splitPtrType = SplitPointerGtd.MakeGenericInstanceType(interiorArgType, argType32, argType64); if (!_splitPointerDefs.TryAdd(interiorArgType.FullName, splitPtrType)) { throw new NotImplementedException(); } splitPtrTypeRef = splitPtrType.Import(Module); } marshallable = Module.DefineType(argTypeNameBase + "Ptr", PublicSealedStructTypeAttributes); var valueField = marshallable.DefineField("Value", splitPtrTypeRef, FieldAttributes.Public | FieldAttributes.InitOnly); // implicit conversion from split pointer to marshallable for use as params var asSplitPtrOp = marshallable.DefineMethod("op_Implicit", PublicStaticMethodAttributes | MethodAttributes.SpecialName, splitPtrTypeRef, marshallable); asSplitPtrOp.GenerateIL(il => { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, valueField); il.Emit(OpCodes.Ret); }); // implicit conversion from marshallable to split pointer for use as returns var toSplitPtrOp = marshallable.DefineMethod("op_Implicit", PublicStaticMethodAttributes | MethodAttributes.SpecialName, marshallable, splitPtrTypeRef); var toSplitPtrOpV0 = new VariableDefinition(marshallable); toSplitPtrOp.Body.Variables.Add(toSplitPtrOpV0); toSplitPtrOp.Body.InitLocals = true; toSplitPtrOp.GenerateIL(il => { il.Emit(OpCodes.Ldloca_S, ptrUmfpV0); il.Emit(OpCodes.Initobj, marshallable); il.Emit(OpCodes.Ldloca_S, ptrUmfpV0); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Stfld, valueField); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); }); if (!MarshallableSplitPointers.TryAdd(argTypeNameBase, marshallable)) { throw new NotImplementedException(); } } Debug.Assert(marshallable != null); argTypes[i] = marshallable.Import(Module) .ApplyTransforms(transforms.Skip(1)); continue; } } if (argTypeDef.BaseType == null) { continue; } if (!argTypeDef.BaseType.Is(MulticastDelegateType)) { continue; } // todo: marshalas umfp marshaller var ufpSpecTypeRef = Module.GetType(argTypeDef.FullName + "Unmanaged"); Debug.Assert(ufpSpecTypeRef != null); argTypes[i] = ufpSpecTypeRef; } try { var ctor = funcDef.DefineConstructor(DelegateConstructorAttributes, Module.TypeSystem.Object, Module.TypeSystem.IntPtr); ctor.SetImplementationFlags(MethodImplAttributes.CodeTypeMask); var method = funcDef.DefineMethod("Invoke", DelegateInvokeMethodAttributes, retType, argTypes); method.SetImplementationFlags(MethodImplAttributes.CodeTypeMask); // todo: figure out why the attribute is jacked up //method.SetCustomAttribute(callConvAttr); argParams.ConsumeLinkedList((argParam, i) => { var param = method.DefineParameter(i + 1, argParam.Attributes, argParam.Name); }); return new[] { funcDef.CreateType() }; } catch (Exception ex) { throw new InvalidProgramException("Critical function type definition failure.", ex); } }); }
private Func <TypeDefinition[]> DefineClrType(ClangUnionInfo unionInfo) { if (unionInfo.Size == 0) { throw new NotImplementedException(); } var unionName = unionInfo.Name; Debug.WriteLine($"Defining union {unionName}"); if (TypeRedirects.TryGetValue(unionName, out var rename)) { unionName = rename; } if (Module.GetType(unionName)?.Resolve() != null) { return(null); } var unionDef = Module.DefineType(unionName, PublicSealedUnionTypeAttributes, null, (int)unionInfo.Alignment, (int)unionInfo.Size); unionDef.SetCustomAttribute(() => new BinderGeneratedAttribute()); //unionDef.SetCustomAttribute(StructLayoutExplicitAttributeInfo); var fieldParams = new LinkedList <ParameterInfo>(unionInfo.Fields.Select(f => ResolveField(f.Type, f.Name, (int)f.Offset))); return(() => { foreach (var fieldParam in fieldParams) { fieldParam.Complete(TypeRedirects, true); } Debug.WriteLine($"Completed dependencies for union {unionName}"); fieldParams.ConsumeLinkedList(fieldParam => { var fieldName = fieldParam.Name; var fieldType = fieldParam.Type; if (!fieldType.IsArray) { var fieldDef = unionDef.DefineField(fieldName, fieldType, FieldAttributes.Public); //fieldDef.SetCustomAttribute(AttributeInfo.Create( // () => new FieldOffsetAttribute(fieldParam.Position)), Module); fieldDef.Offset = fieldParam.Position; } else { var arraySize = fieldParam.ArraySize; fieldType = fieldType.DescendElementType(); var offsetPer = fieldType.SizeOf(); if (offsetPer == -1) { throw new NotImplementedException(); } var fieldDef = unionDef.DefineField($"{fieldName}[0]", fieldType, FieldAttributes.Private); fieldDef.Offset = fieldParam.Position; for (var i = 1; i < arraySize; ++i) { unionDef.DefineField($"{fieldName}[{i}]", fieldType, FieldAttributes.Private) .Offset = fieldParam.Position + i * offsetPer; } var fieldRefType = fieldType.MakeByReferenceType().Import(Module); var unionGetter = unionDef.DefineMethod(fieldName, PublicHideBySigMethodAttributes, fieldRefType, Module.TypeSystem.Int32); unionGetter.DefineParameter(1, ParameterAttributes.In, "index"); SetMethodInliningAttributes(unionGetter); unionGetter.GenerateIL(il => { var argOutOfRange = default(CecilLabel); if (EmitBoundsChecks) { argOutOfRange = il.DefineLabel(); il.Emit(OpCodes.Ldarg_1); // index il.EmitPushConst(0); // underflow il.Emit(OpCodes.Blt, argOutOfRange); il.Emit(OpCodes.Ldarg_1); // index il.EmitPushConst(arraySize); // overflow il.Emit(OpCodes.Bge, argOutOfRange); } il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldflda, fieldDef); il.Emit(OpCodes.Ldarg_1); // index il.Emit(OpCodes.Sizeof, fieldType); il.Emit(OpCodes.Mul); il.Emit(OpCodes.Add); if (fieldType.Resolve().IsInterface) { il.Emit(OpCodes.Box, fieldType); } il.Emit(OpCodes.Ret); if (EmitBoundsChecks) { il.MarkLabel(argOutOfRange); il.Emit(OpCodes.Newobj, ArgumentOutOfRangeCtor); il.Emit(OpCodes.Throw); // ReSharper disable once PossibleNullReferenceException argOutOfRange.Cleanup(); } }); } }); return new[] { unionDef.CreateType() }; }); }
private Func <TypeDefinition[]> DefineClrStructInternal(ClangStructInfo structInfo32, ClangStructInfo structInfo64) { if (structInfo32.Size == 0 && structInfo64.Size == 0) { return(DefineClrHandleStructInternal(structInfo64)); } var structName = structInfo32.Name; Debug.WriteLine($"Defining interface and structure {structName}"); if (TypeRedirects.TryGetValue(structName, out var rename)) { structName = rename; } var interfaceName = "I" + structName; if (Module.GetType(interfaceName)?.Resolve() != null) { return(null); } var interfaceDef = Module.DefineType(interfaceName, PublicInterfaceTypeAttributes); interfaceDef.SetCustomAttribute(() => new BinderGeneratedAttribute()); var structDef32 = Module.DefineType(structName + "32", PublicSealedStructTypeAttributes, null, (int)structInfo32.Alignment, (int)structInfo32.Size); structDef32.SetCustomAttribute(() => new BinderGeneratedAttribute()); /* * structDef32.SetCustomAttribute(AttributeInfo.Create( * () => new StructLayoutAttribute(LayoutKind.Sequential) { * Pack = (int) structInfo32.Alignment, * Size = (int) structInfo32.Size * })); */ var structDef64 = Module.DefineType(structName + "64", PublicSealedStructTypeAttributes, null, (int)structInfo64.Alignment, (int)structInfo64.Size); structDef64.SetCustomAttribute(() => new BinderGeneratedAttribute()); /* * structDef64.SetCustomAttribute(AttributeInfo.Create( * () => new StructLayoutAttribute(LayoutKind.Sequential) { * Pack = (int) structInfo64.Alignment, * Size = (int) structInfo64.Size * })); */ _splitPointerDefs[interfaceDef.FullName] = SplitPointerGtd .MakeGenericInstanceType(interfaceDef, structDef32, structDef64); if (!structDef32.Interfaces.Contains(interfaceDef)) { structDef32.AddInterfaceImplementation(interfaceDef); } if (!structDef64.Interfaces.Contains(interfaceDef)) { structDef64.AddInterfaceImplementation(interfaceDef); } var interfacePropDefs = new ConcurrentDictionary <string, PropertyDefinition>(); var interfaceMethodDefs = new ConcurrentDictionary <string, MethodDefinition>(); var fieldParams32 = new LinkedList <ParameterInfo>( structInfo32.Fields.Select(f => ResolveField(f.Type, f.Name, (int)f.Offset))); var fieldParams64 = new LinkedList <ParameterInfo>( structInfo64.Fields.Select(f => ResolveField(f.Type, f.Name, (int)f.Offset))); var interfacePropNames = new LinkedList <string>(structInfo32.Fields .Select(f => f.Name) .Union(structInfo64.Fields .Select(f => f.Name))); TypeDefinition[] BuildInterfacePropsAndStructFields() { foreach (var fieldParam in fieldParams32) { fieldParam.Complete(TypeRedirects, "32"); } foreach (var fieldParam in fieldParams64) { fieldParam.Complete(TypeRedirects, "64"); } Debug.WriteLine($"Completed dependencies for interface and structure {structName}"); interfacePropNames.ConsumeLinkedList(propName => { BuildInterfaceByRefAccessor(interfaceDef, propName, _splitPointerDefs, fieldParams32.Nodes().First(f => f.Value.Name == propName), fieldParams64.Nodes().First(f => f.Value.Name == propName), out var interfacePropDef, out var interfaceMethodDef); if (interfacePropDef != null) { interfacePropDefs[propName] = interfacePropDef; } if (interfaceMethodDef != null) { interfaceMethodDefs[propName] = interfaceMethodDef; } }); var interfaceType = interfaceDef.IsCreated() ? Module.GetType(interfaceDef.FullName) : interfaceDef.CreateType(); /* * if (!structDef32.ImplementedInterfaces.Contains(interfaceType)) * structDef32.AddInterfaceImplementation(interfaceType); * if (!structDef64.ImplementedInterfaces.Contains(interfaceType)) * structDef64.AddInterfaceImplementation(interfaceType); */ void BuildStructField(ParameterInfo fieldParam, TypeDefinition structDef, int bits) { var ptrSizeForType = bits / 8; var fieldName = fieldParam.Name; var fieldType = fieldParam.Type; var isArray = fieldType.IsArray; // never define an array element on a struct // there should be a fixed buffer attribute on the field if (isArray) { fieldType = fieldType.DescendElementType(); } var fieldDef = PrepareAndDefineField( structDef, isArray, fieldParam, ref fieldType, out var fieldInteriorType, out var fieldTransforms); TypeReference fieldRefType; if (isArray) { fieldRefType = fieldType.MakeByReferenceType(); var intfMethodInfo = interfaceType.GetMethod(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); TypeReference intfMethodType; try { intfMethodType = intfMethodInfo.ReturnType; } catch { intfMethodType = interfaceMethodDefs[fieldName].ReturnType; } var intfMethodElemType = intfMethodType.DescendElementType(); var intfMethodInteriorType = intfMethodType.GetInteriorType(out var methodRetTransforms); if (fieldRefType.Is(intfMethodType) || fieldType.IsPointer && intfMethodElemType.IsPointer || IsIntPtrOrUIntPtr(intfMethodElemType) && fieldType.SizeOf(ptrSizeForType) == ptrSizeForType || IsTypedHandle(intfMethodElemType, fieldType) || fieldInteriorType.Is(intfMethodInteriorType) && fieldTransforms.SequenceEqual(methodRetTransforms.Skip(1))) { //var fixedBufAttrInfo = fieldParam.AttributeInfos.First(ai => ai.Type == FixedBufferAttributeType); var fixedBufSize = fieldParam.ArraySize; var structGetter = structDef.DefineMethod(fieldName, PublicInterfaceImplementationMethodAttributes, intfMethodType, Module.TypeSystem.Int32); structDef.DefineMethodOverride(structGetter, intfMethodInfo); structGetter.DefineParameter(1, ParameterAttributes.In, "index"); SetMethodInliningAttributes(structGetter); structGetter.GenerateIL(il => { var argOutOfRange = default(CecilLabel); if (EmitBoundsChecks) { argOutOfRange = il.DefineLabel(); il.Emit(OpCodes.Ldarg_1); // index il.EmitPushConst(0); // underflow il.Emit(OpCodes.Blt, argOutOfRange); il.Emit(OpCodes.Ldarg_1); // index il.EmitPushConst(fixedBufSize); // overflow il.Emit(OpCodes.Bge, argOutOfRange); } il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldflda, fieldDef); il.Emit(OpCodes.Ldarg_1); // index il.Emit(OpCodes.Sizeof, fieldType); il.Emit(OpCodes.Mul); il.Emit(OpCodes.Add); if (intfMethodType.Resolve().IsInterface) { il.Emit(OpCodes.Box, fieldType); } il.Emit(OpCodes.Ret); if (EmitBoundsChecks) { il.MarkLabel(argOutOfRange); il.Emit(OpCodes.Newobj, ArgumentOutOfRangeCtor); il.Emit(OpCodes.Throw); // ReSharper disable once PossibleNullReferenceException argOutOfRange.Cleanup(); } }); return; } throw new NotImplementedException(); } fieldRefType = fieldType.MakeByReferenceType(); var propInfo = interfaceType.GetProperty(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (propInfo == null) { throw new NotImplementedException(); } TypeReference propType; try { propType = propInfo.PropertyType; } catch { propType = interfacePropDefs[fieldName].PropertyType; } var propInteriorType = propType.GetInteriorType(out var propTransforms).Resolve(); if (propInteriorType == null) { throw new NotImplementedException(); } var propElemType = propType.DescendElementType(); if (fieldRefType.Is(propType) || fieldType.IsPointer && propElemType.IsPointer || IsIntPtrOrUIntPtr(propElemType) && fieldType.SizeOf(ptrSizeForType) == ptrSizeForType || IsTypedHandle(propElemType, fieldType) || fieldInteriorType.Is(propInteriorType) && fieldTransforms.SequenceEqual(propTransforms.Skip(1))) { /* * var structProp = structDef.DefineProperty(fieldName, * PropertyAttributes.SpecialName, * propType, Type.EmptyTypes); */ var structGetter = structDef.DefineMethod("get_" + fieldName, HiddenPropertyMethodAttributes | MethodAttributes.Virtual, propType); SetMethodInliningAttributes(structGetter); //structProp.SetGetMethod(structGetter); structDef.DefineMethodOverride(structGetter, propInfo.Resolve().GetMethod); structGetter.GenerateIL(il => { il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Ldflda, fieldDef); if (propInteriorType.IsInterface) { il.Emit(OpCodes.Box, fieldType); } il.Emit(OpCodes.Ret); }); return; } if (propType.Is(Module.TypeSystem.Object)) { // TODO: boxing reference throw new NotImplementedException(); } if (propType.IsAssignableFrom(fieldType)) { // TODO: boxed interface throw new NotImplementedException(); } throw new NotImplementedException(); } fieldParams32.ConsumeLinkedList(fieldParam => BuildStructField(fieldParam, structDef32, 32)); var structType32 = structDef32; fieldParams64.ConsumeLinkedList(fieldParam => BuildStructField(fieldParam, structDef64, 64)); var structType64 = structDef64; return(new[] { interfaceType, structType32, structType64 }); } return(BuildInterfacePropsAndStructFields); }