PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython.Modules/_ctypes/CFuncPtr.cs

http://github.com/IronLanguages/main
C# | 966 lines | 702 code | 153 blank | 111 comment | 155 complexity | 7a406045bb121a3576fc875c0f3d4352 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. #if FEATURE_CORE_DLR
  17. using System.Linq.Expressions;
  18. using System.Numerics;
  19. #else
  20. using Microsoft.Scripting.Math;
  21. #endif
  22. using System;
  23. using System.Collections.Generic;
  24. using System.Dynamic;
  25. using System.Diagnostics;
  26. using System.Reflection;
  27. using System.Reflection.Emit;
  28. using System.Runtime.CompilerServices;
  29. using System.Runtime.InteropServices;
  30. using System.Threading;
  31. using Microsoft.Scripting;
  32. using Microsoft.Scripting.Ast;
  33. using Microsoft.Scripting.Generation;
  34. using Microsoft.Scripting.Runtime;
  35. using Microsoft.Scripting.Utils;
  36. using IronPython.Runtime;
  37. using IronPython.Runtime.Binding;
  38. using IronPython.Runtime.Operations;
  39. using IronPython.Runtime.Types;
  40. namespace IronPython.Modules {
  41. /// <summary>
  42. /// Provides support for interop with native code from Python code.
  43. /// </summary>
  44. public static partial class CTypes {
  45. [PythonType("CFuncPtr")]
  46. public abstract class _CFuncPtr : CData, IDynamicMetaObjectProvider, ICodeFormattable {
  47. private readonly Delegate _delegate;
  48. private readonly int _comInterfaceIndex = -1;
  49. private object _errcheck, _restype = _noResType;
  50. private IList<object> _argtypes;
  51. private int _id;
  52. private static int _curId = 0;
  53. internal static object _noResType = new object();
  54. // __nonzero__
  55. /// <summary>
  56. /// Creates a new CFuncPtr object from a tuple. The 1st element of the
  57. /// tuple is the ordinal or function name. The second is an object with
  58. /// a _handle property. The _handle property is the handle of the module
  59. /// from which the function will be loaded.
  60. /// </summary>
  61. public _CFuncPtr(PythonTuple args) {
  62. if (args == null) {
  63. throw PythonOps.TypeError("expected sequence, got None");
  64. } else if (args.Count != 2) {
  65. throw PythonOps.TypeError("argument 1 must be a sequence of length 2, not {0}", args.Count);
  66. }
  67. object nameOrOrdinal = args[0];
  68. object dll = args[1];
  69. IntPtr intPtrHandle = GetHandleFromObject(dll, "the _handle attribute of the second element must be an integer");
  70. IntPtr tmpAddr;
  71. string funcName = args[0] as string;
  72. if (funcName != null) {
  73. tmpAddr = NativeFunctions.LoadFunction(intPtrHandle, funcName);
  74. } else {
  75. tmpAddr = NativeFunctions.LoadFunction(intPtrHandle, new IntPtr((int)nameOrOrdinal));
  76. }
  77. if (tmpAddr == IntPtr.Zero) {
  78. if (CallingConvention == CallingConvention.StdCall && funcName != null) {
  79. // apply std call name mangling - prepend a _, append @bytes where
  80. // bytes is the number of bytes of the argument list.
  81. string mangled = "_" + funcName + "@";
  82. for (int i = 0; i < 128 && tmpAddr == IntPtr.Zero; i += 4) {
  83. tmpAddr = NativeFunctions.LoadFunction(intPtrHandle, mangled + i);
  84. }
  85. }
  86. if (tmpAddr == IntPtr.Zero) {
  87. throw PythonOps.AttributeError("function {0} is not defined", args[0]);
  88. }
  89. }
  90. _memHolder = new MemoryHolder(IntPtr.Size);
  91. addr = tmpAddr;
  92. _id = Interlocked.Increment(ref _curId);
  93. }
  94. public _CFuncPtr() {
  95. _id = Interlocked.Increment(ref _curId);
  96. _memHolder = new MemoryHolder(IntPtr.Size);
  97. }
  98. public _CFuncPtr(CodeContext context, object function) {
  99. _memHolder = new MemoryHolder(IntPtr.Size);
  100. if (function != null) {
  101. if (!PythonOps.IsCallable(context, function)) {
  102. throw PythonOps.TypeError("argument must be called or address of function");
  103. }
  104. _delegate = ((CFuncPtrType)DynamicHelpers.GetPythonType(this)).MakeReverseDelegate(context, function);
  105. addr = Marshal.GetFunctionPointerForDelegate(_delegate);
  106. CFuncPtrType myType = (CFuncPtrType)NativeType;
  107. PythonType resType = myType._restype;
  108. if (resType != null) {
  109. if (!(resType is INativeType) || resType is PointerType) {
  110. throw PythonOps.TypeError("invalid result type {0} for callback function", ((PythonType)resType).Name);
  111. }
  112. }
  113. }
  114. _id = Interlocked.Increment(ref _curId);
  115. }
  116. /// <summary>
  117. /// Creates a new CFuncPtr which calls a COM method.
  118. /// </summary>
  119. public _CFuncPtr(int index, string name) {
  120. _memHolder = new MemoryHolder(IntPtr.Size);
  121. _comInterfaceIndex = index;
  122. _id = Interlocked.Increment(ref _curId);
  123. }
  124. /// <summary>
  125. /// Creates a new CFuncPtr with the specfied address.
  126. /// </summary>
  127. public _CFuncPtr(int handle) {
  128. _memHolder = new MemoryHolder(IntPtr.Size);
  129. addr = new IntPtr(handle);
  130. _id = Interlocked.Increment(ref _curId);
  131. }
  132. /// <summary>
  133. /// Creates a new CFuncPtr with the specfied address.
  134. /// </summary>
  135. public _CFuncPtr([NotNull]BigInteger handle) {
  136. _memHolder = new MemoryHolder(IntPtr.Size);
  137. addr = new IntPtr((long)handle);
  138. _id = Interlocked.Increment(ref _curId);
  139. }
  140. public _CFuncPtr(IntPtr handle) {
  141. _memHolder = new MemoryHolder(IntPtr.Size);
  142. addr = handle;
  143. _id = Interlocked.Increment(ref _curId);
  144. }
  145. public bool __nonzero__() {
  146. return addr != IntPtr.Zero;
  147. }
  148. #region Public APIs
  149. [SpecialName, PropertyMethod]
  150. public object Geterrcheck() {
  151. return _errcheck;
  152. }
  153. [SpecialName, PropertyMethod]
  154. public void Seterrcheck(object value) {
  155. _errcheck = value;
  156. }
  157. [SpecialName, PropertyMethod]
  158. public void Deleteerrcheck() {
  159. _errcheck = null;
  160. _id = Interlocked.Increment(ref _curId);
  161. }
  162. [PropertyMethod, SpecialName]
  163. public object Getrestype() {
  164. if (_restype == _noResType) {
  165. return ((CFuncPtrType)NativeType)._restype;
  166. }
  167. return _restype;
  168. }
  169. [PropertyMethod, SpecialName]
  170. public void Setrestype(object value) {
  171. INativeType nt = value as INativeType;
  172. if (nt != null || value == null || PythonOps.IsCallable(((PythonType)NativeType).Context.SharedContext, value)) {
  173. _restype = value;
  174. _id = Interlocked.Increment(ref _curId);
  175. } else {
  176. throw PythonOps.TypeError("restype must be a type, a callable, or None");
  177. }
  178. }
  179. [SpecialName, PropertyMethod]
  180. public void Deleterestype() {
  181. _restype = _noResType;
  182. _id = Interlocked.Increment(ref _curId);
  183. }
  184. public object argtypes {
  185. get {
  186. if (_argtypes != null) {
  187. return _argtypes;
  188. }
  189. if (((CFuncPtrType)NativeType)._argtypes != null) {
  190. return PythonTuple.MakeTuple(((CFuncPtrType)NativeType)._argtypes);
  191. }
  192. return null;
  193. }
  194. set {
  195. if (value != null) {
  196. IList<object> argValues = value as IList<object>;
  197. if (argValues == null) {
  198. throw PythonOps.TypeErrorForTypeMismatch("sequence", value);
  199. }
  200. foreach (object o in argValues) {
  201. if (!(o is INativeType)) {
  202. if (!PythonOps.HasAttr(DefaultContext.Default, o, "from_param")) {
  203. throw PythonOps.TypeErrorForTypeMismatch("ctype or object with from_param", o);
  204. }
  205. }
  206. }
  207. _argtypes = argValues;
  208. } else {
  209. _argtypes = null;
  210. }
  211. _id = Interlocked.Increment(ref _curId);
  212. }
  213. }
  214. #endregion
  215. #region Internal APIs
  216. internal CallingConvention CallingConvention {
  217. get {
  218. return ((CFuncPtrType)DynamicHelpers.GetPythonType(this)).CallingConvention;
  219. }
  220. }
  221. // TODO: access via PythonOps
  222. public IntPtr addr {
  223. [PythonHidden]
  224. get {
  225. return _memHolder.ReadIntPtr(0);
  226. }
  227. [PythonHidden]
  228. set {
  229. _memHolder.WriteIntPtr(0, value);
  230. }
  231. }
  232. internal int Id {
  233. get {
  234. return _id;
  235. }
  236. }
  237. #endregion
  238. #region IDynamicObject Members
  239. // needs to be public so that derived base classes can call it.
  240. [PythonHidden]
  241. public DynamicMetaObject GetMetaObject(Expression parameter) {
  242. return new Meta(parameter, this);
  243. }
  244. #endregion
  245. #region MetaObject
  246. private class Meta : MetaPythonObject {
  247. public Meta(Expression parameter, _CFuncPtr func)
  248. : base(parameter, BindingRestrictions.Empty, func) {
  249. }
  250. public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) {
  251. CodeContext context = PythonContext.GetPythonContext(binder).SharedContext;
  252. ArgumentMarshaller[] signature = GetArgumentMarshallers(args);
  253. BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction(
  254. Expression,
  255. Value.GetType()
  256. ).Merge(
  257. BindingRestrictions.GetExpressionRestriction(
  258. Expression.Call(
  259. typeof(ModuleOps).GetMethod("CheckFunctionId"),
  260. Expression.Convert(Expression, typeof(_CFuncPtr)),
  261. Expression.Constant(Value.Id)
  262. )
  263. )
  264. );
  265. foreach (var arg in signature) {
  266. restrictions = restrictions.Merge(arg.GetRestrictions());
  267. }
  268. int argCount = args.Length;
  269. if (Value._comInterfaceIndex != -1) {
  270. argCount--;
  271. }
  272. // need to verify we have the correct # of args
  273. if (Value._argtypes != null) {
  274. if (argCount < Value._argtypes.Count || (Value.CallingConvention != CallingConvention.Cdecl && argCount > Value._argtypes.Count)) {
  275. return IncorrectArgCount(binder, restrictions, Value._argtypes.Count, argCount);
  276. }
  277. } else {
  278. CFuncPtrType funcType = ((CFuncPtrType)Value.NativeType);
  279. if (funcType._argtypes != null &&
  280. (argCount < funcType._argtypes.Length || (Value.CallingConvention != CallingConvention.Cdecl && argCount > funcType._argtypes.Length))) {
  281. return IncorrectArgCount(binder, restrictions, funcType._argtypes.Length, argCount);
  282. }
  283. }
  284. if (Value._comInterfaceIndex != -1 && args.Length == 0) {
  285. return NoThisParam(binder, restrictions);
  286. }
  287. Expression call = MakeCall(signature, GetNativeReturnType(), Value.Getrestype() == null, GetFunctionAddress(args));
  288. List<Expression> block = new List<Expression>();
  289. Expression res;
  290. if (call.Type != typeof(void)) {
  291. ParameterExpression tmp = Expression.Parameter(call.Type, "ret");
  292. block.Add(Expression.Assign(tmp, call));
  293. AddKeepAlives(signature, block);
  294. block.Add(tmp);
  295. res = Expression.Block(new[] { tmp }, block);
  296. } else {
  297. block.Add(call);
  298. AddKeepAlives(signature, block);
  299. res = Expression.Block(block);
  300. }
  301. res = AddReturnChecks(context, args, res);
  302. return new DynamicMetaObject(Utils.Convert(res, typeof(object)), restrictions);
  303. }
  304. private Expression AddReturnChecks(CodeContext context, DynamicMetaObject[] args, Expression res) {
  305. PythonContext ctx = PythonContext.GetContext(context);
  306. object resType = Value.Getrestype();
  307. if (resType != null) {
  308. // res type can be callable, a type with _check_retval_, or
  309. // it can be just be a type which doesn't require post-processing.
  310. INativeType nativeResType = resType as INativeType;
  311. object checkRetVal = null;
  312. if (nativeResType == null) {
  313. checkRetVal = resType;
  314. } else if (!PythonOps.TryGetBoundAttr(context, nativeResType, "_check_retval_", out checkRetVal)) {
  315. // we just wanted to try and get the value, don't need to do anything here.
  316. checkRetVal = null;
  317. }
  318. if (checkRetVal != null) {
  319. res = Expression.Dynamic(
  320. ctx.CompatInvoke(new CallInfo(1)),
  321. typeof(object),
  322. Expression.Constant(checkRetVal),
  323. res
  324. );
  325. }
  326. }
  327. object errCheck = Value.Geterrcheck();
  328. if (errCheck != null) {
  329. res = Expression.Dynamic(
  330. ctx.CompatInvoke(new CallInfo(3)),
  331. typeof(object),
  332. Expression.Constant(errCheck),
  333. res,
  334. Expression,
  335. Expression.Call(
  336. typeof(PythonOps).GetMethod("MakeTuple"),
  337. Expression.NewArrayInit(
  338. typeof(object),
  339. ArrayUtils.ConvertAll(args, x => Utils.Convert(x.Expression, typeof(object)))
  340. )
  341. )
  342. );
  343. }
  344. return res;
  345. }
  346. private static DynamicMetaObject IncorrectArgCount(DynamicMetaObjectBinder binder, BindingRestrictions restrictions, int expected, int got) {
  347. return new DynamicMetaObject(
  348. binder.Throw(
  349. Expression.Call(
  350. typeof(PythonOps).GetMethod("TypeError"),
  351. Expression.Constant(String.Format("this function takes {0} arguments ({1} given)", expected, got)),
  352. Expression.NewArrayInit(typeof(object))
  353. ),
  354. typeof(object)
  355. ),
  356. restrictions
  357. );
  358. }
  359. private static DynamicMetaObject NoThisParam(DynamicMetaObjectBinder binder, BindingRestrictions restrictions) {
  360. return new DynamicMetaObject(
  361. binder.Throw(
  362. Expression.Call(
  363. typeof(PythonOps).GetMethod("ValueError"),
  364. Expression.Constant("native com method call without 'this' parameter"),
  365. Expression.NewArrayInit(typeof(object))
  366. ),
  367. typeof(object)
  368. ),
  369. restrictions
  370. );
  371. }
  372. /// <summary>
  373. /// we need to keep alive any methods which have arguments for the duration of the
  374. /// call. Otherwise they could be collected on the finalizer thread before we come back.
  375. /// </summary>
  376. private void AddKeepAlives(ArgumentMarshaller[] signature, List<Expression> block) {
  377. foreach (ArgumentMarshaller marshaller in signature) {
  378. Expression keepAlive = marshaller.GetKeepAlive();
  379. if (keepAlive != null) {
  380. block.Add(keepAlive);
  381. }
  382. }
  383. }
  384. private Expression MakeCall(ArgumentMarshaller[] signature, INativeType nativeRetType, bool retVoid, Expression address) {
  385. List<object> constantPool = new List<object>();
  386. MethodInfo interopInvoker = CreateInteropInvoker(
  387. GetCallingConvention(),
  388. signature,
  389. nativeRetType,
  390. retVoid,
  391. constantPool
  392. );
  393. // build the args - IntPtr, user Args, constant pool
  394. Expression[] callArgs = new Expression[signature.Length + 2];
  395. callArgs[0] = address;
  396. for (int i = 0; i < signature.Length; i++) {
  397. callArgs[i + 1] = signature[i].ArgumentExpression;
  398. }
  399. callArgs[callArgs.Length - 1] = Expression.Constant(constantPool.ToArray());
  400. return Expression.Call(interopInvoker, callArgs);
  401. }
  402. private Expression GetFunctionAddress(DynamicMetaObject[] args) {
  403. Expression address;
  404. if (Value._comInterfaceIndex != -1) {
  405. Debug.Assert(args.Length != 0); // checked earlier
  406. address = Expression.Call(
  407. typeof(ModuleOps).GetMethod("GetInterfacePointer"),
  408. Expression.Call(
  409. typeof(ModuleOps).GetMethod("GetPointer"),
  410. args[0].Expression
  411. ),
  412. Expression.Constant(Value._comInterfaceIndex)
  413. );
  414. } else {
  415. address = Expression.Property(
  416. Expression.Convert(Expression, typeof(_CFuncPtr)),
  417. "addr"
  418. );
  419. }
  420. return address;
  421. }
  422. private CallingConvention GetCallingConvention() {
  423. return Value.CallingConvention;
  424. }
  425. private INativeType GetNativeReturnType() {
  426. return Value.Getrestype() as INativeType;
  427. }
  428. private ArgumentMarshaller/*!*/[]/*!*/ GetArgumentMarshallers(DynamicMetaObject/*!*/[]/*!*/ args) {
  429. CFuncPtrType funcType = ((CFuncPtrType)Value.NativeType);
  430. ArgumentMarshaller[] res = new ArgumentMarshaller[args.Length];
  431. // first arg is taken by self if we're a com method
  432. for (int i = 0; i < args.Length; i++) {
  433. DynamicMetaObject mo = args[i];
  434. object argType = null;
  435. if (Value._comInterfaceIndex == -1 || i != 0) {
  436. int argtypeIndex = Value._comInterfaceIndex == -1 ? i : i - 1;
  437. if (Value._argtypes != null && argtypeIndex < Value._argtypes.Count) {
  438. argType = Value._argtypes[argtypeIndex];
  439. } else if (funcType._argtypes != null && argtypeIndex < funcType._argtypes.Length) {
  440. argType = funcType._argtypes[argtypeIndex];
  441. }
  442. }
  443. res[i] = GetMarshaller(mo.Expression, mo.Value, i, argType);
  444. }
  445. return res;
  446. }
  447. private ArgumentMarshaller/*!*/ GetMarshaller(Expression/*!*/ expr, object value, int index, object nativeType) {
  448. if (nativeType != null) {
  449. INativeType nt = nativeType as INativeType;
  450. if (nt != null) {
  451. return new CDataMarshaller(expr, CompilerHelpers.GetType(value), nt);
  452. }
  453. return new FromParamMarshaller(expr);
  454. }
  455. CData data = value as CData;
  456. if (data != null) {
  457. return new CDataMarshaller(expr, CompilerHelpers.GetType(value), data.NativeType);
  458. }
  459. NativeArgument arg = value as NativeArgument;
  460. if (arg != null) {
  461. return new NativeArgumentMarshaller(expr);
  462. }
  463. object val;
  464. if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out val)) {
  465. throw new NotImplementedException("_as_parameter");
  466. //return new UserDefinedMarshaller(GetMarshaller(..., value, index));
  467. }
  468. // Marshalling primitive or an object
  469. return new PrimitiveMarshaller(expr, CompilerHelpers.GetType(value));
  470. }
  471. public new _CFuncPtr/*!*/ Value {
  472. get {
  473. return (_CFuncPtr)base.Value;
  474. }
  475. }
  476. /// <summary>
  477. /// Creates a method for calling with the specified signature. The returned method has a signature
  478. /// of the form:
  479. ///
  480. /// (IntPtr funcAddress, arg0, arg1, ..., object[] constantPool)
  481. ///
  482. /// where IntPtr is the address of the function to be called. The arguments types are based upon
  483. /// the types that the ArgumentMarshaller requires.
  484. /// </summary>
  485. private static MethodInfo/*!*/ CreateInteropInvoker(CallingConvention convention, ArgumentMarshaller/*!*/[]/*!*/ sig, INativeType nativeRetType, bool retVoid, List<object> constantPool) {
  486. Type[] sigTypes = new Type[sig.Length + 2];
  487. sigTypes[0] = typeof(IntPtr);
  488. for (int i = 0; i < sig.Length; i++) {
  489. sigTypes[i + 1] = sig[i].ArgumentExpression.Type;
  490. }
  491. sigTypes[sigTypes.Length - 1] = typeof(object[]);
  492. Type retType = retVoid ? typeof(void) :
  493. nativeRetType != null ? nativeRetType.GetPythonType() : typeof(int);
  494. Type calliRetType = retVoid ? typeof(void) :
  495. nativeRetType != null ? nativeRetType.GetNativeType() : typeof(int);
  496. #if !CTYPES_USE_SNIPPETS
  497. DynamicMethod dm = new DynamicMethod("InteropInvoker", retType, sigTypes, DynamicModule);
  498. #else
  499. TypeGen tg = Snippets.Shared.DefineType("InteropInvoker", typeof(object), false, false);
  500. MethodBuilder dm = tg.TypeBuilder.DefineMethod("InteropInvoker", CompilerHelpers.PublicStatic, retType, sigTypes);
  501. #endif
  502. ILGenerator method = dm.GetILGenerator();
  503. LocalBuilder calliRetTmp = null, finalRetValue = null;
  504. if (dm.ReturnType != typeof(void)) {
  505. calliRetTmp = method.DeclareLocal(calliRetType);
  506. finalRetValue = method.DeclareLocal(dm.ReturnType);
  507. }
  508. // try {
  509. // emit all of the arguments, save their cleanups
  510. method.BeginExceptionBlock();
  511. List<MarshalCleanup> cleanups = null;
  512. for (int i = 0; i < sig.Length; i++) {
  513. #if DEBUG
  514. method.Emit(OpCodes.Ldstr, String.Format("Argument #{0}, Marshaller: {1}, Native Type: {2}", i, sig[i], sig[i].NativeType));
  515. method.Emit(OpCodes.Pop);
  516. #endif
  517. MarshalCleanup cleanup = sig[i].EmitCallStubArgument(method, i + 1, constantPool, sigTypes.Length - 1);
  518. if (cleanup != null) {
  519. if (cleanups == null) {
  520. cleanups = new List<MarshalCleanup>();
  521. }
  522. cleanups.Add(cleanup);
  523. }
  524. }
  525. // emit the target function pointer and the calli
  526. #if DEBUG
  527. method.Emit(OpCodes.Ldstr, "!!! CALLI !!!");
  528. method.Emit(OpCodes.Pop);
  529. #endif
  530. method.Emit(OpCodes.Ldarg_0);
  531. method.Emit(OpCodes.Calli, GetCalliSignature(convention, sig, calliRetType));
  532. // if we have a return value we need to store it and marshal to Python
  533. // before we run any cleanup code.
  534. if (retType != typeof(void)) {
  535. #if DEBUG
  536. method.Emit(OpCodes.Ldstr, "!!! Return !!!");
  537. method.Emit(OpCodes.Pop);
  538. #endif
  539. if (nativeRetType != null) {
  540. method.Emit(OpCodes.Stloc, calliRetTmp);
  541. nativeRetType.EmitReverseMarshalling(method, new Local(calliRetTmp), constantPool, sig.Length + 1);
  542. method.Emit(OpCodes.Stloc, finalRetValue);
  543. } else {
  544. Debug.Assert(retType == typeof(int));
  545. // no marshalling necessary
  546. method.Emit(OpCodes.Stloc, finalRetValue);
  547. }
  548. }
  549. // } finally {
  550. // emit the cleanup code
  551. method.BeginFinallyBlock();
  552. if (cleanups != null) {
  553. foreach (MarshalCleanup mc in cleanups) {
  554. mc.Cleanup(method);
  555. }
  556. }
  557. method.EndExceptionBlock();
  558. // }
  559. // load the temporary value and return it.
  560. if (retType != typeof(void)) {
  561. method.Emit(OpCodes.Ldloc, finalRetValue);
  562. }
  563. method.Emit(OpCodes.Ret);
  564. #if CTYPES_USE_SNIPPETS
  565. return tg.TypeBuilder.CreateType().GetMethod("InteropInvoker");
  566. #else
  567. return dm;
  568. #endif
  569. }
  570. private static SignatureHelper GetCalliSignature(CallingConvention convention, ArgumentMarshaller/*!*/[] sig, Type calliRetType) {
  571. SignatureHelper signature = SignatureHelper.GetMethodSigHelper(convention, calliRetType);
  572. foreach (ArgumentMarshaller argMarshaller in sig) {
  573. signature.AddArgument(argMarshaller.NativeType);
  574. }
  575. return signature;
  576. }
  577. #region Argument Marshalling
  578. /// <summary>
  579. /// Base class for marshalling arguments from the user provided value to the
  580. /// call stub. This class provides the logic for creating the call stub and
  581. /// calling it.
  582. /// </summary>
  583. abstract class ArgumentMarshaller {
  584. private readonly Expression/*!*/ _argExpr;
  585. public ArgumentMarshaller(Expression/*!*/ container) {
  586. _argExpr = container;
  587. }
  588. /// <summary>
  589. /// Emits the IL to get the argument for the call stub generated into
  590. /// a dynamic method.
  591. /// </summary>
  592. public abstract MarshalCleanup EmitCallStubArgument(ILGenerator/*!*/ generator, int argIndex, List<object>/*!*/ constantPool, int constantPoolArgument);
  593. public abstract Type/*!*/ NativeType {
  594. get;
  595. }
  596. /// <summary>
  597. /// Gets the expression used to provide the argument. This is the expression
  598. /// from an incoming DynamicMetaObject.
  599. /// </summary>
  600. public Expression/*!*/ ArgumentExpression {
  601. get {
  602. return _argExpr;
  603. }
  604. }
  605. /// <summary>
  606. /// Gets an expression which keeps alive the argument for the duration of the call.
  607. ///
  608. /// Returns null if a keep alive is not necessary.
  609. /// </summary>
  610. public virtual Expression GetKeepAlive() {
  611. return null;
  612. }
  613. public virtual BindingRestrictions GetRestrictions() {
  614. return BindingRestrictions.Empty;
  615. }
  616. }
  617. /// <summary>
  618. /// Provides marshalling of primitive values when the function type
  619. /// has no type information or when the user has provided us with
  620. /// an explicit cdata instance.
  621. /// </summary>
  622. class PrimitiveMarshaller : ArgumentMarshaller {
  623. private readonly Type/*!*/ _type;
  624. private static MethodInfo _bigIntToInt32;
  625. private static MethodInfo BigIntToInt32 {
  626. get {
  627. if (_bigIntToInt32 == null) {
  628. #if CLR2
  629. _bigIntToInt32 = typeof(BigInteger).GetMethod("ToInt32", ReflectionUtils.EmptyTypes);
  630. #else
  631. MemberInfo[] mis = typeof(BigInteger).GetMember(
  632. "op_Explicit",
  633. MemberTypes.Method,
  634. BindingFlags.Public | BindingFlags.Static
  635. );
  636. foreach (MethodInfo mi in mis) {
  637. if (mi.ReturnType == typeof(int)) {
  638. _bigIntToInt32 = mi;
  639. break;
  640. }
  641. }
  642. Debug.Assert(_bigIntToInt32 != null);
  643. #endif
  644. }
  645. return _bigIntToInt32;
  646. }
  647. }
  648. public PrimitiveMarshaller(Expression/*!*/ container, Type/*!*/ type)
  649. : base(container) {
  650. _type = type;
  651. }
  652. public override MarshalCleanup EmitCallStubArgument(ILGenerator/*!*/ generator, int argIndex, List<object>/*!*/ constantPool, int constantPoolArgument) {
  653. if (_type == typeof(DynamicNull)) {
  654. generator.Emit(OpCodes.Ldc_I4_0);
  655. generator.Emit(OpCodes.Conv_I);
  656. return null;
  657. }
  658. generator.Emit(OpCodes.Ldarg, argIndex);
  659. if (ArgumentExpression.Type != _type) {
  660. generator.Emit(OpCodes.Unbox_Any, _type);
  661. }
  662. if (_type == typeof(string)) {
  663. // pin the string and convert to a wchar*. We could let the CLR do this
  664. // but we need the string to be pinned longer than the duration of the the CLR's
  665. // p/invoke. This is because the function could return the same pointer back
  666. // to us and we need to create a new string from it.
  667. LocalBuilder lb = generator.DeclareLocal(typeof(string), true);
  668. generator.Emit(OpCodes.Stloc, lb);
  669. generator.Emit(OpCodes.Ldloc, lb);
  670. generator.Emit(OpCodes.Conv_I);
  671. generator.Emit(OpCodes.Ldc_I4, RuntimeHelpers.OffsetToStringData);
  672. generator.Emit(OpCodes.Add);
  673. } else if (_type == typeof(Bytes)) {
  674. LocalBuilder lb = generator.DeclareLocal(typeof(byte).MakeByRefType(), true);
  675. generator.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("GetBytes"));
  676. generator.Emit(OpCodes.Ldc_I4_0);
  677. generator.Emit(OpCodes.Ldelema, typeof(Byte));
  678. generator.Emit(OpCodes.Stloc, lb);
  679. generator.Emit(OpCodes.Ldloc, lb);
  680. } else if (_type == typeof(BigInteger)) {
  681. generator.Emit(OpCodes.Call, BigIntToInt32);
  682. } else if (!_type.IsValueType) {
  683. generator.Emit(OpCodes.Call, typeof(CTypes).GetMethod("PyObj_ToPtr"));
  684. }
  685. return null;
  686. }
  687. public override Type NativeType {
  688. get {
  689. if (_type == typeof(BigInteger)) {
  690. return typeof(int);
  691. } else if (!_type.IsValueType) {
  692. return typeof(IntPtr);
  693. }
  694. return _type;
  695. }
  696. }
  697. public override BindingRestrictions GetRestrictions() {
  698. if (_type == typeof(DynamicNull)) {
  699. return BindingRestrictions.GetExpressionRestriction(Expression.Equal(ArgumentExpression, Expression.Constant(null)));
  700. }
  701. return BindingRestrictions.GetTypeRestriction(ArgumentExpression, _type);
  702. }
  703. }
  704. class FromParamMarshaller : ArgumentMarshaller {
  705. public FromParamMarshaller(Expression/*!*/ container)
  706. : base(container) {
  707. }
  708. public override MarshalCleanup EmitCallStubArgument(ILGenerator generator, int argIndex, List<object> constantPool, int constantPoolArgument) {
  709. throw new NotImplementedException();
  710. }
  711. public override Type NativeType {
  712. get { throw new NotImplementedException(); }
  713. }
  714. }
  715. /// <summary>
  716. /// Provides marshalling for when the function type provide argument information.
  717. /// </summary>
  718. class CDataMarshaller : ArgumentMarshaller {
  719. private readonly Type/*!*/ _type;
  720. private readonly INativeType/*!*/ _cdataType;
  721. public CDataMarshaller(Expression/*!*/ container, Type/*!*/ type, INativeType/*!*/cdataType)
  722. : base(container) {
  723. _type = type;
  724. _cdataType = cdataType;
  725. }
  726. public override MarshalCleanup EmitCallStubArgument(ILGenerator/*!*/ generator, int argIndex, List<object>/*!*/ constantPool, int constantPoolArgument) {
  727. return _cdataType.EmitMarshalling(generator, new Arg(argIndex, ArgumentExpression.Type), constantPool, constantPoolArgument);
  728. }
  729. public override Type NativeType {
  730. get {
  731. return _cdataType.GetNativeType();
  732. }
  733. }
  734. public override Expression GetKeepAlive() {
  735. // Future possible optimization - we could just keep alive the MemoryHolder
  736. if (_type.IsValueType) {
  737. return null;
  738. }
  739. return Expression.Call(
  740. typeof(GC).GetMethod("KeepAlive"),
  741. ArgumentExpression
  742. );
  743. }
  744. public override BindingRestrictions GetRestrictions() {
  745. // we base this off of the type marshalling which can handle anything.
  746. return BindingRestrictions.Empty;
  747. }
  748. }
  749. /// <summary>
  750. /// Provides marshalling for when the user provides a native argument object
  751. /// (usually gotten by byref or pointer) and the function type has no type information.
  752. /// </summary>
  753. class NativeArgumentMarshaller : ArgumentMarshaller {
  754. public NativeArgumentMarshaller(Expression/*!*/ container)
  755. : base(container) {
  756. }
  757. public override MarshalCleanup EmitCallStubArgument(ILGenerator/*!*/ generator, int argIndex, List<object>/*!*/ constantPool, int constantPoolArgument) {
  758. // We access UnsafeAddress here but ensure the object is kept
  759. // alive via the expression returned in GetKeepAlive.
  760. generator.Emit(OpCodes.Ldarg, argIndex);
  761. generator.Emit(OpCodes.Castclass, typeof(NativeArgument));
  762. generator.Emit(OpCodes.Call, typeof(NativeArgument).GetMethod("get__obj"));
  763. generator.Emit(OpCodes.Call, typeof(CData).GetMethod("get_UnsafeAddress"));
  764. return null;
  765. }
  766. public override Type/*!*/ NativeType {
  767. get {
  768. return typeof(IntPtr);
  769. }
  770. }
  771. public override Expression GetKeepAlive() {
  772. // Future possible optimization - we could just keep alive the MemoryHolder
  773. return Expression.Call(
  774. typeof(GC).GetMethod("KeepAlive"),
  775. ArgumentExpression
  776. );
  777. }
  778. public override BindingRestrictions GetRestrictions() {
  779. return BindingRestrictions.GetTypeRestriction(ArgumentExpression, typeof(NativeArgument));
  780. }
  781. }
  782. #if FALSE // TODO: not implemented yet
  783. /// <summary>
  784. /// Provides the marshalling for a user defined object which has an _as_parameter_
  785. /// value.
  786. /// </summary>
  787. class UserDefinedMarshaller : ArgumentMarshaller {
  788. private readonly ArgumentMarshaller/*!*/ _marshaller;
  789. public UserDefinedMarshaller(Expression/*!*/ container, ArgumentMarshaller/*!*/ marshaller)
  790. : base(container) {
  791. _marshaller = marshaller;
  792. }
  793. public override Type NativeType {
  794. get { throw new NotImplementedException("user defined marshaller sig type"); }
  795. }
  796. public override MarshalCleanup EmitCallStubArgument(ILGenerator/*!*/ generator, int argIndex, List<object>/*!*/ constantPool, int constantPoolArgument) {
  797. throw new NotImplementedException("user defined marshaller");
  798. }
  799. }
  800. #endif
  801. #endregion
  802. }
  803. #endregion
  804. public string __repr__(CodeContext context) {
  805. if (_comInterfaceIndex != -1) {
  806. return string.Format("<COM method offset {0}: {1} at {2}>", _comInterfaceIndex, DynamicHelpers.GetPythonType(this).Name, _id);
  807. }
  808. return ObjectOps.__repr__(this);
  809. }
  810. }
  811. }
  812. }
  813. #endif