PageRenderTime 41ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/_ctypes/SimpleType.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 811 lines | 666 code | 112 blank | 33 comment | 49 complexity | 3872328a08ad49e5327c2457e7b4ad3a MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. 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 Microsoft Public License, 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 Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Reflection.Emit;
  18. using System.Runtime.CompilerServices;
  19. using System.Runtime.InteropServices;
  20. using Microsoft.Scripting;
  21. using Microsoft.Scripting.Runtime;
  22. using IronPython.Runtime;
  23. using IronPython.Runtime.Operations;
  24. using IronPython.Runtime.Types;
  25. #if CLR2
  26. using Microsoft.Scripting.Math;
  27. #else
  28. using System.Numerics;
  29. #endif
  30. #if !SILVERLIGHT
  31. namespace IronPython.Modules {
  32. /// <summary>
  33. /// Provides support for interop with native code from Python code.
  34. /// </summary>
  35. public static partial class CTypes {
  36. /// <summary>
  37. /// The meta class for ctypes simple data types. These include primitives like ints,
  38. /// floats, etc... char/wchar pointers, and untyped pointers.
  39. /// </summary>
  40. [PythonType, PythonHidden]
  41. public class SimpleType : PythonType, INativeType {
  42. internal readonly SimpleTypeKind _type;
  43. private readonly char _charType;
  44. public SimpleType(CodeContext/*!*/ context, string name, PythonTuple bases, PythonDictionary dict)
  45. : base(context, name, bases, dict) {
  46. object val;
  47. string sVal;
  48. const string allowedTypes = "?cbBghHiIlLdfuzZqQPXOv";
  49. if (!TryGetBoundCustomMember(context, "_type_", out val) ||
  50. (sVal = StringOps.AsString(val)) == null ||
  51. sVal.Length != 1 ||
  52. allowedTypes.IndexOf(sVal[0]) == -1) {
  53. throw PythonOps.AttributeError("AttributeError: class must define a '_type_' attribute which must be a single character string containing one of '{0}'.", allowedTypes);
  54. }
  55. _charType = sVal[0];
  56. switch (sVal[0]) {
  57. case '?': _type = SimpleTypeKind.Boolean; break;
  58. case 'c': _type = SimpleTypeKind.Char; break;
  59. case 'b': _type = SimpleTypeKind.SignedByte; break;
  60. case 'B': _type = SimpleTypeKind.UnsignedByte; break;
  61. case 'h': _type = SimpleTypeKind.SignedShort; break;
  62. case 'H': _type = SimpleTypeKind.UnsignedShort; break;
  63. case 'i': _type = SimpleTypeKind.SignedInt; break;
  64. case 'I': _type = SimpleTypeKind.UnsignedInt; break;
  65. case 'l': _type = SimpleTypeKind.SignedLong; break;
  66. case 'L': _type = SimpleTypeKind.UnsignedLong; break;
  67. case 'f': _type = SimpleTypeKind.Single; break;
  68. case 'g': // long double, new in 2.6
  69. case 'd': _type = SimpleTypeKind.Double; break;
  70. case 'q': _type = SimpleTypeKind.SignedLongLong; break;
  71. case 'Q': _type = SimpleTypeKind.UnsignedLongLong; break;
  72. case 'O': _type = SimpleTypeKind.Object; break;
  73. case 'P': _type = SimpleTypeKind.Pointer; break;
  74. case 'z': _type = SimpleTypeKind.CharPointer; break;
  75. case 'Z': _type = SimpleTypeKind.WCharPointer; break;
  76. case 'u': _type = SimpleTypeKind.WChar; break;
  77. case 'v': _type = SimpleTypeKind.VariantBool; break;
  78. case 'X':
  79. throw new NotImplementedException("simple type " + sVal);
  80. }
  81. }
  82. private SimpleType(Type underlyingSystemType)
  83. : base(underlyingSystemType) {
  84. }
  85. public static ArrayType/*!*/ operator *(SimpleType type, int count) {
  86. return MakeArrayType(type, count);
  87. }
  88. public static ArrayType/*!*/ operator *(int count, SimpleType type) {
  89. return MakeArrayType(type, count);
  90. }
  91. internal static PythonType MakeSystemType(Type underlyingSystemType) {
  92. return PythonType.SetPythonType(underlyingSystemType, new SimpleType(underlyingSystemType));
  93. }
  94. public SimpleCData from_address(CodeContext/*!*/ context, int address) {
  95. return from_address(context, new IntPtr(address));
  96. }
  97. public SimpleCData from_address(CodeContext/*!*/ context, BigInteger address) {
  98. return from_address(context, new IntPtr((long)address));
  99. }
  100. public SimpleCData from_address(CodeContext/*!*/ context, IntPtr ptr) {
  101. SimpleCData res = (SimpleCData)CreateInstance(context);
  102. res.SetAddress(ptr);
  103. return res;
  104. }
  105. public SimpleCData from_buffer(ArrayModule.array array, [DefaultParameterValue(0)]int offset) {
  106. ValidateArraySizes(array, offset, ((INativeType)this).Size);
  107. SimpleCData res = (SimpleCData)CreateInstance(Context.SharedContext);
  108. IntPtr addr = array.GetArrayAddress();
  109. res._memHolder = new MemoryHolder(addr.Add(offset), ((INativeType)this).Size);
  110. res._memHolder.AddObject("ffffffff", array);
  111. return res;
  112. }
  113. public SimpleCData from_buffer_copy(ArrayModule.array array, [DefaultParameterValue(0)]int offset) {
  114. ValidateArraySizes(array, offset, ((INativeType)this).Size);
  115. SimpleCData res = (SimpleCData)CreateInstance(Context.SharedContext);
  116. res._memHolder = new MemoryHolder(((INativeType)this).Size);
  117. res._memHolder.CopyFrom(array.GetArrayAddress().Add(offset), new IntPtr(((INativeType)this).Size));
  118. GC.KeepAlive(array);
  119. return res;
  120. }
  121. /// <summary>
  122. /// Converts an object into a function call parameter.
  123. /// </summary>
  124. public object from_param(object obj) {
  125. // TODO: This isn't right as we have an obj associated w/ the argument, CPython doesn't.
  126. return new NativeArgument((CData)PythonCalls.Call(this, obj), _charType.ToString());
  127. }
  128. public SimpleCData in_dll(CodeContext/*!*/ context, object library, string name) {
  129. IntPtr handle = GetHandleFromObject(library, "in_dll expected object with _handle attribute");
  130. IntPtr addr = NativeFunctions.LoadFunction(handle, name);
  131. if (addr == IntPtr.Zero) {
  132. throw PythonOps.ValueError("{0} not found when attempting to load {1} from dll", name, Name);
  133. }
  134. SimpleCData res = (SimpleCData)CreateInstance(context);
  135. res.SetAddress(addr);
  136. return res;
  137. }
  138. #region INativeType Members
  139. int INativeType.Size {
  140. get {
  141. switch (_type) {
  142. case SimpleTypeKind.Char:
  143. case SimpleTypeKind.SignedByte:
  144. case SimpleTypeKind.UnsignedByte:
  145. case SimpleTypeKind.Boolean:
  146. return 1;
  147. case SimpleTypeKind.SignedShort:
  148. case SimpleTypeKind.UnsignedShort:
  149. case SimpleTypeKind.WChar:
  150. case SimpleTypeKind.VariantBool:
  151. return 2;
  152. case SimpleTypeKind.SignedInt:
  153. case SimpleTypeKind.UnsignedInt:
  154. case SimpleTypeKind.UnsignedLong:
  155. case SimpleTypeKind.SignedLong:
  156. case SimpleTypeKind.Single:
  157. return 4;
  158. case SimpleTypeKind.Double:
  159. case SimpleTypeKind.UnsignedLongLong:
  160. case SimpleTypeKind.SignedLongLong:
  161. return 8;
  162. case SimpleTypeKind.Object:
  163. case SimpleTypeKind.Pointer:
  164. case SimpleTypeKind.CharPointer:
  165. case SimpleTypeKind.WCharPointer:
  166. return IntPtr.Size;
  167. }
  168. throw new InvalidOperationException(_type.ToString());
  169. }
  170. }
  171. int INativeType.Alignment {
  172. get {
  173. return ((INativeType)this).Size;
  174. }
  175. }
  176. object INativeType.GetValue(MemoryHolder/*!*/ owner, object readingFrom, int offset, bool raw) {
  177. object res;
  178. switch (_type) {
  179. case SimpleTypeKind.Boolean: res = owner.ReadByte(offset) != 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False; break;
  180. case SimpleTypeKind.Char: res = new string((char)owner.ReadByte(offset), 1); break;
  181. case SimpleTypeKind.SignedByte: res = GetIntReturn((int)(sbyte)owner.ReadByte(offset)); break;
  182. case SimpleTypeKind.UnsignedByte: res = GetIntReturn((int)owner.ReadByte(offset)); break;
  183. case SimpleTypeKind.SignedShort: res = GetIntReturn((int)owner.ReadInt16(offset)); break;
  184. case SimpleTypeKind.WChar: res = new string((char)owner.ReadInt16(offset), 1); break;
  185. case SimpleTypeKind.UnsignedShort: res = GetIntReturn((int)(ushort)owner.ReadInt16(offset)); break;
  186. case SimpleTypeKind.VariantBool: res = owner.ReadInt16(offset) != 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False; break;
  187. case SimpleTypeKind.SignedInt: res = GetIntReturn((int)owner.ReadInt32(offset)); break;
  188. case SimpleTypeKind.UnsignedInt: res = GetIntReturn((uint)owner.ReadInt32(offset)); break;
  189. case SimpleTypeKind.UnsignedLong: res = GetIntReturn((uint)owner.ReadInt32(offset)); break;
  190. case SimpleTypeKind.SignedLong: res = GetIntReturn(owner.ReadInt32(offset)); break;
  191. case SimpleTypeKind.Single: res = GetSingleReturn(owner.ReadInt32(offset)); break;
  192. case SimpleTypeKind.Double: res = GetDoubleReturn(owner.ReadInt64(offset)); break;
  193. case SimpleTypeKind.UnsignedLongLong: res = GetIntReturn((ulong)owner.ReadInt64(offset)); break;
  194. case SimpleTypeKind.SignedLongLong: res = GetIntReturn(owner.ReadInt64(offset)); break;
  195. case SimpleTypeKind.Object: res = GetObjectReturn(owner.ReadIntPtr(offset)); break;
  196. case SimpleTypeKind.Pointer: res = owner.ReadIntPtr(offset).ToPython(); break;
  197. case SimpleTypeKind.CharPointer: res = owner.ReadMemoryHolder(offset).ReadAnsiString(0); break;
  198. case SimpleTypeKind.WCharPointer: res = owner.ReadMemoryHolder(offset).ReadUnicodeString(0); break;
  199. default:
  200. throw new InvalidOperationException();
  201. }
  202. if (!raw && IsSubClass) {
  203. res = PythonCalls.Call(this, res);
  204. }
  205. return res;
  206. }
  207. /// <summary>
  208. /// Helper function for reading char/wchar's. This is used for reading from
  209. /// arrays and pointers to avoid creating lots of 1-char strings.
  210. /// </summary>
  211. internal char ReadChar(MemoryHolder/*!*/ owner, int offset) {
  212. switch (_type) {
  213. case SimpleTypeKind.Char: return (char)owner.ReadByte(offset);
  214. case SimpleTypeKind.WChar: return (char)owner.ReadInt16(offset);
  215. default: throw new InvalidOperationException();
  216. }
  217. }
  218. object INativeType.SetValue(MemoryHolder/*!*/ owner, int offset, object value) {
  219. SimpleCData data = value as SimpleCData;
  220. if (data != null && data.NativeType == this) {
  221. data._memHolder.CopyTo(owner, offset, ((INativeType)this).Size);
  222. return null;
  223. }
  224. switch (_type) {
  225. case SimpleTypeKind.Boolean: owner.WriteByte(offset, ModuleOps.GetBoolean(value, this)); break;
  226. case SimpleTypeKind.Char: owner.WriteByte(offset, ModuleOps.GetChar(value, this)); break;
  227. case SimpleTypeKind.SignedByte: owner.WriteByte(offset, ModuleOps.GetSignedByte(value, this)); break;
  228. case SimpleTypeKind.UnsignedByte: owner.WriteByte(offset, ModuleOps.GetUnsignedByte(value, this)); break;
  229. case SimpleTypeKind.WChar: owner.WriteInt16(offset, (short)ModuleOps.GetWChar(value, this)); break;
  230. case SimpleTypeKind.SignedShort: owner.WriteInt16(offset, ModuleOps.GetSignedShort(value, this)); break;
  231. case SimpleTypeKind.UnsignedShort: owner.WriteInt16(offset, ModuleOps.GetUnsignedShort(value, this)); break;
  232. case SimpleTypeKind.VariantBool: owner.WriteInt16(offset, (short)ModuleOps.GetVariantBool(value, this)); break;
  233. case SimpleTypeKind.SignedInt: owner.WriteInt32(offset, ModuleOps.GetSignedInt(value, this)); break;
  234. case SimpleTypeKind.UnsignedInt: owner.WriteInt32(offset, ModuleOps.GetUnsignedInt(value, this)); break;
  235. case SimpleTypeKind.UnsignedLong: owner.WriteInt32(offset, ModuleOps.GetUnsignedLong(value, this)); break;
  236. case SimpleTypeKind.SignedLong: owner.WriteInt32(offset, ModuleOps.GetSignedLong(value, this)); break;
  237. case SimpleTypeKind.Single: owner.WriteInt32(offset, ModuleOps.GetSingleBits(value)); break;
  238. case SimpleTypeKind.Double: owner.WriteInt64(offset, ModuleOps.GetDoubleBits(value)); break;
  239. case SimpleTypeKind.UnsignedLongLong: owner.WriteInt64(offset, ModuleOps.GetUnsignedLongLong(value, this)); break;
  240. case SimpleTypeKind.SignedLongLong: owner.WriteInt64(offset, ModuleOps.GetSignedLongLong(value, this)); break;
  241. case SimpleTypeKind.Object: owner.WriteIntPtr(offset, ModuleOps.GetObject(value)); break;
  242. case SimpleTypeKind.Pointer: owner.WriteIntPtr(offset, ModuleOps.GetPointer(value)); break;
  243. case SimpleTypeKind.CharPointer:
  244. owner.WriteIntPtr(offset, ModuleOps.GetCharPointer(value));
  245. return value;
  246. case SimpleTypeKind.WCharPointer:
  247. owner.WriteIntPtr(offset, ModuleOps.GetWCharPointer(value));
  248. return value;
  249. default:
  250. throw new InvalidOperationException();
  251. }
  252. return null;
  253. }
  254. Type/*!*/ INativeType.GetNativeType() {
  255. switch (_type) {
  256. case SimpleTypeKind.Boolean:
  257. return typeof(bool);
  258. case SimpleTypeKind.Char:
  259. return typeof(byte);
  260. case SimpleTypeKind.SignedByte:
  261. return typeof(sbyte);
  262. case SimpleTypeKind.UnsignedByte:
  263. return typeof(byte);
  264. case SimpleTypeKind.SignedShort:
  265. case SimpleTypeKind.VariantBool:
  266. return typeof(short);
  267. case SimpleTypeKind.UnsignedShort:
  268. return typeof(ushort);
  269. case SimpleTypeKind.WChar:
  270. return typeof(char);
  271. case SimpleTypeKind.SignedInt:
  272. case SimpleTypeKind.SignedLong:
  273. return typeof(int);
  274. case SimpleTypeKind.UnsignedInt:
  275. case SimpleTypeKind.UnsignedLong:
  276. return typeof(uint);
  277. case SimpleTypeKind.Single:
  278. return typeof(float);
  279. case SimpleTypeKind.Double:
  280. return typeof(double);
  281. case SimpleTypeKind.UnsignedLongLong:
  282. return typeof(ulong);
  283. case SimpleTypeKind.SignedLongLong:
  284. return typeof(long);
  285. case SimpleTypeKind.Object:
  286. return typeof(IntPtr);
  287. case SimpleTypeKind.Pointer:
  288. case SimpleTypeKind.CharPointer:
  289. case SimpleTypeKind.WCharPointer:
  290. return typeof(IntPtr);
  291. }
  292. throw new InvalidOperationException();
  293. }
  294. MarshalCleanup INativeType.EmitMarshalling(ILGenerator/*!*/ method, LocalOrArg argIndex, List<object>/*!*/ constantPool, int constantPoolArgument) {
  295. MarshalCleanup cleanup = null;
  296. Label marshalled = method.DefineLabel();
  297. Type argumentType = argIndex.Type;
  298. if (!argumentType.IsValueType && _type != SimpleTypeKind.Object && _type != SimpleTypeKind.Pointer) {
  299. // check if we have an explicit CData instance. If we have a CData but it's the
  300. // wrong type CheckSimpleCDataType will throw.
  301. Label primitive = method.DefineLabel();
  302. argIndex.Emit(method);
  303. constantPool.Add(this);
  304. method.Emit(OpCodes.Ldarg, constantPoolArgument);
  305. method.Emit(OpCodes.Ldc_I4, constantPool.Count - 1);
  306. method.Emit(OpCodes.Ldelem_Ref);
  307. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("CheckSimpleCDataType"));
  308. method.Emit(OpCodes.Brfalse, primitive);
  309. argIndex.Emit(method);
  310. method.Emit(OpCodes.Castclass, typeof(CData));
  311. method.Emit(OpCodes.Call, typeof(CData).GetMethod("get_UnsafeAddress"));
  312. method.Emit(OpCodes.Ldobj, ((INativeType)this).GetNativeType());
  313. method.Emit(OpCodes.Br, marshalled);
  314. method.MarkLabel(primitive);
  315. }
  316. argIndex.Emit(method);
  317. if (argumentType.IsValueType) {
  318. method.Emit(OpCodes.Box, argumentType);
  319. }
  320. switch (_type) {
  321. case SimpleTypeKind.Boolean:
  322. case SimpleTypeKind.Char:
  323. case SimpleTypeKind.SignedByte:
  324. case SimpleTypeKind.UnsignedByte:
  325. case SimpleTypeKind.SignedShort:
  326. case SimpleTypeKind.UnsignedShort:
  327. case SimpleTypeKind.WChar:
  328. case SimpleTypeKind.SignedInt:
  329. case SimpleTypeKind.UnsignedInt:
  330. case SimpleTypeKind.UnsignedLong:
  331. case SimpleTypeKind.SignedLong:
  332. case SimpleTypeKind.Single:
  333. case SimpleTypeKind.Double:
  334. case SimpleTypeKind.UnsignedLongLong:
  335. case SimpleTypeKind.SignedLongLong:
  336. case SimpleTypeKind.VariantBool:
  337. constantPool.Add(this);
  338. method.Emit(OpCodes.Ldarg, constantPoolArgument);
  339. method.Emit(OpCodes.Ldc_I4, constantPool.Count - 1);
  340. method.Emit(OpCodes.Ldelem_Ref);
  341. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("Get" + _type));
  342. break;
  343. case SimpleTypeKind.Pointer:
  344. Label done = method.DefineLabel();
  345. TryBytesConversion(method, done);
  346. Label isNull = method.DefineLabel(), nextTry = method.DefineLabel();
  347. argIndex.Emit(method);
  348. if (argumentType.IsValueType) {
  349. method.Emit(OpCodes.Box, argumentType);
  350. }
  351. method.Emit(OpCodes.Isinst, typeof(string));
  352. method.Emit(OpCodes.Dup);
  353. method.Emit(OpCodes.Brfalse, nextTry);
  354. LocalBuilder lb = method.DeclareLocal(typeof(string), true);
  355. method.Emit(OpCodes.Stloc, lb);
  356. method.Emit(OpCodes.Ldloc, lb);
  357. method.Emit(OpCodes.Conv_I);
  358. method.Emit(OpCodes.Ldc_I4, RuntimeHelpers.OffsetToStringData);
  359. method.Emit(OpCodes.Add);
  360. method.Emit(OpCodes.Br, done);
  361. method.MarkLabel(nextTry);
  362. method.Emit(OpCodes.Pop);
  363. argIndex.Emit(method);
  364. if (argumentType.IsValueType) {
  365. method.Emit(OpCodes.Box, argumentType);
  366. }
  367. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("GetPointer"));
  368. method.MarkLabel(done);
  369. break;
  370. case SimpleTypeKind.Object:
  371. // TODO: Need cleanup here
  372. method.Emit(OpCodes.Call, typeof(CTypes).GetMethod("PyObj_ToPtr"));
  373. break;
  374. case SimpleTypeKind.CharPointer:
  375. done = method.DefineLabel();
  376. TryToCharPtrConversion(method, argIndex, argumentType, done);
  377. cleanup = MarshalCharPointer(method, argIndex);
  378. method.MarkLabel(done);
  379. break;
  380. case SimpleTypeKind.WCharPointer:
  381. done = method.DefineLabel();
  382. TryArrayToWCharPtrConversion(method, argIndex, argumentType, done);
  383. MarshalWCharPointer(method, argIndex);
  384. method.MarkLabel(done);
  385. break;
  386. }
  387. method.MarkLabel(marshalled);
  388. return cleanup;
  389. }
  390. private static void TryBytesConversion(ILGenerator method, Label done) {
  391. Label nextTry = method.DefineLabel();
  392. LocalBuilder lb = method.DeclareLocal(typeof(byte).MakeByRefType(), true);
  393. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("TryCheckBytes"));
  394. method.Emit(OpCodes.Dup);
  395. method.Emit(OpCodes.Brfalse, nextTry);
  396. method.Emit(OpCodes.Ldc_I4_0);
  397. method.Emit(OpCodes.Ldelema, typeof(Byte));
  398. method.Emit(OpCodes.Stloc, lb);
  399. method.Emit(OpCodes.Ldloc, lb);
  400. method.Emit(OpCodes.Br, done);
  401. method.MarkLabel(nextTry);
  402. method.Emit(OpCodes.Pop);
  403. }
  404. internal static void TryArrayToWCharPtrConversion(ILGenerator method, LocalOrArg argIndex, Type argumentType, Label done) {
  405. Label nextTry = method.DefineLabel();
  406. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("TryCheckWCharArray"));
  407. method.Emit(OpCodes.Dup);
  408. method.Emit(OpCodes.Brfalse, nextTry);
  409. method.Emit(OpCodes.Call, typeof(CData).GetMethod("get_UnsafeAddress"));
  410. method.Emit(OpCodes.Br, done);
  411. method.MarkLabel(nextTry);
  412. method.Emit(OpCodes.Pop);
  413. argIndex.Emit(method);
  414. if (argumentType.IsValueType) {
  415. method.Emit(OpCodes.Box, argumentType);
  416. }
  417. }
  418. internal static void TryToCharPtrConversion(ILGenerator method, LocalOrArg argIndex, Type argumentType, Label done) {
  419. TryBytesConversion(method, done);
  420. Label nextTry = method.DefineLabel();
  421. argIndex.Emit(method);
  422. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("TryCheckCharArray"));
  423. method.Emit(OpCodes.Dup);
  424. method.Emit(OpCodes.Brfalse, nextTry);
  425. method.Emit(OpCodes.Call, typeof(CData).GetMethod("get_UnsafeAddress"));
  426. method.Emit(OpCodes.Br, done);
  427. method.MarkLabel(nextTry);
  428. method.Emit(OpCodes.Pop);
  429. argIndex.Emit(method);
  430. if (argumentType.IsValueType) {
  431. method.Emit(OpCodes.Box, argumentType);
  432. }
  433. }
  434. internal static void MarshalWCharPointer(ILGenerator method, LocalOrArg argIndex) {
  435. Type argumentType = argIndex.Type;
  436. Label isNull;
  437. Label done;
  438. LocalBuilder lb;
  439. isNull = method.DefineLabel();
  440. done = method.DefineLabel();
  441. method.Emit(OpCodes.Brfalse, isNull);
  442. argIndex.Emit(method);
  443. if (argumentType.IsValueType) {
  444. method.Emit(OpCodes.Box, argumentType);
  445. }
  446. lb = method.DeclareLocal(typeof(string), true);
  447. method.Emit(OpCodes.Stloc, lb);
  448. method.Emit(OpCodes.Ldloc, lb);
  449. method.Emit(OpCodes.Conv_I);
  450. method.Emit(OpCodes.Ldc_I4, RuntimeHelpers.OffsetToStringData);
  451. method.Emit(OpCodes.Add);
  452. method.Emit(OpCodes.Br, done);
  453. method.MarkLabel(isNull);
  454. method.Emit(OpCodes.Ldc_I4_0);
  455. method.Emit(OpCodes.Conv_I);
  456. method.MarkLabel(done);
  457. }
  458. internal static MarshalCleanup MarshalCharPointer(ILGenerator method, LocalOrArg argIndex) {
  459. Type argumentType = argIndex.Type;
  460. Label isNull, done;
  461. LocalBuilder lb;
  462. isNull = method.DefineLabel();
  463. done = method.DefineLabel();
  464. method.Emit(OpCodes.Brfalse, isNull);
  465. argIndex.Emit(method);
  466. if (argumentType.IsValueType) {
  467. method.Emit(OpCodes.Box, argumentType);
  468. }
  469. lb = method.DeclareLocal(typeof(IntPtr));
  470. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("StringToHGlobalAnsi"));
  471. method.Emit(OpCodes.Stloc, lb);
  472. method.Emit(OpCodes.Ldloc, lb);
  473. method.Emit(OpCodes.Br, done);
  474. method.MarkLabel(isNull);
  475. method.Emit(OpCodes.Ldc_I4_0);
  476. method.Emit(OpCodes.Conv_I);
  477. method.MarkLabel(done);
  478. return new StringCleanup(lb);
  479. }
  480. Type/*!*/ INativeType.GetPythonType() {
  481. if (IsSubClass) {
  482. return typeof(object);
  483. }
  484. return GetPythonTypeWorker();
  485. }
  486. private Type GetPythonTypeWorker() {
  487. switch (_type) {
  488. case SimpleTypeKind.Boolean:
  489. return typeof(bool);
  490. case SimpleTypeKind.CharPointer:
  491. case SimpleTypeKind.WCharPointer:
  492. case SimpleTypeKind.WChar:
  493. case SimpleTypeKind.Char:
  494. return typeof(string);
  495. case SimpleTypeKind.VariantBool:
  496. case SimpleTypeKind.SignedByte:
  497. case SimpleTypeKind.UnsignedByte:
  498. case SimpleTypeKind.SignedShort:
  499. case SimpleTypeKind.UnsignedShort:
  500. case SimpleTypeKind.SignedInt:
  501. case SimpleTypeKind.SignedLong:
  502. return typeof(int);
  503. case SimpleTypeKind.UnsignedInt:
  504. case SimpleTypeKind.UnsignedLong:
  505. case SimpleTypeKind.UnsignedLongLong:
  506. case SimpleTypeKind.SignedLongLong:
  507. case SimpleTypeKind.Pointer:
  508. case SimpleTypeKind.Object:
  509. return typeof(object);
  510. case SimpleTypeKind.Single:
  511. case SimpleTypeKind.Double:
  512. return typeof(double);
  513. default:
  514. throw new InvalidOperationException();
  515. }
  516. }
  517. void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, List<object> constantPool, int constantPoolArgument) {
  518. value.Emit(method);
  519. switch (_type) {
  520. case SimpleTypeKind.SignedByte:
  521. case SimpleTypeKind.UnsignedByte:
  522. case SimpleTypeKind.SignedShort:
  523. case SimpleTypeKind.UnsignedShort:
  524. case SimpleTypeKind.VariantBool:
  525. method.Emit(OpCodes.Conv_I4);
  526. break;
  527. case SimpleTypeKind.SignedInt:
  528. case SimpleTypeKind.SignedLong:
  529. case SimpleTypeKind.Boolean:
  530. break;
  531. case SimpleTypeKind.Single:
  532. method.Emit(OpCodes.Conv_R8);
  533. break;
  534. case SimpleTypeKind.Double:
  535. break;
  536. case SimpleTypeKind.UnsignedLongLong:
  537. case SimpleTypeKind.UnsignedInt:
  538. case SimpleTypeKind.UnsignedLong:
  539. EmitInt32ToObject(method, value);
  540. break;
  541. case SimpleTypeKind.SignedLongLong:
  542. EmitInt64ToObject(method, value);
  543. break;
  544. case SimpleTypeKind.Object:
  545. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("IntPtrToObject"));
  546. break;
  547. case SimpleTypeKind.WCharPointer:
  548. method.Emit(OpCodes.Call, typeof(Marshal).GetMethod("PtrToStringUni", new[] { typeof(IntPtr) }));
  549. break;
  550. case SimpleTypeKind.CharPointer:
  551. method.Emit(OpCodes.Call, typeof(Marshal).GetMethod("PtrToStringAnsi", new[] { typeof(IntPtr) }));
  552. break;
  553. case SimpleTypeKind.Char:
  554. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("CharToString"));
  555. break;
  556. case SimpleTypeKind.WChar:
  557. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("WCharToString"));
  558. break;
  559. case SimpleTypeKind.Pointer:
  560. Label done, notNull;
  561. done = method.DefineLabel();
  562. notNull = method.DefineLabel();
  563. if (IntPtr.Size == 4) {
  564. LocalBuilder tmpLocal = method.DeclareLocal(typeof(uint));
  565. method.Emit(OpCodes.Conv_U4);
  566. method.Emit(OpCodes.Stloc, tmpLocal);
  567. method.Emit(OpCodes.Ldloc, tmpLocal);
  568. method.Emit(OpCodes.Ldc_I4_0);
  569. method.Emit(OpCodes.Conv_U4);
  570. method.Emit(OpCodes.Bne_Un, notNull);
  571. method.Emit(OpCodes.Ldnull);
  572. method.Emit(OpCodes.Br, done);
  573. method.MarkLabel(notNull);
  574. method.Emit(OpCodes.Ldloc, tmpLocal);
  575. EmitInt32ToObject(method, new Local(tmpLocal));
  576. } else {
  577. LocalBuilder tmpLocal = method.DeclareLocal(typeof(long));
  578. method.Emit(OpCodes.Conv_I8);
  579. method.Emit(OpCodes.Stloc, tmpLocal);
  580. method.Emit(OpCodes.Ldloc, tmpLocal);
  581. method.Emit(OpCodes.Ldc_I4_0);
  582. method.Emit(OpCodes.Conv_U8);
  583. method.Emit(OpCodes.Bne_Un, notNull);
  584. method.Emit(OpCodes.Ldnull);
  585. method.Emit(OpCodes.Br, done);
  586. method.MarkLabel(notNull);
  587. method.Emit(OpCodes.Ldloc, tmpLocal);
  588. EmitInt64ToObject(method, new Local(tmpLocal));
  589. }
  590. method.MarkLabel(done);
  591. break;
  592. }
  593. if (IsSubClass) {
  594. LocalBuilder tmp = method.DeclareLocal(typeof(object));
  595. if (GetPythonTypeWorker().IsValueType) {
  596. method.Emit(OpCodes.Box, GetPythonTypeWorker());
  597. }
  598. method.Emit(OpCodes.Stloc, tmp);
  599. constantPool.Add(this);
  600. method.Emit(OpCodes.Ldarg, constantPoolArgument);
  601. method.Emit(OpCodes.Ldc_I4, constantPool.Count - 1);
  602. method.Emit(OpCodes.Ldelem_Ref);
  603. method.Emit(OpCodes.Ldloc, tmp);
  604. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("CreateSubclassInstance"));
  605. }
  606. }
  607. private static void EmitInt64ToObject(ILGenerator method, LocalOrArg value) {
  608. Label done;
  609. Label bigInt = method.DefineLabel();
  610. done = method.DefineLabel();
  611. method.Emit(OpCodes.Ldc_I4, Int32.MaxValue);
  612. method.Emit(OpCodes.Conv_I8);
  613. method.Emit(OpCodes.Bgt, bigInt);
  614. value.Emit(method);
  615. method.Emit(OpCodes.Ldc_I4, Int32.MinValue);
  616. method.Emit(OpCodes.Conv_I8);
  617. method.Emit(OpCodes.Blt, bigInt);
  618. value.Emit(method);
  619. method.Emit(OpCodes.Conv_I4);
  620. method.Emit(OpCodes.Box, typeof(int));
  621. method.Emit(OpCodes.Br, done);
  622. method.MarkLabel(bigInt);
  623. value.Emit(method);
  624. method.Emit(OpCodes.Call, typeof(BigInteger).GetMethod("op_Implicit", new[] { value.Type }));
  625. #if !CLR2
  626. method.Emit(OpCodes.Box, typeof(BigInteger));
  627. #endif
  628. method.MarkLabel(done);
  629. }
  630. private static void EmitInt32ToObject(ILGenerator method, LocalOrArg value) {
  631. Label intVal, done;
  632. intVal = method.DefineLabel();
  633. done = method.DefineLabel();
  634. method.Emit(OpCodes.Ldc_I4, Int32.MaxValue);
  635. method.Emit(value.Type == typeof(uint) ? OpCodes.Conv_U4 : OpCodes.Conv_U8);
  636. method.Emit(OpCodes.Ble, intVal);
  637. value.Emit(method);
  638. method.Emit(OpCodes.Call, typeof(BigInteger).GetMethod("op_Implicit", new[] { value.Type }));
  639. #if !CLR2
  640. method.Emit(OpCodes.Box, typeof(BigInteger));
  641. #endif
  642. method.Emit(OpCodes.Br, done);
  643. method.MarkLabel(intVal);
  644. value.Emit(method);
  645. method.Emit(OpCodes.Conv_I4);
  646. method.Emit(OpCodes.Box, typeof(int));
  647. method.MarkLabel(done);
  648. }
  649. private bool IsSubClass {
  650. get {
  651. return BaseTypes.Count != 1 || BaseTypes[0] != CTypes._SimpleCData;
  652. }
  653. }
  654. private object GetObjectReturn(IntPtr intPtr) {
  655. GCHandle handle = GCHandle.FromIntPtr(intPtr);
  656. object res = handle.Target;
  657. // TODO: handle lifetime management
  658. return res;
  659. }
  660. private object GetDoubleReturn(long p) {
  661. return BitConverter.ToDouble(BitConverter.GetBytes(p), 0);
  662. }
  663. private object GetSingleReturn(int p) {
  664. return BitConverter.ToSingle(BitConverter.GetBytes(p), 0);
  665. }
  666. private static object GetIntReturn(int value) {
  667. return ScriptingRuntimeHelpers.Int32ToObject((int)value);
  668. }
  669. private static object GetIntReturn(uint value) {
  670. if (value > Int32.MaxValue) {
  671. return (BigInteger)value;
  672. }
  673. return ScriptingRuntimeHelpers.Int32ToObject((int)value);
  674. }
  675. private static object GetIntReturn(long value) {
  676. if (value <= Int32.MaxValue && value >= Int32.MinValue) {
  677. return (int)value;
  678. }
  679. return (BigInteger)value;
  680. }
  681. private static object GetIntReturn(ulong value) {
  682. if (value <= Int32.MaxValue) {
  683. return (int)value;
  684. }
  685. return (BigInteger)value;
  686. }
  687. string INativeType.TypeFormat {
  688. get {
  689. return (BitConverter.IsLittleEndian ?
  690. '<' :
  691. '>') +
  692. _charType.ToString();
  693. }
  694. }
  695. #endregion
  696. }
  697. }
  698. }
  699. #endif