PageRenderTime 69ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/Runtime/Microsoft.Dynamic/Interpreter/Instructions/InstructionList.cs

http://github.com/IronLanguages/main
C# | 1001 lines | 768 code | 205 blank | 28 comment | 115 complexity | c5692298a92d1f235c4b423cf029df3c MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. // Enables instruction counting and displaying stats at process exit.
  16. // #define STATS
  17. using System;
  18. using System.Collections.Generic;
  19. using System.Diagnostics;
  20. using System.Reflection;
  21. using System.Runtime.CompilerServices;
  22. using System.Security;
  23. using Microsoft.Scripting.Runtime;
  24. using Microsoft.Scripting.Utils;
  25. namespace Microsoft.Scripting.Interpreter {
  26. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")]
  27. [DebuggerTypeProxy(typeof(InstructionArray.DebugView))]
  28. public struct InstructionArray {
  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. // list of (instruction index, cookie) sorted by instruction index:
  35. internal readonly List<KeyValuePair<int, object>> DebugCookies;
  36. internal InstructionArray(int maxStackDepth, int maxContinuationDepth, Instruction[] instructions,
  37. object[] objects, RuntimeLabel[] labels, List<KeyValuePair<int, object>> debugCookies) {
  38. MaxStackDepth = maxStackDepth;
  39. MaxContinuationDepth = maxContinuationDepth;
  40. Instructions = instructions;
  41. DebugCookies = debugCookies;
  42. Objects = objects;
  43. Labels = labels;
  44. }
  45. internal int Length {
  46. get { return Instructions.Length; }
  47. }
  48. #region Debug View
  49. internal sealed class DebugView {
  50. private readonly InstructionArray _array;
  51. public DebugView(InstructionArray array) {
  52. _array = array;
  53. }
  54. [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
  55. public InstructionList.DebugView.InstructionView[]/*!*/ A0 {
  56. get {
  57. return InstructionList.DebugView.GetInstructionViews(
  58. _array.Instructions,
  59. _array.Objects,
  60. (index) => _array.Labels[index].Index,
  61. _array.DebugCookies
  62. );
  63. }
  64. }
  65. }
  66. #endregion
  67. }
  68. [DebuggerTypeProxy(typeof(InstructionList.DebugView))]
  69. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
  70. public sealed class InstructionList {
  71. private readonly List<Instruction> _instructions = new List<Instruction>();
  72. private List<object> _objects;
  73. private int _currentStackDepth;
  74. private int _maxStackDepth;
  75. private int _currentContinuationsDepth;
  76. private int _maxContinuationDepth;
  77. private int _runtimeLabelCount;
  78. private List<BranchLabel> _labels;
  79. // list of (instruction index, cookie) sorted by instruction index:
  80. private List<KeyValuePair<int, object>> _debugCookies = null;
  81. #region Debug View
  82. internal sealed class DebugView {
  83. private readonly InstructionList _list;
  84. public DebugView(InstructionList list) {
  85. _list = list;
  86. }
  87. [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
  88. public InstructionView[]/*!*/ A0 {
  89. get {
  90. return GetInstructionViews(
  91. _list._instructions,
  92. _list._objects,
  93. (index) => _list._labels[index].TargetIndex,
  94. _list._debugCookies
  95. );
  96. }
  97. }
  98. internal static InstructionView[] GetInstructionViews(IList<Instruction> instructions, IList<object> objects,
  99. Func<int, int> labelIndexer, IList<KeyValuePair<int, object>> debugCookies) {
  100. var result = new List<InstructionView>();
  101. int index = 0;
  102. int stackDepth = 0;
  103. int continuationsDepth = 0;
  104. var cookieEnumerator = (debugCookies != null ? debugCookies : new KeyValuePair<int, object>[0]).GetEnumerator();
  105. var hasCookie = cookieEnumerator.MoveNext();
  106. for (int i = 0; i < instructions.Count; i++) {
  107. object cookie = null;
  108. while (hasCookie && cookieEnumerator.Current.Key == i) {
  109. cookie = cookieEnumerator.Current.Value;
  110. hasCookie = cookieEnumerator.MoveNext();
  111. }
  112. int stackDiff = instructions[i].StackBalance;
  113. int contDiff = instructions[i].ContinuationsBalance;
  114. string name = instructions[i].ToDebugString(i, cookie, labelIndexer, objects);
  115. result.Add(new InstructionView(instructions[i], name, i, stackDepth, continuationsDepth));
  116. index++;
  117. stackDepth += stackDiff;
  118. continuationsDepth += contDiff;
  119. }
  120. return result.ToArray();
  121. }
  122. [DebuggerDisplay("{GetValue(),nq}", Name = "{GetName(),nq}", Type = "{GetDisplayType(), nq}")]
  123. internal struct InstructionView {
  124. private readonly int _index;
  125. private readonly int _stackDepth;
  126. private readonly int _continuationsDepth;
  127. private readonly string _name;
  128. private readonly Instruction _instruction;
  129. internal string GetName() {
  130. return _index.ToString() +
  131. (_continuationsDepth == 0 ? "" : " C(" + _continuationsDepth.ToString() + ")") +
  132. (_stackDepth == 0 ? "" : " S(" + _stackDepth.ToString() + ")");
  133. }
  134. internal string GetValue() {
  135. return _name;
  136. }
  137. internal string GetDisplayType() {
  138. return _instruction.ContinuationsBalance.ToString() + "/" + _instruction.StackBalance.ToString();
  139. }
  140. public InstructionView(Instruction instruction, string name, int index, int stackDepth, int continuationsDepth) {
  141. _instruction = instruction;
  142. _name = name;
  143. _index = index;
  144. _stackDepth = stackDepth;
  145. _continuationsDepth = continuationsDepth;
  146. }
  147. }
  148. }
  149. #endregion
  150. #region Core Emit Ops
  151. public void Emit(Instruction instruction) {
  152. _instructions.Add(instruction);
  153. UpdateStackDepth(instruction);
  154. }
  155. private void UpdateStackDepth(Instruction instruction) {
  156. Debug.Assert(instruction.ConsumedStack >= 0 && instruction.ProducedStack >= 0 &&
  157. instruction.ConsumedContinuations >= 0 && instruction.ProducedContinuations >= 0);
  158. _currentStackDepth -= instruction.ConsumedStack;
  159. Debug.Assert(_currentStackDepth >= 0);
  160. _currentStackDepth += instruction.ProducedStack;
  161. if (_currentStackDepth > _maxStackDepth) {
  162. _maxStackDepth = _currentStackDepth;
  163. }
  164. _currentContinuationsDepth -= instruction.ConsumedContinuations;
  165. Debug.Assert(_currentContinuationsDepth >= 0);
  166. _currentContinuationsDepth += instruction.ProducedContinuations;
  167. if (_currentContinuationsDepth > _maxContinuationDepth) {
  168. _maxContinuationDepth = _currentContinuationsDepth;
  169. }
  170. }
  171. /// <summary>
  172. /// Attaches a cookie to the last emitted instruction.
  173. /// </summary>
  174. [Conditional("DEBUG")]
  175. public void SetDebugCookie(object cookie) {
  176. #if DEBUG
  177. if (_debugCookies == null) {
  178. _debugCookies = new List<KeyValuePair<int, object>>();
  179. }
  180. Debug.Assert(Count > 0);
  181. _debugCookies.Add(new KeyValuePair<int, object>(Count - 1, cookie));
  182. #endif
  183. }
  184. public int Count {
  185. get { return _instructions.Count; }
  186. }
  187. public int CurrentStackDepth {
  188. get { return _currentStackDepth; }
  189. }
  190. public int CurrentContinuationsDepth {
  191. get { return _currentContinuationsDepth; }
  192. }
  193. public int MaxStackDepth {
  194. get { return _maxStackDepth; }
  195. }
  196. internal Instruction GetInstruction(int index) {
  197. return _instructions[index];
  198. }
  199. #if STATS
  200. private static Dictionary<string, int> _executedInstructions = new Dictionary<string, int>();
  201. private static Dictionary<string, Dictionary<object, bool>> _instances = new Dictionary<string, Dictionary<object, bool>>();
  202. static InstructionList() {
  203. AppDomain.CurrentDomain.ProcessExit += new EventHandler((_, __) => {
  204. PerfTrack.DumpHistogram(_executedInstructions);
  205. Console.WriteLine("-- Total executed: {0}", _executedInstructions.Values.Aggregate(0, (sum, value) => sum + value));
  206. Console.WriteLine("-----");
  207. var referenced = new Dictionary<string, int>();
  208. int total = 0;
  209. foreach (var entry in _instances) {
  210. referenced[entry.Key] = entry.Value.Count;
  211. total += entry.Value.Count;
  212. }
  213. PerfTrack.DumpHistogram(referenced);
  214. Console.WriteLine("-- Total referenced: {0}", total);
  215. Console.WriteLine("-----");
  216. });
  217. }
  218. #endif
  219. public InstructionArray ToArray() {
  220. #if STATS
  221. lock (_executedInstructions) {
  222. _instructions.ForEach((instr) => {
  223. int value = 0;
  224. var name = instr.GetType().Name;
  225. _executedInstructions.TryGetValue(name, out value);
  226. _executedInstructions[name] = value + 1;
  227. Dictionary<object, bool> dict;
  228. if (!_instances.TryGetValue(name, out dict)) {
  229. _instances[name] = dict = new Dictionary<object, bool>();
  230. }
  231. dict[instr] = true;
  232. });
  233. }
  234. #endif
  235. return new InstructionArray(
  236. _maxStackDepth,
  237. _maxContinuationDepth,
  238. _instructions.ToArray(),
  239. (_objects != null) ? _objects.ToArray() : null,
  240. BuildRuntimeLabels(),
  241. _debugCookies
  242. );
  243. }
  244. #endregion
  245. #region Stack Operations
  246. private const int PushIntMinCachedValue = -100;
  247. private const int PushIntMaxCachedValue = 100;
  248. private const int CachedObjectCount = 256;
  249. private static Instruction _null;
  250. private static Instruction _true;
  251. private static Instruction _false;
  252. private static Instruction[] _ints;
  253. private static Instruction[] _loadObjectCached;
  254. public void EmitLoad(object value) {
  255. EmitLoad(value, null);
  256. }
  257. public void EmitLoad(bool value) {
  258. if ((bool)value) {
  259. Emit(_true ?? (_true = new LoadObjectInstruction(value)));
  260. } else {
  261. Emit(_false ?? (_false = new LoadObjectInstruction(value)));
  262. }
  263. }
  264. public void EmitLoad(object value, Type type) {
  265. if (value == null) {
  266. Emit(_null ?? (_null = new LoadObjectInstruction(null)));
  267. return;
  268. }
  269. if (type == null || type.IsValueType()) {
  270. if (value is bool) {
  271. EmitLoad((bool)value);
  272. return;
  273. }
  274. if (value is int) {
  275. int i = (int)value;
  276. if (i >= PushIntMinCachedValue && i <= PushIntMaxCachedValue) {
  277. if (_ints == null) {
  278. _ints = new Instruction[PushIntMaxCachedValue - PushIntMinCachedValue + 1];
  279. }
  280. i -= PushIntMinCachedValue;
  281. Emit(_ints[i] ?? (_ints[i] = new LoadObjectInstruction(value)));
  282. return;
  283. }
  284. }
  285. }
  286. if (_objects == null) {
  287. _objects = new List<object>();
  288. if (_loadObjectCached == null) {
  289. _loadObjectCached = new Instruction[CachedObjectCount];
  290. }
  291. }
  292. if (_objects.Count < _loadObjectCached.Length) {
  293. uint index = (uint)_objects.Count;
  294. _objects.Add(value);
  295. Emit(_loadObjectCached[index] ?? (_loadObjectCached[index] = new LoadCachedObjectInstruction(index)));
  296. } else {
  297. Emit(new LoadObjectInstruction(value));
  298. }
  299. }
  300. public void EmitDup() {
  301. Emit(DupInstruction.Instance);
  302. }
  303. public void EmitPop() {
  304. Emit(PopInstruction.Instance);
  305. }
  306. #endregion
  307. #region Locals
  308. internal void SwitchToBoxed(int index, int instructionIndex) {
  309. var instruction = _instructions[instructionIndex] as IBoxableInstruction;
  310. if (instruction != null) {
  311. var newInstruction = instruction.BoxIfIndexMatches(index);
  312. if (newInstruction != null) {
  313. _instructions[instructionIndex] = newInstruction;
  314. }
  315. }
  316. }
  317. private const int LocalInstrCacheSize = 64;
  318. private static Instruction[] _loadLocal;
  319. private static Instruction[] _loadLocalBoxed;
  320. private static Instruction[] _loadLocalFromClosure;
  321. private static Instruction[] _loadLocalFromClosureBoxed;
  322. private static Instruction[] _assignLocal;
  323. private static Instruction[] _storeLocal;
  324. private static Instruction[] _assignLocalBoxed;
  325. private static Instruction[] _storeLocalBoxed;
  326. private static Instruction[] _assignLocalToClosure;
  327. private static Instruction[] _initReference;
  328. private static Instruction[] _initImmutableRefBox;
  329. private static Instruction[] _parameterBox;
  330. private static Instruction[] _parameter;
  331. public void EmitLoadLocal(int index) {
  332. if (_loadLocal == null) {
  333. _loadLocal = new Instruction[LocalInstrCacheSize];
  334. }
  335. if (index < _loadLocal.Length) {
  336. Emit(_loadLocal[index] ?? (_loadLocal[index] = new LoadLocalInstruction(index)));
  337. } else {
  338. Emit(new LoadLocalInstruction(index));
  339. }
  340. }
  341. public void EmitLoadLocalBoxed(int index) {
  342. Emit(LoadLocalBoxed(index));
  343. }
  344. internal static Instruction LoadLocalBoxed(int index) {
  345. if (_loadLocalBoxed == null) {
  346. _loadLocalBoxed = new Instruction[LocalInstrCacheSize];
  347. }
  348. if (index < _loadLocalBoxed.Length) {
  349. return _loadLocalBoxed[index] ?? (_loadLocalBoxed[index] = new LoadLocalBoxedInstruction(index));
  350. } else {
  351. return new LoadLocalBoxedInstruction(index);
  352. }
  353. }
  354. public void EmitLoadLocalFromClosure(int index) {
  355. if (_loadLocalFromClosure == null) {
  356. _loadLocalFromClosure = new Instruction[LocalInstrCacheSize];
  357. }
  358. if (index < _loadLocalFromClosure.Length) {
  359. Emit(_loadLocalFromClosure[index] ?? (_loadLocalFromClosure[index] = new LoadLocalFromClosureInstruction(index)));
  360. } else {
  361. Emit(new LoadLocalFromClosureInstruction(index));
  362. }
  363. }
  364. public void EmitLoadLocalFromClosureBoxed(int index) {
  365. if (_loadLocalFromClosureBoxed == null) {
  366. _loadLocalFromClosureBoxed = new Instruction[LocalInstrCacheSize];
  367. }
  368. if (index < _loadLocalFromClosureBoxed.Length) {
  369. Emit(_loadLocalFromClosureBoxed[index] ?? (_loadLocalFromClosureBoxed[index] = new LoadLocalFromClosureBoxedInstruction(index)));
  370. } else {
  371. Emit(new LoadLocalFromClosureBoxedInstruction(index));
  372. }
  373. }
  374. public void EmitAssignLocal(int index) {
  375. if (_assignLocal == null) {
  376. _assignLocal = new Instruction[LocalInstrCacheSize];
  377. }
  378. if (index < _assignLocal.Length) {
  379. Emit(_assignLocal[index] ?? (_assignLocal[index] = new AssignLocalInstruction(index)));
  380. } else {
  381. Emit(new AssignLocalInstruction(index));
  382. }
  383. }
  384. public void EmitStoreLocal(int index) {
  385. if (_storeLocal == null) {
  386. _storeLocal = new Instruction[LocalInstrCacheSize];
  387. }
  388. if (index < _storeLocal.Length) {
  389. Emit(_storeLocal[index] ?? (_storeLocal[index] = new StoreLocalInstruction(index)));
  390. } else {
  391. Emit(new StoreLocalInstruction(index));
  392. }
  393. }
  394. public void EmitAssignLocalBoxed(int index) {
  395. Emit(AssignLocalBoxed(index));
  396. }
  397. internal static Instruction AssignLocalBoxed(int index) {
  398. if (_assignLocalBoxed == null) {
  399. _assignLocalBoxed = new Instruction[LocalInstrCacheSize];
  400. }
  401. if (index < _assignLocalBoxed.Length) {
  402. return _assignLocalBoxed[index] ?? (_assignLocalBoxed[index] = new AssignLocalBoxedInstruction(index));
  403. } else {
  404. return new AssignLocalBoxedInstruction(index);
  405. }
  406. }
  407. public void EmitStoreLocalBoxed(int index) {
  408. Emit(StoreLocalBoxed(index));
  409. }
  410. internal static Instruction StoreLocalBoxed(int index) {
  411. if (_storeLocalBoxed == null) {
  412. _storeLocalBoxed = new Instruction[LocalInstrCacheSize];
  413. }
  414. if (index < _storeLocalBoxed.Length) {
  415. return _storeLocalBoxed[index] ?? (_storeLocalBoxed[index] = new StoreLocalBoxedInstruction(index));
  416. } else {
  417. return new StoreLocalBoxedInstruction(index);
  418. }
  419. }
  420. public void EmitAssignLocalToClosure(int index) {
  421. if (_assignLocalToClosure == null) {
  422. _assignLocalToClosure = new Instruction[LocalInstrCacheSize];
  423. }
  424. if (index < _assignLocalToClosure.Length) {
  425. Emit(_assignLocalToClosure[index] ?? (_assignLocalToClosure[index] = new AssignLocalToClosureInstruction(index)));
  426. } else {
  427. Emit(new AssignLocalToClosureInstruction(index));
  428. }
  429. }
  430. public void EmitStoreLocalToClosure(int index) {
  431. EmitAssignLocalToClosure(index);
  432. EmitPop();
  433. }
  434. public void EmitInitializeLocal(int index, Type type) {
  435. object value = ScriptingRuntimeHelpers.GetPrimitiveDefaultValue(type);
  436. if (value != null) {
  437. Emit(new InitializeLocalInstruction.ImmutableValue(index, value));
  438. } else if (type.IsValueType()) {
  439. Emit(new InitializeLocalInstruction.MutableValue(index, type));
  440. } else {
  441. Emit(InitReference(index));
  442. }
  443. }
  444. internal void EmitInitializeParameter(int index) {
  445. Emit(Parameter(index));
  446. }
  447. internal static Instruction Parameter(int index) {
  448. if (_parameter == null) {
  449. _parameter = new Instruction[LocalInstrCacheSize];
  450. }
  451. if (index < _parameter.Length) {
  452. return _parameter[index] ?? (_parameter[index] = new InitializeLocalInstruction.Parameter(index));
  453. }
  454. return new InitializeLocalInstruction.Parameter(index);
  455. }
  456. internal static Instruction ParameterBox(int index) {
  457. if (_parameterBox == null) {
  458. _parameterBox = new Instruction[LocalInstrCacheSize];
  459. }
  460. if (index < _parameterBox.Length) {
  461. return _parameterBox[index] ?? (_parameterBox[index] = new InitializeLocalInstruction.ParameterBox(index));
  462. }
  463. return new InitializeLocalInstruction.ParameterBox(index);
  464. }
  465. internal static Instruction InitReference(int index) {
  466. if (_initReference == null) {
  467. _initReference = new Instruction[LocalInstrCacheSize];
  468. }
  469. if (index < _initReference.Length) {
  470. return _initReference[index] ?? (_initReference[index] = new InitializeLocalInstruction.Reference(index));
  471. }
  472. return new InitializeLocalInstruction.Reference(index);
  473. }
  474. internal static Instruction InitImmutableRefBox(int index) {
  475. if (_initImmutableRefBox == null) {
  476. _initImmutableRefBox = new Instruction[LocalInstrCacheSize];
  477. }
  478. if (index < _initImmutableRefBox.Length) {
  479. return _initImmutableRefBox[index] ?? (_initImmutableRefBox[index] = new InitializeLocalInstruction.ImmutableBox(index, null));
  480. }
  481. return new InitializeLocalInstruction.ImmutableBox(index, null);
  482. }
  483. public void EmitNewRuntimeVariables(int count) {
  484. Emit(new RuntimeVariablesInstruction(count));
  485. }
  486. #endregion
  487. #region Array Operations
  488. public void EmitGetArrayItem(Type arrayType) {
  489. Type elementType = arrayType.GetElementType();
  490. if (elementType.IsClass() || elementType.IsInterface()) {
  491. Emit(InstructionFactory<object>.Factory.GetArrayItem());
  492. } else {
  493. Emit(InstructionFactory.GetFactory(elementType).GetArrayItem());
  494. }
  495. }
  496. public void EmitSetArrayItem(Type arrayType) {
  497. Type elementType = arrayType.GetElementType();
  498. if (elementType.IsClass() || elementType.IsInterface()) {
  499. Emit(InstructionFactory<object>.Factory.SetArrayItem());
  500. } else {
  501. Emit(InstructionFactory.GetFactory(elementType).SetArrayItem());
  502. }
  503. }
  504. public void EmitNewArray(Type elementType) {
  505. Emit(InstructionFactory.GetFactory(elementType).NewArray());
  506. }
  507. public void EmitNewArrayBounds(Type elementType, int rank) {
  508. Emit(new NewArrayBoundsInstruction(elementType, rank));
  509. }
  510. public void EmitNewArrayInit(Type elementType, int elementCount) {
  511. Emit(InstructionFactory.GetFactory(elementType).NewArrayInit(elementCount));
  512. }
  513. #endregion
  514. #region Arithmetic Operations
  515. public void EmitAdd(Type type, bool @checked) {
  516. if (@checked) {
  517. Emit(AddOvfInstruction.Create(type));
  518. } else {
  519. Emit(AddInstruction.Create(type));
  520. }
  521. }
  522. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
  523. public void EmitSub(Type type, bool @checked) {
  524. throw new NotSupportedException();
  525. }
  526. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
  527. public void EmitMul(Type type, bool @checked) {
  528. throw new NotSupportedException();
  529. }
  530. public void EmitDiv(Type type) {
  531. Emit(DivInstruction.Create(type));
  532. }
  533. #endregion
  534. #region Comparisons
  535. public void EmitEqual(Type type) {
  536. Emit(EqualInstruction.Create(type));
  537. }
  538. public void EmitNotEqual(Type type) {
  539. Emit(NotEqualInstruction.Create(type));
  540. }
  541. public void EmitLessThan(Type type) {
  542. Emit(LessThanInstruction.Create(type));
  543. }
  544. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
  545. public void EmitLessThanOrEqual(Type type) {
  546. throw new NotSupportedException();
  547. }
  548. public void EmitGreaterThan(Type type) {
  549. Emit(GreaterThanInstruction.Create(type));
  550. }
  551. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
  552. public void EmitGreaterThanOrEqual(Type type) {
  553. throw new NotSupportedException();
  554. }
  555. #endregion
  556. #region Conversions
  557. public void EmitNumericConvertChecked(TypeCode from, TypeCode to) {
  558. Emit(new NumericConvertInstruction.Checked(from, to));
  559. }
  560. public void EmitNumericConvertUnchecked(TypeCode from, TypeCode to) {
  561. Emit(new NumericConvertInstruction.Unchecked(from, to));
  562. }
  563. #endregion
  564. #region Boolean Operators
  565. public void EmitNot() {
  566. Emit(NotInstruction.Instance);
  567. }
  568. #endregion
  569. #region Types
  570. public void EmitDefaultValue(Type type) {
  571. Emit(InstructionFactory.GetFactory(type).DefaultValue());
  572. }
  573. public void EmitNew(ConstructorInfo constructorInfo) {
  574. Emit(new NewInstruction(constructorInfo));
  575. }
  576. internal void EmitCreateDelegate(LightDelegateCreator creator) {
  577. Emit(new CreateDelegateInstruction(creator));
  578. }
  579. public void EmitTypeEquals() {
  580. Emit(TypeEqualsInstruction.Instance);
  581. }
  582. public void EmitTypeIs(Type type) {
  583. Emit(InstructionFactory.GetFactory(type).TypeIs());
  584. }
  585. public void EmitTypeAs(Type type) {
  586. Emit(InstructionFactory.GetFactory(type).TypeAs());
  587. }
  588. #endregion
  589. #region Fields and Methods
  590. private static readonly Dictionary<FieldInfo, Instruction> _loadFields = new Dictionary<FieldInfo, Instruction>();
  591. public void EmitLoadField(FieldInfo field) {
  592. Emit(GetLoadField(field));
  593. }
  594. private Instruction GetLoadField(FieldInfo field) {
  595. lock (_loadFields) {
  596. Instruction instruction;
  597. if (!_loadFields.TryGetValue(field, out instruction)) {
  598. if (field.IsStatic) {
  599. instruction = new LoadStaticFieldInstruction(field);
  600. } else {
  601. instruction = new LoadFieldInstruction(field);
  602. }
  603. _loadFields.Add(field, instruction);
  604. }
  605. return instruction;
  606. }
  607. }
  608. public void EmitStoreField(FieldInfo field) {
  609. if (field.IsStatic) {
  610. Emit(new StoreStaticFieldInstruction(field));
  611. } else {
  612. Emit(new StoreFieldInstruction(field));
  613. }
  614. }
  615. #endregion
  616. #region Dynamic
  617. public void EmitDynamic(Type type, CallSiteBinder binder) {
  618. Emit(CreateDynamicInstruction(type, binder));
  619. }
  620. #region Generated Dynamic InstructionList Factory
  621. // *** BEGIN GENERATED CODE ***
  622. // generated by function: gen_instructionlist_factory from: generate_dynamic_instructions.py
  623. public void EmitDynamic<T0, TRet>(CallSiteBinder binder) {
  624. Emit(DynamicInstruction<T0, TRet>.Factory(binder));
  625. }
  626. public void EmitDynamic<T0, T1, TRet>(CallSiteBinder binder) {
  627. Emit(DynamicInstruction<T0, T1, TRet>.Factory(binder));
  628. }
  629. public void EmitDynamic<T0, T1, T2, TRet>(CallSiteBinder binder) {
  630. Emit(DynamicInstruction<T0, T1, T2, TRet>.Factory(binder));
  631. }
  632. public void EmitDynamic<T0, T1, T2, T3, TRet>(CallSiteBinder binder) {
  633. Emit(DynamicInstruction<T0, T1, T2, T3, TRet>.Factory(binder));
  634. }
  635. public void EmitDynamic<T0, T1, T2, T3, T4, TRet>(CallSiteBinder binder) {
  636. Emit(DynamicInstruction<T0, T1, T2, T3, T4, TRet>.Factory(binder));
  637. }
  638. public void EmitDynamic<T0, T1, T2, T3, T4, T5, TRet>(CallSiteBinder binder) {
  639. Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, TRet>.Factory(binder));
  640. }
  641. public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, TRet>(CallSiteBinder binder) {
  642. Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, TRet>.Factory(binder));
  643. }
  644. public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, TRet>(CallSiteBinder binder) {
  645. Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, TRet>.Factory(binder));
  646. }
  647. public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>(CallSiteBinder binder) {
  648. Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>.Factory(binder));
  649. }
  650. public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>(CallSiteBinder binder) {
  651. Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>.Factory(binder));
  652. }
  653. public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>(CallSiteBinder binder) {
  654. Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>.Factory(binder));
  655. }
  656. public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>(CallSiteBinder binder) {
  657. Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>.Factory(binder));
  658. }
  659. public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>(CallSiteBinder binder) {
  660. Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>.Factory(binder));
  661. }
  662. public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>(CallSiteBinder binder) {
  663. Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>.Factory(binder));
  664. }
  665. public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>(CallSiteBinder binder) {
  666. Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>.Factory(binder));
  667. }
  668. // *** END GENERATED CODE ***
  669. #endregion
  670. private static Dictionary<Type, Func<CallSiteBinder, Instruction>> _factories =
  671. new Dictionary<Type, Func<CallSiteBinder, Instruction>>();
  672. /// <exception cref="SecurityException">Instruction can't be created due to insufficient privileges.</exception>
  673. internal static Instruction CreateDynamicInstruction(Type delegateType, CallSiteBinder binder) {
  674. Func<CallSiteBinder, Instruction> factory;
  675. lock (_factories) {
  676. if (!_factories.TryGetValue(delegateType, out factory)) {
  677. if (delegateType.GetMethod("Invoke").ReturnType == typeof(void)) {
  678. // TODO: We should generally support void returning binders but the only
  679. // ones that exist are delete index/member who's perf isn't that critical.
  680. return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder), true);
  681. }
  682. Type instructionType = DynamicInstructionN.GetDynamicInstructionType(delegateType);
  683. if (instructionType == null) {
  684. return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder));
  685. }
  686. factory = (Func<CallSiteBinder, Instruction>)instructionType.GetMethod("Factory").CreateDelegate(typeof(Func<CallSiteBinder, Instruction>));
  687. _factories[delegateType] = factory;
  688. }
  689. }
  690. return factory(binder);
  691. }
  692. #endregion
  693. #region Control Flow
  694. private static readonly RuntimeLabel[] EmptyRuntimeLabels = new RuntimeLabel[] { new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0) };
  695. private RuntimeLabel[] BuildRuntimeLabels() {
  696. if (_runtimeLabelCount == 0) {
  697. return EmptyRuntimeLabels;
  698. }
  699. var result = new RuntimeLabel[_runtimeLabelCount + 1];
  700. foreach (BranchLabel label in _labels) {
  701. if (label.HasRuntimeLabel) {
  702. result[label.LabelIndex] = label.ToRuntimeLabel();
  703. }
  704. }
  705. // "return and rethrow" label:
  706. result[result.Length - 1] = new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0);
  707. return result;
  708. }
  709. public BranchLabel MakeLabel() {
  710. if (_labels == null) {
  711. _labels = new List<BranchLabel>();
  712. }
  713. var label = new BranchLabel();
  714. _labels.Add(label);
  715. return label;
  716. }
  717. internal void FixupBranch(int branchIndex, int offset) {
  718. _instructions[branchIndex] = ((OffsetInstruction)_instructions[branchIndex]).Fixup(offset);
  719. }
  720. private int EnsureLabelIndex(BranchLabel label) {
  721. if (label.HasRuntimeLabel) {
  722. return label.LabelIndex;
  723. }
  724. label.LabelIndex = _runtimeLabelCount;
  725. _runtimeLabelCount++;
  726. return label.LabelIndex;
  727. }
  728. public int MarkRuntimeLabel() {
  729. BranchLabel handlerLabel = MakeLabel();
  730. MarkLabel(handlerLabel);
  731. return EnsureLabelIndex(handlerLabel);
  732. }
  733. public void MarkLabel(BranchLabel label) {
  734. label.Mark(this);
  735. }
  736. public void EmitGoto(BranchLabel label, bool hasResult, bool hasValue) {
  737. Emit(GotoInstruction.Create(EnsureLabelIndex(label), hasResult, hasValue));
  738. }
  739. private void EmitBranch(OffsetInstruction instruction, BranchLabel label) {
  740. Emit(instruction);
  741. label.AddBranch(this, Count - 1);
  742. }
  743. public void EmitBranch(BranchLabel label) {
  744. EmitBranch(new BranchInstruction(), label);
  745. }
  746. public void EmitBranch(BranchLabel label, bool hasResult, bool hasValue) {
  747. EmitBranch(new BranchInstruction(hasResult, hasValue), label);
  748. }
  749. public void EmitCoalescingBranch(BranchLabel leftNotNull) {
  750. EmitBranch(new CoalescingBranchInstruction(), leftNotNull);
  751. }
  752. public void EmitBranchTrue(BranchLabel elseLabel) {
  753. EmitBranch(new BranchTrueInstruction(), elseLabel);
  754. }
  755. public void EmitBranchFalse(BranchLabel elseLabel) {
  756. EmitBranch(new BranchFalseInstruction(), elseLabel);
  757. }
  758. public void EmitThrow() {
  759. Emit(ThrowInstruction.Throw);
  760. }
  761. public void EmitThrowVoid() {
  762. Emit(ThrowInstruction.VoidThrow);
  763. }
  764. public void EmitRethrow() {
  765. Emit(ThrowInstruction.Rethrow);
  766. }
  767. public void EmitRethrowVoid() {
  768. Emit(ThrowInstruction.VoidRethrow);
  769. }
  770. public void EmitEnterTryFinally(BranchLabel finallyStartLabel) {
  771. Emit(EnterTryFinallyInstruction.Create(EnsureLabelIndex(finallyStartLabel)));
  772. }
  773. public void EmitEnterFinally() {
  774. Emit(EnterFinallyInstruction.Instance);
  775. }
  776. public void EmitLeaveFinally() {
  777. Emit(LeaveFinallyInstruction.Instance);
  778. }
  779. public void EmitLeaveFault(bool hasValue) {
  780. Emit(hasValue ? LeaveFaultInstruction.NonVoid : LeaveFaultInstruction.Void);
  781. }
  782. public void EmitEnterExceptionHandlerNonVoid() {
  783. Emit(EnterExceptionHandlerInstruction.NonVoid);
  784. }
  785. public void EmitEnterExceptionHandlerVoid() {
  786. Emit(EnterExceptionHandlerInstruction.Void);
  787. }
  788. public void EmitLeaveExceptionHandler(bool hasValue, BranchLabel tryExpressionEndLabel) {
  789. Emit(LeaveExceptionHandlerInstruction.Create(EnsureLabelIndex(tryExpressionEndLabel), hasValue));
  790. }
  791. public void EmitSwitch(Dictionary<int, int> cases) {
  792. Emit(new SwitchInstruction(cases));
  793. }
  794. #endregion
  795. }
  796. }