PageRenderTime 86ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/Languages/IronPython/IronPython/Runtime/Types/NewTypeMaker.cs

http://github.com/IronLanguages/main
C# | 1845 lines | 1334 code | 305 blank | 206 comment | 285 complexity | c9beb103b9e51a1da237a8512b974654 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  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. using System;
  16. using System.Collections.Generic;
  17. using System.ComponentModel;
  18. using System.Diagnostics;
  19. using System.Linq;
  20. using System.Reflection;
  21. using System.Reflection.Emit;
  22. using System.Runtime.CompilerServices;
  23. using System.Dynamic;
  24. using System.Text;
  25. using Microsoft.Scripting;
  26. using Microsoft.Scripting.Actions;
  27. using Microsoft.Scripting.Generation;
  28. using Microsoft.Scripting.Runtime;
  29. using Microsoft.Scripting.Utils;
  30. using IronPython.Runtime.Binding;
  31. using IronPython.Runtime.Operations;
  32. namespace IronPython.Runtime.Types {
  33. /// <summary>
  34. /// Python class hierarchy is represented using the __class__ field in the object. It does not
  35. /// use the CLI type system for pure Python types. However, Python types which inherit from a
  36. /// CLI type, or from a builtin Python type which is implemented in the engine by a CLI type,
  37. /// do have to use the CLI type system to interoperate with the CLI world. This means that
  38. /// objects of different Python types, but with the same CLI base type, can use the same CLI type -
  39. /// they will just have different values for the __class__ field.
  40. ///
  41. /// The easiest way to inspect the functionality implemented by NewTypeMaker is to persist the
  42. /// generated IL using "ipy.exe -X:SaveAssemblies", and then inspect the
  43. /// persisted IL using ildasm.
  44. /// </summary>
  45. sealed class NewTypeMaker {
  46. private Type _baseType;
  47. private IList<Type> _interfaceTypes;
  48. #if FEATURE_REFEMIT
  49. private TypeBuilder _tg;
  50. private FieldInfo _typeField;
  51. private FieldInfo _dictField;
  52. private FieldInfo _slotsField;
  53. private FieldInfo _explicitMO;
  54. private ILGen _cctor;
  55. private int _site;
  56. [MultiRuntimeAware]
  57. private static int _typeCount;
  58. #endif
  59. public const string VtableNamesField = "#VTableNames#";
  60. public const string TypePrefix = "IronPython.NewTypes.";
  61. public const string BaseMethodPrefix = "#base#";
  62. public const string FieldGetterPrefix = "#field_get#", FieldSetterPrefix = "#field_set#";
  63. #if FEATURE_REFEMIT
  64. public const string ClassFieldName = ".class", DictFieldName = ".dict", SlotsAndWeakRefFieldName = ".slots_and_weakref";
  65. #else
  66. public const string ClassFieldName = "_class", DictFieldName = "_dict", SlotsAndWeakRefFieldName = "_slots_and_weakref";
  67. #endif
  68. private const string _constructorTypeName = "PythonCachedTypeConstructor";
  69. private const string _constructorMethodName = "GetTypeInfo";
  70. [MultiRuntimeAware]
  71. internal static readonly Publisher<NewTypeInfo, Type> _newTypes = new Publisher<NewTypeInfo, Type>();
  72. [MultiRuntimeAware]
  73. private static readonly Dictionary<Type, Dictionary<string, List<MethodInfo>>> _overriddenMethods = new Dictionary<Type, Dictionary<string, List<MethodInfo>>>();
  74. [MultiRuntimeAware]
  75. private static readonly Dictionary<Type, Dictionary<string, List<ExtensionPropertyTracker>>> _overriddenProperties = new Dictionary<Type, Dictionary<string, List<ExtensionPropertyTracker>>>();
  76. private NewTypeMaker(NewTypeInfo typeInfo) {
  77. _baseType = typeInfo.BaseType;
  78. _interfaceTypes = typeInfo.InterfaceTypes;
  79. }
  80. #region Public API
  81. #if FEATURE_REFEMIT
  82. public static Type/*!*/ GetNewType(string/*!*/ typeName, PythonTuple/*!*/ bases) {
  83. Assert.NotNull(typeName, bases);
  84. NewTypeInfo typeInfo = NewTypeInfo.GetTypeInfo(typeName, bases);
  85. if (typeInfo.BaseType.IsValueType()) {
  86. throw PythonOps.TypeError("cannot derive from {0} because it is a value type", typeInfo.BaseType.FullName);
  87. } else if (typeInfo.BaseType.IsSealed()) {
  88. throw PythonOps.TypeError("cannot derive from {0} because it is sealed", typeInfo.BaseType.FullName);
  89. }
  90. Type ret = _newTypes.GetOrCreateValue(typeInfo,
  91. () => {
  92. if (typeInfo.InterfaceTypes.Count == 0) {
  93. // types that the have DynamicBaseType attribute can be used as NewType's directly, no
  94. // need to create a new type unless we're adding interfaces
  95. var attrs = typeInfo.BaseType.GetTypeInfo().GetCustomAttributes(typeof(DynamicBaseTypeAttribute), false);
  96. if (attrs.Any()) {
  97. return typeInfo.BaseType;
  98. }
  99. }
  100. // creation code
  101. return new NewTypeMaker(typeInfo).CreateNewType();
  102. });
  103. return ret;
  104. }
  105. public static void SaveNewTypes(string assemblyName, IList<PythonTuple> types) {
  106. Assert.NotNull(assemblyName, types);
  107. AssemblyGen ag = new AssemblyGen(new AssemblyName(assemblyName), ".", ".dll", false);
  108. TypeBuilder tb = ag.DefinePublicType(_constructorTypeName, typeof(object), true);
  109. tb.SetCustomAttribute(new CustomAttributeBuilder(typeof(PythonCachedTypeInfoAttribute).GetConstructor(ReflectionUtils.EmptyTypes), new object[0]));
  110. MethodBuilder mb = tb.DefineMethod(_constructorMethodName, MethodAttributes.Public | MethodAttributes.Static, typeof(CachedNewTypeInfo[]), ReflectionUtils.EmptyTypes);
  111. ILGenerator ilg = mb.GetILGenerator();
  112. // new CachedTypeInfo[types.Count]
  113. // we leave this on the stack (duping it) and storing into it.
  114. EmitInt(ilg, types.Count);
  115. ilg.Emit(OpCodes.Newarr, typeof(CachedNewTypeInfo));
  116. int curType = 0;
  117. foreach (var v in types) {
  118. NewTypeInfo nti = NewTypeInfo.GetTypeInfo(String.Empty, v);
  119. var typeInfos = new NewTypeMaker(nti).SaveType(ag, "Python" + _typeCount++ + "$" + nti.BaseType.Name);
  120. // prepare for storing the element into our final array
  121. ilg.Emit(OpCodes.Dup);
  122. EmitInt(ilg, curType++);
  123. // new CachedNewTypeInfo(type, specialNames, interfaceTypes):
  124. // load the type
  125. ilg.Emit(OpCodes.Ldtoken, typeInfos.Key);
  126. ilg.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
  127. // create the dictionary<str, str[]> of special names
  128. ilg.Emit(OpCodes.Newobj, typeof(Dictionary<string, string[]>).GetConstructor(new Type[0]));
  129. foreach (var specialName in typeInfos.Value) {
  130. // dup dict
  131. ilg.Emit(OpCodes.Dup);
  132. // emit key
  133. ilg.Emit(OpCodes.Ldstr, specialName.Key);
  134. // emit value
  135. int iVal = specialName.Value.Length;
  136. EmitInt(ilg, iVal);
  137. ilg.Emit(OpCodes.Newarr, typeof(string));
  138. for (int i = 0; i < specialName.Value.Length; i++) {
  139. ilg.Emit(OpCodes.Dup);
  140. EmitInt(ilg, i);
  141. ilg.Emit(OpCodes.Ldstr, specialName.Value[0]);
  142. ilg.Emit(OpCodes.Stelem_Ref);
  143. }
  144. // assign to dict
  145. ilg.Emit(OpCodes.Call, typeof(Dictionary<string, string[]>).GetMethod("set_Item"));
  146. }
  147. // emit the interface types (if any)
  148. if (nti.InterfaceTypes.Count != 0) {
  149. EmitInt(ilg, nti.InterfaceTypes.Count);
  150. ilg.Emit(OpCodes.Newarr, typeof(Type));
  151. for (int i = 0; i < nti.InterfaceTypes.Count; i++) {
  152. ilg.Emit(OpCodes.Dup);
  153. EmitInt(ilg, i);
  154. ilg.Emit(OpCodes.Ldtoken, nti.InterfaceTypes[i]);
  155. ilg.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
  156. ilg.Emit(OpCodes.Stelem_Ref);
  157. }
  158. } else {
  159. ilg.Emit(OpCodes.Ldnull);
  160. }
  161. // crated the CachedNewTypeInfo and store it in the array
  162. ilg.Emit(OpCodes.Newobj, typeof(CachedNewTypeInfo).GetConstructors()[0]);
  163. ilg.Emit(OpCodes.Stelem_Ref);
  164. }
  165. ilg.Emit(OpCodes.Ret);
  166. tb.CreateType();
  167. ag.SaveAssembly();
  168. }
  169. #endif
  170. /// <summary>
  171. /// Loads any available new types from the provided assembly and makes them
  172. /// available via the GetNewType API.
  173. /// </summary>
  174. public static void LoadNewTypes(Assembly/*!*/ asm) {
  175. Assert.NotNull(asm);
  176. Type t = asm.GetType(_constructorTypeName);
  177. if (t == null || !t.GetTypeInfo().IsDefined(typeof(PythonCachedTypeInfoAttribute), false)) {
  178. return;
  179. }
  180. MethodInfo mi = t.GetMethod(_constructorMethodName);
  181. var typeInfo = (CachedNewTypeInfo[])mi.Invoke(null, new object[0]);
  182. foreach (var v in typeInfo) {
  183. _newTypes.GetOrCreateValue(
  184. new NewTypeInfo(v.Type.GetBaseType(), v.InterfaceTypes),
  185. () => {
  186. // type wasn't already created, go ahead and publish
  187. // the info and return the type.
  188. AddBaseMethods(v.Type, v.SpecialNames);
  189. return v.Type;
  190. }
  191. );
  192. }
  193. }
  194. /// <summary>
  195. /// Is this a type used for instances Python types (and not for the types themselves)?
  196. /// </summary>
  197. public static bool IsInstanceType(Type type) {
  198. return type.FullName.IndexOf(NewTypeMaker.TypePrefix) == 0 ||
  199. // Users can create sub-types of instance-types using __clrtype__ without using
  200. // NewTypeMaker.TypePrefix
  201. ((type.GetBaseType() != null) && IsInstanceType(type.GetBaseType()));
  202. }
  203. #endregion
  204. #region Type Generation
  205. #if FEATURE_REFEMIT
  206. private Type CreateNewType() {
  207. string name = GetName();
  208. _tg = Snippets.Shared.DefinePublicType(TypePrefix + name, _baseType);
  209. Dictionary<string, string[]> specialNames = ImplementType();
  210. Type ret = FinishType();
  211. AddBaseMethods(ret, specialNames);
  212. return ret;
  213. }
  214. // Build a name which is unique to this TypeInfo.
  215. private string GetName() {
  216. StringBuilder name = new StringBuilder(_baseType.Namespace);
  217. name.Append('.');
  218. name.Append(_baseType.Name);
  219. foreach (Type interfaceType in _interfaceTypes) {
  220. name.Append("#");
  221. name.Append(interfaceType.Name);
  222. }
  223. name.Append("_");
  224. name.Append(System.Threading.Interlocked.Increment(ref _typeCount));
  225. return name.ToString();
  226. }
  227. private Dictionary<string, string[]> ImplementType() {
  228. DefineInterfaces();
  229. ImplementPythonObject();
  230. ImplementConstructors();
  231. Dictionary<string, string[]> specialNames = new Dictionary<string, string[]>();
  232. OverrideMethods(_baseType, specialNames);
  233. ImplementProtectedFieldAccessors(specialNames);
  234. Dictionary<Type, bool> doneTypes = new Dictionary<Type, bool>();
  235. foreach (Type interfaceType in _interfaceTypes) {
  236. DoInterfaceType(interfaceType, doneTypes, specialNames);
  237. }
  238. return specialNames;
  239. }
  240. private void DefineInterfaces() {
  241. foreach (Type interfaceType in _interfaceTypes) {
  242. ImplementInterface(interfaceType);
  243. }
  244. }
  245. private void ImplementInterface(Type interfaceType) {
  246. _tg.AddInterfaceImplementation(interfaceType);
  247. }
  248. private void ImplementPythonObject() {
  249. ImplementIPythonObject();
  250. ImplementDynamicObject();
  251. #if FEATURE_CUSTOM_TYPE_DESCRIPTOR
  252. ImplementCustomTypeDescriptor();
  253. #endif
  254. #if CLR2
  255. ImplementPythonEquals();
  256. #endif
  257. ImplementWeakReference();
  258. AddDebugView();
  259. }
  260. private void AddDebugView() {
  261. _tg.SetCustomAttribute(
  262. new CustomAttributeBuilder(
  263. typeof(DebuggerTypeProxyAttribute).GetConstructor(new[] { typeof(Type) }),
  264. new object[] { typeof(UserTypeDebugView) }
  265. )
  266. );
  267. _tg.SetCustomAttribute(
  268. new CustomAttributeBuilder(
  269. typeof(DebuggerDisplayAttribute).GetConstructor(new[] { typeof(string) }),
  270. new object[] { "{get_PythonType().GetTypeDebuggerDisplay()}" }
  271. )
  272. );
  273. }
  274. private void EmitGetDict(ILGen gen) {
  275. gen.EmitFieldGet(_dictField);
  276. }
  277. private void EmitSetDict(ILGen gen) {
  278. gen.EmitFieldSet(_dictField);
  279. }
  280. private ParameterInfoWrapper[] GetOverrideCtorSignature(ParameterInfo[] originalParameterInfo) {
  281. ParameterInfoWrapper[] original = originalParameterInfo.Select(o => new ParameterInfoWrapper(o)).ToArray();
  282. if (typeof(IPythonObject).IsAssignableFrom(_baseType)) {
  283. return original;
  284. }
  285. ParameterInfoWrapper[] argTypes = new ParameterInfoWrapper[original.Length + 1];
  286. if (original.Length == 0 || original[0].ParameterType != typeof(CodeContext)) {
  287. argTypes[0] = new ParameterInfoWrapper(typeof(PythonType), "cls");
  288. Array.Copy(original, 0, argTypes, 1, argTypes.Length - 1);
  289. } else {
  290. argTypes[0] = original[0];
  291. argTypes[1] = new ParameterInfoWrapper(typeof(PythonType), "cls");
  292. Array.Copy(original, 1, argTypes, 2, argTypes.Length - 2);
  293. }
  294. return argTypes;
  295. }
  296. private void ImplementConstructors() {
  297. ConstructorInfo[] constructors;
  298. constructors = _baseType.GetConstructors(BindingFlags.Public |
  299. BindingFlags.NonPublic |
  300. BindingFlags.Instance
  301. );
  302. foreach (ConstructorInfo ci in constructors) {
  303. if (ci.IsPublic || ci.IsProtected()) {
  304. OverrideConstructor(ci);
  305. }
  306. }
  307. }
  308. private static bool CanOverrideMethod(MethodInfo mi) {
  309. #if !SILVERLIGHT
  310. return true;
  311. #else
  312. // can only override the method if it is not SecurityCritical
  313. return mi.GetCustomAttributes(typeof(System.Security.SecurityCriticalAttribute), false).Length == 0;
  314. #endif
  315. }
  316. private void DoInterfaceType(Type interfaceType, Dictionary<Type, bool> doneTypes, Dictionary<string, string[]> specialNames) {
  317. if (interfaceType == typeof(IDynamicMetaObjectProvider)) {
  318. // very tricky, we'll handle it when we're creating
  319. // our own IDynamicMetaObjectProvider interface
  320. return;
  321. }
  322. if (doneTypes.ContainsKey(interfaceType)) return;
  323. doneTypes.Add(interfaceType, true);
  324. OverrideMethods(interfaceType, specialNames);
  325. foreach (Type t in interfaceType.GetInterfaces()) {
  326. DoInterfaceType(t, doneTypes, specialNames);
  327. }
  328. }
  329. private void OverrideConstructor(ConstructorInfo parentConstructor) {
  330. ParameterInfo[] pis = parentConstructor.GetParameters();
  331. if (pis.Length == 0 && typeof(IPythonObject).IsAssignableFrom(_baseType)) {
  332. // default ctor on a base type, don't override this one, it assumes
  333. // the PythonType is some default value and we'll always be unique.
  334. return;
  335. }
  336. ParameterInfoWrapper[] overrideParams = GetOverrideCtorSignature(pis);
  337. Type[] argTypes = new Type[overrideParams.Length];
  338. string[] paramNames = new string[overrideParams.Length];
  339. for (int i = 0; i < overrideParams.Length; i++) {
  340. argTypes[i] = overrideParams[i].ParameterType;
  341. paramNames[i] = overrideParams[i].Name;
  342. }
  343. ConstructorBuilder cb = _tg.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, argTypes);
  344. for (int i = 0; i < overrideParams.Length; i++) {
  345. ParameterBuilder pb = cb.DefineParameter(i + 1,
  346. overrideParams[i].Attributes,
  347. overrideParams[i].Name);
  348. int origIndex = GetOriginalIndex(pis, overrideParams, i);
  349. if (origIndex >= 0) {
  350. ParameterInfo pi = pis[origIndex];
  351. // Defines attributes that might be used in .net methods for overload detection and other
  352. // parameter based attribute logic. E.g. [BytesConversionAttribute] to make
  353. // enable automatic cast between .net IList<byte> and string
  354. if (pi.IsDefined(typeof(ParamArrayAttribute), false)) {
  355. pb.SetCustomAttribute(new CustomAttributeBuilder(
  356. typeof(ParamArrayAttribute).GetConstructor(ReflectionUtils.EmptyTypes), ArrayUtils.EmptyObjects));
  357. } else if (pi.IsDefined(typeof(ParamDictionaryAttribute), false)) {
  358. pb.SetCustomAttribute(new CustomAttributeBuilder(
  359. typeof(ParamDictionaryAttribute).GetConstructor(ReflectionUtils.EmptyTypes), ArrayUtils.EmptyObjects));
  360. } else if (pi.IsDefined(typeof(BytesConversionAttribute), false)) {
  361. pb.SetCustomAttribute(new CustomAttributeBuilder(
  362. typeof(BytesConversionAttribute).GetConstructor(ReflectionUtils.EmptyTypes), ArrayUtils.EmptyObjects));
  363. } else if (pi.IsDefined(typeof(BytesConversionNoStringAttribute), false)) {
  364. pb.SetCustomAttribute(new CustomAttributeBuilder(
  365. typeof(BytesConversionNoStringAttribute).GetConstructor(ReflectionUtils.EmptyTypes), ArrayUtils.EmptyObjects));
  366. }
  367. if ((pi.Attributes & ParameterAttributes.HasDefault) != 0) {
  368. if (pi.DefaultValue == null || pi.ParameterType.IsAssignableFrom(pi.DefaultValue.GetType())) {
  369. pb.SetConstant(pi.DefaultValue);
  370. } else {
  371. pb.SetConstant(Convert.ChangeType(
  372. pi.DefaultValue, pi.ParameterType,
  373. System.Globalization.CultureInfo.CurrentCulture
  374. ));
  375. }
  376. }
  377. }
  378. }
  379. ILGen il = new ILGen(cb.GetILGenerator());
  380. int typeArg;
  381. if (pis.Length == 0 || pis[0].ParameterType != typeof(CodeContext)) {
  382. typeArg = 1;
  383. } else {
  384. typeArg = 2;
  385. }
  386. // this.__class__ = <arg?>
  387. // can occur 2 ways:
  388. // 1. If we have our own _typeField then we set it
  389. // 2. If we're a subclass of IPythonObject (e.g. one of our exception classes) then we'll flow it to the
  390. // base type constructor which will set it.
  391. if (!typeof(IPythonObject).IsAssignableFrom(_baseType)) {
  392. il.EmitLoadArg(0);
  393. // base class could have CodeContext parameter in which case our type is the 2nd parameter.
  394. il.EmitLoadArg(typeArg);
  395. il.EmitFieldSet(_typeField);
  396. }
  397. if (_explicitMO != null) {
  398. il.Emit(OpCodes.Ldarg_0);
  399. il.EmitNew(_explicitMO.FieldType.GetConstructor(ReflectionUtils.EmptyTypes));
  400. il.Emit(OpCodes.Stfld, _explicitMO);
  401. }
  402. // initialize all slots to Uninitialized.instance
  403. MethodInfo init = typeof(PythonOps).GetMethod("InitializeUserTypeSlots");
  404. il.EmitLoadArg(0);
  405. il.EmitLoadArg(typeArg);
  406. il.EmitCall(init);
  407. Debug.Assert(_slotsField != null);
  408. il.EmitFieldSet(_slotsField);
  409. CallBaseConstructor(parentConstructor, pis, overrideParams, il);
  410. }
  411. /// <summary>
  412. /// Gets the position for the parameter which we are overriding.
  413. /// </summary>
  414. /// <param name="pis"></param>
  415. /// <param name="overrideParams"></param>
  416. /// <param name="i"></param>
  417. /// <returns></returns>
  418. private static int GetOriginalIndex(ParameterInfo[] pis, ParameterInfoWrapper[] overrideParams, int i) {
  419. if (pis.Length == 0 || pis[0].ParameterType != typeof(CodeContext)) {
  420. return i - (overrideParams.Length - pis.Length);
  421. }
  422. // context & cls are swapped, context comes first.
  423. if (i == 1) return -1;
  424. if (i == 0) return 0;
  425. return i - (overrideParams.Length - pis.Length);
  426. }
  427. private static void CallBaseConstructor(ConstructorInfo parentConstructor, ParameterInfo[] pis, ParameterInfoWrapper[] overrideParams, ILGen il) {
  428. il.EmitLoadArg(0);
  429. #if DEBUG
  430. int lastIndex = -1;
  431. #endif
  432. for (int i = 0; i < overrideParams.Length; i++) {
  433. int index = GetOriginalIndex(pis, overrideParams, i);
  434. #if DEBUG
  435. // we insert a new parameter (the class) but the parametrers should
  436. // still remain in the same order after the extra parameter is removed.
  437. if (index >= 0) {
  438. Debug.Assert(index > lastIndex);
  439. lastIndex = index;
  440. }
  441. #endif
  442. if (index >= 0) {
  443. il.EmitLoadArg(i + 1);
  444. }
  445. }
  446. il.Emit(OpCodes.Call, parentConstructor);
  447. il.Emit(OpCodes.Ret);
  448. }
  449. ILGen GetCCtor() {
  450. if (_cctor == null) {
  451. ConstructorBuilder cctor = _tg.DefineTypeInitializer();
  452. _cctor = new ILGen(cctor.GetILGenerator());
  453. }
  454. return _cctor;
  455. }
  456. #if FEATURE_CUSTOM_TYPE_DESCRIPTOR
  457. private void ImplementCustomTypeDescriptor() {
  458. ImplementInterface(typeof(ICustomTypeDescriptor));
  459. foreach (MethodInfo m in typeof(ICustomTypeDescriptor).GetMethods()) {
  460. ImplementCTDOverride(m);
  461. }
  462. }
  463. private void ImplementCTDOverride(MethodInfo m) {
  464. MethodBuilder builder;
  465. ILGen il = DefineExplicitInterfaceImplementation(m, out builder);
  466. il.EmitLoadArg(0);
  467. ParameterInfo[] pis = m.GetParameters();
  468. Type[] paramTypes = new Type[pis.Length + 1];
  469. paramTypes[0] = typeof(object);
  470. for (int i = 0; i < pis.Length; i++) {
  471. il.EmitLoadArg(i + 1);
  472. paramTypes[i + 1] = pis[i].ParameterType;
  473. }
  474. il.EmitCall(typeof(CustomTypeDescHelpers), m.Name, paramTypes);
  475. il.EmitBoxing(m.ReturnType);
  476. il.Emit(OpCodes.Ret);
  477. _tg.DefineMethodOverride(builder, m);
  478. }
  479. #endif
  480. private bool NeedsPythonObject {
  481. get {
  482. return !typeof(IPythonObject).IsAssignableFrom(_baseType);
  483. }
  484. }
  485. private void ImplementDynamicObject() {
  486. // true if the user has explicitly included IDynamicMetaObjectProvider in the list of interfaces
  487. bool explicitDynamicObject = false;
  488. foreach (Type t in _interfaceTypes) {
  489. if (t == typeof(IDynamicMetaObjectProvider)) {
  490. explicitDynamicObject = true;
  491. break;
  492. }
  493. }
  494. // true if our base type implements IDMOP already
  495. bool baseIdo = typeof(IDynamicMetaObjectProvider).IsAssignableFrom(_baseType);
  496. if (baseIdo) {
  497. InterfaceMapping mapping = _baseType.GetTypeInfo().GetRuntimeInterfaceMap(typeof(IDynamicMetaObjectProvider));
  498. if (mapping.TargetMethods[0].IsPrivate) {
  499. // explicitly implemented IDynamicMetaObjectProvider, we cannot override it.
  500. if (_baseType.GetTypeInfo().IsDefined(typeof(DynamicBaseTypeAttribute), true)) {
  501. // but it's been implemented by IronPython so it's going to return a MetaUserObject
  502. return;
  503. }
  504. // we can't dispatch to the subclasses IDMOP implementation, completely
  505. // replace it with our own.
  506. baseIdo = false;
  507. }
  508. }
  509. ImplementInterface(typeof(IDynamicMetaObjectProvider));
  510. MethodInfo decl;
  511. MethodBuilder impl;
  512. ILGen il = DefineMethodOverride(MethodAttributes.Private, typeof(IDynamicMetaObjectProvider), "GetMetaObject", out decl, out impl);
  513. MethodInfo mi = typeof(UserTypeOps).GetMethod("GetMetaObjectHelper");
  514. LocalBuilder retVal = il.DeclareLocal(typeof(DynamicMetaObject));
  515. Label retLabel = il.DefineLabel();
  516. if (explicitDynamicObject) {
  517. _explicitMO = _tg.DefineField("__gettingMO", typeof(ThreadLocal<bool>), FieldAttributes.InitOnly | FieldAttributes.Private);
  518. Label ipyImpl = il.DefineLabel();
  519. Label noOverride = il.DefineLabel();
  520. Label retNull = il.DefineLabel();
  521. var valueProperty = typeof(ThreadLocal<bool>).GetDeclaredProperty("Value");
  522. // check if the we're recursing (this enables the user to refer to self
  523. // during GetMetaObject calls)
  524. il.Emit(OpCodes.Ldarg_0);
  525. il.Emit(OpCodes.Ldfld, _explicitMO);
  526. il.EmitPropertyGet(valueProperty);
  527. il.Emit(OpCodes.Brtrue, ipyImpl);
  528. // we're not recursing, set the flag...
  529. il.Emit(OpCodes.Ldarg_0);
  530. il.Emit(OpCodes.Ldfld, _explicitMO);
  531. il.Emit(OpCodes.Ldc_I4_1);
  532. il.EmitPropertySet(valueProperty);
  533. il.BeginExceptionBlock();
  534. LocalBuilder callTarget = EmitNonInheritedMethodLookup("GetMetaObject", il);
  535. il.Emit(OpCodes.Brfalse, noOverride);
  536. // call the user GetMetaObject function
  537. EmitClrCallStub(il, typeof(IDynamicMetaObjectProvider).GetMethod("GetMetaObject"), callTarget);
  538. // check for null return
  539. il.Emit(OpCodes.Dup);
  540. il.Emit(OpCodes.Ldnull);
  541. il.Emit(OpCodes.Beq, retNull);
  542. // store the local value
  543. il.Emit(OpCodes.Stloc_S, retVal.LocalIndex);
  544. // returned a value, that's our result
  545. il.Emit(OpCodes.Leave, retLabel);
  546. // user returned null, fallback to base impl
  547. il.MarkLabel(retNull);
  548. il.Emit(OpCodes.Pop);
  549. // no override exists
  550. il.MarkLabel(noOverride);
  551. // will emit leave to end of exception block
  552. il.BeginFinallyBlock();
  553. // restore the flag now that we're done
  554. il.Emit(OpCodes.Ldarg_0);
  555. il.Emit(OpCodes.Ldfld, _explicitMO);
  556. il.Emit(OpCodes.Ldc_I4_0);
  557. il.EmitPropertySet(typeof(ThreadLocal<bool>).GetDeclaredProperty("Value"));
  558. il.EndExceptionBlock();
  559. // no user defined function or no result
  560. il.MarkLabel(ipyImpl);
  561. }
  562. il.EmitLoadArg(0); // this
  563. il.EmitLoadArg(1); // parameter
  564. // baseMetaObject
  565. if (baseIdo) {
  566. InterfaceMapping imap = _baseType.GetTypeInfo().GetRuntimeInterfaceMap(typeof(IDynamicMetaObjectProvider));
  567. il.EmitLoadArg(0); // this
  568. il.EmitLoadArg(1); // parameter
  569. il.EmitCall(imap.TargetMethods[0]);
  570. } else {
  571. il.EmitNull();
  572. }
  573. il.EmitCall(mi);
  574. il.Emit(OpCodes.Stloc, retVal.LocalIndex);
  575. il.MarkLabel(retLabel);
  576. il.Emit(OpCodes.Ldloc, retVal.LocalIndex);
  577. il.Emit(OpCodes.Ret);
  578. _tg.DefineMethodOverride(impl, decl);
  579. }
  580. private void ImplementIPythonObject() {
  581. ILGen il;
  582. MethodInfo decl;
  583. MethodBuilder impl;
  584. if (NeedsPythonObject) {
  585. _typeField = _tg.DefineField(ClassFieldName, typeof(PythonType), FieldAttributes.Public);
  586. _dictField = _tg.DefineField(DictFieldName, typeof(PythonDictionary), FieldAttributes.Public);
  587. ImplementInterface(typeof(IPythonObject));
  588. MethodAttributes attrs = MethodAttributes.Private;
  589. il = DefineMethodOverride(attrs, typeof(IPythonObject), "get_Dict", out decl, out impl);
  590. il.EmitLoadArg(0);
  591. EmitGetDict(il);
  592. il.Emit(OpCodes.Ret);
  593. _tg.DefineMethodOverride(impl, decl);
  594. il = DefineMethodOverride(attrs, typeof(IPythonObject), "ReplaceDict", out decl, out impl);
  595. il.EmitLoadArg(0);
  596. il.EmitLoadArg(1);
  597. EmitSetDict(il);
  598. il.EmitBoolean(true);
  599. il.Emit(OpCodes.Ret);
  600. _tg.DefineMethodOverride(impl, decl);
  601. il = DefineMethodOverride(attrs, typeof(IPythonObject), "SetDict", out decl, out impl);
  602. il.EmitLoadArg(0);
  603. il.EmitFieldAddress(_dictField);
  604. il.EmitLoadArg(1);
  605. il.EmitCall(typeof(UserTypeOps), "SetDictHelper");
  606. il.Emit(OpCodes.Ret);
  607. _tg.DefineMethodOverride(impl, decl);
  608. il = DefineMethodOverride(attrs, typeof(IPythonObject), "get_PythonType", out decl, out impl);
  609. il.EmitLoadArg(0);
  610. il.EmitFieldGet(_typeField);
  611. il.Emit(OpCodes.Ret);
  612. _tg.DefineMethodOverride(impl, decl);
  613. il = DefineMethodOverride(attrs, typeof(IPythonObject), "SetPythonType", out decl, out impl);
  614. il.EmitLoadArg(0);
  615. il.EmitLoadArg(1);
  616. il.EmitFieldSet(_typeField);
  617. il.Emit(OpCodes.Ret);
  618. _tg.DefineMethodOverride(impl, decl);
  619. }
  620. // Types w/ DynamicBaseType attribute still need new slots implementation
  621. _slotsField = _tg.DefineField(SlotsAndWeakRefFieldName, typeof(object[]), FieldAttributes.Public);
  622. il = DefineMethodOverride(MethodAttributes.Private, typeof(IPythonObject), "GetSlots", out decl, out impl);
  623. il.EmitLoadArg(0);
  624. il.EmitFieldGet(_slotsField);
  625. il.Emit(OpCodes.Ret);
  626. _tg.DefineMethodOverride(impl, decl);
  627. il = DefineMethodOverride(MethodAttributes.Private, typeof(IPythonObject), "GetSlotsCreate", out decl, out impl);
  628. il.EmitLoadArg(0);
  629. il.EmitLoadArg(0);
  630. il.EmitFieldAddress(_slotsField);
  631. il.EmitCall(typeof(UserTypeOps).GetMethod("GetSlotsCreate"));
  632. il.Emit(OpCodes.Ret);
  633. _tg.DefineMethodOverride(impl, decl);
  634. }
  635. /// <summary>
  636. /// Defines an interface on the type that forwards all calls
  637. /// to a helper method in UserType. The method names all will
  638. /// have Helper appended to them to get the name for UserType. The
  639. /// UserType version should take 1 extra parameter (self).
  640. /// </summary>
  641. private void DefineHelperInterface(Type intf) {
  642. ImplementInterface(intf);
  643. MethodInfo[] mis = intf.GetMethods();
  644. foreach (MethodInfo mi in mis) {
  645. MethodBuilder impl;
  646. ILGen il = DefineExplicitInterfaceImplementation(mi, out impl);
  647. ParameterInfo[] pis = mi.GetParameters();
  648. MethodInfo helperMethod = typeof(UserTypeOps).GetMethod(mi.Name + "Helper");
  649. int offset = 0;
  650. if (pis.Length > 0 && pis[0].ParameterType == typeof(CodeContext)) {
  651. // if the interface takes CodeContext then the helper method better take
  652. // it as well.
  653. Debug.Assert(helperMethod.GetParameters()[0].ParameterType == typeof(CodeContext));
  654. offset = 1;
  655. il.EmitLoadArg(1);
  656. }
  657. il.EmitLoadArg(0);
  658. for (int i = offset; i < pis.Length; i++) {
  659. il.EmitLoadArg(i + 1);
  660. }
  661. il.EmitCall(helperMethod);
  662. il.Emit(OpCodes.Ret);
  663. _tg.DefineMethodOverride(impl, mi);
  664. }
  665. }
  666. #if CLR2
  667. private void ImplementPythonEquals() {
  668. if (this._baseType.GetInterface("IValueEquality", false) == null) {
  669. DefineHelperInterface(typeof(IValueEquality));
  670. }
  671. }
  672. #endif
  673. private void ImplementWeakReference() {
  674. if (typeof(IWeakReferenceable).IsAssignableFrom(_baseType)) {
  675. return;
  676. }
  677. DefineHelperInterface(typeof(IWeakReferenceable));
  678. }
  679. private void ImplementProtectedFieldAccessors(Dictionary<string, string[]> specialNames) {
  680. // For protected fields to be accessible from the derived type in Silverlight,
  681. // we need to create public helper methods that expose them. These methods are
  682. // used by the IDynamicMetaObjectProvider implementation (in MetaUserObject)
  683. foreach (FieldInfo fi in _baseType.GetInheritedFields(flattenHierarchy: true)) {
  684. if (!fi.IsProtected()) {
  685. continue;
  686. }
  687. List<string> fieldAccessorNames = new List<string>();
  688. PropertyBuilder pb = _tg.DefineProperty(fi.Name, PropertyAttributes.None, fi.FieldType, ReflectionUtils.EmptyTypes);
  689. MethodAttributes methodAttrs = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName;
  690. if (fi.IsStatic) {
  691. methodAttrs |= MethodAttributes.Static;
  692. }
  693. MethodBuilder method;
  694. method = _tg.DefineMethod(FieldGetterPrefix + fi.Name, methodAttrs, fi.FieldType, ReflectionUtils.EmptyTypes);
  695. ILGen il = new ILGen(method.GetILGenerator());
  696. if (!fi.IsStatic) {
  697. il.EmitLoadArg(0);
  698. }
  699. if (fi.IsLiteral) {
  700. // literal fields need to be inlined directly in here... We use GetRawConstant
  701. // which will work even in partial trust if the constant is protected.
  702. object value = fi.GetRawConstantValue();
  703. switch (fi.FieldType.GetTypeCode()) {
  704. case TypeCode.Boolean:
  705. if ((bool)value) {
  706. il.Emit(OpCodes.Ldc_I4_1);
  707. } else {
  708. il.Emit(OpCodes.Ldc_I4_0);
  709. }
  710. break;
  711. case TypeCode.Byte: il.Emit(OpCodes.Ldc_I4, (byte)value); break;
  712. case TypeCode.Char: il.Emit(OpCodes.Ldc_I4, (char)value); break;
  713. case TypeCode.Double: il.Emit(OpCodes.Ldc_R8, (double)value); break;
  714. case TypeCode.Int16: il.Emit(OpCodes.Ldc_I4, (short)value); break;
  715. case TypeCode.Int32: il.Emit(OpCodes.Ldc_I4, (int)value); break;
  716. case TypeCode.Int64: il.Emit(OpCodes.Ldc_I8, (long)value); break;
  717. case TypeCode.SByte: il.Emit(OpCodes.Ldc_I4, (sbyte)value); break;
  718. case TypeCode.Single: il.Emit(OpCodes.Ldc_R4, (float)value); break;
  719. case TypeCode.String: il.Emit(OpCodes.Ldstr, (string)value); break;
  720. case TypeCode.UInt16: il.Emit(OpCodes.Ldc_I4, (ushort)value); break;
  721. case TypeCode.UInt32: il.Emit(OpCodes.Ldc_I4, (uint)value); break;
  722. case TypeCode.UInt64: il.Emit(OpCodes.Ldc_I8, (ulong)value); break;
  723. }
  724. } else {
  725. il.EmitFieldGet(fi);
  726. }
  727. il.Emit(OpCodes.Ret);
  728. pb.SetGetMethod(method);
  729. fieldAccessorNames.Add(method.Name);
  730. if (!fi.IsLiteral && !fi.IsInitOnly) {
  731. method = _tg.DefineMethod(FieldSetterPrefix + fi.Name, methodAttrs,
  732. null, new Type[] { fi.FieldType });
  733. method.DefineParameter(1, ParameterAttributes.None, "value");
  734. il = new ILGen(method.GetILGenerator());
  735. il.EmitLoadArg(0);
  736. if (!fi.IsStatic) {
  737. il.EmitLoadArg(1);
  738. }
  739. il.EmitFieldSet(fi);
  740. il.Emit(OpCodes.Ret);
  741. pb.SetSetMethod(method);
  742. fieldAccessorNames.Add(method.Name);
  743. }
  744. specialNames[fi.Name] = fieldAccessorNames.ToArray();
  745. }
  746. }
  747. /// <summary>
  748. /// Overrides methods - this includes all accessible virtual methods as well as protected non-virtual members
  749. /// including statics and non-statics.
  750. /// </summary>
  751. private void OverrideMethods(Type type, Dictionary<string, string[]> specialNames) {
  752. // if we have conflicting virtual's do to new slots only override the methods on the
  753. // most derived class.
  754. Dictionary<KeyValuePair<string, MethodSignatureInfo>, MethodInfo> added = new Dictionary<KeyValuePair<string, MethodSignatureInfo>, MethodInfo>();
  755. MethodInfo overridden;
  756. MethodInfo[] methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy);
  757. foreach (MethodInfo mi in methods) {
  758. KeyValuePair<string, MethodSignatureInfo> key = new KeyValuePair<string, MethodSignatureInfo>(mi.Name, new MethodSignatureInfo(mi));
  759. if (!added.TryGetValue(key, out overridden)) {
  760. added[key] = mi;
  761. continue;
  762. }
  763. if (overridden.DeclaringType.IsAssignableFrom(mi.DeclaringType)) {
  764. added[key] = mi;
  765. }
  766. }
  767. if (type.IsAbstract() && !type.IsInterface()) {
  768. // abstract types can define interfaces w/o implementations
  769. foreach (Type iface in type.GetInterfaces()) {
  770. InterfaceMapping mapping = type.GetTypeInfo().GetRuntimeInterfaceMap(iface);
  771. for (int i = 0; i < mapping.TargetMethods.Length; i++) {
  772. if (mapping.TargetMethods[i] == null) {
  773. MethodInfo mi = mapping.InterfaceMethods[i];
  774. KeyValuePair<string, MethodSignatureInfo> key = new KeyValuePair<string, MethodSignatureInfo>(mi.Name, new MethodSignatureInfo(mi));
  775. added[key] = mi;
  776. }
  777. }
  778. }
  779. }
  780. Dictionary<PropertyInfo, PropertyBuilder> overriddenProperties = new Dictionary<PropertyInfo, PropertyBuilder>();
  781. foreach (MethodInfo mi in added.Values) {
  782. if (!CanOverrideMethod(mi)) continue;
  783. if (mi.IsPublic || mi.IsProtected()) {
  784. if (mi.IsSpecialName) {
  785. OverrideSpecialName(mi, specialNames, overriddenProperties);
  786. } else {
  787. OverrideBaseMethod(mi, specialNames);
  788. }
  789. }
  790. }
  791. }
  792. private void OverrideSpecialName(MethodInfo mi, Dictionary<string, string[]> specialNames, Dictionary<PropertyInfo, PropertyBuilder> overridden) {
  793. if (!mi.IsVirtual || mi.IsFinal) {
  794. // TODO: A better check here would be mi.IsFamily && mi.IsSpecialName. But we need to also check
  795. // the other property method (getter if we're a setter, setter if we're a getter) because if one is protected
  796. // and the other isn't we need to still override both (so our newslot property is also both a getter and a setter).
  797. if ((mi.IsProtected() || mi.IsSpecialName) && (mi.Name.StartsWith("get_") || mi.Name.StartsWith("set_"))) {
  798. // need to be able to call into protected getter/setter methods from derived types,
  799. // even if these methods aren't virtual and we are in partial trust.
  800. specialNames[mi.Name] = new[] { mi.Name };
  801. MethodBuilder mb = CreateSuperCallHelper(mi);
  802. foreach (PropertyInfo pi in mi.DeclaringType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
  803. if (pi.GetGetMethod(true).MemberEquals(mi) || pi.GetSetMethod(true).MemberEquals(mi)) {
  804. AddPublicProperty(mi, overridden, mb, pi);
  805. break;
  806. }
  807. }
  808. }
  809. } else if (!TryOverrideProperty(mi, specialNames, overridden)) {
  810. string name;
  811. EventInfo[] eis = mi.DeclaringType.GetEvents(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
  812. foreach (EventInfo ei in eis) {
  813. if (ei.GetAddMethod().MemberEquals(mi)) {
  814. if (NameConverter.TryGetName(DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType), ei, mi, out name) == NameType.None) return;
  815. CreateVTableEventOverride(mi, mi.Name);
  816. return;
  817. } else if (ei.GetRemoveMethod().MemberEquals(mi)) {
  818. if (NameConverter.TryGetName(DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType), ei, mi, out name) == NameType.None) return;
  819. CreateVTableEventOverride(mi, mi.Name);
  820. return;
  821. }
  822. }
  823. OverrideBaseMethod(mi, specialNames);
  824. }
  825. }
  826. private bool TryOverrideProperty(MethodInfo mi, Dictionary<string, string[]> specialNames, Dictionary<PropertyInfo, PropertyBuilder> overridden) {
  827. string name;
  828. PropertyInfo[] pis = mi.DeclaringType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
  829. specialNames[mi.Name] = new[] { mi.Name };
  830. MethodBuilder mb = null;
  831. PropertyInfo foundProperty = null;
  832. foreach (PropertyInfo pi in pis) {
  833. if (pi.GetIndexParameters().Length > 0) {
  834. if (mi.MemberEquals(pi.GetGetMethod(true))) {
  835. mb = CreateVTableMethodOverride(mi, "__getitem__");
  836. if (!mi.IsAbstract) {
  837. CreateSuperCallHelper(mi);
  838. }
  839. foundProperty = pi;
  840. break;
  841. } else if (mi.MemberEquals(pi.GetSetMethod(true))) {
  842. mb = CreateVTableMethodOverride(mi, "__setitem__");
  843. if (!mi.IsAbstract) {
  844. CreateSuperCallHelper(mi);
  845. }
  846. foundProperty = pi;
  847. break;
  848. }
  849. } else if (mi.MemberEquals(pi.GetGetMethod(true))) {
  850. if (mi.Name != "get_PythonType") {
  851. if (NameConverter.TryGetName(GetBaseTypeForMethod(mi), pi, mi, out name) == NameType.None) {
  852. return true;
  853. }
  854. mb = CreateVTableGetterOverride(mi, name);
  855. if (!mi.IsAbstract) {
  856. CreateSuperCallHelper(mi);
  857. }
  858. }
  859. foundProperty = pi;
  860. break;
  861. } else if (mi.MemberEquals(pi.GetSetMethod(true))) {
  862. if (NameConverter.TryGetName(GetBaseTypeForMethod(mi), pi, mi, out name) == NameType.None) {
  863. return true;
  864. }
  865. mb = CreateVTableSetterOverride(mi, name);
  866. if (!mi.IsAbstract) {
  867. CreateSuperCallHelper(mi);
  868. }
  869. foundProperty = pi;
  870. break;
  871. }
  872. }
  873. if (foundProperty != null) {
  874. AddPublicProperty(mi, overridden, mb, foundProperty);
  875. return true;
  876. }
  877. return false;
  878. }
  879. private void AddPublicProperty(MethodInfo mi, Dictionary<PropertyInfo, PropertyBuilder> overridden, MethodBuilder mb, PropertyInfo foundProperty) {
  880. MethodInfo getter = foundProperty.GetGetMethod(true);
  881. MethodInfo setter = foundProperty.GetSetMethod(true);
  882. if (getter != null && getter.IsProtected() || setter != null && setter.IsProtected()) {
  883. PropertyBuilder builder;
  884. if (!overridden.TryGetValue(foundProperty, out builder)) {
  885. ParameterInfo[] indexArgs = foundProperty.GetIndexParameters();
  886. Type[] paramTypes = new Type[indexArgs.Length];
  887. for (int i = 0; i < paramTypes.Length; i++) {
  888. paramTypes[i] = indexArgs[i].ParameterType;
  889. }
  890. overridden[foundProperty] = builder = _tg.DefineProperty(foundProperty.Name, foundProperty.Attributes, foundProperty.PropertyType, paramTypes);
  891. }
  892. if (foundProperty.GetGetMethod(true).MemberEquals(mi)) {
  893. builder.SetGetMethod(mb);
  894. } else if (foundProperty.GetSetMethod(true).MemberEquals(mi)) {
  895. builder.SetSetMethod(mb);
  896. }
  897. }
  898. }
  899. /// <summary>
  900. /// Loads all the incoming arguments and forwards them to mi which
  901. /// has the same signature and then returns the result
  902. /// </summary>
  903. private static void EmitBaseMethodDispatch(MethodInfo mi, ILGen il) {
  904. if (!mi.IsAbstract) {
  905. int offset = 0;
  906. if (!mi.IsStatic) {
  907. il.EmitLoadArg(0);
  908. offset = 1;
  909. }
  910. ParameterInfo[] parameters = mi.GetParameters();
  911. for (int i = 0; i < parameters.Length; i++) {
  912. il.EmitLoadArg(i + offset);
  913. }
  914. il.EmitCall(OpCodes.Call, mi, null); // base call must be non-virtual
  915. il.Emit(OpCodes.Ret);
  916. } else {
  917. il.EmitLoadArg(0);
  918. il.EmitString(mi.Name);
  919. il.EmitCall(typeof(PythonOps), "MissingInvokeMethodException");
  920. il.Emit(OpCodes.Throw);
  921. }
  922. }
  923. private void OverrideBaseMethod(MethodInfo mi, Dictionary<string, string[]> specialNames) {
  924. if ((!mi.IsVirtual || mi.IsFinal) && !mi.IsProtected()) {
  925. return;
  926. }
  927. PythonType basePythonType = GetBaseTypeForMethod(mi);
  928. string name = null;
  929. if (NameConverter.TryGetName(basePythonType, mi, out name) == NameType.None)
  930. return;
  931. if (mi.DeclaringType == typeof(object) && mi.Name == "Finalize") return;
  932. specialNames[mi.Name] = new[] { mi.Name };
  933. if (!mi.IsStatic) {
  934. CreateVTableMethodOverride(mi, name);
  935. }
  936. if (!mi.IsAbstract) {
  937. CreateSuperCallHelper(mi);
  938. }
  939. }
  940. private PythonType GetBaseTypeForMethod(MethodInfo mi) {
  941. PythonType basePythonType;
  942. if (_baseType ==

Large files files are truncated, but you can click here to view the full file