1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.Generic;
6 using System.Collections.ObjectModel;
7 using System.Diagnostics;
8 using System.Dynamic.Utils;
9 using System.Globalization;
10 using System.Reflection;
11 using System.Runtime.CompilerServices;
12 using static System.Linq.Expressions.CachedReflectionInfo;
13 
14 using AstUtils = System.Linq.Expressions.Utils;
15 
16 namespace System.Linq.Expressions.Interpreter
17 {
18     internal sealed class ExceptionFilter
19     {
20         public readonly int LabelIndex;
21         public readonly int StartIndex;
22         public readonly int EndIndex;
23 
ExceptionFilter(int labelIndex, int start, int end)24         internal ExceptionFilter(int labelIndex, int start, int end)
25         {
26             LabelIndex = labelIndex;
27             StartIndex = start;
28             EndIndex = end;
29         }
30     }
31 
32     internal sealed class ExceptionHandler
33     {
34         private readonly Type _exceptionType;
35         public readonly int LabelIndex;
36         public readonly int HandlerStartIndex;
37         public readonly int HandlerEndIndex;
38         public readonly ExceptionFilter Filter;
39 
ExceptionHandler(int labelIndex, int handlerStartIndex, int handlerEndIndex, Type exceptionType, ExceptionFilter filter)40         internal ExceptionHandler(int labelIndex, int handlerStartIndex, int handlerEndIndex, Type exceptionType, ExceptionFilter filter)
41         {
42             Debug.Assert(exceptionType != null);
43             LabelIndex = labelIndex;
44             _exceptionType = exceptionType;
45             HandlerStartIndex = handlerStartIndex;
46             HandlerEndIndex = handlerEndIndex;
47             Filter = filter;
48         }
49 
50         public bool Matches(Type exceptionType) => _exceptionType.IsAssignableFrom(exceptionType);
51 
ToString()52         public override string ToString() =>
53             string.Format(CultureInfo.InvariantCulture, "catch({0}) [{1}->{2}]", _exceptionType.Name, HandlerStartIndex, HandlerEndIndex);
54     }
55 
56     internal sealed class TryCatchFinallyHandler
57     {
58         internal readonly int TryStartIndex;
59         internal readonly int TryEndIndex;
60         internal readonly int FinallyStartIndex;
61         internal readonly int FinallyEndIndex;
62         internal readonly int GotoEndTargetIndex;
63 
64         private readonly ExceptionHandler[] _handlers;
65 
66         internal bool IsFinallyBlockExist
67         {
68             get
69             {
70                 Debug.Assert((FinallyStartIndex != Instruction.UnknownInstrIndex) == (FinallyEndIndex != Instruction.UnknownInstrIndex));
71                 return FinallyStartIndex != Instruction.UnknownInstrIndex;
72             }
73         }
74 
75         internal ExceptionHandler[] Handlers => _handlers;
76 
77         internal bool IsCatchBlockExist => _handlers != null;
78 
79         /// <summary>
80         /// No finally block
81         /// </summary>
TryCatchFinallyHandler(int tryStart, int tryEnd, int gotoEndTargetIndex, ExceptionHandler[] handlers)82         internal TryCatchFinallyHandler(int tryStart, int tryEnd, int gotoEndTargetIndex, ExceptionHandler[] handlers)
83             : this(tryStart, tryEnd, gotoEndTargetIndex, Instruction.UnknownInstrIndex, Instruction.UnknownInstrIndex, handlers)
84         {
85             Debug.Assert(handlers != null, "catch blocks should exist");
86         }
87 
88         /// <summary>
89         /// Generic constructor
90         /// </summary>
TryCatchFinallyHandler(int tryStart, int tryEnd, int gotoEndLabelIndex, int finallyStart, int finallyEnd, ExceptionHandler[] handlers)91         internal TryCatchFinallyHandler(int tryStart, int tryEnd, int gotoEndLabelIndex, int finallyStart, int finallyEnd, ExceptionHandler[] handlers)
92         {
93             TryStartIndex = tryStart;
94             TryEndIndex = tryEnd;
95             FinallyStartIndex = finallyStart;
96             FinallyEndIndex = finallyEnd;
97             GotoEndTargetIndex = gotoEndLabelIndex;
98             _handlers = handlers;
99         }
100 
HasHandler(InterpretedFrame frame, Exception exception, out ExceptionHandler handler, out object unwrappedException)101         internal bool HasHandler(InterpretedFrame frame, Exception exception, out ExceptionHandler handler, out object unwrappedException)
102         {
103 #if DEBUG
104             if (exception is RethrowException)
105             {
106                 // Unreachable.
107                 // Want to assert that this case isn't hit, but an assertion failure here will be eaten because
108                 // we are in an exception filter. Therefore return true here and assert in the catch block.
109                 handler = null;
110                 unwrappedException = exception;
111                 return true;
112             }
113 #endif
114             frame.SaveTraceToException(exception);
115 
116             if (IsCatchBlockExist)
117             {
118                 RuntimeWrappedException rwe = exception as RuntimeWrappedException;
119                 unwrappedException = rwe != null ? rwe.WrappedException : exception;
120                 Type exceptionType = unwrappedException.GetType();
121                 foreach (ExceptionHandler candidate in _handlers)
122                 {
123                     if (candidate.Matches(exceptionType) && (candidate.Filter == null || FilterPasses(frame, ref unwrappedException, candidate.Filter)))
124                     {
125                         handler = candidate;
126                         return true;
127                     }
128                 }
129             }
130             else
131             {
132                 unwrappedException = null;
133             }
134 
135             handler = null;
136             return false;
137         }
138 
FilterPasses(InterpretedFrame frame, ref object exception, ExceptionFilter filter)139         private static bool FilterPasses(InterpretedFrame frame, ref object exception, ExceptionFilter filter)
140         {
141             Interpreter interpreter = frame.Interpreter;
142             Instruction[] instructions = interpreter.Instructions.Instructions;
143             int stackIndex = frame.StackIndex;
144             int frameIndex = frame.InstructionIndex;
145             try
146             {
147                 int index = interpreter._labels[filter.LabelIndex].Index;
148                 frame.InstructionIndex = index;
149                 frame.Push(exception);
150                 while (index >= filter.StartIndex && index < filter.EndIndex)
151                 {
152                     index += instructions[index].Run(frame);
153                     frame.InstructionIndex = index;
154                 }
155 
156                 // Exception is stored in a local at start of the filter, and loaded from it at the end, so it is now
157                 // on the top of the stack. It may have been assigned to in the course of the filter running.
158                 // If this is the handler that will be executed, then if the filter has assigned to the exception variable
159                 // that change should be visible to the handler. Otherwise, it should not, so we write it back only on true.
160                 object exceptionLocal = frame.Pop();
161                 if ((bool)frame.Pop())
162                 {
163                     exception = exceptionLocal;
164                     // Stack and instruction indices will be overwritten in the catch block anyway, so no need to restore.
165                     return true;
166                 }
167             }
168             catch
169             {
170                 // Silently eating exceptions and returning false matches the CLR behavior.
171             }
172 
173             frame.StackIndex = stackIndex;
174             frame.InstructionIndex = frameIndex;
175             return false;
176         }
177     }
178 
179     internal sealed class TryFaultHandler
180     {
181         internal readonly int TryStartIndex;
182         internal readonly int TryEndIndex;
183         internal readonly int FinallyStartIndex;
184         internal readonly int FinallyEndIndex;
185 
TryFaultHandler(int tryStart, int tryEnd, int finallyStart, int finallyEnd)186         internal TryFaultHandler(int tryStart, int tryEnd, int finallyStart, int finallyEnd)
187         {
188             TryStartIndex = tryStart;
189             TryEndIndex = tryEnd;
190             FinallyStartIndex = finallyStart;
191             FinallyEndIndex = finallyEnd;
192         }
193     }
194 
195     /// <summary>
196     /// The re-throw instruction will throw this exception
197     /// </summary>
198     internal sealed class RethrowException : Exception
199     {
200     }
201 
202     internal sealed class DebugInfo
203     {
204         public int StartLine, EndLine;
205         public int Index;
206         public string FileName;
207         public bool IsClear;
208         private static readonly DebugInfoComparer s_debugComparer = new DebugInfoComparer();
209 
210         private class DebugInfoComparer : IComparer<DebugInfo>
211         {
212             //We allow comparison between int and DebugInfo here
Compare(DebugInfo d1, DebugInfo d2)213             int IComparer<DebugInfo>.Compare(DebugInfo d1, DebugInfo d2)
214             {
215                 if (d1.Index > d2.Index) return 1;
216                 else if (d1.Index == d2.Index) return 0;
217                 else return -1;
218             }
219         }
220 
GetMatchingDebugInfo(DebugInfo[] debugInfos, int index)221         public static DebugInfo GetMatchingDebugInfo(DebugInfo[] debugInfos, int index)
222         {
223             //Create a faked DebugInfo to do the search
224             var d = new DebugInfo { Index = index };
225 
226             //to find the closest debug info before the current index
227 
228             int i = Array.BinarySearch<DebugInfo>(debugInfos, d, s_debugComparer);
229             if (i < 0)
230             {
231                 //~i is the index for the first bigger element
232                 //if there is no bigger element, ~i is the length of the array
233                 i = ~i;
234                 if (i == 0)
235                 {
236                     return null;
237                 }
238                 //return the last one that is smaller
239                 i = i - 1;
240             }
241 
242             return debugInfos[i];
243         }
244 
ToString()245         public override string ToString()
246         {
247             if (IsClear)
248             {
249                 return string.Format(CultureInfo.InvariantCulture, "{0}: clear", Index);
250             }
251             else
252             {
253                 return string.Format(CultureInfo.InvariantCulture, "{0}: [{1}-{2}] '{3}'", Index, StartLine, EndLine, FileName);
254             }
255         }
256     }
257 
258     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")]
259     internal readonly struct InterpretedFrameInfo
260     {
261         private readonly string _methodName;
262 
263         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
264         private readonly DebugInfo _debugInfo;
265 
InterpretedFrameInfoSystem.Linq.Expressions.Interpreter.InterpretedFrameInfo266         public InterpretedFrameInfo(string methodName, DebugInfo info)
267         {
268             _methodName = methodName;
269             _debugInfo = info;
270         }
271 
ToStringSystem.Linq.Expressions.Interpreter.InterpretedFrameInfo272         public override string ToString() => _debugInfo != null ? _methodName + ": " + _debugInfo : _methodName;
273     }
274 
275     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
276     internal sealed class LightCompiler
277     {
278         private readonly InstructionList _instructions;
279         private readonly LocalVariables _locals = new LocalVariables();
280 
281         private readonly List<DebugInfo> _debugInfos = new List<DebugInfo>();
282         private readonly HybridReferenceDictionary<LabelTarget, LabelInfo> _treeLabels = new HybridReferenceDictionary<LabelTarget, LabelInfo>();
283         private LabelScopeInfo _labelBlock = new LabelScopeInfo(null, LabelScopeKind.Lambda);
284 
285         private readonly Stack<ParameterExpression> _exceptionForRethrowStack = new Stack<ParameterExpression>();
286 
287         private readonly LightCompiler _parent;
288 
289         private readonly StackGuard _guard = new StackGuard();
290 
291         private static readonly LocalDefinition[] s_emptyLocals = Array.Empty<LocalDefinition>();
292 
LightCompiler()293         public LightCompiler()
294         {
295             _instructions = new InstructionList();
296         }
297 
LightCompiler(LightCompiler parent)298         private LightCompiler(LightCompiler parent)
299             : this()
300         {
301             _parent = parent;
302         }
303 
304         public InstructionList Instructions => _instructions;
305 
CompileTop(LambdaExpression node)306         public LightDelegateCreator CompileTop(LambdaExpression node)
307         {
308             node.ValidateArgumentCount();
309 
310             //Console.WriteLine(node.DebugView);
311             for (int i = 0, n = node.ParameterCount; i < n; i++)
312             {
313                 ParameterExpression p = node.GetParameter(i);
314                 LocalDefinition local = _locals.DefineLocal(p, 0);
315                 _instructions.EmitInitializeParameter(local.Index);
316             }
317 
318             Compile(node.Body);
319 
320             // pop the result of the last expression:
321             if (node.Body.Type != typeof(void) && node.ReturnType == typeof(void))
322             {
323                 _instructions.EmitPop();
324             }
325 
326             Debug.Assert(_instructions.CurrentStackDepth == (node.ReturnType != typeof(void) ? 1 : 0));
327 
328             return new LightDelegateCreator(MakeInterpreter(node.Name), node);
329         }
330 
MakeInterpreter(string lambdaName)331         private Interpreter MakeInterpreter(string lambdaName)
332         {
333             DebugInfo[] debugInfos = _debugInfos.ToArray();
334             foreach (KeyValuePair<LabelTarget, LabelInfo> kvp in _treeLabels)
335             {
336                 kvp.Value.ValidateFinish();
337             }
338             return new Interpreter(lambdaName, _locals, _instructions.ToArray(), debugInfos);
339         }
340 
CompileConstantExpression(Expression expr)341         private void CompileConstantExpression(Expression expr)
342         {
343             var node = (ConstantExpression)expr;
344             _instructions.EmitLoad(node.Value, node.Type);
345         }
346 
CompileDefaultExpression(Expression expr)347         private void CompileDefaultExpression(Expression expr)
348         {
349             CompileDefaultExpression(expr.Type);
350         }
351 
CompileDefaultExpression(Type type)352         private void CompileDefaultExpression(Type type)
353         {
354             if (type != typeof(void))
355             {
356                 if (type.IsNullableOrReferenceType())
357                 {
358                     _instructions.EmitLoad(value: null);
359                 }
360                 else
361                 {
362                     object value = ScriptingRuntimeHelpers.GetPrimitiveDefaultValue(type);
363                     if (value != null)
364                     {
365                         _instructions.EmitLoad(value);
366                     }
367                     else
368                     {
369                         _instructions.EmitDefaultValue(type);
370                     }
371                 }
372             }
373         }
374 
EnsureAvailableForClosure(ParameterExpression expr)375         private LocalVariable EnsureAvailableForClosure(ParameterExpression expr)
376         {
377             LocalVariable local;
378             if (_locals.TryGetLocalOrClosure(expr, out local))
379             {
380                 if (!local.InClosure && !local.IsBoxed)
381                 {
382                     _locals.Box(expr, _instructions);
383                 }
384                 return local;
385             }
386             else if (_parent != null)
387             {
388                 _parent.EnsureAvailableForClosure(expr);
389                 return _locals.AddClosureVariable(expr);
390             }
391             else
392             {
393                 throw new InvalidOperationException("unbound variable: " + expr);
394             }
395         }
396 
ResolveLocal(ParameterExpression variable)397         private LocalVariable ResolveLocal(ParameterExpression variable)
398         {
399             LocalVariable local;
400             if (!_locals.TryGetLocalOrClosure(variable, out local))
401             {
402                 local = EnsureAvailableForClosure(variable);
403             }
404             return local;
405         }
406 
CompileGetVariable(ParameterExpression variable)407         private void CompileGetVariable(ParameterExpression variable)
408         {
409             LoadLocalNoValueTypeCopy(variable);
410 
411             _instructions.SetDebugCookie(variable.Name);
412 
413             EmitCopyValueType(variable.Type);
414         }
415 
EmitCopyValueType(Type valueType)416         private void EmitCopyValueType(Type valueType)
417         {
418             if (MaybeMutableValueType(valueType))
419             {
420                 // loading a value type on the stack has copy semantics unless
421                 // we are specifically loading the address of the object, so we
422                 // emit a copy here if we don't know the type is immutable.
423                 _instructions.Emit(ValueTypeCopyInstruction.Instruction);
424             }
425         }
426 
LoadLocalNoValueTypeCopy(ParameterExpression variable)427         private void LoadLocalNoValueTypeCopy(ParameterExpression variable)
428         {
429             LocalVariable local = ResolveLocal(variable);
430 
431             if (local.InClosure)
432             {
433                 _instructions.EmitLoadLocalFromClosure(local.Index);
434             }
435             else if (local.IsBoxed)
436             {
437                 _instructions.EmitLoadLocalBoxed(local.Index);
438             }
439             else
440             {
441                 _instructions.EmitLoadLocal(local.Index);
442             }
443         }
444 
MaybeMutableValueType(Type type)445         private bool MaybeMutableValueType(Type type)
446         {
447             return type.IsValueType && !type.IsEnum && !type.IsPrimitive;
448         }
449 
CompileGetBoxedVariable(ParameterExpression variable)450         private void CompileGetBoxedVariable(ParameterExpression variable)
451         {
452             LocalVariable local = ResolveLocal(variable);
453 
454             if (local.InClosure)
455             {
456                 _instructions.EmitLoadLocalFromClosureBoxed(local.Index);
457             }
458             else
459             {
460                 Debug.Assert(local.IsBoxed);
461                 _instructions.EmitLoadLocal(local.Index);
462             }
463 
464             _instructions.SetDebugCookie(variable.Name);
465         }
466 
CompileSetVariable(ParameterExpression variable, bool isVoid)467         private void CompileSetVariable(ParameterExpression variable, bool isVoid)
468         {
469             LocalVariable local = ResolveLocal(variable);
470 
471             if (local.InClosure)
472             {
473                 if (isVoid)
474                 {
475                     _instructions.EmitStoreLocalToClosure(local.Index);
476                 }
477                 else
478                 {
479                     _instructions.EmitAssignLocalToClosure(local.Index);
480                 }
481             }
482             else if (local.IsBoxed)
483             {
484                 if (isVoid)
485                 {
486                     _instructions.EmitStoreLocalBoxed(local.Index);
487                 }
488                 else
489                 {
490                     _instructions.EmitAssignLocalBoxed(local.Index);
491                 }
492             }
493             else
494             {
495                 if (isVoid)
496                 {
497                     _instructions.EmitStoreLocal(local.Index);
498                 }
499                 else
500                 {
501                     _instructions.EmitAssignLocal(local.Index);
502                 }
503             }
504 
505             _instructions.SetDebugCookie(variable.Name);
506         }
507 
CompileParameterExpression(Expression expr)508         private void CompileParameterExpression(Expression expr)
509         {
510             var node = (ParameterExpression)expr;
511             CompileGetVariable(node);
512         }
513 
CompileBlockExpression(Expression expr, bool asVoid)514         private void CompileBlockExpression(Expression expr, bool asVoid)
515         {
516             var node = (BlockExpression)expr;
517 
518             if (node.ExpressionCount != 0)
519             {
520                 LocalDefinition[] end = CompileBlockStart(node);
521 
522                 Expression lastExpression = node.Expressions[node.Expressions.Count - 1];
523                 Compile(lastExpression, asVoid);
524                 CompileBlockEnd(end);
525             }
526         }
527 
CompileBlockStart(BlockExpression node)528         private LocalDefinition[] CompileBlockStart(BlockExpression node)
529         {
530             int start = _instructions.Count;
531 
532             LocalDefinition[] locals;
533             ReadOnlyCollection<ParameterExpression> variables = node.Variables;
534             if (variables.Count != 0)
535             {
536                 // TODO: basic flow analysis so we don't have to initialize all
537                 // variables.
538                 locals = new LocalDefinition[variables.Count];
539                 int localCnt = 0;
540                 foreach (ParameterExpression variable in variables)
541                 {
542                     LocalDefinition local = _locals.DefineLocal(variable, start);
543                     locals[localCnt++] = local;
544 
545                     _instructions.EmitInitializeLocal(local.Index, variable.Type);
546                     _instructions.SetDebugCookie(variable.Name);
547                 }
548             }
549             else
550             {
551                 locals = s_emptyLocals;
552             }
553 
554             for (int i = 0; i < node.Expressions.Count - 1; i++)
555             {
556                 CompileAsVoid(node.Expressions[i]);
557             }
558             return locals;
559         }
560 
CompileBlockEnd(LocalDefinition[] locals)561         private void CompileBlockEnd(LocalDefinition[] locals)
562         {
563             foreach (LocalDefinition local in locals)
564             {
565                 _locals.UndefineLocal(local, _instructions.Count);
566             }
567         }
568 
CompileIndexExpression(Expression expr)569         private void CompileIndexExpression(Expression expr)
570         {
571             var index = (IndexExpression)expr;
572 
573             // instance:
574             if (index.Object != null)
575             {
576                 EmitThisForMethodCall(index.Object);
577             }
578 
579             // indexes, byref args not allowed.
580             for (int i = 0, n = index.ArgumentCount; i < n; i++)
581             {
582                 Compile(index.GetArgument(i));
583             }
584 
585             EmitIndexGet(index);
586         }
587 
EmitIndexGet(IndexExpression index)588         private void EmitIndexGet(IndexExpression index)
589         {
590             if (index.Indexer != null)
591             {
592                 _instructions.EmitCall(index.Indexer.GetGetMethod(nonPublic: true));
593             }
594             else if (index.ArgumentCount != 1)
595             {
596                 _instructions.EmitCall(index.Object.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance));
597             }
598             else
599             {
600                 _instructions.EmitGetArrayItem();
601             }
602         }
603 
CompileIndexAssignment(BinaryExpression node, bool asVoid)604         private void CompileIndexAssignment(BinaryExpression node, bool asVoid)
605         {
606             var index = (IndexExpression)node.Left;
607 
608             // instance:
609             if (index.Object != null)
610             {
611                 EmitThisForMethodCall(index.Object);
612             }
613 
614             // indexes, byref args not allowed.
615             for (int i = 0, n = index.ArgumentCount; i < n; i++)
616             {
617                 Compile(index.GetArgument(i));
618             }
619 
620             // value:
621             Compile(node.Right);
622             LocalDefinition local = default(LocalDefinition);
623             if (!asVoid)
624             {
625                 local = _locals.DefineLocal(Expression.Parameter(node.Right.Type), _instructions.Count);
626                 _instructions.EmitAssignLocal(local.Index);
627             }
628 
629             if (index.Indexer != null)
630             {
631                 _instructions.EmitCall(index.Indexer.GetSetMethod(nonPublic: true));
632             }
633             else if (index.ArgumentCount != 1)
634             {
635                 _instructions.EmitCall(index.Object.Type.GetMethod("Set", BindingFlags.Public | BindingFlags.Instance));
636             }
637             else
638             {
639                 _instructions.EmitSetArrayItem();
640             }
641 
642             if (!asVoid)
643             {
644                 _instructions.EmitLoadLocal(local.Index);
645                 _locals.UndefineLocal(local, _instructions.Count);
646             }
647         }
648 
CompileMemberAssignment(BinaryExpression node, bool asVoid)649         private void CompileMemberAssignment(BinaryExpression node, bool asVoid)
650         {
651             var member = (MemberExpression)node.Left;
652             Expression expr = member.Expression;
653             if (expr != null)
654             {
655                 EmitThisForMethodCall(expr);
656             }
657 
658             CompileMemberAssignment(asVoid, member.Member, node.Right, forBinding: false);
659         }
660 
CompileMemberAssignment(bool asVoid, MemberInfo refMember, Expression value, bool forBinding)661         private void CompileMemberAssignment(bool asVoid, MemberInfo refMember, Expression value, bool forBinding)
662         {
663             var pi = refMember as PropertyInfo;
664             if (pi != null)
665             {
666                 MethodInfo method = pi.GetSetMethod(nonPublic: true);
667                 if (forBinding && method.IsStatic)
668                 {
669                     throw Error.InvalidProgram();
670                 }
671 
672                 EmitThisForMethodCall(value);
673 
674                 int start = _instructions.Count;
675                 if (!asVoid)
676                 {
677                     LocalDefinition local = _locals.DefineLocal(Expression.Parameter(value.Type), start);
678                     _instructions.EmitAssignLocal(local.Index);
679                     _instructions.EmitCall(method);
680                     _instructions.EmitLoadLocal(local.Index);
681                     _locals.UndefineLocal(local, _instructions.Count);
682                 }
683                 else
684                 {
685                     _instructions.EmitCall(method);
686                 }
687             }
688             else
689             {
690                 // other types inherited from MemberInfo (EventInfo\MethodBase\Type) cannot be used in MemberAssignment
691                 var fi = (FieldInfo)refMember;
692                 Debug.Assert(fi != null);
693                 if (fi.IsLiteral)
694                 {
695                     throw Error.NotSupported();
696                 }
697 
698                 if (forBinding && fi.IsStatic)
699                 {
700                     _instructions.UnEmit(); // Undo having pushed the instance to the stack.
701                 }
702 
703                 EmitThisForMethodCall(value);
704 
705                 int start = _instructions.Count;
706                 if (!asVoid)
707                 {
708                     LocalDefinition local = _locals.DefineLocal(Expression.Parameter(value.Type), start);
709                     _instructions.EmitAssignLocal(local.Index);
710                     _instructions.EmitStoreField(fi);
711                     _instructions.EmitLoadLocal(local.Index);
712                     _locals.UndefineLocal(local, _instructions.Count);
713                 }
714                 else
715                 {
716                     _instructions.EmitStoreField(fi);
717                 }
718             }
719         }
720 
CompileVariableAssignment(BinaryExpression node, bool asVoid)721         private void CompileVariableAssignment(BinaryExpression node, bool asVoid)
722         {
723             Compile(node.Right);
724 
725             var target = (ParameterExpression)node.Left;
726             CompileSetVariable(target, asVoid);
727         }
728 
CompileAssignBinaryExpression(Expression expr, bool asVoid)729         private void CompileAssignBinaryExpression(Expression expr, bool asVoid)
730         {
731             var node = (BinaryExpression)expr;
732 
733             switch (node.Left.NodeType)
734             {
735                 case ExpressionType.Index:
736                     CompileIndexAssignment(node, asVoid);
737                     break;
738 
739                 case ExpressionType.MemberAccess:
740                     CompileMemberAssignment(node, asVoid);
741                     break;
742 
743                 case ExpressionType.Parameter:
744                 case ExpressionType.Extension:
745                     CompileVariableAssignment(node, asVoid);
746                     break;
747 
748                 default:
749                     throw Error.InvalidLvalue(node.Left.NodeType);
750             }
751         }
752 
CompileBinaryExpression(Expression expr)753         private void CompileBinaryExpression(Expression expr)
754         {
755             var node = (BinaryExpression)expr;
756 
757             if (node.Method != null)
758             {
759                 if (node.IsLifted)
760                 {
761                     // lifting: we need to do the null checks for nullable types and reference types.  If the value
762                     // is null we return null, or false for a comparison unless it's not equal, in which case we return
763                     // true.
764 
765                     // INCOMPAT: The DLR binder short circuits on comparisons other than equal and not equal,
766                     // but C# doesn't.
767                     BranchLabel end = _instructions.MakeLabel();
768 
769                     LocalDefinition leftTemp = _locals.DefineLocal(Expression.Parameter(node.Left.Type), _instructions.Count);
770                     Compile(node.Left);
771                     _instructions.EmitStoreLocal(leftTemp.Index);
772 
773                     LocalDefinition rightTemp = _locals.DefineLocal(Expression.Parameter(node.Right.Type), _instructions.Count);
774                     Compile(node.Right);
775                     _instructions.EmitStoreLocal(rightTemp.Index);
776 
777                     switch (node.NodeType)
778                     {
779                         case ExpressionType.Equal:
780                         case ExpressionType.NotEqual:
781                             /* generating (equal/not equal):
782                                 * if(left == null) {
783                                 *      right == null/right != null
784                                 * }else if(right == null) {
785                                 *      False/True
786                                 * }else{
787                                 *      op_Equality(left, right)/op_Inequality(left, right)
788                                 * }
789                                 */
790                             if (node.IsLiftedToNull)
791                             {
792                                 goto default;
793                             }
794 
795                             BranchLabel testRight = _instructions.MakeLabel();
796                             BranchLabel callMethod = _instructions.MakeLabel();
797 
798                             _instructions.EmitLoadLocal(leftTemp.Index);
799                             _instructions.EmitLoad(null, typeof(object));
800                             _instructions.EmitEqual(typeof(object));
801                             _instructions.EmitBranchFalse(testRight);
802 
803                             // left is null
804                             _instructions.EmitLoadLocal(rightTemp.Index);
805                             _instructions.EmitLoad(null, typeof(object));
806                             if (node.NodeType == ExpressionType.Equal)
807                             {
808                                 _instructions.EmitEqual(typeof(object));
809                             }
810                             else
811                             {
812                                 _instructions.EmitNotEqual(typeof(object));
813                             }
814                             _instructions.EmitBranch(end, hasResult: false, hasValue: true);
815 
816                             _instructions.MarkLabel(testRight);
817 
818                             // left is not null, check right
819                             _instructions.EmitLoadLocal(rightTemp.Index);
820                             _instructions.EmitLoad(null, typeof(object));
821                             _instructions.EmitEqual(typeof(object));
822                             _instructions.EmitBranchFalse(callMethod);
823 
824                             // right null, left not, false
825                             // right null, left not, true
826                             _instructions.EmitLoad(
827                                 node.NodeType == ExpressionType.Equal ? AstUtils.BoxedFalse : AstUtils.BoxedTrue,
828                                 typeof(bool));
829                             _instructions.EmitBranch(end, hasResult: false, hasValue: true);
830 
831                             // both are not null
832                             _instructions.MarkLabel(callMethod);
833                             _instructions.EmitLoadLocal(leftTemp.Index);
834                             _instructions.EmitLoadLocal(rightTemp.Index);
835                             _instructions.EmitCall(node.Method);
836                             break;
837                         default:
838                             BranchLabel loadDefault = _instructions.MakeLabel();
839 
840                             if (node.Left.Type.IsNullableOrReferenceType())
841                             {
842                                 _instructions.EmitLoadLocal(leftTemp.Index);
843                                 _instructions.EmitLoad(null, typeof(object));
844                                 _instructions.EmitEqual(typeof(object));
845                                 _instructions.EmitBranchTrue(loadDefault);
846                             }
847 
848                             if (node.Right.Type.IsNullableOrReferenceType())
849                             {
850                                 _instructions.EmitLoadLocal(rightTemp.Index);
851                                 _instructions.EmitLoad(null, typeof(object));
852                                 _instructions.EmitEqual(typeof(object));
853                                 _instructions.EmitBranchTrue(loadDefault);
854                             }
855 
856                             _instructions.EmitLoadLocal(leftTemp.Index);
857                             _instructions.EmitLoadLocal(rightTemp.Index);
858                             _instructions.EmitCall(node.Method);
859                             _instructions.EmitBranch(end, hasResult: false, hasValue: true);
860 
861                             _instructions.MarkLabel(loadDefault);
862                             switch (node.NodeType)
863                             {
864                                 case ExpressionType.LessThan:
865                                 case ExpressionType.LessThanOrEqual:
866                                 case ExpressionType.GreaterThan:
867                                 case ExpressionType.GreaterThanOrEqual:
868                                     if (node.IsLiftedToNull)
869                                     {
870                                         goto default;
871                                     }
872                                     _instructions.EmitLoad(AstUtils.BoxedFalse, typeof(object));
873                                     break;
874                                 default:
875                                     _instructions.EmitLoad(null, typeof(object));
876                                     break;
877                             }
878                             break;
879                     }
880 
881                     _instructions.MarkLabel(end);
882 
883                     _locals.UndefineLocal(leftTemp, _instructions.Count);
884                     _locals.UndefineLocal(rightTemp, _instructions.Count);
885                 }
886                 else
887                 {
888                     Compile(node.Left);
889                     Compile(node.Right);
890                     _instructions.EmitCall(node.Method);
891                 }
892             }
893             else
894             {
895                 switch (node.NodeType)
896                 {
897                     case ExpressionType.ArrayIndex:
898                         Debug.Assert(node.Right.Type == typeof(int));
899                         Compile(node.Left);
900                         Compile(node.Right);
901                         _instructions.EmitGetArrayItem();
902                         return;
903 
904                     case ExpressionType.Add:
905                     case ExpressionType.AddChecked:
906                     case ExpressionType.Subtract:
907                     case ExpressionType.SubtractChecked:
908                     case ExpressionType.Multiply:
909                     case ExpressionType.MultiplyChecked:
910                     case ExpressionType.Divide:
911                     case ExpressionType.Modulo:
912                         CompileArithmetic(node.NodeType, node.Left, node.Right);
913                         return;
914 
915                     case ExpressionType.ExclusiveOr:
916                         Compile(node.Left);
917                         Compile(node.Right);
918                         _instructions.EmitExclusiveOr(node.Left.Type);
919                         break;
920                     case ExpressionType.Or:
921                         Compile(node.Left);
922                         Compile(node.Right);
923                         _instructions.EmitOr(node.Left.Type);
924                         break;
925                     case ExpressionType.And:
926                         Compile(node.Left);
927                         Compile(node.Right);
928                         _instructions.EmitAnd(node.Left.Type);
929                         break;
930 
931                     case ExpressionType.Equal:
932                         CompileEqual(node.Left, node.Right, node.IsLiftedToNull);
933                         return;
934 
935                     case ExpressionType.NotEqual:
936                         CompileNotEqual(node.Left, node.Right, node.IsLiftedToNull);
937                         return;
938 
939                     case ExpressionType.LessThan:
940                     case ExpressionType.LessThanOrEqual:
941                     case ExpressionType.GreaterThan:
942                     case ExpressionType.GreaterThanOrEqual:
943                         CompileComparison((BinaryExpression)node);
944                         return;
945 
946                     case ExpressionType.LeftShift:
947                         Compile(node.Left);
948                         Compile(node.Right);
949                         _instructions.EmitLeftShift(node.Left.Type);
950                         break;
951                     case ExpressionType.RightShift:
952                         Compile(node.Left);
953                         Compile(node.Right);
954                         _instructions.EmitRightShift(node.Left.Type);
955                         break;
956                     default:
957                         throw new PlatformNotSupportedException(SR.Format(SR.UnsupportedExpressionType, node.NodeType));
958                 }
959             }
960         }
961 
962 #if DEBUG
IsNullComparison(Expression left, Expression right)963         private static bool IsNullComparison(Expression left, Expression right)
964         {
965             return IsNullConstant(left)
966                 ? !IsNullConstant(right) && right.Type.IsNullableType()
967                 : IsNullConstant(right) && left.Type.IsNullableType();
968         }
969 
IsNullConstant(Expression e)970         private static bool IsNullConstant(Expression e)
971         {
972             var c = e as ConstantExpression;
973             return c != null && c.Value == null;
974         }
975 #endif
CompileEqual(Expression left, Expression right, bool liftedToNull)976         private void CompileEqual(Expression left, Expression right, bool liftedToNull)
977         {
978 #if DEBUG
979             Debug.Assert(IsNullComparison(left, right) || left.Type == right.Type || !left.Type.IsValueType && !right.Type.IsValueType);
980 #endif
981             Compile(left);
982             Compile(right);
983             _instructions.EmitEqual(left.Type, liftedToNull);
984         }
985 
CompileNotEqual(Expression left, Expression right, bool liftedToNull)986         private void CompileNotEqual(Expression left, Expression right, bool liftedToNull)
987         {
988 #if DEBUG
989             Debug.Assert(IsNullComparison(left, right) || left.Type == right.Type || !left.Type.IsValueType && !right.Type.IsValueType);
990 #endif
991             Compile(left);
992             Compile(right);
993             _instructions.EmitNotEqual(left.Type, liftedToNull);
994         }
995 
CompileComparison(BinaryExpression node)996         private void CompileComparison(BinaryExpression node)
997         {
998             Expression left = node.Left;
999             Expression right = node.Right;
1000             Debug.Assert(left.Type == right.Type && left.Type.IsNumeric());
1001 
1002             Compile(left);
1003             Compile(right);
1004 
1005             switch (node.NodeType)
1006             {
1007                 case ExpressionType.LessThan: _instructions.EmitLessThan(left.Type, node.IsLiftedToNull); break;
1008                 case ExpressionType.LessThanOrEqual: _instructions.EmitLessThanOrEqual(left.Type, node.IsLiftedToNull); break;
1009                 case ExpressionType.GreaterThan: _instructions.EmitGreaterThan(left.Type, node.IsLiftedToNull); break;
1010                 case ExpressionType.GreaterThanOrEqual: _instructions.EmitGreaterThanOrEqual(left.Type, node.IsLiftedToNull); break;
1011                 default: throw ContractUtils.Unreachable;
1012             }
1013         }
1014 
CompileArithmetic(ExpressionType nodeType, Expression left, Expression right)1015         private void CompileArithmetic(ExpressionType nodeType, Expression left, Expression right)
1016         {
1017             Debug.Assert(left.Type == right.Type && left.Type.IsArithmetic());
1018             Compile(left);
1019             Compile(right);
1020             switch (nodeType)
1021             {
1022                 case ExpressionType.Add: _instructions.EmitAdd(left.Type, @checked: false); break;
1023                 case ExpressionType.AddChecked: _instructions.EmitAdd(left.Type, @checked: true); break;
1024                 case ExpressionType.Subtract: _instructions.EmitSub(left.Type, @checked: false); break;
1025                 case ExpressionType.SubtractChecked: _instructions.EmitSub(left.Type, @checked: true); break;
1026                 case ExpressionType.Multiply: _instructions.EmitMul(left.Type, @checked: false); break;
1027                 case ExpressionType.MultiplyChecked: _instructions.EmitMul(left.Type, @checked: true); break;
1028                 case ExpressionType.Divide: _instructions.EmitDiv(left.Type); break;
1029                 case ExpressionType.Modulo: _instructions.EmitModulo(left.Type); break;
1030                 default: throw ContractUtils.Unreachable;
1031             }
1032         }
1033 
CompileConvertUnaryExpression(Expression expr)1034         private void CompileConvertUnaryExpression(Expression expr)
1035         {
1036             var node = (UnaryExpression)expr;
1037             if (node.Method != null)
1038             {
1039                 BranchLabel end = _instructions.MakeLabel();
1040                 BranchLabel loadDefault = _instructions.MakeLabel();
1041                 MethodInfo method = node.Method;
1042                 ParameterInfo[] parameters = method.GetParametersCached();
1043                 Debug.Assert(parameters.Length == 1);
1044                 ParameterInfo parameter = parameters[0];
1045                 Expression operand = node.Operand;
1046                 Type operandType = operand.Type;
1047                 LocalDefinition opTemp = _locals.DefineLocal(Expression.Parameter(operandType), _instructions.Count);
1048                 ByRefUpdater updater = null;
1049                 Type parameterType = parameter.ParameterType;
1050                 if (parameterType.IsByRef)
1051                 {
1052                     if (node.IsLifted)
1053                     {
1054                         Compile(node.Operand);
1055                     }
1056                     else
1057                     {
1058                         updater = CompileAddress(node.Operand, 0);
1059                         parameterType = parameterType.GetElementType();
1060                     }
1061                 }
1062                 else
1063                 {
1064                     Compile(node.Operand);
1065                 }
1066 
1067                 _instructions.EmitStoreLocal(opTemp.Index);
1068 
1069                 if (!operandType.IsValueType || operandType.IsNullableType() && node.IsLiftedToNull)
1070                 {
1071                     _instructions.EmitLoadLocal(opTemp.Index);
1072                     _instructions.EmitLoad(null, typeof(object));
1073                     _instructions.EmitEqual(typeof(object));
1074                     _instructions.EmitBranchTrue(loadDefault);
1075                 }
1076 
1077                 _instructions.EmitLoadLocal(opTemp.Index);
1078                 if (operandType.IsNullableType() && parameterType.Equals(operandType.GetNonNullableType()))
1079                 {
1080                     _instructions.Emit(NullableMethodCallInstruction.CreateGetValue());
1081                 }
1082 
1083                 if (updater == null)
1084                 {
1085                     _instructions.EmitCall(method);
1086                 }
1087                 else
1088                 {
1089                     _instructions.EmitByRefCall(method, parameters, new[] {updater});
1090                     updater.UndefineTemps(_instructions, _locals);
1091                 }
1092 
1093                 _instructions.EmitBranch(end, hasResult: false, hasValue: true);
1094 
1095                 _instructions.MarkLabel(loadDefault);
1096                 _instructions.EmitLoad(null, typeof(object));
1097 
1098                 _instructions.MarkLabel(end);
1099 
1100                 _locals.UndefineLocal(opTemp, _instructions.Count);
1101             }
1102             else if (node.Type == typeof(void))
1103             {
1104                 CompileAsVoid(node.Operand);
1105             }
1106             else
1107             {
1108                 Compile(node.Operand);
1109                 CompileConvertToType(node.Operand.Type, node.Type, node.NodeType == ExpressionType.ConvertChecked, node.IsLiftedToNull);
1110             }
1111         }
1112 
CompileConvertToType(Type typeFrom, Type typeTo, bool isChecked, bool isLiftedToNull)1113         private void CompileConvertToType(Type typeFrom, Type typeTo, bool isChecked, bool isLiftedToNull)
1114         {
1115             Debug.Assert(typeFrom != typeof(void) && typeTo != typeof(void));
1116 
1117             if (typeTo.Equals(typeFrom))
1118             {
1119                 return;
1120             }
1121 
1122             if (typeFrom.IsValueType &&
1123                 typeTo.IsNullableType() &&
1124                 typeTo.GetNonNullableType().Equals(typeFrom))
1125             {
1126                 // VT -> vt?, no conversion necessary
1127                 return;
1128             }
1129 
1130             if (typeTo.IsValueType &&
1131                 typeFrom.IsNullableType() &&
1132                 typeFrom.GetNonNullableType().Equals(typeTo))
1133             {
1134                 // VT? -> vt, call get_Value
1135                 _instructions.Emit(NullableMethodCallInstruction.CreateGetValue());
1136                 return;
1137             }
1138 
1139             Type nonNullableFrom = typeFrom.GetNonNullableType();
1140             Type nonNullableTo = typeTo.GetNonNullableType();
1141 
1142             // use numeric conversions for both numeric types and enums
1143             if ((nonNullableFrom.IsNumericOrBool() || nonNullableFrom.IsEnum)
1144                  && (nonNullableTo.IsNumericOrBool() || nonNullableTo.IsEnum || nonNullableTo == typeof(decimal)))
1145             {
1146                 Type enumTypeTo = null;
1147 
1148                 if (nonNullableFrom.IsEnum)
1149                 {
1150                     nonNullableFrom = Enum.GetUnderlyingType(nonNullableFrom);
1151                 }
1152                 if (nonNullableTo.IsEnum)
1153                 {
1154                     enumTypeTo = nonNullableTo;
1155                     nonNullableTo = Enum.GetUnderlyingType(nonNullableTo);
1156                 }
1157 
1158                 TypeCode from = nonNullableFrom.GetTypeCode();
1159                 TypeCode to = nonNullableTo.GetTypeCode();
1160 
1161                 if (from == to)
1162                 {
1163                     if ((object)enumTypeTo != null)
1164                     {
1165                         // If casting between enums of the same underlying type or to enum from the underlying
1166                         // type, there's no need for the numeric conversion, so just include a null-check if
1167                         // appropriate.
1168                         if (typeFrom.IsNullableType() && !typeTo.IsNullableType())
1169                         {
1170                             _instructions.Emit(NullableMethodCallInstruction.CreateGetValue());
1171                         }
1172                     }
1173                     else
1174                     {
1175                         // Casting to the underlying check still needs a numeric conversion to force the type
1176                         // change that EmitCastToEnum provides for enums, but needs only one cast. Checked can
1177                         // also never throw, so always be unchecked.
1178                         _instructions.EmitConvertToUnderlying(to, isLiftedToNull);
1179                     }
1180                 }
1181                 else
1182                 {
1183                     if (isChecked)
1184                     {
1185                         _instructions.EmitNumericConvertChecked(from, to, isLiftedToNull);
1186                     }
1187                     else
1188                     {
1189                         _instructions.EmitNumericConvertUnchecked(from, to, isLiftedToNull);
1190                     }
1191                 }
1192 
1193                 if ((object)enumTypeTo != null)
1194                 {
1195                     // Convert from underlying to the enum
1196                     _instructions.EmitCastToEnum(enumTypeTo);
1197                 }
1198 
1199                 return;
1200             }
1201 
1202             if (typeTo.IsEnum)
1203             {
1204                 _instructions.Emit(NullCheckInstruction.Instance);
1205                 _instructions.EmitCastReferenceToEnum(typeTo);
1206                 return;
1207             }
1208 
1209             if (typeTo == typeof(object) || typeTo.IsAssignableFrom(typeFrom))
1210             {
1211                 // Conversions to a super-class or implemented interfaces are no-op.
1212                 return;
1213             }
1214 
1215             // A conversion to a non-implemented interface or an unrelated class, etc. should fail.
1216             _instructions.EmitCast(typeTo);
1217         }
1218 
CompileNotExpression(UnaryExpression node)1219         private void CompileNotExpression(UnaryExpression node)
1220         {
1221             Compile(node.Operand);
1222             _instructions.EmitNot(node.Operand.Type);
1223         }
1224 
CompileUnaryExpression(Expression expr)1225         private void CompileUnaryExpression(Expression expr)
1226         {
1227             var node = (UnaryExpression)expr;
1228 
1229             if (node.Method != null)
1230             {
1231                 EmitUnaryMethodCall(node);
1232             }
1233             else
1234             {
1235                 switch (node.NodeType)
1236                 {
1237                     case ExpressionType.Not:
1238                     case ExpressionType.OnesComplement:
1239                         CompileNotExpression(node);
1240                         break;
1241                     case ExpressionType.TypeAs:
1242                         CompileTypeAsExpression(node);
1243                         break;
1244                     case ExpressionType.ArrayLength:
1245                         Compile(node.Operand);
1246                         _instructions.EmitArrayLength();
1247                         break;
1248                     case ExpressionType.NegateChecked:
1249                         Compile(node.Operand);
1250                         _instructions.EmitNegateChecked(node.Type);
1251                         break;
1252                     case ExpressionType.Negate:
1253                         Compile(node.Operand);
1254                         _instructions.EmitNegate(node.Type);
1255                         break;
1256                     case ExpressionType.Increment:
1257                         Compile(node.Operand);
1258                         _instructions.EmitIncrement(node.Type);
1259                         break;
1260                     case ExpressionType.Decrement:
1261                         Compile(node.Operand);
1262                         _instructions.EmitDecrement(node.Type);
1263                         break;
1264                     case ExpressionType.UnaryPlus:
1265                         Compile(node.Operand);
1266                         break;
1267                     case ExpressionType.IsTrue:
1268                     case ExpressionType.IsFalse:
1269                         EmitUnaryBoolCheck(node);
1270                         break;
1271                     default:
1272                         throw new PlatformNotSupportedException(SR.Format(SR.UnsupportedExpressionType, node.NodeType));
1273                 }
1274             }
1275         }
1276 
EmitUnaryMethodCall(UnaryExpression node)1277         private void EmitUnaryMethodCall(UnaryExpression node)
1278         {
1279             Compile(node.Operand);
1280             if (node.IsLifted)
1281             {
1282                 BranchLabel notNull = _instructions.MakeLabel();
1283                 BranchLabel computed = _instructions.MakeLabel();
1284 
1285                 _instructions.EmitCoalescingBranch(notNull);
1286                 _instructions.EmitBranch(computed);
1287 
1288                 _instructions.MarkLabel(notNull);
1289                 _instructions.EmitCall(node.Method);
1290 
1291                 _instructions.MarkLabel(computed);
1292             }
1293             else
1294             {
1295                 _instructions.EmitCall(node.Method);
1296             }
1297         }
1298 
EmitUnaryBoolCheck(UnaryExpression node)1299         private void EmitUnaryBoolCheck(UnaryExpression node)
1300         {
1301             Compile(node.Operand);
1302             if (node.IsLifted)
1303             {
1304                 BranchLabel notNull = _instructions.MakeLabel();
1305                 BranchLabel computed = _instructions.MakeLabel();
1306 
1307                 _instructions.EmitCoalescingBranch(notNull);
1308                 _instructions.EmitBranch(computed);
1309 
1310                 _instructions.MarkLabel(notNull);
1311                 _instructions.EmitLoad(node.NodeType == ExpressionType.IsTrue);
1312                 _instructions.EmitEqual(typeof(bool));
1313 
1314                 _instructions.MarkLabel(computed);
1315             }
1316             else
1317             {
1318                 _instructions.EmitLoad(node.NodeType == ExpressionType.IsTrue);
1319                 _instructions.EmitEqual(typeof(bool));
1320             }
1321         }
1322 
CompileAndAlsoBinaryExpression(Expression expr)1323         private void CompileAndAlsoBinaryExpression(Expression expr)
1324         {
1325             CompileLogicalBinaryExpression((BinaryExpression)expr, andAlso: true);
1326         }
1327 
CompileOrElseBinaryExpression(Expression expr)1328         private void CompileOrElseBinaryExpression(Expression expr)
1329         {
1330             CompileLogicalBinaryExpression((BinaryExpression)expr, andAlso: false);
1331         }
1332 
CompileLogicalBinaryExpression(BinaryExpression b, bool andAlso)1333         private void CompileLogicalBinaryExpression(BinaryExpression b, bool andAlso)
1334         {
1335             if (b.Method != null && !b.IsLiftedLogical)
1336             {
1337                 CompileMethodLogicalBinaryExpression(b, andAlso);
1338             }
1339             else if (b.Left.Type == typeof(bool?))
1340             {
1341                 CompileLiftedLogicalBinaryExpression(b, andAlso);
1342             }
1343             else if (b.IsLiftedLogical)
1344             {
1345                 Compile(b.ReduceUserdefinedLifted());
1346             }
1347             else
1348             {
1349                 CompileUnliftedLogicalBinaryExpression(b, andAlso);
1350             }
1351         }
1352 
CompileMethodLogicalBinaryExpression(BinaryExpression expr, bool andAlso)1353         private void CompileMethodLogicalBinaryExpression(BinaryExpression expr, bool andAlso)
1354         {
1355             BranchLabel labEnd = _instructions.MakeLabel();
1356             Compile(expr.Left);
1357             _instructions.EmitDup();
1358 
1359             MethodInfo opTrue = TypeUtils.GetBooleanOperator(expr.Method.DeclaringType, andAlso ? "op_False" : "op_True");
1360             Debug.Assert(opTrue != null, "factory should check that the method exists");
1361             _instructions.EmitCall(opTrue);
1362             _instructions.EmitBranchTrue(labEnd);
1363 
1364             Compile(expr.Right);
1365 
1366             Debug.Assert(expr.Method.IsStatic);
1367             _instructions.EmitCall(expr.Method);
1368 
1369             _instructions.MarkLabel(labEnd);
1370         }
1371 
CompileLiftedLogicalBinaryExpression(BinaryExpression node, bool andAlso)1372         private void CompileLiftedLogicalBinaryExpression(BinaryExpression node, bool andAlso)
1373         {
1374             BranchLabel computeRight = _instructions.MakeLabel();
1375             BranchLabel returnFalse = _instructions.MakeLabel();
1376             BranchLabel returnNull = _instructions.MakeLabel();
1377             BranchLabel returnValue = _instructions.MakeLabel();
1378             LocalDefinition result = _locals.DefineLocal(Expression.Parameter(node.Left.Type), _instructions.Count);
1379             LocalDefinition leftTemp = _locals.DefineLocal(Expression.Parameter(node.Left.Type), _instructions.Count);
1380 
1381             Compile(node.Left);
1382             _instructions.EmitStoreLocal(leftTemp.Index);
1383 
1384             _instructions.EmitLoadLocal(leftTemp.Index);
1385             _instructions.EmitLoad(null, typeof(object));
1386             _instructions.EmitEqual(typeof(object));
1387 
1388             _instructions.EmitBranchTrue(computeRight);
1389 
1390             _instructions.EmitLoadLocal(leftTemp.Index);
1391 
1392             if (andAlso)
1393             {
1394                 _instructions.EmitBranchFalse(returnFalse);
1395             }
1396             else
1397             {
1398                 _instructions.EmitBranchTrue(returnFalse);
1399             }
1400 
1401             // compute right
1402             _instructions.MarkLabel(computeRight);
1403             LocalDefinition rightTemp = _locals.DefineLocal(Expression.Parameter(node.Right.Type), _instructions.Count);
1404             Compile(node.Right);
1405             _instructions.EmitStoreLocal(rightTemp.Index);
1406 
1407             _instructions.EmitLoadLocal(rightTemp.Index);
1408             _instructions.EmitLoad(null, typeof(object));
1409             _instructions.EmitEqual(typeof(object));
1410             _instructions.EmitBranchTrue(returnNull);
1411 
1412             _instructions.EmitLoadLocal(rightTemp.Index);
1413             if (andAlso)
1414             {
1415                 _instructions.EmitBranchFalse(returnFalse);
1416             }
1417             else
1418             {
1419                 _instructions.EmitBranchTrue(returnFalse);
1420             }
1421 
1422             // check left for null again
1423             _instructions.EmitLoadLocal(leftTemp.Index);
1424             _instructions.EmitLoad(null, typeof(object));
1425             _instructions.EmitEqual(typeof(object));
1426             _instructions.EmitBranchTrue(returnNull);
1427 
1428             // return true
1429             _instructions.EmitLoad(andAlso ? AstUtils.BoxedTrue : AstUtils.BoxedFalse, typeof(object));
1430             _instructions.EmitStoreLocal(result.Index);
1431             _instructions.EmitBranch(returnValue);
1432 
1433             // return false
1434             _instructions.MarkLabel(returnFalse);
1435             _instructions.EmitLoad(andAlso ? AstUtils.BoxedFalse : AstUtils.BoxedTrue, typeof(object));
1436             _instructions.EmitStoreLocal(result.Index);
1437             _instructions.EmitBranch(returnValue);
1438 
1439             // return null
1440             _instructions.MarkLabel(returnNull);
1441             _instructions.EmitLoad(null, typeof(object));
1442             _instructions.EmitStoreLocal(result.Index);
1443 
1444             _instructions.MarkLabel(returnValue);
1445             _instructions.EmitLoadLocal(result.Index);
1446 
1447             _locals.UndefineLocal(leftTemp, _instructions.Count);
1448             _locals.UndefineLocal(rightTemp, _instructions.Count);
1449             _locals.UndefineLocal(result, _instructions.Count);
1450         }
1451 
CompileUnliftedLogicalBinaryExpression(BinaryExpression expr, bool andAlso)1452         private void CompileUnliftedLogicalBinaryExpression(BinaryExpression expr, bool andAlso)
1453         {
1454             BranchLabel elseLabel = _instructions.MakeLabel();
1455             BranchLabel endLabel = _instructions.MakeLabel();
1456             Compile(expr.Left);
1457 
1458             if (andAlso)
1459             {
1460                 _instructions.EmitBranchFalse(elseLabel);
1461             }
1462             else
1463             {
1464                 _instructions.EmitBranchTrue(elseLabel);
1465             }
1466             Compile(expr.Right);
1467             _instructions.EmitBranch(endLabel, hasResult: false, hasValue: true);
1468             _instructions.MarkLabel(elseLabel);
1469             _instructions.EmitLoad(!andAlso);
1470             _instructions.MarkLabel(endLabel);
1471         }
1472 
CompileConditionalExpression(Expression expr, bool asVoid)1473         private void CompileConditionalExpression(Expression expr, bool asVoid)
1474         {
1475             var node = (ConditionalExpression)expr;
1476             Compile(node.Test);
1477 
1478             if (node.IfTrue == AstUtils.Empty)
1479             {
1480                 BranchLabel endOfFalse = _instructions.MakeLabel();
1481                 _instructions.EmitBranchTrue(endOfFalse);
1482                 Compile(node.IfFalse, asVoid);
1483                 _instructions.MarkLabel(endOfFalse);
1484             }
1485             else
1486             {
1487                 BranchLabel endOfTrue = _instructions.MakeLabel();
1488                 _instructions.EmitBranchFalse(endOfTrue);
1489                 Compile(node.IfTrue, asVoid);
1490 
1491                 if (node.IfFalse != AstUtils.Empty)
1492                 {
1493                     BranchLabel endOfFalse = _instructions.MakeLabel();
1494                     _instructions.EmitBranch(endOfFalse, false, !asVoid);
1495                     _instructions.MarkLabel(endOfTrue);
1496                     Compile(node.IfFalse, asVoid);
1497                     _instructions.MarkLabel(endOfFalse);
1498                 }
1499                 else
1500                 {
1501                     _instructions.MarkLabel(endOfTrue);
1502                 }
1503             }
1504         }
1505 
CompileLoopExpression(Expression expr)1506         private void CompileLoopExpression(Expression expr)
1507         {
1508             var node = (LoopExpression)expr;
1509 
1510             PushLabelBlock(LabelScopeKind.Statement);
1511             LabelInfo breakLabel = DefineLabel(node.BreakLabel);
1512             LabelInfo continueLabel = DefineLabel(node.ContinueLabel);
1513 
1514             _instructions.MarkLabel(continueLabel.GetLabel(this));
1515 
1516             // emit loop body:
1517             CompileAsVoid(node.Body);
1518 
1519             // emit loop branch:
1520             _instructions.EmitBranch(continueLabel.GetLabel(this), node.Type != typeof(void), hasValue: false);
1521 
1522             _instructions.MarkLabel(breakLabel.GetLabel(this));
1523 
1524             PopLabelBlock(LabelScopeKind.Statement);
1525         }
1526 
CompileSwitchExpression(Expression expr)1527         private void CompileSwitchExpression(Expression expr)
1528         {
1529             var node = (SwitchExpression)expr;
1530 
1531             if (node.Cases.All(c => c.TestValues.All(t => t is ConstantExpression)))
1532             {
1533                 if (node.Cases.Count == 0)
1534                 {
1535                     // Emit the switch value in case it has side-effects, but as void
1536                     // since the value is ignored.
1537                     CompileAsVoid(node.SwitchValue);
1538 
1539                     // Now if there is a default body, it happens unconditionally.
1540                     if (node.DefaultBody != null)
1541                     {
1542                         Compile(node.DefaultBody);
1543                     }
1544                     else
1545                     {
1546                         // If there are no cases and no default then the type must be void.
1547                         // Assert that earlier validation caught any exceptions to that.
1548                         Debug.Assert(node.Type == typeof(void));
1549                     }
1550                     return;
1551                 }
1552 
1553                 TypeCode switchType = node.SwitchValue.Type.GetTypeCode();
1554 
1555                 if (node.Comparison == null)
1556                 {
1557                     switch (switchType)
1558                     {
1559                         case TypeCode.Int32:
1560                             CompileIntSwitchExpression<int>(node);
1561                             return;
1562 
1563                         // the following cases are uncommon,
1564                         // so to avoid numerous unnecessary generic
1565                         // instantiations of Dictionary<K, V> and related types
1566                         // in AOT scenarios, we will just use "object" as the key
1567                         // NOTE: this does not actually result in any
1568                         //       extra boxing since both keys and values
1569                         //       are already boxed when we get them
1570                         case TypeCode.Byte:
1571                         case TypeCode.SByte:
1572                         case TypeCode.UInt16:
1573                         case TypeCode.Int16:
1574                         case TypeCode.UInt32:
1575                         case TypeCode.UInt64:
1576                         case TypeCode.Int64:
1577                             CompileIntSwitchExpression<object>(node);
1578                             return;
1579                     }
1580                 }
1581 
1582                 if (switchType == TypeCode.String)
1583                 {
1584                     // If we have a comparison other than string equality, bail
1585                     MethodInfo equality = String_op_Equality_String_String;
1586                     if (equality != null && !equality.IsStatic)
1587                     {
1588                         equality = null;
1589                     }
1590 
1591                     if (object.Equals(node.Comparison, equality))
1592                     {
1593                         CompileStringSwitchExpression(node);
1594                         return;
1595                     }
1596                 }
1597             }
1598 
1599             LocalDefinition temp = _locals.DefineLocal(Expression.Parameter(node.SwitchValue.Type), _instructions.Count);
1600             Compile(node.SwitchValue);
1601             _instructions.EmitStoreLocal(temp.Index);
1602 
1603             LabelTarget doneLabel = Expression.Label(node.Type, "done");
1604 
1605             foreach (SwitchCase @case in node.Cases)
1606             {
1607                 foreach (Expression val in @case.TestValues)
1608                 {
1609                     //  temp == val ?
1610                     //          goto(Body) doneLabel:
1611                     //          {};
1612                     CompileConditionalExpression(
1613                         Expression.Condition(
1614                             Expression.Equal(temp.Parameter, val, false, node.Comparison),
1615                             Expression.Goto(doneLabel, @case.Body),
1616                             AstUtils.Empty
1617                         ),
1618                         asVoid: true);
1619                 }
1620             }
1621 
1622             // doneLabel(DefaultBody):
1623             CompileLabelExpression(Expression.Label(doneLabel, node.DefaultBody));
1624 
1625             _locals.UndefineLocal(temp, _instructions.Count);
1626         }
1627 
CompileIntSwitchExpression(SwitchExpression node)1628         private void CompileIntSwitchExpression<T>(SwitchExpression node)
1629         {
1630             LabelInfo end = DefineLabel(node: null);
1631             bool hasValue = node.Type != typeof(void);
1632 
1633             Compile(node.SwitchValue);
1634             var caseDict = new Dictionary<T, int>();
1635             int switchIndex = _instructions.Count;
1636             _instructions.EmitIntSwitch(caseDict);
1637 
1638             if (node.DefaultBody != null)
1639             {
1640                 Compile(node.DefaultBody, !hasValue);
1641             }
1642             else
1643             {
1644                 Debug.Assert(!hasValue);
1645             }
1646             _instructions.EmitBranch(end.GetLabel(this), false, hasValue);
1647 
1648             for (int i = 0; i < node.Cases.Count; i++)
1649             {
1650                 SwitchCase switchCase = node.Cases[i];
1651 
1652                 int caseOffset = _instructions.Count - switchIndex;
1653                 foreach (ConstantExpression testValue in switchCase.TestValues)
1654                 {
1655                     var key = (T)testValue.Value;
1656                     caseDict.TryAdd(key, caseOffset);
1657                 }
1658 
1659                 Compile(switchCase.Body, !hasValue);
1660 
1661                 if (i < node.Cases.Count - 1)
1662                 {
1663                     _instructions.EmitBranch(end.GetLabel(this), false, hasValue);
1664                 }
1665             }
1666 
1667             _instructions.MarkLabel(end.GetLabel(this));
1668         }
1669 
CompileStringSwitchExpression(SwitchExpression node)1670         private void CompileStringSwitchExpression(SwitchExpression node)
1671         {
1672             LabelInfo end = DefineLabel(node: null);
1673             bool hasValue = node.Type != typeof(void);
1674 
1675             Compile(node.SwitchValue);
1676             var caseDict = new Dictionary<string, int>();
1677             int switchIndex = _instructions.Count;
1678             // by default same as default
1679             var nullCase = new StrongBox<int>(1);
1680             _instructions.EmitStringSwitch(caseDict, nullCase);
1681 
1682             if (node.DefaultBody != null)
1683             {
1684                 Compile(node.DefaultBody, !hasValue);
1685             }
1686             else
1687             {
1688                 Debug.Assert(!hasValue);
1689             }
1690             _instructions.EmitBranch(end.GetLabel(this), false, hasValue);
1691 
1692             for (int i = 0; i < node.Cases.Count; i++)
1693             {
1694                 SwitchCase switchCase = node.Cases[i];
1695 
1696                 int caseOffset = _instructions.Count - switchIndex;
1697                 foreach (ConstantExpression testValue in switchCase.TestValues)
1698                 {
1699                     var key = (string)testValue.Value;
1700                     if (key == null)
1701                     {
1702                         if (nullCase.Value == 1)
1703                         {
1704                             nullCase.Value = caseOffset;
1705                         }
1706                     }
1707                     else
1708                     {
1709                         caseDict.TryAdd(key, caseOffset);
1710                     }
1711                 }
1712 
1713                 Compile(switchCase.Body, !hasValue);
1714 
1715                 if (i < node.Cases.Count - 1)
1716                 {
1717                     _instructions.EmitBranch(end.GetLabel(this), false, hasValue);
1718                 }
1719             }
1720 
1721             _instructions.MarkLabel(end.GetLabel(this));
1722         }
1723 
CompileLabelExpression(Expression expr)1724         private void CompileLabelExpression(Expression expr)
1725         {
1726             var node = (LabelExpression)expr;
1727 
1728             // If we're an immediate child of a block, our label will already
1729             // be defined. If not, we need to define our own block so this
1730             // label isn't exposed except to its own child expression.
1731             LabelInfo label = null;
1732 
1733             if (_labelBlock.Kind == LabelScopeKind.Block)
1734             {
1735                 _labelBlock.TryGetLabelInfo(node.Target, out label);
1736 
1737                 // We're in a block but didn't find our label, try switch
1738                 if (label == null && _labelBlock.Parent.Kind == LabelScopeKind.Switch)
1739                 {
1740                     _labelBlock.Parent.TryGetLabelInfo(node.Target, out label);
1741                 }
1742 
1743                 // if we're in a switch or block, we should've found the label
1744                 Debug.Assert(label != null);
1745             }
1746 
1747             if (label == null)
1748             {
1749                 label = DefineLabel(node.Target);
1750             }
1751 
1752             if (node.DefaultValue != null)
1753             {
1754                 if (node.Target.Type == typeof(void))
1755                 {
1756                     CompileAsVoid(node.DefaultValue);
1757                 }
1758                 else
1759                 {
1760                     Compile(node.DefaultValue);
1761                 }
1762             }
1763 
1764             _instructions.MarkLabel(label.GetLabel(this));
1765         }
1766 
CompileGotoExpression(Expression expr)1767         private void CompileGotoExpression(Expression expr)
1768         {
1769             var node = (GotoExpression)expr;
1770             LabelInfo labelInfo = ReferenceLabel(node.Target);
1771 
1772             if (node.Value != null)
1773             {
1774                 Compile(node.Value);
1775             }
1776 
1777             _instructions.EmitGoto(labelInfo.GetLabel(this),
1778                 node.Type != typeof(void),
1779                 node.Value != null && node.Value.Type != typeof(void),
1780                 node.Target.Type != typeof(void));
1781         }
1782 
PushLabelBlock(LabelScopeKind type)1783         private void PushLabelBlock(LabelScopeKind type)
1784         {
1785             _labelBlock = new LabelScopeInfo(_labelBlock, type);
1786         }
1787 
1788         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "kind")]
PopLabelBlock(LabelScopeKind kind)1789         private void PopLabelBlock(LabelScopeKind kind)
1790         {
1791             Debug.Assert(_labelBlock != null && _labelBlock.Kind == kind);
1792             _labelBlock = _labelBlock.Parent;
1793         }
1794 
EnsureLabel(LabelTarget node)1795         private LabelInfo EnsureLabel(LabelTarget node)
1796         {
1797             LabelInfo result;
1798             if (!_treeLabels.TryGetValue(node, out result))
1799             {
1800                 _treeLabels[node] = result = new LabelInfo(node);
1801             }
1802             return result;
1803         }
1804 
ReferenceLabel(LabelTarget node)1805         private LabelInfo ReferenceLabel(LabelTarget node)
1806         {
1807             LabelInfo result = EnsureLabel(node);
1808             result.Reference(_labelBlock);
1809             return result;
1810         }
1811 
DefineLabel(LabelTarget node)1812         private LabelInfo DefineLabel(LabelTarget node)
1813         {
1814             if (node == null)
1815             {
1816                 return new LabelInfo(null);
1817             }
1818             LabelInfo result = EnsureLabel(node);
1819             result.Define(_labelBlock);
1820             return result;
1821         }
1822 
TryPushLabelBlock(Expression node)1823         private bool TryPushLabelBlock(Expression node)
1824         {
1825             // Anything that is "statement-like" -- e.g. has no associated
1826             // stack state can be jumped into, with the exception of try-blocks
1827             // We indicate this by a "Block"
1828             //
1829             // Otherwise, we push an "Expression" to indicate that it can't be
1830             // jumped into
1831             switch (node.NodeType)
1832             {
1833                 default:
1834                     if (_labelBlock.Kind != LabelScopeKind.Expression)
1835                     {
1836                         PushLabelBlock(LabelScopeKind.Expression);
1837                         return true;
1838                     }
1839                     return false;
1840                 case ExpressionType.Label:
1841                     // LabelExpression is a bit special, if it's directly in a
1842                     // block it becomes associate with the block's scope. Same
1843                     // thing if it's in a switch case body.
1844                     if (_labelBlock.Kind == LabelScopeKind.Block)
1845                     {
1846                         LabelTarget label = ((LabelExpression)node).Target;
1847                         if (_labelBlock.ContainsTarget(label))
1848                         {
1849                             return false;
1850                         }
1851                         if (_labelBlock.Parent.Kind == LabelScopeKind.Switch &&
1852                             _labelBlock.Parent.ContainsTarget(label))
1853                         {
1854                             return false;
1855                         }
1856                     }
1857                     PushLabelBlock(LabelScopeKind.Statement);
1858                     return true;
1859                 case ExpressionType.Block:
1860                     PushLabelBlock(LabelScopeKind.Block);
1861                     // Labels defined immediately in the block are valid for
1862                     // the whole block.
1863                     if (_labelBlock.Parent.Kind != LabelScopeKind.Switch)
1864                     {
1865                         DefineBlockLabels(node);
1866                     }
1867                     return true;
1868                 case ExpressionType.Switch:
1869                     PushLabelBlock(LabelScopeKind.Switch);
1870                     // Define labels inside of the switch cases so they are in
1871                     // scope for the whole switch. This allows "goto case" and
1872                     // "goto default" to be considered as local jumps.
1873                     var @switch = (SwitchExpression)node;
1874                     foreach (SwitchCase c in @switch.Cases)
1875                     {
1876                         DefineBlockLabels(c.Body);
1877                     }
1878                     DefineBlockLabels(@switch.DefaultBody);
1879                     return true;
1880 
1881                 // Remove this when Convert(Void) goes away.
1882                 case ExpressionType.Convert:
1883                     if (node.Type != typeof(void))
1884                     {
1885                         // treat it as an expression
1886                         goto default;
1887                     }
1888                     PushLabelBlock(LabelScopeKind.Statement);
1889                     return true;
1890 
1891                 case ExpressionType.Conditional:
1892                 case ExpressionType.Loop:
1893                 case ExpressionType.Goto:
1894                     PushLabelBlock(LabelScopeKind.Statement);
1895                     return true;
1896             }
1897         }
1898 
DefineBlockLabels(Expression node)1899         private void DefineBlockLabels(Expression node)
1900         {
1901             var block = node as BlockExpression;
1902             if (block == null)
1903             {
1904                 return;
1905             }
1906 
1907             for (int i = 0, n = block.Expressions.Count; i < n; i++)
1908             {
1909                 Expression e = block.Expressions[i];
1910 
1911                 var label = e as LabelExpression;
1912                 if (label != null)
1913                 {
1914                     DefineLabel(label.Target);
1915                 }
1916             }
1917         }
1918 
CheckRethrow()1919         private void CheckRethrow()
1920         {
1921             // Rethrow is only valid inside a catch.
1922             for (LabelScopeInfo j = _labelBlock; j != null; j = j.Parent)
1923             {
1924                 if (j.Kind == LabelScopeKind.Catch)
1925                 {
1926                     return;
1927                 }
1928                 else if (j.Kind == LabelScopeKind.Finally)
1929                 {
1930                     // Rethrow from inside finally is not verifiable
1931                     break;
1932                 }
1933             }
1934             throw Error.RethrowRequiresCatch();
1935         }
1936 
CompileThrowUnaryExpression(Expression expr, bool asVoid)1937         private void CompileThrowUnaryExpression(Expression expr, bool asVoid)
1938         {
1939             var node = (UnaryExpression)expr;
1940 
1941             if (node.Operand == null)
1942             {
1943                 CheckRethrow();
1944 
1945                 CompileParameterExpression(_exceptionForRethrowStack.Peek());
1946                 if (asVoid)
1947                 {
1948                     _instructions.EmitRethrowVoid();
1949                 }
1950                 else
1951                 {
1952                     _instructions.EmitRethrow();
1953                 }
1954             }
1955             else
1956             {
1957                 Compile(node.Operand);
1958                 if (asVoid)
1959                 {
1960                     _instructions.EmitThrowVoid();
1961                 }
1962                 else
1963                 {
1964                     _instructions.EmitThrow();
1965                 }
1966             }
1967         }
1968 
CompileTryExpression(Expression expr)1969         private void CompileTryExpression(Expression expr)
1970         {
1971             var node = (TryExpression)expr;
1972             if (node.Fault != null)
1973             {
1974                 CompileTryFaultExpression(node);
1975             }
1976             else
1977             {
1978                 BranchLabel end = _instructions.MakeLabel();
1979                 BranchLabel gotoEnd = _instructions.MakeLabel();
1980                 int tryStart = _instructions.Count;
1981 
1982                 BranchLabel startOfFinally = null;
1983                 if (node.Finally != null)
1984                 {
1985                     startOfFinally = _instructions.MakeLabel();
1986                     _instructions.EmitEnterTryFinally(startOfFinally);
1987                 }
1988                 else
1989                 {
1990                     _instructions.EmitEnterTryCatch();
1991                 }
1992 
1993                 List<ExceptionHandler> exHandlers = null;
1994                 var enterTryInstr = _instructions.GetInstruction(tryStart) as EnterTryCatchFinallyInstruction;
1995                 Debug.Assert(enterTryInstr != null);
1996 
1997                 PushLabelBlock(LabelScopeKind.Try);
1998                 bool hasValue = node.Type != typeof(void);
1999 
2000                 Compile(node.Body, !hasValue);
2001 
2002                 int tryEnd = _instructions.Count;
2003 
2004                 // handlers jump here:
2005                 _instructions.MarkLabel(gotoEnd);
2006                 _instructions.EmitGoto(end, hasValue, hasValue, hasValue);
2007 
2008                 // keep the result on the stack:
2009                 if (node.Handlers.Count > 0)
2010                 {
2011                     exHandlers = new List<ExceptionHandler>();
2012                     foreach (CatchBlock handler in node.Handlers)
2013                     {
2014                         ParameterExpression parameter = handler.Variable ?? Expression.Parameter(handler.Test);
2015 
2016                         LocalDefinition local = _locals.DefineLocal(parameter, _instructions.Count);
2017                         _exceptionForRethrowStack.Push(parameter);
2018 
2019                         ExceptionFilter filter = null;
2020 
2021                         if (handler.Filter != null)
2022                         {
2023                             PushLabelBlock(LabelScopeKind.Filter);
2024 
2025                             _instructions.EmitEnterExceptionFilter();
2026 
2027                             // at this point the stack balance is prepared for the hidden exception variable:
2028                             int filterLabel = _instructions.MarkRuntimeLabel();
2029                             int filterStart = _instructions.Count;
2030 
2031                             CompileSetVariable(parameter, isVoid: true);
2032                             Compile(handler.Filter);
2033                             CompileGetVariable(parameter);
2034 
2035                             filter = new ExceptionFilter(filterLabel, filterStart, _instructions.Count);
2036 
2037                             // keep the value of the body on the stack:
2038                             _instructions.EmitLeaveExceptionFilter();
2039 
2040                             PopLabelBlock(LabelScopeKind.Filter);
2041                         }
2042 
2043                         PushLabelBlock(LabelScopeKind.Catch);
2044 
2045                         // add a stack balancing nop instruction (exception handling pushes the current exception):
2046                         if (hasValue)
2047                         {
2048                             _instructions.EmitEnterExceptionHandlerNonVoid();
2049                         }
2050                         else
2051                         {
2052                             _instructions.EmitEnterExceptionHandlerVoid();
2053                         }
2054 
2055                         // at this point the stack balance is prepared for the hidden exception variable:
2056                         int handlerLabel = _instructions.MarkRuntimeLabel();
2057                         int handlerStart = _instructions.Count;
2058 
2059                         CompileSetVariable(parameter, isVoid: true);
2060                         Compile(handler.Body, !hasValue);
2061 
2062                         _exceptionForRethrowStack.Pop();
2063 
2064                         // keep the value of the body on the stack:
2065                         _instructions.EmitLeaveExceptionHandler(hasValue, gotoEnd);
2066 
2067                         exHandlers.Add(new ExceptionHandler(handlerLabel, handlerStart, _instructions.Count, handler.Test, filter));
2068                         PopLabelBlock(LabelScopeKind.Catch);
2069 
2070                         _locals.UndefineLocal(local, _instructions.Count);
2071                     }
2072                 }
2073 
2074                 if (node.Finally != null)
2075                 {
2076                     Debug.Assert(startOfFinally != null);
2077                     PushLabelBlock(LabelScopeKind.Finally);
2078 
2079                     _instructions.MarkLabel(startOfFinally);
2080                     _instructions.EmitEnterFinally(startOfFinally);
2081                     CompileAsVoid(node.Finally);
2082                     _instructions.EmitLeaveFinally();
2083 
2084                     enterTryInstr.SetTryHandler(
2085                         new TryCatchFinallyHandler(tryStart, tryEnd, gotoEnd.TargetIndex,
2086                             startOfFinally.TargetIndex, _instructions.Count,
2087                             exHandlers?.ToArray()));
2088                     PopLabelBlock(LabelScopeKind.Finally);
2089                 }
2090                 else
2091                 {
2092                     Debug.Assert(exHandlers != null);
2093                     enterTryInstr.SetTryHandler(
2094                         new TryCatchFinallyHandler(tryStart, tryEnd, gotoEnd.TargetIndex, exHandlers.ToArray()));
2095                 }
2096 
2097                 _instructions.MarkLabel(end);
2098 
2099                 PopLabelBlock(LabelScopeKind.Try);
2100             }
2101         }
2102 
CompileTryFaultExpression(TryExpression expr)2103         private void CompileTryFaultExpression(TryExpression expr)
2104         {
2105             Debug.Assert(expr.Finally == null);
2106             Debug.Assert(expr.Handlers.Count == 0);
2107 
2108             // Mark where we begin.
2109             int tryStart = _instructions.Count;
2110             BranchLabel end = _instructions.MakeLabel();
2111             EnterTryFaultInstruction enterTryInstr = _instructions.EmitEnterTryFault(end);
2112             Debug.Assert(enterTryInstr == _instructions.GetInstruction(tryStart));
2113 
2114             // Emit the try block.
2115             PushLabelBlock(LabelScopeKind.Try);
2116             bool hasValue = expr.Type != typeof(void);
2117             Compile(expr.Body, !hasValue);
2118             int tryEnd = _instructions.Count;
2119 
2120             // Jump out of the try block to the end of the finally. If we got
2121             // This far, then the fault block shouldn't be run.
2122             _instructions.EmitGoto(end, hasValue, hasValue, hasValue);
2123 
2124             // Emit the fault block. The scope kind used is the same as for finally
2125             // blocks, which matches the Compiler.LambdaCompiler.EmitTryExpression approach.
2126             PushLabelBlock(LabelScopeKind.Finally);
2127             BranchLabel startOfFault = _instructions.MakeLabel();
2128             _instructions.MarkLabel(startOfFault);
2129             _instructions.EmitEnterFault(startOfFault);
2130             CompileAsVoid(expr.Fault);
2131             _instructions.EmitLeaveFault();
2132             enterTryInstr.SetTryHandler(new TryFaultHandler(tryStart, tryEnd, startOfFault.TargetIndex, _instructions.Count));
2133             PopLabelBlock(LabelScopeKind.Finally);
2134             PopLabelBlock(LabelScopeKind.Try);
2135             _instructions.MarkLabel(end);
2136         }
2137 
CompileMethodCallExpression(Expression expr)2138         private void CompileMethodCallExpression(Expression expr)
2139         {
2140             var node = (MethodCallExpression)expr;
2141             CompileMethodCallExpression(node.Object, node.Method, node);
2142         }
2143 
2144         private void CompileMethodCallExpression(Expression @object, MethodInfo method, IArgumentProvider arguments)
2145         {
2146             ParameterInfo[] parameters = method.GetParametersCached();
2147 
2148             // TODO: Support pass by reference.
2149             List<ByRefUpdater> updaters = null;
2150             if (!method.IsStatic)
2151             {
2152                 ByRefUpdater updater = CompileAddress(@object, -1);
2153                 if (updater != null)
2154                 {
2155                     updaters = new List<ByRefUpdater>() { updater };
2156                 }
2157             }
2158 
2159             Debug.Assert(parameters.Length == arguments.ArgumentCount);
2160 
2161             for (int i = 0, n = arguments.ArgumentCount; i < n; i++)
2162             {
2163                 Expression arg = arguments.GetArgument(i);
2164 
2165                 // byref calls leave out values on the stack, we use a callback
2166                 // to emit the code which processes each value left on the stack.
2167                 if (parameters[i].ParameterType.IsByRef)
2168                 {
2169                     ByRefUpdater updater = CompileAddress(arg, i);
2170                     if (updater != null)
2171                     {
2172                         if (updaters == null)
2173                         {
2174                             updaters = new List<ByRefUpdater>();
2175                         }
2176 
2177                         updaters.Add(updater);
2178                     }
2179                 }
2180                 else
2181                 {
2182                     Compile(arg);
2183                 }
2184             }
2185 
2186             if (!method.IsStatic &&
2187                 @object.Type.IsNullableType())
2188             {
2189                 // reflection doesn't let us call methods on Nullable<T> when the value
2190                 // is null...  so we get to special case those methods!
2191                 _instructions.EmitNullableCall(method, parameters);
2192             }
2193             else
2194             {
2195                 if (updaters == null)
2196                 {
2197                     _instructions.EmitCall(method, parameters);
2198                 }
2199                 else
2200                 {
2201                     _instructions.EmitByRefCall(method, parameters, updaters.ToArray());
2202 
2203                     foreach (ByRefUpdater updater in updaters)
2204                     {
2205                         updater.UndefineTemps(_instructions, _locals);
2206                     }
2207                 }
2208             }
2209         }
2210 
CompileArrayIndexAddress(Expression array, Expression index, int argumentIndex)2211         private ByRefUpdater CompileArrayIndexAddress(Expression array, Expression index, int argumentIndex)
2212         {
2213             LocalDefinition left = _locals.DefineLocal(Expression.Parameter(array.Type, nameof(array)), _instructions.Count);
2214             LocalDefinition right = _locals.DefineLocal(Expression.Parameter(index.Type, nameof(index)), _instructions.Count);
2215             Compile(array);
2216             _instructions.EmitStoreLocal(left.Index);
2217             Compile(index);
2218             _instructions.EmitStoreLocal(right.Index);
2219 
2220             _instructions.EmitLoadLocal(left.Index);
2221             _instructions.EmitLoadLocal(right.Index);
2222             _instructions.EmitGetArrayItem();
2223 
2224             return new ArrayByRefUpdater(left, right, argumentIndex);
2225         }
2226 
EmitThisForMethodCall(Expression node)2227         private void EmitThisForMethodCall(Expression node)
2228         {
2229             CompileAddress(node, -1);
2230         }
2231 
ShouldWritebackNode(Expression node)2232         private static bool ShouldWritebackNode(Expression node)
2233         {
2234             if (node.Type.IsValueType)
2235             {
2236                 switch (node.NodeType)
2237                 {
2238                     case ExpressionType.Parameter:
2239                     case ExpressionType.Call:
2240                     case ExpressionType.ArrayIndex:
2241                         return true;
2242                     case ExpressionType.Index:
2243                         return ((IndexExpression)node).Object.Type.IsArray;
2244                     case ExpressionType.MemberAccess:
2245                         return ((MemberExpression)node).Member is FieldInfo;
2246                         // ExpressionType.Unbox does have the behaviour write-back is used to simulate, but
2247                         // it doesn't need explicit write-back to produce it, so include it in the default
2248                         // false cases.
2249                 }
2250             }
2251             return false;
2252         }
2253 
2254         /// <summary>
2255         /// Emits the address of the specified node.
2256         /// </summary>
CompileAddress(Expression node, int index)2257         private ByRefUpdater CompileAddress(Expression node, int index)
2258         {
2259             if (index != -1 || ShouldWritebackNode(node))
2260             {
2261                 switch (node.NodeType)
2262                 {
2263                     case ExpressionType.Parameter:
2264                         LoadLocalNoValueTypeCopy((ParameterExpression)node);
2265 
2266                         return new ParameterByRefUpdater(ResolveLocal((ParameterExpression)node), index);
2267                     case ExpressionType.ArrayIndex:
2268                         var array = (BinaryExpression)node;
2269 
2270                         return CompileArrayIndexAddress(array.Left, array.Right, index);
2271                     case ExpressionType.Index:
2272                         var indexNode = (IndexExpression)node;
2273                         if (/*!TypeUtils.AreEquivalent(type, node.Type) || */indexNode.Indexer != null)
2274                         {
2275                             LocalDefinition? objTmp = null;
2276                             if (indexNode.Object != null)
2277                             {
2278                                 objTmp = _locals.DefineLocal(Expression.Parameter(indexNode.Object.Type), _instructions.Count);
2279                                 EmitThisForMethodCall(indexNode.Object);
2280                                 _instructions.EmitDup();
2281                                 _instructions.EmitStoreLocal(objTmp.GetValueOrDefault().Index);
2282                             }
2283 
2284                             int count = indexNode.ArgumentCount;
2285                             var indexLocals = new LocalDefinition[count];
2286                             for (int i = 0; i < count; i++)
2287                             {
2288                                 Expression arg = indexNode.GetArgument(i);
2289                                 Compile(arg);
2290 
2291                                 LocalDefinition argTmp = _locals.DefineLocal(Expression.Parameter(arg.Type), _instructions.Count);
2292                                 _instructions.EmitDup();
2293                                 _instructions.EmitStoreLocal(argTmp.Index);
2294 
2295                                 indexLocals[i] = argTmp;
2296                             }
2297 
2298                             EmitIndexGet(indexNode);
2299 
2300                             return new IndexMethodByRefUpdater(objTmp, indexLocals, indexNode.Indexer.GetSetMethod(), index);
2301                         }
2302                         else if (indexNode.ArgumentCount == 1)
2303                         {
2304                             return CompileArrayIndexAddress(indexNode.Object, indexNode.GetArgument(0), index);
2305                         }
2306                         else
2307                         {
2308                             return CompileMultiDimArrayAccess(indexNode.Object, indexNode, index);
2309                         }
2310                     case ExpressionType.MemberAccess:
2311                         var member = (MemberExpression)node;
2312 
2313                         LocalDefinition? memberTemp = null;
2314                         if (member.Expression != null)
2315                         {
2316                             memberTemp = _locals.DefineLocal(Expression.Parameter(member.Expression.Type, "member"), _instructions.Count);
2317                             EmitThisForMethodCall(member.Expression);
2318                             _instructions.EmitDup();
2319                             _instructions.EmitStoreLocal(memberTemp.GetValueOrDefault().Index);
2320                         }
2321 
2322                         var field = member.Member as FieldInfo;
2323                         if (field != null)
2324                         {
2325                             _instructions.EmitLoadField(field);
2326                             if (!field.IsLiteral && !field.IsInitOnly)
2327                             {
2328                                 return new FieldByRefUpdater(memberTemp, field, index);
2329                             }
2330                             return null;
2331                         }
2332                         Debug.Assert(member.Member is PropertyInfo);
2333                         var property = (PropertyInfo)member.Member;
2334                         _instructions.EmitCall(property.GetGetMethod(nonPublic: true));
2335                         if (property.CanWrite)
2336                         {
2337                             return new PropertyByRefUpdater(memberTemp, property, index);
2338                         }
2339                         return null;
2340                     case ExpressionType.Call:
2341                         // An array index of a multi-dimensional array is represented by a call to Array.Get,
2342                         // rather than having its own array-access node. This means that when we are trying to
2343                         // get the address of a member of a multi-dimensional array, we'll be trying to
2344                         // get the address of a Get method, and it will fail to do so. Instead, detect
2345                         // this situation and replace it with a call to the Address method.
2346                         var call = (MethodCallExpression)node;
2347                         if (!call.Method.IsStatic &&
2348                             call.Object.Type.IsArray &&
2349                             call.Method == call.Object.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance))
2350                         {
2351                             return CompileMultiDimArrayAccess(
2352                                 call.Object,
2353                                 call,
2354                                 index
2355                             );
2356                         }
2357                         break;
2358                 }
2359             }
2360             // Includes Unbox case as it doesn't need explicit write-back.
2361             Compile(node);
2362             return null;
2363         }
2364 
CompileMultiDimArrayAccess(Expression array, IArgumentProvider arguments, int index)2365         private ByRefUpdater CompileMultiDimArrayAccess(Expression array, IArgumentProvider arguments, int index)
2366         {
2367             Compile(array);
2368             LocalDefinition objTmp = _locals.DefineLocal(Expression.Parameter(array.Type), _instructions.Count);
2369             _instructions.EmitDup();
2370             _instructions.EmitStoreLocal(objTmp.Index);
2371 
2372             int count = arguments.ArgumentCount;
2373             var indexLocals = new LocalDefinition[count];
2374             for (int i = 0; i < count; i++)
2375             {
2376                 Expression arg = arguments.GetArgument(i);
2377                 Compile(arg);
2378 
2379                 LocalDefinition argTmp = _locals.DefineLocal(Expression.Parameter(arg.Type), _instructions.Count);
2380                 _instructions.EmitDup();
2381                 _instructions.EmitStoreLocal(argTmp.Index);
2382 
2383                 indexLocals[i] = argTmp;
2384             }
2385 
2386             _instructions.EmitCall(array.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance));
2387 
2388             return new IndexMethodByRefUpdater(objTmp, indexLocals, array.Type.GetMethod("Set", BindingFlags.Public | BindingFlags.Instance), index);
2389         }
2390 
CompileNewExpression(Expression expr)2391         private void CompileNewExpression(Expression expr)
2392         {
2393             var node = (NewExpression)expr;
2394 
2395             if (node.Constructor != null)
2396             {
2397                 if (node.Constructor.DeclaringType.IsAbstract)
2398                     throw Error.NonAbstractConstructorRequired();
2399 
2400                 ParameterInfo[] parameters = node.Constructor.GetParametersCached();
2401                 List<ByRefUpdater> updaters = null;
2402 
2403                 for (int i = 0; i < parameters.Length; i++)
2404                 {
2405                     Expression arg = node.GetArgument(i);
2406 
2407                     if (parameters[i].ParameterType.IsByRef)
2408                     {
2409                         ByRefUpdater updater = CompileAddress(arg, i);
2410                         if (updater != null)
2411                         {
2412                             if (updaters == null)
2413                             {
2414                                 updaters = new List<ByRefUpdater>();
2415                             }
2416                             updaters.Add(updater);
2417                         }
2418                     }
2419                     else
2420                     {
2421                         Compile(arg);
2422                     }
2423                 }
2424 
2425                 if (updaters != null)
2426                 {
2427                     _instructions.EmitByRefNew(node.Constructor, parameters, updaters.ToArray());
2428                 }
2429                 else
2430                 {
2431                     _instructions.EmitNew(node.Constructor, parameters);
2432                 }
2433             }
2434             else
2435             {
2436                 Type type = node.Type;
2437                 Debug.Assert(type.IsValueType);
2438                 if (type.IsNullableType())
2439                 {
2440                     _instructions.EmitLoad(value: null);
2441                 }
2442                 else
2443                 {
2444                     _instructions.EmitDefaultValue(type);
2445                 }
2446             }
2447         }
2448 
CompileMemberExpression(Expression expr)2449         private void CompileMemberExpression(Expression expr)
2450         {
2451             var node = (MemberExpression)expr;
2452 
2453             CompileMember(node.Expression, node.Member, forBinding: false);
2454         }
2455 
CompileMember(Expression from, MemberInfo member, bool forBinding)2456         private void CompileMember(Expression from, MemberInfo member, bool forBinding)
2457         {
2458             var fi = member as FieldInfo;
2459             if (fi != null)
2460             {
2461                 if (fi.IsLiteral)
2462                 {
2463                     Debug.Assert(!forBinding);
2464                     _instructions.EmitLoad(fi.GetValue(obj: null), fi.FieldType);
2465                 }
2466                 else if (fi.IsStatic)
2467                 {
2468                     if (forBinding)
2469                     {
2470                         throw Error.InvalidProgram();
2471                     }
2472 
2473                     if (fi.IsInitOnly)
2474                     {
2475                         _instructions.EmitLoad(fi.GetValue(obj: null), fi.FieldType);
2476                     }
2477                     else
2478                     {
2479                         _instructions.EmitLoadField(fi);
2480                     }
2481                 }
2482                 else
2483                 {
2484                     if (from != null)
2485                     {
2486                         EmitThisForMethodCall(from);
2487                     }
2488 
2489                     _instructions.EmitLoadField(fi);
2490                 }
2491             }
2492             else
2493             {
2494                 // MemberExpression can use either FieldInfo or PropertyInfo - other types derived from MemberInfo are not permitted
2495                 var pi = (PropertyInfo)member;
2496                 if (pi != null)
2497                 {
2498                     MethodInfo method = pi.GetGetMethod(nonPublic: true);
2499                     if (forBinding && method.IsStatic)
2500                     {
2501                         throw Error.InvalidProgram();
2502                     }
2503 
2504                     if (from != null)
2505                     {
2506                         EmitThisForMethodCall(from);
2507                     }
2508 
2509                     if (!method.IsStatic &&
2510                         (from != null && from.Type.IsNullableType()))
2511                     {
2512                         // reflection doesn't let us call methods on Nullable<T> when the value
2513                         // is null...  so we get to special case those methods!
2514                         _instructions.EmitNullableCall(method, Array.Empty<ParameterInfo>());
2515                     }
2516                     else
2517                     {
2518                         _instructions.EmitCall(method);
2519                     }
2520                 }
2521             }
2522         }
2523 
CompileNewArrayExpression(Expression expr)2524         private void CompileNewArrayExpression(Expression expr)
2525         {
2526             var node = (NewArrayExpression)expr;
2527 
2528             foreach (Expression arg in node.Expressions)
2529             {
2530                 Compile(arg);
2531             }
2532 
2533             Type elementType = node.Type.GetElementType();
2534             int rank = node.Expressions.Count;
2535 
2536             if (node.NodeType == ExpressionType.NewArrayInit)
2537             {
2538                 _instructions.EmitNewArrayInit(elementType, rank);
2539             }
2540             else
2541             {
2542                 Debug.Assert(node.NodeType == ExpressionType.NewArrayBounds);
2543                 if (rank == 1)
2544                 {
2545                     _instructions.EmitNewArray(elementType);
2546                 }
2547                 else
2548                 {
2549                     _instructions.EmitNewArrayBounds(elementType, rank);
2550                 }
2551             }
2552         }
2553 
CompileDebugInfoExpression(Expression expr)2554         private void CompileDebugInfoExpression(Expression expr)
2555         {
2556             var node = (DebugInfoExpression)expr;
2557             int start = _instructions.Count;
2558             var info = new DebugInfo()
2559             {
2560                 Index = start,
2561                 FileName = node.Document.FileName,
2562                 StartLine = node.StartLine,
2563                 EndLine = node.EndLine,
2564                 IsClear = node.IsClear
2565             };
2566             _debugInfos.Add(info);
2567         }
2568 
CompileRuntimeVariablesExpression(Expression expr)2569         private void CompileRuntimeVariablesExpression(Expression expr)
2570         {
2571             // Generates IRuntimeVariables for all requested variables
2572             var node = (RuntimeVariablesExpression)expr;
2573             foreach (ParameterExpression variable in node.Variables)
2574             {
2575                 EnsureAvailableForClosure(variable);
2576                 CompileGetBoxedVariable(variable);
2577             }
2578 
2579             _instructions.EmitNewRuntimeVariables(node.Variables.Count);
2580         }
2581 
CompileLambdaExpression(Expression expr)2582         private void CompileLambdaExpression(Expression expr)
2583         {
2584             var node = (LambdaExpression)expr;
2585             var compiler = new LightCompiler(this);
2586             LightDelegateCreator creator = compiler.CompileTop(node);
2587 
2588             if (compiler._locals.ClosureVariables != null)
2589             {
2590                 foreach (ParameterExpression variable in compiler._locals.ClosureVariables.Keys)
2591                 {
2592                     EnsureAvailableForClosure(variable);
2593                     CompileGetBoxedVariable(variable);
2594                 }
2595             }
2596             _instructions.EmitCreateDelegate(creator);
2597         }
2598 
CompileCoalesceBinaryExpression(Expression expr)2599         private void CompileCoalesceBinaryExpression(Expression expr)
2600         {
2601             var node = (BinaryExpression)expr;
2602 
2603             bool hasConversion = node.Conversion != null;
2604             bool hasImplicitConversion = false;
2605             if (!hasConversion && node.Left.Type.IsNullableType())
2606             {
2607                 // reference types don't need additional conversions (the interpreter operates on Object
2608                 // anyway); non-nullable value types can't occur on the left side; all that's left is
2609                 // nullable value types with implicit (numeric) conversions which are allowed by Coalesce
2610                 // factory methods
2611 
2612                 Type typeToCompare = node.Left.Type;
2613                 if (!node.Type.IsNullableType())
2614                 {
2615                     typeToCompare = typeToCompare.GetNonNullableType();
2616                 }
2617 
2618                 if (!TypeUtils.AreEquivalent(node.Type, typeToCompare))
2619                 {
2620                     hasImplicitConversion = true;
2621                     hasConversion = true;
2622                 }
2623             }
2624 
2625             BranchLabel leftNotNull = _instructions.MakeLabel();
2626             BranchLabel end = null;
2627 
2628             Compile(node.Left);
2629             _instructions.EmitCoalescingBranch(leftNotNull);
2630             _instructions.EmitPop();
2631             Compile(node.Right);
2632 
2633             if (hasConversion)
2634             {
2635                 // skip over conversion on RHS
2636                 end = _instructions.MakeLabel();
2637                 _instructions.EmitBranch(end);
2638             }
2639             else if (node.Right.Type.IsValueType && !TypeUtils.AreEquivalent(node.Type, node.Right.Type))
2640             {
2641                 // The right hand side may need to be widened to either the left hand side's type
2642                 // if the right hand side is nullable, or the left hand side's underlying type otherwise
2643                 CompileConvertToType(node.Right.Type, node.Type, isChecked: true, isLiftedToNull: node.Type.IsNullableType());
2644             }
2645 
2646             _instructions.MarkLabel(leftNotNull);
2647 
2648             if (node.Conversion != null)
2649             {
2650                 ParameterExpression temp = Expression.Parameter(node.Left.Type, "temp");
2651                 LocalDefinition local = _locals.DefineLocal(temp, _instructions.Count);
2652                 _instructions.EmitStoreLocal(local.Index);
2653 
2654                 CompileMethodCallExpression(
2655                     Expression.Call(node.Conversion, node.Conversion.Type.GetInvokeMethod(), new[] { temp })
2656                 );
2657 
2658                 _locals.UndefineLocal(local, _instructions.Count);
2659             }
2660             else if (hasImplicitConversion)
2661             {
2662                 Type nnLeftType = node.Left.Type.GetNonNullableType();
2663                 CompileConvertToType(nnLeftType, node.Type, isChecked: true, isLiftedToNull: false);
2664             }
2665 
2666             if (hasConversion)
2667             {
2668                 _instructions.MarkLabel(end);
2669             }
2670         }
2671 
CompileInvocationExpression(Expression expr)2672         private void CompileInvocationExpression(Expression expr)
2673         {
2674             var node = (InvocationExpression)expr;
2675 
2676             if (typeof(LambdaExpression).IsAssignableFrom(node.Expression.Type))
2677             {
2678                 MethodInfo compMethod = node.Expression.Type.GetMethod("Compile", Array.Empty<Type>());
2679                 CompileMethodCallExpression(
2680                     Expression.Call(
2681                         node.Expression,
2682                         compMethod
2683                     ),
2684                     compMethod.ReturnType.GetInvokeMethod(),
2685                     node
2686                 );
2687             }
2688             else
2689             {
2690                 CompileMethodCallExpression(
2691                     node.Expression, node.Expression.Type.GetInvokeMethod(), node
2692                 );
2693             }
2694         }
2695 
CompileListInitExpression(Expression expr)2696         private void CompileListInitExpression(Expression expr)
2697         {
2698             var node = (ListInitExpression)expr;
2699             EmitThisForMethodCall(node.NewExpression);
2700             ReadOnlyCollection<ElementInit> initializers = node.Initializers;
2701             CompileListInit(initializers);
2702         }
2703 
CompileListInit(ReadOnlyCollection<ElementInit> initializers)2704         private void CompileListInit(ReadOnlyCollection<ElementInit> initializers)
2705         {
2706             for (int i = 0; i < initializers.Count; i++)
2707             {
2708                 ElementInit initializer = initializers[i];
2709                 _instructions.EmitDup();
2710                 foreach (Expression arg in initializer.Arguments)
2711                 {
2712                     Compile(arg);
2713                 }
2714                 MethodInfo add = initializer.AddMethod;
2715                 _instructions.EmitCall(add);
2716                 if (add.ReturnType != typeof(void))
2717                     _instructions.EmitPop();
2718             }
2719         }
2720 
CompileMemberInitExpression(Expression expr)2721         private void CompileMemberInitExpression(Expression expr)
2722         {
2723             var node = (MemberInitExpression)expr;
2724             EmitThisForMethodCall(node.NewExpression);
2725             CompileMemberInit(node.Bindings);
2726         }
2727 
CompileMemberInit(ReadOnlyCollection<MemberBinding> bindings)2728         private void CompileMemberInit(ReadOnlyCollection<MemberBinding> bindings)
2729         {
2730             foreach (MemberBinding binding in bindings)
2731             {
2732                 switch (binding.BindingType)
2733                 {
2734                     case MemberBindingType.Assignment:
2735                         _instructions.EmitDup();
2736                         CompileMemberAssignment(
2737                             true,
2738                             ((MemberAssignment)binding).Member,
2739                             ((MemberAssignment)binding).Expression,
2740                             forBinding: true
2741                         );
2742                         break;
2743                     case MemberBindingType.ListBinding:
2744                         var memberList = (MemberListBinding)binding;
2745                         _instructions.EmitDup();
2746                         CompileMember(null, memberList.Member, forBinding: true);
2747                         CompileListInit(memberList.Initializers);
2748                         _instructions.EmitPop();
2749                         break;
2750                     case MemberBindingType.MemberBinding:
2751                         var memberMember = (MemberMemberBinding)binding;
2752                         _instructions.EmitDup();
2753                         Type type = GetMemberType(memberMember.Member);
2754                         if (memberMember.Member is PropertyInfo && type.IsValueType)
2755                         {
2756                             throw Error.CannotAutoInitializeValueTypeMemberThroughProperty(memberMember.Bindings);
2757                         }
2758 
2759                         CompileMember(null, memberMember.Member, forBinding: true);
2760                         CompileMemberInit(memberMember.Bindings);
2761                         _instructions.EmitPop();
2762                         break;
2763                 }
2764             }
2765         }
2766 
GetMemberType(MemberInfo member)2767         private static Type GetMemberType(MemberInfo member)
2768         {
2769             var fi = member as FieldInfo;
2770             if (fi != null) return fi.FieldType;
2771             var pi = member as PropertyInfo;
2772             if (pi != null) return pi.PropertyType;
2773             throw new InvalidOperationException("MemberNotFieldOrProperty");
2774         }
2775 
CompileQuoteUnaryExpression(Expression expr)2776         private void CompileQuoteUnaryExpression(Expression expr)
2777         {
2778             var unary = (UnaryExpression)expr;
2779 
2780             var visitor = new QuoteVisitor();
2781             visitor.Visit(unary.Operand);
2782 
2783             var mapping = new Dictionary<ParameterExpression, LocalVariable>();
2784 
2785             foreach (ParameterExpression local in visitor._hoistedParameters)
2786             {
2787                 EnsureAvailableForClosure(local);
2788                 mapping[local] = ResolveLocal(local);
2789             }
2790 
2791             _instructions.Emit(new QuoteInstruction(unary.Operand, mapping.Count > 0 ? mapping : null));
2792         }
2793 
2794         private sealed class QuoteVisitor : ExpressionVisitor
2795         {
2796             private readonly Dictionary<ParameterExpression, int> _definedParameters = new Dictionary<ParameterExpression, int>();
2797             public readonly HashSet<ParameterExpression> _hoistedParameters = new HashSet<ParameterExpression>();
2798 
VisitParameter(ParameterExpression node)2799             protected internal override Expression VisitParameter(ParameterExpression node)
2800             {
2801                 if (!_definedParameters.ContainsKey(node))
2802                 {
2803                     _hoistedParameters.Add(node);
2804                 }
2805                 return node;
2806             }
2807 
VisitBlock(BlockExpression node)2808             protected internal override Expression VisitBlock(BlockExpression node)
2809             {
2810                 PushParameters(node.Variables);
2811 
2812                 base.VisitBlock(node);
2813 
2814                 PopParameters(node.Variables);
2815 
2816                 return node;
2817             }
2818 
VisitCatchBlock(CatchBlock node)2819             protected override CatchBlock VisitCatchBlock(CatchBlock node)
2820             {
2821                 if (node.Variable != null)
2822                 {
2823                     PushParameters(new[] { node.Variable });
2824                 }
2825                 Visit(node.Body);
2826                 Visit(node.Filter);
2827                 if (node.Variable != null)
2828                 {
2829                     PopParameters(new[] { node.Variable });
2830                 }
2831                 return node;
2832             }
2833 
VisitLambda(Expression<T> node)2834             protected internal override Expression VisitLambda<T>(Expression<T> node)
2835             {
2836                 IEnumerable<ParameterExpression> parameters = Array.Empty<ParameterExpression>();
2837 
2838                 int count = node.ParameterCount;
2839 
2840                 if (count > 0)
2841                 {
2842                     var parameterList = new List<ParameterExpression>(count);
2843 
2844                     for (int i = 0; i < count; i++)
2845                     {
2846                         parameterList.Add(node.GetParameter(i));
2847                     }
2848 
2849                     parameters = parameterList;
2850                 }
2851 
2852                 PushParameters(parameters);
2853 
2854                 base.VisitLambda(node);
2855 
2856                 PopParameters(parameters);
2857 
2858                 return node;
2859             }
2860 
PushParameters(IEnumerable<ParameterExpression> parameters)2861             private void PushParameters(IEnumerable<ParameterExpression> parameters)
2862             {
2863                 foreach (ParameterExpression param in parameters)
2864                 {
2865                     int count;
2866                     if (_definedParameters.TryGetValue(param, out count))
2867                     {
2868                         _definedParameters[param] = count + 1;
2869                     }
2870                     else
2871                     {
2872                         _definedParameters[param] = 1;
2873                     }
2874                 }
2875             }
2876 
PopParameters(IEnumerable<ParameterExpression> parameters)2877             private void PopParameters(IEnumerable<ParameterExpression> parameters)
2878             {
2879                 foreach (ParameterExpression param in parameters)
2880                 {
2881                     int count = _definedParameters[param];
2882                     if (count == 0)
2883                     {
2884                         _definedParameters.Remove(param);
2885                     }
2886                     else
2887                     {
2888                         _definedParameters[param] = count - 1;
2889                     }
2890                 }
2891             }
2892         }
2893 
CompileUnboxUnaryExpression(Expression expr)2894         private void CompileUnboxUnaryExpression(Expression expr)
2895         {
2896             var node = (UnaryExpression)expr;
2897 
2898             Compile(node.Operand);
2899 
2900             if (node.Type.IsValueType && !node.Type.IsNullableType())
2901             {
2902                 _instructions.Emit(NullCheckInstruction.Instance);
2903             }
2904         }
2905 
CompileTypeEqualExpression(Expression expr)2906         private void CompileTypeEqualExpression(Expression expr)
2907         {
2908             Debug.Assert(expr.NodeType == ExpressionType.TypeEqual);
2909             var node = (TypeBinaryExpression)expr;
2910 
2911             Compile(node.Expression);
2912             if (node.Expression.Type == typeof(void))
2913             {
2914                 _instructions.EmitLoad(node.TypeOperand == typeof(void), typeof(bool));
2915             }
2916             else
2917             {
2918                 _instructions.EmitLoad(node.TypeOperand.GetNonNullableType());
2919                 _instructions.EmitTypeEquals();
2920             }
2921         }
2922 
CompileTypeAsExpression(UnaryExpression node)2923         private void CompileTypeAsExpression(UnaryExpression node)
2924         {
2925             Compile(node.Operand);
2926             _instructions.EmitTypeAs(node.Type);
2927         }
2928 
CompileTypeIsExpression(Expression expr)2929         private void CompileTypeIsExpression(Expression expr)
2930         {
2931             Debug.Assert(expr.NodeType == ExpressionType.TypeIs);
2932             var node = (TypeBinaryExpression)expr;
2933 
2934             AnalyzeTypeIsResult result = ConstantCheck.AnalyzeTypeIs(node);
2935 
2936             Compile(node.Expression);
2937 
2938             switch (result)
2939             {
2940                 case AnalyzeTypeIsResult.KnownTrue:
2941                 case AnalyzeTypeIsResult.KnownFalse:
2942 
2943                     // Result is known statically, so just emit the expression for
2944                     // its side effects and return the result
2945                     if (node.Expression.Type != typeof(void))
2946                     {
2947                         _instructions.EmitPop();
2948                     }
2949 
2950                     _instructions.EmitLoad(result == AnalyzeTypeIsResult.KnownTrue);
2951                     break;
2952                 case AnalyzeTypeIsResult.KnownAssignable:
2953 
2954                     // Either the value is of the type or it is null
2955                     // so emit test for not-null.
2956                     _instructions.EmitLoad(null);
2957                     _instructions.EmitNotEqual(typeof(object));
2958                     break;
2959                 default:
2960                     if (node.TypeOperand.IsValueType)
2961                     {
2962                         _instructions.EmitLoad(node.TypeOperand.GetNonNullableType());
2963                         _instructions.EmitTypeEquals();
2964                     }
2965                     else
2966                     {
2967                         _instructions.EmitTypeIs(node.TypeOperand);
2968                     }
2969                     break;
2970             }
2971         }
2972 
Compile(Expression expr, bool asVoid)2973         private void Compile(Expression expr, bool asVoid)
2974         {
2975             if (asVoid)
2976             {
2977                 CompileAsVoid(expr);
2978             }
2979             else
2980             {
2981                 Compile(expr);
2982             }
2983         }
2984 
CompileAsVoid(Expression expr)2985         private void CompileAsVoid(Expression expr)
2986         {
2987             bool pushLabelBlock = TryPushLabelBlock(expr);
2988             int startingStackDepth = _instructions.CurrentStackDepth;
2989             switch (expr.NodeType)
2990             {
2991                 case ExpressionType.Assign:
2992                     CompileAssignBinaryExpression(expr, asVoid: true);
2993                     break;
2994 
2995                 case ExpressionType.Block:
2996                     CompileBlockExpression(expr, asVoid: true);
2997                     break;
2998 
2999                 case ExpressionType.Throw:
3000                     CompileThrowUnaryExpression(expr, asVoid: true);
3001                     break;
3002 
3003                 case ExpressionType.Constant:
3004                 case ExpressionType.Default:
3005                 case ExpressionType.Parameter:
3006                     // no-op
3007                     break;
3008 
3009                 default:
3010                     CompileNoLabelPush(expr);
3011                     if (expr.Type != typeof(void))
3012                     {
3013                         _instructions.EmitPop();
3014                     }
3015                     break;
3016             }
3017             Debug.Assert(_instructions.CurrentStackDepth == startingStackDepth);
3018             if (pushLabelBlock)
3019             {
3020                 PopLabelBlock(_labelBlock.Kind);
3021             }
3022         }
3023 
3024         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
CompileNoLabelPush(Expression expr)3025         private void CompileNoLabelPush(Expression expr)
3026         {
3027             // When compiling deep trees, we run the risk of triggering a terminating StackOverflowException,
3028             // so we use the StackGuard utility here to probe for sufficient stack and continue the work on
3029             // another thread when we run out of stack space.
3030             if (!_guard.TryEnterOnCurrentStack())
3031             {
3032                 _guard.RunOnEmptyStack((LightCompiler @this, Expression e) => @this.CompileNoLabelPush(e), this, expr);
3033                 return;
3034             }
3035 
3036             int startingStackDepth = _instructions.CurrentStackDepth;
3037             switch (expr.NodeType)
3038             {
3039                 case ExpressionType.Add:
3040                 case ExpressionType.AddChecked:
3041                 case ExpressionType.And:
3042                 case ExpressionType.ArrayIndex:
3043                 case ExpressionType.Divide:
3044                 case ExpressionType.Equal:
3045                 case ExpressionType.ExclusiveOr:
3046                 case ExpressionType.GreaterThan:
3047                 case ExpressionType.GreaterThanOrEqual:
3048                 case ExpressionType.LeftShift:
3049                 case ExpressionType.LessThan:
3050                 case ExpressionType.LessThanOrEqual:
3051                 case ExpressionType.Modulo:
3052                 case ExpressionType.Multiply:
3053                 case ExpressionType.MultiplyChecked:
3054                 case ExpressionType.NotEqual:
3055                 case ExpressionType.Or:
3056                 case ExpressionType.Power:
3057                 case ExpressionType.RightShift:
3058                 case ExpressionType.Subtract:
3059                 case ExpressionType.SubtractChecked: CompileBinaryExpression(expr); break;
3060                 case ExpressionType.AndAlso: CompileAndAlsoBinaryExpression(expr); break;
3061                 case ExpressionType.OrElse: CompileOrElseBinaryExpression(expr); break;
3062                 case ExpressionType.Coalesce: CompileCoalesceBinaryExpression(expr); break;
3063                 case ExpressionType.ArrayLength:
3064                 case ExpressionType.Decrement:
3065                 case ExpressionType.Increment:
3066                 case ExpressionType.IsTrue:
3067                 case ExpressionType.IsFalse:
3068                 case ExpressionType.Negate:
3069                 case ExpressionType.NegateChecked:
3070                 case ExpressionType.Not:
3071                 case ExpressionType.OnesComplement:
3072                 case ExpressionType.TypeAs:
3073                 case ExpressionType.UnaryPlus: CompileUnaryExpression(expr); break;
3074                 case ExpressionType.Convert:
3075                 case ExpressionType.ConvertChecked: CompileConvertUnaryExpression(expr); break;
3076                 case ExpressionType.Quote: CompileQuoteUnaryExpression(expr); break;
3077                 case ExpressionType.Throw: CompileThrowUnaryExpression(expr, expr.Type == typeof(void)); break;
3078                 case ExpressionType.Unbox: CompileUnboxUnaryExpression(expr); break;
3079                 case ExpressionType.Call: CompileMethodCallExpression(expr); break;
3080                 case ExpressionType.Conditional: CompileConditionalExpression(expr, expr.Type == typeof(void)); break;
3081                 case ExpressionType.Constant: CompileConstantExpression(expr); break;
3082                 case ExpressionType.Invoke: CompileInvocationExpression(expr); break;
3083                 case ExpressionType.Lambda: CompileLambdaExpression(expr); break;
3084                 case ExpressionType.ListInit: CompileListInitExpression(expr); break;
3085                 case ExpressionType.MemberAccess: CompileMemberExpression(expr); break;
3086                 case ExpressionType.MemberInit: CompileMemberInitExpression(expr); break;
3087                 case ExpressionType.New: CompileNewExpression(expr); break;
3088                 case ExpressionType.NewArrayInit:
3089                 case ExpressionType.NewArrayBounds: CompileNewArrayExpression(expr); break;
3090                 case ExpressionType.Parameter: CompileParameterExpression(expr); break;
3091                 case ExpressionType.TypeIs: CompileTypeIsExpression(expr); break;
3092                 case ExpressionType.TypeEqual: CompileTypeEqualExpression(expr); break;
3093                 case ExpressionType.Assign: CompileAssignBinaryExpression(expr, expr.Type == typeof(void)); break;
3094                 case ExpressionType.Block: CompileBlockExpression(expr, expr.Type == typeof(void)); break;
3095                 case ExpressionType.DebugInfo: CompileDebugInfoExpression(expr); break;
3096                 case ExpressionType.Default: CompileDefaultExpression(expr); break;
3097                 case ExpressionType.Goto: CompileGotoExpression(expr); break;
3098                 case ExpressionType.Index: CompileIndexExpression(expr); break;
3099                 case ExpressionType.Label: CompileLabelExpression(expr); break;
3100                 case ExpressionType.RuntimeVariables: CompileRuntimeVariablesExpression(expr); break;
3101                 case ExpressionType.Loop: CompileLoopExpression(expr); break;
3102                 case ExpressionType.Switch: CompileSwitchExpression(expr); break;
3103                 case ExpressionType.Try: CompileTryExpression(expr); break;
3104                 default:
3105                     Compile(expr.ReduceAndCheck());
3106                     break;
3107             }
3108             Debug.Assert(_instructions.CurrentStackDepth == startingStackDepth + (expr.Type == typeof(void) ? 0 : 1),
3109                 string.Format("{0} vs {1} for {2}", _instructions.CurrentStackDepth, startingStackDepth + (expr.Type == typeof(void) ? 0 : 1), expr.NodeType));
3110         }
3111 
Compile(Expression expr)3112         private void Compile(Expression expr)
3113         {
3114             bool pushLabelBlock = TryPushLabelBlock(expr);
3115             CompileNoLabelPush(expr);
3116             if (pushLabelBlock)
3117             {
3118                 PopLabelBlock(_labelBlock.Kind);
3119             }
3120         }
3121     }
3122 
3123     internal abstract class ByRefUpdater
3124     {
3125         public readonly int ArgumentIndex;
3126 
ByRefUpdater(int argumentIndex)3127         public ByRefUpdater(int argumentIndex)
3128         {
3129             ArgumentIndex = argumentIndex;
3130         }
3131 
Update(InterpretedFrame frame, object value)3132         public abstract void Update(InterpretedFrame frame, object value);
3133 
UndefineTemps(InstructionList instructions, LocalVariables locals)3134         public virtual void UndefineTemps(InstructionList instructions, LocalVariables locals)
3135         {
3136         }
3137     }
3138 
3139     internal sealed class ParameterByRefUpdater : ByRefUpdater
3140     {
3141         private readonly LocalVariable _parameter;
3142 
ParameterByRefUpdater(LocalVariable parameter, int argumentIndex)3143         public ParameterByRefUpdater(LocalVariable parameter, int argumentIndex)
3144             : base(argumentIndex)
3145         {
3146             _parameter = parameter;
3147         }
3148 
Update(InterpretedFrame frame, object value)3149         public override void Update(InterpretedFrame frame, object value)
3150         {
3151             if (_parameter.InClosure)
3152             {
3153                 IStrongBox box = frame.Closure[_parameter.Index];
3154                 box.Value = value;
3155             }
3156             else if (_parameter.IsBoxed)
3157             {
3158                 var box = (IStrongBox)frame.Data[_parameter.Index];
3159                 box.Value = value;
3160             }
3161             else
3162             {
3163                 frame.Data[_parameter.Index] = value;
3164             }
3165         }
3166     }
3167 
3168     internal sealed class ArrayByRefUpdater : ByRefUpdater
3169     {
3170         private readonly LocalDefinition _array, _index;
3171 
ArrayByRefUpdater(LocalDefinition array, LocalDefinition index, int argumentIndex)3172         public ArrayByRefUpdater(LocalDefinition array, LocalDefinition index, int argumentIndex)
3173             : base(argumentIndex)
3174         {
3175             _array = array;
3176             _index = index;
3177         }
3178 
Update(InterpretedFrame frame, object value)3179         public override void Update(InterpretedFrame frame, object value)
3180         {
3181             object index = frame.Data[_index.Index];
3182             ((Array)frame.Data[_array.Index]).SetValue(value, (int)index);
3183         }
3184 
UndefineTemps(InstructionList instructions, LocalVariables locals)3185         public override void UndefineTemps(InstructionList instructions, LocalVariables locals)
3186         {
3187             locals.UndefineLocal(_array, instructions.Count);
3188             locals.UndefineLocal(_index, instructions.Count);
3189         }
3190     }
3191 
3192     internal sealed class FieldByRefUpdater : ByRefUpdater
3193     {
3194         private readonly LocalDefinition? _object;
3195         private readonly FieldInfo _field;
3196 
3197         public FieldByRefUpdater(LocalDefinition? obj, FieldInfo field, int argumentIndex)
base(argumentIndex)3198             : base(argumentIndex)
3199         {
3200             _object = obj;
3201             _field = field;
3202         }
3203 
Update(InterpretedFrame frame, object value)3204         public override void Update(InterpretedFrame frame, object value)
3205         {
3206             object obj = _object == null ? null : frame.Data[_object.GetValueOrDefault().Index];
3207             _field.SetValue(obj, value);
3208         }
3209 
UndefineTemps(InstructionList instructions, LocalVariables locals)3210         public override void UndefineTemps(InstructionList instructions, LocalVariables locals)
3211         {
3212             if (_object != null)
3213             {
3214                 locals.UndefineLocal(_object.GetValueOrDefault(), instructions.Count);
3215             }
3216         }
3217     }
3218 
3219     internal sealed class PropertyByRefUpdater : ByRefUpdater
3220     {
3221         private readonly LocalDefinition? _object;
3222         private readonly PropertyInfo _property;
3223 
3224         public PropertyByRefUpdater(LocalDefinition? obj, PropertyInfo property, int argumentIndex)
base(argumentIndex)3225             : base(argumentIndex)
3226         {
3227             _object = obj;
3228             _property = property;
3229         }
3230 
Update(InterpretedFrame frame, object value)3231         public override void Update(InterpretedFrame frame, object value)
3232         {
3233             object obj = _object == null ? null : frame.Data[_object.GetValueOrDefault().Index];
3234 
3235             try
3236             {
3237                 _property.SetValue(obj, value);
3238             }
3239             catch (TargetInvocationException e)
3240             {
3241                 ExceptionHelpers.UnwrapAndRethrow(e);
3242                 throw ContractUtils.Unreachable;
3243             }
3244         }
3245 
UndefineTemps(InstructionList instructions, LocalVariables locals)3246         public override void UndefineTemps(InstructionList instructions, LocalVariables locals)
3247         {
3248             if (_object != null)
3249             {
3250                 locals.UndefineLocal(_object.GetValueOrDefault(), instructions.Count);
3251             }
3252         }
3253     }
3254 
3255     internal sealed class IndexMethodByRefUpdater : ByRefUpdater
3256     {
3257         private readonly MethodInfo _indexer;
3258         private readonly LocalDefinition? _obj;
3259         private readonly LocalDefinition[] _args;
3260 
3261         public IndexMethodByRefUpdater(LocalDefinition? obj, LocalDefinition[] args, MethodInfo indexer, int argumentIndex)
base(argumentIndex)3262             : base(argumentIndex)
3263         {
3264             _obj = obj;
3265             _args = args;
3266             _indexer = indexer;
3267         }
3268 
Update(InterpretedFrame frame, object value)3269         public override void Update(InterpretedFrame frame, object value)
3270         {
3271             var args = new object[_args.Length + 1];
3272             for (int i = 0; i < args.Length - 1; i++)
3273             {
3274                 args[i] = frame.Data[_args[i].Index];
3275             }
3276             args[args.Length - 1] = value;
3277 
3278             object instance = _obj == null ? null : frame.Data[_obj.GetValueOrDefault().Index];
3279 
3280             try
3281             {
3282                 _indexer.Invoke(instance, args);
3283             }
3284             catch (TargetInvocationException e)
3285             {
3286                 ExceptionHelpers.UnwrapAndRethrow(e);
3287                 throw ContractUtils.Unreachable;
3288             }
3289         }
3290 
UndefineTemps(InstructionList instructions, LocalVariables locals)3291         public override void UndefineTemps(InstructionList instructions, LocalVariables locals)
3292         {
3293             if (_obj != null)
3294             {
3295                 locals.UndefineLocal(_obj.GetValueOrDefault(), instructions.Count);
3296             }
3297 
3298             for (int i = 0; i < _args.Length; i++)
3299             {
3300                 locals.UndefineLocal(_args[i], instructions.Count);
3301             }
3302         }
3303     }
3304 }
3305