PageRenderTime 28ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

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

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