Merge remote-tracking branch 'upstream/master' into feature
[platform/upstream/coreclr.git] / src / jit / sm.cpp
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 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                 State machine used in the JIT                             XX
9 XX                                                                           XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 */
13
14 #include "jitpch.h"
15 #ifdef _MSC_VER
16 #pragma hdrstop
17 #endif
18
19 #include "smcommon.cpp"
20
21 //
22 // The array to map from EE opcodes (i.e. CEE_ ) to state machine opcodes (i.e. SM_ )
23 //
24 const SM_OPCODE smOpcodeMap[] =
25 {
26     #define OPCODEMAP(eename,eestring,smname) smname,
27     #include "smopcodemap.def"
28     #undef  OPCODEMAP
29 };
30
31
32 // ????????? How to make this method inlinable, since it refers to smOpcodeMap????
33 /* static */ SM_OPCODE    CodeSeqSM::MapToSMOpcode(OPCODE opcode)
34 {
35     assert(opcode < CEE_COUNT);
36
37     SM_OPCODE smOpcode = smOpcodeMap[opcode];
38     assert(smOpcode < SM_COUNT);
39     return smOpcode;
40 }
41
42 void CodeSeqSM::Start(Compiler * comp) 
43 {    
44     pComp             = comp;
45     States            = gp_SMStates;
46     JumpTableCells    = gp_SMJumpTableCells;
47     StateWeights      = gp_StateWeights;
48     NativeSize        = 0;
49
50     Reset();  
51 }
52
53 void CodeSeqSM::Reset() 
54 {
55     curState      = SM_STATE_ID_START;
56
57 #ifdef DEBUG
58     // Reset the state occurence counts
59     memset(StateMatchedCounts, 0, sizeof(StateMatchedCounts));
60 #endif
61
62 }
63
64 void CodeSeqSM::End() 
65 {
66     if (States[curState].term)
67     {
68         TermStateMatch(curState DEBUGARG(pComp->verbose));
69     }
70 }
71
72 void  CodeSeqSM::Run(SM_OPCODE opcode DEBUGARG(int level))
73 {    
74     SM_STATE_ID nextState;
75     SM_STATE_ID rollbackState;
76
77     SM_OPCODE   opcodesToRevisit[MAX_CODE_SEQUENCE_LENGTH];
78
79     assert(level<=MAX_CODE_SEQUENCE_LENGTH);
80
81 _Next:
82     nextState = GetDestState(curState, opcode);    
83
84     if (nextState != 0)
85     {
86         // This is easy, Just go to the next state.
87         curState = nextState;
88         return;            
89     }
90
91     assert(curState != SM_STATE_ID_START); 
92         
93     if (States[curState].term)
94     {
95         TermStateMatch(curState DEBUGARG(pComp->verbose));
96         curState = SM_STATE_ID_START;
97         goto _Next;
98     }
99         
100     // This is hard. We need to rollback to the longest matched term state and restart from there.
101
102     rollbackState = States[curState].longestTermState;
103     TermStateMatch(rollbackState DEBUGARG(pComp->verbose));
104
105     assert(States[curState].length > States[rollbackState].length);
106      
107     unsigned numOfOpcodesToRevisit = States[curState].length - States[rollbackState].length + 1;
108     assert(numOfOpcodesToRevisit > 1   &&
109            numOfOpcodesToRevisit <= MAX_CODE_SEQUENCE_LENGTH); // So it can fit in the local array opcodesToRevisit[]
110
111     SM_OPCODE * p = opcodesToRevisit + (numOfOpcodesToRevisit - 1);
112
113     *p = opcode;
114
115     // Fill in the local array:
116     for (unsigned i = 0; i<numOfOpcodesToRevisit-1; ++i) 
117     {
118         * (--p) = States[curState].opc;
119         curState = States[curState].prevState;
120     }
121
122     assert(curState == rollbackState);    
123
124     // Now revisit these opcodes, starting from SM_STATE_ID_START.
125     curState = SM_STATE_ID_START;
126     for (p = opcodesToRevisit; p< opcodesToRevisit + numOfOpcodesToRevisit; ++p)
127     {
128         Run(*p DEBUGARG(level+1));
129     }    
130 }
131
132
133 SM_STATE_ID  CodeSeqSM::GetDestState(SM_STATE_ID srcState, SM_OPCODE opcode)
134 {
135     assert(opcode < SM_COUNT);
136          
137     JumpTableCell * pThisJumpTable = (JumpTableCell * )(((PBYTE)JumpTableCells) + States[srcState].jumpTableByteOffset);
138
139     JumpTableCell * cell = pThisJumpTable+opcode;
140
141     if (cell->srcState != srcState)
142     {
143         assert(cell->srcState == 0 || cell->srcState != srcState); // Either way means there is not outgoing edge from srcState.
144         return 0;
145     }
146     else
147     {
148         return cell->destState; 
149     }
150 }
151
152 #ifdef DEBUG
153
154 const char * CodeSeqSM::StateDesc(SM_STATE_ID stateID)
155 {    
156     static char      s_StateDesc[500];
157     static SM_OPCODE s_StateDescOpcodes[MAX_CODE_SEQUENCE_LENGTH];
158
159     if (stateID == 0)
160         return "invalid";
161     
162     if (stateID == SM_STATE_ID_START)
163         return "start";    
164
165     unsigned i = 0;
166     
167     SM_STATE_ID b = stateID; 
168  
169     while (States[b].prevState != 0)
170     {
171         s_StateDescOpcodes[i] = States[b].opc;
172         b = States[b].prevState;
173         ++i;
174     }
175
176     assert(i == States[stateID].length && i>0);
177
178     * s_StateDesc = 0;
179     
180     while (--i>0)
181     {
182         strcat(s_StateDesc, smOpcodeNames[s_StateDescOpcodes[i]]);
183         strcat(s_StateDesc, " -> ");
184     }
185
186     strcat(s_StateDesc, smOpcodeNames[s_StateDescOpcodes[0]]); 
187
188     return s_StateDesc;
189 }
190
191 #endif // DEBUG
192