PageRenderTime 170ms CodeModel.GetById 25ms RepoModel.GetById 19ms app.codeStats 0ms

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

https://bitbucket.org/williamybs/uidipythontool
C# | 475 lines | 366 code | 75 blank | 34 comment | 78 complexity | d6efeb620d124a48f42db625eab9f3eb MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Reflection.Emit;
  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. using System.Text;
  27. #if CLR2
  28. using Microsoft.Scripting.Math;
  29. #else
  30. using System.Numerics;
  31. #endif
  32. #if !SILVERLIGHT
  33. namespace IronPython.Modules {
  34. /// <summary>
  35. /// Provides support for interop with native code from Python code.
  36. /// </summary>
  37. public static partial class CTypes {
  38. /// <summary>
  39. /// Meta class for structures. Validates _fields_ on creation, provides factory
  40. /// methods for creating instances from addresses and translating to parameters.
  41. /// </summary>
  42. [PythonType, PythonHidden]
  43. public class StructType : PythonType, INativeType {
  44. internal Field[] _fields;
  45. private int? _size, _alignment, _pack;
  46. private static readonly Field[] _emptyFields = new Field[0]; // fields were never initialized before a type was created
  47. public StructType(CodeContext/*!*/ context, string name, PythonTuple bases, PythonDictionary members)
  48. : base(context, name, bases, members) {
  49. foreach (PythonType pt in ResolutionOrder) {
  50. StructType st = pt as StructType;
  51. if (st != this && st != null) {
  52. st.EnsureFinal();
  53. }
  54. UnionType ut = pt as UnionType;
  55. if (ut != null) {
  56. ut.EnsureFinal();
  57. }
  58. }
  59. object pack;
  60. if (members.TryGetValue("_pack_", out pack)) {
  61. if (!(pack is int) || ((int)pack < 0)) {
  62. throw PythonOps.ValueError("pack must be a non-negative integer");
  63. }
  64. _pack = (int)pack;
  65. }
  66. object fields;
  67. if (members.TryGetValue("_fields_", out fields)) {
  68. SetFields(fields);
  69. }
  70. // TODO: _anonymous_
  71. }
  72. private StructType(Type underlyingSystemType)
  73. : base(underlyingSystemType) {
  74. }
  75. public static ArrayType/*!*/ operator *(StructType type, int count) {
  76. return MakeArrayType(type, count);
  77. }
  78. public static ArrayType/*!*/ operator *(int count, StructType type) {
  79. return MakeArrayType(type, count);
  80. }
  81. public _Structure from_address(CodeContext/*!*/ context, int address) {
  82. return from_address(context, new IntPtr(address));
  83. }
  84. public _Structure from_address(CodeContext/*!*/ context, BigInteger address) {
  85. return from_address(context, new IntPtr((long)address));
  86. }
  87. public _Structure from_address(CodeContext/*!*/ context, IntPtr ptr) {
  88. _Structure res = (_Structure)CreateInstance(context);
  89. res.SetAddress(ptr);
  90. return res;
  91. }
  92. public _Structure from_buffer(ArrayModule.array array, [DefaultParameterValue(0)]int offset) {
  93. ValidateArraySizes(array, offset, ((INativeType)this).Size);
  94. _Structure res = (_Structure)CreateInstance(Context.SharedContext);
  95. IntPtr addr = array.GetArrayAddress();
  96. res._memHolder = new MemoryHolder(addr.Add(offset), ((INativeType)this).Size);
  97. res._memHolder.AddObject("ffffffff", array);
  98. return res;
  99. }
  100. public _Structure from_buffer_copy(ArrayModule.array array, [DefaultParameterValue(0)]int offset) {
  101. ValidateArraySizes(array, offset, ((INativeType)this).Size);
  102. _Structure res = (_Structure)CreateInstance(Context.SharedContext);
  103. res._memHolder = new MemoryHolder(((INativeType)this).Size);
  104. res._memHolder.CopyFrom(array.GetArrayAddress().Add(offset), new IntPtr(((INativeType)this).Size));
  105. GC.KeepAlive(array);
  106. return res;
  107. }
  108. /// <summary>
  109. /// Converts an object into a function call parameter.
  110. ///
  111. /// Structures just return themselves.
  112. /// </summary>
  113. public object from_param(object obj) {
  114. if (!Builtin.isinstance(obj, this)) {
  115. throw PythonOps.TypeError("expected {0} instance got {1}", Name, PythonTypeOps.GetName(obj));
  116. }
  117. return obj;
  118. }
  119. public object in_dll(object library, string name) {
  120. throw new NotImplementedException("in dll");
  121. }
  122. public new void __setattr__(CodeContext/*!*/ context, string name, object value) {
  123. if (name == "_fields_") {
  124. lock (this) {
  125. if (_fields != null) {
  126. throw PythonOps.AttributeError("_fields_ is final");
  127. }
  128. SetFields(value);
  129. }
  130. }
  131. base.__setattr__(context, name, value);
  132. }
  133. #region INativeType Members
  134. int INativeType.Size {
  135. get {
  136. EnsureSizeAndAlignment();
  137. return _size.Value;
  138. }
  139. }
  140. int INativeType.Alignment {
  141. get {
  142. EnsureSizeAndAlignment();
  143. return _alignment.Value;
  144. }
  145. }
  146. object INativeType.GetValue(MemoryHolder/*!*/ owner, object readingFrom, int offset, bool raw) {
  147. _Structure res = (_Structure)CreateInstance(this.Context.SharedContext);
  148. res._memHolder = owner.GetSubBlock(offset);
  149. return res;
  150. }
  151. object INativeType.SetValue(MemoryHolder/*!*/ address, int offset, object value) {
  152. try {
  153. return SetValueInternal(address, offset, value);
  154. } catch (ArgumentTypeException e) {
  155. throw PythonOps.RuntimeError("({0}) <type 'exceptions.TypeError'>: {1}",
  156. Name,
  157. e.Message);
  158. } catch (ArgumentException e) {
  159. throw PythonOps.RuntimeError("({0}) <type 'exceptions.ValueError'>: {1}",
  160. Name,
  161. e.Message);
  162. }
  163. }
  164. internal object SetValueInternal(MemoryHolder address, int offset, object value) {
  165. IList<object> init = value as IList<object>;
  166. if (init != null) {
  167. if (init.Count > _fields.Length) {
  168. throw PythonOps.TypeError("too many initializers");
  169. }
  170. for (int i = 0; i < init.Count; i++) {
  171. _fields[i].SetValue(address, offset, init[i]);
  172. }
  173. } else {
  174. CData data = value as CData;
  175. if (data != null) {
  176. data._memHolder.CopyTo(address, offset, data.Size);
  177. return data._memHolder.EnsureObjects();
  178. } else {
  179. throw new NotImplementedException("set value");
  180. }
  181. }
  182. return null;
  183. }
  184. Type/*!*/ INativeType.GetNativeType() {
  185. EnsureFinal();
  186. return GetMarshalTypeFromSize(_size.Value);
  187. }
  188. MarshalCleanup INativeType.EmitMarshalling(ILGenerator/*!*/ method, LocalOrArg argIndex, List<object>/*!*/ constantPool, int constantPoolArgument) {
  189. Type argumentType = argIndex.Type;
  190. argIndex.Emit(method);
  191. if (argumentType.IsValueType) {
  192. method.Emit(OpCodes.Box, argumentType);
  193. }
  194. constantPool.Add(this);
  195. method.Emit(OpCodes.Ldarg, constantPoolArgument);
  196. method.Emit(OpCodes.Ldc_I4, constantPool.Count - 1);
  197. method.Emit(OpCodes.Ldelem_Ref);
  198. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("CheckCDataType"));
  199. method.Emit(OpCodes.Call, typeof(CData).GetMethod("get_UnsafeAddress"));
  200. method.Emit(OpCodes.Ldobj, ((INativeType)this).GetNativeType());
  201. return null;
  202. }
  203. Type/*!*/ INativeType.GetPythonType() {
  204. return typeof(object);
  205. }
  206. void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, List<object> constantPool, int constantPoolArgument) {
  207. value.Emit(method);
  208. EmitCDataCreation(this, method, constantPool, constantPoolArgument);
  209. }
  210. string INativeType.TypeFormat {
  211. get {
  212. if (_pack != null || _fields == _emptyFields || _fields == null) {
  213. return "B";
  214. }
  215. StringBuilder res = new StringBuilder();
  216. res.Append("T{");
  217. foreach (Field f in _fields) {
  218. res.Append(f.NativeType.TypeFormat);
  219. res.Append(':');
  220. res.Append(f.FieldName);
  221. res.Append(':');
  222. }
  223. res.Append('}');
  224. return res.ToString();
  225. }
  226. }
  227. #endregion
  228. internal static PythonType MakeSystemType(Type underlyingSystemType) {
  229. return PythonType.SetPythonType(underlyingSystemType, new StructType(underlyingSystemType));
  230. }
  231. private void SetFields(object fields) {
  232. lock (this) {
  233. IList<object> list = GetFieldsList(fields);
  234. int size;
  235. int alignment;
  236. int? bitCount = null;
  237. int? curBitCount = null;
  238. INativeType lastType = null;
  239. List<Field> allFields = GetBaseSizeAlignmentAndFields(out size, out alignment);
  240. IList<object> anonFields = GetAnonymousFields(this);
  241. for (int fieldIndex = 0; fieldIndex < list.Count; fieldIndex++) {
  242. object o = list[fieldIndex];
  243. string fieldName;
  244. INativeType cdata;
  245. GetFieldInfo(this, o, out fieldName, out cdata, out bitCount);
  246. int prevSize = UpdateSizeAndAlignment(cdata, bitCount, lastType, ref size, ref alignment, ref curBitCount);
  247. Field newField = new Field(fieldName, cdata, prevSize, allFields.Count, bitCount, curBitCount - bitCount);
  248. allFields.Add(newField);
  249. AddSlot(fieldName, newField);
  250. if (anonFields != null && anonFields.Contains(fieldName)) {
  251. AddAnonymousFields(this, allFields, cdata, newField);
  252. }
  253. lastType = cdata;
  254. }
  255. CheckAnonymousFields(allFields, anonFields);
  256. if (bitCount != null) {
  257. size += lastType.Size;
  258. }
  259. _fields = allFields.ToArray();
  260. _size = PythonStruct.Align(size, alignment);
  261. _alignment = alignment;
  262. }
  263. }
  264. internal static void CheckAnonymousFields(List<Field> allFields, IList<object> anonFields) {
  265. if (anonFields != null) {
  266. foreach (string s in anonFields) {
  267. bool found = false;
  268. foreach (Field f in allFields) {
  269. if (f.FieldName == s) {
  270. found = true;
  271. break;
  272. }
  273. }
  274. if (!found) {
  275. throw PythonOps.AttributeError("anonymous field {0} is not defined in this structure", s);
  276. }
  277. }
  278. }
  279. }
  280. internal static IList<object> GetAnonymousFields(PythonType type) {
  281. object anonymous;
  282. IList<object> anonFields = null;
  283. if (type.TryGetBoundAttr(type.Context.SharedContext, type, "_anonymous_", out anonymous)) {
  284. anonFields = anonymous as IList<object>;
  285. if (anonFields == null) {
  286. throw PythonOps.TypeError("_anonymous_ must be a sequence");
  287. }
  288. }
  289. return anonFields;
  290. }
  291. internal static void AddAnonymousFields(PythonType type, List<Field> allFields, INativeType cdata, Field newField) {
  292. Field[] childFields;
  293. if (cdata is StructType) {
  294. childFields = ((StructType)cdata)._fields;
  295. } else if (cdata is UnionType) {
  296. childFields = ((UnionType)cdata)._fields;
  297. } else {
  298. throw PythonOps.TypeError("anonymous field must be struct or union");
  299. }
  300. foreach (Field existingField in childFields) {
  301. Field anonField = new Field(
  302. existingField.FieldName,
  303. existingField.NativeType,
  304. checked(existingField.offset + newField.offset),
  305. allFields.Count
  306. );
  307. type.AddSlot(existingField.FieldName, anonField);
  308. allFields.Add(anonField);
  309. }
  310. }
  311. private List<Field> GetBaseSizeAlignmentAndFields(out int size, out int alignment) {
  312. size = 0;
  313. alignment = 1;
  314. List<Field> allFields = new List<Field>();
  315. INativeType lastType = null;
  316. int? totalBitCount = null;
  317. foreach (PythonType pt in BaseTypes) {
  318. StructType st = pt as StructType;
  319. if (st != null) {
  320. foreach (Field f in st._fields) {
  321. allFields.Add(f);
  322. UpdateSizeAndAlignment(f.NativeType, f.BitCount, lastType, ref size, ref alignment, ref totalBitCount);
  323. if (f.NativeType == this) {
  324. throw StructureCannotContainSelf();
  325. }
  326. lastType = f.NativeType;
  327. }
  328. }
  329. }
  330. return allFields;
  331. }
  332. private int UpdateSizeAndAlignment(INativeType cdata, int? bitCount, INativeType lastType, ref int size, ref int alignment, ref int? totalBitCount) {
  333. int prevSize = size;
  334. if (bitCount != null) {
  335. if (lastType != null && lastType.Size != cdata.Size) {
  336. totalBitCount = null;
  337. prevSize = size += lastType.Size;
  338. }
  339. size = PythonStruct.Align(size, cdata.Alignment);
  340. if (totalBitCount != null) {
  341. if ((bitCount + totalBitCount + 7) / 8 <= cdata.Size) {
  342. totalBitCount = bitCount + totalBitCount;
  343. } else {
  344. size += lastType.Size;
  345. prevSize = size;
  346. totalBitCount = bitCount;
  347. }
  348. } else {
  349. totalBitCount = bitCount;
  350. }
  351. } else {
  352. if (totalBitCount != null) {
  353. size += lastType.Size;
  354. prevSize = size;
  355. totalBitCount = null;
  356. }
  357. if (_pack != null) {
  358. alignment = _pack.Value;
  359. prevSize = size = PythonStruct.Align(size, _pack.Value);
  360. size += cdata.Size;
  361. } else {
  362. alignment = Math.Max(alignment, cdata.Alignment);
  363. prevSize = size = PythonStruct.Align(size, cdata.Alignment);
  364. size += cdata.Size;
  365. }
  366. }
  367. return prevSize;
  368. }
  369. internal void EnsureFinal() {
  370. if (_fields == null) {
  371. SetFields(PythonTuple.EMPTY);
  372. if (_fields.Length == 0) {
  373. // track that we were initialized w/o fields.
  374. _fields = _emptyFields;
  375. }
  376. }
  377. }
  378. /// <summary>
  379. /// If our size/alignment hasn't been initialized then grabs the size/alignment
  380. /// from all of our base classes. If later new _fields_ are added we'll be
  381. /// initialized and these values will be replaced.
  382. /// </summary>
  383. private void EnsureSizeAndAlignment() {
  384. Debug.Assert(_size.HasValue == _alignment.HasValue);
  385. // these are always iniitalized together
  386. if (_size == null) {
  387. lock (this) {
  388. if (_size == null) {
  389. int size, alignment;
  390. GetBaseSizeAlignmentAndFields(out size, out alignment);
  391. _size = size;
  392. _alignment = alignment;
  393. }
  394. }
  395. }
  396. }
  397. }
  398. }
  399. }
  400. #endif