PageRenderTime 46ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/DICK.B1/IronPython/Runtime/Types/NewTypeMaker.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 1811 lines | 1309 code | 299 blank | 203 comment | 277 complexity | 25eec33db06fd76c3372af2dce9629b9 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.ComponentModel;
  18. using System.Diagnostics;
  19. using System.Reflection;
  20. using System.Reflection.Emit;
  21. using System.Runtime.CompilerServices;
  22. using System.Dynamic;
  23. using System.Text;
  24. using Microsoft.Scripting;
  25. using Microsoft.Scripting.Actions;
  26. using Microsoft.Scripting.Generation;
  27. using Microsoft.Scripting.Runtime;
  28. using Microsoft.Scripting.Utils;
  29. using IronPython.Runtime.Binding;
  30. using IronPython.Runtime.Operations;
  31. namespace IronPython.Runtime.Types {
  32. /// <summary>
  33. /// Python class hierarchy is represented using the __class__ field in the object. It does not
  34. /// use the CLI type system for pure Python types. However, Python types which inherit from a
  35. /// CLI type, or from a builtin Python type which is implemented in the engine by a CLI type,
  36. /// do have to use the CLI type system to interoperate with the CLI world. This means that
  37. /// objects of different Python types, but with the same CLI base type, can use the same CLI type -
  38. /// they will just have different values for the __class__ field.
  39. ///
  40. /// The easiest way to inspect the functionality implemented by NewTypeMaker is to persist the
  41. /// generated IL using "ipy.exe -X:SaveAssemblies", and then inspect the
  42. /// persisted IL using ildasm.
  43. /// </summary>
  44. sealed class NewTypeMaker {
  45. private Type _baseType;
  46. private TypeBuilder _tg;
  47. private FieldInfo _typeField;
  48. private FieldInfo _dictField;
  49. private FieldInfo _slotsField;
  50. private FieldInfo _explicitMO;
  51. private IList<Type> _interfaceTypes;
  52. private ILGen _cctor;
  53. private int _site;
  54. public const string VtableNamesField = "#VTableNames#";
  55. public const string TypePrefix = "IronPython.NewTypes.";
  56. public const string BaseMethodPrefix = "#base#";
  57. public const string FieldGetterPrefix = "#field_get#", FieldSetterPrefix = "#field_set#";
  58. public const string ClassFieldName = ".class", DictFieldName = ".dict", SlotsAndWeakRefFieldName = ".slots_and_weakref";
  59. private const string _constructorTypeName = "PythonCachedTypeConstructor";
  60. private const string _constructorMethodName = "GetTypeInfo";
  61. [MultiRuntimeAware]
  62. private static int _typeCount;
  63. [MultiRuntimeAware]
  64. internal static readonly Publisher<NewTypeInfo, Type> _newTypes = new Publisher<NewTypeInfo, Type>();
  65. [MultiRuntimeAware]
  66. private static readonly Dictionary<Type, Dictionary<string, List<MethodInfo>>> _overriddenMethods = new Dictionary<Type, Dictionary<string, List<MethodInfo>>>();
  67. [MultiRuntimeAware]
  68. private static readonly Dictionary<Type, Dictionary<string, List<ExtensionPropertyTracker>>> _overriddenProperties = new Dictionary<Type, Dictionary<string, List<ExtensionPropertyTracker>>>();
  69. private NewTypeMaker(NewTypeInfo typeInfo) {
  70. _baseType = typeInfo.BaseType;
  71. _interfaceTypes = typeInfo.InterfaceTypes;
  72. }
  73. #region Public API
  74. public static Type/*!*/ GetNewType(string/*!*/ typeName, PythonTuple/*!*/ bases) {
  75. Assert.NotNull(typeName, bases);
  76. NewTypeInfo typeInfo = NewTypeInfo.GetTypeInfo(typeName, bases);
  77. if (typeInfo.BaseType.IsValueType) {
  78. throw PythonOps.TypeError("cannot derive from {0} because it is a value type", typeInfo.BaseType.FullName);
  79. } else if (typeInfo.BaseType.IsSealed) {
  80. throw PythonOps.TypeError("cannot derive from {0} because it is sealed", typeInfo.BaseType.FullName);
  81. }
  82. Type ret = _newTypes.GetOrCreateValue(typeInfo,
  83. () => {
  84. if (typeInfo.InterfaceTypes.Count == 0) {
  85. // types that the have DynamicBaseType attribute can be used as NewType's directly, no
  86. // need to create a new type unless we're adding interfaces
  87. object[] attrs = typeInfo.BaseType.GetCustomAttributes(typeof(DynamicBaseTypeAttribute), false);
  88. if (attrs.Length > 0) {
  89. return typeInfo.BaseType;
  90. }
  91. }
  92. // creation code
  93. return new NewTypeMaker(typeInfo).CreateNewType();
  94. });
  95. return ret;
  96. }
  97. public static void SaveNewTypes(string assemblyName, IList<PythonTuple> types) {
  98. Assert.NotNull(assemblyName, types);
  99. AssemblyGen ag = new AssemblyGen(new AssemblyName(assemblyName), ".", ".dll", false);
  100. TypeBuilder tb = ag.DefinePublicType(_constructorTypeName, typeof(object), true);
  101. tb.SetCustomAttribute(typeof(PythonCachedTypeInfoAttribute).GetConstructor(Type.EmptyTypes), new byte[0]);
  102. MethodBuilder mb = tb.DefineMethod(_constructorMethodName, MethodAttributes.Public | MethodAttributes.Static, typeof(CachedNewTypeInfo[]), Type.EmptyTypes);
  103. ILGenerator ilg = mb.GetILGenerator();
  104. // new CachedTypeInfo[types.Count]
  105. // we leave this on the stack (duping it) and storing into it.
  106. EmitInt(ilg, types.Count);
  107. ilg.Emit(OpCodes.Newarr, typeof(CachedNewTypeInfo));
  108. int curType = 0;
  109. foreach (var v in types) {
  110. NewTypeInfo nti = NewTypeInfo.GetTypeInfo(String.Empty, v);
  111. var typeInfos = new NewTypeMaker(nti).SaveType(ag, "Python" + _typeCount++ + "$" + nti.BaseType.Name);
  112. // prepare for storing the element into our final array
  113. ilg.Emit(OpCodes.Dup);
  114. EmitInt(ilg, curType++);
  115. // new CachedNewTypeInfo(type, specialNames, interfaceTypes):
  116. // load the type
  117. ilg.Emit(OpCodes.Ldtoken, typeInfos.Key);
  118. ilg.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
  119. // create the dictionary<str, str[]> of special names
  120. ilg.Emit(OpCodes.Newobj, typeof(Dictionary<string, string[]>).GetConstructor(new Type[0]));
  121. foreach (var specialName in typeInfos.Value) {
  122. // dup dict
  123. ilg.Emit(OpCodes.Dup);
  124. // emit key
  125. ilg.Emit(OpCodes.Ldstr, specialName.Key);
  126. // emit value
  127. int iVal = specialName.Value.Length;
  128. EmitInt(ilg, iVal);
  129. ilg.Emit(OpCodes.Newarr, typeof(string));
  130. for (int i = 0; i < specialName.Value.Length; i++) {
  131. ilg.Emit(OpCodes.Dup);
  132. EmitInt(ilg, i);
  133. ilg.Emit(OpCodes.Ldstr, specialName.Value[0]);
  134. ilg.Emit(OpCodes.Stelem_Ref);
  135. }
  136. // assign to dict
  137. ilg.Emit(OpCodes.Call, typeof(Dictionary<string, string[]>).GetMethod("set_Item"));
  138. }
  139. // emit the interface types (if any)
  140. if (nti.InterfaceTypes.Count != 0) {
  141. EmitInt(ilg, nti.InterfaceTypes.Count);
  142. ilg.Emit(OpCodes.Newarr, typeof(Type));
  143. for (int i = 0; i < nti.InterfaceTypes.Count; i++) {
  144. ilg.Emit(OpCodes.Dup);
  145. EmitInt(ilg, i);
  146. ilg.Emit(OpCodes.Ldtoken, nti.InterfaceTypes[i]);
  147. ilg.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
  148. ilg.Emit(OpCodes.Stelem_Ref);
  149. }
  150. } else {
  151. ilg.Emit(OpCodes.Ldnull);
  152. }
  153. // crated the CachedNewTypeInfo and store it in the array
  154. ilg.Emit(OpCodes.Newobj, typeof(CachedNewTypeInfo).GetConstructors()[0]);
  155. ilg.Emit(OpCodes.Stelem_Ref);
  156. }
  157. ilg.Emit(OpCodes.Ret);
  158. tb.CreateType();
  159. ag.SaveAssembly();
  160. }
  161. /// <summary>
  162. /// Loads any available new types from the provided assembly and makes them
  163. /// available via the GetNewType API.
  164. /// </summary>
  165. public static void LoadNewTypes(Assembly/*!*/ asm) {
  166. Assert.NotNull(asm);
  167. Type t = asm.GetType(_constructorTypeName);
  168. if (t == null || !t.IsDefined(typeof(PythonCachedTypeInfoAttribute), false)) {
  169. return;
  170. }
  171. MethodInfo mi = t.GetMethod(_constructorMethodName);
  172. var typeInfo = (CachedNewTypeInfo[])mi.Invoke(null, new object[0]);
  173. foreach (var v in typeInfo) {
  174. _newTypes.GetOrCreateValue(
  175. new NewTypeInfo(v.Type.BaseType, v.InterfaceTypes),
  176. () => {
  177. // type wasn't already created, go ahead and publish
  178. // the info and return the type.
  179. AddBaseMethods(v.Type, v.SpecialNames);
  180. return v.Type;
  181. }
  182. );
  183. }
  184. }
  185. /// <summary>
  186. /// Is this a type used for instances Python types (and not for the types themselves)?
  187. /// </summary>
  188. public static bool IsInstanceType(Type type) {
  189. return type.FullName.IndexOf(NewTypeMaker.TypePrefix) == 0 ||
  190. // Users can create sub-types of instance-types using __clrtype__ without using
  191. // NewTypeMaker.TypePrefix
  192. ((type.BaseType != null) && IsInstanceType(type.BaseType));
  193. }
  194. #endregion
  195. #region Type Generation
  196. private Type CreateNewType() {
  197. string name = GetName();
  198. _tg = Snippets.Shared.DefinePublicType(TypePrefix + name, _baseType);
  199. Dictionary<string, string[]> specialNames = ImplementType();
  200. Type ret = FinishType();
  201. AddBaseMethods(ret, specialNames);
  202. return ret;
  203. }
  204. // Build a name which is unique to this TypeInfo.
  205. private string GetName() {
  206. StringBuilder name = new StringBuilder(_baseType.Namespace);
  207. name.Append('.');
  208. name.Append(_baseType.Name);
  209. foreach (Type interfaceType in _interfaceTypes) {
  210. name.Append("#");
  211. name.Append(interfaceType.Name);
  212. }
  213. name.Append("_");
  214. name.Append(System.Threading.Interlocked.Increment(ref _typeCount));
  215. return name.ToString();
  216. }
  217. private Dictionary<string, string[]> ImplementType() {
  218. DefineInterfaces();
  219. ImplementPythonObject();
  220. ImplementConstructors();
  221. Dictionary<string, string[]> specialNames = new Dictionary<string, string[]>();
  222. OverrideMethods(_baseType, specialNames);
  223. ImplementProtectedFieldAccessors(specialNames);
  224. Dictionary<Type, bool> doneTypes = new Dictionary<Type, bool>();
  225. foreach (Type interfaceType in _interfaceTypes) {
  226. DoInterfaceType(interfaceType, doneTypes, specialNames);
  227. }
  228. return specialNames;
  229. }
  230. private void DefineInterfaces() {
  231. foreach (Type interfaceType in _interfaceTypes) {
  232. ImplementInterface(interfaceType);
  233. }
  234. }
  235. private void ImplementInterface(Type interfaceType) {
  236. _tg.AddInterfaceImplementation(interfaceType);
  237. }
  238. private void ImplementPythonObject() {
  239. ImplementIPythonObject();
  240. ImplementDynamicObject();
  241. #if !SILVERLIGHT // ICustomTypeDescriptor
  242. ImplementCustomTypeDescriptor();
  243. #endif
  244. #if CLR2
  245. ImplementPythonEquals();
  246. #endif
  247. ImplementWeakReference();
  248. AddDebugView();
  249. }
  250. private void AddDebugView() {
  251. _tg.SetCustomAttribute(
  252. new CustomAttributeBuilder(
  253. typeof(DebuggerTypeProxyAttribute).GetConstructor(new[] { typeof(Type) }),
  254. new object[] { typeof(UserTypeDebugView) }
  255. )
  256. );
  257. _tg.SetCustomAttribute(
  258. new CustomAttributeBuilder(
  259. typeof(DebuggerDisplayAttribute).GetConstructor(new[] { typeof(string) }),
  260. new object[] { "{get_PythonType().GetTypeDebuggerDisplay()}" }
  261. )
  262. );
  263. }
  264. private void EmitGetDict(ILGen gen) {
  265. gen.EmitFieldGet(_dictField);
  266. }
  267. private void EmitSetDict(ILGen gen) {
  268. gen.EmitFieldSet(_dictField);
  269. }
  270. private ParameterInfo[] GetOverrideCtorSignature(ParameterInfo[] original) {
  271. if (typeof(IPythonObject).IsAssignableFrom(_baseType)) {
  272. return original;
  273. }
  274. ParameterInfo[] argTypes = new ParameterInfo[original.Length + 1];
  275. if (original.Length == 0 || original[0].ParameterType != typeof(CodeContext)) {
  276. argTypes[0] = new ParameterInfoWrapper(typeof(PythonType), "cls");
  277. Array.Copy(original, 0, argTypes, 1, argTypes.Length - 1);
  278. } else {
  279. argTypes[0] = original[0];
  280. argTypes[1] = new ParameterInfoWrapper(typeof(PythonType), "cls");
  281. Array.Copy(original, 1, argTypes, 2, argTypes.Length - 2);
  282. }
  283. return argTypes;
  284. }
  285. private void ImplementConstructors() {
  286. ConstructorInfo[] constructors;
  287. constructors = _baseType.GetConstructors(BindingFlags.Public |
  288. BindingFlags.NonPublic |
  289. BindingFlags.Instance
  290. );
  291. foreach (ConstructorInfo ci in constructors) {
  292. if (ci.IsPublic || ci.IsProtected()) {
  293. OverrideConstructor(ci);
  294. }
  295. }
  296. }
  297. private static bool CanOverrideMethod(MethodInfo mi) {
  298. #if !SILVERLIGHT
  299. return true;
  300. #else
  301. // can only override the method if it is not SecurityCritical
  302. return mi.GetCustomAttributes(typeof(System.Security.SecurityCriticalAttribute), false).Length == 0;
  303. #endif
  304. }
  305. private void DoInterfaceType(Type interfaceType, Dictionary<Type, bool> doneTypes, Dictionary<string, string[]> specialNames) {
  306. if (interfaceType == typeof(IDynamicMetaObjectProvider)) {
  307. // very tricky, we'll handle it when we're creating
  308. // our own IDynamicMetaObjectProvider interface
  309. return;
  310. }
  311. if (doneTypes.ContainsKey(interfaceType)) return;
  312. doneTypes.Add(interfaceType, true);
  313. OverrideMethods(interfaceType, specialNames);
  314. foreach (Type t in interfaceType.GetInterfaces()) {
  315. DoInterfaceType(t, doneTypes, specialNames);
  316. }
  317. }
  318. private void OverrideConstructor(ConstructorInfo parentConstructor) {
  319. ParameterInfo[] pis = parentConstructor.GetParameters();
  320. if (pis.Length == 0 && typeof(IPythonObject).IsAssignableFrom(_baseType)) {
  321. // default ctor on a base type, don't override this one, it assumes
  322. // the PythonType is some default value and we'll always be unique.
  323. return;
  324. }
  325. ParameterInfo[] overrideParams = GetOverrideCtorSignature(pis);
  326. Type[] argTypes = new Type[overrideParams.Length];
  327. string[] paramNames = new string[overrideParams.Length];
  328. for (int i = 0; i < overrideParams.Length; i++) {
  329. argTypes[i] = overrideParams[i].ParameterType;
  330. paramNames[i] = overrideParams[i].Name;
  331. }
  332. ConstructorBuilder cb = _tg.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, argTypes);
  333. for (int i = 0; i < overrideParams.Length; i++) {
  334. ParameterBuilder pb = cb.DefineParameter(i + 1,
  335. overrideParams[i].Attributes,
  336. overrideParams[i].Name);
  337. int origIndex = GetOriginalIndex(pis, overrideParams, i);
  338. if (origIndex >= 0) {
  339. if (pis[origIndex].IsDefined(typeof(ParamArrayAttribute), false)) {
  340. pb.SetCustomAttribute(new CustomAttributeBuilder(
  341. typeof(ParamArrayAttribute).GetConstructor(Type.EmptyTypes), ArrayUtils.EmptyObjects));
  342. } else if (pis[origIndex].IsDefined(typeof(ParamDictionaryAttribute), false)) {
  343. pb.SetCustomAttribute(new CustomAttributeBuilder(
  344. typeof(ParamDictionaryAttribute).GetConstructor(Type.EmptyTypes), ArrayUtils.EmptyObjects));
  345. }
  346. if ((pis[origIndex].Attributes & ParameterAttributes.HasDefault) != 0) {
  347. pb.SetConstant(pis[origIndex].DefaultValue);
  348. }
  349. }
  350. }
  351. ILGen il = new ILGen(cb.GetILGenerator());
  352. int typeArg;
  353. if (pis.Length == 0 || pis[0].ParameterType != typeof(CodeContext)) {
  354. typeArg = 1;
  355. } else {
  356. typeArg = 2;
  357. }
  358. // this.__class__ = <arg?>
  359. // can occur 2 ways:
  360. // 1. If we have our own _typeField then we set it
  361. // 2. If we're a subclass of IPythonObject (e.g. one of our exception classes) then we'll flow it to the
  362. // base type constructor which will set it.
  363. if (!typeof(IPythonObject).IsAssignableFrom(_baseType)) {
  364. il.EmitLoadArg(0);
  365. // base class could have CodeContext parameter in which case our type is the 2nd parameter.
  366. il.EmitLoadArg(typeArg);
  367. il.EmitFieldSet(_typeField);
  368. }
  369. if (_explicitMO != null) {
  370. il.Emit(OpCodes.Ldarg_0);
  371. il.EmitNew(_explicitMO.FieldType.GetConstructor(Type.EmptyTypes));
  372. il.Emit(OpCodes.Stfld, _explicitMO);
  373. }
  374. // initialize all slots to Uninitialized.instance
  375. MethodInfo init = typeof(PythonOps).GetMethod("InitializeUserTypeSlots");
  376. il.EmitLoadArg(0);
  377. il.EmitLoadArg(typeArg);
  378. il.EmitCall(init);
  379. Debug.Assert(_slotsField != null);
  380. il.EmitFieldSet(_slotsField);
  381. CallBaseConstructor(parentConstructor, pis, overrideParams, il);
  382. }
  383. /// <summary>
  384. /// Gets the position for the parameter which we are overriding.
  385. /// </summary>
  386. /// <param name="pis"></param>
  387. /// <param name="overrideParams"></param>
  388. /// <param name="i"></param>
  389. /// <returns></returns>
  390. private static int GetOriginalIndex(ParameterInfo[] pis, ParameterInfo[] overrideParams, int i) {
  391. if (pis.Length == 0 || pis[0].ParameterType != typeof(CodeContext)) {
  392. return i - (overrideParams.Length - pis.Length);
  393. }
  394. // context & cls are swapped, context comes first.
  395. if (i == 1) return -1;
  396. if (i == 0) return 0;
  397. return i - (overrideParams.Length - pis.Length);
  398. }
  399. private static void CallBaseConstructor(ConstructorInfo parentConstructor, ParameterInfo[] pis, ParameterInfo[] overrideParams, ILGen il) {
  400. il.EmitLoadArg(0);
  401. #if DEBUG
  402. int lastIndex = -1;
  403. #endif
  404. for (int i = 0; i < overrideParams.Length; i++) {
  405. int index = GetOriginalIndex(pis, overrideParams, i);
  406. #if DEBUG
  407. // we insert a new parameter (the class) but the parametrers should
  408. // still remain in the same order after the extra parameter is removed.
  409. if (index >= 0) {
  410. Debug.Assert(index > lastIndex);
  411. lastIndex = index;
  412. }
  413. #endif
  414. if (index >= 0) {
  415. il.EmitLoadArg(i + 1);
  416. }
  417. }
  418. il.Emit(OpCodes.Call, parentConstructor);
  419. il.Emit(OpCodes.Ret);
  420. }
  421. ILGen GetCCtor() {
  422. if (_cctor == null) {
  423. ConstructorBuilder cctor = _tg.DefineTypeInitializer();
  424. _cctor = new ILGen(cctor.GetILGenerator());
  425. }
  426. return _cctor;
  427. }
  428. #if !SILVERLIGHT // ICustomTypeDescriptor
  429. private void ImplementCustomTypeDescriptor() {
  430. ImplementInterface(typeof(ICustomTypeDescriptor));
  431. foreach (MethodInfo m in typeof(ICustomTypeDescriptor).GetMethods()) {
  432. ImplementCTDOverride(m);
  433. }
  434. }
  435. private void ImplementCTDOverride(MethodInfo m) {
  436. MethodBuilder builder;
  437. ILGen il = DefineExplicitInterfaceImplementation(m, out builder);
  438. il.EmitLoadArg(0);
  439. ParameterInfo[] pis = m.GetParameters();
  440. Type[] paramTypes = new Type[pis.Length + 1];
  441. paramTypes[0] = typeof(object);
  442. for (int i = 0; i < pis.Length; i++) {
  443. il.EmitLoadArg(i + 1);
  444. paramTypes[i + 1] = pis[i].ParameterType;
  445. }
  446. il.EmitCall(typeof(CustomTypeDescHelpers), m.Name, paramTypes);
  447. il.EmitBoxing(m.ReturnType);
  448. il.Emit(OpCodes.Ret);
  449. _tg.DefineMethodOverride(builder, m);
  450. }
  451. #endif
  452. private bool NeedsPythonObject {
  453. get {
  454. return !typeof(IPythonObject).IsAssignableFrom(_baseType);
  455. }
  456. }
  457. private void ImplementDynamicObject() {
  458. // true if the user has explicitly included IDynamicMetaObjectProvider in the list of interfaces
  459. bool explicitDynamicObject = false;
  460. foreach (Type t in _interfaceTypes) {
  461. if (t == typeof(IDynamicMetaObjectProvider)) {
  462. explicitDynamicObject = true;
  463. break;
  464. }
  465. }
  466. // true if our base type implements IDMOP already
  467. bool baseIdo = typeof(IDynamicMetaObjectProvider).IsAssignableFrom(_baseType);
  468. if (baseIdo) {
  469. InterfaceMapping mapping = _baseType.GetInterfaceMap(typeof(IDynamicMetaObjectProvider));
  470. if (mapping.TargetMethods[0].IsPrivate) {
  471. // explicitly implemented IDynamicMetaObjectProvider, we cannot override it.
  472. if (_baseType.IsDefined(typeof(DynamicBaseTypeAttribute), true)) {
  473. // but it's been implemented by IronPython so it's going to return a MetaUserObject
  474. return;
  475. }
  476. // we can't dispatch to the subclasses IDMOP implementation, completely
  477. // replace it with our own.
  478. baseIdo = false;
  479. }
  480. }
  481. ImplementInterface(typeof(IDynamicMetaObjectProvider));
  482. MethodInfo decl;
  483. MethodBuilder impl;
  484. ILGen il = DefineMethodOverride(MethodAttributes.Private, typeof(IDynamicMetaObjectProvider), "GetMetaObject", out decl, out impl);
  485. MethodInfo mi = typeof(UserTypeOps).GetMethod("GetMetaObjectHelper");
  486. LocalBuilder retVal = il.DeclareLocal(typeof(DynamicMetaObject));
  487. Label retLabel = il.DefineLabel();
  488. if (explicitDynamicObject) {
  489. _explicitMO = _tg.DefineField("__gettingMO", typeof(ThreadLocal<bool>), FieldAttributes.InitOnly | FieldAttributes.Private);
  490. Label ipyImpl = il.DefineLabel();
  491. Label noOverride = il.DefineLabel();
  492. Label retNull = il.DefineLabel();
  493. // check if the we're recursing (this enables the user to refer to self
  494. // during GetMetaObject calls)
  495. il.Emit(OpCodes.Ldarg_0);
  496. il.Emit(OpCodes.Ldfld, _explicitMO);
  497. il.EmitPropertyGet(typeof(ThreadLocal<bool>), "Value");
  498. il.Emit(OpCodes.Brtrue, ipyImpl);
  499. // we're not recursing, set the flag...
  500. il.Emit(OpCodes.Ldarg_0);
  501. il.Emit(OpCodes.Ldfld, _explicitMO);
  502. il.Emit(OpCodes.Ldc_I4_1);
  503. il.EmitPropertySet(typeof(ThreadLocal<bool>), "Value");
  504. il.BeginExceptionBlock();
  505. LocalBuilder callTarget = EmitNonInheritedMethodLookup("GetMetaObject", il);
  506. il.Emit(OpCodes.Brfalse, noOverride);
  507. // call the user GetMetaObject function
  508. EmitClrCallStub(il, typeof(IDynamicMetaObjectProvider).GetMethod("GetMetaObject"), callTarget);
  509. // check for null return
  510. il.Emit(OpCodes.Dup);
  511. il.Emit(OpCodes.Ldnull);
  512. il.Emit(OpCodes.Beq, retNull);
  513. // store the local value
  514. il.Emit(OpCodes.Stloc_S, retVal.LocalIndex);
  515. // returned a value, that's our result
  516. il.Emit(OpCodes.Leave, retLabel);
  517. // user returned null, fallback to base impl
  518. il.MarkLabel(retNull);
  519. il.Emit(OpCodes.Pop);
  520. // no override exists
  521. il.MarkLabel(noOverride);
  522. // will emit leave to end of exception block
  523. il.BeginFinallyBlock();
  524. // restore the flag now that we're done
  525. il.Emit(OpCodes.Ldarg_0);
  526. il.Emit(OpCodes.Ldfld, _explicitMO);
  527. il.Emit(OpCodes.Ldc_I4_0);
  528. il.EmitPropertySet(typeof(ThreadLocal<bool>), "Value");
  529. il.EndExceptionBlock();
  530. // no user defined function or no result
  531. il.MarkLabel(ipyImpl);
  532. }
  533. il.EmitLoadArg(0); // this
  534. il.EmitLoadArg(1); // parameter
  535. // baseMetaObject
  536. if (baseIdo) {
  537. InterfaceMapping imap = _baseType.GetInterfaceMap(typeof(IDynamicMetaObjectProvider));
  538. il.EmitLoadArg(0); // this
  539. il.EmitLoadArg(1); // parameter
  540. il.EmitCall(imap.TargetMethods[0]);
  541. } else {
  542. il.EmitNull();
  543. }
  544. il.EmitCall(mi);
  545. il.Emit(OpCodes.Stloc, retVal.LocalIndex);
  546. il.MarkLabel(retLabel);
  547. il.Emit(OpCodes.Ldloc, retVal.LocalIndex);
  548. il.Emit(OpCodes.Ret);
  549. _tg.DefineMethodOverride(impl, decl);
  550. }
  551. private void ImplementIPythonObject() {
  552. ILGen il;
  553. MethodInfo decl;
  554. MethodBuilder impl;
  555. if (NeedsPythonObject) {
  556. _typeField = _tg.DefineField(ClassFieldName, typeof(PythonType), FieldAttributes.Public);
  557. _dictField = _tg.DefineField(DictFieldName, typeof(PythonDictionary), FieldAttributes.Public);
  558. ImplementInterface(typeof(IPythonObject));
  559. MethodAttributes attrs = MethodAttributes.Private;
  560. il = DefineMethodOverride(attrs, typeof(IPythonObject), "get_Dict", out decl, out impl);
  561. il.EmitLoadArg(0);
  562. EmitGetDict(il);
  563. il.Emit(OpCodes.Ret);
  564. _tg.DefineMethodOverride(impl, decl);
  565. il = DefineMethodOverride(attrs, typeof(IPythonObject), "ReplaceDict", out decl, out impl);
  566. il.EmitLoadArg(0);
  567. il.EmitLoadArg(1);
  568. EmitSetDict(il);
  569. il.EmitBoolean(true);
  570. il.Emit(OpCodes.Ret);
  571. _tg.DefineMethodOverride(impl, decl);
  572. il = DefineMethodOverride(attrs, typeof(IPythonObject), "SetDict", out decl, out impl);
  573. il.EmitLoadArg(0);
  574. il.EmitFieldAddress(_dictField);
  575. il.EmitLoadArg(1);
  576. il.EmitCall(typeof(UserTypeOps), "SetDictHelper");
  577. il.Emit(OpCodes.Ret);
  578. _tg.DefineMethodOverride(impl, decl);
  579. il = DefineMethodOverride(attrs, typeof(IPythonObject), "get_PythonType", out decl, out impl);
  580. il.EmitLoadArg(0);
  581. il.EmitFieldGet(_typeField);
  582. il.Emit(OpCodes.Ret);
  583. _tg.DefineMethodOverride(impl, decl);
  584. il = DefineMethodOverride(attrs, typeof(IPythonObject), "SetPythonType", out decl, out impl);
  585. il.EmitLoadArg(0);
  586. il.EmitLoadArg(1);
  587. il.EmitFieldSet(_typeField);
  588. il.Emit(OpCodes.Ret);
  589. _tg.DefineMethodOverride(impl, decl);
  590. }
  591. // Types w/ DynamicBaseType attribute still need new slots implementation
  592. _slotsField = _tg.DefineField(SlotsAndWeakRefFieldName, typeof(object[]), FieldAttributes.Public);
  593. il = DefineMethodOverride(MethodAttributes.Private, typeof(IPythonObject), "GetSlots", out decl, out impl);
  594. il.EmitLoadArg(0);
  595. il.EmitFieldGet(_slotsField);
  596. il.Emit(OpCodes.Ret);
  597. _tg.DefineMethodOverride(impl, decl);
  598. il = DefineMethodOverride(MethodAttributes.Private, typeof(IPythonObject), "GetSlotsCreate", out decl, out impl);
  599. il.EmitLoadArg(0);
  600. il.EmitLoadArg(0);
  601. il.EmitFieldAddress(_slotsField);
  602. il.EmitCall(typeof(UserTypeOps).GetMethod("GetSlotsCreate"));
  603. il.Emit(OpCodes.Ret);
  604. _tg.DefineMethodOverride(impl, decl);
  605. }
  606. /// <summary>
  607. /// Defines an interface on the type that forwards all calls
  608. /// to a helper method in UserType. The method names all will
  609. /// have Helper appended to them to get the name for UserType. The
  610. /// UserType version should take 1 extra parameter (self).
  611. /// </summary>
  612. private void DefineHelperInterface(Type intf) {
  613. ImplementInterface(intf);
  614. MethodInfo[] mis = intf.GetMethods();
  615. foreach (MethodInfo mi in mis) {
  616. MethodBuilder impl;
  617. ILGen il = DefineExplicitInterfaceImplementation(mi, out impl);
  618. ParameterInfo[] pis = mi.GetParameters();
  619. MethodInfo helperMethod = typeof(UserTypeOps).GetMethod(mi.Name + "Helper");
  620. int offset = 0;
  621. if (pis.Length > 0 && pis[0].ParameterType == typeof(CodeContext)) {
  622. // if the interface takes CodeContext then the helper method better take
  623. // it as well.
  624. Debug.Assert(helperMethod.GetParameters()[0].ParameterType == typeof(CodeContext));
  625. offset = 1;
  626. il.EmitLoadArg(1);
  627. }
  628. il.EmitLoadArg(0);
  629. for (int i = offset; i < pis.Length; i++) {
  630. il.EmitLoadArg(i + 1);
  631. }
  632. il.EmitCall(helperMethod);
  633. il.Emit(OpCodes.Ret);
  634. _tg.DefineMethodOverride(impl, mi);
  635. }
  636. }
  637. #if CLR2
  638. private void ImplementPythonEquals() {
  639. if (this._baseType.GetInterface("IValueEquality", false) == null) {
  640. DefineHelperInterface(typeof(IValueEquality));
  641. }
  642. }
  643. #endif
  644. private void ImplementWeakReference() {
  645. if (typeof(IWeakReferenceable).IsAssignableFrom(_baseType)) {
  646. return;
  647. }
  648. DefineHelperInterface(typeof(IWeakReferenceable));
  649. }
  650. private void ImplementProtectedFieldAccessors(Dictionary<string, string[]> specialNames) {
  651. // For protected fields to be accessible from the derived type in Silverlight,
  652. // we need to create public helper methods that expose them. These methods are
  653. // used by the IDynamicMetaObjectProvider implementation (in MetaUserObject)
  654. FieldInfo[] fields = _baseType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy);
  655. foreach (FieldInfo fi in fields) {
  656. if (!fi.IsProtected()) {
  657. continue;
  658. }
  659. List<string> fieldAccessorNames = new List<string>();
  660. PropertyBuilder pb = _tg.DefineProperty(fi.Name, PropertyAttributes.None, fi.FieldType, Type.EmptyTypes);
  661. MethodAttributes methodAttrs = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName;
  662. if (fi.IsStatic) {
  663. methodAttrs |= MethodAttributes.Static;
  664. }
  665. MethodBuilder method;
  666. method = _tg.DefineMethod(FieldGetterPrefix + fi.Name, methodAttrs,
  667. fi.FieldType, Type.EmptyTypes);
  668. ILGen il = new ILGen(method.GetILGenerator());
  669. if (!fi.IsStatic) {
  670. il.EmitLoadArg(0);
  671. }
  672. if (fi.IsLiteral) {
  673. // literal fields need to be inlined directly in here... We use GetRawConstant
  674. // which will work even in partial trust if the constant is protected.
  675. object value = fi.GetRawConstantValue();
  676. switch (Type.GetTypeCode(fi.FieldType)) {
  677. case TypeCode.Boolean:
  678. if ((bool)value) {
  679. il.Emit(OpCodes.Ldc_I4_1);
  680. } else {
  681. il.Emit(OpCodes.Ldc_I4_0);
  682. }
  683. break;
  684. case TypeCode.Byte: il.Emit(OpCodes.Ldc_I4, (byte)value); break;
  685. case TypeCode.Char: il.Emit(OpCodes.Ldc_I4, (char)value); break;
  686. case TypeCode.Double: il.Emit(OpCodes.Ldc_R8, (double)value); break;
  687. case TypeCode.Int16: il.Emit(OpCodes.Ldc_I4, (short)value); break;
  688. case TypeCode.Int32: il.Emit(OpCodes.Ldc_I4, (int)value); break;
  689. case TypeCode.Int64: il.Emit(OpCodes.Ldc_I8, (long)value); break;
  690. case TypeCode.SByte: il.Emit(OpCodes.Ldc_I4, (sbyte)value); break;
  691. case TypeCode.Single: il.Emit(OpCodes.Ldc_R4, (float)value); break;
  692. case TypeCode.String: il.Emit(OpCodes.Ldstr, (string)value); break;
  693. case TypeCode.UInt16: il.Emit(OpCodes.Ldc_I4, (ushort)value); break;
  694. case TypeCode.UInt32: il.Emit(OpCodes.Ldc_I4, (uint)value); break;
  695. case TypeCode.UInt64: il.Emit(OpCodes.Ldc_I8, (ulong)value); break;
  696. }
  697. } else {
  698. il.EmitFieldGet(fi);
  699. }
  700. il.Emit(OpCodes.Ret);
  701. pb.SetGetMethod(method);
  702. fieldAccessorNames.Add(method.Name);
  703. if (!fi.IsLiteral && !fi.IsInitOnly) {
  704. method = _tg.DefineMethod(FieldSetterPrefix + fi.Name, methodAttrs,
  705. null, new Type[] { fi.FieldType });
  706. method.DefineParameter(1, ParameterAttributes.None, "value");
  707. il = new ILGen(method.GetILGenerator());
  708. il.EmitLoadArg(0);
  709. if (!fi.IsStatic) {
  710. il.EmitLoadArg(1);
  711. }
  712. il.EmitFieldSet(fi);
  713. il.Emit(OpCodes.Ret);
  714. pb.SetSetMethod(method);
  715. fieldAccessorNames.Add(method.Name);
  716. }
  717. specialNames[fi.Name] = fieldAccessorNames.ToArray();
  718. }
  719. }
  720. /// <summary>
  721. /// Overrides methods - this includes all accessible virtual methods as well as protected non-virtual members
  722. /// including statics and non-statics.
  723. /// </summary>
  724. private void OverrideMethods(Type type, Dictionary<string, string[]> specialNames) {
  725. // if we have conflicting virtual's do to new slots only override the methods on the
  726. // most derived class.
  727. Dictionary<KeyValuePair<string, MethodSignatureInfo>, MethodInfo> added = new Dictionary<KeyValuePair<string, MethodSignatureInfo>, MethodInfo>();
  728. MethodInfo overridden;
  729. MethodInfo[] methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy);
  730. foreach (MethodInfo mi in methods) {
  731. KeyValuePair<string, MethodSignatureInfo> key = new KeyValuePair<string, MethodSignatureInfo>(mi.Name, new MethodSignatureInfo(mi));
  732. if (!added.TryGetValue(key, out overridden)) {
  733. added[key] = mi;
  734. continue;
  735. }
  736. if (overridden.DeclaringType.IsAssignableFrom(mi.DeclaringType)) {
  737. added[key] = mi;
  738. }
  739. }
  740. if (type.IsAbstract && !type.IsInterface) {
  741. // abstract types can define interfaces w/o implementations
  742. Type[] interfaces = type.GetInterfaces();
  743. foreach (Type iface in interfaces) {
  744. InterfaceMapping mapping = type.GetInterfaceMap(iface);
  745. for (int i = 0; i < mapping.TargetMethods.Length; i++) {
  746. if (mapping.TargetMethods[i] == null) {
  747. MethodInfo mi = mapping.InterfaceMethods[i];
  748. KeyValuePair<string, MethodSignatureInfo> key = new KeyValuePair<string, MethodSignatureInfo>(mi.Name, new MethodSignatureInfo(mi));
  749. added[key] = mi;
  750. }
  751. }
  752. }
  753. }
  754. Dictionary<PropertyInfo, PropertyBuilder> overriddenProperties = new Dictionary<PropertyInfo, PropertyBuilder>();
  755. foreach (MethodInfo mi in added.Values) {
  756. if (!CanOverrideMethod(mi)) continue;
  757. if (mi.IsPublic || mi.IsProtected()) {
  758. if (mi.IsSpecialName) {
  759. OverrideSpecialName(mi, specialNames, overriddenProperties);
  760. } else {
  761. OverrideBaseMethod(mi, specialNames);
  762. }
  763. }
  764. }
  765. }
  766. private void OverrideSpecialName(MethodInfo mi, Dictionary<string, string[]> specialNames, Dictionary<PropertyInfo, PropertyBuilder> overridden) {
  767. if (!mi.IsVirtual || mi.IsFinal) {
  768. // TODO: A better check here would be mi.IsFamily && mi.IsSpecialName. But we need to also check
  769. // the other property method (getter if we're a setter, setter if we're a getter) because if one is protected
  770. // and the other isn't we need to still override both (so our newslot property is also both a getter and a setter).
  771. if ((mi.IsProtected() || mi.IsSpecialName) && (mi.Name.StartsWith("get_") || mi.Name.StartsWith("set_"))) {
  772. // need to be able to call into protected getter/setter methods from derived types,
  773. // even if these methods aren't virtual and we are in partial trust.
  774. specialNames[mi.Name] = new[] { mi.Name };
  775. MethodBuilder mb = CreateSuperCallHelper(mi);
  776. foreach (PropertyInfo pi in mi.DeclaringType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
  777. if (pi.GetGetMethod(true).MemberEquals(mi) || pi.GetSetMethod(true).MemberEquals(mi)) {
  778. AddPublicProperty(mi, overridden, mb, pi);
  779. break;
  780. }
  781. }
  782. }
  783. } else if (!TryOverrideProperty(mi, specialNames, overridden)) {
  784. string name;
  785. EventInfo[] eis = mi.DeclaringType.GetEvents(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
  786. foreach (EventInfo ei in eis) {
  787. if (ei.GetAddMethod().MemberEquals(mi)) {
  788. if (NameConverter.TryGetName(DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType), ei, mi, out name) == NameType.None) return;
  789. CreateVTableEventOverride(mi, mi.Name);
  790. return;
  791. } else if (ei.GetRemoveMethod().MemberEquals(mi)) {
  792. if (NameConverter.TryGetName(DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType), ei, mi, out name) == NameType.None) return;
  793. CreateVTableEventOverride(mi, mi.Name);
  794. return;
  795. }
  796. }
  797. OverrideBaseMethod(mi, specialNames);
  798. }
  799. }
  800. private bool TryOverrideProperty(MethodInfo mi, Dictionary<string, string[]> specialNames, Dictionary<PropertyInfo, PropertyBuilder> overridden) {
  801. string name;
  802. PropertyInfo[] pis = mi.DeclaringType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
  803. specialNames[mi.Name] = new[] { mi.Name };
  804. MethodBuilder mb = null;
  805. PropertyInfo foundProperty = null;
  806. foreach (PropertyInfo pi in pis) {
  807. if (pi.GetIndexParameters().Length > 0) {
  808. if (mi.MemberEquals(pi.GetGetMethod(true))) {
  809. mb = CreateVTableMethodOverride(mi, "__getitem__");
  810. if (!mi.IsAbstract) {
  811. CreateSuperCallHelper(mi);
  812. }
  813. foundProperty = pi;
  814. break;
  815. } else if (mi.MemberEquals(pi.GetSetMethod(true))) {
  816. mb = CreateVTableMethodOverride(mi, "__setitem__");
  817. if (!mi.IsAbstract) {
  818. CreateSuperCallHelper(mi);
  819. }
  820. foundProperty = pi;
  821. break;
  822. }
  823. } else if (mi.MemberEquals(pi.GetGetMethod(true))) {
  824. if (mi.Name != "get_PythonType") {
  825. if (NameConverter.TryGetName(GetBaseTypeForMethod(mi), pi, mi, out name) == NameType.None) {
  826. return true;
  827. }
  828. mb = CreateVTableGetterOverride(mi, name);
  829. if (!mi.IsAbstract) {
  830. CreateSuperCallHelper(mi);
  831. }
  832. }
  833. foundProperty = pi;
  834. break;
  835. } else if (mi.MemberEquals(pi.GetSetMethod(true))) {
  836. if (NameConverter.TryGetName(GetBaseTypeForMethod(mi), pi, mi, out name) == NameType.None) {
  837. return true;
  838. }
  839. mb = CreateVTableSetterOverride(mi, name);
  840. if (!mi.IsAbstract) {
  841. CreateSuperCallHelper(mi);
  842. }
  843. foundProperty = pi;
  844. break;
  845. }
  846. }
  847. if (foundProperty != null) {
  848. AddPublicProperty(mi, overridden, mb, foundProperty);
  849. return true;
  850. }
  851. return false;
  852. }
  853. private void AddPublicProperty(MethodInfo mi, Dictionary<PropertyInfo, PropertyBuilder> overridden, MethodBuilder mb, PropertyInfo foundProperty) {
  854. MethodInfo getter = foundProperty.GetGetMethod(true);
  855. MethodInfo setter = foundProperty.GetSetMethod(true);
  856. if (getter != null && getter.IsProtected() || setter != null && setter.IsProtected()) {
  857. PropertyBuilder builder;
  858. if (!overridden.TryGetValue(foundProperty, out builder)) {
  859. ParameterInfo[] indexArgs = foundProperty.GetIndexParameters();
  860. Type[] paramTypes = new Type[indexArgs.Length];
  861. for (int i = 0; i < paramTypes.Length; i++) {
  862. paramTypes[i] = indexArgs[i].ParameterType;
  863. }
  864. overridden[foundProperty] = builder = _tg.DefineProperty(foundProperty.Name, foundProperty.Attributes, foundProperty.PropertyType, paramTypes);
  865. }
  866. if (foundProperty.GetGetMethod(true).MemberEquals(mi)) {
  867. builder.SetGetMethod(mb);
  868. } else if (foundProperty.GetSetMethod(true).MemberEquals(mi)) {
  869. builder.SetSetMethod(mb);
  870. }
  871. }
  872. }
  873. /// <summary>
  874. /// Loads all the incoming arguments and forwards them to mi which
  875. /// has the same signature and then returns the result
  876. /// </summary>
  877. private static void EmitBaseMethodDispatch(MethodInfo mi, ILGen il) {
  878. if (!mi.IsAbstract) {
  879. int offset = 0;
  880. if (!mi.IsStatic) {
  881. il.EmitLoadArg(0);
  882. offset = 1;
  883. }
  884. ParameterInfo[] parameters = mi.GetParameters();
  885. for (int i = 0; i < parameters.Length; i++) {
  886. il.EmitLoadArg(i + offset);
  887. }
  888. il.EmitCall(OpCodes.Call, mi, null); // base call must be non-virtual
  889. il.Emit(OpCodes.Ret);
  890. } else {
  891. il.EmitLoadArg(0);
  892. il.EmitString(mi.Name);
  893. il.EmitCall(typeof(PythonOps), "MissingInvokeMethodException");
  894. il.Emit(OpCodes.Throw);
  895. }
  896. }
  897. private void OverrideBaseMethod(MethodInfo mi, Dictionary<string, string[]> specialNames) {
  898. if ((!mi.IsVirtual || mi.IsFinal) && !mi.IsProtected()) {
  899. return;
  900. }
  901. PythonType basePythonType = GetBaseTypeForMethod(mi);
  902. string name = null;
  903. if (NameConverter.TryGetName(basePythonType, mi, out name) == NameType.None)
  904. return;
  905. if (mi.DeclaringType == typeof(object) && mi.Name == "Finalize") return;
  906. specialNames[mi.Name] = new[] { mi.Name };
  907. if (!mi.IsStatic) {
  908. CreateVTableMethodOverride(mi, name);
  909. }
  910. if (!mi.IsAbstract) {
  911. CreateSuperCallHelper(mi);
  912. }
  913. }
  914. private PythonType GetBaseTypeForMethod(MethodInfo mi) {
  915. PythonType basePythonType;
  916. if (_baseType == mi.DeclaringType || _baseType.IsSubclassOf(mi.DeclaringType)) {
  917. basePythonType = DynamicHelpers.GetPythonTypeFromType(_baseType);
  918. } else {
  919. // We must be inherting from an interface
  920. Debug.Assert(mi.DeclaringType.IsInterface);
  921. basePythonType = DynamicHelpers.GetPythonTypeFromType(mi.DeclaringType);
  922. }
  923. return basePythonType;
  924. }
  925. /// <summary>
  926. /// Emits code to check if the class has overridden this specific
  927. /// function. For example:
  928. ///
  929. /// MyDerivedType.SomeVirtualFunction = ...
  930. /// or
  931. ///
  932. /// class MyDerivedType(MyBaseType):
  933. /// def SomeVirtualFunction(self, ...):
  934. ///
  935. /// </summary>
  936. private LocalBuilder EmitBaseClassCallCheckForProperties(ILGen il, MethodInfo baseMethod, string name) {
  937. Label instanceCall = il.DefineLabel();
  938. LocalBuilder callTarget = il.DeclareLocal(typeof(object));
  939. // first lookup under the property name
  940. il.EmitLoadArg(0);
  941. il.EmitString(name);
  942. il.Emit(OpCodes.Ldloca, callTarget);
  943. il.EmitCall(typeof(UserTypeOps), "TryGetNonInheritedValueHelper");
  944. il.Emit(OpCodes.Brtrue, instanceCall);
  945. // then look up under the method name (get_Foo/set_Foo)
  946. LocalBuilder methodTarget = EmitNonInheritedMethodLookup(baseMethod.Name, il);
  947. Label instanceCallMethod = il.DefineLabel();
  948. il.Emit(OpCodes.Brtrue, instanceCallMethod);
  949. // method isn't overridden using either form
  950. EmitBaseMethodDispatch(baseMethod, il);
  951. // we're calling the get_/set_ method
  952. il.MarkLabel(instanceCallMethod);
  953. EmitClrCallStub(il, baseMethod, methodTarget);
  954. il.Emit(OpCodes.Ret);
  955. il.MarkLabel(instanceCall);
  956. // we're accessing a property
  957. return callTarget;
  958. }
  959. private MethodBuilder CreateVTableGetterOverride(MethodInfo mi, string name) {
  960. MethodBuilder impl;
  961. ILGen il;
  962. DefineVTableMethodOverride(mi, out impl, out il);
  963. LocalBuilder callTarget = EmitBaseClassCallCheckForProperties(il, mi, name);
  964. il.Emit(OpCodes.Ldloc, callTarget);
  965. il.EmitLoadArg(0);
  966. il.EmitString(name);
  967. il.EmitCall(typeof(UserTypeOps), "GetPropertyHelper");
  968. if (!il.TryEmitImplicitCast(typeof(object), mi.ReturnType)) {
  969. EmitConvertFromObject(il, mi.ReturnType);
  970. }
  971. il.Emit(OpCodes.Ret);
  972. _tg.DefineMethodOverride(impl, mi);
  973. return impl;
  974. }
  975. /// <summary>
  976. /// Emit code to convert object to a given type. This code is semantically equivalent
  977. /// to PythonBinder.EmitConvertFromObject, except this version accepts ILGen whereas
  978. /// PythonBinder accepts Compiler. The Binder will chagne soon and the two will merge.
  979. /// </summary>
  980. private static void EmitConvertFromObject(ILGen il, Type toType) {
  981. if (toType == typeof(object)) return;
  982. if (toType.IsGenericParameter) {
  983. il.EmitCall(typeof(PythonOps).GetMethod("ConvertFromObject").MakeGenericMethod(toType));
  984. return;
  985. }
  986. MethodInfo fastConvertMethod = PythonBinder.GetFastConvertMethod(toType);
  987. if (fastConvertMethod != null) {
  988. il.EmitCall(fastConvertMethod);
  989. } else if (toType == typeof(void)) {
  990. il.Emit(OpCodes.Pop);
  991. } else if (typeof(Delegate).IsAssignableFrom(toType)) {
  992. il.EmitType(toType);
  993. il.EmitCall(typeof(Converter), "ConvertToDelegate");
  994. il.Emit(OpCodes.Castclass, toType);
  995. } else {
  996. Label end = il.DefineLabel();
  997. il.Emit(OpCodes.Dup);
  998. il.Emit(OpCodes.Isinst, toType);
  999. il.Emit(OpCodes.Brtrue_S, end);
  1000. il.Emit(OpCodes.Ldtoken, toType);
  1001. il.EmitCall(PythonBinder.GetGenericConvertMethod(toType));
  1002. il.MarkLabel(end);
  1003. il.Emit(OpCodes.Unbox_Any, toType); //??? this check may be redundant
  1004. }
  1005. }
  1006. private MethodBuilder CreateVTableSetterOverride(MethodInfo mi, string name) {
  1007. MethodBuilder impl;
  1008. ILGen il;
  1009. DefineVTableMethodOverride(mi, out impl, out il);
  1010. LocalBuilder callTarget = EmitBaseClassCallCheckForProperties(il, mi, name);
  1011. il.Emit(OpCodes.Ldloc, callTarget); // property
  1012. il.EmitLoadArg(0); // instance
  1013. il.EmitLoadArg(1);
  1014. il.EmitBoxing(mi.GetParameters()[0].ParameterType); // newValue
  1015. il.EmitString(name); // name
  1016. il.EmitCall(typeof(UserTypeOps), "SetPropertyHelper");
  1017. il.Emit(OpCodes.Ret);
  1018. _tg.DefineMethodOverride(impl, mi);
  1019. return impl;
  1020. }
  1021. private void CreateVTableEventOverride(MethodInfo mi, string name) {
  1022. // override the add/remove method
  1023. MethodBuilder impl;
  1024. ILGen il = DefineMethodOverride(mi, out impl);
  1025. LocalBuilder callTarget = EmitBaseClassCallCheckForEvents(il, mi, name);
  1026. il.Emit(OpCodes.Ldloc, callTarget);
  1027. il.EmitLoadArg(0);
  1028. il.EmitLoadArg(1);
  1029. il.EmitBoxing(mi.GetParameters()[0].ParameterType);
  1030. il.EmitString(name);
  1031. il.EmitCall(typeof(UserTypeOps), "AddRemoveEventHelper");
  1032. il.Emit(OpCodes.Ret);
  1033. _tg.DefineMethodOverride(impl, mi);
  1034. }
  1035. /// <summary>
  1036. /// Emits code to check if the class has overridden this specific
  1037. /// function. For example:
  1038. ///
  1039. /// MyDerivedType.SomeVirtualFunction = ...
  1040. /// or
  1041. ///
  1042. /// class MyDerivedType(MyBaseType):
  1043. /// def SomeVirtualFunction(self, ...):
  1044. ///
  1045. /// </summary>
  1046. private static LocalBuilder EmitBaseClassCallCheckForEvents(ILGen il, MethodInfo baseMethod, string name) {
  1047. Label instanceCall = il.DefineLabel();
  1048. LocalBuilder callTarget = il.DeclareLocal(typeof(object));
  1049. il.EmitLoadArg(0);
  1050. il.EmitString(name);
  1051. il.Emit(OpCodes.Ldloca, callTarget);
  1052. il.EmitCall(typeof(UserTypeOps), "TryGetNonInheritedValueHelper");
  1053. il.Emit(OpCodes.Brtrue, instanceCall);
  1054. EmitBaseMethodDispatch(baseMethod, il);
  1055. il.MarkLabel(instanceCall);
  1056. return callTarget;
  1057. }
  1058. private MethodBuilder CreateVTableMethodOverride(MethodInfo mi, string name) {
  1059. MethodBuilder impl;
  1060. ILGen il;
  1061. DefineVTableMethodOverride(mi, out impl, out il);
  1062. //CompilerHelpers.GetArgumentNames(parameters)); TODO: Set names
  1063. LocalBuilder callTarget = EmitNonInheritedMethodLookup(name, il);
  1064. Label instanceCall = il.DefineLabel();
  1065. il.Emit(OpCodes.Brtrue, instanceCall);
  1066. // lookup failed, call the base class method (this returns or throws)
  1067. EmitBaseMethodDispatch(mi, il);
  1068. // lookup succeeded, call the user defined method & return
  1069. il.MarkLabel(instanceCall);
  1070. EmitClrCallStub(il, mi, callTarget);
  1071. il.Emit(OpCodes.Ret);
  1072. if (mi.IsVirtual && !mi.IsFinal) {
  1073. _tg.DefineMethodOverride(impl, mi);
  1074. }
  1075. return impl;
  1076. }
  1077. private void DefineVTableMethodOverride(MethodInfo mi, out MethodBuilder impl, out ILGen il) {
  1078. if (mi.IsVirtual && !mi.IsFinal) {
  1079. il = DefineMethodOverride(MethodAttributes.Public, mi, out impl);
  1080. } else {
  1081. impl = _tg.DefineMethod(
  1082. mi.Name,
  1083. mi.IsVirtual ?
  1084. (mi.Attributes | MethodAttributes.NewSlot) :
  1085. ((mi.Attributes & ~MethodAttributes.MemberAccessMask) | MethodAttributes.Public),
  1086. mi.CallingConvention
  1087. );
  1088. ReflectionUtils.CopyMethodSignature(mi, impl, false);
  1089. il = new ILGen(impl.GetILGenerator());
  1090. }
  1091. }
  1092. /// <summary>
  1093. /// Emits the call to lookup a member defined in the user's type. Returns
  1094. /// the local which stores the resulting value and leaves a value on the
  1095. /// stack indicating the success of the lookup.
  1096. /// </summary>
  1097. private LocalBuilder EmitNonInheritedMethodLookup(string name, ILGen il) {
  1098. LocalBuilder callTarget = il.DeclareLocal(typeof(object));
  1099. // emit call to helper to do lookup
  1100. il.EmitLoadArg(0);
  1101. if (typeof(IPythonObject).IsAssignableFrom(_baseType)) {
  1102. Debug.Assert(_typeField == null);
  1103. il.EmitPropertyGet(TypeInfo._IPythonObject.PythonType);
  1104. } else {
  1105. il.EmitFieldGet(_typeField);
  1106. }
  1107. il.EmitLoadArg(0);
  1108. il.EmitString(name);
  1109. il.Emit(OpCodes.Ldloca, callTarget);
  1110. il.EmitCall(typeof(UserTypeOps), "TryGetNonInheritedMethodHelper");
  1111. return callTarget;
  1112. }
  1113. /// <summary>
  1114. /// Creates a method for doing a base method dispatch. This is used to support
  1115. /// super(type, obj) calls.
  1116. /// </summary>
  1117. private MethodBuilder CreateSuperCallHelper(MethodInfo mi) {
  1118. MethodAttributes attrs = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName;
  1119. if (mi.IsStatic) {
  1120. attrs |= MethodAttributes.Static;
  1121. }
  1122. MethodBuilder method = _tg.DefineMethod(BaseMethodPrefix + mi.Name, attrs, mi.CallingConvention);
  1123. ReflectionUtils.CopyMethodSignature(mi, method, true);
  1124. EmitBaseMethodDispatch(mi, new ILGen(method.GetILGenerator()));
  1125. return method;
  1126. }
  1127. private KeyValuePair<Type, Dictionary<string, string[]>> SaveType(AssemblyGen ag, string name) {
  1128. _tg = ag.DefinePublicType(TypePrefix + name, _baseType, true);
  1129. Dictionary<string, string[]> specialNames = ImplementType();
  1130. Type ret = FinishType();
  1131. return new KeyValuePair<Type, Dictionary<string, string[]>>(ret, specialNames);
  1132. }
  1133. private Type FinishType() {
  1134. if (_cctor != null) {
  1135. _cctor.Emit(OpCodes.Ret);
  1136. }
  1137. return _tg.CreateType();
  1138. }
  1139. private ILGen DefineExplicitInterfaceImplementation(MethodInfo baseMethod, out MethodBuilder builder) {
  1140. MethodAttributes attrs = baseMethod.Attributes & ~(MethodAttributes.Abstract | MethodAttributes.Public);
  1141. attrs |= MethodAttributes.NewSlot | MethodAttributes.Final;
  1142. Type[] baseSignature = ReflectionUtils.GetParameterTypes(baseMethod.GetParameters());
  1143. builder = _tg.DefineMethod(
  1144. baseMethod.DeclaringType.Name + "." + baseMethod.Name,
  1145. attrs,
  1146. baseMethod.ReturnType,
  1147. baseSignature
  1148. );
  1149. return new ILGen(builder.GetILGenerator());
  1150. }
  1151. private const MethodAttributes MethodAttributesToEraseInOveride = MethodAttributes.Abstract | MethodAttributes.ReservedMask;
  1152. private ILGen DefineMethodOverride(MethodAttributes extra, Type type, string name, out MethodInfo decl, out MethodBuilder impl) {
  1153. decl = type.GetMethod(name);
  1154. return DefineMethodOverride(extra, decl, out impl);
  1155. }
  1156. private ILGen DefineMethodOverride(MethodInfo decl, out MethodBuilder impl) {
  1157. return DefineMethodOverride(MethodAttributes.PrivateScope, decl, out impl);
  1158. }
  1159. private ILGen DefineMethodOverride(MethodAttributes extra, MethodInfo decl, out MethodBuilder impl) {
  1160. impl = ReflectionUtils.DefineMethodOverride(_tg, extra, decl);
  1161. return new ILGen(impl.GetILGenerator());
  1162. }
  1163. /// <summary>
  1164. /// Generates stub to receive the CLR call and then call the dynamic language code.
  1165. /// This code is same as StubGenerator.cs in the Microsoft.Scripting, except it
  1166. /// accepts ILGen instead of Compiler.
  1167. /// </summary>
  1168. private void EmitClrCallStub(ILGen il, MethodInfo mi, LocalBuilder callTarget) {
  1169. int firstArg = 0;
  1170. bool list = false; // The list calling convention
  1171. bool context = false; // Context is an argument
  1172. ParameterInfo[] pis = mi.GetParameters();
  1173. if (pis.Length > 0) {
  1174. if (pis[0].ParameterType == typeof(CodeContext)) {
  1175. firstArg = 1;
  1176. context = true;
  1177. }
  1178. if (pis[pis.Length - 1].IsDefined(typeof(ParamArrayAttribute), false)) {
  1179. list = true;
  1180. }
  1181. }
  1182. ParameterInfo[] args = pis;
  1183. int nargs = args.Length - firstArg;
  1184. Type[] genericArgs = mi.GetGenericArguments();
  1185. // Create the action
  1186. ILGen cctor = GetCCtor();
  1187. if (list || genericArgs.Length > 0) {
  1188. // Use a complex call signature that includes param array and keywords
  1189. cctor.EmitInt(nargs);
  1190. cctor.EmitBoolean(list);
  1191. // Emit an array of keyword names:
  1192. cctor.EmitInt(genericArgs.Length);
  1193. cctor.Emit(OpCodes.Newarr, typeof(string));
  1194. for (int i = 0; i < genericArgs.Length; i++) {
  1195. cctor.Emit(OpCodes.Dup);
  1196. cctor.EmitInt(i);
  1197. cctor.Emit(OpCodes.Ldelema, typeof(string));
  1198. cctor.Emit(OpCodes.Ldstr, genericArgs[i].Name);
  1199. cctor.Emit(OpCodes.Stobj, typeof(string));
  1200. }
  1201. cctor.EmitCall(typeof(PythonOps).GetMethod("MakeComplexCallAction"));
  1202. } else {
  1203. cctor.EmitInt(nargs);
  1204. cctor.EmitCall(typeof(PythonOps).GetMethod("MakeSimpleCallAction"));
  1205. }
  1206. // Create the dynamic site
  1207. Type siteType = CompilerHelpers.MakeCallSiteType(MakeSiteSignature(nargs + genericArgs.Length));
  1208. FieldBuilder site = _tg.DefineField("site$" + _site++, siteType, FieldAttributes.Private | FieldAttributes.Static);
  1209. cctor.EmitCall(siteType.GetMethod("Create"));
  1210. cctor.EmitFieldSet(site);
  1211. List<ReturnFixer> fixers = new List<ReturnFixer>(0);
  1212. //
  1213. // Emit the site invoke
  1214. //
  1215. il.EmitFieldGet(site);
  1216. FieldInfo target = siteType.GetField("Target");
  1217. il.EmitFieldGet(target);
  1218. il.EmitFieldGet(site);
  1219. // Emit the code context
  1220. EmitCodeContext(il, context);
  1221. il.Emit(OpCodes.Ldloc, callTarget);
  1222. for (int i = firstArg; i < args.Length; i++) {
  1223. ReturnFixer rf = ReturnFixer.EmitArgument(il, args[i], i + 1);
  1224. if (rf != null) {
  1225. fixers.Add(rf);
  1226. }
  1227. }
  1228. for (int i = 0; i < genericArgs.Length; i++) {
  1229. il.EmitType(genericArgs[i]);
  1230. il.EmitCall(typeof(DynamicHelpers).GetMethod("GetPythonTypeFromType"));
  1231. }
  1232. il.EmitCall(target.FieldType, "Invoke");
  1233. foreach (ReturnFixer rf in fixers) {
  1234. rf.FixReturn(il);
  1235. }
  1236. EmitConvertFromObject(il, mi.ReturnType);
  1237. }
  1238. private static void EmitCodeContext(ILGen il, bool context) {
  1239. if (context) {
  1240. il.EmitLoadArg(1);
  1241. } else {
  1242. il.EmitPropertyGet(typeof(DefaultContext).GetProperty("Default"));
  1243. }
  1244. }
  1245. private static void EmitInt(ILGenerator ilg, int iVal) {
  1246. switch (iVal) {
  1247. case 0: ilg.Emit(OpCodes.Ldc_I4_0); break;
  1248. case 1: ilg.Emit(OpCodes.Ldc_I4_1); break;
  1249. case 2: ilg.Emit(OpCodes.Ldc_I4_2); break;
  1250. case 3: ilg.Emit(OpCodes.Ldc_I4_3); break;
  1251. case 4: ilg.Emit(OpCodes.Ldc_I4_4); break;
  1252. case 5: ilg.Emit(OpCodes.Ldc_I4_5); break;
  1253. case 6: ilg.Emit(OpCodes.Ldc_I4_6); break;
  1254. case 7: ilg.Emit(OpCodes.Ldc_I4_7); break;
  1255. case 8: ilg.Emit(OpCodes.Ldc_I4_8); break;
  1256. default: ilg.Emit(OpCodes.Ldc_I4, iVal); break;
  1257. }
  1258. }
  1259. private static Type[] MakeSiteSignature(int nargs) {
  1260. Type[] sig = new Type[nargs + 4];
  1261. sig[0] = typeof(CallSite);
  1262. sig[1] = typeof(CodeContext);
  1263. for (int i = 2; i < sig.Length; i++) {
  1264. sig[i] = typeof(object);
  1265. }
  1266. return sig;
  1267. }
  1268. #endregion
  1269. #region Base type helper data updates
  1270. private static void AddBaseMethods(Type finishedType, Dictionary<string, string[]> specialNames) {
  1271. // "Adds" base methods to super type - this makes super(...).xyz to work - otherwise
  1272. // we'd return a function that did a virtual call resulting in a stack overflow.
  1273. // The addition is to a seperate cache that NewTypeMaker maintains. TypeInfo consults this
  1274. // cache when doing member lookup and includes these members in the returned members.
  1275. foreach (MethodInfo mi in finishedType.GetMethods()) {
  1276. if (IsInstanceType(finishedType.BaseType) && IsInstanceType(mi.DeclaringType)) continue;
  1277. string methodName = mi.Name;
  1278. if (methodName.StartsWith(BaseMethodPrefix) || methodName.StartsWith(FieldGetterPrefix) || methodName.StartsWith(FieldSetterPrefix)) {
  1279. foreach (string newName in GetBaseName(mi, specialNames)) {
  1280. if (mi.IsSpecialName && (newName.StartsWith("get_") || newName.StartsWith("set_"))) {
  1281. // if it's a property we want to override it
  1282. string propName = newName.Substring(4);
  1283. MemberInfo[] defaults = finishedType.BaseType.GetDefaultMembers();
  1284. if (defaults.Length > 0) {
  1285. // if it's an indexer then we want to override get_Item/set_Item methods
  1286. // which map to __getitem__ and __setitem__ as normal Python methods.
  1287. foreach (MemberInfo method in defaults) {
  1288. if (method.Name == propName) {
  1289. StoreOverriddenMethod(mi, newName);
  1290. break;
  1291. }
  1292. }
  1293. }
  1294. StoreOverriddenProperty(mi, newName);
  1295. } else if (mi.IsSpecialName && (newName.StartsWith(FieldGetterPrefix) || newName.StartsWith(FieldSetterPrefix))) {
  1296. StoreOverriddenField(mi, newName);
  1297. } else {
  1298. // not a property, just store the overridden method.
  1299. StoreOverriddenMethod(mi, newName);
  1300. }
  1301. }
  1302. }
  1303. }
  1304. }
  1305. private static void StoreOverriddenField(MethodInfo mi, string newName) {
  1306. Type baseType = mi.DeclaringType.BaseType;
  1307. string fieldName = newName.Substring(FieldGetterPrefix.Length); // get_ or set_
  1308. lock (PythonTypeOps._propertyCache) {
  1309. foreach (FieldInfo pi in baseType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy)) {
  1310. if (pi.Name == fieldName) {
  1311. if (newName.StartsWith(FieldGetterPrefix)) {
  1312. AddPropertyInfo(pi.DeclaringType, fieldName, mi, null);
  1313. } else if (newName.StartsWith(FieldSetterPrefix)) {
  1314. AddPropertyInfo(pi.DeclaringType, fieldName, null, mi);
  1315. }
  1316. }
  1317. }
  1318. }
  1319. }
  1320. private static ExtensionPropertyTracker AddPropertyInfo(Type baseType, string/*!*/ propName, MethodInfo get, MethodInfo set) {
  1321. MethodInfo mi = get ?? set;
  1322. Dictionary<string, List<ExtensionPropertyTracker>> propInfoList;
  1323. if (!_overriddenProperties.TryGetValue(baseType, out propInfoList)) {
  1324. _overriddenProperties[baseType] = propInfoList = new Dictionary<string, List<ExtensionPropertyTracker>>();
  1325. }
  1326. List<ExtensionPropertyTracker> trackers;
  1327. if (!propInfoList.TryGetValue(propName, out trackers)) {
  1328. propInfoList[propName] = trackers = new List<ExtensionPropertyTracker>();
  1329. }
  1330. ExtensionPropertyTracker res;
  1331. for (int i = 0; i < trackers.Count; i++) {
  1332. if (trackers[i].DeclaringType == mi.DeclaringType) {
  1333. trackers[i] = res = new ExtensionPropertyTracker(
  1334. propName,
  1335. get ?? trackers[i].GetGetMethod(),
  1336. set ?? trackers[i].GetSetMethod(),
  1337. null,
  1338. mi.DeclaringType
  1339. );
  1340. return res;
  1341. }
  1342. }
  1343. trackers.Add(
  1344. res = new ExtensionPropertyTracker(
  1345. propName,
  1346. mi,
  1347. null,
  1348. null,
  1349. mi.DeclaringType
  1350. )
  1351. );
  1352. return res;
  1353. }
  1354. private static void StoreOverriddenMethod(MethodInfo mi, string newName) {
  1355. Type baseType = mi.DeclaringType.BaseType;
  1356. MemberInfo[] members = baseType.GetMember(newName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy);
  1357. Debug.Assert(members.Length > 0, String.Format("{0} from {1}", newName, baseType.Name));
  1358. Type declType = ((MethodInfo)members[0]).GetBaseDefinition().DeclaringType;
  1359. string pythonName = newName;
  1360. switch (newName) {
  1361. case "get_Item": pythonName = "__getitem__"; break;
  1362. case "set_Item": pythonName = "__setitem__"; break;
  1363. }
  1364. // back-patch any existing functions so that cached rules will work
  1365. // when called again...
  1366. lock (PythonTypeOps._functions) {
  1367. foreach (BuiltinFunction bf in PythonTypeOps._functions.Values) {
  1368. if (bf.Name == pythonName && bf.DeclaringType == declType) {
  1369. bf.AddMethod(mi);
  1370. break;
  1371. }
  1372. }
  1373. Dictionary<string, List<MethodInfo>> overrideInfo;
  1374. if (!_overriddenMethods.TryGetValue(declType, out overrideInfo)) {
  1375. _overriddenMethods[declType] = overrideInfo = new Dictionary<string, List<MethodInfo>>();
  1376. }
  1377. List<MethodInfo> methods;
  1378. if (!overrideInfo.TryGetValue(pythonName, out methods)) {
  1379. overrideInfo[pythonName] = methods = new List<MethodInfo>();
  1380. }
  1381. methods.Add(mi);
  1382. }
  1383. }
  1384. private static void StoreOverriddenProperty(MethodInfo mi, string newName) {
  1385. Type baseType = mi.DeclaringType.BaseType;
  1386. lock (PythonTypeOps._propertyCache) {
  1387. string propName = newName.Substring(4); // get_ or set_
  1388. ExtensionPropertyTracker newProp = null;
  1389. foreach (PropertyInfo pi in baseType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy)) {
  1390. if (pi.Name == propName) {
  1391. Type declType = pi.DeclaringType;
  1392. if (newName.StartsWith("get_")) {
  1393. newProp = AddPropertyInfo(declType, propName, mi, null);
  1394. } else if (newName.StartsWith("set_")) {
  1395. newProp = AddPropertyInfo(declType, propName, null, mi);
  1396. }
  1397. }
  1398. }
  1399. if (newProp != null) {
  1400. // back-patch any existing properties so that cached rules will work
  1401. // when called again...
  1402. foreach (ReflectedGetterSetter rg in PythonTypeOps._propertyCache.Values) {
  1403. if (rg.DeclaringType != baseType ||
  1404. rg.__name__ != newProp.Name) {
  1405. continue;
  1406. }
  1407. if (newProp.GetGetMethod(true) != null) {
  1408. rg.AddGetter(newProp.GetGetMethod(true));
  1409. }
  1410. if (newProp.GetSetMethod(true) != null) {
  1411. rg.AddSetter(newProp.GetSetMethod(true));
  1412. }
  1413. }
  1414. }
  1415. }
  1416. }
  1417. private static IEnumerable<string> GetBaseName(MethodInfo mi, Dictionary<string, string[]> specialNames) {
  1418. string newName;
  1419. if (mi.Name.StartsWith(BaseMethodPrefix)) {
  1420. newName = mi.Name.Substring(BaseMethodPrefix.Length);
  1421. } else if (mi.Name.StartsWith(FieldGetterPrefix)) {
  1422. newName = mi.Name.Substring(FieldGetterPrefix.Length);
  1423. } else if (mi.Name.StartsWith(FieldSetterPrefix)) {
  1424. newName = mi.Name.Substring(FieldSetterPrefix.Length);
  1425. } else {
  1426. throw new InvalidOperationException();
  1427. }
  1428. Debug.Assert(specialNames.ContainsKey(newName));
  1429. return specialNames[newName];
  1430. }
  1431. /// <summary>
  1432. /// Called from PythonTypeOps - the BuiltinFunction._function lock must be held.
  1433. /// </summary>
  1434. internal static IList<MethodInfo> GetOverriddenMethods(Type type, string name) {
  1435. Dictionary<string, List<MethodInfo>> methods;
  1436. List<MethodInfo> res = null;
  1437. Type curType = type;
  1438. while (curType != null) {
  1439. if (_overriddenMethods.TryGetValue(curType, out methods)) {
  1440. List<MethodInfo> methodList;
  1441. if (methods.TryGetValue(name, out methodList)) {
  1442. if (res == null) {
  1443. res = new List<MethodInfo>(methodList.Count);
  1444. }
  1445. foreach (MethodInfo method in methodList) {
  1446. if (type.IsAssignableFrom(method.DeclaringType)) {
  1447. res.Add(method);
  1448. }
  1449. }
  1450. }
  1451. }
  1452. curType = curType.BaseType;
  1453. }
  1454. if (res != null) {
  1455. return res;
  1456. }
  1457. return new MethodInfo[0];
  1458. }
  1459. internal static IList<ExtensionPropertyTracker> GetOverriddenProperties(Type type, string name) {
  1460. lock (_overriddenProperties) {
  1461. Dictionary<string, List<ExtensionPropertyTracker>> props;
  1462. if (_overriddenProperties.TryGetValue(type, out props)) {
  1463. List<ExtensionPropertyTracker> propList;
  1464. if (props.TryGetValue(name, out propList)) {
  1465. return propList;
  1466. }
  1467. }
  1468. }
  1469. return new ExtensionPropertyTracker[0];
  1470. }
  1471. #endregion
  1472. }
  1473. /// <summary>
  1474. /// Same as the DLR ReturnFixer, but accepts lower level constructs,
  1475. /// such as LocalBuilder, ParameterInfos and ILGen.
  1476. /// </summary>
  1477. sealed class ReturnFixer {
  1478. private readonly ParameterInfo _parameter;
  1479. private readonly LocalBuilder _reference;
  1480. private readonly int _index;
  1481. private ReturnFixer(LocalBuilder reference, ParameterInfo parameter, int index) {
  1482. Debug.Assert(reference.LocalType.IsGenericType && reference.LocalType.GetGenericTypeDefinition() == typeof(StrongBox<>));
  1483. Debug.Assert(parameter.ParameterType.IsByRef);
  1484. _parameter = parameter;
  1485. _reference = reference;
  1486. _index = index;
  1487. }
  1488. public void FixReturn(ILGen il) {
  1489. il.EmitLoadArg(_index);
  1490. il.Emit(OpCodes.Ldloc, _reference);
  1491. il.EmitFieldGet(_reference.LocalType.GetField("Value"));
  1492. il.EmitStoreValueIndirect(_parameter.ParameterType.GetElementType());
  1493. }
  1494. public static ReturnFixer EmitArgument(ILGen il, ParameterInfo parameter, int index) {
  1495. il.EmitLoadArg(index);
  1496. if (parameter.ParameterType.IsByRef) {
  1497. Type elementType = parameter.ParameterType.GetElementType();
  1498. Type concreteType = typeof(StrongBox<>).MakeGenericType(elementType);
  1499. LocalBuilder refSlot = il.DeclareLocal(concreteType);
  1500. il.EmitLoadValueIndirect(elementType);
  1501. ConstructorInfo ci = concreteType.GetConstructor(new Type[] { elementType });
  1502. il.Emit(OpCodes.Newobj, ci);
  1503. il.Emit(OpCodes.Stloc, refSlot);
  1504. il.Emit(OpCodes.Ldloc, refSlot);
  1505. return new ReturnFixer(refSlot, parameter, index);
  1506. } else {
  1507. il.EmitBoxing(parameter.ParameterType);
  1508. return null;
  1509. }
  1510. }
  1511. }
  1512. }