FunctionExecutionStateMachine.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeBasePch.h"
  6. #include "FunctionExecutionStateMachine.h"
  7. #include "Warnings.h"
  8. namespace Js
  9. {
  10. FunctionExecutionStateMachine::FunctionExecutionStateMachine() :
  11. owner(nullptr),
  12. executionState(ExecutionState::Interpreter),
  13. interpreterLimit(0),
  14. autoProfilingInterpreter0Limit(0),
  15. profilingInterpreter0Limit(0),
  16. autoProfilingInterpreter1Limit(0),
  17. simpleJitLimit(0),
  18. profilingInterpreter1Limit(0),
  19. interpretedCount(0),
  20. fullJitThreshold(0),
  21. fullJitRequeueThreshold(0),
  22. committedProfiledIterations(0),
  23. lastInterpretedCount(0)
  24. #if DBG
  25. ,initializedExecutionModeAndLimits(false)
  26. ,hasBeenReinitialized(false)
  27. #ifdef ENABLE_SCRIPT_DEBUGGING
  28. ,initDebuggerMode(DebuggerMode::NotDebugging)
  29. ,reinitDebuggerMode(DebuggerMode::NotDebugging)
  30. #endif
  31. #endif
  32. {
  33. }
  34. void FunctionExecutionStateMachine::InitializeExecutionModeAndLimits(FunctionBody* functionBody)
  35. {
  36. #if DBG
  37. #ifdef ENABLE_SCRIPT_DEBUGGING
  38. if (!initializedExecutionModeAndLimits)
  39. {
  40. initDebuggerMode = functionBody->GetDebuggerMode();
  41. }
  42. #endif
  43. initializedExecutionModeAndLimits = true;
  44. #endif
  45. // Assert we're either uninitialized, or being reinitialized on the same FunctionBody
  46. Assert(owner == nullptr || owner == functionBody);
  47. owner = functionBody;
  48. const ConfigFlagsTable &configFlags = Configuration::Global.flags;
  49. // AutoProfilingInterpreter might decide to not profile on the first run. For generator
  50. // functions, that means we will miss the profiling information on the first run when we resume
  51. // back to the function. This might result in lots of BailOnNoProfile even though we should have
  52. // profiling information. So always collect profile data for generators
  53. const bool skipAutoProfileForGenerator = functionBody->SkipAutoProfileForCoroutine();
  54. interpreterLimit = 0;
  55. autoProfilingInterpreter0Limit = skipAutoProfileForGenerator ? 0 : static_cast<uint16>(configFlags.AutoProfilingInterpreter0Limit);
  56. profilingInterpreter0Limit = static_cast<uint16>(configFlags.ProfilingInterpreter0Limit);
  57. autoProfilingInterpreter1Limit = skipAutoProfileForGenerator ? 0 : static_cast<uint16>(configFlags.AutoProfilingInterpreter1Limit);
  58. simpleJitLimit = static_cast<uint16>(configFlags.SimpleJitLimit);
  59. profilingInterpreter1Limit = static_cast<uint16>(configFlags.ProfilingInterpreter1Limit);
  60. // Based on which execution modes are disabled, calculate the number of additional iterations that need to be covered by
  61. // the execution mode that will scale with the full JIT threshold
  62. uint16 scale = 0;
  63. const bool doInterpreterProfile = owner->DoInterpreterProfile();
  64. if (!doInterpreterProfile)
  65. {
  66. scale +=
  67. autoProfilingInterpreter0Limit +
  68. profilingInterpreter0Limit +
  69. autoProfilingInterpreter1Limit +
  70. profilingInterpreter1Limit;
  71. autoProfilingInterpreter0Limit = 0;
  72. profilingInterpreter0Limit = 0;
  73. autoProfilingInterpreter1Limit = 0;
  74. profilingInterpreter1Limit = 0;
  75. }
  76. else if (!owner->DoInterpreterAutoProfile())
  77. {
  78. scale += autoProfilingInterpreter0Limit + autoProfilingInterpreter1Limit;
  79. autoProfilingInterpreter0Limit = 0;
  80. autoProfilingInterpreter1Limit = 0;
  81. if (!CONFIG_FLAG(NewSimpleJit))
  82. {
  83. simpleJitLimit += profilingInterpreter0Limit;
  84. profilingInterpreter0Limit = 0;
  85. }
  86. }
  87. if (!owner->DoSimpleJit())
  88. {
  89. if (!CONFIG_FLAG(NewSimpleJit) && doInterpreterProfile)
  90. {
  91. // The old simple JIT is off, but since it does profiling, it will be replaced with the profiling interpreter
  92. profilingInterpreter1Limit += simpleJitLimit;
  93. }
  94. else
  95. {
  96. scale += simpleJitLimit;
  97. }
  98. simpleJitLimit = 0;
  99. }
  100. if (PHASE_OFF(FullJitPhase, owner))
  101. {
  102. scale += profilingInterpreter1Limit;
  103. profilingInterpreter1Limit = 0;
  104. }
  105. uint16 fullJitThresholdConfig =
  106. static_cast<uint16>(
  107. (skipAutoProfileForGenerator ? 0 : configFlags.AutoProfilingInterpreter0Limit) +
  108. configFlags.ProfilingInterpreter0Limit +
  109. (skipAutoProfileForGenerator ? 0 : configFlags.AutoProfilingInterpreter1Limit) +
  110. configFlags.SimpleJitLimit +
  111. configFlags.ProfilingInterpreter1Limit);
  112. if (!configFlags.EnforceExecutionModeLimits)
  113. {
  114. /*
  115. Scale the full JIT threshold based on some heuristics:
  116. - If the % of code in loops is > 50, scale by 1
  117. - Byte-code size of code outside loops
  118. - If the size is < 50, scale by 1.2
  119. - If the size is < 100, scale by 1.4
  120. - If the size is >= 100, scale by 1.6
  121. */
  122. const uint loopPercentage = owner->GetByteCodeInLoopCount() * 100 / max(1u, owner->GetByteCodeCount());
  123. const int byteCodeSizeThresholdForInlineCandidate = CONFIG_FLAG(LoopInlineThreshold);
  124. bool delayFullJITThisFunc =
  125. (CONFIG_FLAG(DelayFullJITSmallFunc) > 0) && (owner->GetByteCodeWithoutLDACount() <= (uint)byteCodeSizeThresholdForInlineCandidate);
  126. if (loopPercentage <= 50 || delayFullJITThisFunc)
  127. {
  128. const uint straightLineSize = owner->GetByteCodeCount() - owner->GetByteCodeInLoopCount();
  129. double fullJitDelayMultiplier;
  130. if (delayFullJITThisFunc)
  131. {
  132. fullJitDelayMultiplier = CONFIG_FLAG(DelayFullJITSmallFunc) / 10.0;
  133. }
  134. else if (straightLineSize < 50)
  135. {
  136. fullJitDelayMultiplier = 1.2;
  137. }
  138. else if (straightLineSize < 100)
  139. {
  140. fullJitDelayMultiplier = 1.4;
  141. }
  142. else
  143. {
  144. fullJitDelayMultiplier = 1.6;
  145. }
  146. const uint16 newFullJitThreshold = static_cast<uint16>(fullJitThresholdConfig * fullJitDelayMultiplier);
  147. scale += newFullJitThreshold - fullJitThresholdConfig;
  148. fullJitThresholdConfig = newFullJitThreshold;
  149. }
  150. }
  151. Assert(fullJitThresholdConfig >= scale);
  152. fullJitThreshold = fullJitThresholdConfig - scale;
  153. SetInterpretedCount(0);
  154. SetDefaultInterpreterExecutionMode();
  155. SetFullJitThreshold(fullJitThresholdConfig);
  156. TryTransitionToNextInterpreterExecutionMode();
  157. }
  158. void FunctionExecutionStateMachine::ReinitializeExecutionModeAndLimits(FunctionBody* functionBody)
  159. {
  160. #if DBG
  161. hasBeenReinitialized = true;
  162. #ifdef ENABLE_SCRIPT_DEBUGGING
  163. reinitDebuggerMode = functionBody->GetDebuggerMode();
  164. #endif
  165. #endif
  166. // TODO: Investigate what it would take to make this invariant hold. Currently fails in AsmJS tests
  167. // Assert(initializedExecutionModeAndLimits);
  168. fullJitRequeueThreshold = 0;
  169. committedProfiledIterations = 0;
  170. InitializeExecutionModeAndLimits(functionBody);
  171. }
  172. bool FunctionExecutionStateMachine::InterpretedSinceCallCountCollection() const
  173. {
  174. return interpretedCount != lastInterpretedCount;
  175. }
  176. void FunctionExecutionStateMachine::CollectInterpretedCounts()
  177. {
  178. lastInterpretedCount = interpretedCount;
  179. }
  180. ExecutionMode FunctionExecutionStateMachine::GetExecutionMode() const
  181. {
  182. ExecutionMode executionMode = StateToMode(executionState);
  183. VerifyExecutionMode(executionMode);
  184. return executionMode;
  185. }
  186. void FunctionExecutionStateMachine::SetExecutionState(ExecutionState state)
  187. {
  188. // TODO: Investigate what it would take to make this invariant hold
  189. // Assert(state == GetDefaultInterpreterExecutionState() || IsTerminalState(state));
  190. VerifyExecutionMode(StateToMode(state));
  191. executionState = state;
  192. }
  193. void FunctionExecutionStateMachine::SetAsmJsExecutionMode()
  194. {
  195. SetExecutionState(ExecutionState::FullJit);
  196. }
  197. void FunctionExecutionStateMachine::SetDefaultInterpreterExecutionMode()
  198. {
  199. SetExecutionState(GetDefaultInterpreterExecutionState());
  200. }
  201. FunctionExecutionStateMachine::ExecutionState FunctionExecutionStateMachine::GetDefaultInterpreterExecutionState() const
  202. {
  203. if (!owner->DoInterpreterProfile())
  204. {
  205. VerifyExecutionMode(ExecutionMode::Interpreter);
  206. return ExecutionState::Interpreter;
  207. }
  208. else if (owner->DoInterpreterAutoProfile())
  209. {
  210. VerifyExecutionMode(ExecutionMode::AutoProfilingInterpreter);
  211. return ExecutionState::AutoProfilingInterpreter0;
  212. }
  213. else
  214. {
  215. VerifyExecutionMode(ExecutionMode::ProfilingInterpreter);
  216. return ExecutionState::ProfilingInterpreter0;
  217. }
  218. }
  219. ExecutionMode FunctionExecutionStateMachine::GetInterpreterExecutionMode(const bool isPostBailout)
  220. {
  221. Assert(initializedExecutionModeAndLimits);
  222. if (isPostBailout && owner->DoInterpreterProfile())
  223. {
  224. return ExecutionMode::ProfilingInterpreter;
  225. }
  226. switch (GetExecutionMode())
  227. {
  228. case ExecutionMode::Interpreter:
  229. case ExecutionMode::AutoProfilingInterpreter:
  230. case ExecutionMode::ProfilingInterpreter:
  231. return GetExecutionMode();
  232. case ExecutionMode::SimpleJit:
  233. if (CONFIG_FLAG(NewSimpleJit))
  234. {
  235. return StateToMode(GetDefaultInterpreterExecutionState());
  236. }
  237. // fall through
  238. case ExecutionMode::FullJit:
  239. {
  240. const ExecutionMode executionMode =
  241. owner->DoInterpreterProfile() ? ExecutionMode::ProfilingInterpreter : ExecutionMode::Interpreter;
  242. VerifyExecutionMode(executionMode);
  243. return executionMode;
  244. }
  245. default:
  246. Assert(false);
  247. __assume(false);
  248. }
  249. }
  250. bool FunctionExecutionStateMachine::IsInterpreterExecutionMode() const
  251. {
  252. return GetExecutionMode() <= ExecutionMode::ProfilingInterpreter;
  253. }
  254. uint16 FunctionExecutionStateMachine::GetSimpleJitExecutedIterations() const
  255. {
  256. Assert(initializedExecutionModeAndLimits);
  257. Assert(GetExecutionMode() == ExecutionMode::SimpleJit);
  258. FunctionEntryPointInfo *const simpleJitEntryPointInfo = owner->GetSimpleJitEntryPointInfo();
  259. if (!simpleJitEntryPointInfo)
  260. {
  261. return 0;
  262. }
  263. // Simple JIT counts down and transitions on overflow
  264. const uint32 callCount = simpleJitEntryPointInfo->callsCount;
  265. Assert(simpleJitLimit == 0 ? callCount == 0 : simpleJitLimit > callCount);
  266. return callCount == 0 ?
  267. static_cast<uint16>(simpleJitLimit) :
  268. static_cast<uint16>(simpleJitLimit) - static_cast<uint16>(callCount) - 1;
  269. }
  270. void FunctionExecutionStateMachine::SetSimpleJitCallCount(const uint16 simpleJitLimit) const
  271. {
  272. Assert(GetExecutionMode() == ExecutionMode::SimpleJit);
  273. Assert(owner->GetDefaultFunctionEntryPointInfo() == owner->GetSimpleJitEntryPointInfo());
  274. // Simple JIT counts down and transitions on overflow
  275. const uint8 limit = static_cast<uint8>(min(0xffui16, simpleJitLimit));
  276. owner->GetSimpleJitEntryPointInfo()->callsCount = limit == 0 ? 0 : limit - 1;
  277. }
  278. void FunctionExecutionStateMachine::SetFullJitRequeueThreshold(const uint16 newFullJitRequeueThreshold)
  279. {
  280. fullJitRequeueThreshold = newFullJitRequeueThreshold;
  281. }
  282. void FunctionExecutionStateMachine::SetFullJitThreshold(const uint16 newFullJitThreshold, const bool skipSimpleJit)
  283. {
  284. Assert(initializedExecutionModeAndLimits);
  285. Assert(GetExecutionMode() != ExecutionMode::FullJit);
  286. int scale = newFullJitThreshold - fullJitThreshold;
  287. if (scale == 0)
  288. {
  289. VerifyExecutionModeLimits();
  290. return;
  291. }
  292. fullJitThreshold = newFullJitThreshold;
  293. const auto ScaleLimit = [&](uint16 &limit) -> bool
  294. {
  295. Assert(scale != 0);
  296. const int limitScale = max(-static_cast<int>(limit), scale);
  297. const int newLimit = limit + limitScale;
  298. Assert(static_cast<int>(static_cast<uint16>(newLimit)) == newLimit);
  299. limit = static_cast<uint16>(newLimit);
  300. scale -= limitScale;
  301. Assert(limit == 0 || scale == 0);
  302. if (&limit == &simpleJitLimit)
  303. {
  304. FunctionEntryPointInfo *const simpleJitEntryPointInfo = owner->GetSimpleJitEntryPointInfo();
  305. if (owner->GetDefaultFunctionEntryPointInfo() == simpleJitEntryPointInfo)
  306. {
  307. Assert(GetExecutionMode() == ExecutionMode::SimpleJit);
  308. const int newSimpleJitCallCount = max(0, (int)simpleJitEntryPointInfo->callsCount + limitScale);
  309. Assert(static_cast<int>(static_cast<uint16>(newSimpleJitCallCount)) == newSimpleJitCallCount);
  310. SetSimpleJitCallCount(static_cast<uint16>(newSimpleJitCallCount));
  311. }
  312. }
  313. return scale == 0;
  314. };
  315. /*
  316. Determine which execution mode's limit scales with the full JIT threshold, in order of preference:
  317. - New simple JIT
  318. - Auto-profiling interpreter 1
  319. - Auto-profiling interpreter 0
  320. - Interpreter
  321. - Profiling interpreter 0 (when using old simple JIT)
  322. - Old simple JIT
  323. - Profiling interpreter 1
  324. - Profiling interpreter 0 (when using new simple JIT)
  325. */
  326. const bool doSimpleJit = owner->DoSimpleJit();
  327. const bool doInterpreterProfile = owner->DoInterpreterProfile();
  328. const bool fullyScaled =
  329. (CONFIG_FLAG(NewSimpleJit) && doSimpleJit && ScaleLimit(simpleJitLimit)) ||
  330. (
  331. doInterpreterProfile
  332. ? owner->DoInterpreterAutoProfile() &&
  333. (ScaleLimit(autoProfilingInterpreter1Limit) || ScaleLimit(autoProfilingInterpreter0Limit))
  334. : ScaleLimit(interpreterLimit)
  335. ) ||
  336. (
  337. CONFIG_FLAG(NewSimpleJit)
  338. ? doInterpreterProfile &&
  339. (ScaleLimit(profilingInterpreter1Limit) || ScaleLimit(profilingInterpreter0Limit))
  340. : (doInterpreterProfile && ScaleLimit(profilingInterpreter0Limit)) ||
  341. (doSimpleJit && ScaleLimit(simpleJitLimit)) ||
  342. (doInterpreterProfile && ScaleLimit(profilingInterpreter1Limit))
  343. );
  344. Assert(fullyScaled);
  345. Assert(scale == 0);
  346. if (GetExecutionMode() != ExecutionMode::SimpleJit)
  347. {
  348. Assert(IsInterpreterExecutionMode());
  349. if (simpleJitLimit != 0 &&
  350. (skipSimpleJit || simpleJitLimit < DEFAULT_CONFIG_MinSimpleJitIterations) &&
  351. !PHASE_FORCE(Phase::SimpleJitPhase, owner))
  352. {
  353. // Simple JIT code has not yet been generated, and was either requested to be skipped, or the limit was scaled
  354. // down too much. Skip simple JIT by moving any remaining iterations to an equivalent interpreter execution
  355. // mode.
  356. (CONFIG_FLAG(NewSimpleJit) ? autoProfilingInterpreter1Limit : profilingInterpreter1Limit) += simpleJitLimit;
  357. simpleJitLimit = 0;
  358. TryTransitionToNextInterpreterExecutionMode();
  359. }
  360. }
  361. VerifyExecutionModeLimits();
  362. }
  363. FunctionExecutionStateMachine::ExecutionState FunctionExecutionStateMachine::ModeToState(ExecutionMode mode) const
  364. {
  365. switch (mode)
  366. {
  367. case ExecutionMode::AutoProfilingInterpreter:
  368. return ExecutionState::AutoProfilingInterpreter0;
  369. case ExecutionMode::ProfilingInterpreter:
  370. return ExecutionState::ProfilingInterpreter0;
  371. case ExecutionMode::SimpleJit:
  372. return ExecutionState::SimpleJit;
  373. case ExecutionMode::FullJit:
  374. return ExecutionState::FullJit;
  375. default:
  376. Assert(!"Unexpected ExecutionMode for ExecutionState");
  377. // fall through
  378. case ExecutionMode::Interpreter:
  379. return ExecutionState::Interpreter;
  380. }
  381. }
  382. ExecutionMode FunctionExecutionStateMachine::StateToMode(ExecutionState state) const
  383. {
  384. switch (state)
  385. {
  386. case ExecutionState::AutoProfilingInterpreter0:
  387. case ExecutionState::AutoProfilingInterpreter1:
  388. return ExecutionMode::AutoProfilingInterpreter;
  389. case ExecutionState::ProfilingInterpreter0:
  390. case ExecutionState::ProfilingInterpreter1:
  391. return ExecutionMode::ProfilingInterpreter;
  392. case ExecutionState::SimpleJit:
  393. return ExecutionMode::SimpleJit;
  394. case ExecutionState::FullJit:
  395. return ExecutionMode::FullJit;
  396. default:
  397. Assert(!"Unexpected ExecutionState for ExecutionMode");
  398. // fall through
  399. case ExecutionState::Interpreter:
  400. return ExecutionMode::Interpreter;
  401. }
  402. }
  403. uint16& FunctionExecutionStateMachine::GetStateLimit(ExecutionState state)
  404. {
  405. switch (state)
  406. {
  407. case ExecutionState::Interpreter:
  408. return interpreterLimit;
  409. case ExecutionState::AutoProfilingInterpreter0:
  410. return autoProfilingInterpreter0Limit;
  411. case ExecutionState::AutoProfilingInterpreter1:
  412. return autoProfilingInterpreter1Limit;
  413. case ExecutionState::ProfilingInterpreter0:
  414. return profilingInterpreter0Limit;
  415. case ExecutionState::ProfilingInterpreter1:
  416. return profilingInterpreter1Limit;
  417. case ExecutionState::SimpleJit:
  418. return simpleJitLimit;
  419. default:
  420. Assert(!"Unexpected ExecutionState for limit");
  421. return interpreterLimit;
  422. }
  423. }
  424. // An execution state is terminal if the current FunctionExecutionStateMachine's limits
  425. // allow the state to continue to run.
  426. // FullJit is always a terminal state and is the last terminal state.
  427. bool FunctionExecutionStateMachine::IsTerminalState(ExecutionState state)
  428. {
  429. return state == ExecutionState::FullJit || GetStateLimit(state) != 0;
  430. }
  431. // Safely moves from one execution mode to another and updates appropriate class members for the next
  432. // mode. Note that there are other functions that modify execution state that do not involve this function.
  433. // This function transitions ExecutionMode as ExecutionState in the following order:
  434. //
  435. // +-- Interpreter
  436. // |
  437. // | AutoProfilingInterpreter --+
  438. // | | ^ |
  439. // | | | v
  440. // | | | SimpleJit
  441. // | v | |
  442. // | ProfilingInterpreter <----+
  443. // | |
  444. // | |
  445. // | v
  446. // +-> FullJit
  447. //
  448. // Transition to the next mode occurs when the limit for the current execution mode reaches 0.
  449. // Returns true when a transition occurs (i.e., the execution state was updated since the beginning of
  450. // this function call). Otherwise, returns false to indicate no change in state.
  451. // See more details of each mode in ExecutionModes.h
  452. bool FunctionExecutionStateMachine::TryTransitionToNextExecutionMode()
  453. {
  454. Assert(initializedExecutionModeAndLimits);
  455. bool isStateChanged = false;
  456. if (executionState != ExecutionState::FullJit)
  457. {
  458. bool isTransitionNeeded;
  459. uint16& stateLimit = GetStateLimit(executionState);
  460. FunctionEntryPointInfo *const simpleJitEntryPointInfo = owner->GetSimpleJitEntryPointInfo();
  461. // Determine if the current state should not transition when
  462. // - for non-JITed states, the interpreted count is less than the limit
  463. // - for JITed states (specifically, SimpleJIT because it can transition), the callsCount
  464. // is non-zero. CallsCount starts at the limit and decrements to 0 to indicate transition.
  465. if ((executionState != ExecutionState::SimpleJit && GetInterpretedCount() < stateLimit)
  466. || (simpleJitEntryPointInfo != nullptr && simpleJitEntryPointInfo->callsCount > 0))
  467. {
  468. // Since the current state is under its limit, no transition is needed.
  469. // Simply verify the current state's execution mode before returning.
  470. isTransitionNeeded = false;
  471. }
  472. else
  473. {
  474. // Since the current state's limit is reached, transition from this state to the next state
  475. // First, save data from the current state
  476. CommitExecutedIterations(stateLimit, stateLimit);
  477. // Then, reset data for the next state
  478. SetInterpretedCount(0);
  479. isTransitionNeeded = true;
  480. }
  481. if (isTransitionNeeded)
  482. {
  483. // Keep advancing the state until a terminal state is found or until there are no more
  484. // states to reach. The path of advancement is described in the banner comment above.
  485. ExecutionState newState = executionState;
  486. while (isTransitionNeeded && !IsTerminalState(newState))
  487. {
  488. if (newState != ExecutionState::Interpreter)
  489. {
  490. // Most states simply advance to the next state
  491. newState = static_cast<ExecutionState>(static_cast<uint8>(newState) + 1);
  492. }
  493. else
  494. {
  495. // Interpreter advances straight to FullJit
  496. newState = ExecutionState::FullJit;
  497. }
  498. // If FullJit is the next state, but FullJit is disabled, then no transition
  499. // is needed.
  500. if (newState == ExecutionState::FullJit && PHASE_OFF(FullJitPhase, owner))
  501. {
  502. isTransitionNeeded = false;
  503. }
  504. else
  505. {
  506. // Otherwise, transition is needed because there is new state available
  507. isTransitionNeeded = true;
  508. }
  509. }
  510. // Only update the execution state when the new state is a terminal state
  511. if (isTransitionNeeded && IsTerminalState(newState))
  512. {
  513. Assert(newState != executionState);
  514. SetExecutionState(newState);
  515. isStateChanged = true;
  516. }
  517. }
  518. }
  519. return isStateChanged;
  520. }
  521. void FunctionExecutionStateMachine::TryTransitionToNextInterpreterExecutionMode()
  522. {
  523. Assert(IsInterpreterExecutionMode());
  524. TryTransitionToNextExecutionMode();
  525. SetExecutionState(ModeToState(GetInterpreterExecutionMode(false)));
  526. }
  527. bool FunctionExecutionStateMachine::TryTransitionToJitExecutionMode()
  528. {
  529. const ExecutionMode previousExecutionMode = GetExecutionMode();
  530. TryTransitionToNextExecutionMode();
  531. switch (GetExecutionMode())
  532. {
  533. case ExecutionMode::SimpleJit:
  534. break;
  535. case ExecutionMode::FullJit:
  536. if (fullJitRequeueThreshold == 0)
  537. {
  538. break;
  539. }
  540. --fullJitRequeueThreshold;
  541. return false;
  542. default:
  543. return false;
  544. }
  545. if (GetExecutionMode() != previousExecutionMode)
  546. {
  547. owner->TraceExecutionMode();
  548. }
  549. return true;
  550. }
  551. void FunctionExecutionStateMachine::TransitionToSimpleJitExecutionMode()
  552. {
  553. CommitExecutedIterations();
  554. interpreterLimit = 0;
  555. autoProfilingInterpreter0Limit = 0;
  556. profilingInterpreter0Limit = 0;
  557. autoProfilingInterpreter1Limit = 0;
  558. fullJitThreshold = simpleJitLimit + profilingInterpreter1Limit;
  559. VerifyExecutionModeLimits();
  560. SetExecutionState(ExecutionState::SimpleJit);
  561. }
  562. void FunctionExecutionStateMachine::TransitionToFullJitExecutionMode()
  563. {
  564. CommitExecutedIterations();
  565. interpreterLimit = 0;
  566. autoProfilingInterpreter0Limit = 0;
  567. profilingInterpreter0Limit = 0;
  568. autoProfilingInterpreter1Limit = 0;
  569. simpleJitLimit = 0;
  570. profilingInterpreter1Limit = 0;
  571. fullJitThreshold = 0;
  572. VerifyExecutionModeLimits();
  573. SetExecutionState(ExecutionState::FullJit);
  574. }
  575. void FunctionExecutionStateMachine::SetIsSpeculativeJitCandidate()
  576. {
  577. // This function is a candidate for speculative JIT. Ensure that it is profiled immediately by transitioning out of the
  578. // auto-profiling interpreter mode.
  579. if (GetExecutionMode() != ExecutionMode::AutoProfilingInterpreter || GetProfiledIterations() != 0)
  580. {
  581. return;
  582. }
  583. owner->TraceExecutionMode("IsSpeculativeJitCandidate (before)");
  584. if (autoProfilingInterpreter0Limit != 0)
  585. {
  586. (profilingInterpreter0Limit == 0 ? profilingInterpreter0Limit : autoProfilingInterpreter1Limit) +=
  587. autoProfilingInterpreter0Limit;
  588. autoProfilingInterpreter0Limit = 0;
  589. }
  590. else if (profilingInterpreter0Limit == 0)
  591. {
  592. profilingInterpreter0Limit += autoProfilingInterpreter1Limit;
  593. autoProfilingInterpreter1Limit = 0;
  594. }
  595. owner->TraceExecutionMode("IsSpeculativeJitCandidate");
  596. TryTransitionToNextInterpreterExecutionMode();
  597. }
  598. void FunctionExecutionStateMachine::ResetSimpleJitLimit()
  599. {
  600. Assert(initializedExecutionModeAndLimits);
  601. SetExecutionState(ExecutionState::SimpleJit);
  602. const uint16 simpleJitNewLimit = static_cast<uint8>(Configuration::Global.flags.SimpleJitLimit);
  603. if (simpleJitLimit < simpleJitNewLimit)
  604. {
  605. fullJitThreshold += simpleJitNewLimit - simpleJitLimit;
  606. simpleJitLimit = simpleJitNewLimit;
  607. }
  608. SetInterpretedCount(0);
  609. }
  610. uint16 FunctionExecutionStateMachine::GetProfiledIterations() const
  611. {
  612. Assert(initializedExecutionModeAndLimits);
  613. uint16 profiledIterations = committedProfiledIterations;
  614. switch (GetExecutionMode())
  615. {
  616. case ExecutionMode::ProfilingInterpreter:
  617. {
  618. uint32 interpretedCount = GetInterpretedCount();
  619. const uint16 clampedInterpretedCount =
  620. interpretedCount <= UINT16_MAX
  621. ? static_cast<uint16>(interpretedCount)
  622. : UINT16_MAX;
  623. const uint16 newProfiledIterations = profiledIterations + clampedInterpretedCount;
  624. profiledIterations = newProfiledIterations >= profiledIterations ? newProfiledIterations : UINT16_MAX;
  625. break;
  626. }
  627. case ExecutionMode::SimpleJit:
  628. if (!CONFIG_FLAG(NewSimpleJit))
  629. {
  630. const uint16 newProfiledIterations = profiledIterations + GetSimpleJitExecutedIterations();
  631. profiledIterations = newProfiledIterations >= profiledIterations ? newProfiledIterations : UINT16_MAX;
  632. }
  633. break;
  634. }
  635. return profiledIterations;
  636. }
  637. void FunctionExecutionStateMachine::CommitExecutedIterations()
  638. {
  639. Assert(initializedExecutionModeAndLimits);
  640. switch (GetExecutionMode())
  641. {
  642. case ExecutionMode::Interpreter:
  643. CommitExecutedIterations(interpreterLimit, GetInterpretedCount());
  644. break;
  645. case ExecutionMode::AutoProfilingInterpreter:
  646. CommitExecutedIterations(
  647. autoProfilingInterpreter0Limit == 0 && profilingInterpreter0Limit == 0
  648. ? autoProfilingInterpreter1Limit
  649. : autoProfilingInterpreter0Limit,
  650. GetInterpretedCount());
  651. break;
  652. case ExecutionMode::ProfilingInterpreter:
  653. CommitExecutedIterations(
  654. owner->GetSimpleJitEntryPointInfo()
  655. ? profilingInterpreter1Limit
  656. : profilingInterpreter0Limit,
  657. GetInterpretedCount());
  658. break;
  659. case ExecutionMode::SimpleJit:
  660. CommitExecutedIterations(simpleJitLimit, GetSimpleJitExecutedIterations());
  661. break;
  662. case ExecutionMode::FullJit:
  663. break;
  664. default:
  665. Assert(false);
  666. __assume(false);
  667. }
  668. }
  669. void FunctionExecutionStateMachine::CommitExecutedIterations(uint16 &limit, const uint executedIterations)
  670. {
  671. Assert(initializedExecutionModeAndLimits);
  672. Assert(
  673. &limit == &interpreterLimit ||
  674. &limit == &autoProfilingInterpreter0Limit ||
  675. &limit == &profilingInterpreter0Limit ||
  676. &limit == &autoProfilingInterpreter1Limit ||
  677. &limit == &simpleJitLimit ||
  678. &limit == &profilingInterpreter1Limit);
  679. const uint16 clampedExecutedIterations = executedIterations >= limit ? limit : static_cast<uint16>(executedIterations);
  680. Assert(fullJitThreshold >= clampedExecutedIterations);
  681. fullJitThreshold -= clampedExecutedIterations;
  682. limit -= clampedExecutedIterations;
  683. VerifyExecutionModeLimits();
  684. if (&limit == &profilingInterpreter0Limit ||
  685. (!CONFIG_FLAG(NewSimpleJit) && &limit == &simpleJitLimit) ||
  686. &limit == &profilingInterpreter1Limit)
  687. {
  688. const uint16 newCommittedProfiledIterations = committedProfiledIterations + clampedExecutedIterations;
  689. committedProfiledIterations =
  690. newCommittedProfiledIterations >= committedProfiledIterations ? newCommittedProfiledIterations : UINT16_MAX;
  691. }
  692. }
  693. void FunctionExecutionStateMachine::VerifyExecutionModeLimits() const
  694. {
  695. Assert(initializedExecutionModeAndLimits);
  696. Assert(
  697. (
  698. interpreterLimit +
  699. autoProfilingInterpreter0Limit +
  700. profilingInterpreter0Limit +
  701. autoProfilingInterpreter1Limit +
  702. simpleJitLimit +
  703. profilingInterpreter1Limit
  704. ) == fullJitThreshold);
  705. }
  706. void FunctionExecutionStateMachine::VerifyExecutionMode(const ExecutionMode executionMode) const
  707. {
  708. #if DBG
  709. Assert(initializedExecutionModeAndLimits);
  710. Assert(executionMode < ExecutionMode::Count);
  711. switch (executionMode)
  712. {
  713. case ExecutionMode::Interpreter:
  714. Assert(!owner->DoInterpreterProfile());
  715. break;
  716. case ExecutionMode::AutoProfilingInterpreter:
  717. Assert(owner->DoInterpreterProfile());
  718. Assert(owner->DoInterpreterAutoProfile());
  719. break;
  720. case ExecutionMode::ProfilingInterpreter:
  721. Assert(owner->DoInterpreterProfile());
  722. break;
  723. case ExecutionMode::SimpleJit:
  724. Assert(owner->DoSimpleJit());
  725. break;
  726. case ExecutionMode::FullJit:
  727. Assert(!PHASE_OFF(FullJitPhase, owner));
  728. break;
  729. default:
  730. Assert(false);
  731. __assume(false);
  732. }
  733. #else
  734. UNREFERENCED_PARAMETER(executionMode);
  735. #endif
  736. }
  737. void FunctionExecutionStateMachine::PrintLimits() const
  738. {
  739. Output::Print(
  740. _u("limits: %hu.%hu.%hu.%hu.%hu = %hu"),
  741. interpreterLimit + autoProfilingInterpreter0Limit,
  742. profilingInterpreter0Limit,
  743. autoProfilingInterpreter1Limit,
  744. simpleJitLimit,
  745. profilingInterpreter1Limit,
  746. fullJitThreshold);
  747. }
  748. void FunctionExecutionStateMachine::AssertIsInitialized() const
  749. {
  750. #if DBG
  751. Assert(initializedExecutionModeAndLimits);
  752. Assert(owner != nullptr);
  753. #endif
  754. }
  755. }