PageRenderTime 60ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/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
  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 == mi.DeclaringType || _baseType.IsSubclassOf(mi.DeclaringType)) {
  943. basePythonType = DynamicHelpers.GetPythonTypeFromType(_baseType);
  944. } else {
  945. // We must be inherting from an interface
  946. Debug.Assert(mi.DeclaringType.IsInterface());
  947. basePythonType = DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType);
  948. }
  949. return basePythonType;
  950. }
  951. /// <summary>
  952. /// Emits code to check if the class has overridden this specific
  953. /// function. For example:
  954. ///
  955. /// MyDerivedType.SomeVirtualFunction = ...
  956. /// or
  957. ///
  958. /// class MyDerivedType(MyBaseType):
  959. /// def SomeVirtualFunction(self, ...):
  960. ///
  961. /// </summary>
  962. private LocalBuilder EmitBaseClassCallCheckForProperties(ILGen il, MethodInfo baseMethod, string name) {
  963. Label instanceCall = il.DefineLabel();
  964. LocalBuilder callTarget = il.DeclareLocal(typeof(object));
  965. // first lookup under the property name
  966. il.EmitLoadArg(0);
  967. il.EmitString(name);
  968. il.Emit(OpCodes.Ldloca, callTarget);
  969. il.EmitCall(typeof(UserTypeOps), "TryGetNonInheritedValueHelper");
  970. il.Emit(OpCodes.Brtrue, instanceCall);
  971. // then look up under the method name (get_Foo/set_Foo)
  972. LocalBuilder methodTarget = EmitNonInheritedMethodLookup(baseMethod.Name, il);
  973. Label instanceCallMethod = il.DefineLabel();
  974. il.Emit(OpCodes.Brtrue, instanceCallMethod);
  975. // method isn't overridden using either form
  976. EmitBaseMethodDispatch(baseMethod, il);
  977. // we're calling the get_/set_ method
  978. il.MarkLabel(instanceCallMethod);
  979. EmitClrCallStub(il, baseMethod, methodTarget);
  980. il.Emit(OpCodes.Ret);
  981. il.MarkLabel(instanceCall);
  982. // we're accessing a property
  983. return callTarget;
  984. }
  985. private MethodBuilder CreateVTableGetterOverride(MethodInfo mi, string name) {
  986. MethodBuilder impl;
  987. ILGen il;
  988. DefineVTableMethodOverride(mi, out impl, out il);
  989. LocalBuilder callTarget = EmitBaseClassCallCheckForProperties(il, mi, name);
  990. il.Emit(OpCodes.Ldloc, callTarget);
  991. il.EmitLoadArg(0);
  992. il.EmitString(name);
  993. il.EmitCall(typeof(UserTypeOps), "GetPropertyHelper");
  994. if (!il.TryEmitImplicitCast(typeof(object), mi.ReturnType)) {
  995. EmitConvertFromObject(il, mi.ReturnType);
  996. }
  997. il.Emit(OpCodes.Ret);
  998. _tg.DefineMethodOverride(impl, mi);
  999. return impl;
  1000. }
  1001. /// <summary>
  1002. /// Emit code to convert object to a given type. This code is semantically equivalent
  1003. /// to PythonBinder.EmitConvertFromObject, except this version accepts ILGen whereas
  1004. /// PythonBinder accepts Compiler. The Binder will chagne soon and the two will merge.
  1005. /// </summary>
  1006. private static void EmitConvertFromObject(ILGen il, Type toType) {
  1007. if (toType == typeof(object)) return;
  1008. if (toType.IsGenericParameter) {
  1009. il.EmitCall(typeof(PythonOps).GetMethod("ConvertFromObject").MakeGenericMethod(toType));
  1010. return;
  1011. }
  1012. MethodInfo fastConvertMethod = PythonBinder.GetFastConvertMethod(toType);
  1013. if (fastConvertMethod != null) {
  1014. il.EmitCall(fastConvertMethod);
  1015. } else if (toType == typeof(void)) {
  1016. il.Emit(OpCodes.Pop);
  1017. } else if (typeof(Delegate).IsAssignableFrom(toType)) {
  1018. il.EmitType(toType);
  1019. il.EmitCall(typeof(Converter), "ConvertToDelegate");
  1020. il.Emit(OpCodes.Castclass, toType);
  1021. } else {
  1022. Label end = il.DefineLabel();
  1023. il.Emit(OpCodes.Dup);
  1024. il.Emit(OpCodes.Isinst, toType);
  1025. il.Emit(OpCodes.Brtrue_S, end);
  1026. il.Emit(OpCodes.Ldtoken, toType);
  1027. il.EmitCall(PythonBinder.GetGenericConvertMethod(toType));
  1028. il.MarkLabel(end);
  1029. il.Emit(OpCodes.Unbox_Any, toType); //??? this check may be redundant
  1030. }
  1031. }
  1032. private MethodBuilder CreateVTableSetterOverride(MethodInfo mi, string name) {
  1033. MethodBuilder impl;
  1034. ILGen il;
  1035. DefineVTableMethodOverride(mi, out impl, out il);
  1036. LocalBuilder callTarget = EmitBaseClassCallCheckForProperties(il, mi, name);
  1037. il.Emit(OpCodes.Ldloc, callTarget); // property
  1038. il.EmitLoadArg(0); // instance
  1039. il.EmitLoadArg(1);
  1040. il.EmitBoxing(mi.GetParameters()[0].ParameterType); // newValue
  1041. il.EmitString(name); // name
  1042. il.EmitCall(typeof(UserTypeOps), "SetPropertyHelper");
  1043. il.Emit(OpCodes.Ret);
  1044. _tg.DefineMethodOverride(impl, mi);
  1045. return impl;
  1046. }
  1047. private void CreateVTableEventOverride(MethodInfo mi, string name) {
  1048. // override the add/remove method
  1049. MethodBuilder impl;
  1050. ILGen il = DefineMethodOverride(mi, out impl);
  1051. LocalBuilder callTarget = EmitBaseClassCallCheckForEvents(il, mi, name);
  1052. il.Emit(OpCodes.Ldloc, callTarget);
  1053. il.EmitLoadArg(0);
  1054. il.EmitLoadArg(1);
  1055. il.EmitBoxing(mi.GetParameters()[0].ParameterType);
  1056. il.EmitString(name);
  1057. il.EmitCall(typeof(UserTypeOps), "AddRemoveEventHelper");
  1058. il.Emit(OpCodes.Ret);
  1059. _tg.DefineMethodOverride(impl, mi);
  1060. }
  1061. /// <summary>
  1062. /// Emits code to check if the class has overridden this specific
  1063. /// function. For example:
  1064. ///
  1065. /// MyDerivedType.SomeVirtualFunction = ...
  1066. /// or
  1067. ///
  1068. /// class MyDerivedType(MyBaseType):
  1069. /// def SomeVirtualFunction(self, ...):
  1070. ///
  1071. /// </summary>
  1072. private static LocalBuilder EmitBaseClassCallCheckForEvents(ILGen il, MethodInfo baseMethod, string name) {
  1073. Label instanceCall = il.DefineLabel();
  1074. LocalBuilder callTarget = il.DeclareLocal(typeof(object));
  1075. il.EmitLoadArg(0);
  1076. il.EmitString(name);
  1077. il.Emit(OpCodes.Ldloca, callTarget);
  1078. il.EmitCall(typeof(UserTypeOps), "TryGetNonInheritedValueHelper");
  1079. il.Emit(OpCodes.Brtrue, instanceCall);
  1080. EmitBaseMethodDispatch(baseMethod, il);
  1081. il.MarkLabel(instanceCall);
  1082. return callTarget;
  1083. }
  1084. private MethodBuilder CreateVTableMethodOverride(MethodInfo mi, string name) {
  1085. MethodBuilder impl;
  1086. ILGen il;
  1087. DefineVTableMethodOverride(mi, out impl, out il);
  1088. //CompilerHelpers.GetArgumentNames(parameters)); TODO: Set names
  1089. LocalBuilder callTarget = EmitNonInheritedMethodLookup(name, il);
  1090. Label instanceCall = il.DefineLabel();
  1091. il.Emit(OpCodes.Brtrue, instanceCall);
  1092. // lookup failed, call the base class method (this returns or throws)
  1093. EmitBaseMethodDispatch(mi, il);
  1094. // lookup succeeded, call the user defined method & return
  1095. il.MarkLabel(instanceCall);
  1096. EmitClrCallStub(il, mi, callTarget);
  1097. il.Emit(OpCodes.Ret);
  1098. if (mi.IsVirtual && !mi.IsFinal) {
  1099. _tg.DefineMethodOverride(impl, mi);
  1100. }
  1101. return impl;
  1102. }
  1103. private void DefineVTableMethodOverride(MethodInfo mi, out MethodBuilder impl, out ILGen il) {
  1104. if (mi.IsVirtual && !mi.IsFinal) {
  1105. il = DefineMethodOverride(MethodAttributes.Public, mi, out impl);
  1106. } else {
  1107. impl = _tg.DefineMethod(
  1108. mi.Name,
  1109. mi.IsVirtual ?
  1110. (mi.Attributes | MethodAttributes.NewSlot) :
  1111. ((mi.Attributes & ~MethodAttributes.MemberAccessMask) | MethodAttributes.Public),
  1112. mi.CallingConvention
  1113. );
  1114. ReflectionUtils.CopyMethodSignature(mi, impl, false);
  1115. il = new ILGen(impl.GetILGenerator());
  1116. }
  1117. }
  1118. /// <summary>
  1119. /// Emits the call to lookup a member defined in the user's type. Returns
  1120. /// the local which stores the resulting value and leaves a value on the
  1121. /// stack indicating the success of the lookup.
  1122. /// </summary>
  1123. private LocalBuilder EmitNonInheritedMethodLookup(string name, ILGen il) {
  1124. LocalBuilder callTarget = il.DeclareLocal(typeof(object));
  1125. // emit call to helper to do lookup
  1126. il.EmitLoadArg(0);
  1127. if (typeof(IPythonObject).IsAssignableFrom(_baseType)) {
  1128. Debug.Assert(_typeField == null);
  1129. il.EmitPropertyGet(PythonTypeInfo._IPythonObject.PythonType);
  1130. } else {
  1131. il.EmitFieldGet(_typeField);
  1132. }
  1133. il.EmitLoadArg(0);
  1134. il.EmitString(name);
  1135. il.Emit(OpCodes.Ldloca, callTarget);
  1136. il.EmitCall(typeof(UserTypeOps), "TryGetNonInheritedMethodHelper");
  1137. return callTarget;
  1138. }
  1139. /// <summary>
  1140. /// Creates a method for doing a base method dispatch. This is used to support
  1141. /// super(type, obj) calls.
  1142. /// </summary>
  1143. private MethodBuilder CreateSuperCallHelper(MethodInfo mi) {
  1144. MethodAttributes attrs = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName;
  1145. if (mi.IsStatic) {
  1146. attrs |= MethodAttributes.Static;
  1147. }
  1148. MethodBuilder method = _tg.DefineMethod(BaseMethodPrefix + mi.Name, attrs, mi.CallingConvention);
  1149. ReflectionUtils.CopyMethodSignature(mi, method, true);
  1150. EmitBaseMethodDispatch(mi, new ILGen(method.GetILGenerator()));
  1151. return method;
  1152. }
  1153. private KeyValuePair<Type, Dictionary<string, string[]>> SaveType(AssemblyGen ag, string name) {
  1154. _tg = ag.DefinePublicType(TypePrefix + name, _baseType, true);
  1155. Dictionary<string, string[]> specialNames = ImplementType();
  1156. Type ret = FinishType();
  1157. return new KeyValuePair<Type, Dictionary<string, string[]>>(ret, specialNames);
  1158. }
  1159. private Type FinishType() {
  1160. if (_cctor != null) {
  1161. _cctor.Emit(OpCodes.Ret);
  1162. }
  1163. return _tg.CreateType();
  1164. }
  1165. private ILGen DefineExplicitInterfaceImplementation(MethodInfo baseMethod, out MethodBuilder builder) {
  1166. MethodAttributes attrs = baseMethod.Attributes & ~(MethodAttributes.Abstract | MethodAttributes.Public);
  1167. attrs |= MethodAttributes.NewSlot | MethodAttributes.Final;
  1168. Type[] baseSignature = ReflectionUtils.GetParameterTypes(baseMethod.GetParameters());
  1169. builder = _tg.DefineMethod(
  1170. baseMethod.DeclaringType.Name + "." + baseMethod.Name,
  1171. attrs,
  1172. baseMethod.ReturnType,
  1173. baseSignature
  1174. );
  1175. return new ILGen(builder.GetILGenerator());
  1176. }
  1177. private const MethodAttributes MethodAttributesReservedMask = (MethodAttributes)0xD000; // MethodAttributes.ReservedMask
  1178. private const MethodAttributes MethodAttributesToEraseInOveride = MethodAttributes.Abstract | MethodAttributesReservedMask;
  1179. private ILGen DefineMethodOverride(MethodAttributes extra, Type type, string name, out MethodInfo decl, out MethodBuilder impl) {
  1180. decl = type.GetMethod(name);
  1181. return DefineMethodOverride(extra, decl, out impl);
  1182. }
  1183. private ILGen DefineMethodOverride(MethodInfo decl, out MethodBuilder impl) {
  1184. return DefineMethodOverride(MethodAttributes.PrivateScope, decl, out impl);
  1185. }
  1186. private ILGen DefineMethodOverride(MethodAttributes extra, MethodInfo decl, out MethodBuilder impl) {
  1187. impl = ReflectionUtils.DefineMethodOverride(_tg, extra, decl);
  1188. return new ILGen(impl.GetILGenerator());
  1189. }
  1190. /// <summary>
  1191. /// Generates stub to receive the CLR call and then call the dynamic language code.
  1192. /// This code is same as StubGenerator.cs in the Microsoft.Scripting, except it
  1193. /// accepts ILGen instead of Compiler.
  1194. /// </summary>
  1195. private void EmitClrCallStub(ILGen il, MethodInfo mi, LocalBuilder callTarget) {
  1196. int firstArg = 0;
  1197. bool list = false; // The list calling convention
  1198. bool context = false; // Context is an argument
  1199. ParameterInfo[] pis = mi.GetParameters();
  1200. if (pis.Length > 0) {
  1201. if (pis[0].ParameterType == typeof(CodeContext)) {
  1202. firstArg = 1;
  1203. context = true;
  1204. }
  1205. if (pis[pis.Length - 1].IsDefined(typeof(ParamArrayAttribute), false)) {
  1206. list = true;
  1207. }
  1208. }
  1209. ParameterInfo[] args = pis;
  1210. int nargs = args.Length - firstArg;
  1211. Type[] genericArgs = mi.GetGenericArguments();
  1212. // Create the action
  1213. ILGen cctor = GetCCtor();
  1214. if (list || genericArgs.Length > 0) {
  1215. // Use a complex call signature that includes param array and keywords
  1216. cctor.EmitInt(nargs);
  1217. cctor.EmitBoolean(list);
  1218. // Emit an array of keyword names:
  1219. cctor.EmitInt(genericArgs.Length);
  1220. cctor.Emit(OpCodes.Newarr, typeof(string));
  1221. for (int i = 0; i < genericArgs.Length; i++) {
  1222. cctor.Emit(OpCodes.Dup);
  1223. cctor.EmitInt(i);
  1224. cctor.Emit(OpCodes.Ldelema, typeof(string));
  1225. cctor.Emit(OpCodes.Ldstr, genericArgs[i].Name);
  1226. cctor.Emit(OpCodes.Stobj, typeof(string));
  1227. }
  1228. cctor.EmitCall(typeof(PythonOps).GetMethod("MakeComplexCallAction"));
  1229. } else {
  1230. cctor.EmitInt(nargs);
  1231. cctor.EmitCall(typeof(PythonOps).GetMethod("MakeSimpleCallAction"));
  1232. }
  1233. // Create the dynamic site
  1234. Type siteType = CompilerHelpers.MakeCallSiteType(MakeSiteSignature(nargs + genericArgs.Length));
  1235. FieldBuilder site = _tg.DefineField("site$" + _site++, siteType, FieldAttributes.Private | FieldAttributes.Static);
  1236. cctor.EmitCall(siteType.GetMethod("Create"));
  1237. cctor.EmitFieldSet(site);
  1238. List<ReturnFixer> fixers = new List<ReturnFixer>(0);
  1239. //
  1240. // Emit the site invoke
  1241. //
  1242. il.EmitFieldGet(site);
  1243. FieldInfo target = siteType.GetDeclaredField("Target");
  1244. il.EmitFieldGet(target);
  1245. il.EmitFieldGet(site);
  1246. // Emit the code context
  1247. EmitCodeContext(il, context);
  1248. il.Emit(OpCodes.Ldloc, callTarget);
  1249. for (int i = firstArg; i < args.Length; i++) {
  1250. ReturnFixer rf = ReturnFixer.EmitArgument(il, args[i], i + 1);
  1251. if (rf != null) {
  1252. fixers.Add(rf);
  1253. }
  1254. }
  1255. for (int i = 0; i < genericArgs.Length; i++) {
  1256. il.EmitType(genericArgs[i]);
  1257. il.EmitCall(typeof(DynamicHelpers).GetMethod("GetPythonTypeFromType"));
  1258. }
  1259. il.EmitCall(target.FieldType, "Invoke");
  1260. foreach (ReturnFixer rf in fixers) {
  1261. rf.FixReturn(il);
  1262. }
  1263. EmitConvertFromObject(il, mi.ReturnType);
  1264. }
  1265. private static void EmitCodeContext(ILGen il, bool context) {
  1266. if (context) {
  1267. il.EmitLoadArg(1);
  1268. } else {
  1269. il.EmitPropertyGet(typeof(DefaultContext).GetProperty("Default"));
  1270. }
  1271. }
  1272. private static void EmitInt(ILGenerator ilg, int iVal) {
  1273. switch (iVal) {
  1274. case 0: ilg.Emit(OpCodes.Ldc_I4_0); break;
  1275. case 1: ilg.Emit(OpCodes.Ldc_I4_1); break;
  1276. case 2: ilg.Emit(OpCodes.Ldc_I4_2); break;
  1277. case 3: ilg.Emit(OpCodes.Ldc_I4_3); break;
  1278. case 4: ilg.Emit(OpCodes.Ldc_I4_4); break;
  1279. case 5: ilg.Emit(OpCodes.Ldc_I4_5); break;
  1280. case 6: ilg.Emit(OpCodes.Ldc_I4_6); break;
  1281. case 7: ilg.Emit(OpCodes.Ldc_I4_7); break;
  1282. case 8: ilg.Emit(OpCodes.Ldc_I4_8); break;
  1283. default: ilg.Emit(OpCodes.Ldc_I4, iVal); break;
  1284. }
  1285. }
  1286. private static Type[] MakeSiteSignature(int nargs) {
  1287. Type[] sig = new Type[nargs + 4];
  1288. sig[0] = typeof(CallSite);
  1289. sig[1] = typeof(CodeContext);
  1290. for (int i = 2; i < sig.Length; i++) {
  1291. sig[i] = typeof(object);
  1292. }
  1293. return sig;
  1294. }
  1295. #endif
  1296. #endregion
  1297. #region Base type helper data updates
  1298. private static void AddBaseMethods(Type finishedType, Dictionary<string, string[]> specialNames) {
  1299. // "Adds" base methods to super type - this makes super(...).xyz to work - otherwise
  1300. // we'd return a function that did a virtual call resulting in a stack overflow.
  1301. // The addition is to a seperate cache that NewTypeMaker maintains. TypeInfo consults this
  1302. // cache when doing member lookup and includes these members in the returned members.
  1303. foreach (MethodInfo mi in finishedType.GetMethods()) {
  1304. if (IsInstanceType(finishedType.GetTypeInfo().BaseType) && IsInstanceType(mi.DeclaringType)) continue;
  1305. string methodName = mi.Name;
  1306. if (methodName.StartsWith(BaseMethodPrefix) || methodName.StartsWith(FieldGetterPrefix) || methodName.StartsWith(FieldSetterPrefix)) {
  1307. foreach (string newName in GetBaseName(mi, specialNames)) {
  1308. if (mi.IsSpecialName && (newName.StartsWith("get_") || newName.StartsWith("set_"))) {
  1309. // if it's a property we want to override it
  1310. string propName = newName.Substring(4);
  1311. MemberInfo[] defaults = finishedType.GetTypeInfo().BaseType.GetDefaultMembers();
  1312. if (defaults.Length > 0) {
  1313. // if it's an indexer then we want to override get_Item/set_Item methods
  1314. // which map to __getitem__ and __setitem__ as normal Python methods.
  1315. foreach (MemberInfo method in defaults) {
  1316. if (method.Name == propName) {
  1317. StoreOverriddenMethod(mi, newName);
  1318. break;
  1319. }
  1320. }
  1321. }
  1322. StoreOverriddenProperty(mi, newName);
  1323. } else if (mi.IsSpecialName && (newName.StartsWith(FieldGetterPrefix) || newName.StartsWith(FieldSetterPrefix))) {
  1324. StoreOverriddenField(mi, newName);
  1325. } else {
  1326. // not a property, just store the overridden method.
  1327. StoreOverriddenMethod(mi, newName);
  1328. }
  1329. }
  1330. }
  1331. }
  1332. }
  1333. private static void StoreOverriddenField(MethodInfo mi, string newName) {
  1334. Type baseType = mi.DeclaringType.GetBaseType();
  1335. string fieldName = newName.Substring(FieldGetterPrefix.Length); // get_ or set_
  1336. lock (PythonTypeOps._propertyCache) {
  1337. foreach (FieldInfo pi in baseType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy)) {
  1338. if (pi.Name == fieldName) {
  1339. if (newName.StartsWith(FieldGetterPrefix)) {
  1340. AddPropertyInfo(pi.DeclaringType, fieldName, mi, null);
  1341. } else if (newName.StartsWith(FieldSetterPrefix)) {
  1342. AddPropertyInfo(pi.DeclaringType, fieldName, null, mi);
  1343. }
  1344. }
  1345. }
  1346. }
  1347. }
  1348. private static ExtensionPropertyTracker AddPropertyInfo(Type baseType, string/*!*/ propName, MethodInfo get, MethodInfo set) {
  1349. MethodInfo mi = get ?? set;
  1350. Dictionary<string, List<ExtensionPropertyTracker>> propInfoList;
  1351. if (!_overriddenProperties.TryGetValue(baseType, out propInfoList)) {
  1352. _overriddenProperties[baseType] = propInfoList = new Dictionary<string, List<ExtensionPropertyTracker>>();
  1353. }
  1354. List<ExtensionPropertyTracker> trackers;
  1355. if (!propInfoList.TryGetValue(propName, out trackers)) {
  1356. propInfoList[propName] = trackers = new List<ExtensionPropertyTracker>();
  1357. }
  1358. ExtensionPropertyTracker res;
  1359. for (int i = 0; i < trackers.Count; i++) {
  1360. if (trackers[i].DeclaringType == mi.DeclaringType) {
  1361. trackers[i] = res = new ExtensionPropertyTracker(
  1362. propName,
  1363. get ?? trackers[i].GetGetMethod(),
  1364. set ?? trackers[i].GetSetMethod(),
  1365. null,
  1366. mi.DeclaringType
  1367. );
  1368. return res;
  1369. }
  1370. }
  1371. trackers.Add(
  1372. res = new ExtensionPropertyTracker(
  1373. propName,
  1374. mi,
  1375. null,
  1376. null,
  1377. mi.DeclaringType
  1378. )
  1379. );
  1380. return res;
  1381. }
  1382. private static void StoreOverriddenMethod(MethodInfo mi, string newName) {
  1383. Type baseType = mi.DeclaringType.GetBaseType();
  1384. MemberInfo[] members = baseType.GetMember(newName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy);
  1385. Debug.Assert(members.Length > 0, String.Format("{0} from {1}", newName, baseType.Name));
  1386. Type declType = ((MethodInfo)members[0]).GetBaseDefinition().DeclaringType;
  1387. string pythonName = newName;
  1388. switch (newName) {
  1389. case "get_Item": pythonName = "__getitem__"; break;
  1390. case "set_Item": pythonName = "__setitem__"; break;
  1391. }
  1392. // back-patch any existing functions so that cached rules will work
  1393. // when called again...
  1394. lock (PythonTypeOps._functions) {
  1395. foreach (BuiltinFunction bf in PythonTypeOps._functions.Values) {
  1396. if (bf.Name == pythonName && bf.DeclaringType == declType) {
  1397. bf.AddMethod(mi);
  1398. break;
  1399. }
  1400. }
  1401. Dictionary<string, List<MethodInfo>> overrideInfo;
  1402. if (!_overriddenMethods.TryGetValue(declType, out overrideInfo)) {
  1403. _overriddenMethods[declType] = overrideInfo = new Dictionary<string, List<MethodInfo>>();
  1404. }
  1405. List<MethodInfo> methods;
  1406. if (!overrideInfo.TryGetValue(pythonName, out methods)) {
  1407. overrideInfo[pythonName] = methods = new List<MethodInfo>();
  1408. }
  1409. methods.Add(mi);
  1410. }
  1411. }
  1412. private static void StoreOverriddenProperty(MethodInfo mi, string newName) {
  1413. Type baseType = mi.DeclaringType.GetBaseType();
  1414. lock (PythonTypeOps._propertyCache) {
  1415. string propName = newName.Substring(4); // get_ or set_
  1416. ExtensionPropertyTracker newProp = null;
  1417. foreach (PropertyInfo pi in baseType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy)) {
  1418. if (pi.Name == propName) {
  1419. Type declType = pi.DeclaringType;
  1420. if (newName.StartsWith("get_")) {
  1421. newProp = AddPropertyInfo(declType, propName, mi, null);
  1422. } else if (newName.StartsWith("set_")) {
  1423. newProp = AddPropertyInfo(declType, propName, null, mi);
  1424. }
  1425. }
  1426. }
  1427. if (newProp != null) {
  1428. // back-patch any existing properties so that cached rules will work
  1429. // when called again...
  1430. foreach (ReflectedGetterSetter rg in PythonTypeOps._propertyCache.Values) {
  1431. if (rg.DeclaringType != baseType ||
  1432. rg.__name__ != newProp.Name) {
  1433. continue;
  1434. }
  1435. if (newProp.GetGetMethod(true) != null) {
  1436. rg.AddGetter(newProp.GetGetMethod(true));
  1437. }
  1438. if (newProp.GetSetMethod(true) != null) {
  1439. rg.AddSetter(newProp.GetSetMethod(true));
  1440. }
  1441. }
  1442. }
  1443. }
  1444. }
  1445. private static IEnumerable<string> GetBaseName(MethodInfo mi, Dictionary<string, string[]> specialNames) {
  1446. string newName;
  1447. if (mi.Name.StartsWith(BaseMethodPrefix)) {
  1448. newName = mi.Name.Substring(BaseMethodPrefix.Length);
  1449. } else if (mi.Name.StartsWith(FieldGetterPrefix)) {
  1450. newName = mi.Name.Substring(FieldGetterPrefix.Length);
  1451. } else if (mi.Name.StartsWith(FieldSetterPrefix)) {
  1452. newName = mi.Name.Substring(FieldSetterPrefix.Length);
  1453. } else {
  1454. throw new InvalidOperationException();
  1455. }
  1456. Debug.Assert(specialNames.ContainsKey(newName));
  1457. return specialNames[newName];
  1458. }
  1459. /// <summary>
  1460. /// Called from PythonTypeOps - the BuiltinFunction._function lock must be held.
  1461. /// </summary>
  1462. internal static IList<MethodInfo> GetOverriddenMethods(Type type, string name) {
  1463. Dictionary<string, List<MethodInfo>> methods;
  1464. List<MethodInfo> res = null;
  1465. Type curType = type;
  1466. while (curType != null) {
  1467. if (_overriddenMethods.TryGetValue(curType, out methods)) {
  1468. List<MethodInfo> methodList;
  1469. if (methods.TryGetValue(name, out methodList)) {
  1470. if (res == null) {
  1471. res = new List<MethodInfo>(methodList.Count);
  1472. }
  1473. foreach (MethodInfo method in methodList) {
  1474. if (type.IsAssignableFrom(method.DeclaringType)) {
  1475. res.Add(method);
  1476. }
  1477. }
  1478. }
  1479. }
  1480. curType = curType.GetBaseType();
  1481. }
  1482. if (res != null) {
  1483. return res;
  1484. }
  1485. return new MethodInfo[0];
  1486. }
  1487. internal static IList<ExtensionPropertyTracker> GetOverriddenProperties(Type type, string name) {
  1488. lock (_overriddenProperties) {
  1489. Dictionary<string, List<ExtensionPropertyTracker>> props;
  1490. if (_overriddenProperties.TryGetValue(type, out props)) {
  1491. List<ExtensionPropertyTracker> propList;
  1492. if (props.TryGetValue(name, out propList)) {
  1493. return propList;
  1494. }
  1495. }
  1496. }
  1497. return new ExtensionPropertyTracker[0];
  1498. }
  1499. #endregion
  1500. }
  1501. /// <summary>
  1502. /// Same as the DLR ReturnFixer, but accepts lower level constructs,
  1503. /// such as LocalBuilder, ParameterInfos and ILGen.
  1504. /// </summary>
  1505. sealed class ReturnFixer {
  1506. private readonly ParameterInfo _parameter;
  1507. private readonly LocalBuilder _reference;
  1508. private readonly int _index;
  1509. private ReturnFixer(LocalBuilder reference, ParameterInfo parameter, int index) {
  1510. Debug.Assert(reference.LocalType.IsGenericType() && reference.LocalType.GetGenericTypeDefinition() == typeof(StrongBox<>));
  1511. Debug.Assert(parameter.ParameterType.IsByRef);
  1512. _parameter = parameter;
  1513. _reference = reference;
  1514. _index = index;
  1515. }
  1516. public void FixReturn(ILGen il) {
  1517. il.EmitLoadArg(_index);
  1518. il.Emit(OpCodes.Ldloc, _reference);
  1519. il.EmitFieldGet(_reference.LocalType.GetDeclaredField("Value"));
  1520. il.EmitStoreValueIndirect(_parameter.ParameterType.GetElementType());
  1521. }
  1522. public static ReturnFixer EmitArgument(ILGen il, ParameterInfo parameter, int index) {
  1523. il.EmitLoadArg(index);
  1524. if (parameter.ParameterType.IsByRef) {
  1525. Type elementType = parameter.ParameterType.GetElementType();
  1526. Type concreteType = typeof(StrongBox<>).MakeGenericType(elementType);
  1527. LocalBuilder refSlot = il.DeclareLocal(concreteType);
  1528. il.EmitLoadValueIndirect(elementType);
  1529. ConstructorInfo ci = concreteType.GetConstructor(new Type[] { elementType });
  1530. il.Emit(OpCodes.Newobj, ci);
  1531. il.Emit(OpCodes.Stloc, refSlot);
  1532. il.Emit(OpCodes.Ldloc, refSlot);
  1533. return new ReturnFixer(refSlot, parameter, index);
  1534. } else {
  1535. il.EmitBoxing(parameter.ParameterType);
  1536. return null;
  1537. }
  1538. }
  1539. }
  1540. }