PageRenderTime 63ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

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

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