PageRenderTime 69ms CodeModel.GetById 11ms app.highlight 51ms RepoModel.GetById 2ms app.codeStats 0ms

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

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