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 EmitGetArrayLength(Type arrayType) {
605 Emit(GetArrayLengthInstruction.Create());
608 public void EmitSetArrayItem(Type arrayType) {
609 Type elementType = arrayType.GetElementType();
610 if (elementType.IsClass() || elementType.IsInterface()) {
611 Emit(InstructionFactory<object>.Factory.SetArrayItem());
613 Emit(InstructionFactory.GetFactory(elementType).SetArrayItem());
617 public void EmitNewArray(Type elementType) {
618 Emit(InstructionFactory.GetFactory(elementType).NewArray());
621 public void EmitNewArrayBounds(Type elementType, int rank) {
622 Emit(new NewArrayBoundsInstruction(elementType, rank));
625 public void EmitNewArrayInit(Type elementType, int elementCount) {
626 Emit(InstructionFactory.GetFactory(elementType).NewArrayInit(elementCount));
631 #region Arithmetic Operations
633 public void EmitAdd(Type type, bool @checked) {
635 Emit(AddOvfInstruction.Create(type));
637 Emit(AddInstruction.Create(type));
641 public void EmitSub(Type type, bool @checked) {
643 Emit(SubOvfInstruction.Create(type));
645 Emit(SubInstruction.Create(type));
649 public void EmitMul(Type type, bool @checked) {
651 Emit(MulOvfInstruction.Create(type));
653 Emit(MulInstruction.Create(type));
657 public void EmitDiv(Type type) {
658 Emit(DivInstruction.Create(type));
661 public void EmitMod(Type type) {
662 Emit(ModInstruction.Create(type));
667 public void EmitShl(Type type, bool lifted) {
668 Emit(lifted ? ShlInstruction.CreateLifted(type) : ShlInstruction.Create(type));
671 public void EmitShr(Type type, bool lifted) {
672 Emit(lifted ? ShrInstruction.CreateLifted(type) : ShrInstruction.Create(type));
675 public void EmitOr(Type type, bool lifted) {
676 Emit(lifted ? OrInstruction.CreateLifted(type) : OrInstruction.Create(type));
679 public void EmitAnd(Type type, bool lifted) {
680 Emit(lifted ? AndInstruction.CreateLifted (type) : AndInstruction.Create(type));
683 public void EmitExclusiveOr(Type type, bool lifted) {
684 Emit(lifted ? XorInstruction.CreateLifted(type) : XorInstruction.Create(type));
689 public void EmitEqual(Type type, bool liftedResult) {
691 EqualInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
692 EqualInstruction.Create(TypeUtils.GetNonNullableType (type)));
695 public void EmitNotEqual(Type type, bool liftedResult) {
697 NotEqualInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
698 NotEqualInstruction.Create(TypeUtils.GetNonNullableType (type)));
701 public void EmitLessThan(Type type, bool liftedResult) {
703 LessThanInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
704 LessThanInstruction.Create(TypeUtils.GetNonNullableType (type)));
707 public void EmitLessThanOrEqual(Type type, bool liftedResult) {
709 LessThanOrEqualInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
710 LessThanOrEqualInstruction.Create(TypeUtils.GetNonNullableType (type)));
713 public void EmitGreaterThan(Type type, bool liftedResult) {
715 GreaterThanInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
716 GreaterThanInstruction.Create(TypeUtils.GetNonNullableType (type)));
719 public void EmitGreaterThanOrEqual(Type type, bool liftedResult) {
721 GreaterThanOrEqualInstruction.CreateLifted(TypeUtils.GetNonNullableType (type)) :
722 GreaterThanOrEqualInstruction.Create(TypeUtils.GetNonNullableType (type)));
729 public void EmitNumericConvertChecked(TypeCode from, TypeCode to) {
730 Emit(new NumericConvertInstruction.Checked(from, to));
733 public void EmitNumericConvertUnchecked(TypeCode from, TypeCode to) {
734 Emit(new NumericConvertInstruction.Unchecked(from, to));
739 #region Unary Operators
741 public void EmitNegate(Type type, bool @checked, bool lifted) {
743 Emit(lifted ? NegateOvfInstruction.CreateLifted(type) : NegateOvfInstruction.Create(type));
745 Emit(lifted ? NegateInstruction.CreateLifted(type) : NegateInstruction.Create(type));
748 public void EmitNot(Type type, bool lifted) {
749 Emit(lifted ? NotInstruction.CreateLifted (type) : NotInstruction.Create(type));
754 #region Nullable operations
756 public void EmitWrap (Type elementType)
758 Emit(InstructionFactory.GetFactory(elementType).WrapToNullable (elementType));
765 public void EmitDefaultValue(Type type) {
766 Emit(InstructionFactory.GetFactory(type).DefaultValue());
769 public void EmitNew(ConstructorInfo constructorInfo) {
770 Emit(new NewInstruction(constructorInfo));
773 internal void EmitCreateDelegate(LightDelegateCreator creator) {
774 Emit(new CreateDelegateInstruction(creator));
777 public void EmitTypeEquals() {
778 Emit(TypeEqualsInstruction.Instance);
781 public void EmitTypeIs(Type type) {
782 Emit(InstructionFactory.GetFactory(type).TypeIs());
785 public void EmitTypeAs(Type type) {
786 Emit(InstructionFactory.GetFactory(type).TypeAs());
791 #region Fields and Methods
793 private static readonly Dictionary<FieldInfo, Instruction> _loadFields = new Dictionary<FieldInfo, Instruction>();
795 public void EmitLoadField(FieldInfo field) {
796 Emit(GetLoadField(field));
799 private Instruction GetLoadField(FieldInfo field) {
801 Instruction instruction;
802 if (!_loadFields.TryGetValue(field, out instruction)) {
803 if (field.IsStatic) {
804 instruction = new LoadStaticFieldInstruction(field);
806 instruction = new LoadFieldInstruction(field);
808 _loadFields.Add(field, instruction);
814 public void EmitStoreField(FieldInfo field) {
815 if (field.IsStatic) {
816 Emit(new StoreStaticFieldInstruction(field));
818 Emit(new StoreFieldInstruction(field));
826 public void EmitDynamic(Type type, CallSiteBinder binder) {
827 Emit(CreateDynamicInstruction(type, binder));
830 #region Generated Dynamic InstructionList Factory
832 // *** BEGIN GENERATED CODE ***
833 // generated by function: gen_instructionlist_factory from: generate_dynamic_instructions.py
835 public void EmitDynamic<T0, TRet>(CallSiteBinder binder) {
836 Emit(DynamicInstruction<T0, TRet>.Factory(binder));
839 public void EmitDynamic<T0, T1, TRet>(CallSiteBinder binder) {
840 Emit(DynamicInstruction<T0, T1, TRet>.Factory(binder));
843 public void EmitDynamic<T0, T1, T2, TRet>(CallSiteBinder binder) {
844 Emit(DynamicInstruction<T0, T1, T2, TRet>.Factory(binder));
847 public void EmitDynamic<T0, T1, T2, T3, TRet>(CallSiteBinder binder) {
848 Emit(DynamicInstruction<T0, T1, T2, T3, TRet>.Factory(binder));
851 public void EmitDynamic<T0, T1, T2, T3, T4, TRet>(CallSiteBinder binder) {
852 Emit(DynamicInstruction<T0, T1, T2, T3, T4, TRet>.Factory(binder));
855 public void EmitDynamic<T0, T1, T2, T3, T4, T5, TRet>(CallSiteBinder binder) {
856 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, TRet>.Factory(binder));
859 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, TRet>(CallSiteBinder binder) {
860 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, TRet>.Factory(binder));
863 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, TRet>(CallSiteBinder binder) {
864 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, TRet>.Factory(binder));
867 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>(CallSiteBinder binder) {
868 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>.Factory(binder));
871 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>(CallSiteBinder binder) {
872 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>.Factory(binder));
875 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>(CallSiteBinder binder) {
876 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>.Factory(binder));
879 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>(CallSiteBinder binder) {
880 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>.Factory(binder));
883 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>(CallSiteBinder binder) {
884 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>.Factory(binder));
887 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>(CallSiteBinder binder) {
888 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>.Factory(binder));
891 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>(CallSiteBinder binder) {
892 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>.Factory(binder));
896 // *** END GENERATED CODE ***
900 private static Dictionary<Type, Func<CallSiteBinder, Instruction>> _factories =
901 new Dictionary<Type, Func<CallSiteBinder, Instruction>>();
903 /// <exception cref="SecurityException">Instruction can't be created due to insufficient privileges.</exception>
904 internal static Instruction CreateDynamicInstruction(Type delegateType, CallSiteBinder binder) {
905 Func<CallSiteBinder, Instruction> factory;
907 if (!_factories.TryGetValue(delegateType, out factory)) {
908 if (delegateType.GetMethod("Invoke").ReturnType == typeof(void)) {
909 // TODO: We should generally support void returning binders but the only
910 // ones that exist are delete index/member who's perf isn't that critical.
911 return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder), true);
914 Type instructionType = DynamicInstructionN.GetDynamicInstructionType(delegateType);
915 if (instructionType == null) {
916 return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder));
919 factory = (Func<CallSiteBinder, Instruction>)instructionType.GetMethod("Factory").CreateDelegate(typeof(Func<CallSiteBinder, Instruction>));
920 _factories[delegateType] = factory;
923 return factory(binder);
930 private static readonly RuntimeLabel[] EmptyRuntimeLabels = new RuntimeLabel[] { new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0) };
932 private RuntimeLabel[] BuildRuntimeLabels() {
933 if (_runtimeLabelCount == 0) {
934 return EmptyRuntimeLabels;
937 var result = new RuntimeLabel[_runtimeLabelCount + 1];
938 foreach (BranchLabel label in _labels) {
939 if (label.HasRuntimeLabel) {
940 result[label.LabelIndex] = label.ToRuntimeLabel();
943 // "return and rethrow" label:
944 result[result.Length - 1] = new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0);
948 public BranchLabel MakeLabel() {
949 if (_labels == null) {
950 _labels = new List<BranchLabel>();
953 var label = new BranchLabel();
958 internal void FixupBranch(int branchIndex, int offset) {
959 _instructions[branchIndex] = ((OffsetInstruction)_instructions[branchIndex]).Fixup(offset);
962 private int EnsureLabelIndex(BranchLabel label) {
963 if (label.HasRuntimeLabel) {
964 return label.LabelIndex;
967 label.LabelIndex = _runtimeLabelCount;
968 _runtimeLabelCount++;
969 return label.LabelIndex;
972 public int MarkRuntimeLabel() {
973 BranchLabel handlerLabel = MakeLabel();
974 MarkLabel(handlerLabel);
975 return EnsureLabelIndex(handlerLabel);
978 public void MarkLabel(BranchLabel label) {
982 public void EmitGoto(BranchLabel label, bool hasResult, bool hasValue) {
983 Emit(GotoInstruction.Create(EnsureLabelIndex(label), hasResult, hasValue));
986 private void EmitBranch(OffsetInstruction instruction, BranchLabel label) {
988 label.AddBranch(this, Count - 1);
991 public void EmitBranch(BranchLabel label) {
992 EmitBranch(new BranchInstruction(), label);
995 public void EmitBranch(BranchLabel label, bool hasResult, bool hasValue) {
996 EmitBranch(new BranchInstruction(hasResult, hasValue), label);
999 public void EmitCoalescingBranch(BranchLabel leftNotNull) {
1000 EmitBranch(new CoalescingBranchInstruction(), leftNotNull);
1003 public void EmitBranchTrue(BranchLabel elseLabel) {
1004 EmitBranch(new BranchTrueInstruction(), elseLabel);
1007 public void EmitBranchFalse(BranchLabel elseLabel) {
1008 EmitBranch(new BranchFalseInstruction(), elseLabel);
1011 public void EmitBranchNull(BranchLabel elseLabel) {
1012 EmitBranch(new BranchNullInstruction(), elseLabel);
1015 public void EmitThrow() {
1016 Emit(ThrowInstruction.Throw);
1019 public void EmitThrowVoid() {
1020 Emit(ThrowInstruction.VoidThrow);
1023 public void EmitRethrow() {
1024 Emit(ThrowInstruction.Rethrow);
1027 public void EmitRethrowVoid() {
1028 Emit(ThrowInstruction.VoidRethrow);
1031 public void EmitEnterTryFinally(BranchLabel finallyStartLabel) {
1032 Emit(EnterTryFinallyInstruction.Create(EnsureLabelIndex(finallyStartLabel)));
1035 public void EmitEnterFinally() {
1036 Emit(EnterFinallyInstruction.Instance);
1039 public void EmitLeaveFinally() {
1040 Emit(LeaveFinallyInstruction.Instance);
1043 public void EmitLeaveFault(bool hasValue) {
1044 Emit(hasValue ? LeaveFaultInstruction.NonVoid : LeaveFaultInstruction.Void);
1047 public void EmitEnterExceptionHandlerNonVoid() {
1048 Emit(EnterExceptionHandlerInstruction.NonVoid);
1051 public void EmitEnterExceptionHandlerVoid() {
1052 Emit(EnterExceptionHandlerInstruction.Void);
1055 public void EmitLeaveExceptionHandler(bool hasValue, BranchLabel tryExpressionEndLabel) {
1056 Emit(LeaveExceptionHandlerInstruction.Create(EnsureLabelIndex(tryExpressionEndLabel), hasValue));
1059 public void EmitSwitch(Dictionary<int, int> cases) {
1060 Emit(new SwitchInstruction(cases));