private Func <TypeDefinition[]> DefineClrType(ClangStructInfo structInfo32, ClangStructInfo structInfo64) { if (structInfo32 == null) { return(DefineClrHandleStructInternal(structInfo64, 64)); } if (structInfo64 == null) { return(DefineClrHandleStructInternal(structInfo32, 32)); } return(DefineClrStructInternal(structInfo32, structInfo64)); }
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(ClangStructInfo structInfo) { if (structInfo.Size == 0) { return(DefineClrHandleStructInternal(structInfo)); } var structName = structInfo.Name; Debug.WriteLine($"Defining simple structure {structName}"); if (TypeRedirects.TryGetValue(structName, out var rename)) { structName = rename; } if (Module.GetType(structName)?.Resolve() != null) { return(null); } TypeDefinition structDef = Module.DefineType(structName, PublicSealedStructTypeAttributes, null, (int)structInfo.Alignment, (int)structInfo.Size); structDef.SetCustomAttribute(() => new BinderGeneratedAttribute()); var fieldParams = new LinkedList <ParameterInfo>(structInfo.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 simple structure {structName}"); fieldParams.ConsumeLinkedList(fieldParam => { var fieldName = fieldParam.Name; var fieldType = fieldParam.Type; if (!fieldType.IsArray) { var fieldDef = structDef.DefineField(fieldName, fieldType, FieldAttributes.Public); } else { var arraySize = fieldParam.ArraySize; fieldType = fieldType.DescendElementType(); var offsetPer = fieldType.SizeOf(); if (offsetPer == -1) { throw new NotImplementedException(); } var fieldDef = structDef.DefineField($"{fieldName}[0]", fieldType, FieldAttributes.Private); fieldDef.Offset = fieldParam.Position; for (var i = 1; i < arraySize; ++i) { structDef.DefineField($"{fieldName}[{i}]", fieldType, FieldAttributes.Private) .Offset = fieldParam.Position + i * offsetPer; } var fieldRefType = fieldType.MakeByReferenceType().Import(Module); var unionGetter = structDef.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[] { structDef.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); }