PageRenderTime 39ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/IronPython_Main/Languages/IronPython/IronPython/Compiler/UncollectableCompilationMode.cs

#
C# | 557 lines | 414 code | 112 blank | 31 comment | 32 complexity | cdd787da53fcf1dd154efcb5b17d9489 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.Dynamic;
  19. using System.Reflection;
  20. using System.Runtime.CompilerServices;
  21. using Microsoft.Scripting;
  22. using Microsoft.Scripting.Ast;
  23. using Microsoft.Scripting.Generation;
  24. using Microsoft.Scripting.Interpreter;
  25. using Microsoft.Scripting.Runtime;
  26. using Microsoft.Scripting.Utils;
  27. using IronPython.Runtime;
  28. #if !CLR2
  29. using MSAst = System.Linq.Expressions;
  30. #else
  31. using MSAst = Microsoft.Scripting.Ast;
  32. #endif
  33. using AstUtils = Microsoft.Scripting.Ast.Utils;
  34. namespace IronPython.Compiler.Ast {
  35. using Ast = MSAst.Expression;
  36. /// <summary>
  37. /// Implements globals which are backed by a static type, followed by an array if the static types' slots become full. The global
  38. /// variables are stored in static fields on a type for fast access. The type also includes fields for constants and call sites
  39. /// so they can be accessed much fasetr.
  40. ///
  41. /// We don't generate any code into the type though - DynamicMethod's are much faster for code gen then normal ref emit.
  42. /// </summary>
  43. partial class UncollectableCompilationMode : CompilationMode {
  44. private static readonly Dictionary<object/*!*/, ConstantInfo/*!*/>/*!*/ _allConstants = new Dictionary<object/*!*/, ConstantInfo/*!*/>();
  45. private static readonly Dictionary<Type/*!*/, DelegateCache/*!*/>/*!*/ _delegateCache = new Dictionary<Type/*!*/, DelegateCache/*!*/>();
  46. public UncollectableCompilationMode() {
  47. }
  48. public override LightLambdaExpression ReduceAst(PythonAst instance, string name) {
  49. return Utils.LightLambda<Func<FunctionCode, object>>(typeof(object), AstUtils.Convert(instance.ReduceWorker(), typeof(object)), name, new[] { PythonAst._functionCode });
  50. }
  51. #region Cached Constant/Symbol/Global Support
  52. public override MSAst.Expression/*!*/ GetConstant(object value) {
  53. // if we can emit the value and we won't be continiously boxing/unboxing
  54. // then don't bother caching the value in a static field.
  55. // TODO: Sometimes we don't want to pre-box the values, such as if it's an int
  56. // going to a call site which can be strongly typed. We need to coordinate
  57. // more with whoever consumes the values.
  58. if (CompilerHelpers.CanEmitConstant(value, CompilerHelpers.GetType(value)) &&
  59. !CompilerHelpers.GetType(value).IsValueType) {
  60. return Utils.Constant(value);
  61. }
  62. ConstantInfo ci;
  63. lock (_allConstants) {
  64. if (!_allConstants.TryGetValue(value, out ci)) {
  65. _allConstants[value] = ci = NextConstant(_allConstants.Count, value);
  66. PublishConstant(value, ci);
  67. }
  68. }
  69. return ci.Expression;
  70. }
  71. public override Type GetConstantType(object value) {
  72. if (value == null || value.GetType().IsValueType) {
  73. return typeof(object);
  74. }
  75. return value.GetType();
  76. }
  77. public override MSAst.Expression GetGlobal(MSAst.Expression globalContext, int arrayIndex, PythonVariable variable, PythonGlobal/*!*/ global) {
  78. Assert.NotNull(global);
  79. lock (StorageData.Globals) {
  80. ConstantInfo info = NextGlobal(0);
  81. StorageData.GlobalStorageType(StorageData.GlobalCount + 1);
  82. PublishWorker(StorageData.GlobalCount, StorageData.GlobalTypes, info, global, StorageData.Globals);
  83. StorageData.GlobalCount += 1;
  84. return new PythonGlobalVariableExpression(info.Expression, variable, global);
  85. }
  86. }
  87. public override Type DelegateType {
  88. get {
  89. return typeof(MSAst.Expression<Func<FunctionCode, object>>);
  90. }
  91. }
  92. #endregion
  93. #region Field Allocation and Publishing
  94. public override UncollectableCompilationMode.ConstantInfo GetContext() {
  95. lock (StorageData.Contexts) {
  96. int index = StorageData.ContextCount++;
  97. int arrIndex = index - StorageData.ContextTypes * StorageData.StaticFields;
  98. Type storageType = StorageData.ContextStorageType(index);
  99. MSAst.Expression expr;
  100. FieldInfo fieldInfo;
  101. if (arrIndex < 0) {
  102. fieldInfo = storageType.GetField(string.Format("Context{0:000}", index % StorageData.StaticFields));
  103. expr = Ast.Field(null, fieldInfo);
  104. } else {
  105. fieldInfo = typeof(StorageData).GetField("Contexts");
  106. expr = Ast.ArrayIndex(
  107. Ast.Field(null, fieldInfo),
  108. Ast.Constant(arrIndex, typeof(int))
  109. );
  110. }
  111. return new ConstantInfo(new CodeContextExpression(expr), fieldInfo, index);
  112. }
  113. }
  114. class CodeContextExpression : MSAst.Expression, IInstructionProvider {
  115. private readonly MSAst.Expression _expression;
  116. public CodeContext Context;
  117. public CodeContextExpression(MSAst.Expression expression) {
  118. _expression = expression;
  119. }
  120. public override MSAst.Expression Reduce() {
  121. return _expression;
  122. }
  123. public override bool CanReduce {
  124. get {
  125. return true;
  126. }
  127. }
  128. public override Type Type {
  129. get {
  130. return typeof(CodeContext);
  131. }
  132. }
  133. public override MSAst.ExpressionType NodeType {
  134. get {
  135. return MSAst.ExpressionType.Extension;
  136. }
  137. }
  138. #region IInstructionProvider Members
  139. public void AddInstructions(LightCompiler compiler) {
  140. compiler.Instructions.EmitLoad(Context);
  141. }
  142. #endregion
  143. }
  144. private static ConstantInfo/*!*/ NextConstant(int offset, object value) {
  145. return new ConstantInfo(new ConstantExpression(offset, value), null, offset);
  146. }
  147. private static ConstantInfo/*!*/ NextGlobal(int offset) {
  148. return new ConstantInfo(new GlobalExpression(offset), null, offset);
  149. }
  150. // public for accessibility via GetMethod("NextSite")
  151. public static SiteInfo/*!*/ NextSite<T>(DynamicMetaObjectBinder/*!*/ binder) where T : class {
  152. lock (StorageData.SiteLockObj) {
  153. int index = SiteStorage<T>.SiteCount++;
  154. int arrIndex = index - StorageData.SiteTypes * StorageData.StaticFields;
  155. Type storageType = SiteStorage<T>.SiteStorageType(index);
  156. MSAst.Expression expr;
  157. FieldInfo fieldInfo;
  158. if (arrIndex < 0) {
  159. fieldInfo = storageType.GetField(string.Format("Site{0:000}", index % StorageData.StaticFields));
  160. expr = Ast.Field(null, fieldInfo);
  161. } else {
  162. fieldInfo = typeof(SiteStorage<T>).GetField("Sites");
  163. expr = Ast.ArrayIndex(
  164. Ast.Field(null, fieldInfo),
  165. Ast.Constant(arrIndex, typeof(int))
  166. );
  167. }
  168. return PublishSite(new SiteInfo<T>(binder, expr, fieldInfo, index));
  169. }
  170. }
  171. // Note: This should stay non-public to avoid name conflicts when accessing the
  172. // generic overload via GetMethod("NextSite")
  173. private static SiteInfo/*!*/ NextSite(DynamicMetaObjectBinder/*!*/ binder, Type/*!*/ delegateType) {
  174. Type siteType = typeof(SiteStorage<>).MakeGenericType(delegateType);
  175. lock (StorageData.SiteLockObj) {
  176. int index = (int)siteType.GetField("SiteCount").GetValue(null);
  177. siteType.GetField("SiteCount").SetValue(null, index + 1);
  178. int arrIndex = index - StorageData.SiteTypes * StorageData.StaticFields;
  179. Type storageType = (Type)siteType.GetMethod("SiteStorageType").Invoke(null, new object[] { index });
  180. MSAst.Expression expr;
  181. FieldInfo fieldInfo;
  182. if (arrIndex < 0) {
  183. fieldInfo = storageType.GetField(string.Format("Site{0:000}", index % StorageData.StaticFields));
  184. expr = Ast.Field(null, fieldInfo);
  185. } else {
  186. fieldInfo = siteType.GetField("Sites");
  187. expr = Ast.ArrayIndex(
  188. Ast.Field(null, fieldInfo),
  189. Ast.Constant(arrIndex, typeof(int))
  190. );
  191. }
  192. return PublishSite(new SiteInfoLarge(binder, expr, fieldInfo, index, delegateType));
  193. }
  194. }
  195. public override void PublishContext(CodeContext/*!*/ context, ConstantInfo/*!*/ codeContextInfo) {
  196. int arrIndex = codeContextInfo.Offset - StorageData.ContextTypes * StorageData.StaticFields;
  197. if (arrIndex < 0) {
  198. codeContextInfo.Field.SetValue(null, context);
  199. } else {
  200. lock (StorageData.Contexts) {
  201. StorageData.Contexts[arrIndex] = context;
  202. }
  203. }
  204. ((CodeContextExpression)codeContextInfo.Expression).Context = context;
  205. }
  206. private static void PublishConstant(object constant, ConstantInfo info) {
  207. StorageData.ConstantStorageType(info.Offset);
  208. PublishWorker(0, StorageData.ConstantTypes, info, constant, StorageData.Constants);
  209. }
  210. private static SiteInfo PublishSite(SiteInfo si) {
  211. int arrIndex = si.Offset - StorageData.SiteTypes * StorageData.StaticFields;
  212. CallSite site = si.MakeSite();
  213. if (arrIndex < 0) {
  214. si.Field.SetValue(null, site);
  215. } else {
  216. lock (StorageData.SiteLockObj) {
  217. ((CallSite[])si.Field.GetValue(null))[arrIndex] = site;
  218. }
  219. }
  220. return si;
  221. }
  222. private static void PublishWorker<T>(int start, int nTypes, ConstantInfo info, T value, T[] fallbackArray) {
  223. int arrIndex = start + info.Offset - nTypes * StorageData.StaticFields;
  224. ((ReducibleExpression)info.Expression).Start = start;
  225. if (arrIndex < 0) {
  226. ((ReducibleExpression)info.Expression).FieldInfo.SetValue(null, value);
  227. } else {
  228. fallbackArray[arrIndex] = value;
  229. }
  230. }
  231. #endregion
  232. #region ConstantInfo
  233. public class ConstantInfo {
  234. public readonly MSAst.Expression/*!*/ Expression;
  235. public readonly FieldInfo Field;
  236. public readonly int Offset;
  237. public ConstantInfo(MSAst.Expression/*!*/ expr, FieldInfo field, int offset) {
  238. Assert.NotNull(expr);
  239. Expression = expr;
  240. Field = field;
  241. Offset = offset;
  242. }
  243. }
  244. public abstract class SiteInfo : ConstantInfo {
  245. public readonly DynamicMetaObjectBinder/*!*/ Binder;
  246. public readonly Type/*!*/ DelegateType;
  247. protected Type/*!*/ _siteType;
  248. public Type/*!*/ SiteType {
  249. get {
  250. if (_siteType != null) {
  251. _siteType = typeof(CallSite<>).MakeGenericType(DelegateType);
  252. }
  253. return _siteType;
  254. }
  255. }
  256. public SiteInfo(DynamicMetaObjectBinder/*!*/ binder, MSAst.Expression/*!*/ expr, FieldInfo/*!*/ field, int index, Type/*!*/ delegateType)
  257. : base(expr, field, index) {
  258. Assert.NotNull(binder);
  259. Binder = binder;
  260. DelegateType = delegateType;
  261. }
  262. public SiteInfo(DynamicMetaObjectBinder/*!*/ binder, MSAst.Expression/*!*/ expr, FieldInfo/*!*/ field, int index, Type/*!*/ delegateType, Type/*!*/ siteType)
  263. : this(binder, expr, field, index, delegateType) {
  264. _siteType = siteType;
  265. }
  266. public abstract CallSite/*!*/ MakeSite();
  267. }
  268. public class SiteInfoLarge : SiteInfo {
  269. public SiteInfoLarge(DynamicMetaObjectBinder/*!*/ binder, MSAst.Expression/*!*/ expr, FieldInfo/*!*/ field, int index, Type/*!*/ delegateType)
  270. : base (binder, expr, field, index, delegateType) { }
  271. public override CallSite MakeSite() {
  272. return CallSite.Create(DelegateType, Binder);
  273. }
  274. }
  275. public class SiteInfo<T> : SiteInfo where T : class {
  276. public SiteInfo(DynamicMetaObjectBinder/*!*/ binder, MSAst.Expression/*!*/ expr, FieldInfo/*!*/ field, int index)
  277. : base(binder, expr, field, index, typeof(T), typeof(CallSite<T>)) { }
  278. public override CallSite MakeSite() {
  279. return CallSite<T>.Create(Binder);
  280. }
  281. }
  282. #endregion
  283. #region Dynamic CallSite Type Information
  284. private sealed class DelegateCache {
  285. public Type/*!*/ DelegateType;
  286. public Type/*!*/ SiteType;
  287. public Func<DynamicMetaObjectBinder/*!*/, SiteInfo/*!*/>/*!*/ NextSite;
  288. public FieldInfo/*!*/ TargetField; // SiteType.GetField("Target")
  289. public MethodInfo/*!*/ InvokeMethod; // DelegateType.GetMethod("Invoke")
  290. public Dictionary<Type/*!*/, DelegateCache> TypeChain;
  291. public void MakeDelegateType(Type/*!*/ retType, params MSAst.Expression/*!*/[]/*!*/ args) {
  292. DelegateType = GetDelegateType(retType, args);
  293. SiteType = typeof(CallSite<>).MakeGenericType(DelegateType);
  294. NextSite = (Func<DynamicMetaObjectBinder, SiteInfo>)Delegate.CreateDelegate(
  295. typeof(Func<DynamicMetaObjectBinder, SiteInfo>),
  296. typeof(UncollectableCompilationMode).GetMethod("NextSite").MakeGenericMethod(DelegateType)
  297. );
  298. TargetField = SiteType.GetField("Target");
  299. InvokeMethod = DelegateType.GetMethod("Invoke");
  300. }
  301. public static DelegateCache FirstCacheNode(Type/*!*/ argType) {
  302. DelegateCache nextCacheNode;
  303. if (!_delegateCache.TryGetValue(argType, out nextCacheNode)) {
  304. nextCacheNode = new DelegateCache();
  305. _delegateCache[argType] = nextCacheNode;
  306. }
  307. return nextCacheNode;
  308. }
  309. public DelegateCache NextCacheNode(Type/*!*/ argType) {
  310. Assert.NotNull(argType);
  311. DelegateCache nextCacheNode;
  312. if (TypeChain == null) {
  313. TypeChain = new Dictionary<Type, DelegateCache>();
  314. }
  315. if (!TypeChain.TryGetValue(argType, out nextCacheNode)) {
  316. nextCacheNode = new DelegateCache();
  317. TypeChain[argType] = nextCacheNode;
  318. }
  319. return nextCacheNode;
  320. }
  321. }
  322. #endregion
  323. #region Reducible Expressions
  324. internal abstract class ReducibleExpression : MSAst.Expression {
  325. private readonly int _offset;
  326. private int _start = -1;
  327. private FieldInfo _fieldInfo;
  328. public ReducibleExpression(int offset) {
  329. _offset = offset;
  330. }
  331. public abstract string/*!*/ Name { get; }
  332. public abstract int FieldCount { get; }
  333. public abstract override Type/*!*/ Type { get; }
  334. protected abstract Type/*!*/ GetStorageType(int index);
  335. public FieldInfo FieldInfo {
  336. get {
  337. return _fieldInfo;
  338. }
  339. }
  340. // Note: Because of a call to GetStorageType, which possibly resizes a storage
  341. // array, a lock must be acquired prior to setting this property.
  342. public int Start {
  343. get {
  344. return _start;
  345. }
  346. set {
  347. Debug.Assert(_start < 0); // setter should only be called once
  348. Debug.Assert(value >= 0);
  349. _start = value;
  350. int index = _offset + _start;
  351. Type storageType = GetStorageType(index);
  352. if (storageType != typeof(StorageData)) {
  353. _fieldInfo = storageType.GetField(Name + string.Format("{0:000}", index % StorageData.StaticFields));
  354. } else {
  355. _fieldInfo = typeof(StorageData).GetField(Name + "s");
  356. }
  357. }
  358. }
  359. public override MSAst.Expression/*!*/ Reduce() {
  360. Debug.Assert(_start >= 0);
  361. Assert.NotNull(_fieldInfo);
  362. int index = _offset + _start;
  363. int arrIndex = index - FieldCount;
  364. if (arrIndex < 0) {
  365. return Ast.Field(null, _fieldInfo);
  366. } else {
  367. return Ast.ArrayIndex(
  368. Ast.Field(null, _fieldInfo),
  369. Ast.Constant(arrIndex, typeof(int))
  370. );
  371. }
  372. }
  373. public override MSAst.ExpressionType NodeType {
  374. get {
  375. return MSAst.ExpressionType.Extension;
  376. }
  377. }
  378. protected override MSAst.Expression Accept(MSAst.ExpressionVisitor visitor) {
  379. return this;
  380. }
  381. protected override MSAst.Expression VisitChildren(MSAst.ExpressionVisitor visitor) {
  382. return this;
  383. }
  384. public override bool CanReduce {
  385. get {
  386. return true;
  387. }
  388. }
  389. }
  390. internal sealed class ConstantExpression : ReducibleExpression {
  391. private object _value;
  392. public ConstantExpression(int offset, object value) : base(offset) {
  393. Type returnType = value.GetType();
  394. _value = value;
  395. }
  396. public override string/*!*/ Name {
  397. get { return "Constant"; }
  398. }
  399. public override int FieldCount {
  400. get { return StorageData.ConstantTypes * StorageData.StaticFields; }
  401. }
  402. protected override Type/*!*/ GetStorageType(int index) {
  403. return StorageData.ConstantStorageType(index);
  404. }
  405. public override Type/*!*/ Type {
  406. get {
  407. Type returnType = _value.GetType();
  408. if (!returnType.IsValueType) {
  409. return returnType;
  410. } else {
  411. return typeof(object);
  412. }
  413. }
  414. }
  415. public object Value {
  416. get {
  417. return _value;
  418. }
  419. }
  420. public override MSAst.Expression Reduce() {
  421. if (_value.GetType().IsValueType) {
  422. return base.Reduce();
  423. } else {
  424. return MSAst.Expression.Convert(base.Reduce(), _value.GetType());
  425. }
  426. }
  427. }
  428. internal sealed class GlobalExpression : ReducibleExpression {
  429. public GlobalExpression(int offset) : base(offset) { }
  430. public override string/*!*/ Name {
  431. get { return "Global"; }
  432. }
  433. public override int FieldCount {
  434. get { return StorageData.GlobalTypes * StorageData.StaticFields; }
  435. }
  436. protected override Type/*!*/ GetStorageType(int index) {
  437. return StorageData.GlobalStorageType(index);
  438. }
  439. public override Type/*!*/ Type {
  440. get { return typeof(PythonGlobal); }
  441. }
  442. }
  443. #endregion
  444. }
  445. }