InstructionList.cs :  » Script » IronRuby » Microsoft » Scripting » Interpreter » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Script » IronRuby 
IronRuby » Microsoft » Scripting » Interpreter » InstructionList.cs
/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/
// Enables instruction counting and displaying stats at process exit.
// #define STATS

#if !CLR2
using System.Linq.Expressions;
#else
using Microsoft.Scripting.Ast;
#endif

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using Microsoft.Scripting.Utils;
using AstUtilsMicrosoft.Scripting.Ast.Utils;
using Microsoft.Scripting.Generation;
using Microsoft.Scripting.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Microsoft.Scripting.Interpreter{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")]
    [DebuggerTypeProxy(typeof(InstructionArray.DebugView))]
    public struct InstructionArray {
        internal readonly int MaxStackDepth;
        internal readonly int MaxContinuationDepth;
        internal readonly Instruction[] Instructions;
        internal readonly object[] Objects;
        internal readonly RuntimeLabel[] Labels;

        // list of (instruction index, cookie) sorted by instruction index:
        internal readonly List<KeyValuePair<int, object>> DebugCookies;

        internal InstructionArray(int maxStackDepth, int maxContinuationDepth, Instruction[] instructions, 
            object[] objects, RuntimeLabel[] labels, List<KeyValuePair<int, object>> debugCookies) {

            MaxStackDepth = maxStackDepth;
            MaxContinuationDepth = maxContinuationDepth;
            Instructions = instructions;
            DebugCookies = debugCookies;
            Objects = objects;
            Labels = labels;
        }

        internal int Length {
            get { return Instructions.Length; }
        }

        #region Debug View

        internal sealed class DebugView {
            private readonly InstructionArray _array;

            public DebugView(InstructionArray array) {
                _array = array;

            }

            [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
            public InstructionList.DebugView.InstructionView[]/*!*/ A0 {
                get {
                    return InstructionList.DebugView.GetInstructionViews(
                        _array.Instructions, 
                        _array.Objects, 
                        (index) => _array.Labels[index].Index, 
                        _array.DebugCookies
                    );
                }
            }
        }

        #endregion
    }

    [DebuggerTypeProxy(typeof(InstructionList.DebugView))]
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
    public sealed class InstructionList {
        private readonly List<Instruction> _instructions = new List<Instruction>();
        private List<object> _objects;

        private int _currentStackDepth;
        private int _maxStackDepth;
        private int _currentContinuationsDepth;
        private int _maxContinuationDepth;
        private int _runtimeLabelCount;
        private List<BranchLabel> _labels;
        
        // list of (instruction index, cookie) sorted by instruction index:
        private List<KeyValuePair<int, object>> _debugCookies = null;

        #region Debug View

        internal sealed class DebugView {
            private readonly InstructionList _list;

            public DebugView(InstructionList list) {
                _list = list;
            }

            [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
            public InstructionView[]/*!*/ A0 {
                get {
                    return GetInstructionViews(
                        _list._instructions, 
                        _list._objects, 
                        (index) => _list._labels[index].TargetIndex, 
                        _list._debugCookies
                    );
                }
            }

            internal static InstructionView[] GetInstructionViews(IList<Instruction> instructions, IList<object> objects,
                Func<int, int> labelIndexer, IList<KeyValuePair<int, object>> debugCookies) {

                var result = new List<InstructionView>();
                int index = 0;
                int stackDepth = 0;
                int continuationsDepth = 0;

                var cookieEnumerator = (debugCookies != null ? debugCookies : new KeyValuePair<int, object>[0]).GetEnumerator();
                var hasCookie = cookieEnumerator.MoveNext();

                for (int i = 0; i < instructions.Count; i++) {
                    object cookie = null;
                    while (hasCookie && cookieEnumerator.Current.Key == i) {
                        cookie = cookieEnumerator.Current.Value;
                        hasCookie = cookieEnumerator.MoveNext();
                    }

                    int stackDiff = instructions[i].StackBalance;
                    int contDiff = instructions[i].ContinuationsBalance;
                    string name = instructions[i].ToDebugString(i, cookie, labelIndexer, objects);
                    result.Add(new InstructionView(instructions[i], name, i, stackDepth, continuationsDepth));
                    
                    index++;
                    stackDepth += stackDiff;
                    continuationsDepth += contDiff;
                }
                return result.ToArray();
            }

            [DebuggerDisplay("{GetValue(),nq}", Name = "{GetName(),nq}", Type = "{GetDisplayType(), nq}")]
            internal struct InstructionView {
                private readonly int _index;
                private readonly int _stackDepth;
                private readonly int _continuationsDepth;
                private readonly string _name;
                private readonly Instruction _instruction;

                internal string GetName() {
                    return _index.ToString() +
                        (_continuationsDepth == 0 ? "" : " C(" + _continuationsDepth.ToString() + ")") +
                        (_stackDepth == 0 ? "" : " S(" + _stackDepth.ToString() + ")");
                }

                internal string GetValue() {
                    return _name;
                }

                internal string GetDisplayType() {
                    return _instruction.ContinuationsBalance.ToString() + "/" + _instruction.StackBalance.ToString();
                }

                public InstructionView(Instruction instruction, string name, int index, int stackDepth, int continuationsDepth) {
                    _instruction = instruction;
                    _name = name;
                    _index = index;
                    _stackDepth = stackDepth;
                    _continuationsDepth = continuationsDepth;
                }
            }
        }
                        
        #endregion

        #region Core Emit Ops

        public void Emit(Instruction instruction) {
            _instructions.Add(instruction);
            UpdateStackDepth(instruction);
        }

        private void UpdateStackDepth(Instruction instruction) {
            Debug.Assert(instruction.ConsumedStack >= 0 && instruction.ProducedStack >= 0 &&
                instruction.ConsumedContinuations >= 0 && instruction.ProducedContinuations >= 0);

            _currentStackDepth -= instruction.ConsumedStack;
            Debug.Assert(_currentStackDepth >= 0);
            _currentStackDepth += instruction.ProducedStack;
            if (_currentStackDepth > _maxStackDepth) {
                _maxStackDepth = _currentStackDepth;
            }

            _currentContinuationsDepth -= instruction.ConsumedContinuations;
            Debug.Assert(_currentContinuationsDepth >= 0);
            _currentContinuationsDepth += instruction.ProducedContinuations;
            if (_currentContinuationsDepth > _maxContinuationDepth) {
                _maxContinuationDepth = _currentContinuationsDepth;
            }
        }

        /// <summary>
        /// Attaches a cookie to the last emitted instruction.
        /// </summary>
        [Conditional("DEBUG")]
        public void SetDebugCookie(object cookie) {
#if DEBUG
            if (_debugCookies == null) {
                _debugCookies = new List<KeyValuePair<int, object>>();
            }

            Debug.Assert(Count > 0);
            _debugCookies.Add(new KeyValuePair<int, object>(Count - 1, cookie));
#endif
        }

        public int Count {
            get { return _instructions.Count; }
        }

        public int CurrentStackDepth {
            get { return _currentStackDepth; }
        }

        public int CurrentContinuationsDepth {
            get { return _currentContinuationsDepth; }
        }

        public int MaxStackDepth {
            get { return _maxStackDepth; }
        }

        internal Instruction GetInstruction(int index) {
            return _instructions[index];
        }

#if STATS
        private static Dictionary<string, int> _executedInstructions = new Dictionary<string, int>();
        private static Dictionary<string, Dictionary<object, bool>> _instances = new Dictionary<string, Dictionary<object, bool>>();

        static InstructionList() {
            AppDomain.CurrentDomain.ProcessExit += new EventHandler((_, __) => {
                PerfTrack.DumpHistogram(_executedInstructions);
                Console.WriteLine("-- Total executed: {0}", _executedInstructions.Values.Aggregate(0, (sum, value) => sum + value));
                Console.WriteLine("-----");

                var referenced = new Dictionary<string, int>();
                int total = 0;
                foreach (var entry in _instances) {
                    referenced[entry.Key] = entry.Value.Count;
                    total += entry.Value.Count;
                }

                PerfTrack.DumpHistogram(referenced);
                Console.WriteLine("-- Total referenced: {0}", total);
                Console.WriteLine("-----");
            });
        }
#endif
        public InstructionArray ToArray() {
#if STATS
            lock (_executedInstructions) {
                _instructions.ForEach((instr) => {
                    int value = 0;
                    var name = instr.GetType().Name;
                    _executedInstructions.TryGetValue(name, out value);
                    _executedInstructions[name] = value + 1;

                    Dictionary<object, bool> dict;
                    if (!_instances.TryGetValue(name, out dict)) {
                        _instances[name] = dict = new Dictionary<object, bool>();
                    }
                    dict[instr] = true;
                });
            }
#endif
            return new InstructionArray(
                _maxStackDepth,
                _maxContinuationDepth,
                _instructions.ToArray(),                
                (_objects != null) ? _objects.ToArray() : null,
                BuildRuntimeLabels(),
                _debugCookies
            );
        }

        #endregion

        #region Stack Operations

        private const int PushIntMinCachedValue = -100;
        private const int PushIntMaxCachedValue = 100;
        private const int CachedObjectCount = 256;

        private static Instruction _null;
        private static Instruction _true;
        private static Instruction _false;
        private static Instruction[] _ints;
        private static Instruction[] _loadObjectCached;

        public void EmitLoad(object value) {
            EmitLoad(value, null);
        }

        public void EmitLoad(bool value) {
            if ((bool)value) {
                Emit(_true ?? (_true = new LoadObjectInstruction(value)));
            } else {
                Emit(_false ?? (_false = new LoadObjectInstruction(value)));
            }
        }

        public void EmitLoad(object value, Type type) {
            if (value == null) {
                Emit(_null ?? (_null = new LoadObjectInstruction(null)));
                return;
            }

            if (type == null || type.IsValueType) {
                if (value is bool) {
                    EmitLoad((bool)value);
                    return;
                } 
                
                if (value is int) {
                    int i = (int)value;
                    if (i >= PushIntMinCachedValue && i <= PushIntMaxCachedValue) {
                        if (_ints == null) {
                            _ints = new Instruction[PushIntMaxCachedValue - PushIntMinCachedValue + 1];
                        }
                        i -= PushIntMinCachedValue;
                        Emit(_ints[i] ?? (_ints[i] = new LoadObjectInstruction(value)));
                        return;
                    }
                }
            }

            if (_objects == null) {
                _objects = new List<object>();
                if (_loadObjectCached == null) {
                    _loadObjectCached = new Instruction[CachedObjectCount];
                }
            }

            if (_objects.Count < _loadObjectCached.Length) {
                uint index = (uint)_objects.Count;
                _objects.Add(value);
                Emit(_loadObjectCached[index] ?? (_loadObjectCached[index] = new LoadCachedObjectInstruction(index)));
            } else {
                Emit(new LoadObjectInstruction(value));
            }
        }

        public void EmitDup() {
            Emit(DupInstruction.Instance);
        }

        public void EmitPop() {
            Emit(PopInstruction.Instance);
        }

        #endregion

        #region Locals

        internal void SwitchToBoxed(int index, int instructionIndex) {
            var instruction = _instructions[instructionIndex] as IBoxableInstruction;

            if (instruction != null) {
                var newInstruction = instruction.BoxIfIndexMatches(index);
                if (newInstruction != null) {
                    _instructions[instructionIndex] = newInstruction;
                }
            }
        }

        private const int LocalInstrCacheSize = 64;

        private static Instruction[] _loadLocal;
        private static Instruction[] _loadLocalBoxed;
        private static Instruction[] _loadLocalFromClosure;
        private static Instruction[] _loadLocalFromClosureBoxed;
        private static Instruction[] _assignLocal;
        private static Instruction[] _storeLocal;
        private static Instruction[] _assignLocalBoxed;
        private static Instruction[] _storeLocalBoxed;
        private static Instruction[] _assignLocalToClosure;
        private static Instruction[] _initReference;
        private static Instruction[] _initImmutableRefBox;
        private static Instruction[] _parameterBox;
        private static Instruction[] _parameter;

        public void EmitLoadLocal(int index) {
            if (_loadLocal == null) {
                _loadLocal = new Instruction[LocalInstrCacheSize];
            }

            if (index < _loadLocal.Length) {
                Emit(_loadLocal[index] ?? (_loadLocal[index] = new LoadLocalInstruction(index)));
            } else {
                Emit(new LoadLocalInstruction(index));
            }
        }

        public void EmitLoadLocalBoxed(int index) {
            Emit(LoadLocalBoxed(index));
        }

        internal static Instruction LoadLocalBoxed(int index) {
            if (_loadLocalBoxed == null) {
                _loadLocalBoxed = new Instruction[LocalInstrCacheSize];
            }

            if (index < _loadLocalBoxed.Length) {
                return _loadLocalBoxed[index] ?? (_loadLocalBoxed[index] = new LoadLocalBoxedInstruction(index));
            } else {
                return new LoadLocalBoxedInstruction(index);
            }
        }

        public void EmitLoadLocalFromClosure(int index) {
            if (_loadLocalFromClosure == null) {
                _loadLocalFromClosure = new Instruction[LocalInstrCacheSize];
            }

            if (index < _loadLocalFromClosure.Length) {
                Emit(_loadLocalFromClosure[index] ?? (_loadLocalFromClosure[index] = new LoadLocalFromClosureInstruction(index)));
            } else {
                Emit(new LoadLocalFromClosureInstruction(index));
            }
        }

        public void EmitLoadLocalFromClosureBoxed(int index) {
            if (_loadLocalFromClosureBoxed == null) {
                _loadLocalFromClosureBoxed = new Instruction[LocalInstrCacheSize];
            }

            if (index < _loadLocalFromClosureBoxed.Length) {
                Emit(_loadLocalFromClosureBoxed[index] ?? (_loadLocalFromClosureBoxed[index] = new LoadLocalFromClosureBoxedInstruction(index)));
            } else {
                Emit(new LoadLocalFromClosureBoxedInstruction(index));
            }
        }

        public void EmitAssignLocal(int index) {
            if (_assignLocal == null) {
                _assignLocal = new Instruction[LocalInstrCacheSize];
            }

            if (index < _assignLocal.Length) {
                Emit(_assignLocal[index] ?? (_assignLocal[index] = new AssignLocalInstruction(index)));
            } else {
                Emit(new AssignLocalInstruction(index));
            }
        }

        public void EmitStoreLocal(int index) {
            if (_storeLocal == null) {
                _storeLocal = new Instruction[LocalInstrCacheSize];
            }

            if (index < _storeLocal.Length) {
                Emit(_storeLocal[index] ?? (_storeLocal[index] = new StoreLocalInstruction(index)));
            } else {
                Emit(new StoreLocalInstruction(index));
            }
        }

        public void EmitAssignLocalBoxed(int index) {
            Emit(AssignLocalBoxed(index));
        }

        internal static Instruction AssignLocalBoxed(int index) {
            if (_assignLocalBoxed == null) {
                _assignLocalBoxed = new Instruction[LocalInstrCacheSize];
            }

            if (index < _assignLocalBoxed.Length) {
                return _assignLocalBoxed[index] ?? (_assignLocalBoxed[index] = new AssignLocalBoxedInstruction(index));
            } else {
                return new AssignLocalBoxedInstruction(index);
            }
        }

        public void EmitStoreLocalBoxed(int index) {
            Emit(StoreLocalBoxed(index));
        }

        internal static Instruction StoreLocalBoxed(int index) {
            if (_storeLocalBoxed == null) {
                _storeLocalBoxed = new Instruction[LocalInstrCacheSize];
            }

            if (index < _storeLocalBoxed.Length) {
                return _storeLocalBoxed[index] ?? (_storeLocalBoxed[index] = new StoreLocalBoxedInstruction(index));
            } else {
                return new StoreLocalBoxedInstruction(index);
            }
        }

        public void EmitAssignLocalToClosure(int index) {
            if (_assignLocalToClosure == null) {
                _assignLocalToClosure = new Instruction[LocalInstrCacheSize];
            }

            if (index < _assignLocalToClosure.Length) {
                Emit(_assignLocalToClosure[index] ?? (_assignLocalToClosure[index] = new AssignLocalToClosureInstruction(index)));
            } else {
                Emit(new AssignLocalToClosureInstruction(index));
            }
        }

        public void EmitStoreLocalToClosure(int index) {
            EmitAssignLocalToClosure(index);
            EmitPop();
        }

        public void EmitInitializeLocal(int index, Type type) {
            object value = ScriptingRuntimeHelpers.GetPrimitiveDefaultValue(type);
            if (value != null) {
                Emit(new InitializeLocalInstruction.ImmutableValue(index, value));
            } else if (type.IsValueType) {
                Emit(new InitializeLocalInstruction.MutableValue(index, type));
            } else {
                Emit(InitReference(index));
            }
        }

        internal void EmitInitializeParameter(int index) {
            Emit(Parameter(index));
        }

        internal static Instruction Parameter(int index) {
            if (_parameter == null) {
                _parameter = new Instruction[LocalInstrCacheSize];
            }

            if (index < _parameter.Length) {
                return _parameter[index] ?? (_parameter[index] = new InitializeLocalInstruction.Parameter(index));
            }

            return new InitializeLocalInstruction.Parameter(index);
        }

        internal static Instruction ParameterBox(int index) {
            if (_parameterBox == null) {
                _parameterBox = new Instruction[LocalInstrCacheSize];
            }

            if (index < _parameterBox.Length) {
                return _parameterBox[index] ?? (_parameterBox[index] = new InitializeLocalInstruction.ParameterBox(index));
            }

            return new InitializeLocalInstruction.ParameterBox(index);
        }

        internal static Instruction InitReference(int index) {
            if (_initReference == null) {
                _initReference = new Instruction[LocalInstrCacheSize];
            }

            if (index < _initReference.Length) {
                return _initReference[index] ?? (_initReference[index] = new InitializeLocalInstruction.Reference(index));
            }

            return new InitializeLocalInstruction.Reference(index);
        }

        internal static Instruction InitImmutableRefBox(int index) {
            if (_initImmutableRefBox == null) {
                _initImmutableRefBox = new Instruction[LocalInstrCacheSize];
            }

            if (index < _initImmutableRefBox.Length) {
                return _initImmutableRefBox[index] ?? (_initImmutableRefBox[index] = new InitializeLocalInstruction.ImmutableBox(index, null));
            }

            return new InitializeLocalInstruction.ImmutableBox(index, null);
        }

        public void EmitNewRuntimeVariables(int count) {
            Emit(new RuntimeVariablesInstruction(count));
        }

        #endregion

        #region Array Operations

        public void EmitGetArrayItem(Type arrayType) {
            Type elementType = arrayType.GetElementType();
            if (elementType.IsClass || elementType.IsInterface) {
                Emit(InstructionFactory<object>.Factory.GetArrayItem());
            } else {
                Emit(InstructionFactory.GetFactory(elementType).GetArrayItem());
            }
        }

        public void EmitSetArrayItem(Type arrayType) {
            Type elementType = arrayType.GetElementType();
            if (elementType.IsClass || elementType.IsInterface) {
                Emit(InstructionFactory<object>.Factory.SetArrayItem());
            } else {
                Emit(InstructionFactory.GetFactory(elementType).SetArrayItem());
            }
        }

        public void EmitNewArray(Type elementType) {
            Emit(InstructionFactory.GetFactory(elementType).NewArray());
        }

        public void EmitNewArrayBounds(Type elementType, int rank) {
            Emit(new NewArrayBoundsInstruction(elementType, rank));
        }

        public void EmitNewArrayInit(Type elementType, int elementCount) {
            Emit(InstructionFactory.GetFactory(elementType).NewArrayInit(elementCount));
        }

        #endregion

        #region Arithmetic Operations

        public void EmitAdd(Type type, bool @checked) {
            if (@checked) {
                Emit(AddOvfInstruction.Create(type));
            } else {
                Emit(AddInstruction.Create(type));
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
        public void EmitSub(Type type, bool @checked) {
            throw new NotSupportedException();
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
        public void EmitMul(Type type, bool @checked) {
            throw new NotSupportedException();
        }

        public void EmitDiv(Type type) {
            Emit(DivInstruction.Create(type));
        }

        #endregion

        #region Comparisons

        public void EmitEqual(Type type) {
            Emit(EqualInstruction.Create(type));
        }

        public void EmitNotEqual(Type type) {
            Emit(NotEqualInstruction.Create(type));
        }

        public void EmitLessThan(Type type) {
            Emit(LessThanInstruction.Create(type));
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
        public void EmitLessThanOrEqual(Type type) {
            throw new NotSupportedException();
        }

        public void EmitGreaterThan(Type type) {
            Emit(GreaterThanInstruction.Create(type));
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
        public void EmitGreaterThanOrEqual(Type type) {
            throw new NotSupportedException();
        }

        #endregion

        #region Conversions

        public void EmitNumericConvertChecked(TypeCode from, TypeCode to) {
            Emit(new NumericConvertInstruction.Checked(from, to));
        }

        public void EmitNumericConvertUnchecked(TypeCode from, TypeCode to) {
            Emit(new NumericConvertInstruction.Unchecked(from, to));
        }

        #endregion

        #region Boolean Operators

        public void EmitNot() {
            Emit(NotInstruction.Instance);
        }

        #endregion

        #region Types

        public void EmitDefaultValue(Type type) {
            Emit(InstructionFactory.GetFactory(type).DefaultValue());
        }

        public void EmitNew(ConstructorInfo constructorInfo) {
            Emit(new NewInstruction(constructorInfo));
        }

        internal void EmitCreateDelegate(LightDelegateCreator creator) {
            Emit(new CreateDelegateInstruction(creator));
        }

        public void EmitTypeEquals() {
            Emit(TypeEqualsInstruction.Instance);
        }

        public void EmitTypeIs(Type type) {
            Emit(InstructionFactory.GetFactory(type).TypeIs());
        }

        public void EmitTypeAs(Type type) {
            Emit(InstructionFactory.GetFactory(type).TypeAs());
        }

        #endregion

        #region Fields and Methods

        private static readonly Dictionary<FieldInfo, Instruction> _loadFields = new Dictionary<FieldInfo, Instruction>();

        public void EmitLoadField(FieldInfo field) {
            Emit(GetLoadField(field));
        }

        private Instruction GetLoadField(FieldInfo field) {
            lock (_loadFields) {
                Instruction instruction;
                if (!_loadFields.TryGetValue(field, out instruction)) {
                    if (field.IsStatic) {
                        instruction = new LoadStaticFieldInstruction(field);
                    } else {
                        instruction = new LoadFieldInstruction(field);
                    }
                    _loadFields.Add(field, instruction);
                }
                return instruction;
            }
        }
        
        public void EmitStoreField(FieldInfo field) {
            if (field.IsStatic) {
                Emit(new StoreStaticFieldInstruction(field));
            } else {
                Emit(new StoreFieldInstruction(field));
            }
        }

        public void EmitCall(MethodInfo method) {
            EmitCall(method, method.GetParameters());
        }

        public void EmitCall(MethodInfo method, ParameterInfo[] parameters) {
            Emit(CallInstruction.Create(method, parameters));
        }

        #endregion

        #region Dynamic

        public void EmitDynamic(Type type, CallSiteBinder binder) {
            Emit(CreateDynamicInstruction(type, binder));
        }

        private static Dictionary<Type, Func<CallSiteBinder, Instruction>> _factories =
            new Dictionary<Type, Func<CallSiteBinder, Instruction>>();

        internal static Instruction CreateDynamicInstruction(Type delegateType, CallSiteBinder binder) {
            Func<CallSiteBinder, Instruction> factory;
            lock (_factories) {
                if (!_factories.TryGetValue(delegateType, out factory)) {
                    if (delegateType.GetMethod("Invoke").ReturnType == typeof(void)) {
                        // TODO: We should generally support void returning binders but the only
                        // ones that exist are delete index/member who's perf isn't that critical.
                        return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder), true);
                    }

                    Type instructionType = DynamicInstructionN.GetDynamicInstructionType(delegateType);
                    if (instructionType == null) {
                        return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder));
                    }

                    factory = (Func<CallSiteBinder, Instruction>)Delegate.CreateDelegate(
                        typeof(Func<CallSiteBinder, Instruction>),
                        instructionType.GetMethod("Factory")
                    );

                    _factories[delegateType] = factory;
                }
            }
            return factory(binder);
        }

        #endregion

        #region Control Flow

        private static readonly RuntimeLabel[] EmptyRuntimeLabels = new RuntimeLabel[] { new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0) };

        private RuntimeLabel[] BuildRuntimeLabels() {
            if (_runtimeLabelCount == 0) {
                return EmptyRuntimeLabels;
            }

            var result = new RuntimeLabel[_runtimeLabelCount + 1];
            foreach (BranchLabel label in _labels) {
                if (label.HasRuntimeLabel) {
                    result[label.LabelIndex] = label.ToRuntimeLabel();
                }
            }
            // "return and rethrow" label:
            result[result.Length - 1] = new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0);
            return result;
        }

        public BranchLabel MakeLabel() {
            if (_labels == null) {
                _labels = new List<BranchLabel>();
            }

            var label = new BranchLabel();
            _labels.Add(label);
            return label;
        }

        internal void FixupBranch(int branchIndex, int offset, int targetContinuationDepth, int targetStackDepth) {
            _instructions[branchIndex] = ((OffsetInstruction)_instructions[branchIndex]).Fixup(offset, targetContinuationDepth, targetStackDepth);
        }

        private int EnsureLabelIndex(BranchLabel label) {
            if (label.HasRuntimeLabel) {
                return label.LabelIndex;
            }

            label.LabelIndex = _runtimeLabelCount;
            _runtimeLabelCount++;
            return label.LabelIndex;
        }

        public int MarkRuntimeLabel() {
            BranchLabel handlerLabel = MakeLabel();
            MarkLabel(handlerLabel);
            return EnsureLabelIndex(handlerLabel);
        }

        public void MarkLabel(BranchLabel label) {
            label.Mark(this);
        }

        public void EmitGoto(BranchLabel label, bool hasResult, bool hasValue) {
            Emit(GotoInstruction.Create(EnsureLabelIndex(label), hasResult, hasValue));
        }

        private void EmitBranch(OffsetInstruction instruction, BranchLabel label) {
            Emit(instruction);
            label.AddBranch(this, Count - 1);
        }

        public void EmitBranch(BranchLabel label) {
            EmitBranch(new BranchInstruction(), label);
        }

        public void EmitBranch(BranchLabel label, bool hasResult, bool hasValue) {
            EmitBranch(new BranchInstruction(hasResult, hasValue), label);
        }

        public void EmitCoalescingBranch(BranchLabel leftNotNull) {
            EmitBranch(new CoalescingBranchInstruction(), leftNotNull);
        }

        public void EmitBranchTrue(BranchLabel elseLabel) {
            EmitBranch(new BranchTrueInstruction(), elseLabel);
        }

        public void EmitBranchFalse(BranchLabel elseLabel) {
            EmitBranch(new BranchFalseInstruction(), elseLabel);
        }

        public void EmitThrow() {
            Emit(ThrowInstruction.Throw);
        }

        public void EmitThrowVoid() {
            Emit(ThrowInstruction.VoidThrow);
        }

        public void EmitRethrow() {
            Emit(ThrowInstruction.Rethrow);
        }

        public void EmitRethrowVoid() {
            Emit(ThrowInstruction.VoidRethrow);
        }

        public void EmitEnterTryFinally(BranchLabel finallyStartLabel) {
            Emit(EnterTryFinallyInstruction.Create(EnsureLabelIndex(finallyStartLabel)));
        }

        public void EmitEnterFinally() {
            Emit(EnterFinallyInstruction.Instance);
        }

        public void EmitLeaveFinally() {
            Emit(LeaveFinallyInstruction.Instance);
        }

        public void EmitLeaveFault(bool hasValue) {
            Emit(hasValue ? LeaveFaultInstruction.NonVoid : LeaveFaultInstruction.Void);
        }

        public void EmitEnterExceptionHandlerNonVoid() {
            Emit(EnterExceptionHandlerInstruction.NonVoid);
        }

        public void EmitEnterExceptionHandlerVoid() {
            Emit(EnterExceptionHandlerInstruction.Void);
        }

        public void EmitLeaveExceptionHandler(bool hasValue, BranchLabel tryExpressionEndLabel) {
            Emit(LeaveExceptionHandlerInstruction.Create(EnsureLabelIndex(tryExpressionEndLabel), hasValue));
        }

        public void EmitSwitch(Dictionary<int, int> cases) {
            Emit(new SwitchInstruction(cases));
        }

        #endregion
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.