FunctionExecutionTest.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  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 "stdafx.h"
  6. #pragma warning(disable:26434) // Function definition hides non-virtual function in base class
  7. #pragma warning(disable:26439) // Implicit noexcept
  8. #pragma warning(disable:26451) // Arithmetic overflow
  9. #pragma warning(disable:26495) // Uninitialized member variable
  10. #include "catch.hpp"
  11. #include "FunctionExecutionTest.h"
  12. // Definition of tests that exercise FunctionExecutionStateMachine
  13. namespace FunctionExecutionTest
  14. {
  15. // Simple test case to validate that the state machine was created.
  16. TEST_CASE("FuncExe_BasicTest")
  17. {
  18. Js::FunctionExecutionStateMachine f;
  19. Js::FunctionBody body(false, false, false);
  20. f.InitializeExecutionModeAndLimits(&body);
  21. CHECK(f.GetExecutionMode() == ExecutionMode::Interpreter);
  22. }
  23. // Mimics script that repeatedly calls a function (not in a loop, but multiple times). This pattern hits all execution modes:
  24. //ExecutionMode - function : testfn((#1.1), #2), mode : AutoProfilingInterpreter, size : 36, limits : 12.4.89.21.0 = 126, event : IsSpeculativeJitCandidate(before)
  25. //ExecutionMode - function : testfn((#1.1), #2), mode : AutoProfilingInterpreter, size : 36, limits : 0.4.101.21.0 = 126, event : IsSpeculativeJitCandidate
  26. //ExecutionMode - function : testfn((#1.1), #2), mode : ProfilingInterpreter, size : 36, limits : 0.4.101.21.0 = 126
  27. //ExecutionMode - function : testfn((#1.1), #2), mode : AutoProfilingInterpreter, size : 36, limits : 0.0.101.21.0 = 122
  28. //ExecutionMode - function : testfn((#1.1), #2), mode : SimpleJit, size : 36, limits : 0.0.0.21.0 = 21
  29. //ExecutionMode - function : testfn((#1.1), #2), mode : SimpleJit, size : 36, limits : 0.0.0.21.0 = 21
  30. //ExecutionMode - function : testfn((#1.1), #2), mode : FullJit, size : 36, limits : 0.0.0.0.0 = 0
  31. template <bool TFullJitPhase, ExecutionMode TFinalMode>
  32. void NormalExecution()
  33. {
  34. bool prevValue = FullJitPhaseOffFlag;
  35. FullJitPhaseOffFlag = TFullJitPhase;
  36. // Setup the function environment
  37. int calls = 0;
  38. Js::Configuration::Global.flags.SetDefaults();
  39. Js::FunctionExecutionStateMachine f;
  40. Js::FunctionBody body(true, true, true);
  41. // Transition from Interpreter to AutoProfilingInterpreter
  42. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  43. //01 chakra!Js::FunctionExecutionStateMachine::InitializeExecutionModeAndLimits
  44. //02 chakra!Js::FunctionBody::MarkScript
  45. //03 chakra!Js::ByteCodeWriter::End
  46. //04 chakra!ByteCodeGenerator::EmitOneFunction
  47. //05 chakra!ByteCodeGenerator::EmitScopeList
  48. //06 chakra!ByteCodeGenerator::EmitScopeList
  49. //07 chakra!ByteCodeGenerator::EmitScopeList
  50. //08 chakra!ByteCodeGenerator::EmitProgram
  51. //09 chakra!ByteCodeGenerator::Generate
  52. //0a chakra!GenerateByteCode
  53. //0b chakra!ScriptEngine::CompileUTF8Core
  54. //0c chakra!ScriptEngine::CompileUTF8
  55. //0d chakra!ScriptEngine::DefaultCompile
  56. //0e chakra!ScriptEngine::CreateScriptBody
  57. //0f chakra!ScriptEngine::ParseScriptTextCore
  58. //10 chakra!ScriptEngine::ParseScriptText
  59. f.InitializeExecutionModeAndLimits(&body);
  60. CHECK(f.GetExecutionMode() == ExecutionMode::AutoProfilingInterpreter);
  61. CHECK(f.GetInterpretedCount() == 0);
  62. f.PrintLimits();
  63. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  64. //01 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextExecutionMode
  65. //02 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextInterpreterExecutionMode
  66. //03 chakra!Js::FunctionExecutionStateMachine::SetIsSpeculativeJitCandidate
  67. //04 chakra!Js::FunctionBody::SetIsSpeculativeJitCandidate
  68. //05 chakra!CodeGenWorkItem::ShouldSpeculativelyJitBasedOnProfile
  69. //06 chakra!CodeGenWorkItem::ShouldSpeculativelyJit
  70. //07 chakra!NativeCodeGenerator::GetJobToProcessProactively
  71. //08 chakra!JsUtil::ForegroundJobProcessor::PrioritizeManagerAndWait<NativeCodeGenerator>
  72. //09 chakra!JsUtil::JobProcessor::PrioritizeManagerAndWait<NativeCodeGenerator>
  73. //0a chakra!NativeCodeGenerator::EnterScriptStart
  74. //0b chakra!NativeCodeGenEnterScriptStart
  75. //0c chakra!Js::ScriptContext::OnScriptStart
  76. //0d chakra!Js::JavascriptFunction::CallRootFunctionInternal
  77. //0e chakra!Js::JavascriptFunction::CallRootFunction
  78. //0f chakra!ScriptSite::CallRootFunction
  79. //10 chakra!ScriptSite::Execute
  80. //11 chakra!ScriptEngine::ExecutePendingScripts
  81. //12 chakra!ScriptEngine::ParseScriptTextCore
  82. //13 chakra!ScriptEngine::ParseScriptText
  83. f.SetIsSpeculativeJitCandidate();
  84. CHECK(f.GetExecutionMode() == ExecutionMode::ProfilingInterpreter);
  85. CHECK(f.GetInterpretedCount() == 0);
  86. // "Run" the function in the interpreter
  87. for (; calls < 4; calls++)
  88. {
  89. f.IncreaseInterpretedCount();
  90. }
  91. CHECK(f.GetExecutionMode() == ExecutionMode::ProfilingInterpreter);
  92. CHECK(f.GetInterpretedCount() == 4);
  93. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  94. //01 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextExecutionMode
  95. //02 chakra!Js::FunctionExecutionStateMachine::TryTransitionToJitExecutionMode
  96. //03 chakra!Js::FunctionBody::TryTransitionToJitExecutionMode
  97. //04 chakra!NativeCodeGenerator::Prioritize
  98. //05 chakra!JsUtil::ForegroundJobProcessor::PrioritizeJob<NativeCodeGenerator, Js::FunctionEntryPointInfo * __ptr64>
  99. //06 chakra!JsUtil::JobProcessor::PrioritizeJob<NativeCodeGenerator, Js::FunctionEntryPointInfo * __ptr64>
  100. //07 chakra!NativeCodeGenerator::CheckCodeGen
  101. //08 chakra!NativeCodeGenerator::CheckCodeGenThunk
  102. //09 chakra!amd64_CallFunction
  103. //0a chakra!Js::JavascriptFunction::CallFunction<1>
  104. //0b chakra!Js::InterpreterStackFrame::OP_CallCommon<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >
  105. //0c chakra!Js::InterpreterStackFrame::OP_CallI<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >
  106. //0d chakra!Js::InterpreterStackFrame::ProcessUnprofiled
  107. //0e chakra!Js::InterpreterStackFrame::Process
  108. //0f chakra!Js::InterpreterStackFrame::InterpreterHelper
  109. //10 chakra!Js::InterpreterStackFrame::InterpreterThunk
  110. //11 0x0
  111. //12 chakra!amd64_CallFunction
  112. //13 chakra!Js::JavascriptFunction::CallFunction<1>
  113. //14 chakra!Js::JavascriptFunction::CallRootFunctionInternal
  114. //15 chakra!Js::JavascriptFunction::CallRootFunction
  115. //16 chakra!ScriptSite::CallRootFunction
  116. //17 chakra!ScriptSite::Execute
  117. //18 chakra!ScriptEngine::ExecutePendingScripts
  118. //19 chakra!ScriptEngine::ParseScriptTextCore
  119. //1a chakra!ScriptEngine::ParseScriptText
  120. f.TryTransitionToJitExecutionMode();
  121. CHECK(f.GetExecutionMode() == ExecutionMode::AutoProfilingInterpreter);
  122. CHECK(f.GetInterpretedCount() == 0);
  123. // "Run" the function in the interpreter
  124. for (; calls < 105; calls++)
  125. {
  126. f.IncreaseInterpretedCount();
  127. }
  128. CHECK(f.GetExecutionMode() == ExecutionMode::AutoProfilingInterpreter);
  129. CHECK(f.GetInterpretedCount() == 0x65);
  130. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  131. //01 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextExecutionMode
  132. //02 chakra!Js::FunctionExecutionStateMachine::TryTransitionToJitExecutionMode
  133. //03 chakra!Js::FunctionBody::TryTransitionToJitExecutionMode
  134. //04 chakra!NativeCodeGenerator::Prioritize
  135. //05 chakra!JsUtil::ForegroundJobProcessor::PrioritizeJob<NativeCodeGenerator, Js::FunctionEntryPointInfo * __ptr64>
  136. //06 chakra!JsUtil::JobProcessor::PrioritizeJob<NativeCodeGenerator, Js::FunctionEntryPointInfo * __ptr64>
  137. //07 chakra!NativeCodeGenerator::CheckCodeGen
  138. //08 chakra!NativeCodeGenerator::CheckCodeGenThunk
  139. //09 chakra!amd64_CallFunction
  140. //0a chakra!Js::JavascriptFunction::CallFunction<1>
  141. //0b chakra!Js::InterpreterStackFrame::OP_CallCommon<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >
  142. //0c chakra!Js::InterpreterStackFrame::OP_CallI<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >
  143. //0d chakra!Js::InterpreterStackFrame::ProcessUnprofiled
  144. //0e chakra!Js::InterpreterStackFrame::Process
  145. //0f chakra!Js::InterpreterStackFrame::InterpreterHelper
  146. //10 chakra!Js::InterpreterStackFrame::InterpreterThunk
  147. //11 0x0
  148. //12 chakra!amd64_CallFunction
  149. //13 chakra!Js::JavascriptFunction::CallFunction<1>
  150. //14 chakra!Js::JavascriptFunction::CallRootFunctionInternal
  151. //15 chakra!Js::JavascriptFunction::CallRootFunction
  152. //16 chakra!ScriptSite::CallRootFunction
  153. //17 chakra!ScriptSite::Execute
  154. //18 chakra!ScriptEngine::ExecutePendingScripts
  155. //19 chakra!ScriptEngine::ParseScriptTextCore
  156. //1a chakra!ScriptEngine::ParseScriptText
  157. f.TryTransitionToJitExecutionMode();
  158. CHECK(f.GetExecutionMode() == ExecutionMode::SimpleJit);
  159. CHECK(f.GetInterpretedCount() == 0);
  160. // Simple JIT EntryPoint Info keeps a count from the limit and decrements per call.
  161. // Since the stub entry point is initialized to 0, proceed with transition.
  162. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  163. //01 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextExecutionMode
  164. //02 chakra!Js::FunctionBody::TryTransitionToNextExecutionMode
  165. //03 chakra!NativeCodeGenerator::TransitionFromSimpleJit
  166. //04 chakra!NativeCodeGenerator::Jit_TransitionFromSimpleJit
  167. //05 0x0
  168. //06 chakra!amd64_CallFunction
  169. //07 chakra!Js::JavascriptFunction::CallFunction<1>
  170. //08 chakra!Js::InterpreterStackFrame::OP_CallCommon<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >
  171. //09 chakra!Js::InterpreterStackFrame::OP_CallI<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<Js::LayoutSizePolicy<0> > > >
  172. //0a chakra!Js::InterpreterStackFrame::ProcessUnprofiled
  173. //0b chakra!Js::InterpreterStackFrame::Process
  174. //0c chakra!Js::InterpreterStackFrame::InterpreterHelper
  175. //0d chakra!Js::InterpreterStackFrame::InterpreterThunk
  176. //0e 0x0
  177. //0f chakra!amd64_CallFunction
  178. //10 chakra!Js::JavascriptFunction::CallFunction<1>
  179. //11 chakra!Js::JavascriptFunction::CallRootFunctionInternal
  180. //12 chakra!Js::JavascriptFunction::CallRootFunction
  181. //13 chakra!ScriptSite::CallRootFunction
  182. //14 chakra!ScriptSite::Execute
  183. //15 chakra!ScriptEngine::ExecutePendingScripts
  184. //16 chakra!ScriptEngine::ParseScriptTextCore
  185. //17 chakra!ScriptEngine::ParseScriptText
  186. f.TryTransitionToNextExecutionMode();
  187. CHECK(f.GetExecutionMode() == TFinalMode);
  188. CHECK(f.GetInterpretedCount() == 0);
  189. FullJitPhaseOffFlag = prevValue;
  190. }
  191. TEST_CASE("FuncExe_NormalExecution")
  192. {
  193. NormalExecution<false, ExecutionMode::FullJit>();
  194. }
  195. TEST_CASE("FuncExe_NormalExecutionNoFullJit")
  196. {
  197. NormalExecution<true, ExecutionMode::SimpleJit>();
  198. }
  199. // test what happens when we jit a Loop Body
  200. TEST_CASE("FuncExe_NormalExecutionOfLoop")
  201. {
  202. }
  203. // Emulate/test what happens when we have the cmd args similar to JS unittests as Interpreted:
  204. // -bvt -BaselineMode -DumpOnCrash -maxInterpretCount:1 -maxSimpleJitRunCount:1 -bgjit-
  205. TEST_CASE("FuncExe_JSUnitTestInterpreted")
  206. {
  207. Js::Configuration::Global.flags.SetInterpretedValues();
  208. Js::FunctionExecutionStateMachine f;
  209. Js::FunctionBody body(true, true, true);
  210. // to AutoProf
  211. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  212. //01 chakra!Js::FunctionExecutionStateMachine::InitializeExecutionModeAndLimits
  213. //02 chakra!Js::FunctionBody::MarkScript
  214. //03 chakra!Js::ByteCodeWriter::End
  215. // ...and then to Prof
  216. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  217. //01 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextExecutionMode
  218. //02 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextInterpreterExecutionMode
  219. //03 chakra!Js::FunctionExecutionStateMachine::InitializeExecutionModeAndLimits
  220. //04 chakra!Js::FunctionBody::MarkScript
  221. //05 chakra!Js::ByteCodeWriter::End
  222. f.InitializeExecutionModeAndLimits(&body);
  223. CHECK(f.GetExecutionMode() == ExecutionMode::ProfilingInterpreter);
  224. CHECK(f.GetInterpretedCount() == 0);
  225. // Run the function once under the Interpreter
  226. f.IncreaseInterpretedCount();
  227. // to Simple
  228. //# Call Site
  229. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  230. //01 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextExecutionMode
  231. //02 chakra!Js::FunctionExecutionStateMachine::TryTransitionToJitExecutionMode
  232. //03 chakra!Js::FunctionBody::TryTransitionToJitExecutionMode
  233. //04 chakra!NativeCodeGenerator::CheckCodeGen
  234. //05 chakra!NativeCodeGenerator::CheckCodeGenThunk
  235. //06 chakra!amd64_CallFunction
  236. f.TryTransitionToJitExecutionMode();
  237. CHECK(f.GetExecutionMode() == ExecutionMode::SimpleJit);
  238. CHECK(f.GetInterpretedCount() == 0);
  239. // Simple JIT EntryPoint Info keeps a count from the limit and decrements per call.
  240. // Since the stub entry point is initialized to 0, proceed with transition.
  241. // to full
  242. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  243. //01 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextExecutionMode
  244. //02 chakra!Js::FunctionBody::TryTransitionToNextExecutionMode
  245. //03 chakra!NativeCodeGenerator::TransitionFromSimpleJit
  246. //04 chakra!NativeCodeGenerator::Jit_TransitionFromSimpleJit
  247. f.TryTransitionToNextExecutionMode();
  248. CHECK(f.GetExecutionMode() == ExecutionMode::FullJit);
  249. CHECK(f.GetInterpretedCount() == 0);
  250. }
  251. // Emulate/test what happens when we have the cmd args similar to JS unittests as DynaPogo:
  252. // -bvt -BaselineMode -DumpOnCrash -forceNative -off:simpleJit -bgJitDelay:0
  253. template <bool TFullJitPhase, ExecutionMode TInitialMode, ExecutionMode TFinalMode>
  254. void JSUnitTestDynapogo()
  255. {
  256. bool prevValue = FullJitPhaseOffFlag;
  257. FullJitPhaseOffFlag = TFullJitPhase;
  258. Js::Configuration::Global.flags.SetDynaPogoValues();
  259. Js::FunctionExecutionStateMachine f;
  260. Js::FunctionBody body(true, true, false);
  261. // to AutoProf
  262. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  263. //01 chakra!Js::FunctionExecutionStateMachine::InitializeExecutionModeAndLimits
  264. //02 chakra!Js::FunctionBody::MarkScript
  265. //03 chakra!Js::ByteCodeWriter::End
  266. // ...then FullJit
  267. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  268. //01 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextExecutionMode
  269. //02 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextInterpreterExecutionMode
  270. //03 chakra!Js::FunctionExecutionStateMachine::InitializeExecutionModeAndLimits
  271. //04 chakra!Js::FunctionBody::MarkScript
  272. //05 chakra!Js::ByteCodeWriter::End
  273. // ..then profiling
  274. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  275. //01 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextInterpreterExecutionMode
  276. //02 chakra!Js::FunctionExecutionStateMachine::InitializeExecutionModeAndLimits
  277. //03 chakra!Js::FunctionBody::MarkScript
  278. //04 chakra!Js::ByteCodeWriter::End
  279. f.InitializeExecutionModeAndLimits(&body);
  280. CHECK(f.GetExecutionMode() == TInitialMode);
  281. CHECK(f.GetInterpretedCount() == 0);
  282. // to full
  283. //00 chakra!Js::FunctionExecutionStateMachine::SetExecutionMode
  284. //01 chakra!Js::FunctionExecutionStateMachine::TryTransitionToNextExecutionMode
  285. //02 chakra!Js::FunctionExecutionStateMachine::TryTransitionToJitExecutionMode
  286. //03 chakra!Js::FunctionBody::TryTransitionToJitExecutionMode
  287. //04 chakra!NativeCodeGenerator::CheckCodeGen
  288. //05 chakra!NativeCodeGenerator::CheckCodeGenThunk
  289. f.TryTransitionToJitExecutionMode();
  290. CHECK(f.GetExecutionMode() == TFinalMode);
  291. CHECK(f.GetInterpretedCount() == 0);
  292. FullJitPhaseOffFlag = prevValue;
  293. }
  294. TEST_CASE("FuncExe_JSUnitTestDynapogo")
  295. {
  296. JSUnitTestDynapogo<false, ExecutionMode::ProfilingInterpreter, ExecutionMode::FullJit>();
  297. }
  298. TEST_CASE("FuncExe_JSUnitTestDynapogoNoFullJit")
  299. {
  300. JSUnitTestDynapogo<true, ExecutionMode::AutoProfilingInterpreter, ExecutionMode::AutoProfilingInterpreter>();
  301. }
  302. // test what hits TransitionToSimpleJitExecutionMode
  303. // NativeCodeGenerator::GenerateFunction with the following args
  304. // -bgjit- -trace:executionmode -prejit -force:simplejit
  305. TEST_CASE("FuncExe_TransitionToSimpleJit")
  306. {
  307. }
  308. // test what hits TransitionToFullJitExecutionMode
  309. // Note: also called from
  310. // - BailOutRecord::ScheduleFunctionCodeGen, when we rejit after bailout
  311. // - NativeCodeGenerator::GetJobToProcessProactively, looks like it's for speculative jit
  312. // - NativeCodeGenerator::GenerateFunction, when prejitting with the following args
  313. // -bgjit- -trace:executionmode -prejit
  314. TEST_CASE("FuncExe_TransitionToFullJit")
  315. {
  316. }
  317. }