PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/Languages/IronPython/IronPython.Modules/_ctypes/PointerType.cs

http://github.com/IronLanguages/main
C# | 287 lines | 214 code | 44 blank | 29 comment | 41 complexity | 402ef776ba167f75fa7a09a10ff62c50 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if FEATURE_NATIVE
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Reflection.Emit;
  19. using Microsoft.Scripting;
  20. using Microsoft.Scripting.Runtime;
  21. using IronPython.Runtime;
  22. using IronPython.Runtime.Operations;
  23. using IronPython.Runtime.Types;
  24. #if CLR2
  25. using Microsoft.Scripting.Math;
  26. #else
  27. using System.Numerics;
  28. #endif
  29. namespace IronPython.Modules {
  30. /// <summary>
  31. /// Provides support for interop with native code from Python code.
  32. /// </summary>
  33. public static partial class CTypes {
  34. /// <summary>
  35. /// The meta class for ctypes pointers.
  36. /// </summary>
  37. [PythonType, PythonHidden]
  38. public class PointerType : PythonType, INativeType {
  39. internal INativeType _type;
  40. private readonly string _typeFormat;
  41. public PointerType(CodeContext/*!*/ context, string name, PythonTuple bases, PythonDictionary members)
  42. : base(context, name, bases, members) {
  43. object type;
  44. if (members.TryGetValue("_type_", out type) && !(type is INativeType)) {
  45. throw PythonOps.TypeError("_type_ must be a type");
  46. }
  47. _type = (INativeType)type;
  48. if (_type != null) {
  49. _typeFormat = _type.TypeFormat;
  50. }
  51. }
  52. private PointerType(Type underlyingSystemType)
  53. : base(underlyingSystemType) {
  54. }
  55. public object from_param([NotNull]CData obj) {
  56. return new NativeArgument((CData)PythonCalls.Call(this, obj), "P");
  57. }
  58. /// <summary>
  59. /// Converts an object into a function call parameter.
  60. /// </summary>
  61. public object from_param(Pointer obj) {
  62. if (obj == null) {
  63. return ScriptingRuntimeHelpers.Int32ToObject(0);
  64. }
  65. if (obj.NativeType != this) {
  66. throw PythonOps.TypeError("assign to pointer of type {0} from {1} is not valid", Name, ((PythonType)obj.NativeType).Name);
  67. }
  68. Pointer res = (Pointer)PythonCalls.Call(this);
  69. res._memHolder.WriteIntPtr(0, obj._memHolder.ReadMemoryHolder(0));
  70. return res;
  71. }
  72. public object from_param([NotNull]NativeArgument obj) {
  73. return (CData)PythonCalls.Call(this, obj._obj);
  74. }
  75. /// <summary>
  76. /// Access an instance at the specified address
  77. /// </summary>
  78. public object from_address(object obj) {
  79. throw new NotImplementedException("pointer from address");
  80. }
  81. public void set_type(PythonType type) {
  82. _type = (INativeType)type;
  83. }
  84. internal static PythonType MakeSystemType(Type underlyingSystemType) {
  85. return PythonType.SetPythonType(underlyingSystemType, new PointerType(underlyingSystemType));
  86. }
  87. public static ArrayType/*!*/ operator *(PointerType type, int count) {
  88. return MakeArrayType(type, count);
  89. }
  90. public static ArrayType/*!*/ operator *(int count, PointerType type) {
  91. return MakeArrayType(type, count);
  92. }
  93. #region INativeType Members
  94. int INativeType.Size {
  95. get {
  96. return IntPtr.Size;
  97. }
  98. }
  99. int INativeType.Alignment {
  100. get {
  101. return IntPtr.Size;
  102. }
  103. }
  104. object INativeType.GetValue(MemoryHolder owner, object readingFrom, int offset, bool raw) {
  105. if (!raw) {
  106. Pointer res = (Pointer)PythonCalls.Call(Context.SharedContext, this);
  107. res._memHolder.WriteIntPtr(0, owner.ReadIntPtr(offset));
  108. res._memHolder.AddObject(offset, readingFrom);
  109. return res;
  110. }
  111. return owner.ReadIntPtr(offset).ToPython();
  112. }
  113. object INativeType.SetValue(MemoryHolder address, int offset, object value) {
  114. Pointer ptr;
  115. _Array array;
  116. if (value == null) {
  117. address.WriteIntPtr(offset, IntPtr.Zero);
  118. } else if (value is int) {
  119. address.WriteIntPtr(offset, new IntPtr((int)value));
  120. } else if (value is BigInteger) {
  121. address.WriteIntPtr(offset, new IntPtr((long)(BigInteger)value));
  122. } else if ((ptr = value as Pointer) != null) {
  123. address.WriteIntPtr(offset, ptr._memHolder.ReadMemoryHolder(0));
  124. return PythonOps.MakeDictFromItems(ptr, "0", ptr._objects, "1");
  125. } else if ((array = value as _Array) != null) {
  126. address.WriteIntPtr(offset, array._memHolder);
  127. return array;
  128. } else {
  129. throw PythonOps.TypeErrorForTypeMismatch(Name, value);
  130. }
  131. return null;
  132. }
  133. Type INativeType.GetNativeType() {
  134. return typeof(IntPtr);
  135. }
  136. MarshalCleanup INativeType.EmitMarshalling(ILGenerator/*!*/ method, LocalOrArg argIndex, List<object>/*!*/ constantPool, int constantPoolArgument) {
  137. Type argumentType = argIndex.Type;
  138. Label nextTry = method.DefineLabel();
  139. Label done = method.DefineLabel();
  140. if (!argumentType.IsValueType) {
  141. argIndex.Emit(method);
  142. method.Emit(OpCodes.Ldnull);
  143. method.Emit(OpCodes.Bne_Un, nextTry);
  144. method.Emit(OpCodes.Ldc_I4_0);
  145. method.Emit(OpCodes.Conv_I);
  146. method.Emit(OpCodes.Br, done);
  147. }
  148. method.MarkLabel(nextTry);
  149. nextTry = method.DefineLabel();
  150. argIndex.Emit(method);
  151. if (argumentType.IsValueType) {
  152. method.Emit(OpCodes.Box, argumentType);
  153. }
  154. constantPool.Add(this);
  155. SimpleType st = _type as SimpleType;
  156. MarshalCleanup res = null;
  157. if (st != null && !argIndex.Type.IsValueType) {
  158. if (st._type == SimpleTypeKind.Char || st._type == SimpleTypeKind.WChar) {
  159. if (st._type == SimpleTypeKind.Char) {
  160. SimpleType.TryToCharPtrConversion(method, argIndex, argumentType, done);
  161. } else {
  162. SimpleType.TryArrayToWCharPtrConversion(method, argIndex, argumentType, done);
  163. }
  164. Label notStr = method.DefineLabel();
  165. LocalOrArg str = argIndex;
  166. if (argumentType != typeof(string)) {
  167. LocalBuilder lb = method.DeclareLocal(typeof(string));
  168. method.Emit(OpCodes.Isinst, typeof(string));
  169. method.Emit(OpCodes.Brfalse, notStr);
  170. argIndex.Emit(method);
  171. method.Emit(OpCodes.Castclass, typeof(string));
  172. method.Emit(OpCodes.Stloc, lb);
  173. method.Emit(OpCodes.Ldloc, lb);
  174. str = new Local(lb);
  175. }
  176. if (st._type == SimpleTypeKind.Char) {
  177. res = SimpleType.MarshalCharPointer(method, str);
  178. } else {
  179. SimpleType.MarshalWCharPointer(method, str);
  180. }
  181. method.Emit(OpCodes.Br, done);
  182. method.MarkLabel(notStr);
  183. argIndex.Emit(method);
  184. }
  185. }
  186. // native argument being pased (byref)
  187. method.Emit(OpCodes.Ldarg, constantPoolArgument);
  188. method.Emit(OpCodes.Ldc_I4, constantPool.Count - 1);
  189. method.Emit(OpCodes.Ldelem_Ref);
  190. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("CheckNativeArgument"));
  191. method.Emit(OpCodes.Dup);
  192. method.Emit(OpCodes.Brfalse, nextTry);
  193. method.Emit(OpCodes.Call, typeof(CData).GetMethod("get_UnsafeAddress"));
  194. method.Emit(OpCodes.Br, done);
  195. // lone cdata being passed
  196. method.MarkLabel(nextTry);
  197. nextTry = method.DefineLabel();
  198. method.Emit(OpCodes.Pop); // extra null native arg
  199. argIndex.Emit(method);
  200. if (argumentType.IsValueType) {
  201. method.Emit(OpCodes.Box, argumentType);
  202. }
  203. method.Emit(OpCodes.Ldarg, constantPoolArgument);
  204. method.Emit(OpCodes.Ldc_I4, constantPool.Count - 1);
  205. method.Emit(OpCodes.Ldelem_Ref);
  206. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("TryCheckCDataPointerType"));
  207. method.Emit(OpCodes.Dup);
  208. method.Emit(OpCodes.Brfalse, nextTry);
  209. method.Emit(OpCodes.Call, typeof(CData).GetMethod("get_UnsafeAddress"));
  210. method.Emit(OpCodes.Br, done);
  211. // pointer object being passed
  212. method.MarkLabel(nextTry);
  213. method.Emit(OpCodes.Pop); // extra null cdata
  214. argIndex.Emit(method);
  215. if (argumentType.IsValueType) {
  216. method.Emit(OpCodes.Box, argumentType);
  217. }
  218. method.Emit(OpCodes.Ldarg, constantPoolArgument);
  219. method.Emit(OpCodes.Ldc_I4, constantPool.Count - 1);
  220. method.Emit(OpCodes.Ldelem_Ref);
  221. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("CheckCDataType"));
  222. method.Emit(OpCodes.Call, typeof(CData).GetMethod("get_UnsafeAddress"));
  223. method.Emit(OpCodes.Ldind_I);
  224. method.MarkLabel(done);
  225. return res;
  226. }
  227. Type/*!*/ INativeType.GetPythonType() {
  228. return typeof(object);
  229. }
  230. void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, List<object> constantPool, int constantPoolArgument) {
  231. value.Emit(method);
  232. EmitCDataCreation(this, method, constantPool, constantPoolArgument);
  233. }
  234. string INativeType.TypeFormat {
  235. get {
  236. return "&" + (_typeFormat ?? _type.TypeFormat);
  237. }
  238. }
  239. #endregion
  240. }
  241. }
  242. }
  243. #endif