c605977208d005d92a984e14b492ecb275e89fe2
[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 EmitSetArrayItem(Type arrayType) {
605             Type elementType = arrayType.GetElementType();
606             if (elementType.IsClass() || elementType.IsInterface()) {
607                 Emit(InstructionFactory<object>.Factory.SetArrayItem());
608             } else {
609                 Emit(InstructionFactory.GetFactory(elementType).SetArrayItem());
610             }
611         }
612
613         public void EmitNewArray(Type elementType) {
614             Emit(InstructionFactory.GetFactory(elementType).NewArray());
615         }
616
617         public void EmitNewArrayBounds(Type elementType, int rank) {
618             Emit(new NewArrayBoundsInstruction(elementType, rank));
619         }
620
621         public void EmitNewArrayInit(Type elementType, int elementCount) {
622             Emit(InstructionFactory.GetFactory(elementType).NewArrayInit(elementCount));
623         }
624
625         #endregion
626
627         #region Arithmetic Operations
628
629         public void EmitAdd(Type type, bool @checked) {
630             if (@checked) {
631                 Emit(AddOvfInstruction.Create(type));
632             } else {
633                 Emit(AddInstruction.Create(type));
634             }
635         }
636
637         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
638         public void EmitSub(Type type, bool @checked) {
639             throw new NotSupportedException();
640         }
641
642         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
643         public void EmitMul(Type type, bool @checked) {
644             throw new NotSupportedException();
645         }
646
647         public void EmitDiv(Type type) {
648             Emit(DivInstruction.Create(type));
649         }
650
651         #endregion
652
653         #region Comparisons
654
655         public void EmitEqual(Type type) {
656             Emit(EqualInstruction.Create(type));
657         }
658
659         public void EmitNotEqual(Type type) {
660             Emit(NotEqualInstruction.Create(type));
661         }
662
663         public void EmitLessThan(Type type) {
664             Emit(LessThanInstruction.Create(type));
665         }
666
667         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
668         public void EmitLessThanOrEqual(Type type) {
669             throw new NotSupportedException();
670         }
671
672         public void EmitGreaterThan(Type type) {
673             Emit(GreaterThanInstruction.Create(type));
674         }
675
676         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
677         public void EmitGreaterThanOrEqual(Type type) {
678             throw new NotSupportedException();
679         }
680
681         #endregion
682
683         #region Conversions
684
685         public void EmitNumericConvertChecked(TypeCode from, TypeCode to) {
686             Emit(new NumericConvertInstruction.Checked(from, to));
687         }
688
689         public void EmitNumericConvertUnchecked(TypeCode from, TypeCode to) {
690             Emit(new NumericConvertInstruction.Unchecked(from, to));
691         }
692
693         #endregion
694
695         #region Boolean Operators
696
697         public void EmitNot() {
698             Emit(NotInstruction.Instance);
699         }
700
701         #endregion
702
703         #region Types
704
705         public void EmitDefaultValue(Type type) {
706             Emit(InstructionFactory.GetFactory(type).DefaultValue());
707         }
708
709         public void EmitNew(ConstructorInfo constructorInfo) {
710             Emit(new NewInstruction(constructorInfo));
711         }
712
713         internal void EmitCreateDelegate(LightDelegateCreator creator) {
714             Emit(new CreateDelegateInstruction(creator));
715         }
716
717         public void EmitTypeEquals() {
718             Emit(TypeEqualsInstruction.Instance);
719         }
720
721         public void EmitTypeIs(Type type) {
722             Emit(InstructionFactory.GetFactory(type).TypeIs());
723         }
724
725         public void EmitTypeAs(Type type) {
726             Emit(InstructionFactory.GetFactory(type).TypeAs());
727         }
728
729         #endregion
730
731         #region Fields and Methods
732
733         private static readonly Dictionary<FieldInfo, Instruction> _loadFields = new Dictionary<FieldInfo, Instruction>();
734
735         public void EmitLoadField(FieldInfo field) {
736             Emit(GetLoadField(field));
737         }
738
739         private Instruction GetLoadField(FieldInfo field) {
740             lock (_loadFields) {
741                 Instruction instruction;
742                 if (!_loadFields.TryGetValue(field, out instruction)) {
743                     if (field.IsStatic) {
744                         instruction = new LoadStaticFieldInstruction(field);
745                     } else {
746                         instruction = new LoadFieldInstruction(field);
747                     }
748                     _loadFields.Add(field, instruction);
749                 }
750                 return instruction;
751             }
752         }
753         
754         public void EmitStoreField(FieldInfo field) {
755             if (field.IsStatic) {
756                 Emit(new StoreStaticFieldInstruction(field));
757             } else {
758                 Emit(new StoreFieldInstruction(field));
759             }
760         }
761
762         #endregion
763
764         #region Dynamic
765
766         public void EmitDynamic(Type type, CallSiteBinder binder) {
767             Emit(CreateDynamicInstruction(type, binder));
768         }
769
770         #region Generated Dynamic InstructionList Factory
771
772         // *** BEGIN GENERATED CODE ***
773         // generated by function: gen_instructionlist_factory from: generate_dynamic_instructions.py
774
775         public void EmitDynamic<T0, TRet>(CallSiteBinder binder) {
776             Emit(DynamicInstruction<T0, TRet>.Factory(binder));
777         }
778
779         public void EmitDynamic<T0, T1, TRet>(CallSiteBinder binder) {
780             Emit(DynamicInstruction<T0, T1, TRet>.Factory(binder));
781         }
782
783         public void EmitDynamic<T0, T1, T2, TRet>(CallSiteBinder binder) {
784             Emit(DynamicInstruction<T0, T1, T2, TRet>.Factory(binder));
785         }
786
787         public void EmitDynamic<T0, T1, T2, T3, TRet>(CallSiteBinder binder) {
788             Emit(DynamicInstruction<T0, T1, T2, T3, TRet>.Factory(binder));
789         }
790
791         public void EmitDynamic<T0, T1, T2, T3, T4, TRet>(CallSiteBinder binder) {
792             Emit(DynamicInstruction<T0, T1, T2, T3, T4, TRet>.Factory(binder));
793         }
794
795         public void EmitDynamic<T0, T1, T2, T3, T4, T5, TRet>(CallSiteBinder binder) {
796             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, TRet>.Factory(binder));
797         }
798
799         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, TRet>(CallSiteBinder binder) {
800             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, TRet>.Factory(binder));
801         }
802
803         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, TRet>(CallSiteBinder binder) {
804             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, TRet>.Factory(binder));
805         }
806
807         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>(CallSiteBinder binder) {
808             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>.Factory(binder));
809         }
810
811         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>(CallSiteBinder binder) {
812             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>.Factory(binder));
813         }
814
815         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>(CallSiteBinder binder) {
816             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>.Factory(binder));
817         }
818
819         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>(CallSiteBinder binder) {
820             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>.Factory(binder));
821         }
822
823         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>(CallSiteBinder binder) {
824             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>.Factory(binder));
825         }
826
827         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>(CallSiteBinder binder) {
828             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>.Factory(binder));
829         }
830
831         public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>(CallSiteBinder binder) {
832             Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>.Factory(binder));
833         }
834
835
836         // *** END GENERATED CODE ***
837
838         #endregion
839
840         private static Dictionary<Type, Func<CallSiteBinder, Instruction>> _factories =
841             new Dictionary<Type, Func<CallSiteBinder, Instruction>>();
842
843         /// <exception cref="SecurityException">Instruction can't be created due to insufficient privileges.</exception>
844         internal static Instruction CreateDynamicInstruction(Type delegateType, CallSiteBinder binder) {
845             Func<CallSiteBinder, Instruction> factory;
846             lock (_factories) {
847                 if (!_factories.TryGetValue(delegateType, out factory)) {
848                     if (delegateType.GetMethod("Invoke").ReturnType == typeof(void)) {
849                         // TODO: We should generally support void returning binders but the only
850                         // ones that exist are delete index/member who's perf isn't that critical.
851                         return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder), true);
852                     }
853
854                     Type instructionType = DynamicInstructionN.GetDynamicInstructionType(delegateType);
855                     if (instructionType == null) {
856                         return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder));
857                     }
858
859                     factory = (Func<CallSiteBinder, Instruction>)instructionType.GetMethod("Factory").CreateDelegate(typeof(Func<CallSiteBinder, Instruction>));
860                     _factories[delegateType] = factory;
861                 }
862             }
863             return factory(binder);
864         }
865
866         #endregion
867
868         #region Control Flow
869
870         private static readonly RuntimeLabel[] EmptyRuntimeLabels = new RuntimeLabel[] { new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0) };
871
872         private RuntimeLabel[] BuildRuntimeLabels() {
873             if (_runtimeLabelCount == 0) {
874                 return EmptyRuntimeLabels;
875             }
876
877             var result = new RuntimeLabel[_runtimeLabelCount + 1];
878             foreach (BranchLabel label in _labels) {
879                 if (label.HasRuntimeLabel) {
880                     result[label.LabelIndex] = label.ToRuntimeLabel();
881                 }
882             }
883             // "return and rethrow" label:
884             result[result.Length - 1] = new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0);
885             return result;
886         }
887
888         public BranchLabel MakeLabel() {
889             if (_labels == null) {
890                 _labels = new List<BranchLabel>();
891             }
892
893             var label = new BranchLabel();
894             _labels.Add(label);
895             return label;
896         }
897
898         internal void FixupBranch(int branchIndex, int offset) {
899             _instructions[branchIndex] = ((OffsetInstruction)_instructions[branchIndex]).Fixup(offset);
900         }
901
902         private int EnsureLabelIndex(BranchLabel label) {
903             if (label.HasRuntimeLabel) {
904                 return label.LabelIndex;
905             }
906
907             label.LabelIndex = _runtimeLabelCount;
908             _runtimeLabelCount++;
909             return label.LabelIndex;
910         }
911
912         public int MarkRuntimeLabel() {
913             BranchLabel handlerLabel = MakeLabel();
914             MarkLabel(handlerLabel);
915             return EnsureLabelIndex(handlerLabel);
916         }
917
918         public void MarkLabel(BranchLabel label) {
919             label.Mark(this);
920         }
921
922         public void EmitGoto(BranchLabel label, bool hasResult, bool hasValue) {
923             Emit(GotoInstruction.Create(EnsureLabelIndex(label), hasResult, hasValue));
924         }
925
926         private void EmitBranch(OffsetInstruction instruction, BranchLabel label) {
927             Emit(instruction);
928             label.AddBranch(this, Count - 1);
929         }
930
931         public void EmitBranch(BranchLabel label) {
932             EmitBranch(new BranchInstruction(), label);
933         }
934
935         public void EmitBranch(BranchLabel label, bool hasResult, bool hasValue) {
936             EmitBranch(new BranchInstruction(hasResult, hasValue), label);
937         }
938
939         public void EmitCoalescingBranch(BranchLabel leftNotNull) {
940             EmitBranch(new CoalescingBranchInstruction(), leftNotNull);
941         }
942
943         public void EmitBranchTrue(BranchLabel elseLabel) {
944             EmitBranch(new BranchTrueInstruction(), elseLabel);
945         }
946
947         public void EmitBranchFalse(BranchLabel elseLabel) {
948             EmitBranch(new BranchFalseInstruction(), elseLabel);
949         }
950
951         public void EmitThrow() {
952             Emit(ThrowInstruction.Throw);
953         }
954
955         public void EmitThrowVoid() {
956             Emit(ThrowInstruction.VoidThrow);
957         }
958
959         public void EmitRethrow() {
960             Emit(ThrowInstruction.Rethrow);
961         }
962
963         public void EmitRethrowVoid() {
964             Emit(ThrowInstruction.VoidRethrow);
965         }
966
967         public void EmitEnterTryFinally(BranchLabel finallyStartLabel) {
968             Emit(EnterTryFinallyInstruction.Create(EnsureLabelIndex(finallyStartLabel)));
969         }
970
971         public void EmitEnterFinally() {
972             Emit(EnterFinallyInstruction.Instance);
973         }
974
975         public void EmitLeaveFinally() {
976             Emit(LeaveFinallyInstruction.Instance);
977         }
978
979         public void EmitLeaveFault(bool hasValue) {
980             Emit(hasValue ? LeaveFaultInstruction.NonVoid : LeaveFaultInstruction.Void);
981         }
982
983         public void EmitEnterExceptionHandlerNonVoid() {
984             Emit(EnterExceptionHandlerInstruction.NonVoid);
985         }
986
987         public void EmitEnterExceptionHandlerVoid() {
988             Emit(EnterExceptionHandlerInstruction.Void);
989         }
990
991         public void EmitLeaveExceptionHandler(bool hasValue, BranchLabel tryExpressionEndLabel) {
992             Emit(LeaveExceptionHandlerInstruction.Create(EnsureLabelIndex(tryExpressionEndLabel), hasValue));
993         }
994
995         public void EmitSwitch(Dictionary<int, int> cases) {
996             Emit(new SwitchInstruction(cases));
997         }
998
999         #endregion
1000     }
1001 }