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.Diagnostics;
6 using System.Collections.Generic;
7 using System.Globalization;
8 
9 namespace System.Linq.Expressions.Interpreter
10 {
11     internal readonly struct RuntimeLabel
12     {
13         public readonly int Index;
14         public readonly int StackDepth;
15         public readonly int ContinuationStackDepth;
16 
RuntimeLabelSystem.Linq.Expressions.Interpreter.RuntimeLabel17         public RuntimeLabel(int index, int continuationStackDepth, int stackDepth)
18         {
19             Index = index;
20             ContinuationStackDepth = continuationStackDepth;
21             StackDepth = stackDepth;
22         }
23 
ToStringSystem.Linq.Expressions.Interpreter.RuntimeLabel24         public override string ToString()
25         {
26             return string.Format(CultureInfo.InvariantCulture, "->{0} C({1}) S({2})", Index, ContinuationStackDepth, StackDepth);
27         }
28     }
29 
30     internal sealed class BranchLabel
31     {
32         internal const int UnknownIndex = int.MinValue;
33         internal const int UnknownDepth = int.MinValue;
34 
35         private int _targetIndex = UnknownIndex;
36         private int _stackDepth = UnknownDepth;
37         private int _continuationStackDepth = UnknownDepth;
38 
39         // Offsets of forward branching instructions targeting this label
40         // that need to be updated after we emit the label.
41         private List<int> _forwardBranchFixups;
42 
43         internal int LabelIndex { get; set; } = UnknownIndex;
44         internal bool HasRuntimeLabel => LabelIndex != UnknownIndex;
45         internal int TargetIndex => _targetIndex;
46 
ToRuntimeLabel()47         internal RuntimeLabel ToRuntimeLabel()
48         {
49             Debug.Assert(_targetIndex != UnknownIndex && _stackDepth != UnknownDepth && _continuationStackDepth != UnknownDepth);
50             return new RuntimeLabel(_targetIndex, _continuationStackDepth, _stackDepth);
51         }
52 
Mark(InstructionList instructions)53         internal void Mark(InstructionList instructions)
54         {
55             //ContractUtils.Requires(_targetIndex == UnknownIndex && _stackDepth == UnknownDepth && _continuationStackDepth == UnknownDepth);
56 
57             _stackDepth = instructions.CurrentStackDepth;
58             _continuationStackDepth = instructions.CurrentContinuationsDepth;
59             _targetIndex = instructions.Count;
60 
61             if (_forwardBranchFixups != null)
62             {
63                 foreach (int branchIndex in _forwardBranchFixups)
64                 {
65                     FixupBranch(instructions, branchIndex);
66                 }
67                 _forwardBranchFixups = null;
68             }
69         }
70 
AddBranch(InstructionList instructions, int branchIndex)71         internal void AddBranch(InstructionList instructions, int branchIndex)
72         {
73             Debug.Assert(((_targetIndex == UnknownIndex) == (_stackDepth == UnknownDepth)));
74             Debug.Assert(((_targetIndex == UnknownIndex) == (_continuationStackDepth == UnknownDepth)));
75 
76             if (_targetIndex == UnknownIndex)
77             {
78                 if (_forwardBranchFixups == null)
79                 {
80                     _forwardBranchFixups = new List<int>();
81                 }
82                 _forwardBranchFixups.Add(branchIndex);
83             }
84             else
85             {
86                 FixupBranch(instructions, branchIndex);
87             }
88         }
89 
FixupBranch(InstructionList instructions, int branchIndex)90         internal void FixupBranch(InstructionList instructions, int branchIndex)
91         {
92             Debug.Assert(_targetIndex != UnknownIndex);
93             instructions.FixupBranch(branchIndex, _targetIndex - branchIndex);
94         }
95     }
96 }
97