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.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8 XX State machine used in the JIT XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
19 #include "smcommon.cpp"
22 // The array to map from EE opcodes (i.e. CEE_ ) to state machine opcodes (i.e. SM_ )
24 const SM_OPCODE smOpcodeMap[] = {
25 #define OPCODEMAP(eename, eestring, smname) smname,
26 #include "smopcodemap.def"
30 // ????????? How to make this method inlinable, since it refers to smOpcodeMap????
31 /* static */ SM_OPCODE CodeSeqSM::MapToSMOpcode(OPCODE opcode)
33 assert(opcode < CEE_COUNT);
35 SM_OPCODE smOpcode = smOpcodeMap[opcode];
36 assert(smOpcode < SM_COUNT);
40 void CodeSeqSM::Start(Compiler* comp)
44 JumpTableCells = gp_SMJumpTableCells;
45 StateWeights = gp_StateWeights;
51 void CodeSeqSM::Reset()
53 curState = SM_STATE_ID_START;
56 // Reset the state occurence counts
57 memset(StateMatchedCounts, 0, sizeof(StateMatchedCounts));
63 if (States[curState].term)
65 TermStateMatch(curState DEBUGARG(pComp->verbose));
69 void CodeSeqSM::Run(SM_OPCODE opcode DEBUGARG(int level))
71 SM_STATE_ID nextState;
72 SM_STATE_ID rollbackState;
74 SM_OPCODE opcodesToRevisit[MAX_CODE_SEQUENCE_LENGTH];
76 assert(level <= MAX_CODE_SEQUENCE_LENGTH);
79 nextState = GetDestState(curState, opcode);
83 // This is easy, Just go to the next state.
88 assert(curState != SM_STATE_ID_START);
90 if (States[curState].term)
92 TermStateMatch(curState DEBUGARG(pComp->verbose));
93 curState = SM_STATE_ID_START;
97 // This is hard. We need to rollback to the longest matched term state and restart from there.
99 rollbackState = States[curState].longestTermState;
100 TermStateMatch(rollbackState DEBUGARG(pComp->verbose));
102 assert(States[curState].length > States[rollbackState].length);
104 unsigned numOfOpcodesToRevisit = States[curState].length - States[rollbackState].length + 1;
105 assert(numOfOpcodesToRevisit > 1 &&
106 numOfOpcodesToRevisit <= MAX_CODE_SEQUENCE_LENGTH); // So it can fit in the local array opcodesToRevisit[]
108 SM_OPCODE* p = opcodesToRevisit + (numOfOpcodesToRevisit - 1);
112 // Fill in the local array:
113 for (unsigned i = 0; i < numOfOpcodesToRevisit - 1; ++i)
115 *(--p) = States[curState].opc;
116 curState = States[curState].prevState;
119 assert(curState == rollbackState);
121 // Now revisit these opcodes, starting from SM_STATE_ID_START.
122 curState = SM_STATE_ID_START;
123 for (p = opcodesToRevisit; p < opcodesToRevisit + numOfOpcodesToRevisit; ++p)
125 Run(*p DEBUGARG(level + 1));
129 SM_STATE_ID CodeSeqSM::GetDestState(SM_STATE_ID srcState, SM_OPCODE opcode)
131 assert(opcode < SM_COUNT);
133 JumpTableCell* pThisJumpTable = (JumpTableCell*)(((PBYTE)JumpTableCells) + States[srcState].jumpTableByteOffset);
135 JumpTableCell* cell = pThisJumpTable + opcode;
137 if (cell->srcState != srcState)
139 assert(cell->srcState == 0 ||
140 cell->srcState != srcState); // Either way means there is not outgoing edge from srcState.
145 return cell->destState;
151 const char* CodeSeqSM::StateDesc(SM_STATE_ID stateID)
153 static char s_StateDesc[500];
154 static SM_OPCODE s_StateDescOpcodes[MAX_CODE_SEQUENCE_LENGTH];
160 if (stateID == SM_STATE_ID_START)
166 SM_STATE_ID b = stateID;
168 while (States[b].prevState != 0)
170 s_StateDescOpcodes[i] = States[b].opc;
171 b = States[b].prevState;
175 assert(i == States[stateID].length && i > 0);
181 strcat(s_StateDesc, smOpcodeNames[s_StateDescOpcodes[i]]);
182 strcat(s_StateDesc, " -> ");
185 strcat(s_StateDesc, smOpcodeNames[s_StateDescOpcodes[0]]);