1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
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.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
15 // Enables instruction counting and displaying stats at process exit.
19 using System.Collections.Generic;
20 using System.Diagnostics;
21 using System.Reflection;
22 using System.Runtime.CompilerServices;
23 using System.Security;
24 using Microsoft.Scripting.Runtime;
25 using Microsoft.Scripting.Utils;
27 namespace Microsoft.Scripting.Interpreter {
28 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")]
29 [DebuggerTypeProxy(typeof(InstructionArray.DebugView))]
30 public struct InstructionArray {
31 internal readonly int MaxStackDepth;
32 internal readonly int MaxContinuationDepth;
33 internal readonly Instruction[] Instructions;
34 internal readonly object[] Objects;
35 internal readonly RuntimeLabel[] Labels;
37 // list of (instruction index, cookie) sorted by instruction index:
38 internal readonly List<KeyValuePair<int, object>> DebugCookies;
40 internal InstructionArray(int maxStackDepth, int maxContinuationDepth, Instruction[] instructions,
41 object[] objects, RuntimeLabel[] labels, List<KeyValuePair<int, object>> debugCookies) {
43 MaxStackDepth = maxStackDepth;
44 MaxContinuationDepth = maxContinuationDepth;
45 Instructions = instructions;
46 DebugCookies = debugCookies;
52 get { return Instructions.Length; }
57 internal sealed class DebugView {
58 private readonly InstructionArray _array;
60 public DebugView(InstructionArray array) {
65 [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
66 public InstructionList.DebugView.InstructionView[]/*!*/ A0 {
68 return InstructionList.DebugView.GetInstructionViews(
71 (index) => _array.Labels[index].Index,
81 [DebuggerTypeProxy(typeof(InstructionList.DebugView))]
82 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
83 public sealed class InstructionList {
84 private readonly List<Instruction> _instructions = new List<Instruction>();
85 private List<object> _objects;
87 private int _currentStackDepth;
88 private int _maxStackDepth;
89 private int _currentContinuationsDepth;
90 private int _maxContinuationDepth;
91 private int _runtimeLabelCount;
92 private List<BranchLabel> _labels;
94 // list of (instruction index, cookie) sorted by instruction index:
95 private List<KeyValuePair<int, object>> _debugCookies = null;
99 internal sealed class DebugView {
100 private readonly InstructionList _list;
102 public DebugView(InstructionList list) {
106 [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
107 public InstructionView[]/*!*/ A0 {
109 return GetInstructionViews(
112 (index) => _list._labels[index].TargetIndex,
118 internal static InstructionView[] GetInstructionViews(IList<Instruction> instructions, IList<object> objects,
119 Func<int, int> labelIndexer, IList<KeyValuePair<int, object>> debugCookies) {
121 var result = new List<InstructionView>();
124 int continuationsDepth = 0;
126 var cookieEnumerator = (debugCookies != null ? debugCookies : new KeyValuePair<int, object>[0]).GetEnumerator();
127 var hasCookie = cookieEnumerator.MoveNext();
129 for (int i = 0; i < instructions.Count; i++) {
130 object cookie = null;
131 while (hasCookie && cookieEnumerator.Current.Key == i) {
132 cookie = cookieEnumerator.Current.Value;
133 hasCookie = cookieEnumerator.MoveNext();
136 int stackDiff = instructions[i].StackBalance;
137 int contDiff = instructions[i].ContinuationsBalance;
138 string name = instructions[i].ToDebugString(i, cookie, labelIndexer, objects);
139 result.Add(new InstructionView(instructions[i], name, i, stackDepth, continuationsDepth));
142 stackDepth += stackDiff;
143 continuationsDepth += contDiff;
145 return result.ToArray();
148 [DebuggerDisplay("{GetValue(),nq}", Name = "{GetName(),nq}", Type = "{GetDisplayType(), nq}")]
149 internal struct InstructionView {
150 private readonly int _index;
151 private readonly int _stackDepth;
152 private readonly int _continuationsDepth;
153 private readonly string _name;
154 private readonly Instruction _instruction;
156 internal string GetName() {
157 return _index.ToString() +
158 (_continuationsDepth == 0 ? "" : " C(" + _continuationsDepth.ToString() + ")") +
159 (_stackDepth == 0 ? "" : " S(" + _stackDepth.ToString() + ")");
162 internal string GetValue() {
166 internal string GetDisplayType() {
167 return _instruction.ContinuationsBalance.ToString() + "/" + _instruction.StackBalance.ToString();
170 public InstructionView(Instruction instruction, string name, int index, int stackDepth, int continuationsDepth) {
171 _instruction = instruction;
174 _stackDepth = stackDepth;
175 _continuationsDepth = continuationsDepth;
182 #region Core Emit Ops
184 public void Emit(Instruction instruction) {
185 _instructions.Add(instruction);
186 UpdateStackDepth(instruction);
189 private void UpdateStackDepth(Instruction instruction) {
190 Debug.Assert(instruction.ConsumedStack >= 0 && instruction.ProducedStack >= 0 &&
191 instruction.ConsumedContinuations >= 0 && instruction.ProducedContinuations >= 0);
193 _currentStackDepth -= instruction.ConsumedStack;
194 Debug.Assert(_currentStackDepth >= 0);
195 _currentStackDepth += instruction.ProducedStack;
196 if (_currentStackDepth > _maxStackDepth) {
197 _maxStackDepth = _currentStackDepth;
200 _currentContinuationsDepth -= instruction.ConsumedContinuations;
201 Debug.Assert(_currentContinuationsDepth >= 0);
202 _currentContinuationsDepth += instruction.ProducedContinuations;
203 if (_currentContinuationsDepth > _maxContinuationDepth) {
204 _maxContinuationDepth = _currentContinuationsDepth;
209 /// Attaches a cookie to the last emitted instruction.
211 [Conditional("DEBUG")]
212 public void SetDebugCookie(object cookie) {
214 if (_debugCookies == null) {
215 _debugCookies = new List<KeyValuePair<int, object>>();
218 Debug.Assert(Count > 0);
219 _debugCookies.Add(new KeyValuePair<int, object>(Count - 1, cookie));
224 get { return _instructions.Count; }
227 public int CurrentStackDepth {
228 get { return _currentStackDepth; }
231 public int CurrentContinuationsDepth {
232 get { return _currentContinuationsDepth; }
235 public int MaxStackDepth {
236 get { return _maxStackDepth; }
239 internal Instruction GetInstruction(int index) {
240 return _instructions[index];
244 private static Dictionary<string, int> _executedInstructions = new Dictionary<string, int>();
245 private static Dictionary<string, Dictionary<object, bool>> _instances = new Dictionary<string, Dictionary<object, bool>>();
247 static InstructionList() {
248 AppDomain.CurrentDomain.ProcessExit += new EventHandler((_, __) => {
249 PerfTrack.DumpHistogram(_executedInstructions);
250 Console.WriteLine("-- Total executed: {0}", _executedInstructions.Values.Aggregate(0, (sum, value) => sum + value));
251 Console.WriteLine("-----");
253 var referenced = new Dictionary<string, int>();
255 foreach (var entry in _instances) {
256 referenced[entry.Key] = entry.Value.Count;
257 total += entry.Value.Count;
260 PerfTrack.DumpHistogram(referenced);
261 Console.WriteLine("-- Total referenced: {0}", total);
262 Console.WriteLine("-----");
266 public InstructionArray ToArray() {
268 lock (_executedInstructions) {
269 _instructions.ForEach((instr) => {
271 var name = instr.GetType().Name;
272 _executedInstructions.TryGetValue(name, out value);
273 _executedInstructions[name] = value + 1;
275 Dictionary<object, bool> dict;
276 if (!_instances.TryGetValue(name, out dict)) {
277 _instances[name] = dict = new Dictionary<object, bool>();
283 return new InstructionArray(
285 _maxContinuationDepth,
286 _instructions.ToArray(),
287 (_objects != null) ? _objects.ToArray() : null,
288 BuildRuntimeLabels(),
295 #region Stack Operations
297 private const int PushIntMinCachedValue = -100;
298 private const int PushIntMaxCachedValue = 100;
299 private const int CachedObjectCount = 256;
301 private static Instruction _null;
302 private static Instruction _true;
303 private static Instruction _false;
304 private static Instruction[] _ints;
305 private static Instruction[] _loadObjectCached;
307 public void EmitLoad(object value) {
308 EmitLoad(value, null);
311 public void EmitLoad(bool value) {
313 Emit(_true ?? (_true = new LoadObjectInstruction(value)));
315 Emit(_false ?? (_false = new LoadObjectInstruction(value)));
319 public void EmitLoad(object value, Type type) {
321 Emit(_null ?? (_null = new LoadObjectInstruction(null)));
325 if (type == null || type.IsValueType()) {
327 EmitLoad((bool)value);
333 if (i >= PushIntMinCachedValue && i <= PushIntMaxCachedValue) {
335 _ints = new Instruction[PushIntMaxCachedValue - PushIntMinCachedValue + 1];
337 i -= PushIntMinCachedValue;
338 Emit(_ints[i] ?? (_ints[i] = new LoadObjectInstruction(value)));
344 if (_objects == null) {
345 _objects = new List<object>();
346 if (_loadObjectCached == null) {
347 _loadObjectCached = new Instruction[CachedObjectCount];
351 if (_objects.Count < _loadObjectCached.Length) {
352 uint index = (uint)_objects.Count;
354 Emit(_loadObjectCached[index] ?? (_loadObjectCached[index] = new LoadCachedObjectInstruction(index)));
356 Emit(new LoadObjectInstruction(value));
360 public void EmitDup() {
361 Emit(DupInstruction.Instance);
364 public void EmitPop() {
365 Emit(PopInstruction.Instance);
372 internal void SwitchToBoxed(int index, int instructionIndex) {
373 var instruction = _instructions[instructionIndex] as IBoxableInstruction;
375 if (instruction != null) {
376 var newInstruction = instruction.BoxIfIndexMatches(index);
377 if (newInstruction != null) {
378 _instructions[instructionIndex] = newInstruction;
383 private const int LocalInstrCacheSize = 64;
385 private static Instruction[] _loadLocal;
386 private static Instruction[] _loadLocalBoxed;
387 private static Instruction[] _loadLocalFromClosure;
388 private static Instruction[] _loadLocalFromClosureBoxed;
389 private static Instruction[] _assignLocal;
390 private static Instruction[] _storeLocal;
391 private static Instruction[] _assignLocalBoxed;
392 private static Instruction[] _storeLocalBoxed;
393 private static Instruction[] _assignLocalToClosure;
394 private static Instruction[] _initReference;
395 private static Instruction[] _initImmutableRefBox;
396 private static Instruction[] _parameterBox;
397 private static Instruction[] _parameter;
399 public void EmitLoadLocal(int index) {
400 if (_loadLocal == null) {
401 _loadLocal = new Instruction[LocalInstrCacheSize];
404 if (index < _loadLocal.Length) {
405 Emit(_loadLocal[index] ?? (_loadLocal[index] = new LoadLocalInstruction(index)));
407 Emit(new LoadLocalInstruction(index));
411 public void EmitLoadLocalBoxed(int index) {
412 Emit(LoadLocalBoxed(index));
415 internal static Instruction LoadLocalBoxed(int index) {
416 if (_loadLocalBoxed == null) {
417 _loadLocalBoxed = new Instruction[LocalInstrCacheSize];
420 if (index < _loadLocalBoxed.Length) {
421 return _loadLocalBoxed[index] ?? (_loadLocalBoxed[index] = new LoadLocalBoxedInstruction(index));
423 return new LoadLocalBoxedInstruction(index);
427 public void EmitLoadLocalFromClosure(int index) {
428 if (_loadLocalFromClosure == null) {
429 _loadLocalFromClosure = new Instruction[LocalInstrCacheSize];
432 if (index < _loadLocalFromClosure.Length) {
433 Emit(_loadLocalFromClosure[index] ?? (_loadLocalFromClosure[index] = new LoadLocalFromClosureInstruction(index)));
435 Emit(new LoadLocalFromClosureInstruction(index));
439 public void EmitLoadLocalFromClosureBoxed(int index) {
440 if (_loadLocalFromClosureBoxed == null) {
441 _loadLocalFromClosureBoxed = new Instruction[LocalInstrCacheSize];
444 if (index < _loadLocalFromClosureBoxed.Length) {
445 Emit(_loadLocalFromClosureBoxed[index] ?? (_loadLocalFromClosureBoxed[index] = new LoadLocalFromClosureBoxedInstruction(index)));
447 Emit(new LoadLocalFromClosureBoxedInstruction(index));
451 public void EmitAssignLocal(int index) {
452 if (_assignLocal == null) {
453 _assignLocal = new Instruction[LocalInstrCacheSize];
456 if (index < _assignLocal.Length) {
457 Emit(_assignLocal[index] ?? (_assignLocal[index] = new AssignLocalInstruction(index)));
459 Emit(new AssignLocalInstruction(index));
463 public void EmitStoreLocal(int index) {
464 if (_storeLocal == null) {
465 _storeLocal = new Instruction[LocalInstrCacheSize];
468 if (index < _storeLocal.Length) {
469 Emit(_storeLocal[index] ?? (_storeLocal[index] = new StoreLocalInstruction(index)));
471 Emit(new StoreLocalInstruction(index));
475 public void EmitAssignLocalBoxed(int index) {
476 Emit(AssignLocalBoxed(index));
479 internal static Instruction AssignLocalBoxed(int index) {
480 if (_assignLocalBoxed == null) {
481 _assignLocalBoxed = new Instruction[LocalInstrCacheSize];
484 if (index < _assignLocalBoxed.Length) {
485 return _assignLocalBoxed[index] ?? (_assignLocalBoxed[index] = new AssignLocalBoxedInstruction(index));
487 return new AssignLocalBoxedInstruction(index);
491 public void EmitStoreLocalBoxed(int index) {
492 Emit(StoreLocalBoxed(index));
495 internal static Instruction StoreLocalBoxed(int index) {
496 if (_storeLocalBoxed == null) {
497 _storeLocalBoxed = new Instruction[LocalInstrCacheSize];
500 if (index < _storeLocalBoxed.Length) {
501 return _storeLocalBoxed[index] ?? (_storeLocalBoxed[index] = new StoreLocalBoxedInstruction(index));
503 return new StoreLocalBoxedInstruction(index);
507 public void EmitAssignLocalToClosure(int index) {
508 if (_assignLocalToClosure == null) {
509 _assignLocalToClosure = new Instruction[LocalInstrCacheSize];
512 if (index < _assignLocalToClosure.Length) {
513 Emit(_assignLocalToClosure[index] ?? (_assignLocalToClosure[index] = new AssignLocalToClosureInstruction(index)));
515 Emit(new AssignLocalToClosureInstruction(index));
519 public void EmitStoreLocalToClosure(int index) {
520 EmitAssignLocalToClosure(index);
524 public void EmitInitializeLocal(int index, Type type) {
525 object value = ScriptingRuntimeHelpers.GetPrimitiveDefaultValue(type);
527 Emit(new InitializeLocalInstruction.ImmutableValue(index, value));
528 } else if (type.IsValueType()) {
529 Emit(new InitializeLocalInstruction.MutableValue(index, type));
531 Emit(InitReference(index));
535 internal void EmitInitializeParameter(int index) {
536 Emit(Parameter(index));
539 internal static Instruction Parameter(int index) {
540 if (_parameter == null) {
541 _parameter = new Instruction[LocalInstrCacheSize];
544 if (index < _parameter.Length) {
545 return _parameter[index] ?? (_parameter[index] = new InitializeLocalInstruction.Parameter(index));
548 return new InitializeLocalInstruction.Parameter(index);
551 internal static Instruction ParameterBox(int index) {
552 if (_parameterBox == null) {
553 _parameterBox = new Instruction[LocalInstrCacheSize];
556 if (index < _parameterBox.Length) {
557 return _parameterBox[index] ?? (_parameterBox[index] = new InitializeLocalInstruction.ParameterBox(index));
560 return new InitializeLocalInstruction.ParameterBox(index);
563 internal static Instruction InitReference(int index) {
564 if (_initReference == null) {
565 _initReference = new Instruction[LocalInstrCacheSize];
568 if (index < _initReference.Length) {
569 return _initReference[index] ?? (_initReference[index] = new InitializeLocalInstruction.Reference(index));
572 return new InitializeLocalInstruction.Reference(index);
575 internal static Instruction InitImmutableRefBox(int index) {
576 if (_initImmutableRefBox == null) {
577 _initImmutableRefBox = new Instruction[LocalInstrCacheSize];
580 if (index < _initImmutableRefBox.Length) {
581 return _initImmutableRefBox[index] ?? (_initImmutableRefBox[index] = new InitializeLocalInstruction.ImmutableBox(index, null));
584 return new InitializeLocalInstruction.ImmutableBox(index, null);
587 public void EmitNewRuntimeVariables(int count) {
588 Emit(new RuntimeVariablesInstruction(count));
593 #region Array Operations
595 public void EmitGetArrayItem(Type arrayType) {
596 Type elementType = arrayType.GetElementType();
597 if (elementType.IsClass() || elementType.IsInterface()) {
598 Emit(InstructionFactory<object>.Factory.GetArrayItem());
600 Emit(InstructionFactory.GetFactory(elementType).GetArrayItem());
604 public void EmitSetArrayItem(Type arrayType) {
605 Type elementType = arrayType.GetElementType();
606 if (elementType.IsClass() || elementType.IsInterface()) {
607 Emit(InstructionFactory<object>.Factory.SetArrayItem());
609 Emit(InstructionFactory.GetFactory(elementType).SetArrayItem());
613 public void EmitNewArray(Type elementType) {
614 Emit(InstructionFactory.GetFactory(elementType).NewArray());
617 public void EmitNewArrayBounds(Type elementType, int rank) {
618 Emit(new NewArrayBoundsInstruction(elementType, rank));
621 public void EmitNewArrayInit(Type elementType, int elementCount) {
622 Emit(InstructionFactory.GetFactory(elementType).NewArrayInit(elementCount));
627 #region Arithmetic Operations
629 public void EmitAdd(Type type, bool @checked) {
631 Emit(AddOvfInstruction.Create(type));
633 Emit(AddInstruction.Create(type));
637 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
638 public void EmitSub(Type type, bool @checked) {
639 throw new NotSupportedException();
642 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
643 public void EmitMul(Type type, bool @checked) {
644 throw new NotSupportedException();
647 public void EmitDiv(Type type) {
648 Emit(DivInstruction.Create(type));
655 public void EmitEqual(Type type) {
656 Emit(EqualInstruction.Create(type));
659 public void EmitNotEqual(Type type) {
660 Emit(NotEqualInstruction.Create(type));
663 public void EmitLessThan(Type type) {
664 Emit(LessThanInstruction.Create(type));
667 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
668 public void EmitLessThanOrEqual(Type type) {
669 throw new NotSupportedException();
672 public void EmitGreaterThan(Type type) {
673 Emit(GreaterThanInstruction.Create(type));
676 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
677 public void EmitGreaterThanOrEqual(Type type) {
678 throw new NotSupportedException();
685 public void EmitNumericConvertChecked(TypeCode from, TypeCode to) {
686 Emit(new NumericConvertInstruction.Checked(from, to));
689 public void EmitNumericConvertUnchecked(TypeCode from, TypeCode to) {
690 Emit(new NumericConvertInstruction.Unchecked(from, to));
695 #region Boolean Operators
697 public void EmitNot() {
698 Emit(NotInstruction.Instance);
705 public void EmitDefaultValue(Type type) {
706 Emit(InstructionFactory.GetFactory(type).DefaultValue());
709 public void EmitNew(ConstructorInfo constructorInfo) {
710 Emit(new NewInstruction(constructorInfo));
713 internal void EmitCreateDelegate(LightDelegateCreator creator) {
714 Emit(new CreateDelegateInstruction(creator));
717 public void EmitTypeEquals() {
718 Emit(TypeEqualsInstruction.Instance);
721 public void EmitTypeIs(Type type) {
722 Emit(InstructionFactory.GetFactory(type).TypeIs());
725 public void EmitTypeAs(Type type) {
726 Emit(InstructionFactory.GetFactory(type).TypeAs());
731 #region Fields and Methods
733 private static readonly Dictionary<FieldInfo, Instruction> _loadFields = new Dictionary<FieldInfo, Instruction>();
735 public void EmitLoadField(FieldInfo field) {
736 Emit(GetLoadField(field));
739 private Instruction GetLoadField(FieldInfo field) {
741 Instruction instruction;
742 if (!_loadFields.TryGetValue(field, out instruction)) {
743 if (field.IsStatic) {
744 instruction = new LoadStaticFieldInstruction(field);
746 instruction = new LoadFieldInstruction(field);
748 _loadFields.Add(field, instruction);
754 public void EmitStoreField(FieldInfo field) {
755 if (field.IsStatic) {
756 Emit(new StoreStaticFieldInstruction(field));
758 Emit(new StoreFieldInstruction(field));
766 public void EmitDynamic(Type type, CallSiteBinder binder) {
767 Emit(CreateDynamicInstruction(type, binder));
770 #region Generated Dynamic InstructionList Factory
772 // *** BEGIN GENERATED CODE ***
773 // generated by function: gen_instructionlist_factory from: generate_dynamic_instructions.py
775 public void EmitDynamic<T0, TRet>(CallSiteBinder binder) {
776 Emit(DynamicInstruction<T0, TRet>.Factory(binder));
779 public void EmitDynamic<T0, T1, TRet>(CallSiteBinder binder) {
780 Emit(DynamicInstruction<T0, T1, TRet>.Factory(binder));
783 public void EmitDynamic<T0, T1, T2, TRet>(CallSiteBinder binder) {
784 Emit(DynamicInstruction<T0, T1, T2, TRet>.Factory(binder));
787 public void EmitDynamic<T0, T1, T2, T3, TRet>(CallSiteBinder binder) {
788 Emit(DynamicInstruction<T0, T1, T2, T3, TRet>.Factory(binder));
791 public void EmitDynamic<T0, T1, T2, T3, T4, TRet>(CallSiteBinder binder) {
792 Emit(DynamicInstruction<T0, T1, T2, T3, T4, TRet>.Factory(binder));
795 public void EmitDynamic<T0, T1, T2, T3, T4, T5, TRet>(CallSiteBinder binder) {
796 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, TRet>.Factory(binder));
799 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, TRet>(CallSiteBinder binder) {
800 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, TRet>.Factory(binder));
803 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, TRet>(CallSiteBinder binder) {
804 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, TRet>.Factory(binder));
807 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>(CallSiteBinder binder) {
808 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>.Factory(binder));
811 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>(CallSiteBinder binder) {
812 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>.Factory(binder));
815 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>(CallSiteBinder binder) {
816 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>.Factory(binder));
819 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>(CallSiteBinder binder) {
820 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>.Factory(binder));
823 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>(CallSiteBinder binder) {
824 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>.Factory(binder));
827 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>(CallSiteBinder binder) {
828 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>.Factory(binder));
831 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>(CallSiteBinder binder) {
832 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>.Factory(binder));
836 // *** END GENERATED CODE ***
840 private static Dictionary<Type, Func<CallSiteBinder, Instruction>> _factories =
841 new Dictionary<Type, Func<CallSiteBinder, Instruction>>();
843 /// <exception cref="SecurityException">Instruction can't be created due to insufficient privileges.</exception>
844 internal static Instruction CreateDynamicInstruction(Type delegateType, CallSiteBinder binder) {
845 Func<CallSiteBinder, Instruction> factory;
847 if (!_factories.TryGetValue(delegateType, out factory)) {
848 if (delegateType.GetMethod("Invoke").ReturnType == typeof(void)) {
849 // TODO: We should generally support void returning binders but the only
850 // ones that exist are delete index/member who's perf isn't that critical.
851 return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder), true);
854 Type instructionType = DynamicInstructionN.GetDynamicInstructionType(delegateType);
855 if (instructionType == null) {
856 return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder));
859 factory = (Func<CallSiteBinder, Instruction>)instructionType.GetMethod("Factory").CreateDelegate(typeof(Func<CallSiteBinder, Instruction>));
860 _factories[delegateType] = factory;
863 return factory(binder);
870 private static readonly RuntimeLabel[] EmptyRuntimeLabels = new RuntimeLabel[] { new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0) };
872 private RuntimeLabel[] BuildRuntimeLabels() {
873 if (_runtimeLabelCount == 0) {
874 return EmptyRuntimeLabels;
877 var result = new RuntimeLabel[_runtimeLabelCount + 1];
878 foreach (BranchLabel label in _labels) {
879 if (label.HasRuntimeLabel) {
880 result[label.LabelIndex] = label.ToRuntimeLabel();
883 // "return and rethrow" label:
884 result[result.Length - 1] = new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0);
888 public BranchLabel MakeLabel() {
889 if (_labels == null) {
890 _labels = new List<BranchLabel>();
893 var label = new BranchLabel();
898 internal void FixupBranch(int branchIndex, int offset) {
899 _instructions[branchIndex] = ((OffsetInstruction)_instructions[branchIndex]).Fixup(offset);
902 private int EnsureLabelIndex(BranchLabel label) {
903 if (label.HasRuntimeLabel) {
904 return label.LabelIndex;
907 label.LabelIndex = _runtimeLabelCount;
908 _runtimeLabelCount++;
909 return label.LabelIndex;
912 public int MarkRuntimeLabel() {
913 BranchLabel handlerLabel = MakeLabel();
914 MarkLabel(handlerLabel);
915 return EnsureLabelIndex(handlerLabel);
918 public void MarkLabel(BranchLabel label) {
922 public void EmitGoto(BranchLabel label, bool hasResult, bool hasValue) {
923 Emit(GotoInstruction.Create(EnsureLabelIndex(label), hasResult, hasValue));
926 private void EmitBranch(OffsetInstruction instruction, BranchLabel label) {
928 label.AddBranch(this, Count - 1);
931 public void EmitBranch(BranchLabel label) {
932 EmitBranch(new BranchInstruction(), label);
935 public void EmitBranch(BranchLabel label, bool hasResult, bool hasValue) {
936 EmitBranch(new BranchInstruction(hasResult, hasValue), label);
939 public void EmitCoalescingBranch(BranchLabel leftNotNull) {
940 EmitBranch(new CoalescingBranchInstruction(), leftNotNull);
943 public void EmitBranchTrue(BranchLabel elseLabel) {
944 EmitBranch(new BranchTrueInstruction(), elseLabel);
947 public void EmitBranchFalse(BranchLabel elseLabel) {
948 EmitBranch(new BranchFalseInstruction(), elseLabel);
951 public void EmitThrow() {
952 Emit(ThrowInstruction.Throw);
955 public void EmitThrowVoid() {
956 Emit(ThrowInstruction.VoidThrow);
959 public void EmitRethrow() {
960 Emit(ThrowInstruction.Rethrow);
963 public void EmitRethrowVoid() {
964 Emit(ThrowInstruction.VoidRethrow);
967 public void EmitEnterTryFinally(BranchLabel finallyStartLabel) {
968 Emit(EnterTryFinallyInstruction.Create(EnsureLabelIndex(finallyStartLabel)));
971 public void EmitEnterFinally() {
972 Emit(EnterFinallyInstruction.Instance);
975 public void EmitLeaveFinally() {
976 Emit(LeaveFinallyInstruction.Instance);
979 public void EmitLeaveFault(bool hasValue) {
980 Emit(hasValue ? LeaveFaultInstruction.NonVoid : LeaveFaultInstruction.Void);
983 public void EmitEnterExceptionHandlerNonVoid() {
984 Emit(EnterExceptionHandlerInstruction.NonVoid);
987 public void EmitEnterExceptionHandlerVoid() {
988 Emit(EnterExceptionHandlerInstruction.Void);
991 public void EmitLeaveExceptionHandler(bool hasValue, BranchLabel tryExpressionEndLabel) {
992 Emit(LeaveExceptionHandlerInstruction.Create(EnsureLabelIndex(tryExpressionEndLabel), hasValue));
995 public void EmitSwitch(Dictionary<int, int> cases) {
996 Emit(new SwitchInstruction(cases));