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