PageRenderTime 71ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/Languages/IronPython/IronPython/Runtime/Types/PythonType.cs

http://github.com/IronLanguages/main
C# | 3624 lines | 2649 code | 622 blank | 353 comment | 753 complexity | 2cef20ee4eb7d89ae2890c8135461ba3 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_CORE_DLR
  16. using System.Linq.Expressions;
  17. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. using System;
  21. using System.Collections;
  22. using System.Collections.Generic;
  23. using System.Diagnostics;
  24. using System.Globalization;
  25. using System.Linq;
  26. using System.Reflection;
  27. using System.Runtime.CompilerServices;
  28. using System.Dynamic;
  29. using System.Text;
  30. using System.Threading;
  31. using Microsoft.Scripting;
  32. using Microsoft.Scripting.Actions;
  33. using Microsoft.Scripting.Runtime;
  34. using Microsoft.Scripting.Utils;
  35. using IronPython.Runtime.Binding;
  36. using IronPython.Runtime.Operations;
  37. #if FEATURE_NUMERICS
  38. using System.Numerics;
  39. #else
  40. using Microsoft.Scripting.Math;
  41. using Complex = Microsoft.Scripting.Math.Complex64;
  42. #endif
  43. namespace IronPython.Runtime.Types {
  44. /// <summary>
  45. /// Represents a PythonType. Instances of PythonType are created via PythonTypeBuilder.
  46. /// </summary>
  47. [DebuggerDisplay("PythonType: {Name}"), DebuggerTypeProxy(typeof(PythonType.DebugProxy))]
  48. [PythonType("type")]
  49. [Documentation(@"type(object) -> gets the type of the object
  50. type(name, bases, dict) -> creates a new type instance with the given name, base classes, and members from the dictionary")]
  51. public partial class PythonType : IPythonMembersList, IDynamicMetaObjectProvider, IWeakReferenceable, IWeakReferenceableByProxy, ICodeFormattable, IFastGettable, IFastSettable, IFastInvokable {
  52. private Type/*!*/ _underlyingSystemType; // the underlying CLI system type for this type
  53. private string _name; // the name of the type
  54. private Dictionary<string, PythonTypeSlot> _dict; // type-level slots & attributes
  55. private PythonTypeAttributes _attrs; // attributes of the type
  56. private int _flags; // CPython-like flags on the type
  57. private int _version = GetNextVersion(); // version of the type
  58. private List<WeakReference> _subtypes; // all of the subtypes of the PythonType
  59. private PythonContext _pythonContext; // the context the type was created from, or null for system types.
  60. private bool? _objectNew, _objectInit; // true if the type doesn't override __new__ / __init__ from object.
  61. internal Dictionary<CachedGetKey, FastGetBase> _cachedGets; // cached gets on user defined type instances
  62. internal Dictionary<CachedGetKey, FastGetBase> _cachedTryGets; // cached try gets on used defined type instances
  63. internal Dictionary<SetMemberKey, FastSetBase> _cachedSets; // cached sets on user defined instances
  64. internal Dictionary<string, TypeGetBase> _cachedTypeGets; // cached gets on types (system and user types)
  65. internal Dictionary<string, TypeGetBase> _cachedTypeTryGets; // cached gets on types (system and user types)
  66. // commonly calculatable
  67. private List<PythonType> _resolutionOrder; // the search order for methods in the type
  68. private PythonType/*!*/[]/*!*/ _bases; // the base classes of the type
  69. private BuiltinFunction _ctor; // the built-in function which allocates an instance - a .NET ctor
  70. private Type _finalSystemType; // base .NET type if we're inherited from another Python-like type.
  71. // fields that frequently remain null
  72. private WeakRefTracker _weakrefTracker; // storage for Python style weak references
  73. private WeakReference _weakRef; // single weak ref instance used for all user PythonTypes.
  74. private string[] _slots; // the slots when the class was created
  75. private OldClass _oldClass; // the associated OldClass or null for new-style types
  76. private int _originalSlotCount; // the number of slots when the type was created
  77. private InstanceCreator _instanceCtor; // creates instances
  78. private CallSite<Func<CallSite, object, int>> _hashSite;
  79. private CallSite<Func<CallSite, object, object, bool>> _eqSite;
  80. private CallSite<Func<CallSite, object, object, int>> _compareSite;
  81. private Dictionary<CallSignature, LateBoundInitBinder> _lateBoundInitBinders;
  82. private string[] _optimizedInstanceNames; // optimized names stored in a custom dictionary
  83. private int _optimizedInstanceVersion;
  84. private Dictionary<string, List<MethodInfo>> _extensionMethods; // extension methods defined on the type
  85. private PythonSiteCache _siteCache = new PythonSiteCache();
  86. private PythonTypeSlot _lenSlot; // cached length slot, cleared when the type is mutated
  87. internal Func<string, Exception> _makeException = DefaultMakeException;
  88. [MultiRuntimeAware]
  89. private static int MasterVersion = 1;
  90. private static readonly CommonDictionaryStorage _pythonTypes = new CommonDictionaryStorage();
  91. internal static readonly PythonType _pythonTypeType = DynamicHelpers.GetPythonTypeFromType(typeof(PythonType));
  92. private static readonly WeakReference[] _emptyWeakRef = new WeakReference[0];
  93. private static object _subtypesLock = new object();
  94. internal static readonly Func<string, Exception> DefaultMakeException = (message) => new Exception(message);
  95. /// <summary>
  96. /// Provides delegates that will invoke a parameterless type ctor. The first key provides
  97. /// the dictionary for a specific type, the 2nd key provides the delegate for a specific
  98. /// call site type used in conjunction w/ our IFastInvokable implementation.
  99. /// </summary>
  100. private static Dictionary<Type, Dictionary<Type, Delegate>> _fastBindCtors = new Dictionary<Type, Dictionary<Type, Delegate>>();
  101. /// <summary>
  102. /// Shared built-in functions for creating instances of user defined types. Because all
  103. /// types w/ the same UnderlyingSystemType share the same constructors these can be
  104. /// shared across multiple types.
  105. /// </summary>
  106. private static Dictionary<Type, BuiltinFunction> _userTypeCtors = new Dictionary<Type, BuiltinFunction>();
  107. /// <summary>
  108. /// Creates a new type for a user defined type. The name, base classes (a tuple of type
  109. /// objects), and a dictionary of members is provided.
  110. /// </summary>
  111. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
  112. public PythonType(CodeContext/*!*/ context, string name, PythonTuple bases, PythonDictionary dict)
  113. : this(context, name, bases, dict, String.Empty) {
  114. }
  115. /// <summary>
  116. /// Creates a new type for a user defined type. The name, base classes (a tuple of type
  117. /// objects), and a dictionary of members is provided.
  118. /// </summary>
  119. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
  120. internal PythonType(CodeContext/*!*/ context, string name, PythonTuple bases, PythonDictionary dict, string selfNames) {
  121. InitializeUserType(context, name, bases, dict, selfNames);
  122. }
  123. internal PythonType() {
  124. }
  125. /// <summary>
  126. /// Creates a new PythonType object which is backed by the specified .NET type for
  127. /// storage. The type is considered a system type which can not be modified
  128. /// by the user.
  129. /// </summary>
  130. /// <param name="underlyingSystemType"></param>
  131. internal PythonType(Type underlyingSystemType) {
  132. _underlyingSystemType = underlyingSystemType;
  133. InitializeSystemType();
  134. }
  135. /// <summary>
  136. /// Creates a new PythonType which is a subclass of the specified PythonType.
  137. ///
  138. /// Used for runtime defined new-style classes which require multiple inheritance. The
  139. /// primary example of this is the exception system.
  140. /// </summary>
  141. internal PythonType(PythonType baseType, string name, Func<string, Exception> exceptionMaker) {
  142. _underlyingSystemType = baseType.UnderlyingSystemType;
  143. IsSystemType = baseType.IsSystemType;
  144. IsPythonType = baseType.IsPythonType;
  145. Name = name;
  146. _bases = new PythonType[] { baseType };
  147. ResolutionOrder = Mro.Calculate(this, _bases);
  148. _attrs |= PythonTypeAttributes.HasDictionary;
  149. _makeException = exceptionMaker;
  150. }
  151. /// <summary>
  152. /// Creates a new PythonType which is a subclass of the specified PythonTypes.
  153. ///
  154. /// Used for runtime defined new-style classes which require multiple inheritance. The
  155. /// primary example of this is the exception system.
  156. /// </summary>
  157. internal PythonType(PythonType[] baseTypes, string name) {
  158. bool isSystemType = false;
  159. bool isPythonType = false;
  160. foreach (PythonType baseType in baseTypes) {
  161. isSystemType |= baseType.IsSystemType;
  162. isPythonType |= baseType.IsPythonType;
  163. }
  164. IsSystemType = isSystemType;
  165. IsPythonType = isPythonType;
  166. Name = name;
  167. _bases = baseTypes;
  168. ResolutionOrder = Mro.Calculate(this, _bases);
  169. _attrs |= PythonTypeAttributes.HasDictionary;
  170. }
  171. /// <summary>
  172. /// Creates a new PythonType which is a subclass of the specified PythonTypes.
  173. ///
  174. /// Used for runtime defined new-style classes which require multiple inheritance. The
  175. /// primary example of this is the exception system.
  176. /// </summary>
  177. internal PythonType(PythonType[] baseTypes, Type underlyingType, string name, Func<string, Exception> exceptionMaker)
  178. : this(baseTypes, name) {
  179. _underlyingSystemType = underlyingType;
  180. _makeException = exceptionMaker;
  181. }
  182. /// <summary>
  183. /// Creates a new PythonType which is a subclass of the specified PythonType.
  184. ///
  185. /// Used for runtime defined new-style classes which require multiple inheritance. The
  186. /// primary example of this is the exception system.
  187. /// </summary>
  188. internal PythonType(PythonContext context, PythonType baseType, string name, string module, string doc, Func<string, Exception> exceptionMaker)
  189. : this(baseType, name, exceptionMaker) {
  190. EnsureDict();
  191. _dict["__doc__"] = new PythonTypeUserDescriptorSlot(doc, true);
  192. _dict["__module__"] = new PythonTypeUserDescriptorSlot(module, true);
  193. IsSystemType = false;
  194. IsPythonType = false;
  195. _pythonContext = context;
  196. _attrs |= PythonTypeAttributes.HasDictionary;
  197. }
  198. /// <summary>
  199. /// Creates a new PythonType which is a subclass of the specified PythonTypes.
  200. ///
  201. /// Used for runtime defined new-style classes which require multiple inheritance. The
  202. /// primary example of this is the exception system.
  203. /// </summary>
  204. internal PythonType(PythonContext context, PythonType[] baseTypes, string name, string module, string doc)
  205. : this(baseTypes, name) {
  206. EnsureDict();
  207. _dict["__doc__"] = new PythonTypeUserDescriptorSlot(doc, true);
  208. _dict["__module__"] = new PythonTypeUserDescriptorSlot(module, true);
  209. _pythonContext = context;
  210. _attrs |= PythonTypeAttributes.HasDictionary;
  211. }
  212. /// <summary>
  213. /// Creates a new PythonType which is a subclass of the specified PythonTypes.
  214. ///
  215. /// Used for runtime defined new-style classes which require multiple inheritance. The
  216. /// primary example of this is the exception system.
  217. /// </summary>
  218. internal PythonType(PythonContext context, PythonType[] baseTypes, Type underlyingType, string name, string module, string doc, Func<string, Exception> exceptionMaker)
  219. : this(baseTypes, underlyingType, name, exceptionMaker) {
  220. EnsureDict();
  221. _dict["__doc__"] = new PythonTypeUserDescriptorSlot(doc, true);
  222. _dict["__module__"] = new PythonTypeUserDescriptorSlot(module, true);
  223. IsSystemType = false;
  224. IsPythonType = false;
  225. _pythonContext = context;
  226. _attrs |= PythonTypeAttributes.HasDictionary;
  227. }
  228. /// <summary>
  229. /// Creates a new PythonType object which represents an Old-style class.
  230. /// </summary>
  231. internal PythonType(OldClass oc) {
  232. EnsureDict();
  233. _underlyingSystemType = typeof(OldInstance);
  234. Name = oc.Name;
  235. OldClass = oc;
  236. List<PythonType> ocs = new List<PythonType>(oc.BaseClasses.Count);
  237. foreach (OldClass klass in oc.BaseClasses) {
  238. ocs.Add(klass.TypeObject);
  239. }
  240. List<PythonType> mro = new List<PythonType>();
  241. mro.Add(this);
  242. _bases = ocs.ToArray();
  243. _resolutionOrder = mro;
  244. AddSlot("__class__", new PythonTypeUserDescriptorSlot(this, true));
  245. }
  246. internal BuiltinFunction Ctor {
  247. get {
  248. EnsureConstructor();
  249. return _ctor;
  250. }
  251. }
  252. #region Public API
  253. public static object __new__(CodeContext/*!*/ context, PythonType cls, string name, PythonTuple bases, PythonDictionary dict) {
  254. return __new__(context, cls, name, bases, dict, String.Empty);
  255. }
  256. internal static object __new__(CodeContext/*!*/ context, PythonType cls, string name, PythonTuple bases, PythonDictionary dict, string selfNames) {
  257. if (name == null) {
  258. throw PythonOps.TypeError("type() argument 1 must be string, not None");
  259. }
  260. if (bases == null) {
  261. throw PythonOps.TypeError("type() argument 2 must be tuple, not None");
  262. }
  263. if (dict == null) {
  264. throw PythonOps.TypeError("TypeError: type() argument 3 must be dict, not None");
  265. }
  266. EnsureModule(context, dict);
  267. PythonType meta = FindMetaClass(cls, bases);
  268. if (meta != TypeCache.OldInstance && meta != TypeCache.PythonType) {
  269. if (meta != cls) {
  270. // the user has a custom __new__ which picked the wrong meta class, call the correct metaclass
  271. return PythonCalls.Call(context, meta, name, bases, dict);
  272. }
  273. // we have the right user __new__, call our ctor method which will do the actual
  274. // creation.
  275. return meta.CreateInstance(context, name, bases, dict);
  276. }
  277. // no custom user type for __new__
  278. return new PythonType(context, name, bases, dict, selfNames);
  279. }
  280. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  281. public void __init__(string name, PythonTuple bases, PythonDictionary dict) {
  282. }
  283. internal static PythonType FindMetaClass(PythonType cls, PythonTuple bases) {
  284. PythonType meta = cls;
  285. foreach (object dt in bases) {
  286. PythonType metaCls = DynamicHelpers.GetPythonType(dt);
  287. if (metaCls == TypeCache.OldClass) continue;
  288. if (meta.IsSubclassOf(metaCls)) continue;
  289. if (metaCls.IsSubclassOf(meta)) {
  290. meta = metaCls;
  291. continue;
  292. }
  293. throw PythonOps.TypeError("Error when calling the metaclass bases\n metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases");
  294. }
  295. return meta;
  296. }
  297. public static object __new__(CodeContext/*!*/ context, object cls, object o) {
  298. return DynamicHelpers.GetPythonType(o);
  299. }
  300. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  301. public void __init__(object o) {
  302. }
  303. [SpecialName, PropertyMethod, WrapperDescriptor]
  304. public static PythonTuple Get__bases__(CodeContext/*!*/ context, PythonType/*!*/ type) {
  305. return type.GetBasesTuple();
  306. }
  307. private PythonTuple GetBasesTuple() {
  308. object[] res = new object[BaseTypes.Count];
  309. IList<PythonType> bases = BaseTypes;
  310. for (int i = 0; i < bases.Count; i++) {
  311. PythonType baseType = bases[i];
  312. if (baseType.IsOldClass) {
  313. res[i] = baseType.OldClass;
  314. } else {
  315. res[i] = baseType;
  316. }
  317. }
  318. return PythonTuple.MakeTuple(res);
  319. }
  320. [SpecialName, PropertyMethod, WrapperDescriptor]
  321. public static PythonType Get__base__(CodeContext/*!*/ context, PythonType/*!*/ type) {
  322. foreach (object typeObj in Get__bases__(context, type)) {
  323. PythonType pt = typeObj as PythonType;
  324. if (pt != null) {
  325. return pt;
  326. }
  327. }
  328. return null;
  329. }
  330. /// <summary>
  331. /// Used in copy_reg which is the only consumer of __flags__ in the standard library.
  332. ///
  333. /// Set if the type is user defined
  334. /// </summary>
  335. private const int TypeFlagHeapType = 0x00000200;
  336. /// <summary>
  337. /// Set if the type has __abstractmethods__ defined
  338. /// </summary>
  339. private const int TypeFlagAbstractMethodsDefined = 0x00080000;
  340. private const int TypeFlagAbstractMethodsNonEmpty = 0x00100000;
  341. private bool SetAbstractMethodFlags(string name, object value) {
  342. if (name != "__abstractmethods__") {
  343. return false;
  344. }
  345. int res = _flags | TypeFlagAbstractMethodsDefined;
  346. IEnumerator enumerator;
  347. if (value == null ||
  348. !PythonOps.TryGetEnumerator(DefaultContext.Default, value, out enumerator) ||
  349. !enumerator.MoveNext()) {
  350. // CPython treats None, non-iterables, and empty iterables as empty sets
  351. // of abstract methods, and sets this flag accordingly
  352. res &= ~(TypeFlagAbstractMethodsNonEmpty);
  353. } else {
  354. res |= TypeFlagAbstractMethodsNonEmpty;
  355. }
  356. _flags = res;
  357. return true;
  358. }
  359. /// <summary>
  360. /// Check whether the current type is iterabel
  361. /// </summary>
  362. /// <param name="context"></param>
  363. /// <returns>True if it is iterable</returns>
  364. internal bool IsIterable(CodeContext context)
  365. {
  366. object _dummy = null;
  367. if (PythonOps.TryGetBoundAttr(context, this, "__iter__", out _dummy) &&
  368. !Object.ReferenceEquals(_dummy, NotImplementedType.Value)
  369. && PythonOps.TryGetBoundAttr(context, this, "next", out _dummy) &&
  370. !Object.ReferenceEquals(_dummy, NotImplementedType.Value))
  371. {
  372. return true;
  373. }
  374. return false;
  375. }
  376. private void ClearAbstractMethodFlags(string name) {
  377. if (name == "__abstractmethods__") {
  378. _flags &= ~(TypeFlagAbstractMethodsDefined | TypeFlagAbstractMethodsNonEmpty);
  379. }
  380. }
  381. internal bool HasAbstractMethods(CodeContext/*!*/ context) {
  382. object abstractMethods;
  383. IEnumerator en;
  384. return (_flags & TypeFlagAbstractMethodsNonEmpty) != 0 &&
  385. TryGetBoundCustomMember(context, "__abstractmethods__", out abstractMethods) &&
  386. PythonOps.TryGetEnumerator(context, abstractMethods, out en) &&
  387. en.MoveNext();
  388. }
  389. internal string GetAbstractErrorMessage(CodeContext/*!*/ context) {
  390. if ((_flags & TypeFlagAbstractMethodsNonEmpty) == 0) {
  391. return null;
  392. }
  393. object abstractMethods;
  394. IEnumerator en;
  395. if (!TryGetBoundCustomMember(context, "__abstractmethods__", out abstractMethods) ||
  396. !PythonOps.TryGetEnumerator(context, abstractMethods, out en) ||
  397. !en.MoveNext()) {
  398. return null;
  399. }
  400. string comma = "";
  401. StringBuilder error = new StringBuilder("Can't instantiate abstract class ");
  402. error.Append(Name);
  403. error.Append(" with abstract methods ");
  404. int i = 0;
  405. do {
  406. string s = en.Current as string;
  407. if (s == null) {
  408. Extensible<string> es = en.Current as Extensible<string>;
  409. if (es != null) {
  410. s = es.Value;
  411. }
  412. }
  413. if (s == null) {
  414. return string.Format(
  415. "sequence item {0}: expected string, {1} found",
  416. i, PythonTypeOps.GetName(en.Current)
  417. );
  418. }
  419. error.Append(comma);
  420. error.Append(en.Current);
  421. comma = ", ";
  422. i++;
  423. } while (en.MoveNext());
  424. return error.ToString();
  425. }
  426. [SpecialName, PropertyMethod, WrapperDescriptor]
  427. public static int Get__flags__(CodeContext/*!*/ context, PythonType/*!*/ type) {
  428. int res = type._flags;
  429. if (type.IsSystemType) {
  430. res |= TypeFlagHeapType;
  431. }
  432. return res;
  433. }
  434. [SpecialName, PropertyMethod, WrapperDescriptor]
  435. public static void Set__bases__(CodeContext/*!*/ context, PythonType/*!*/ type, object value) {
  436. // validate we got a tuple...
  437. PythonTuple t = value as PythonTuple;
  438. if (t == null) throw PythonOps.TypeError("expected tuple of types or old-classes, got '{0}'", PythonTypeOps.GetName(value));
  439. List<PythonType> ldt = new List<PythonType>();
  440. foreach (object o in t) {
  441. // gather all the type objects...
  442. PythonType adt = o as PythonType;
  443. if (adt == null) {
  444. OldClass oc = o as OldClass;
  445. if (oc == null) {
  446. throw PythonOps.TypeError("expected tuple of types, got '{0}'", PythonTypeOps.GetName(o));
  447. }
  448. adt = oc.TypeObject;
  449. }
  450. ldt.Add(adt);
  451. }
  452. #if FEATURE_REFEMIT
  453. // Ensure that we are not switching the CLI type
  454. Type newType = NewTypeMaker.GetNewType(type.Name, t);
  455. if (type.UnderlyingSystemType != newType)
  456. throw PythonOps.TypeErrorForIncompatibleObjectLayout("__bases__ assignment", type, newType);
  457. #endif
  458. // set bases & the new resolution order
  459. List<PythonType> mro = CalculateMro(type, ldt);
  460. type.BaseTypes = ldt;
  461. type._resolutionOrder = mro;
  462. }
  463. private static List<PythonType> CalculateMro(PythonType type, IList<PythonType> ldt) {
  464. return Mro.Calculate(type, ldt);
  465. }
  466. private static bool TryReplaceExtensibleWithBase(Type curType, out Type newType) {
  467. if (curType.GetTypeInfo().IsGenericType &&
  468. curType.GetGenericTypeDefinition() == typeof(Extensible<>)) {
  469. newType = curType.GetGenericArguments()[0];
  470. return true;
  471. }
  472. newType = null;
  473. return false;
  474. }
  475. public object __call__(CodeContext context, params object[] args) {
  476. return PythonTypeOps.CallParams(context, this, args);
  477. }
  478. public object __call__(CodeContext context, [ParamDictionary]IDictionary<string, object> kwArgs, params object[] args) {
  479. return PythonTypeOps.CallWorker(context, this, kwArgs, args);
  480. }
  481. public int __cmp__([NotNull]PythonType other) {
  482. if (other != this) {
  483. int res = Name.CompareTo(other.Name);
  484. if (res == 0) {
  485. long thisId = IdDispenser.GetId(this);
  486. long otherId = IdDispenser.GetId(other);
  487. if (thisId > otherId) {
  488. return 1;
  489. } else {
  490. return -1;
  491. }
  492. }
  493. return res;
  494. }
  495. return 0;
  496. }
  497. // Do not override == and != because it causes lots of spurious warnings
  498. // TODO Replace those warnings with .ReferenceEquals calls & overload ==/!=
  499. public bool __eq__([NotNull]PythonType other) {
  500. return this.__cmp__(other) == 0;
  501. }
  502. public bool __ne__([NotNull]PythonType other) {
  503. return this.__cmp__(other) != 0;
  504. }
  505. [Python3Warning("type inequality comparisons not supported in 3.x")]
  506. public static bool operator >(PythonType self, PythonType other) {
  507. return self.__cmp__(other) > 0;
  508. }
  509. [Python3Warning("type inequality comparisons not supported in 3.x")]
  510. public static bool operator <(PythonType self, PythonType other) {
  511. return self.__cmp__(other) < 0;
  512. }
  513. [Python3Warning("type inequality comparisons not supported in 3.x")]
  514. public static bool operator >=(PythonType self, PythonType other) {
  515. return self.__cmp__(other) >= 0;
  516. }
  517. [Python3Warning("type inequality comparisons not supported in 3.x")]
  518. public static bool operator <=(PythonType self, PythonType other) {
  519. return self.__cmp__(other) <= 0;
  520. }
  521. public void __delattr__(CodeContext/*!*/ context, string name) {
  522. DeleteCustomMember(context, name);
  523. }
  524. [SlotField]
  525. public static PythonTypeSlot __dict__ = new PythonTypeDictSlot(_pythonTypeType);
  526. [SpecialName, PropertyMethod, WrapperDescriptor]
  527. public static object Get__doc__(CodeContext/*!*/ context, PythonType self) {
  528. PythonTypeSlot pts;
  529. object res;
  530. if (self.TryLookupSlot(context, "__doc__", out pts) &&
  531. pts.TryGetValue(context, null, self, out res)) {
  532. return res;
  533. } else if (self.IsSystemType) {
  534. return PythonTypeOps.GetDocumentation(self.UnderlyingSystemType);
  535. }
  536. return null;
  537. }
  538. public object __getattribute__(CodeContext/*!*/ context, string name) {
  539. object value;
  540. if (TryGetBoundCustomMember(context, name, out value)) {
  541. return value;
  542. }
  543. throw PythonOps.AttributeError("type object '{0}' has no attribute '{1}'", Name, name);
  544. }
  545. public PythonType this[params Type[] args] {
  546. get {
  547. if (UnderlyingSystemType == typeof(Array)) {
  548. if (args.Length == 1) {
  549. return DynamicHelpers.GetPythonTypeFromType(args[0].MakeArrayType());
  550. }
  551. throw PythonOps.TypeError("expected one argument to make array type, got {0}", args.Length);
  552. }
  553. if (!UnderlyingSystemType.IsGenericTypeDefinition()) {
  554. throw new InvalidOperationException("MakeGenericType on non-generic type");
  555. }
  556. return DynamicHelpers.GetPythonTypeFromType(UnderlyingSystemType.MakeGenericType(args));
  557. }
  558. }
  559. [SpecialName, PropertyMethod, WrapperDescriptor]
  560. public static object Get__module__(CodeContext/*!*/ context, PythonType self) {
  561. PythonTypeSlot pts;
  562. object res;
  563. if (self._dict != null &&
  564. self._dict.TryGetValue("__module__", out pts) &&
  565. pts.TryGetValue(context, self, DynamicHelpers.GetPythonType(self), out res)) {
  566. return res;
  567. }
  568. return PythonTypeOps.GetModuleName(context, self.UnderlyingSystemType);
  569. }
  570. [SpecialName, PropertyMethod, WrapperDescriptor, PythonHidden]
  571. public static string Get__clr_assembly__(PythonType self) {
  572. return self.UnderlyingSystemType.Namespace + " in " + self.UnderlyingSystemType.GetTypeInfo().Assembly.FullName;
  573. }
  574. [SpecialName, PropertyMethod, WrapperDescriptor]
  575. public static void Set__module__(CodeContext/*!*/ context, PythonType self, object value) {
  576. if (self.IsSystemType) {
  577. throw PythonOps.TypeError("can't set {0}.__module__", self.Name);
  578. }
  579. Debug.Assert(self._dict != null);
  580. self._dict["__module__"] = new PythonTypeUserDescriptorSlot(value);
  581. self.UpdateVersion();
  582. }
  583. [SpecialName, PropertyMethod, WrapperDescriptor]
  584. public static void Delete__module__(CodeContext/*!*/ context, PythonType self) {
  585. throw PythonOps.TypeError("can't delete {0}.__module__", self.Name);
  586. }
  587. [SpecialName, PropertyMethod, WrapperDescriptor]
  588. public static PythonTuple Get__mro__(PythonType type) {
  589. return PythonTypeOps.MroToPython(type.ResolutionOrder);
  590. }
  591. [SpecialName, PropertyMethod, WrapperDescriptor]
  592. public static string Get__name__(PythonType type) {
  593. return type.Name;
  594. }
  595. [SpecialName, PropertyMethod, WrapperDescriptor]
  596. public static void Set__name__(PythonType type, string name) {
  597. if (type.IsSystemType) {
  598. throw PythonOps.TypeError("can't set attributes of built-in/extension type '{0}'", type.Name);
  599. }
  600. type.Name = name;
  601. }
  602. public string/*!*/ __repr__(CodeContext/*!*/ context) {
  603. string name = Name;
  604. if (IsSystemType) {
  605. if (PythonTypeOps.IsRuntimeAssembly(UnderlyingSystemType.GetTypeInfo().Assembly) || IsPythonType) {
  606. object module = Get__module__(context, this);
  607. if (!module.Equals("__builtin__")) {
  608. return string.Format("<type '{0}.{1}'>", module, Name);
  609. }
  610. }
  611. return string.Format("<type '{0}'>", Name);
  612. } else {
  613. PythonTypeSlot dts;
  614. string module = "unknown";
  615. object modObj;
  616. if (TryLookupSlot(context, "__module__", out dts) &&
  617. dts.TryGetValue(context, this, this, out modObj)) {
  618. module = modObj as string;
  619. }
  620. return string.Format("<class '{0}.{1}'>", module, name);
  621. }
  622. }
  623. internal string/*!*/ GetTypeDebuggerDisplay() {
  624. PythonTypeSlot dts;
  625. string module = "unknown";
  626. object modObj;
  627. if (TryLookupSlot(Context.SharedContext, "__module__", out dts) &&
  628. dts.TryGetValue(Context.SharedContext, this, this, out modObj)) {
  629. module = modObj as string;
  630. }
  631. return string.Format("{0}.{1} instance", module, Name);
  632. }
  633. public void __setattr__(CodeContext/*!*/ context, string name, object value) {
  634. SetCustomMember(context, name, value);
  635. }
  636. public List __subclasses__(CodeContext/*!*/ context) {
  637. List ret = new List();
  638. IList<WeakReference> subtypes = SubTypes;
  639. if (subtypes != null) {
  640. PythonContext pc = PythonContext.GetContext(context);
  641. foreach (WeakReference wr in subtypes) {
  642. if (wr.IsAlive) {
  643. PythonType pt = (PythonType)wr.Target;
  644. if (pt.PythonContext == null || pt.PythonContext == pc) {
  645. ret.AddNoLock(wr.Target);
  646. }
  647. }
  648. }
  649. }
  650. return ret;
  651. }
  652. public virtual List mro() {
  653. return new List(Get__mro__(this));
  654. }
  655. /// <summary>
  656. /// Returns true if the specified object is an instance of this type.
  657. /// </summary>
  658. public virtual bool __instancecheck__(object instance) {
  659. return SubclassImpl(DynamicHelpers.GetPythonType(instance));
  660. }
  661. public virtual bool __subclasscheck__(PythonType sub) {
  662. return SubclassImpl(sub);
  663. }
  664. private bool SubclassImpl(PythonType sub) {
  665. if (UnderlyingSystemType.IsInterface()) {
  666. // interfaces aren't in bases, and therefore IsSubclassOf doesn't do this check.
  667. if (UnderlyingSystemType.IsAssignableFrom(sub.UnderlyingSystemType)) {
  668. return true;
  669. }
  670. }
  671. return sub.IsSubclassOf(this);
  672. }
  673. public virtual bool __subclasscheck__(OldClass sub) {
  674. return IsSubclassOf(sub.TypeObject);
  675. }
  676. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")]
  677. public static implicit operator Type(PythonType self) {
  678. return self.UnderlyingSystemType;
  679. }
  680. public static implicit operator TypeTracker(PythonType self) {
  681. return ReflectionCache.GetTypeTracker(self.UnderlyingSystemType);
  682. }
  683. #endregion
  684. #region Internal API
  685. internal bool IsMixedNewStyleOldStyle() {
  686. if (!IsOldClass) {
  687. foreach (PythonType baseType in ResolutionOrder) {
  688. if (baseType.IsOldClass) {
  689. // mixed new-style/old-style class, we can't handle
  690. // __init__ in an old-style class yet (it doesn't show
  691. // up in a slot).
  692. return true;
  693. }
  694. }
  695. }
  696. return false;
  697. }
  698. internal int SlotCount {
  699. get {
  700. return _originalSlotCount;
  701. }
  702. }
  703. /// <summary>
  704. /// Gets the name of the dynamic type
  705. /// </summary>
  706. internal string Name {
  707. get {
  708. return _name;
  709. }
  710. set {
  711. _name = value;
  712. }
  713. }
  714. internal int Version {
  715. get {
  716. return _version;
  717. }
  718. }
  719. internal bool IsNull {
  720. get {
  721. return UnderlyingSystemType == typeof(DynamicNull);
  722. }
  723. }
  724. /// <summary>
  725. /// Gets the resolution order used for attribute lookup
  726. /// </summary>
  727. internal IList<PythonType> ResolutionOrder {
  728. get {
  729. return _resolutionOrder;
  730. }
  731. set {
  732. lock (SyncRoot) {
  733. _resolutionOrder = new List<PythonType>(value);
  734. }
  735. }
  736. }
  737. /// <summary>
  738. /// Gets the dynamic type that corresponds with the provided static type.
  739. ///
  740. /// Returns null if no type is available. TODO: In the future this will
  741. /// always return a PythonType created by the DLR.
  742. /// </summary>
  743. /// <param name="type"></param>
  744. /// <returns></returns>
  745. internal static PythonType/*!*/ GetPythonType(Type type) {
  746. object res;
  747. if (!_pythonTypes.TryGetValue(type, out res)) {
  748. lock (_pythonTypes) {
  749. if (!_pythonTypes.TryGetValue(type, out res)) {
  750. res = new PythonType(type);
  751. _pythonTypes.Add(type, res);
  752. }
  753. }
  754. }
  755. return (PythonType)res;
  756. }
  757. /// <summary>
  758. /// Sets the python type that corresponds with the provided static type.
  759. ///
  760. /// This is used for built-in types which have a metaclass. Currently
  761. /// only used by ctypes.
  762. /// </summary>
  763. internal static PythonType SetPythonType(Type type, PythonType pyType) {
  764. lock (_pythonTypes) {
  765. Debug.Assert(!_pythonTypes.Contains(type));
  766. Debug.Assert(pyType.GetType() != typeof(PythonType));
  767. _pythonTypes.Add(type, pyType);
  768. }
  769. return pyType;
  770. }
  771. /// <summary>
  772. /// Allocates the storage for the instance running the .NET constructor. This provides
  773. /// the creation functionality for __new__ implementations.
  774. /// </summary>
  775. internal object CreateInstance(CodeContext/*!*/ context) {
  776. EnsureInstanceCtor();
  777. return _instanceCtor.CreateInstance(context);
  778. }
  779. /// <summary>
  780. /// Allocates the storage for the instance running the .NET constructor. This provides
  781. /// the creation functionality for __new__ implementations.
  782. /// </summary>
  783. internal object CreateInstance(CodeContext/*!*/ context, object arg0) {
  784. EnsureInstanceCtor();
  785. return _instanceCtor.CreateInstance(context, arg0);
  786. }
  787. /// <summary>
  788. /// Allocates the storage for the instance running the .NET constructor. This provides
  789. /// the creation functionality for __new__ implementations.
  790. /// </summary>
  791. internal object CreateInstance(CodeContext/*!*/ context, object arg0, object arg1) {
  792. EnsureInstanceCtor();
  793. return _instanceCtor.CreateInstance(context, arg0, arg1);
  794. }
  795. /// <summary>
  796. /// Allocates the storage for the instance running the .NET constructor. This provides
  797. /// the creation functionality for __new__ implementations.
  798. /// </summary>
  799. internal object CreateInstance(CodeContext/*!*/ context, object arg0, object arg1, object arg2) {
  800. EnsureInstanceCtor();
  801. return _instanceCtor.CreateInstance(context, arg0, arg1, arg2);
  802. }
  803. /// <summary>
  804. /// Allocates the storage for the instance running the .NET constructor. This provides
  805. /// the creation functionality for __new__ implementations.
  806. /// </summary>
  807. internal object CreateInstance(CodeContext context, params object[] args) {
  808. Assert.NotNull(args);
  809. EnsureInstanceCtor();
  810. // unpack args for common cases so we don't generate code to do it...
  811. switch (args.Length) {
  812. case 0: return _instanceCtor.CreateInstance(context);
  813. case 1: return _instanceCtor.CreateInstance(context, args[0]);
  814. case 2: return _instanceCtor.CreateInstance(context, args[0], args[1]);
  815. case 3: return _instanceCtor.CreateInstance(context, args[0], args[1], args[2]);
  816. default:
  817. return _instanceCtor.CreateInstance(context, args);
  818. }
  819. }
  820. /// <summary>
  821. /// Allocates the storage for the instance running the .NET constructor. This provides
  822. /// the creation functionality for __new__ implementations.
  823. /// </summary>
  824. internal object CreateInstance(CodeContext context, object[] args, string[] names) {
  825. Assert.NotNull(args, "args");
  826. Assert.NotNull(names, "names");
  827. EnsureInstanceCtor();
  828. return _instanceCtor.CreateInstance(context, args, names);
  829. }
  830. internal int Hash(object o) {
  831. EnsureHashSite();
  832. return _hashSite.Target(_hashSite, o);
  833. }
  834. internal bool TryGetLength(CodeContext context, object o, out int length) {
  835. CallSite<Func<CallSite, CodeContext, object, object>> lenSite;
  836. if (IsSystemType) {
  837. lenSite = PythonContext.GetContext(context).GetSiteCacheForSystemType(UnderlyingSystemType).GetLenSite(context);
  838. } else {
  839. lenSite = _siteCache.GetLenSite(context);
  840. }
  841. PythonTypeSlot lenSlot = _lenSlot;
  842. if (lenSlot == null && !PythonOps.TryResolveTypeSlot(context, this, "__len__", out lenSlot)) {
  843. length = 0;
  844. return false;
  845. }
  846. object func;
  847. if (!lenSlot.TryGetValue(context, o, this, out func)) {
  848. length = 0;
  849. return false;
  850. }
  851. object res = lenSite.Target(lenSite, context, func);
  852. if (!(res is int)) {
  853. throw PythonOps.ValueError("__len__ must return int");
  854. }
  855. length = (int)res;
  856. return true;
  857. }
  858. internal bool EqualRetBool(object self, object other) {
  859. if (_eqSite == null) {
  860. Interlocked.CompareExchange(
  861. ref _eqSite,
  862. Context.CreateComparisonSite(PythonOperationKind.Equal),
  863. null
  864. );
  865. }
  866. return _eqSite.Target(_eqSite, self, other);
  867. }
  868. internal int Compare(object self, object other) {
  869. if (_compareSite == null) {
  870. Interlocked.CompareExchange(
  871. ref _compareSite,
  872. Context.MakeSortCompareSite(),
  873. null
  874. );
  875. }
  876. return _compareSite.Target(_compareSite, self, other);
  877. }
  878. internal bool TryGetBoundAttr(CodeContext context, object o, string name, out object ret) {
  879. CallSite<Func<CallSite, object, CodeContext, object>> site;
  880. if (IsSystemType) {
  881. site = PythonContext.GetContext(context).GetSiteCacheForSystemType(UnderlyingSystemType).GetTryGetMemberSite(context, name);
  882. } else {
  883. site = _siteCache.GetTryGetMemberSite(context, name);
  884. }
  885. try {
  886. ret = site.Target(site, o, context);
  887. return ret != OperationFailed.Value;
  888. } catch (MissingMemberException) {
  889. ret = null;
  890. return false;
  891. }
  892. }
  893. internal CallSite<Func<CallSite, object, int>> HashSite {
  894. get {
  895. EnsureHashSite();
  896. return _hashSite;
  897. }
  898. }
  899. private void EnsureHashSite() {
  900. if(_hashSite == null) {
  901. Interlocked.CompareExchange(
  902. ref _hashSite,
  903. CallSite<Func<CallSite, object, int>>.Create(
  904. Context.Operation(
  905. PythonOperationKind.Hash
  906. )
  907. ),
  908. null
  909. );
  910. }
  911. }
  912. /// <summary>
  913. /// Gets the underlying system type that is backing this type. All instances of this
  914. /// type are an instance of the underlying system type.
  915. /// </summary>
  916. internal Type/*!*/ UnderlyingSystemType {
  917. get {
  918. return _underlyingSystemType;
  919. }
  920. }
  921. internal Type/*!*/ FinalSystemType {
  922. get {
  923. return _finalSystemType ?? (_finalSystemType = PythonTypeOps.GetFinalSystemType(_underlyingSystemType));
  924. }
  925. }
  926. /// <summary>
  927. /// Gets the extension type for this type. The extension type provides
  928. /// a .NET type which can be inherited from to extend sealed classes
  929. /// or value types which Python allows inheritance from.
  930. /// </summary>
  931. internal Type/*!*/ ExtensionType {
  932. get {
  933. if (!_underlyingSystemType.IsEnum()) {
  934. switch (_underlyingSystemType.GetTypeCode()) {
  935. case TypeCode.String: return typeof(ExtensibleString);
  936. case TypeCode.Int32: return typeof(Extensible<int>);
  937. case TypeCode.Double: return typeof(Extensible<double>);
  938. case TypeCode.Object:
  939. if (_underlyingSystemType == typeof(BigInteger)) {
  940. return typeof(Extensible<BigInteger>);
  941. } else if (_underlyingSystemType == typeof(Complex)) {
  942. return typeof(ExtensibleComplex);
  943. }
  944. break;
  945. }
  946. }
  947. return _underlyingSystemType;
  948. }
  949. }
  950. /// <summary>
  951. /// Gets the base types from which this type inherits.
  952. /// </summary>
  953. internal IList<PythonType>/*!*/ BaseTypes {
  954. get {
  955. return _bases;
  956. }
  957. set {
  958. // validate input...
  959. foreach (PythonType pt in value) {
  960. if (pt == null) throw new ArgumentNullException("value", "a PythonType was null while assigning base classes");
  961. }
  962. // first update our sub-type list
  963. lock (_bases) {
  964. foreach (PythonType dt in _bases) {
  965. dt.RemoveSubType(this);
  966. }
  967. // set the new bases
  968. List<PythonType> newBases = new List<PythonType>(value);
  969. // add us as subtypes of our new bases
  970. foreach (PythonType dt in newBases) {
  971. dt.AddSubType(this);
  972. }
  973. UpdateVersion();
  974. _bases = newBases.ToArray();
  975. }
  976. }
  977. }
  978. /// <summary>
  979. /// Returns true if this type is a subclass of other
  980. /// </summary>
  981. internal bool IsSubclassOf(PythonType other) {
  982. // check for a type match
  983. if (other == this) {
  984. return true;
  985. }
  986. //Python doesn't have value types inheriting from ValueType, but we fake this for interop
  987. if (other.UnderlyingSystemType == typeof(ValueType) && UnderlyingSystemType.IsValueType()) {
  988. return true;
  989. }
  990. return IsSubclassWorker(other);
  991. }
  992. private bool IsSubclassWorker(PythonType other) {
  993. for (int i = 0; i < _bases.Length; i++) {
  994. PythonType baseClass = _bases[i];
  995. if (baseClass == other || baseClass.IsSubclassWorker(other)) {
  996. return true;
  997. }
  998. }
  999. return false;
  1000. }
  1001. /// <summary>
  1002. /// True if the type is a system type. A system type is a type which represents an
  1003. /// underlying .NET type and not a subtype of one of these types.
  1004. /// </summary>
  1005. internal bool IsSystemType {
  1006. get {
  1007. return (_attrs & PythonTypeAttributes.SystemType) != 0;
  1008. }
  1009. set {
  1010. if (value) _attrs |= PythonTypeAttributes.SystemType;
  1011. else _attrs &= (~PythonTypeAttributes.SystemType);
  1012. }
  1013. }
  1014. internal bool IsWeakReferencable {
  1015. get {
  1016. return (_attrs & PythonTypeAttributes.WeakReferencable) != 0;
  1017. }
  1018. set {
  1019. if (value) _attrs |= PythonTypeAttributes.WeakReferencable;
  1020. else _attrs &= (~PythonTypeAttributes.WeakReferencable);
  1021. }
  1022. }
  1023. internal bool HasDictionary {
  1024. get {
  1025. return (_attrs & PythonTypeAttributes.HasDictionary) != 0;
  1026. }
  1027. set {
  1028. if (value) _attrs |= PythonTypeAttributes.HasDictionary;
  1029. else _attrs &= (~PythonTypeAttributes.HasDictionary);
  1030. }
  1031. }
  1032. internal bool HasSystemCtor {
  1033. get {
  1034. return (_attrs & PythonTypeAttributes.SystemCtor) != 0;
  1035. }
  1036. }
  1037. internal void SetConstructor(BuiltinFunction ctor) {
  1038. _ctor = ctor;
  1039. }
  1040. internal bool IsPythonType {
  1041. get {
  1042. return (_attrs & PythonTypeAttributes.IsPythonType) != 0;
  1043. }
  1044. set {
  1045. if (value) {
  1046. _attrs |= PythonTypeAttributes.IsPythonType;
  1047. } else {
  1048. _attrs &= ~PythonTypeAttributes.IsPythonType;
  1049. }
  1050. }
  1051. }
  1052. internal OldClass OldClass {
  1053. get {
  1054. return _oldClass;
  1055. }
  1056. set {
  1057. _oldClass = value;
  1058. }
  1059. }
  1060. internal bool IsOldClass {
  1061. get {
  1062. return _oldClass != null;
  1063. }
  1064. }
  1065. internal PythonContext PythonContext {
  1066. get {
  1067. return _pythonContext;
  1068. }
  1069. }
  1070. internal PythonContext/*!*/ Context {
  1071. get {
  1072. return _pythonContext ?? DefaultContext.DefaultPythonContext;
  1073. }
  1074. }
  1075. internal object SyncRoot {
  1076. get {
  1077. // TODO: This is un-ideal, we should lock on something private.
  1078. return this;
  1079. }
  1080. }
  1081. internal bool IsHiddenMember(string name) {
  1082. PythonTypeSlot dummySlot;
  1083. return !TryResolveSlot(DefaultContext.Default, name, out dummySlot) &&
  1084. TryResolveSlot(DefaultContext.DefaultCLS, name, out dummySlot);
  1085. }
  1086. internal LateBoundInitBinder GetLateBoundInitBinder(CallSignature signature) {
  1087. Debug.Assert(!IsSystemType); // going to hold onto a PythonContext, shouldn't ever be a system type
  1088. Debug.Assert(_pythonContext != null);
  1089. if (_lateBoundInitBinders == null) {
  1090. Interlocked.CompareExchange(ref _lateBoundInitBinders, new Dictionary<CallSignature, LateBoundInitBinder>(), null);
  1091. }
  1092. lock(_lateBoundInitBinders) {
  1093. LateBoundInitBinder res;
  1094. if (!_lateBoundInitBinders.TryGetValue(signature, out res)) {
  1095. _lateBoundInitBinders[signature] = res = new LateBoundInitBinder(this, signature);
  1096. }
  1097. return res;
  1098. }
  1099. }
  1100. internal Dictionary<string, List<MethodInfo>> ExtensionMethods {
  1101. get {
  1102. if (_extensionMethods == null) {
  1103. Dictionary<string, List<MethodInfo>> extMethods = new Dictionary<string, List<MethodInfo>>();
  1104. foreach (var method in UnderlyingSystemType.GetMethods(BindingFlags.Static | BindingFlags.Public)) {
  1105. if (method.IsExtension()) {
  1106. List<MethodInfo> methods;
  1107. if (!extMethods.TryGetValue(method.Name, out methods)) {
  1108. extMethods[method.Name] = methods = new List<MethodInfo>();
  1109. }
  1110. methods.Add(method);
  1111. }
  1112. }
  1113. _extensionMethods = extMethods;
  1114. }
  1115. return _extensionMethods;
  1116. }
  1117. }
  1118. #endregion
  1119. #region Type member access
  1120. /// <summary>
  1121. /// Looks up a slot on the dynamic type
  1122. /// </summary>
  1123. internal bool TryLookupSlot(CodeContext context, string name, out PythonTypeSlot slot) {
  1124. if (IsSystemType) {
  1125. return PythonBinder.GetBinder(context).TryLookupSlot(context, this, name, out slot);
  1126. }
  1127. return _dict.TryGetValue(name, out slot);
  1128. }
  1129. /// <summary>
  1130. /// Searches the resolution order for a slot matching by name
  1131. /// </summary>
  1132. internal bool TryResolveSlot(CodeContext context, string name, out PythonTypeSlot slot) {
  1133. for (int i = 0; i < _resolutionOrder.Count; i++) {
  1134. PythonType dt = _resolutionOrder[i];
  1135. // don't look at interfaces - users can inherit from them, but we resolve members
  1136. // via methods implemented on types and defined by Python.
  1137. if (dt.IsSystemType && !dt.UnderlyingSystemType.IsInterface()) {
  1138. return PythonBinder.GetBinder(context).TryResolveSlot(context, dt, this, name, out slot);
  1139. }
  1140. if (dt.TryLookupSlot(context, name, out slot)) {
  1141. return true;
  1142. }
  1143. }
  1144. if (UnderlyingSystemType.IsInterface()) {
  1145. return TypeCache.Object.TryResolveSlot(context, name, out slot);
  1146. }
  1147. slot = null;
  1148. return false;
  1149. }
  1150. /// <summary>
  1151. /// Searches the resolution order for a slot matching by name.
  1152. ///
  1153. /// Includes searching for methods in old-style classes
  1154. /// </summary>
  1155. internal bool TryResolveMixedSlot(CodeContext context, string name, out PythonTypeSlot slot) {
  1156. for (int i = 0; i < _resolutionOrder.Count; i++) {
  1157. PythonType dt = _resolutionOrder[i];
  1158. if (dt.TryLookupSlot(context, name, out slot)) {
  1159. return true;
  1160. }
  1161. if (dt.OldClass != null) {
  1162. object ret;
  1163. if (dt.OldClass.TryLookupSlot(name, out ret)) {
  1164. slot = ToTypeSlot(ret);
  1165. return true;
  1166. }
  1167. }
  1168. }
  1169. slot = null;
  1170. return false;
  1171. }
  1172. /// <summary>
  1173. /// Internal helper to add a new slot to the type
  1174. /// </summary>
  1175. /// <param name="name"></param>
  1176. /// <param name="slot"></param>
  1177. internal void AddSlot(string name, PythonTypeSlot slot) {
  1178. Debug.Assert(!IsSystemType);
  1179. _dict[name] = slot;
  1180. if (name == "__new__") {
  1181. _objectNew = null;
  1182. ClearObjectNewInSubclasses(this);
  1183. } else if (name == "__init__") {
  1184. _objectInit = null;
  1185. ClearObjectInitInSubclasses(this);
  1186. }
  1187. }
  1188. private void ClearObjectNewInSubclasses(PythonType pt) {
  1189. lock (_subtypesLock) {
  1190. if (pt._subtypes != null) {
  1191. foreach (WeakReference wr in pt._subtypes) {
  1192. PythonType type = wr.Target as PythonType;
  1193. if (type != null) {
  1194. type._objectNew = null;
  1195. ClearObjectNewInSubclasses(type);
  1196. }
  1197. }
  1198. }
  1199. }
  1200. }
  1201. private void ClearObjectInitInSubclasses(PythonType pt) {
  1202. lock (_subtypesLock) {
  1203. if (pt._subtypes != null) {
  1204. foreach (WeakReference wr in pt._subtypes) {
  1205. PythonType type = wr.Target as PythonType;
  1206. if (type != null) {
  1207. type._objectInit = null;
  1208. ClearObjectInitInSubclasses(type);
  1209. }
  1210. }
  1211. }
  1212. }
  1213. }
  1214. internal bool TryGetCustomSetAttr(CodeContext context, out PythonTypeSlot pts) {
  1215. PythonContext pc = PythonContext.GetContext(context);
  1216. return pc.Binder.TryResolveSlot(
  1217. context,
  1218. DynamicHelpers.GetPythonType(this),
  1219. this,
  1220. "__setattr__",
  1221. out pts) &&
  1222. pts is BuiltinMethodDescriptor &&
  1223. ((BuiltinMethodDescriptor)pts).DeclaringType != typeof(PythonType);
  1224. }
  1225. internal void SetCustomMember(CodeContext/*!*/ context, string name, object value) {
  1226. Debug.Assert(context != null);
  1227. PythonTypeSlot dts;
  1228. if (TryResolveSlot(context, name, out dts)) {
  1229. if (dts.TrySetValue(context, null, this, value)) {
  1230. return;
  1231. }
  1232. }
  1233. if (PythonType._pythonTypeType.TryResolveSlot(context, name, out dts)) {
  1234. if (dts.TrySetValue(context, this, PythonType._pythonTypeType, value)) {
  1235. return;
  1236. }
  1237. }
  1238. if (IsSystemType) {
  1239. throw new MissingMemberException(String.Format("'{0}' object has no attribute '{1}'", Name, name));
  1240. }
  1241. PythonTypeSlot curSlot;
  1242. if (!(value is PythonTypeSlot) && _dict.TryGetValue(name, out curSlot) && curSlot is PythonTypeUserDescriptorSlot) {
  1243. if (SetAbstractMethodFlags(name, value)) {
  1244. UpdateVersion();
  1245. }
  1246. ((PythonTypeUserDescriptorSlot)curSlot).Value = value;
  1247. } else {
  1248. SetAbstractMethodFlags(name, value);
  1249. AddSlot(name, ToTypeSlot(value));
  1250. UpdateVersion();
  1251. }
  1252. }
  1253. internal static PythonTypeSlot ToTypeSlot(object value) {
  1254. PythonTypeSlot pts = value as PythonTypeSlot;
  1255. if (pts != null) {
  1256. return pts;
  1257. }
  1258. // We could do more checks for things which aren't descriptors
  1259. if (value != null) {
  1260. return new PythonTypeUserDescriptorSlot(value);
  1261. }
  1262. return new PythonTypeUserDescriptorSlot(value, true);
  1263. }
  1264. internal bool DeleteCustomMember(CodeContext/*!*/ context, string name) {
  1265. Debug.Assert(context != null);
  1266. PythonTypeSlot dts;
  1267. if (TryResolveSlot(context, name, out dts)) {
  1268. if (dts.TryDeleteValue(context, null, this))
  1269. return true;
  1270. }
  1271. if (IsSystemType) {
  1272. throw new MissingMemberException(String.Format("can't delete attributes of built-in/extension type '{0}'", Name));
  1273. }
  1274. if (!_dict.Remove(name)) {
  1275. throw new MissingMemberException(String.Format(CultureInfo.CurrentCulture,
  1276. IronPython.Resources.MemberDoesNotExist,
  1277. name.ToString()));
  1278. }
  1279. // match CPython's buggy behavior, there's a test in test_class for this.
  1280. /*
  1281. if (name == "__new__") {
  1282. _objectNew = null;
  1283. ClearObjectNewInSubclasses(this);
  1284. } else if (name == "__init__") {
  1285. _objectInit = null;
  1286. ClearObjectInitInSubclasses(this);
  1287. }*/
  1288. ClearAbstractMethodFlags(name);
  1289. UpdateVersion();
  1290. return true;
  1291. }
  1292. internal bool TryGetBoundCustomMember(CodeContext context, string name, out object value) {
  1293. PythonTypeSlot dts;
  1294. if (TryResolveSlot(context, name, out dts) &&
  1295. dts.TryGetValue(context, null, this, out value)) {
  1296. return true;
  1297. }
  1298. // search the type
  1299. PythonType myType = DynamicHelpers.GetPythonType(this);
  1300. if (myType.TryResolveSlot(context, name, out dts) &&
  1301. dts.TryGetValue(context, this, myType, out value)) {
  1302. return true;
  1303. }
  1304. value = null;
  1305. return false;
  1306. }
  1307. #region IFastGettable Members
  1308. T IFastGettable.MakeGetBinding<T>(CallSite<T> site, PythonGetMemberBinder/*!*/ binder, CodeContext context, string name) {
  1309. return (T)(object)new MetaPythonType.FastGetBinderHelper(this, context, binder).GetBinding();
  1310. }
  1311. #endregion
  1312. #endregion
  1313. #region Instance member access
  1314. internal object GetMember(CodeContext context, object instance, string name) {
  1315. object res;
  1316. if (TryGetMember(context, instance, name, out res)) {
  1317. return res;
  1318. }
  1319. throw new MissingMemberException(String.Format(CultureInfo.CurrentCulture,
  1320. IronPython.Resources.CantFindMember,
  1321. name));
  1322. }
  1323. internal void SetMember(CodeContext context, object instance, string name, object value) {
  1324. if (TrySetMember(context, instance, name, value)) {
  1325. return;
  1326. }
  1327. throw new MissingMemberException(
  1328. String.Format(CultureInfo.CurrentCulture,
  1329. IronPython.Resources.Slot_CantSet,
  1330. name));
  1331. }
  1332. internal void DeleteMember(CodeContext context, object instance, string name) {
  1333. if (TryDeleteMember(context, instance, name)) {
  1334. return;
  1335. }
  1336. throw new MissingMemberException(String.Format(CultureInfo.CurrentCulture, "couldn't delete member {0}", name));
  1337. }
  1338. /// <summary>
  1339. /// Gets a value from a dynamic type and any sub-types. Values are stored in slots (which serve as a level of
  1340. /// indirection). This searches the types resolution order and returns the first slot that
  1341. /// contains the value.
  1342. /// </summary>
  1343. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  1344. internal bool TryGetMember(CodeContext context, object instance, string name, out object value) {
  1345. if (TryGetNonCustomMember(context, instance, name, out value)) {
  1346. return true;
  1347. }
  1348. try {
  1349. if (PythonTypeOps.TryInvokeBinaryOperator(context, instance, name, "__getattr__", out value)) {
  1350. return true;
  1351. }
  1352. } catch (MissingMemberException) {
  1353. //!!! when do we let the user see this exception?
  1354. }
  1355. return false;
  1356. }
  1357. /// <summary>
  1358. /// Attempts to lookup a member w/o using the customizer. Equivelent to object.__getattribute__
  1359. /// but it doens't throw an exception.
  1360. /// </summary>
  1361. /// <returns></returns>
  1362. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  1363. internal bool TryGetNonCustomMember(CodeContext context, object instance, string name, out object value) {
  1364. PythonType pt;
  1365. IPythonObject sdo;
  1366. bool hasValue = false;
  1367. value = null;
  1368. // first see if we have the value in the instance dictionary...
  1369. // TODO: Instance checks should also work on functions,
  1370. if ((pt = instance as PythonType) != null) {
  1371. PythonTypeSlot pts;
  1372. if (pt.TryLookupSlot(context, name, out pts)) {
  1373. hasValue = pts.TryGetValue(context, null, this, out value);
  1374. }
  1375. } else if ((sdo = instance as IPythonObject) != null) {
  1376. PythonDictionary dict = sdo.Dict;
  1377. hasValue = dict != null && dict.TryGetValue(name, out value);
  1378. }
  1379. // then check through all the descriptors. If we have a data
  1380. // descriptor it takes priority over the value we found in the
  1381. // dictionary. Otherwise only run a get descriptor if we don't
  1382. // already have a value.
  1383. for (int i = 0; i < _resolutionOrder.Count; i++) {
  1384. PythonType dt = _resolutionOrder[i];
  1385. PythonTypeSlot slot;
  1386. object newValue;
  1387. if (dt.TryLookupSlot(context, name, out slot)) {
  1388. if (!hasValue || slot.IsSetDescriptor(context, this)) {
  1389. if (slot.TryGetValue(context, instance, this, out newValue))
  1390. value = newValue;
  1391. return true;
  1392. }
  1393. }
  1394. }
  1395. return hasValue;
  1396. }
  1397. /// <summary>
  1398. /// Gets a value from a dynamic type and any sub-types. Values are stored in slots (which serve as a level of
  1399. /// indirection). This searches the types resolution order and returns the first slot that
  1400. /// contains the value.
  1401. /// </summary>
  1402. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  1403. internal bool TryGetBoundMember(CodeContext context, object instance, string name, out object value) {
  1404. object getattr;
  1405. if (TryResolveNonObjectSlot(context, instance, "__getattribute__", out getattr)) {
  1406. value = InvokeGetAttributeMethod(context, name, getattr);
  1407. return true;
  1408. }
  1409. return TryGetNonCustomBoundMember(context, instance, name, out value);
  1410. }
  1411. private object InvokeGetAttributeMethod(CodeContext context, string name, object getattr) {
  1412. CallSite<Func<CallSite, CodeContext, object, string, object>> getAttributeSite;
  1413. if (IsSystemType) {
  1414. getAttributeSite = PythonContext.GetContext(context).GetSiteCacheForSystemType(UnderlyingSystemType).GetGetAttributeSite(context);
  1415. } else {
  1416. getAttributeSite = _siteCache.GetGetAttributeSite(context);
  1417. }
  1418. return getAttributeSite.Target(getAttributeSite, context, getattr, name);
  1419. }
  1420. /// <summary>
  1421. /// Attempts to lookup a member w/o using the customizer.
  1422. /// </summary>
  1423. /// <returns></returns>
  1424. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  1425. internal bool TryGetNonCustomBoundMember(CodeContext context, object instance, string name, out object value) {
  1426. IPythonObject sdo = instance as IPythonObject;
  1427. if (sdo != null) {
  1428. PythonDictionary iac = sdo.Dict;
  1429. if (iac != null && iac.TryGetValue(name, out value)) {
  1430. return true;
  1431. }
  1432. }
  1433. if (TryResolveSlot(context, instance, name, out value)) {
  1434. return true;
  1435. }
  1436. try {
  1437. object getattr;
  1438. if (TryResolveNonObjectSlot(context, instance, "__getattr__", out getattr)) {
  1439. value = InvokeGetAttributeMethod(context, name, getattr);
  1440. return true;
  1441. }
  1442. } catch (MissingMemberException) {
  1443. //!!! when do we let the user see this exception?
  1444. }
  1445. value = null;
  1446. return false;
  1447. }
  1448. private bool TryResolveSlot(CodeContext context, object instance, string name, out object value) {
  1449. for (int i = 0; i < _resolutionOrder.Count; i++) {
  1450. PythonType dt = _resolutionOrder[i];
  1451. PythonTypeSlot slot;
  1452. if (dt.TryLookupSlot(context, name, out slot)) {
  1453. if (slot.TryGetValue(context, instance, this, out value))
  1454. return true;
  1455. }
  1456. }
  1457. value = null;
  1458. return false;
  1459. }
  1460. private bool TryResolveNonObjectSlot(CodeContext context, object instance, string name, out object value) {
  1461. for (int i = 0; i < _resolutionOrder.Count; i++) {
  1462. PythonType dt = _resolutionOrder[i];
  1463. if (dt == TypeCache.Object) break;
  1464. PythonTypeSlot slot;
  1465. if (dt.TryLookupSlot(context, name, out slot)) {
  1466. if (slot.TryGetValue(context, instance, this, out value))
  1467. return true;
  1468. }
  1469. }
  1470. value = null;
  1471. return false;
  1472. }
  1473. /// <summary>
  1474. /// Sets a value on an instance. If a slot is available in the most derived type the slot
  1475. /// is set there, otherwise the value is stored directly in the instance.
  1476. /// </summary>
  1477. internal bool TrySetMember(CodeContext context, object instance, string name, object value) {
  1478. object setattr;
  1479. if (TryResolveNonObjectSlot(context, instance, "__setattr__", out setattr)) {
  1480. CallSite<Func<CallSite, CodeContext, object, object, string, object, object>> setAttrSite;
  1481. if (IsSystemType) {
  1482. setAttrSite = PythonContext.GetContext(context).GetSiteCacheForSystemType(UnderlyingSystemType).GetSetAttrSite(context);
  1483. } else {
  1484. setAttrSite = _siteCache.GetSetAttrSite(context);
  1485. }
  1486. setAttrSite.Target(setAttrSite, context, setattr, instance, name, value);
  1487. return true;
  1488. }
  1489. return TrySetNonCustomMember(context, instance, name, value);
  1490. }
  1491. /// <summary>
  1492. /// Attempst to set a value w/o going through the customizer.
  1493. ///
  1494. /// This enables languages to provide the "base" implementation for setting attributes
  1495. /// so that the customizer can call back here.
  1496. /// </summary>
  1497. internal bool TrySetNonCustomMember(CodeContext context, object instance, string name, object value) {
  1498. PythonTypeSlot slot;
  1499. if (TryResolveSlot(context, name, out slot)) {
  1500. if (slot.TrySetValue(context, instance, this, value)) {
  1501. return true;
  1502. }
  1503. }
  1504. // set the attribute on the instance
  1505. IPythonObject sdo = instance as IPythonObject;
  1506. if (sdo != null) {
  1507. PythonDictionary iac = sdo.Dict;
  1508. if (iac == null && sdo.PythonType.HasDictionary) {
  1509. iac = MakeDictionary();
  1510. if ((iac = sdo.SetDict(iac)) == null) {
  1511. return false;
  1512. }
  1513. }
  1514. iac[name] = value;
  1515. return true;
  1516. }
  1517. return false;
  1518. }
  1519. internal bool TryDeleteMember(CodeContext context, object instance, string name) {
  1520. try {
  1521. object delattr;
  1522. if (TryResolveNonObjectSlot(context, instance, "__delattr__", out delattr)) {
  1523. InvokeGetAttributeMethod(context, name, delattr);
  1524. return true;
  1525. }
  1526. } catch (MissingMemberException) {
  1527. //!!! when do we let the user see this exception?
  1528. }
  1529. return TryDeleteNonCustomMember(context, instance, name);
  1530. }
  1531. internal bool TryDeleteNonCustomMember(CodeContext context, object instance, string name) {
  1532. PythonTypeSlot slot;
  1533. if (TryResolveSlot(context, name, out slot)) {
  1534. if (slot.TryDeleteValue(context, instance, this)) {
  1535. return true;
  1536. }
  1537. }
  1538. // set the attribute on the instance
  1539. IPythonObject sdo = instance as IPythonObject;
  1540. if (sdo != null) {
  1541. PythonDictionary dict = sdo.Dict;
  1542. if (dict == null && sdo.PythonType.HasDictionary) {
  1543. dict = MakeDictionary();
  1544. if ((dict = sdo.SetDict(dict)) == null) {
  1545. return false;
  1546. }
  1547. }
  1548. return dict.Remove(name);
  1549. }
  1550. return false;
  1551. }
  1552. #endregion
  1553. #region Member lists
  1554. /// <summary>
  1555. /// Returns a list of all slot names for the type and any subtypes.
  1556. /// </summary>
  1557. /// <param name="context">The context that is doing the inquiry of InvariantContext.Instance.</param>
  1558. internal List GetMemberNames(CodeContext context) {
  1559. return GetMemberNames(context, null);
  1560. }
  1561. /// <summary>
  1562. /// Returns a list of all slot names for the type, any subtypes, and the instance.
  1563. /// </summary>
  1564. /// <param name="context">The context that is doing the inquiry of InvariantContext.Instance.</param>
  1565. /// <param name="self">the instance to get instance members from, or null.</param>
  1566. internal List GetMemberNames(CodeContext context, object self) {
  1567. List res = TryGetCustomDir(context, self);
  1568. if (res != null) {
  1569. return res;
  1570. }
  1571. Dictionary<string, string> keys = new Dictionary<string, string>();
  1572. res = new List();
  1573. for (int i = 0; i < _resolutionOrder.Count; i++) {
  1574. PythonType dt = _resolutionOrder[i];
  1575. if (dt.IsSystemType) {
  1576. PythonBinder.GetBinder(context).ResolveMemberNames(context, dt, this, keys);
  1577. } else {
  1578. AddUserTypeMembers(context, keys, dt, res);
  1579. }
  1580. }
  1581. var extMethods = context.ModuleContext.ExtensionMethods;
  1582. if (extMethods != ExtensionMethodSet.Empty) {
  1583. // add any available extension methods.
  1584. foreach (var method in extMethods.GetExtensionMethods(this)) {
  1585. keys[method.Name] = method.Name;
  1586. }
  1587. }
  1588. return AddInstanceMembers(self, keys, res);
  1589. }
  1590. private List TryGetCustomDir(CodeContext context, object self) {
  1591. if (self != null) {
  1592. object dir;
  1593. if (TryResolveNonObjectSlot(context, self, "__dir__", out dir)) {
  1594. CallSite<Func<CallSite, CodeContext, object, object>> dirSite;
  1595. if (IsSystemType) {
  1596. dirSite = PythonContext.GetContext(context).GetSiteCacheForSystemType(UnderlyingSystemType).GetDirSite(context);
  1597. } else {
  1598. dirSite = _siteCache.GetDirSite(context);
  1599. }
  1600. return new List(dirSite.Target(dirSite, context, dir));
  1601. }
  1602. }
  1603. return null;
  1604. }
  1605. /// <summary>
  1606. /// Adds members from a user defined type.
  1607. /// </summary>
  1608. private static void AddUserTypeMembers(CodeContext context, Dictionary<string, string> keys, PythonType dt, List res) {
  1609. if (dt.OldClass != null) {
  1610. foreach (KeyValuePair<object, object> kvp in dt.OldClass._dict) {
  1611. AddOneMember(keys, res, kvp.Key);
  1612. }
  1613. } else {
  1614. foreach (KeyValuePair<string, PythonTypeSlot> kvp in dt._dict) {
  1615. if (keys.ContainsKey(kvp.Key)) continue;
  1616. keys[kvp.Key] = kvp.Key;
  1617. }
  1618. }
  1619. }
  1620. private static void AddOneMember(Dictionary<string, string> keys, List res, object name) {
  1621. string strKey = name as string;
  1622. if (strKey != null) {
  1623. keys[strKey] = strKey;
  1624. } else {
  1625. res.Add(name);
  1626. }
  1627. }
  1628. /// <summary>
  1629. /// Adds members from a user defined type instance
  1630. /// </summary>
  1631. private static List AddInstanceMembers(object self, Dictionary<string, string> keys, List res) {
  1632. IPythonObject dyno = self as IPythonObject;
  1633. if (dyno != null) {
  1634. PythonDictionary dict = dyno.Dict;
  1635. if (dict != null) {
  1636. lock (dict) {
  1637. foreach (object name in dict.Keys) {
  1638. AddOneMember(keys, res, name);
  1639. }
  1640. }
  1641. }
  1642. }
  1643. List<string> strKeys = new List<string>(keys.Keys);
  1644. strKeys.Sort();
  1645. res.extend(strKeys);
  1646. return res;
  1647. }
  1648. internal PythonDictionary GetMemberDictionary(CodeContext context) {
  1649. return GetMemberDictionary(context, true);
  1650. }
  1651. internal PythonDictionary GetMemberDictionary(CodeContext context, bool excludeDict) {
  1652. PythonDictionary dict = PythonDictionary.MakeSymbolDictionary();
  1653. if (IsSystemType) {
  1654. PythonBinder.GetBinder(context).LookupMembers(context, this, dict);
  1655. } else {
  1656. foreach (var item in _dict) {
  1657. if (excludeDict && item.Key == "__dict__") {
  1658. continue;
  1659. }
  1660. PythonTypeUserDescriptorSlot dts = item.Value as PythonTypeUserDescriptorSlot;
  1661. object val = dts == null ? item.Value : dts.Value;
  1662. dict[item.Key] = val;
  1663. }
  1664. }
  1665. return dict;
  1666. }
  1667. #endregion
  1668. #region User type initialization
  1669. private void InitializeUserType(CodeContext/*!*/ context, string name, PythonTuple bases, PythonDictionary vars, string selfNames) {
  1670. // we don't support overriding __mro__
  1671. if (vars.ContainsKey("__mro__"))
  1672. throw new NotImplementedException("Overriding __mro__ of built-in types is not implemented");
  1673. // cannot override mro when inheriting from type
  1674. if (vars.ContainsKey("mro")) {
  1675. foreach (object o in bases) {
  1676. PythonType dt = o as PythonType;
  1677. if (dt != null && dt.IsSubclassOf(TypeCache.PythonType)) {
  1678. throw new NotImplementedException("Overriding type.mro is not implemented");
  1679. }
  1680. }
  1681. }
  1682. bases = ValidateBases(bases);
  1683. _name = name;
  1684. _bases = GetBasesAsList(bases).ToArray();
  1685. _pythonContext = PythonContext.GetContext(context);
  1686. _resolutionOrder = CalculateMro(this, _bases);
  1687. bool hasSlots = false;
  1688. foreach (PythonType pt in _bases) {
  1689. // if we directly inherit from 2 types with slots then the indexes would
  1690. // conflict so inheritance isn't allowed.
  1691. int slotCount = pt.GetUsedSlotCount();
  1692. if (slotCount != 0) {
  1693. if (hasSlots) {
  1694. throw PythonOps.TypeError("multiple bases have instance lay-out conflict");
  1695. }
  1696. hasSlots = true;
  1697. }
  1698. pt.AddSubType(this);
  1699. }
  1700. HashSet<string> optimizedInstanceNames = null;
  1701. foreach (PythonType pt in _resolutionOrder) {
  1702. // we need to calculate the number of slots from resolution
  1703. // order to deal with multiple bases having __slots__ that
  1704. // directly inherit from each other.
  1705. _originalSlotCount += pt.GetUsedSlotCount();
  1706. if (pt._optimizedInstanceNames != null) {
  1707. if (optimizedInstanceNames == null) {
  1708. optimizedInstanceNames = new HashSet<string>();
  1709. }
  1710. optimizedInstanceNames.UnionWith(pt._optimizedInstanceNames);
  1711. }
  1712. }
  1713. if (!String.IsNullOrEmpty(selfNames)) {
  1714. if (optimizedInstanceNames == null) {
  1715. optimizedInstanceNames = new HashSet<string>();
  1716. }
  1717. optimizedInstanceNames.UnionWith(selfNames.Split(','));
  1718. }
  1719. if (optimizedInstanceNames != null) {
  1720. _optimizedInstanceVersion = CustomInstanceDictionaryStorage.AllocateVersion();
  1721. _optimizedInstanceNames = new List<string>(optimizedInstanceNames).ToArray();
  1722. }
  1723. EnsureDict();
  1724. PopulateDictionary(context, name, bases, vars);
  1725. #if FEATURE_REFEMIT
  1726. // calculate the .NET type once so it can be used for things like super calls
  1727. _underlyingSystemType = NewTypeMaker.GetNewType(name, bases);
  1728. // then let the user intercept and rewrite the type - the user can't create
  1729. // instances of this type yet.
  1730. _underlyingSystemType = __clrtype__();
  1731. if (_underlyingSystemType == null) {
  1732. throw PythonOps.ValueError("__clrtype__ must return a type, not None");
  1733. }
  1734. #else
  1735. _underlyingSystemType = typeof(IronPython.NewTypes.System.Object_1_1);
  1736. #endif
  1737. // finally assign the ctors from the real type the user provided
  1738. lock (_userTypeCtors) {
  1739. if (!_userTypeCtors.TryGetValue(_underlyingSystemType, out _ctor)) {
  1740. ConstructorInfo[] ctors = _underlyingSystemType.GetConstructors();
  1741. bool isPythonType = false;
  1742. foreach (ConstructorInfo ci in ctors) {
  1743. ParameterInfo[] pis = ci.GetParameters();
  1744. if((pis.Length > 1 && pis[0].ParameterType == typeof(CodeContext) && pis[1].ParameterType == typeof(PythonType)) ||
  1745. (pis.Length > 0 && pis[0].ParameterType == typeof(PythonType))) {
  1746. isPythonType = true;
  1747. break;
  1748. }
  1749. }
  1750. _ctor = BuiltinFunction.MakeFunction(Name, ctors, _underlyingSystemType);
  1751. if (isPythonType) {
  1752. _userTypeCtors[_underlyingSystemType] = _ctor;
  1753. } else {
  1754. // __clrtype__ returned a type w/o any PythonType parameters, force this to
  1755. // be created like a normal .NET type. Presumably the user is planning on storing
  1756. // the Python type in a static field or something and passing the Type object to
  1757. // some .NET API which wants to Activator.CreateInstance on it w/o providing a
  1758. // PythonType object.
  1759. _instanceCtor = new SystemInstanceCreator(this);
  1760. _attrs |= PythonTypeAttributes.SystemCtor;
  1761. }
  1762. }
  1763. }
  1764. UpdateObjectNewAndInit(context);
  1765. }
  1766. internal PythonDictionary MakeDictionary() {
  1767. if (_optimizedInstanceNames != null) {
  1768. return new PythonDictionary(new CustomInstanceDictionaryStorage(_optimizedInstanceNames, _optimizedInstanceVersion));
  1769. }
  1770. return PythonDictionary.MakeSymbolDictionary();
  1771. }
  1772. internal IList<string> GetOptimizedInstanceNames() {
  1773. return _optimizedInstanceNames;
  1774. }
  1775. internal int GetOptimizedInstanceVersion() {
  1776. return _optimizedInstanceVersion;
  1777. }
  1778. internal IList<string> GetTypeSlots() {
  1779. PythonTypeSlot pts;
  1780. if(_dict != null && _dict.TryGetValue("__slots__", out pts) && pts is PythonTypeUserDescriptorSlot) {
  1781. return SlotsToList(((PythonTypeUserDescriptorSlot)pts).Value);
  1782. }
  1783. return ArrayUtils.EmptyStrings;
  1784. }
  1785. internal static List<string> GetSlots(PythonDictionary dict) {
  1786. List<string> res = null;
  1787. object slots;
  1788. if (dict != null && dict.TryGetValue("__slots__", out slots)) {
  1789. res = SlotsToList(slots);
  1790. }
  1791. return res;
  1792. }
  1793. internal static List<string> SlotsToList(object slots) {
  1794. List<string> res = new List<string>();
  1795. IList<object> seq = slots as IList<object>;
  1796. if (seq != null) {
  1797. res = new List<string>(seq.Count);
  1798. for (int i = 0; i < seq.Count; i++) {
  1799. res.Add(GetSlotName(seq[i]));
  1800. }
  1801. res.Sort();
  1802. } else {
  1803. res = new List<string>(1);
  1804. res.Add(GetSlotName(slots));
  1805. }
  1806. return res;
  1807. }
  1808. internal bool HasObjectNew(CodeContext context) {
  1809. if (!_objectNew.HasValue) {
  1810. UpdateObjectNewAndInit(context);
  1811. }
  1812. Debug.Assert(_objectNew.HasValue);
  1813. return _objectNew.Value;
  1814. }
  1815. internal bool HasObjectInit(CodeContext context) {
  1816. if (!_objectInit.HasValue) {
  1817. UpdateObjectNewAndInit(context);
  1818. }
  1819. Debug.Assert(_objectInit.HasValue);
  1820. return _objectInit.Value;
  1821. }
  1822. private void UpdateObjectNewAndInit(CodeContext context) {
  1823. PythonTypeSlot slot;
  1824. object funcObj;
  1825. foreach (PythonType pt in _bases) {
  1826. if (pt == TypeCache.Object) {
  1827. continue;
  1828. }
  1829. if (pt._objectNew == null || pt._objectInit == null) {
  1830. pt.UpdateObjectNewAndInit(context);
  1831. }
  1832. Debug.Assert(pt._objectInit != null && pt._objectNew != null);
  1833. if (!pt._objectNew.Value) {
  1834. _objectNew = false;
  1835. }
  1836. if (!pt._objectInit.Value) {
  1837. _objectInit = false;
  1838. }
  1839. }
  1840. if (_objectInit == null) {
  1841. _objectInit = TryResolveSlot(context, "__init__", out slot) && slot.TryGetValue(context, null, this, out funcObj) && funcObj == InstanceOps.Init;
  1842. }
  1843. if (_objectNew == null) {
  1844. _objectNew = TryResolveSlot(context, "__new__", out slot) && slot.TryGetValue(context, null, this, out funcObj) && funcObj == InstanceOps.New;
  1845. }
  1846. }
  1847. private static string GetSlotName(object o) {
  1848. string value;
  1849. if (!Converter.TryConvertToString(o, out value) || String.IsNullOrEmpty(value))
  1850. throw PythonOps.TypeError("slots must be one string or a list of strings");
  1851. for (int i = 0; i < value.Length; i++) {
  1852. if ((value[i] >= 'a' && value[i] <= 'z') ||
  1853. (value[i] >= 'A' && value[i] <= 'Z') ||
  1854. (i != 0 && value[i] >= '0' && value[i] <= '9') ||
  1855. value[i] == '_') {
  1856. continue;
  1857. }
  1858. throw PythonOps.TypeError("__slots__ must be valid identifiers");
  1859. }
  1860. return value;
  1861. }
  1862. private int GetUsedSlotCount() {
  1863. int slotCount = 0;
  1864. if (_slots != null) {
  1865. slotCount = _slots.Length;
  1866. if (Array.IndexOf(_slots, "__weakref__") != -1) {
  1867. slotCount--;
  1868. }
  1869. if (Array.IndexOf(_slots, "__dict__") != -1) {
  1870. slotCount--;
  1871. }
  1872. }
  1873. return slotCount;
  1874. }
  1875. private void PopulateDictionary(CodeContext/*!*/ context, string name, PythonTuple bases, PythonDictionary vars) {
  1876. PopulateSlot("__doc__", null);
  1877. List<string> slots = GetSlots(vars);
  1878. if (slots != null) {
  1879. _slots = slots.ToArray();
  1880. int index = _originalSlotCount;
  1881. string typeName = IronPython.Compiler.Parser.GetPrivatePrefix(name);
  1882. for (int i = 0; i < slots.Count; i++) {
  1883. string slotName = slots[i];
  1884. if (slotName.StartsWith("__") && !slotName.EndsWith("__")) {
  1885. slotName = "_" + typeName + slotName;
  1886. }
  1887. AddSlot(slotName, new ReflectedSlotProperty(slotName, name, i + index));
  1888. }
  1889. _originalSlotCount += slots.Count;
  1890. }
  1891. // check the slots to see if we're weak refable
  1892. if (CheckForSlotWithDefault(context, _resolutionOrder, slots, "__weakref__")) {
  1893. _attrs |= PythonTypeAttributes.WeakReferencable;
  1894. AddSlot("__weakref__", new PythonTypeWeakRefSlot(this));
  1895. }
  1896. // check if we have a dictionary
  1897. if (CheckForSlotWithDefault(context, _resolutionOrder, slots, "__dict__")) {
  1898. _attrs |= PythonTypeAttributes.HasDictionary;
  1899. PythonTypeSlot pts;
  1900. bool inheritsDict = false;
  1901. for (int i = 1; i<_resolutionOrder.Count; i++) {
  1902. PythonType pt = _resolutionOrder[i];
  1903. if (pt.TryResolveSlot(context, "__dict__", out pts)) {
  1904. inheritsDict = true;
  1905. break;
  1906. }
  1907. }
  1908. if (!inheritsDict) {
  1909. AddSlot("__dict__", new PythonTypeDictSlot(this));
  1910. }
  1911. }
  1912. object modName;
  1913. if (context.TryGetVariable("__name__", out modName)) {
  1914. PopulateSlot("__module__", modName);
  1915. }
  1916. foreach (var kvp in vars) {
  1917. if (kvp.Key is string) {
  1918. PopulateSlot((string)kvp.Key, kvp.Value);
  1919. }
  1920. }
  1921. PythonTypeSlot val;
  1922. if (_dict.TryGetValue("__new__", out val) && val is PythonFunction) {
  1923. AddSlot("__new__", new staticmethod(val));
  1924. }
  1925. }
  1926. private bool CheckForSlotWithDefault(CodeContext context, IList<PythonType> resolutionOrder, List<string> slots, string name) {
  1927. // slots not restricted
  1928. if (slots == null)
  1929. return true;
  1930. // slot defined in the __slots__ tuple
  1931. if (slots.Contains(name)) {
  1932. if (resolutionOrder.Count > 1) {
  1933. PythonType dt = resolutionOrder[1];
  1934. PythonTypeSlot dummy;
  1935. if (dt != null && dt.TryLookupSlot(context, name, out dummy)) {
  1936. throw PythonOps.TypeError(name + " slot disallowed: we already got one");
  1937. }
  1938. }
  1939. return true;
  1940. }
  1941. // slot defined in a base class
  1942. foreach (PythonType dt in resolutionOrder.Skip(1)) {
  1943. PythonTypeSlot dummy;
  1944. if (dt.TryLookupSlot(context, name, out dummy)) {
  1945. return true;
  1946. }
  1947. }
  1948. // slot not available
  1949. return false;
  1950. }
  1951. /// <summary>
  1952. /// Gets the .NET type which is used for instances of the Python type.
  1953. ///
  1954. /// When overridden by a metaclass enables a customization of the .NET type which
  1955. /// is used for instances of the Python type. Meta-classes can construct custom
  1956. /// types at runtime which include new .NET methods, fields, custom attributes or
  1957. /// other features to better interoperate with .NET.
  1958. /// </summary>
  1959. [PythonHidden]
  1960. public virtual Type __clrtype__() {
  1961. return _underlyingSystemType;
  1962. }
  1963. private void PopulateSlot(string key, object value) {
  1964. AddSlot(key, ToTypeSlot(value));
  1965. }
  1966. private static List<PythonType> GetBasesAsList(PythonTuple bases) {
  1967. List<PythonType> newbs = new List<PythonType>();
  1968. foreach (object typeObj in bases) {
  1969. PythonType dt = typeObj as PythonType;
  1970. if (dt == null) {
  1971. dt = ((OldClass)typeObj).TypeObject;
  1972. }
  1973. newbs.Add(dt);
  1974. }
  1975. return newbs;
  1976. }
  1977. private static PythonTuple ValidateBases(PythonTuple bases) {
  1978. PythonTuple newBases = PythonTypeOps.EnsureBaseType(bases);
  1979. for (int i = 0; i < newBases.__len__(); i++) {
  1980. #if !FEATURE_REFEMIT
  1981. PythonType pt = newBases[i] as PythonType;
  1982. if (pt != null && pt.IsSystemType && pt != TypeCache.Object) {
  1983. // The only supported CLR base class w/o refemit is object
  1984. throw new NotSupportedException(string.Format("{0} is not a valid CLR base class. Only object is supported w/o refemit.", pt.UnderlyingSystemType.FullName));
  1985. }
  1986. #endif
  1987. for (int j = 0; j < newBases.__len__(); j++) {
  1988. if (i != j && newBases[i] == newBases[j]) {
  1989. OldClass oc = newBases[i] as OldClass;
  1990. if (oc != null) {
  1991. throw PythonOps.TypeError("duplicate base class {0}", oc.Name);
  1992. } else {
  1993. throw PythonOps.TypeError("duplicate base class {0}", ((PythonType)newBases[i]).Name);
  1994. }
  1995. }
  1996. }
  1997. }
  1998. return newBases;
  1999. }
  2000. private static void EnsureModule(CodeContext context, PythonDictionary dict) {
  2001. if (!dict.ContainsKey("__module__")) {
  2002. object modName;
  2003. if (context.TryGetVariable("__name__", out modName)) {
  2004. dict["__module__"] = modName;
  2005. }
  2006. }
  2007. }
  2008. #endregion
  2009. #region System type initialization
  2010. /// <summary>
  2011. /// Initializes a PythonType that represents a standard .NET type. The same .NET type
  2012. /// can be shared with the Python type system. For example object, string, int,
  2013. /// etc... are all the same types.
  2014. /// </summary>
  2015. private void InitializeSystemType() {
  2016. IsSystemType = true;
  2017. IsPythonType = PythonBinder.IsPythonType(_underlyingSystemType);
  2018. _name = NameConverter.GetTypeName(_underlyingSystemType);
  2019. AddSystemBases();
  2020. }
  2021. private void AddSystemBases() {
  2022. List<PythonType> mro = new List<PythonType>();
  2023. mro.Add(this);
  2024. if (_underlyingSystemType.GetBaseType() != null) {
  2025. Type baseType;
  2026. if (_underlyingSystemType == typeof(bool)) {
  2027. // bool inherits from int in python
  2028. baseType = typeof(int);
  2029. } else if (_underlyingSystemType.GetBaseType() == typeof(ValueType)) {
  2030. // hide ValueType, it doesn't exist in Python
  2031. baseType = typeof(object);
  2032. } else {
  2033. baseType = _underlyingSystemType.GetBaseType();
  2034. }
  2035. while (baseType.GetTypeInfo().IsDefined(typeof(PythonHiddenBaseClassAttribute), false)) {
  2036. baseType = baseType.GetBaseType();
  2037. }
  2038. _bases = new PythonType[] { GetPythonType(baseType) };
  2039. Type curType = baseType;
  2040. while (curType != null) {
  2041. Type newType;
  2042. if (TryReplaceExtensibleWithBase(curType, out newType)) {
  2043. mro.Add(DynamicHelpers.GetPythonTypeFromType(newType));
  2044. } else if(!curType.GetTypeInfo().IsDefined(typeof(PythonHiddenBaseClassAttribute), false)) {
  2045. mro.Add(DynamicHelpers.GetPythonTypeFromType(curType));
  2046. }
  2047. curType = curType.GetBaseType();
  2048. }
  2049. if (!IsPythonType) {
  2050. AddSystemInterfaces(mro);
  2051. }
  2052. } else if (_underlyingSystemType.IsInterface()) {
  2053. // add interfaces to MRO & create bases list
  2054. Type[] interfaces = _underlyingSystemType.GetInterfaces();
  2055. PythonType[] bases = new PythonType[interfaces.Length];
  2056. for (int i = 0; i < interfaces.Length; i++) {
  2057. Type iface = interfaces[i];
  2058. PythonType it = DynamicHelpers.GetPythonTypeFromType(iface);
  2059. mro.Add(it);
  2060. bases[i] = it;
  2061. }
  2062. _bases = bases;
  2063. } else {
  2064. _bases = new PythonType[0];
  2065. }
  2066. _resolutionOrder = mro;
  2067. }
  2068. private void AddSystemInterfaces(List<PythonType> mro) {
  2069. if (_underlyingSystemType.IsArray) {
  2070. // include the standard array interfaces in the array MRO. We pick the
  2071. // non-strongly typed versions which are also in Array.__mro__
  2072. mro.Add(DynamicHelpers.GetPythonTypeFromType(typeof(IList)));
  2073. mro.Add(DynamicHelpers.GetPythonTypeFromType(typeof(ICollection)));
  2074. mro.Add(DynamicHelpers.GetPythonTypeFromType(typeof(IEnumerable)));
  2075. return;
  2076. }
  2077. Type[] interfaces = _underlyingSystemType.GetInterfaces();
  2078. Dictionary<string, Type> methodMap = new Dictionary<string, Type>();
  2079. bool hasExplicitIface = false;
  2080. List<Type> nonCollidingInterfaces = new List<Type>(interfaces);
  2081. PythonType[] bases = new PythonType[_bases.Length + interfaces.Length];
  2082. Array.Copy(_bases, bases, _bases.Length);
  2083. for(int i = 0; i < interfaces.Length; i++) {
  2084. bases[i + _bases.Length] = PythonType.GetPythonType(interfaces[i]);
  2085. }
  2086. lock (_bases) {
  2087. _bases = bases;
  2088. }
  2089. foreach (Type iface in interfaces) {
  2090. InterfaceMapping mapping = _underlyingSystemType.GetTypeInfo().GetRuntimeInterfaceMap(iface);
  2091. // grab all the interface methods which would hide other members
  2092. for (int i = 0; i < mapping.TargetMethods.Length; i++) {
  2093. MethodInfo target = mapping.TargetMethods[i];
  2094. if (target == null) {
  2095. continue;
  2096. }
  2097. if (!target.IsPrivate) {
  2098. methodMap[target.Name] = null;
  2099. } else {
  2100. hasExplicitIface = true;
  2101. }
  2102. }
  2103. if (hasExplicitIface) {
  2104. for (int i = 0; i < mapping.TargetMethods.Length; i++) {
  2105. MethodInfo target = mapping.TargetMethods[i];
  2106. MethodInfo iTarget = mapping.InterfaceMethods[i];
  2107. // any methods which aren't explicit are picked up at the appropriate
  2108. // time earlier in the MRO so they can be ignored
  2109. if (target != null && target.IsPrivate) {
  2110. hasExplicitIface = true;
  2111. Type existing;
  2112. if (methodMap.TryGetValue(iTarget.Name, out existing)) {
  2113. if (existing != null) {
  2114. // collision, multiple interfaces implement the same name, and
  2115. // we're not hidden by another method. remove both interfaces,
  2116. // but leave so future interfaces get removed
  2117. nonCollidingInterfaces.Remove(iface);
  2118. nonCollidingInterfaces.Remove(methodMap[iTarget.Name]);
  2119. break;
  2120. }
  2121. } else {
  2122. // no collisions so far...
  2123. methodMap[iTarget.Name] = iface;
  2124. }
  2125. }
  2126. }
  2127. }
  2128. }
  2129. if (hasExplicitIface) {
  2130. // add any non-colliding interfaces into the MRO
  2131. foreach (Type t in nonCollidingInterfaces) {
  2132. Debug.Assert(t.GetTypeInfo().IsInterface);
  2133. mro.Add(DynamicHelpers.GetPythonTypeFromType(t));
  2134. }
  2135. }
  2136. }
  2137. /// <summary>
  2138. /// Creates a __new__ method for the type. If the type defines interesting constructors
  2139. /// then the __new__ method will call that. Otherwise if it has only a single argless
  2140. /// </summary>
  2141. private void AddSystemConstructors() {
  2142. if (typeof(Delegate).IsAssignableFrom(_underlyingSystemType)) {
  2143. SetConstructor(
  2144. BuiltinFunction.MakeFunction(
  2145. _underlyingSystemType.Name,
  2146. new[] { typeof(DelegateOps).GetMethod("__new__") },
  2147. _underlyingSystemType
  2148. )
  2149. );
  2150. } else if (!_underlyingSystemType.IsAbstract()) {
  2151. BuiltinFunction reflectedCtors = GetConstructors();
  2152. if (reflectedCtors == null) {
  2153. return; // no ctors, no __new__
  2154. }
  2155. SetConstructor(reflectedCtors);
  2156. }
  2157. }
  2158. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  2159. private BuiltinFunction GetConstructors() {
  2160. Type type = _underlyingSystemType;
  2161. string name = Name;
  2162. return PythonTypeOps.GetConstructorFunction(type, name);
  2163. }
  2164. private void EnsureConstructor() {
  2165. if (_ctor == null) {
  2166. AddSystemConstructors();
  2167. if (_ctor == null) {
  2168. throw PythonOps.TypeError(_underlyingSystemType.FullName + " does not define any public constructors.");
  2169. }
  2170. }
  2171. }
  2172. private void EnsureInstanceCtor() {
  2173. if (_instanceCtor == null) {
  2174. _instanceCtor = InstanceCreator.Make(this);
  2175. }
  2176. }
  2177. #endregion
  2178. #region Private implementation details
  2179. private void UpdateVersion() {
  2180. foreach (WeakReference wr in SubTypes) {
  2181. if (wr.IsAlive) {
  2182. ((PythonType)wr.Target).UpdateVersion();
  2183. }
  2184. }
  2185. _lenSlot = null;
  2186. _version = GetNextVersion();
  2187. }
  2188. /// <summary>
  2189. /// This will return a unique integer for every version of every type in the system.
  2190. /// This means that DynamicSite code can generate a check to see if it has the correct
  2191. /// PythonType and version with a single integer compare.
  2192. ///
  2193. /// TODO - This method and related code should fail gracefully on overflow.
  2194. /// </summary>
  2195. private static int GetNextVersion() {
  2196. if (MasterVersion < 0) {
  2197. throw new InvalidOperationException(IronPython.Resources.TooManyVersions);
  2198. }
  2199. return Interlocked.Increment(ref MasterVersion);
  2200. }
  2201. private void EnsureDict() {
  2202. if (_dict == null) {
  2203. Interlocked.CompareExchange<Dictionary<string, PythonTypeSlot>>(
  2204. ref _dict,
  2205. new Dictionary<string, PythonTypeSlot>(StringComparer.Ordinal),
  2206. null);
  2207. }
  2208. }
  2209. /// <summary>
  2210. /// Internal helper function to add a subtype
  2211. /// </summary>
  2212. private void AddSubType(PythonType subtype) {
  2213. if (_subtypes == null) {
  2214. Interlocked.CompareExchange<List<WeakReference>>(ref _subtypes, new List<WeakReference>(), null);
  2215. }
  2216. lock (_subtypesLock) {
  2217. _subtypes.Add(new WeakReference(subtype));
  2218. }
  2219. }
  2220. private void RemoveSubType(PythonType subtype) {
  2221. int i = 0;
  2222. if (_subtypes != null) {
  2223. lock (_subtypesLock) {
  2224. while (i < _subtypes.Count) {
  2225. if (!_subtypes[i].IsAlive || _subtypes[i].Target == subtype) {
  2226. _subtypes.RemoveAt(i);
  2227. continue;
  2228. }
  2229. i++;
  2230. }
  2231. }
  2232. }
  2233. }
  2234. /// <summary>
  2235. /// Gets a list of weak references to all the subtypes of this class. May return null
  2236. /// if there are no subtypes of the class.
  2237. /// </summary>
  2238. private IList<WeakReference> SubTypes {
  2239. get {
  2240. if (_subtypes == null) return _emptyWeakRef;
  2241. lock (_subtypesLock) {
  2242. return _subtypes.ToArray();
  2243. }
  2244. }
  2245. }
  2246. [Flags]
  2247. private enum PythonTypeAttributes {
  2248. None = 0x00,
  2249. Immutable = 0x01,
  2250. SystemType = 0x02,
  2251. IsPythonType = 0x04,
  2252. WeakReferencable = 0x08,
  2253. HasDictionary = 0x10,
  2254. /// <summary>
  2255. /// The type has a ctor which does not accept PythonTypes. This is used
  2256. /// for user defined types which implement __clrtype__
  2257. /// </summary>
  2258. SystemCtor = 0x20
  2259. }
  2260. #endregion
  2261. #region IMembersList Members
  2262. IList<string> IMembersList.GetMemberNames() {
  2263. return PythonOps.GetStringMemberList(this);
  2264. }
  2265. IList<object> IPythonMembersList.GetMemberNames(CodeContext/*!*/ context) {
  2266. IList<object> res = GetMemberNames(context);
  2267. object[] arr = new object[res.Count];
  2268. res.CopyTo(arr, 0);
  2269. Array.Sort(arr);
  2270. return arr;
  2271. }
  2272. #endregion
  2273. #region IWeakReferenceable Members
  2274. WeakRefTracker IWeakReferenceable.GetWeakRef() {
  2275. return _weakrefTracker;
  2276. }
  2277. bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
  2278. if (!IsSystemType) {
  2279. return Interlocked.CompareExchange<WeakRefTracker>(ref _weakrefTracker, value, null) == null;
  2280. } else {
  2281. return false;
  2282. }
  2283. }
  2284. void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
  2285. if (!IsSystemType) {
  2286. _weakrefTracker = value;
  2287. } else {
  2288. // do nothing, system types are never collected
  2289. }
  2290. }
  2291. IWeakReferenceable IWeakReferenceableByProxy.GetWeakRefProxy(PythonContext context) {
  2292. return new WeakReferenceProxy(context, this);
  2293. }
  2294. class WeakReferenceProxy : IWeakReferenceable {
  2295. private readonly PythonContext context;
  2296. private readonly PythonType type;
  2297. internal WeakReferenceProxy(PythonContext context, PythonType type) {
  2298. this.type = type;
  2299. this.context = context;
  2300. }
  2301. public WeakRefTracker GetWeakRef() {
  2302. if(type.IsSystemType) {
  2303. return this.context.GetSystemPythonTypeWeakRef(type);
  2304. } else {
  2305. IWeakReferenceable weakref = (IWeakReferenceable)type;
  2306. return weakref.GetWeakRef();
  2307. }
  2308. }
  2309. public void SetFinalizer(WeakRefTracker value) {
  2310. if(type.IsSystemType) {
  2311. this.context.SetSystemPythonTypeFinalizer(type, value);
  2312. } else {
  2313. IWeakReferenceable weakref = (IWeakReferenceable)type;
  2314. weakref.SetFinalizer(value);
  2315. }
  2316. }
  2317. public bool SetWeakRef(WeakRefTracker value) {
  2318. if(type.IsSystemType) {
  2319. return this.context.SetSystemPythonTypeWeakRef(type, value);
  2320. } else {
  2321. IWeakReferenceable weakref = (IWeakReferenceable)type;
  2322. return weakref.SetWeakRef(value);
  2323. }
  2324. }
  2325. }
  2326. #endregion
  2327. #region IDynamicMetaObjectProvider Members
  2328. [PythonHidden]
  2329. public DynamicMetaObject/*!*/ GetMetaObject(Expression/*!*/ parameter) {
  2330. return new Binding.MetaPythonType(parameter, BindingRestrictions.Empty, this);
  2331. }
  2332. #endregion
  2333. /// <summary>
  2334. /// Returns a CLR WeakReference object to this PythonType that can be shared
  2335. /// between anyone who needs a weak reference to the type.
  2336. /// </summary>
  2337. internal WeakReference/*!*/ GetSharedWeakReference() {
  2338. if (_weakRef == null) {
  2339. _weakRef = new WeakReference(this);
  2340. }
  2341. return _weakRef;
  2342. }
  2343. #region IFastSettable Members
  2344. T IFastSettable.MakeSetBinding<T>(CallSite<T> site, PythonSetMemberBinder binder) {
  2345. PythonTypeSlot pts;
  2346. // if our meta class has a custom __setattr__ then we don't handle it in the
  2347. // fast path. Usually this is handled by a user defined type (UserTypeOps) IDynamicMetaObjectProvider
  2348. // class. But w/ _ctypes support we can have a built-in meta class which doesn't
  2349. // get this treatment.
  2350. if (!IsSystemType && !TryGetCustomSetAttr(Context.SharedContext, out pts)) {
  2351. CodeContext context = PythonContext.GetPythonContext(binder).SharedContext;
  2352. string name = binder.Name;
  2353. // optimized versions for possible literals that can show up in code.
  2354. Type setType = typeof(T);
  2355. if (setType == typeof(Func<CallSite, object, object, object>)) {
  2356. return (T)(object)MakeFastSet<object>(context, name);
  2357. } else if (setType == typeof(Func<CallSite, object, string, object>)) {
  2358. return (T)(object)MakeFastSet<string>(context, name);
  2359. } else if (setType == typeof(Func<CallSite, object, int, object>)) {
  2360. return (T)(object)MakeFastSet<int>(context, name);
  2361. } else if (setType == typeof(Func<CallSite, object, double, object>)) {
  2362. return (T)(object)MakeFastSet<double>(context, name);
  2363. } else if (setType == typeof(Func<CallSite, object, List, object>)) {
  2364. return (T)(object)MakeFastSet<List>(context, name);
  2365. } else if (setType == typeof(Func<CallSite, object, PythonTuple, object>)) {
  2366. return (T)(object)MakeFastSet<PythonTuple>(context, name);
  2367. } else if (setType == typeof(Func<CallSite, object, PythonDictionary, object>)) {
  2368. return (T)(object)MakeFastSet<PythonDictionary>(context, name);
  2369. } else if (setType == typeof(Func<CallSite, object, SetCollection, object>)) {
  2370. return (T)(object)MakeFastSet<SetCollection>(context, name);
  2371. } else if (setType == typeof(Func<CallSite, object, FrozenSetCollection, object>)) {
  2372. return (T)(object)MakeFastSet<FrozenSetCollection>(context, name);
  2373. }
  2374. }
  2375. return null;
  2376. }
  2377. private static Func<CallSite, object, T, object> MakeFastSet<T>(CodeContext/*!*/ context, string name) {
  2378. return new Setter<T>(context, name).Target;
  2379. }
  2380. class Setter<T> : FastSetBase<T> {
  2381. private readonly CodeContext/*!*/ _context;
  2382. private readonly string _name;
  2383. public Setter(CodeContext/*!*/ context, string name)
  2384. : base(-1) {
  2385. _context = context;
  2386. _name = name;
  2387. }
  2388. public object Target(CallSite site, object self, T value) {
  2389. PythonType type = self as PythonType;
  2390. if (type != null && !type.IsSystemType) {
  2391. type.SetCustomMember(_context, _name, value);
  2392. return value;
  2393. }
  2394. return Update(site, self, value);
  2395. }
  2396. }
  2397. #endregion
  2398. internal class DebugProxy {
  2399. private readonly PythonType _type;
  2400. public DebugProxy(PythonType type) {
  2401. _type = type;
  2402. }
  2403. public PythonType[] __bases__ {
  2404. get {
  2405. return ArrayUtils.ToArray(_type.BaseTypes);
  2406. }
  2407. }
  2408. [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
  2409. public List<ObjectDebugView> Members {
  2410. get {
  2411. var res = new List<ObjectDebugView>();
  2412. if (_type._dict != null) {
  2413. foreach (var v in _type._dict) {
  2414. if (v.Value is PythonTypeUserDescriptorSlot) {
  2415. res.Add(new ObjectDebugView(v.Key, ((PythonTypeUserDescriptorSlot)v.Value).Value));
  2416. } else {
  2417. res.Add(new ObjectDebugView(v.Key, v.Value));
  2418. }
  2419. }
  2420. }
  2421. return res;
  2422. }
  2423. }
  2424. }
  2425. }
  2426. enum OptimizedGetKind {
  2427. None,
  2428. SlotDict,
  2429. SlotOnly,
  2430. PropertySlot,
  2431. UserSlotDict,
  2432. UserSlotOnly,
  2433. }
  2434. class UserGetBase : FastGetBase {
  2435. internal readonly int _version;
  2436. public UserGetBase(PythonGetMemberBinder binder, int version) {
  2437. _version = version;
  2438. }
  2439. public override bool IsValid(PythonType type) {
  2440. return _version == type.Version;
  2441. }
  2442. }
  2443. class ChainedUserGet : UserGetBase {
  2444. public ChainedUserGet(PythonGetMemberBinder binder, int version, Func<CallSite, object, CodeContext, object> func)
  2445. : base(binder, version) {
  2446. _func = func;
  2447. }
  2448. internal override bool ShouldCache {
  2449. get {
  2450. return false;
  2451. }
  2452. }
  2453. }
  2454. class GetAttributeDelegates : UserGetBase {
  2455. private readonly string _name;
  2456. private readonly PythonTypeSlot _getAttributeSlot;
  2457. private readonly PythonTypeSlot _getAttrSlot;
  2458. private readonly SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, string, object>>>/*!*/ _storage;
  2459. private readonly bool _isNoThrow;
  2460. public GetAttributeDelegates(PythonGetMemberBinder/*!*/ binder, string/*!*/ name, int version, PythonTypeSlot/*!*/ getAttributeSlot, PythonTypeSlot/*!*/ getAttrSlot)
  2461. : base(binder, version) {
  2462. Assert.NotNull(binder, getAttributeSlot);
  2463. _storage = new SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, string, object>>>();
  2464. _getAttributeSlot = getAttributeSlot;
  2465. _getAttrSlot = getAttrSlot;
  2466. _name = name;
  2467. _func = GetAttribute;
  2468. _isNoThrow = binder.IsNoThrow;
  2469. }
  2470. public object GetAttribute(CallSite site, object self, CodeContext context) {
  2471. IPythonObject ipo = self as IPythonObject;
  2472. if (ipo != null && ipo.PythonType.Version == _version) {
  2473. if (_isNoThrow) {
  2474. return UserTypeOps.GetAttributeNoThrow(context, self, _name, _getAttributeSlot, _getAttrSlot, _storage);
  2475. }
  2476. return UserTypeOps.GetAttribute(context, self, _name, _getAttributeSlot, _getAttrSlot, _storage);
  2477. }
  2478. return Update(site, self, context);
  2479. }
  2480. }
  2481. class GetMemberDelegates : UserGetBase {
  2482. private readonly string _name;
  2483. private readonly bool _isNoThrow;
  2484. private readonly PythonTypeSlot _slot, _getattrSlot;
  2485. private readonly SlotGetValue _slotFunc;
  2486. private readonly Func<CallSite, object, CodeContext, object> _fallback;
  2487. private readonly int _dictVersion, _dictIndex;
  2488. private readonly ExtensionMethodSet _extMethods;
  2489. public GetMemberDelegates(OptimizedGetKind getKind, PythonType type, PythonGetMemberBinder binder, string name, int version, PythonTypeSlot slot, PythonTypeSlot getattrSlot, SlotGetValue slotFunc, Func<CallSite, object, CodeContext, object> fallback, ExtensionMethodSet extMethods)
  2490. : base(binder, version) {
  2491. _slot = slot;
  2492. _name = name;
  2493. _getattrSlot = getattrSlot;
  2494. _slotFunc = slotFunc;
  2495. _fallback = fallback;
  2496. _isNoThrow = binder.IsNoThrow;
  2497. _extMethods = extMethods;
  2498. var optNames = type.GetOptimizedInstanceNames();
  2499. switch (getKind) {
  2500. case OptimizedGetKind.SlotDict:
  2501. if (optNames != null) {
  2502. _dictIndex = optNames.IndexOf(name);
  2503. }
  2504. if (optNames != null && _dictIndex != -1) {
  2505. _func = SlotDictOptimized;
  2506. _dictVersion = type.GetOptimizedInstanceVersion();
  2507. } else {
  2508. _func = SlotDict;
  2509. }
  2510. break;
  2511. case OptimizedGetKind.SlotOnly: _func = SlotOnly; break;
  2512. case OptimizedGetKind.PropertySlot: _func = UserSlot; break;
  2513. case OptimizedGetKind.UserSlotDict:
  2514. if (optNames != null) {
  2515. _dictIndex = optNames.IndexOf(name);
  2516. }
  2517. if (optNames != null && _dictIndex != -1) {
  2518. _dictVersion = type.GetOptimizedInstanceVersion();
  2519. if (_getattrSlot != null) {
  2520. _func = UserSlotDictGetAttrOptimized;
  2521. } else {
  2522. _func = UserSlotDictOptimized;
  2523. }
  2524. } else if (_getattrSlot != null) {
  2525. _func = UserSlotDictGetAttr;
  2526. } else {
  2527. _func = UserSlotDict;
  2528. }
  2529. break;
  2530. case OptimizedGetKind.UserSlotOnly:
  2531. if (_getattrSlot != null) {
  2532. _func = UserSlotOnlyGetAttr;
  2533. } else {
  2534. _func = UserSlotOnly;
  2535. }
  2536. break;
  2537. default: throw new InvalidOperationException();
  2538. }
  2539. }
  2540. public object SlotDict(CallSite site, object self, CodeContext context) {
  2541. IPythonObject ipo = self as IPythonObject;
  2542. if (ipo != null && ipo.PythonType.Version == _version && ShouldUseNonOptimizedSite && (object)context.ModuleContext.ExtensionMethods == (object)_extMethods) {
  2543. _hitCount++;
  2544. object res;
  2545. if (ipo.Dict != null && ipo.Dict.TryGetValue(_name, out res)) {
  2546. return res;
  2547. }
  2548. if (_slot != null && _slot.TryGetValue(context, self, ipo.PythonType, out res)) {
  2549. return res;
  2550. }
  2551. if (_getattrSlot != null && _getattrSlot.TryGetValue(context, self, ipo.PythonType, out res)) {
  2552. return GetAttr(context, res);
  2553. }
  2554. return TypeError(site, ipo, context);
  2555. }
  2556. return Update(site, self, context);
  2557. }
  2558. public object SlotDictOptimized(CallSite site, object self, CodeContext context) {
  2559. IPythonObject ipo = self as IPythonObject;
  2560. if (ipo != null && ipo.PythonType.Version == _version && ShouldUseNonOptimizedSite && (object)context.ModuleContext.ExtensionMethods == (object)_extMethods) {
  2561. _hitCount++;
  2562. object res;
  2563. PythonDictionary dict = ipo.Dict;
  2564. if (UserTypeOps.TryGetDictionaryValue(dict, _name, _dictVersion, _dictIndex, out res)) {
  2565. return res;
  2566. }
  2567. if (_slot != null && _slot.TryGetValue(context, self, ipo.PythonType, out res)) {
  2568. return res;
  2569. }
  2570. if (_getattrSlot != null && _getattrSlot.TryGetValue(context, self, ipo.PythonType, out res)) {
  2571. return GetAttr(context, res);
  2572. }
  2573. return TypeError(site, ipo, context);
  2574. }
  2575. return Update(site, self, context);
  2576. }
  2577. public object SlotOnly(CallSite site, object self, CodeContext context) {
  2578. IPythonObject ipo = self as IPythonObject;
  2579. if (ipo != null && ipo.PythonType.Version == _version && ShouldUseNonOptimizedSite && (object)context.ModuleContext.ExtensionMethods == (object)_extMethods) {
  2580. _hitCount++;
  2581. object res;
  2582. if (_slot != null && _slot.TryGetValue(context, self, ipo.PythonType, out res)) {
  2583. return res;
  2584. }
  2585. if (_getattrSlot != null && _getattrSlot.TryGetValue(context, self, ipo.PythonType, out res)) {
  2586. return GetAttr(context, res);
  2587. }
  2588. return TypeError(site, ipo, context);
  2589. }
  2590. return Update(site, self, context);
  2591. }
  2592. public object UserSlotDict(CallSite site, object self, CodeContext context) {
  2593. IPythonObject ipo = self as IPythonObject;
  2594. if (ipo != null && ipo.PythonType.Version == _version && (object)context.ModuleContext.ExtensionMethods == (object)_extMethods) {
  2595. object res;
  2596. if (ipo.Dict != null && ipo.Dict.TryGetValue(_name, out res)) {
  2597. return res;
  2598. }
  2599. return ((PythonTypeUserDescriptorSlot)_slot).GetValue(context, self, ipo.PythonType);
  2600. }
  2601. return Update(site, self, context);
  2602. }
  2603. public object UserSlotDictOptimized(CallSite site, object self, CodeContext context) {
  2604. IPythonObject ipo = self as IPythonObject;
  2605. if (ipo != null && ipo.PythonType.Version == _version && (object)context.ModuleContext.ExtensionMethods == (object)_extMethods) {
  2606. object res;
  2607. PythonDictionary dict = ipo.Dict;
  2608. if (UserTypeOps.TryGetDictionaryValue(dict, _name, _dictVersion, _dictIndex, out res)) {
  2609. return res;
  2610. }
  2611. return ((PythonTypeUserDescriptorSlot)_slot).GetValue(context, self, ipo.PythonType);
  2612. }
  2613. return Update(site, self, context);
  2614. }
  2615. public object UserSlotOnly(CallSite site, object self, CodeContext context) {
  2616. IPythonObject ipo = self as IPythonObject;
  2617. if (ipo != null && ipo.PythonType.Version == _version && (object)context.ModuleContext.ExtensionMethods == (object)_extMethods) {
  2618. return ((PythonTypeUserDescriptorSlot)_slot).GetValue(context, self, ipo.PythonType);
  2619. }
  2620. return Update(site, self, context);
  2621. }
  2622. public object UserSlotDictGetAttr(CallSite site, object self, CodeContext context) {
  2623. IPythonObject ipo = self as IPythonObject;
  2624. if (ipo != null && ipo.PythonType.Version == _version && (object)context.ModuleContext.ExtensionMethods == (object)_extMethods) {
  2625. object res;
  2626. if (ipo.Dict != null && ipo.Dict.TryGetValue(_name, out res)) {
  2627. return res;
  2628. }
  2629. try {
  2630. return ((PythonTypeUserDescriptorSlot)_slot).GetValue(context, self, ipo.PythonType);
  2631. } catch (MissingMemberException) {
  2632. }
  2633. if (_getattrSlot.TryGetValue(context, self, ipo.PythonType, out res)) {
  2634. return GetAttr(context, res);
  2635. }
  2636. return TypeError(site, ipo, context);
  2637. }
  2638. return Update(site, self, context);
  2639. }
  2640. public object UserSlotDictGetAttrOptimized(CallSite site, object self, CodeContext context) {
  2641. IPythonObject ipo = self as IPythonObject;
  2642. if (ipo != null && ipo.PythonType.Version == _version && (object)context.ModuleContext.ExtensionMethods == (object)_extMethods) {
  2643. object res;
  2644. PythonDictionary dict = ipo.Dict;
  2645. if (UserTypeOps.TryGetDictionaryValue(dict, _name, _dictVersion, _dictIndex, out res)) {
  2646. return res;
  2647. }
  2648. try {
  2649. return ((PythonTypeUserDescriptorSlot)_slot).GetValue(context, self, ipo.PythonType);
  2650. } catch (MissingMemberException) {
  2651. }
  2652. if (_getattrSlot.TryGetValue(context, self, ipo.PythonType, out res)) {
  2653. return GetAttr(context, res);
  2654. }
  2655. return TypeError(site, ipo, context);
  2656. }
  2657. return Update(site, self, context);
  2658. }
  2659. public object UserSlotOnlyGetAttr(CallSite site, object self, CodeContext context) {
  2660. IPythonObject ipo = self as IPythonObject;
  2661. if (ipo != null && ipo.PythonType.Version == _version && (object)context.ModuleContext.ExtensionMethods == (object)_extMethods) {
  2662. try {
  2663. return ((PythonTypeUserDescriptorSlot)_slot).GetValue(context, self, ipo.PythonType);
  2664. } catch (MissingMemberException) {
  2665. }
  2666. object res;
  2667. if (_getattrSlot.TryGetValue(context, self, ipo.PythonType, out res)) {
  2668. return GetAttr(context, res);
  2669. }
  2670. return TypeError(site, ipo, context);
  2671. }
  2672. return Update(site, self, context);
  2673. }
  2674. public object UserSlot(CallSite site, object self, CodeContext context) {
  2675. IPythonObject ipo = self as IPythonObject;
  2676. if (ipo != null && ipo.PythonType.Version == _version && ShouldUseNonOptimizedSite && (object)context.ModuleContext.ExtensionMethods == (object)_extMethods) {
  2677. object res = _slotFunc(self);
  2678. if (res != Uninitialized.Instance) {
  2679. return res;
  2680. }
  2681. if (_getattrSlot != null && _getattrSlot.TryGetValue(context, self, ipo.PythonType, out res)) {
  2682. return GetAttr(context, res);
  2683. }
  2684. return TypeError(site, ipo, context);
  2685. }
  2686. return Update(site, self, context);
  2687. }
  2688. private object GetAttr(CodeContext context, object res) {
  2689. if (_isNoThrow) {
  2690. try {
  2691. return PythonContext.GetContext(context).Call(context, res, _name);
  2692. } catch (MissingMemberException) {
  2693. return OperationFailed.Value;
  2694. }
  2695. } else {
  2696. return PythonContext.GetContext(context).Call(context, res, _name);
  2697. }
  2698. }
  2699. private object TypeError(CallSite site, IPythonObject ipo, CodeContext context) {
  2700. return _fallback(site, ipo, context);
  2701. }
  2702. }
  2703. enum OptimizedSetKind {
  2704. None,
  2705. SetAttr,
  2706. UserSlot,
  2707. SetDict,
  2708. Error
  2709. }
  2710. class SetMemberDelegates<TValue> : FastSetBase<TValue> {
  2711. private readonly string _name;
  2712. private readonly PythonTypeSlot _slot;
  2713. private readonly SlotSetValue _slotFunc;
  2714. private readonly CodeContext _context;
  2715. private readonly int _index, _keysVersion;
  2716. public SetMemberDelegates(CodeContext context, PythonType type, OptimizedSetKind kind, string name, int version, PythonTypeSlot slot, SlotSetValue slotFunc)
  2717. : base(version) {
  2718. _slot = slot;
  2719. _name = name;
  2720. _slotFunc = slotFunc;
  2721. _context = context;
  2722. switch (kind) {
  2723. case OptimizedSetKind.SetAttr: _func = new Func<CallSite, object, TValue, object>(SetAttr); break;
  2724. case OptimizedSetKind.UserSlot: _func = new Func<CallSite, object, TValue, object>(UserSlot); break;
  2725. case OptimizedSetKind.SetDict:
  2726. var optNames = type.GetOptimizedInstanceNames();
  2727. int index;
  2728. if (optNames != null && (index = optNames.IndexOf(name)) != -1) {
  2729. _index = index;
  2730. _keysVersion = type.GetOptimizedInstanceVersion();
  2731. _func = new Func<CallSite, object, TValue, object>(SetDictOptimized);
  2732. } else {
  2733. _func = new Func<CallSite, object, TValue, object>(SetDict);
  2734. }
  2735. break;
  2736. case OptimizedSetKind.Error: _func = new Func<CallSite, object, TValue, object>(Error); break;
  2737. }
  2738. }
  2739. public object SetAttr(CallSite site, object self, TValue value) {
  2740. IPythonObject ipo = self as IPythonObject;
  2741. if (ipo != null && ipo.PythonType.Version == _version && ShouldUseNonOptimizedSite) {
  2742. _hitCount++;
  2743. object res;
  2744. if (_slot.TryGetValue(_context, self, ipo.PythonType, out res)) {
  2745. return PythonOps.CallWithContext(_context, res, _name, value);
  2746. }
  2747. return TypeError(ipo);
  2748. }
  2749. return Update(site, self, value);
  2750. }
  2751. public object SetDictOptimized(CallSite site, object self, TValue value) {
  2752. IPythonObject ipo = self as IPythonObject;
  2753. if (ipo != null && ipo.PythonType.Version == _version && ShouldUseNonOptimizedSite) {
  2754. _hitCount++;
  2755. return UserTypeOps.SetDictionaryValueOptimized(ipo, _name, value, _keysVersion, _index);
  2756. }
  2757. return Update(site, self, value);
  2758. }
  2759. public object SetDict(CallSite site, object self, TValue value) {
  2760. IPythonObject ipo = self as IPythonObject;
  2761. if (ipo != null && ipo.PythonType.Version == _version && ShouldUseNonOptimizedSite) {
  2762. _hitCount++;
  2763. UserTypeOps.SetDictionaryValue(ipo, _name, value);
  2764. return null;
  2765. }
  2766. return Update(site, self, value);
  2767. }
  2768. public object Error(CallSite site, object self, TValue value) {
  2769. IPythonObject ipo = self as IPythonObject;
  2770. if (ipo != null && ipo.PythonType.Version == _version) {
  2771. return TypeError(ipo);
  2772. }
  2773. return Update(site, self, value);
  2774. }
  2775. public object UserSlot(CallSite site, object self, TValue value) {
  2776. IPythonObject ipo = self as IPythonObject;
  2777. if (ipo != null && ipo.PythonType.Version == _version && ShouldUseNonOptimizedSite) {
  2778. _hitCount++;
  2779. _slotFunc(self, value);
  2780. return null;
  2781. }
  2782. return Update(site, self, value);
  2783. }
  2784. private object TypeError(IPythonObject ipo) {
  2785. throw PythonOps.AttributeErrorForMissingAttribute(ipo.PythonType.Name, _name);
  2786. }
  2787. }
  2788. class SetMemberKey : IEquatable<SetMemberKey> {
  2789. public readonly Type Type;
  2790. public readonly string Name;
  2791. public SetMemberKey(Type type, string name) {
  2792. Type = type;
  2793. Name = name;
  2794. }
  2795. #region IEquatable<SetMemberKey> Members
  2796. public bool Equals(SetMemberKey other) {
  2797. return Type == other.Type && Name == other.Name;
  2798. }
  2799. #endregion
  2800. public override bool Equals(object obj) {
  2801. SetMemberKey other = obj as SetMemberKey;
  2802. if (other == null) {
  2803. return false;
  2804. }
  2805. return Equals(other);
  2806. }
  2807. public override int GetHashCode() {
  2808. return Type.GetHashCode() ^ Name.GetHashCode();
  2809. }
  2810. }
  2811. abstract class TypeGetBase : FastGetBase {
  2812. private readonly FastGetDelegate[] _delegates;
  2813. public TypeGetBase(PythonGetMemberBinder binder, FastGetDelegate[] delegates) {
  2814. _delegates = delegates;
  2815. }
  2816. protected object RunDelegates(object self, CodeContext context) {
  2817. _hitCount++;
  2818. for (int i = 0; i < _delegates.Length; i++) {
  2819. object res;
  2820. if (_delegates[i](context, self, out res)) {
  2821. return res;
  2822. }
  2823. }
  2824. // last delegate should always throw or succeed, this should be unreachable
  2825. throw new InvalidOperationException();
  2826. }
  2827. protected object RunDelegatesNoOptimize(object self, CodeContext context) {
  2828. for (int i = 0; i < _delegates.Length; i++) {
  2829. object res;
  2830. if (_delegates[i](context, self, out res)) {
  2831. return res;
  2832. }
  2833. }
  2834. // last delegate should always throw or succeed, this should be unreachable
  2835. throw new InvalidOperationException();
  2836. }
  2837. }
  2838. delegate bool FastGetDelegate(CodeContext context, object self, out object result);
  2839. class TypeGet : TypeGetBase {
  2840. private int _version;
  2841. public TypeGet(PythonGetMemberBinder binder, FastGetDelegate[] delegates, int version, bool isMeta, bool canOptimize)
  2842. : base(binder, delegates) {
  2843. _version = version;
  2844. if (canOptimize) {
  2845. if (isMeta) {
  2846. _func = MetaOnlyTargetOptimizing;
  2847. } else {
  2848. _func = TargetOptimizing;
  2849. }
  2850. } else {
  2851. if (isMeta) {
  2852. _func = MetaOnlyTarget;
  2853. } else {
  2854. _func = Target;
  2855. }
  2856. }
  2857. }
  2858. public object Target(CallSite site, object self, CodeContext context) {
  2859. PythonType pt = self as PythonType;
  2860. if (pt != null && pt.Version == _version) {
  2861. return RunDelegatesNoOptimize(self, context);
  2862. }
  2863. return Update(site, self, context);
  2864. }
  2865. public object MetaOnlyTarget(CallSite site, object self, CodeContext context) {
  2866. PythonType pt = self as PythonType;
  2867. if (pt != null && PythonOps.CheckTypeVersion(pt, _version)) {
  2868. return RunDelegatesNoOptimize(self, context);
  2869. }
  2870. return Update(site, self, context);
  2871. }
  2872. public object TargetOptimizing(CallSite site, object self, CodeContext context) {
  2873. PythonType pt = self as PythonType;
  2874. if (pt != null && pt.Version == _version && ShouldUseNonOptimizedSite) {
  2875. return RunDelegates(self, context);
  2876. }
  2877. return Update(site, self, context);
  2878. }
  2879. public object MetaOnlyTargetOptimizing(CallSite site, object self, CodeContext context) {
  2880. PythonType pt = self as PythonType;
  2881. if (pt != null && PythonOps.CheckTypeVersion(pt, _version) && ShouldUseNonOptimizedSite) {
  2882. return RunDelegates(self, context);
  2883. }
  2884. return Update(site, self, context);
  2885. }
  2886. public override bool IsValid(PythonType type) {
  2887. if (_func == MetaOnlyTarget || _func == MetaOnlyTargetOptimizing) {
  2888. return PythonOps.CheckTypeVersion(type, _version);
  2889. }
  2890. return type.Version == _version;
  2891. }
  2892. }
  2893. class SystemTypeGet : TypeGetBase {
  2894. private readonly PythonType _self;
  2895. public SystemTypeGet(PythonGetMemberBinder binder, FastGetDelegate[] delegates, PythonType type, bool isMeta, bool optimizing)
  2896. : base(binder, delegates) {
  2897. _self = type;
  2898. if (optimizing) {
  2899. if (isMeta) {
  2900. _func = MetaOnlyTargetOptimizing;
  2901. } else {
  2902. _func = TargetOptimizing;
  2903. }
  2904. } else {
  2905. if (isMeta) {
  2906. _func = MetaOnlyTarget;
  2907. } else {
  2908. _func = Target;
  2909. }
  2910. }
  2911. }
  2912. public object Target(CallSite site, object self, CodeContext context) {
  2913. if (self == _self) {
  2914. return RunDelegatesNoOptimize(self, context);
  2915. }
  2916. return Update(site, self, context);
  2917. }
  2918. public object MetaOnlyTarget(CallSite site, object self, CodeContext context) {
  2919. if (self is PythonType) {
  2920. return RunDelegatesNoOptimize(self, context);
  2921. }
  2922. return Update(site, self, context);
  2923. }
  2924. public object TargetOptimizing(CallSite site, object self, CodeContext context) {
  2925. if (self == _self && ShouldUseNonOptimizedSite) {
  2926. return RunDelegates(self, context);
  2927. }
  2928. return Update(site, self, context);
  2929. }
  2930. public object MetaOnlyTargetOptimizing(CallSite site, object self, CodeContext context) {
  2931. if (self is PythonType && ShouldUseNonOptimizedSite) {
  2932. return RunDelegates(self, context);
  2933. }
  2934. return Update(site, self, context);
  2935. }
  2936. public override bool IsValid(PythonType type) {
  2937. if (_func == MetaOnlyTarget || _func == MetaOnlyTargetOptimizing) {
  2938. return true;
  2939. }
  2940. return type == _self;
  2941. }
  2942. }
  2943. internal abstract class CachedGetKey : IEquatable<CachedGetKey> {
  2944. public readonly string Name;
  2945. public CachedGetKey(string name) {
  2946. Name = name;
  2947. }
  2948. public static CachedGetKey Make(string name, ExtensionMethodSet set) {
  2949. if (set.Id != ExtensionMethodSet.OutOfIds) {
  2950. return new CachedGetIdIntExtensionMethod(name, set.Id);
  2951. }
  2952. return new CachedGetIdWeakRefExtensionMethod(name, new WeakReference(set));
  2953. }
  2954. public override bool Equals(object obj) {
  2955. CachedGetKey cachedKey = obj as CachedGetKey;
  2956. if (cachedKey == null) {
  2957. return false;
  2958. }
  2959. return this.Equals(cachedKey);
  2960. }
  2961. public override int GetHashCode() {
  2962. return Name.GetHashCode();
  2963. }
  2964. public abstract bool Equals(CachedGetKey key);
  2965. }
  2966. internal sealed class CachedGetIdIntExtensionMethod : CachedGetKey {
  2967. private readonly int _id;
  2968. public CachedGetIdIntExtensionMethod(string name, int id)
  2969. : base(name) {
  2970. _id = id;
  2971. }
  2972. public override int GetHashCode() {
  2973. return Name.GetHashCode() ^ _id;
  2974. }
  2975. #region IEquatable<CachedGetKey> Members
  2976. public override bool Equals(CachedGetKey other) {
  2977. var obj = other as CachedGetIdIntExtensionMethod;
  2978. if (obj == null) {
  2979. return false;
  2980. }
  2981. return obj._id == _id && obj.Name == Name;
  2982. }
  2983. #endregion
  2984. }
  2985. internal sealed class CachedGetIdWeakRefExtensionMethod : CachedGetKey {
  2986. private readonly WeakReference _extMethodSet;
  2987. public CachedGetIdWeakRefExtensionMethod(string name, WeakReference weakReference)
  2988. : base(name) {
  2989. _extMethodSet = weakReference;
  2990. }
  2991. #region IEquatable<CachedGetKey> Members
  2992. public override bool Equals(CachedGetKey other) {
  2993. var obj = other as CachedGetIdWeakRefExtensionMethod;
  2994. if (obj == null) {
  2995. return false;
  2996. }
  2997. return obj._extMethodSet.Target == _extMethodSet.Target &&
  2998. obj.Name == Name;
  2999. }
  3000. #endregion
  3001. }
  3002. }