PageRenderTime 55ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/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

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

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the 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 Som…

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