PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython.Modules/_ctypes/SimpleType.cs

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