MegaBites-AI/Windows-powershell
0372
1/* ****************************************************************************2 *3 * Copyright (c) Microsoft Corporation.4 *5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A6 * copy of the license can be found in the License.html file at the root of this distribution. If7 * you cannot locate the Apache License, Version 2.0, please send an email to8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound9 * by the terms of the Apache License, Version 2.0.10 *11 * You must not remove this notice, or any other, from this software.12 *13 *14 * ***************************************************************************/15// Enables instruction counting and displaying stats at process exit.16// #define STATS17 18using System.Collections.Generic;19using System.Diagnostics;20using System.Reflection;21using System.Runtime.CompilerServices;22 23namespace System.Management.Automation.Interpreter24{25 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")]26 [DebuggerTypeProxy(typeof(InstructionArray.DebugView))]27 internal readonly struct InstructionArray28 {29 internal readonly int MaxStackDepth;30 internal readonly int MaxContinuationDepth;31 internal readonly Instruction[] Instructions;32 internal readonly object[] Objects;33 internal readonly RuntimeLabel[] Labels;34 35 // list of (instruction index, cookie) sorted by instruction index:36 internal readonly List<KeyValuePair<int, object>> DebugCookies;37 38 internal InstructionArray(int maxStackDepth, int maxContinuationDepth, Instruction[] instructions,39 object[] objects, RuntimeLabel[] labels, List<KeyValuePair<int, object>> debugCookies)40 {41 MaxStackDepth = maxStackDepth;42 MaxContinuationDepth = maxContinuationDepth;43 Instructions = instructions;44 DebugCookies = debugCookies;45 Objects = objects;46 Labels = labels;47 }48 49 internal int Length50 {51 get { return Instructions.Length; }52 }53 54 #region Debug View55 56 internal sealed class DebugView57 {58 private readonly InstructionArray _array;59 60 public DebugView(InstructionArray array)61 {62 _array = array;63 }64 65 [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]66 public InstructionList.DebugView.InstructionView[] A067 {68 get69 {70 return InstructionList.DebugView.GetInstructionViews(71 _array.Instructions,72 _array.Objects,73 (index) => _array.Labels[index].Index,74 _array.DebugCookies75 );76 }77 }78 }79 80 #endregion81 }82 83 [DebuggerTypeProxy(typeof(InstructionList.DebugView))]84 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]85 internal sealed class InstructionList86 {87 private readonly List<Instruction> _instructions = new List<Instruction>();88 private List<object> _objects;89 90 private int _currentStackDepth;91 private int _maxStackDepth;92 private int _currentContinuationsDepth;93 private int _maxContinuationDepth;94 private int _runtimeLabelCount;95 private List<BranchLabel> _labels;96 97 // list of (instruction index, cookie) sorted by instruction index:98#pragma warning disable IDE0044 // Add readonly modifier99 private List<KeyValuePair<int, object>> _debugCookies = null;100#pragma warning restore IDE0044 // Variable is assigned when DEBUG is defined.101 102 #region Debug View103 104 internal sealed class DebugView105 {106 private readonly InstructionList _list;107 108 public DebugView(InstructionList list)109 {110 _list = list;111 }112 113 [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]114 public InstructionView[] A0115 {116 get117 {118 return GetInstructionViews(119 _list._instructions,120 _list._objects,121 (index) => _list._labels[index].TargetIndex,122 _list._debugCookies123 );124 }125 }126 127 internal static InstructionView[] GetInstructionViews(IList<Instruction> instructions, IList<object> objects,128 Func<int, int> labelIndexer, IList<KeyValuePair<int, object>> debugCookies)129 {130 var result = new List<InstructionView>();131 int index = 0;132 int stackDepth = 0;133 int continuationsDepth = 0;134 135 var cookieEnumerator = (debugCookies ?? Array.Empty<KeyValuePair<int, object>>()).GetEnumerator();136 var hasCookie = cookieEnumerator.MoveNext();137 138 for (int i = 0; i < instructions.Count; i++)139 {140 object cookie = null;141 while (hasCookie && cookieEnumerator.Current.Key == i)142 {143 cookie = cookieEnumerator.Current.Value;144 hasCookie = cookieEnumerator.MoveNext();145 }146 147 int stackDiff = instructions[i].StackBalance;148 int contDiff = instructions[i].ContinuationsBalance;149 string name = instructions[i].ToDebugString(i, cookie, labelIndexer, objects);150 result.Add(new InstructionView(instructions[i], name, i, stackDepth, continuationsDepth));151 152 index++;153 stackDepth += stackDiff;154 continuationsDepth += contDiff;155 }156 157 return result.ToArray();158 }159 160 [DebuggerDisplay("{GetValue(),nq}", Name = "{GetName(),nq}", Type = "{GetDisplayType(), nq}")]161 internal readonly struct InstructionView162 {163 private readonly int _index;164 private readonly int _stackDepth;165 private readonly int _continuationsDepth;166 private readonly string _name;167 private readonly Instruction _instruction;168 169 internal string GetName()170 {171 return _index +172 (_continuationsDepth == 0 ? string.Empty : " C(" + _continuationsDepth + ")") +173 (_stackDepth == 0 ? string.Empty : " S(" + _stackDepth + ")");174 }175 176 internal string GetValue()177 {178 return _name;179 }180 181 internal string GetDisplayType()182 {183 return _instruction.ContinuationsBalance + "/" + _instruction.StackBalance;184 }185 186 public InstructionView(Instruction instruction, string name, int index, int stackDepth, int continuationsDepth)187 {188 _instruction = instruction;189 _name = name;190 _index = index;191 _stackDepth = stackDepth;192 _continuationsDepth = continuationsDepth;193 }194 }195 }196 197 #endregion198 199 #region Core Emit Ops200 201 public void Emit(Instruction instruction)202 {203 _instructions.Add(instruction);204 UpdateStackDepth(instruction);205 }206 207 private void UpdateStackDepth(Instruction instruction)208 {209 Debug.Assert(instruction.ConsumedStack >= 0 && instruction.ProducedStack >= 0 &&210 instruction.ConsumedContinuations >= 0 && instruction.ProducedContinuations >= 0);211 212 _currentStackDepth -= instruction.ConsumedStack;213 Debug.Assert(_currentStackDepth >= 0);214 _currentStackDepth += instruction.ProducedStack;215 if (_currentStackDepth > _maxStackDepth)216 {217 _maxStackDepth = _currentStackDepth;218 }219 220 _currentContinuationsDepth -= instruction.ConsumedContinuations;221 Debug.Assert(_currentContinuationsDepth >= 0);222 _currentContinuationsDepth += instruction.ProducedContinuations;223 if (_currentContinuationsDepth > _maxContinuationDepth)224 {225 _maxContinuationDepth = _currentContinuationsDepth;226 }227 }228 229 /// <summary>230 /// Attaches a cookie to the last emitted instruction.231 /// </summary>232 [Conditional("DEBUG")]233 public void SetDebugCookie(object cookie)234 {235#if DEBUG236 _debugCookies ??= new List<KeyValuePair<int, object>>();237 238 Debug.Assert(Count > 0);239 _debugCookies.Add(new KeyValuePair<int, object>(Count - 1, cookie));240#endif241 }242 243 public int Count244 {245 get { return _instructions.Count; }246 }247 248 public int CurrentStackDepth249 {250 get { return _currentStackDepth; }251 }252 253 public int CurrentContinuationsDepth254 {255 get { return _currentContinuationsDepth; }256 }257 258 public int MaxStackDepth259 {260 get { return _maxStackDepth; }261 }262 263 internal Instruction GetInstruction(int index)264 {265 return _instructions[index];266 }267 268#if STATS269 private static Dictionary<string, int> _executedInstructions = new Dictionary<string, int>();270 private static Dictionary<string, Dictionary<object, bool>> _instances = new Dictionary<string, Dictionary<object, bool>>();271 272 static InstructionList() {273 AppDomain.CurrentDomain.ProcessExit += new EventHandler((_, __) => {274 PerfTrack.DumpHistogram(_executedInstructions);275 Console.WriteLine("-- Total executed: {0}", _executedInstructions.Values.Aggregate(0, static (sum, value) => sum + value));276 Console.WriteLine("-----");277 278 var referenced = new Dictionary<string, int>();279 int total = 0;280 foreach (var entry in _instances) {281 referenced[entry.Key] = entry.Value.Count;282 total += entry.Value.Count;283 }284 285 PerfTrack.DumpHistogram(referenced);286 Console.WriteLine("-- Total referenced: {0}", total);287 Console.WriteLine("-----");288 });289 }290#endif291 public InstructionArray ToArray()292 {293#if STATS294 lock (_executedInstructions) {295 _instructions.ForEach((instr) => {296 int value = 0;297 var name = instr.GetType().Name;298 _executedInstructions.TryGetValue(name, out value);299 _executedInstructions[name] = value + 1;300 301 Dictionary<object, bool> dict;302 if (!_instances.TryGetValue(name, out dict)) {303 _instances[name] = dict = new Dictionary<object, bool>();304 }305 306 dict[instr] = true;307 });308 }309#endif310 return new InstructionArray(311 _maxStackDepth,312 _maxContinuationDepth,313 _instructions.ToArray(),314 _objects?.ToArray(),315 BuildRuntimeLabels(),316 _debugCookies317 );318 }319 320 #endregion321 322 #region Stack Operations323 324 private const int PushIntMinCachedValue = -100;325 private const int PushIntMaxCachedValue = 100;326 private const int CachedObjectCount = 256;327 328 private static Instruction s_null;329 private static Instruction s_true;330 private static Instruction s_false;331 private static Instruction[] s_ints;332 private static Instruction[] s_loadObjectCached;333 334 public void EmitLoad(object value)335 {336 EmitLoad(value, null);337 }338 339 public void EmitLoad(bool value)340 {341 if ((bool)value)342 {343 Emit(s_true ??= new LoadObjectInstruction(value));344 }345 else346 {347 Emit(s_false ??= new LoadObjectInstruction(value));348 }349 }350 351 public void EmitLoad(object value, Type type)352 {353 if (value == null)354 {355 Emit(s_null ??= new LoadObjectInstruction(null));356 return;357 }358 359 if (type == null || type.IsValueType)360 {361 if (value is bool)362 {363 EmitLoad((bool)value);364 return;365 }366 367 if (value is int)368 {369 int i = (int)value;370 if (i >= PushIntMinCachedValue && i <= PushIntMaxCachedValue)371 {372 s_ints ??= new Instruction[PushIntMaxCachedValue - PushIntMinCachedValue + 1];373 374 i -= PushIntMinCachedValue;375 Emit(s_ints[i] ?? (s_ints[i] = new LoadObjectInstruction(value)));376 return;377 }378 }379 }380 381 if (_objects == null)382 {383 _objects = new List<object>();384 s_loadObjectCached ??= new Instruction[CachedObjectCount];385 }386 387 if (_objects.Count < s_loadObjectCached.Length)388 {389 uint index = (uint)_objects.Count;390 _objects.Add(value);391 Emit(s_loadObjectCached[index] ?? (s_loadObjectCached[index] = new LoadCachedObjectInstruction(index)));392 }393 else394 {395 Emit(new LoadObjectInstruction(value));396 }397 }398 399 public void EmitDup()400 {401 Emit(DupInstruction.Instance);402 }403 404 public void EmitPop()405 {406 Emit(PopInstruction.Instance);407 }408 409 #endregion410 411 #region Locals412 413 internal void SwitchToBoxed(int index, int instructionIndex)414 {415 var instruction = _instructions[instructionIndex] as IBoxableInstruction;416 417 if (instruction != null)418 {419 var newInstruction = instruction.BoxIfIndexMatches(index);420 if (newInstruction != null)421 {422 _instructions[instructionIndex] = newInstruction;423 }424 }425 }426 427 private const int LocalInstrCacheSize = 64;428 429 private static Instruction[] s_loadLocal;430 private static Instruction[] s_loadLocalBoxed;431 private static Instruction[] s_loadLocalFromClosure;432 private static Instruction[] s_loadLocalFromClosureBoxed;433 private static Instruction[] s_assignLocal;434 private static Instruction[] s_storeLocal;435 private static Instruction[] s_assignLocalBoxed;436 private static Instruction[] s_storeLocalBoxed;437 private static Instruction[] s_assignLocalToClosure;438 private static Instruction[] s_initReference;439 private static Instruction[] s_initImmutableRefBox;440 private static Instruction[] s_parameterBox;441 private static Instruction[] s_parameter;442 443 public void EmitLoadLocal(int index)444 {445 s_loadLocal ??= new Instruction[LocalInstrCacheSize];446 447 if (index < s_loadLocal.Length)448 {449 Emit(s_loadLocal[index] ?? (s_loadLocal[index] = new LoadLocalInstruction(index)));450 }451 else452 {453 Emit(new LoadLocalInstruction(index));454 }455 }456 457 public void EmitLoadLocalBoxed(int index)458 {459 Emit(LoadLocalBoxed(index));460 }461 462 internal static Instruction LoadLocalBoxed(int index)463 {464 s_loadLocalBoxed ??= new Instruction[LocalInstrCacheSize];465 466 if (index < s_loadLocalBoxed.Length)467 {468 return s_loadLocalBoxed[index] ?? (s_loadLocalBoxed[index] = new LoadLocalBoxedInstruction(index));469 }470 else471 {472 return new LoadLocalBoxedInstruction(index);473 }474 }475 476 public void EmitLoadLocalFromClosure(int index)477 {478 s_loadLocalFromClosure ??= new Instruction[LocalInstrCacheSize];479 480 if (index < s_loadLocalFromClosure.Length)481 {482 Emit(s_loadLocalFromClosure[index] ?? (s_loadLocalFromClosure[index] = new LoadLocalFromClosureInstruction(index)));483 }484 else485 {486 Emit(new LoadLocalFromClosureInstruction(index));487 }488 }489 490 public void EmitLoadLocalFromClosureBoxed(int index)491 {492 s_loadLocalFromClosureBoxed ??= new Instruction[LocalInstrCacheSize];493 494 if (index < s_loadLocalFromClosureBoxed.Length)495 {496 Emit(s_loadLocalFromClosureBoxed[index] ?? (s_loadLocalFromClosureBoxed[index] = new LoadLocalFromClosureBoxedInstruction(index)));497 }498 else499 {500 Emit(new LoadLocalFromClosureBoxedInstruction(index));501 }502 }503 504 public void EmitAssignLocal(int index)505 {506 s_assignLocal ??= new Instruction[LocalInstrCacheSize];507 508 if (index < s_assignLocal.Length)509 {510 Emit(s_assignLocal[index] ?? (s_assignLocal[index] = new AssignLocalInstruction(index)));511 }512 else513 {514 Emit(new AssignLocalInstruction(index));515 }516 }517 518 public void EmitStoreLocal(int index)519 {520 s_storeLocal ??= new Instruction[LocalInstrCacheSize];521 522 if (index < s_storeLocal.Length)523 {524 Emit(s_storeLocal[index] ?? (s_storeLocal[index] = new StoreLocalInstruction(index)));525 }526 else527 {528 Emit(new StoreLocalInstruction(index));529 }530 }531 532 public void EmitAssignLocalBoxed(int index)533 {534 Emit(AssignLocalBoxed(index));535 }536 537 internal static Instruction AssignLocalBoxed(int index)538 {539 s_assignLocalBoxed ??= new Instruction[LocalInstrCacheSize];540 541 if (index < s_assignLocalBoxed.Length)542 {543 return s_assignLocalBoxed[index] ?? (s_assignLocalBoxed[index] = new AssignLocalBoxedInstruction(index));544 }545 else546 {547 return new AssignLocalBoxedInstruction(index);548 }549 }550 551 public void EmitStoreLocalBoxed(int index)552 {553 Emit(StoreLocalBoxed(index));554 }555 556 internal static Instruction StoreLocalBoxed(int index)557 {558 s_storeLocalBoxed ??= new Instruction[LocalInstrCacheSize];559 560 if (index < s_storeLocalBoxed.Length)561 {562 return s_storeLocalBoxed[index] ?? (s_storeLocalBoxed[index] = new StoreLocalBoxedInstruction(index));563 }564 else565 {566 return new StoreLocalBoxedInstruction(index);567 }568 }569 570 public void EmitAssignLocalToClosure(int index)571 {572 s_assignLocalToClosure ??= new Instruction[LocalInstrCacheSize];573 574 if (index < s_assignLocalToClosure.Length)575 {576 Emit(s_assignLocalToClosure[index] ?? (s_assignLocalToClosure[index] = new AssignLocalToClosureInstruction(index)));577 }578 else579 {580 Emit(new AssignLocalToClosureInstruction(index));581 }582 }583 584 public void EmitStoreLocalToClosure(int index)585 {586 EmitAssignLocalToClosure(index);587 EmitPop();588 }589 590 public void EmitInitializeLocal(int index, Type type)591 {592 object value = ScriptingRuntimeHelpers.GetPrimitiveDefaultValue(type);593 if (value != null)594 {595 Emit(new InitializeLocalInstruction.ImmutableValue(index, value));596 }597 else if (type.IsValueType)598 {599 Emit(new InitializeLocalInstruction.MutableValue(index, type));600 }601 else602 {603 Emit(InitReference(index));604 }605 }606 607 internal void EmitInitializeParameter(int index)608 {609 Emit(Parameter(index));610 }611 612 internal static Instruction Parameter(int index)613 {614 s_parameter ??= new Instruction[LocalInstrCacheSize];615 616 if (index < s_parameter.Length)617 {618 return s_parameter[index] ?? (s_parameter[index] = new InitializeLocalInstruction.Parameter(index));619 }620 621 return new InitializeLocalInstruction.Parameter(index);622 }623 624 internal static Instruction ParameterBox(int index)625 {626 s_parameterBox ??= new Instruction[LocalInstrCacheSize];627 628 if (index < s_parameterBox.Length)629 {630 return s_parameterBox[index] ?? (s_parameterBox[index] = new InitializeLocalInstruction.ParameterBox(index));631 }632 633 return new InitializeLocalInstruction.ParameterBox(index);634 }635 636 internal static Instruction InitReference(int index)637 {638 s_initReference ??= new Instruction[LocalInstrCacheSize];639 640 if (index < s_initReference.Length)641 {642 return s_initReference[index] ?? (s_initReference[index] = new InitializeLocalInstruction.Reference(index));643 }644 645 return new InitializeLocalInstruction.Reference(index);646 }647 648 internal static Instruction InitImmutableRefBox(int index)649 {650 s_initImmutableRefBox ??= new Instruction[LocalInstrCacheSize];651 652 if (index < s_initImmutableRefBox.Length)653 {654 return s_initImmutableRefBox[index] ?? (s_initImmutableRefBox[index] = new InitializeLocalInstruction.ImmutableBox(index, null));655 }656 657 return new InitializeLocalInstruction.ImmutableBox(index, null);658 }659 660 public void EmitNewRuntimeVariables(int count)661 {662 Emit(new RuntimeVariablesInstruction(count));663 }664 665 #endregion666 667 #region Array Operations668 669 public void EmitGetArrayItem(Type arrayType)670 {671 var elementType = arrayType.GetElementType();672 if (elementType.IsClass || elementType.IsInterface)673 {674 Emit(InstructionFactory<object>.Factory.GetArrayItem());675 }676 else677 {678 Emit(InstructionFactory.GetFactory(elementType).GetArrayItem());679 }680 }681 682 public void EmitSetArrayItem(Type arrayType)683 {684 var elementType = arrayType.GetElementType();685 if (elementType.IsClass || elementType.IsInterface)686 {687 Emit(InstructionFactory<object>.Factory.SetArrayItem());688 }689 else690 {691 Emit(InstructionFactory.GetFactory(elementType).SetArrayItem());692 }693 }694 695 public void EmitNewArray(Type elementType)696 {697 Emit(InstructionFactory.GetFactory(elementType).NewArray());698 }699 700 public void EmitNewArrayBounds(Type elementType, int rank)701 {702 Emit(new NewArrayBoundsInstruction(elementType, rank));703 }704 705 public void EmitNewArrayInit(Type elementType, int elementCount)706 {707 // To avoid lock contention in InstructionFactory.GetFactory, we special case the most common708 // types of arrays that the compiler creates.709 if (elementType == typeof(CommandParameterInternal))710 {711 Emit(InstructionFactory<CommandParameterInternal>.Factory.NewArrayInit(elementCount));712 }713 else if (elementType == typeof(CommandParameterInternal[]))714 {715 Emit(InstructionFactory<CommandParameterInternal[]>.Factory.NewArrayInit(elementCount));716 }717 else if (elementType == typeof(object))718 {719 Emit(InstructionFactory<object>.Factory.NewArrayInit(elementCount));720 }721 else if (elementType == typeof(string))722 {723 Emit(InstructionFactory<string>.Factory.NewArrayInit(elementCount));724 }725 else726 {727 Emit(InstructionFactory.GetFactory(elementType).NewArrayInit(elementCount));728 }729 }730 731 #endregion732 733 #region Arithmetic Operations734 735 public void EmitAdd(Type type, bool @checked)736 {737 if (@checked)738 {739 Emit(AddOvfInstruction.Create(type));740 }741 else742 {743 Emit(AddInstruction.Create(type));744 }745 }746 747 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]748 public void EmitSub(Type type, bool @checked)749 {750 if (@checked)751 {752 Emit(SubOvfInstruction.Create(type));753 }754 else755 {756 Emit(SubInstruction.Create(type));757 }758 }759 760 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]761 public void EmitMul(Type type, bool @checked)762 {763 if (@checked)764 {765 Emit(MulOvfInstruction.Create(type));766 }767 else768 {769 Emit(MulInstruction.Create(type));770 }771 }772 773 public void EmitDiv(Type type)774 {775 Emit(DivInstruction.Create(type));776 }777 778 #endregion779 780 #region Comparisons781 782 public void EmitEqual(Type type)783 {784 Emit(EqualInstruction.Create(type));785 }786 787 public void EmitNotEqual(Type type)788 {789 Emit(NotEqualInstruction.Create(type));790 }791 792 public void EmitLessThan(Type type)793 {794 Emit(LessThanInstruction.Create(type));795 }796 797 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]798 public void EmitLessThanOrEqual(Type type)799 {800 throw new NotSupportedException();801 }802 803 public void EmitGreaterThan(Type type)804 {805 Emit(GreaterThanInstruction.Create(type));806 }807 808 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]809 public void EmitGreaterThanOrEqual(Type type)810 {811 throw new NotSupportedException();812 }813 814 #endregion815 816 #region Conversions817 818 public void EmitNumericConvertChecked(TypeCode from, TypeCode to)819 {820 Emit(new NumericConvertInstruction.Checked(from, to));821 }822 823 public void EmitNumericConvertUnchecked(TypeCode from, TypeCode to)824 {825 Emit(new NumericConvertInstruction.Unchecked(from, to));826 }827 828 #endregion829 830 #region Boolean Operators831 832 public void EmitNot()833 {834 Emit(NotInstruction.Instance);835 }836 837 #endregion838 839 #region Types840 841 public void EmitDefaultValue(Type type)842 {843 Emit(InstructionFactory.GetFactory(type).DefaultValue());844 }845 846 public void EmitNew(ConstructorInfo constructorInfo)847 {848 Emit(new NewInstruction(constructorInfo));849 }850 851 internal void EmitCreateDelegate(LightDelegateCreator creator)852 {853 Emit(new CreateDelegateInstruction(creator));854 }855 856 public void EmitTypeEquals()857 {858 Emit(TypeEqualsInstruction.Instance);859 }860 861 public void EmitTypeIs(Type type)862 {863 Emit(InstructionFactory.GetFactory(type).TypeIs());864 }865 866 public void EmitTypeAs(Type type)867 {868 Emit(InstructionFactory.GetFactory(type).TypeAs());869 }870 871 #endregion872 873 #region Fields and Methods874 875 private static readonly Dictionary<FieldInfo, Instruction> s_loadFields = new Dictionary<FieldInfo, Instruction>();876 877 public void EmitLoadField(FieldInfo field)878 {879 Emit(GetLoadField(field));880 }881 882 private static Instruction GetLoadField(FieldInfo field)883 {884 lock (s_loadFields)885 {886 Instruction instruction;887 if (!s_loadFields.TryGetValue(field, out instruction))888 {889 if (field.IsStatic)890 {891 instruction = new LoadStaticFieldInstruction(field);892 }893 else894 {895 instruction = new LoadFieldInstruction(field);896 }897 898 s_loadFields.Add(field, instruction);899 }900 901 return instruction;902 }903 }904 905 public void EmitStoreField(FieldInfo field)906 {907 if (field.IsStatic)908 {909 Emit(new StoreStaticFieldInstruction(field));910 }911 else912 {913 Emit(new StoreFieldInstruction(field));914 }915 }916 917 public void EmitCall(MethodInfo method)918 {919 EmitCall(method, method.GetParameters());920 }921 922 public void EmitCall(MethodInfo method, ParameterInfo[] parameters)923 {924 Emit(CallInstruction.Create(method, parameters));925 }926 927 #endregion928 929 #region Dynamic930 931 public void EmitDynamic(Type type, CallSiteBinder binder)932 {933 Emit(CreateDynamicInstruction(type, binder));934 }935 936 #region Generated Dynamic InstructionList Factory937 938 // *** BEGIN GENERATED CODE ***939 // generated by function: gen_instructionlist_factory from: generate_dynamic_instructions.py940 941 public void EmitDynamic<T0, TRet>(CallSiteBinder binder)942 {943 Emit(DynamicInstruction<T0, TRet>.Factory(binder));944 }945 946 public void EmitDynamic<T0, T1, TRet>(CallSiteBinder binder)947 {948 Emit(DynamicInstruction<T0, T1, TRet>.Factory(binder));949 }950 951 public void EmitDynamic<T0, T1, T2, TRet>(CallSiteBinder binder)952 {953 Emit(DynamicInstruction<T0, T1, T2, TRet>.Factory(binder));954 }955 956 public void EmitDynamic<T0, T1, T2, T3, TRet>(CallSiteBinder binder)957 {958 Emit(DynamicInstruction<T0, T1, T2, T3, TRet>.Factory(binder));959 }960 961 public void EmitDynamic<T0, T1, T2, T3, T4, TRet>(CallSiteBinder binder)962 {963 Emit(DynamicInstruction<T0, T1, T2, T3, T4, TRet>.Factory(binder));964 }965 966 public void EmitDynamic<T0, T1, T2, T3, T4, T5, TRet>(CallSiteBinder binder)967 {968 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, TRet>.Factory(binder));969 }970 971 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, TRet>(CallSiteBinder binder)972 {973 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, TRet>.Factory(binder));974 }975 976 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, TRet>(CallSiteBinder binder)977 {978 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, TRet>.Factory(binder));979 }980 981 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>(CallSiteBinder binder)982 {983 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>.Factory(binder));984 }985 986 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>(CallSiteBinder binder)987 {988 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>.Factory(binder));989 }990 991 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>(CallSiteBinder binder)992 {993 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>.Factory(binder));994 }995 996 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>(CallSiteBinder binder)997 {998 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>.Factory(binder));999 }1000 1001 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>(CallSiteBinder binder)1002 {1003 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>.Factory(binder));1004 }1005 1006 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>(CallSiteBinder binder)1007 {1008 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>.Factory(binder));1009 }1010 1011 public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>(CallSiteBinder binder)1012 {1013 Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>.Factory(binder));1014 }1015 1016 // *** END GENERATED CODE ***1017 1018 #endregion1019 1020 private static readonly Dictionary<Type, Func<CallSiteBinder, Instruction>> s_factories =1021 new Dictionary<Type, Func<CallSiteBinder, Instruction>>();1022 1023 internal static Instruction CreateDynamicInstruction(Type delegateType, CallSiteBinder binder)1024 {1025 Func<CallSiteBinder, Instruction> factory;1026 lock (s_factories)1027 {1028 if (!s_factories.TryGetValue(delegateType, out factory))1029 {1030 if (delegateType.GetMethod("Invoke").ReturnType == typeof(void))1031 {1032 // TODO: We should generally support void returning binders but the only1033 // ones that exist are delete index/member who's perf isn't that critical.1034 return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder), true);1035 }1036 1037 Type instructionType = DynamicInstructionN.GetDynamicInstructionType(delegateType);1038 if (instructionType == null)1039 {1040 return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder));1041 }1042 1043 factory = (Func<CallSiteBinder, Instruction>)instructionType1044 .GetMethod("Factory")1045 .CreateDelegate(typeof(Func<CallSiteBinder, Instruction>));1046 1047 s_factories[delegateType] = factory;1048 }1049 }1050 1051 return factory(binder);1052 }1053 1054 #endregion1055 1056 #region Control Flow1057 1058 private static readonly RuntimeLabel[] s_emptyRuntimeLabels = new RuntimeLabel[] { new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0) };1059 1060 private RuntimeLabel[] BuildRuntimeLabels()1061 {1062 if (_runtimeLabelCount == 0)1063 {1064 return s_emptyRuntimeLabels;1065 }1066 1067 var result = new RuntimeLabel[_runtimeLabelCount + 1];1068 foreach (BranchLabel label in _labels)1069 {1070 if (label.HasRuntimeLabel)1071 {1072 result[label.LabelIndex] = label.ToRuntimeLabel();1073 }1074 }1075 // "return and rethrow" label:1076 result[result.Length - 1] = new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0);1077 return result;1078 }1079 1080 public BranchLabel MakeLabel()1081 {1082 _labels ??= new List<BranchLabel>();1083 1084 var label = new BranchLabel();1085 _labels.Add(label);1086 return label;1087 }1088 1089 internal void FixupBranch(int branchIndex, int offset)1090 {1091 _instructions[branchIndex] = ((OffsetInstruction)_instructions[branchIndex]).Fixup(offset);1092 }1093 1094 private int EnsureLabelIndex(BranchLabel label)1095 {1096 if (label.HasRuntimeLabel)1097 {1098 return label.LabelIndex;1099 }1100 1101 label.LabelIndex = _runtimeLabelCount;1102 _runtimeLabelCount++;1103 return label.LabelIndex;1104 }1105 1106 public int MarkRuntimeLabel()1107 {1108 BranchLabel handlerLabel = MakeLabel();1109 MarkLabel(handlerLabel);1110 return EnsureLabelIndex(handlerLabel);1111 }1112 1113 public void MarkLabel(BranchLabel label)1114 {1115 label.Mark(this);1116 }1117 1118 public void EmitGoto(BranchLabel label, bool hasResult, bool hasValue)1119 {1120 Emit(GotoInstruction.Create(EnsureLabelIndex(label), hasResult, hasValue));1121 }1122 1123 private void EmitBranch(OffsetInstruction instruction, BranchLabel label)1124 {1125 Emit(instruction);1126 label.AddBranch(this, Count - 1);1127 }1128 1129 public void EmitBranch(BranchLabel label)1130 {1131 EmitBranch(new BranchInstruction(), label);1132 }1133 1134 public void EmitBranch(BranchLabel label, bool hasResult, bool hasValue)1135 {1136 EmitBranch(new BranchInstruction(hasResult, hasValue), label);1137 }1138 1139 public void EmitCoalescingBranch(BranchLabel leftNotNull)1140 {1141 EmitBranch(new CoalescingBranchInstruction(), leftNotNull);1142 }1143 1144 public void EmitBranchTrue(BranchLabel elseLabel)1145 {1146 EmitBranch(new BranchTrueInstruction(), elseLabel);1147 }1148 1149 public void EmitBranchFalse(BranchLabel elseLabel)1150 {1151 EmitBranch(new BranchFalseInstruction(), elseLabel);1152 }1153 1154 public void EmitThrow()1155 {1156 Emit(ThrowInstruction.Throw);1157 }1158 1159 public void EmitThrowVoid()1160 {1161 Emit(ThrowInstruction.VoidThrow);1162 }1163 1164 public void EmitRethrow()1165 {1166 Emit(ThrowInstruction.Rethrow);1167 }1168 1169 public void EmitRethrowVoid()1170 {1171 Emit(ThrowInstruction.VoidRethrow);1172 }1173 1174 public void EmitEnterTryFinally(BranchLabel finallyStartLabel)1175 {1176 Emit(EnterTryCatchFinallyInstruction.CreateTryFinally(EnsureLabelIndex(finallyStartLabel)));1177 }1178 1179 public void EmitEnterTryCatch()1180 {1181 Emit(EnterTryCatchFinallyInstruction.CreateTryCatch());1182 }1183 1184 public void EmitEnterFinally(BranchLabel finallyStartLabel)1185 {1186 Emit(EnterFinallyInstruction.Create(EnsureLabelIndex(finallyStartLabel)));1187 }1188 1189 public void EmitLeaveFinally()1190 {1191 Emit(LeaveFinallyInstruction.Instance);1192 }1193 1194 public void EmitLeaveFault(bool hasValue)1195 {1196 Emit(hasValue ? LeaveFaultInstruction.NonVoid : LeaveFaultInstruction.Void);1197 }1198 1199 public void EmitEnterExceptionHandlerNonVoid()1200 {