InterpreterLoop.inl 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  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. // Shared interpreter loop
  6. //
  7. // This holds the single definition of the interpreter loop.
  8. // It allows for configurable copies of the loop that do extra work without
  9. // impacting the mainline performance. (for example the debug loop can simply
  10. // check a bit without concern for impacting the nondebug mode.)
  11. #if defined(INTERPRETER_ASMJS)
  12. #define INTERPRETER_OPCODE OpCodeAsmJs
  13. #define TRACING_FUNC &InterpreterStackFrame::TraceAsmJsOpCode
  14. #else
  15. #define INTERPRETER_OPCODE OpCode
  16. #define TRACING_FUNC &InterpreterStackFrame::TraceOpCode
  17. #endif
  18. #ifdef PROVIDE_INTERPRETER_STMTS
  19. #define READ_OP ReadOp_WPreviousStmtTracking<INTERPRETER_OPCODE, ByteCodeReader::ReadByteOp, TRACING_FUNC>
  20. #define READ_EXT_OP ReadOp_WPreviousStmtTracking<INTERPRETER_OPCODE, ByteCodeReader::ReadExtOp, TRACING_FUNC>
  21. #else
  22. #define READ_OP ReadOp<INTERPRETER_OPCODE, ByteCodeReader::ReadByteOp, TRACING_FUNC>
  23. #define READ_EXT_OP ReadOp<INTERPRETER_OPCODE, ByteCodeReader::ReadExtOp, TRACING_FUNC>
  24. #endif
  25. #ifdef PROVIDE_DEBUGGING
  26. #define DEBUGGING_LOOP 1
  27. #else
  28. #define DEBUGGING_LOOP 0
  29. #endif
  30. #ifdef PROVIDE_INTERPRETERPROFILE
  31. #define INTERPRETERPROFILE 1
  32. #define PROFILEDOP(prof, unprof) prof
  33. #else
  34. #define INTERPRETERPROFILE 0
  35. #define PROFILEDOP(prof, unprof) unprof
  36. #endif
  37. //two layers of macros are necessary to get arguments to the invocation of the top level macro expanded.
  38. #define CONCAT_TOKENS_AGAIN(loopName, fnSuffix) loopName ## fnSuffix
  39. #define CONCAT_TOKENS(loopName, fnSuffix) CONCAT_TOKENS_AGAIN(loopName, fnSuffix)
  40. #define PROCESS_OPCODE_FN_NAME(fnSuffix) CONCAT_TOKENS(INTERPRETERLOOPNAME, fnSuffix)
  41. const byte* Js::InterpreterStackFrame::PROCESS_OPCODE_FN_NAME(ExtendedOpcodePrefix)(const byte* ip)
  42. {
  43. INTERPRETER_OPCODE op = READ_EXT_OP(ip);
  44. switch (op)
  45. {
  46. #define EXDEF2(x, op, func) PROCESS_##x(op, func)
  47. #define EXDEF3(x, op, func, y) PROCESS_##x(op, func, y)
  48. #define EXDEF2_WMS(x, op, func) PROCESS_##x##_COMMON(op, func, _Small)
  49. #define EXDEF3_WMS(x, op, func, y) PROCESS_##x##_COMMON(op, func, y, _Small)
  50. #define EXDEF4_WMS(x, op, func, y, t) PROCESS_##x##_COMMON(op, func, y, _Small, t)
  51. #include "InterpreterHandler.inl"
  52. default:
  53. // Help the C++ optimizer by declaring that the cases we
  54. // have above are sufficient
  55. AssertMsg(false, "dispatch to bad opcode");
  56. __assume(false);
  57. };
  58. return ip;
  59. }
  60. const byte* Js::InterpreterStackFrame::PROCESS_OPCODE_FN_NAME(MediumLayoutPrefix)(const byte* ip, Var& yieldValue)
  61. {
  62. INTERPRETER_OPCODE op = READ_OP(ip);
  63. switch (op)
  64. {
  65. #ifndef INTERPRETER_ASMJS
  66. case INTERPRETER_OPCODE::Yield:
  67. m_reader.Reg2_Medium(ip);
  68. yieldValue = GetReg(GetFunctionBody()->GetYieldRegister());
  69. break;
  70. #endif
  71. #define DEF2_WMS(x, op, func) PROCESS_##x##_COMMON(op, func, _Medium)
  72. #define DEF3_WMS(x, op, func, y) PROCESS_##x##_COMMON(op, func, y, _Medium)
  73. #define DEF4_WMS(x, op, func, y, t) PROCESS_##x##_COMMON(op, func, y, _Medium, t)
  74. #include "InterpreterHandler.inl"
  75. default:
  76. // Help the C++ optimizer by declaring that the cases we
  77. // have above are sufficient
  78. AssertMsg(false, "dispatch to bad opcode");
  79. __assume(false);
  80. }
  81. return ip;
  82. }
  83. const byte* Js::InterpreterStackFrame::PROCESS_OPCODE_FN_NAME(ExtendedMediumLayoutPrefix)(const byte* ip)
  84. {
  85. INTERPRETER_OPCODE op = READ_EXT_OP(ip);
  86. switch (op)
  87. {
  88. #define EXDEF2_WMS(x, op, func) PROCESS_##x##_COMMON(op, func, _Medium)
  89. #define EXDEF3_WMS(x, op, func, y) PROCESS_##x##_COMMON(op, func, y, _Medium)
  90. #define EXDEF4_WMS(x, op, func, y, t) PROCESS_##x##_COMMON(op, func, y, _Medium, t)
  91. #include "InterpreterHandler.inl"
  92. default:
  93. // Help the C++ optimizer by declaring that the cases we
  94. // have above are sufficient
  95. AssertMsg(false, "dispatch to bad opcode");
  96. __assume(false);
  97. };
  98. return ip;
  99. }
  100. const byte* Js::InterpreterStackFrame::PROCESS_OPCODE_FN_NAME(LargeLayoutPrefix)(const byte* ip, Var& yieldValue)
  101. {
  102. INTERPRETER_OPCODE op = READ_OP(ip);
  103. switch (op)
  104. {
  105. #ifndef INTERPRETER_ASMJS
  106. case INTERPRETER_OPCODE::Yield:
  107. m_reader.Reg2_Large(ip);
  108. yieldValue = GetReg(GetFunctionBody()->GetYieldRegister());
  109. break;
  110. #endif
  111. #define DEF2_WMS(x, op, func) PROCESS_##x##_COMMON(op, func, _Large)
  112. #define DEF3_WMS(x, op, func, y) PROCESS_##x##_COMMON(op, func, y, _Large)
  113. #define DEF4_WMS(x, op, func, y, t) PROCESS_##x##_COMMON(op, func, y, _Large, t)
  114. #include "InterpreterHandler.inl"
  115. default:
  116. // Help the C++ optimizer by declaring that the cases we
  117. // have above are sufficient
  118. AssertMsg(false, "dispatch to bad opcode");
  119. __assume(false);
  120. }
  121. return ip;
  122. }
  123. const byte* Js::InterpreterStackFrame::PROCESS_OPCODE_FN_NAME(ExtendedLargeLayoutPrefix)(const byte* ip)
  124. {
  125. INTERPRETER_OPCODE op = READ_EXT_OP(ip);
  126. switch (op)
  127. {
  128. #define EXDEF2_WMS(x, op, func) PROCESS_##x##_COMMON(op, func, _Large)
  129. #define EXDEF3_WMS(x, op, func, y) PROCESS_##x##_COMMON(op, func, y, _Large)
  130. #define EXDEF4_WMS(x, op, func, y, t) PROCESS_##x##_COMMON(op, func, y, _Large, t)
  131. #include "InterpreterHandler.inl"
  132. default:
  133. // Help the C++ optimizer by declaring that the cases we
  134. // have above are sufficient
  135. AssertMsg(false, "dispatch to bad opcode");
  136. __assume(false);
  137. };
  138. return ip;
  139. }
  140. #if defined (DBG)
  141. // Win8 516184: Huge switch with lots of labels each having a few locals on ARM.DBG causes each occurrence
  142. // of this function (call of a javascript function in interpreter mode) to take 7+KB stack space
  143. // (without optimizations the compiler accounts for ALL locals inside case labels when allocating space on stack
  144. // for locals - SP does not change inside the function). On other platforms this is still huge but better than ARM.
  145. // So, for DBG turn on optimizations to prevent this huge loss of stack.
  146. #pragma optimize("g", on)
  147. #endif
  148. Js::Var Js::InterpreterStackFrame::INTERPRETERLOOPNAME()
  149. {
  150. PROBE_STACK(scriptContext, Js::Constants::MinStackInterpreter);
  151. if (!this->closureInitDone)
  152. {
  153. // If this is the start of the function, then we've waited until after the stack probe above
  154. // to set up the FD/SS pointers, so do it now.
  155. Assert(this->m_reader.GetCurrentOffset() == 0);
  156. this->InitializeClosures();
  157. }
  158. Assert(this->returnAddress != nullptr);
  159. AssertMsg(!this->GetFunctionBody()->GetUsesArgumentsObject() || m_arguments == NULL || Js::ArgumentsObject::Is(m_arguments), "Bad arguments!");
  160. // IP Passing in the interpreter:
  161. // We keep a local copy of the bytecode's instruction pointer and
  162. // pass it by reference to the bytecode reader.
  163. // This allows the optimizer to recognize that the local (held in a register)
  164. // dominates the copy in the reader.
  165. // The effect is our dispatch loop is significantly smaller in the common case
  166. // on optimized builds.
  167. //
  168. // For checked builds this does mean we are incrementing 2 different counters to
  169. // track the ip.
  170. const byte* ip = m_reader.GetIP();
  171. while (true)
  172. {
  173. INTERPRETER_OPCODE op = READ_OP(ip);
  174. #ifdef ENABLE_BASIC_TELEMETRY
  175. if( TELEMETRY_OPCODE_OFFSET_ENABLED )
  176. {
  177. OpcodeTelemetry& opcodeTelemetry = this->scriptContext->GetTelemetry().GetOpcodeTelemetry();
  178. opcodeTelemetry.ProgramLocationFunctionId ( this->function->GetFunctionInfo()->GetLocalFunctionId() );
  179. opcodeTelemetry.ProgramLocationBytecodeOffset( this->m_reader.GetCurrentOffset() );
  180. }
  181. #endif
  182. #if DEBUGGING_LOOP
  183. if (this->scriptContext->GetThreadContext()->GetDebugManager()->stepController.IsActive() &&
  184. this->scriptContext->GetThreadContext()->GetDebugManager()->stepController.IsStepComplete_AllowingFalsePositives(this))
  185. {
  186. // BrLong is used for branch island, we don't want to break over there, as they don't belong to any statement. Just skip this.
  187. if (!InterpreterStackFrame::IsBrLong(op, ip) && !this->m_functionBody->GetUtf8SourceInfo()->GetIsLibraryCode())
  188. {
  189. uint prevOffset = m_reader.GetCurrentOffset();
  190. #if ENABLE_TTD
  191. bool bpTaken = (!this->scriptContext->GetThreadContext()->IsRuntimeInTTDMode()) || this->scriptContext->GetThreadContext()->TTDExecutionInfo->ProcessBPInfoPreBreak(this->m_functionBody, this->scriptContext->GetThreadContext()->TTDLog);
  192. if(bpTaken)
  193. {
  194. InterpreterHaltState haltState(STOP_STEPCOMPLETE, m_functionBody);
  195. this->scriptContext->GetDebugContext()->GetProbeContainer()->DispatchStepHandler(&haltState, &op);
  196. }
  197. #else
  198. InterpreterHaltState haltState(STOP_STEPCOMPLETE, m_functionBody);
  199. this->scriptContext->GetDebugContext()->GetProbeContainer()->DispatchStepHandler(&haltState, &op);
  200. #endif
  201. #if ENABLE_TTD
  202. if(bpTaken && this->scriptContext->GetThreadContext()->IsRuntimeInTTDMode())
  203. {
  204. this->scriptContext->GetThreadContext()->TTDExecutionInfo->ProcessBPInfoPostBreak(this->m_functionBody);
  205. }
  206. #endif
  207. if (prevOffset != m_reader.GetCurrentOffset())
  208. {
  209. // The location of the statement has been changed, setnextstatement was called.
  210. // Reset m_outParams and m_outSp as before SetNext was called, we could be in the middle of StartCall.
  211. // It's fine to do because SetNext can only be done to a statement -- function-level destination,
  212. // and can't land to an expression inside call.
  213. ResetOut();
  214. ip = m_reader.GetIP();
  215. continue;
  216. }
  217. }
  218. }
  219. // The break opcode will be handled later in the switch block.
  220. if (op != OpCode::Break && this->scriptContext->GetThreadContext()->GetDebugManager()->asyncBreakController.IsBreak())
  221. {
  222. if (!InterpreterStackFrame::IsBrLong(op, ip) && !this->m_functionBody->GetUtf8SourceInfo()->GetIsLibraryCode())
  223. {
  224. uint prevOffset = m_reader.GetCurrentOffset();
  225. #if ENABLE_TTD
  226. bool bpTaken = (!this->scriptContext->GetThreadContext()->IsRuntimeInTTDMode()) || this->scriptContext->GetThreadContext()->TTDExecutionInfo->ProcessBPInfoPreBreak(this->m_functionBody, this->scriptContext->GetThreadContext()->TTDLog);
  227. if(bpTaken)
  228. {
  229. InterpreterHaltState haltState(STOP_ASYNCBREAK, m_functionBody);
  230. this->scriptContext->GetDebugContext()->GetProbeContainer()->DispatchAsyncBreak(&haltState);
  231. }
  232. #else
  233. InterpreterHaltState haltState(STOP_ASYNCBREAK, m_functionBody);
  234. this->scriptContext->GetDebugContext()->GetProbeContainer()->DispatchAsyncBreak(&haltState);
  235. #endif
  236. #if ENABLE_TTD
  237. if(bpTaken && this->scriptContext->GetThreadContext()->IsRuntimeInTTDMode())
  238. {
  239. this->scriptContext->GetThreadContext()->TTDExecutionInfo->ProcessBPInfoPostBreak(this->m_functionBody);
  240. }
  241. #endif
  242. if (prevOffset != m_reader.GetCurrentOffset())
  243. {
  244. // The location of the statement has been changed, setnextstatement was called.
  245. ip = m_reader.GetIP();
  246. continue;
  247. }
  248. }
  249. }
  250. SWAP_BP_FOR_OPCODE:
  251. #endif
  252. switch (op)
  253. {
  254. case INTERPRETER_OPCODE::Ret:
  255. {
  256. //
  257. // Return "Reg: 0" as the return-value.
  258. // - JavaScript functions always return a value, and this value is always
  259. // accessible to the caller. For an empty "return;" or exiting the end of the
  260. // function's body, it is assumed that the byte-code author
  261. // (ByteCodeGenerator) will load 'undefined' into R0.
  262. // - If R0 has not explicitly been set, it will contain whatever garbage value
  263. // was last set.
  264. //
  265. this->retOffset = m_reader.GetCurrentOffset();
  266. m_reader.Empty(ip);
  267. return GetReg((RegSlot)0);
  268. }
  269. #ifndef INTERPRETER_ASMJS
  270. case INTERPRETER_OPCODE::Yield:
  271. {
  272. m_reader.Reg2_Small(ip);
  273. return GetReg(GetFunctionBody()->GetYieldRegister());
  274. }
  275. #endif
  276. #define DEF2(x, op, func) PROCESS_##x(op, func)
  277. #define DEF3(x, op, func, y) PROCESS_##x(op, func, y)
  278. #define DEF2_WMS(x, op, func) PROCESS_##x##_COMMON(op, func, _Small)
  279. #define DEF3_WMS(x, op, func, y) PROCESS_##x##_COMMON(op, func, y, _Small)
  280. #define DEF4_WMS(x, op, func, y, t) PROCESS_##x##_COMMON(op, func, y, _Small, t)
  281. #include "InterpreterHandler.inl"
  282. #ifndef INTERPRETER_ASMJS
  283. case INTERPRETER_OPCODE::Leave:
  284. // Return the continuation address to the helper.
  285. // This tells the helper that control left the scope without completing the try/handler,
  286. // which is particularly significant when executing a finally.
  287. m_reader.Empty(ip);
  288. return (Var)this->m_reader.GetCurrentOffset();
  289. case INTERPRETER_OPCODE::LeaveNull:
  290. // Return to the helper without specifying a continuation address,
  291. // indicating that the handler completed without jumping, so exception processing
  292. // should continue.
  293. m_reader.Empty(ip);
  294. return nullptr;
  295. #endif
  296. #if ENABLE_PROFILE_INFO && !defined(INTERPRETER_ASMJS)
  297. // Aborting the current interpreter loop to switch the profile mode
  298. #define CHECK_SWITCH_PROFILE_MODE() if (switchProfileMode) return nullptr;
  299. #else
  300. #define CHECK_SWITCH_PROFILE_MODE()
  301. #endif
  302. #ifndef INTERPRETER_ASMJS
  303. #define CHECK_YIELD_VALUE() if (yieldValue != nullptr) return yieldValue;
  304. #else
  305. #define CHECK_YIELD_VALUE() Unused(yieldValue);
  306. #endif
  307. #define ExtendedCase(opcode) \
  308. case INTERPRETER_OPCODE::opcode: \
  309. ip = PROCESS_OPCODE_FN_NAME(opcode)(ip); \
  310. CHECK_SWITCH_PROFILE_MODE(); \
  311. break;
  312. ExtendedCase(ExtendedOpcodePrefix)
  313. ExtendedCase(ExtendedMediumLayoutPrefix)
  314. ExtendedCase(ExtendedLargeLayoutPrefix)
  315. case INTERPRETER_OPCODE::MediumLayoutPrefix:
  316. {
  317. Var yieldValue = nullptr;
  318. ip = PROCESS_OPCODE_FN_NAME(MediumLayoutPrefix)(ip, yieldValue);
  319. CHECK_YIELD_VALUE();
  320. CHECK_SWITCH_PROFILE_MODE();
  321. break;
  322. }
  323. case INTERPRETER_OPCODE::LargeLayoutPrefix:
  324. {
  325. Var yieldValue = nullptr;
  326. ip = PROCESS_OPCODE_FN_NAME(LargeLayoutPrefix)(ip, yieldValue);
  327. CHECK_YIELD_VALUE();
  328. CHECK_SWITCH_PROFILE_MODE();
  329. break;
  330. }
  331. case INTERPRETER_OPCODE::EndOfBlock:
  332. {
  333. // Note that at this time though ip was advanced by 'OpCode op = ReadByteOp<INTERPRETER_OPCODE>(ip)',
  334. // we haven't advanced m_reader.m_currentLocation yet, thus m_reader.m_currentLocation still points to EndOfBLock,
  335. // and that +1 will point to 1st byte past the buffer.
  336. Assert(m_reader.GetCurrentOffset() + sizeof(byte) == m_functionBody->GetByteCode()->GetLength());
  337. //
  338. // Reached an "OpCode::EndOfBlock" so need to exit this interpreter loop because
  339. // there is no more byte-code to execute.
  340. // - This prevents us from accessing random memory as byte-codes.
  341. // - Functions should contain an "OpCode::Ret" instruction to organize an
  342. // orderly return.
  343. //
  344. #if DEBUGGING_LOOP
  345. // However, during debugging an exception can be skipped which causes the
  346. // statement that caused to exception to be skipped. If this statement is
  347. // the statement that contains the OpCode::Ret then the EndOfBlock will
  348. // be executed. In these cases it is sufficient to return undefined.
  349. return this->scriptContext->GetLibrary()->GetUndefined();
  350. #else
  351. return nullptr;
  352. #endif
  353. }
  354. #ifndef INTERPRETER_ASMJS
  355. case INTERPRETER_OPCODE::Break:
  356. {
  357. #if DEBUGGING_LOOP
  358. // The reader has already advanced the IP:
  359. if (this->m_functionBody->ProbeAtOffset(m_reader.GetCurrentOffset(), &op))
  360. {
  361. uint prevOffset = m_reader.GetCurrentOffset();
  362. #if ENABLE_TTD
  363. bool bpTaken = (!this->scriptContext->GetThreadContext()->IsRuntimeInTTDMode()) || this->scriptContext->GetThreadContext()->TTDExecutionInfo->ProcessBPInfoPreBreak(this->m_functionBody, this->scriptContext->GetThreadContext()->TTDLog);
  364. if(bpTaken)
  365. {
  366. InterpreterHaltState haltState(STOP_BREAKPOINT, m_functionBody);
  367. this->scriptContext->GetDebugContext()->GetProbeContainer()->DispatchProbeHandlers(&haltState);
  368. }
  369. #else
  370. InterpreterHaltState haltState(STOP_BREAKPOINT, m_functionBody);
  371. this->scriptContext->GetDebugContext()->GetProbeContainer()->DispatchProbeHandlers(&haltState);
  372. #endif
  373. #if ENABLE_TTD
  374. if(bpTaken && this->scriptContext->GetThreadContext()->IsRuntimeInTTDMode())
  375. {
  376. this->scriptContext->GetThreadContext()->TTDExecutionInfo->ProcessBPInfoPostBreak(this->m_functionBody);
  377. }
  378. #endif
  379. if (prevOffset != m_reader.GetCurrentOffset())
  380. {
  381. // The location of the statement has been changed, setnextstatement was called.
  382. ip = m_reader.GetIP();
  383. continue;
  384. }
  385. // Jump back to the start of the switch.
  386. goto SWAP_BP_FOR_OPCODE;
  387. }
  388. else
  389. {
  390. #if DEBUGGING_LOOP
  391. // an inline break statement rather than a probe
  392. if (!this->scriptContext->GetThreadContext()->GetDebugManager()->stepController.ContinueFromInlineBreakpoint())
  393. {
  394. uint prevOffset = m_reader.GetCurrentOffset();
  395. #if ENABLE_TTD
  396. bool bpTaken = (!this->scriptContext->GetThreadContext()->IsRuntimeInTTDMode()) || this->scriptContext->GetThreadContext()->TTDExecutionInfo->ProcessBPInfoPreBreak(this->m_functionBody, this->scriptContext->GetThreadContext()->TTDLog);
  397. if(bpTaken)
  398. {
  399. InterpreterHaltState haltState(STOP_INLINEBREAKPOINT, m_functionBody);
  400. this->scriptContext->GetDebugContext()->GetProbeContainer()->DispatchInlineBreakpoint(&haltState);
  401. }
  402. #else
  403. InterpreterHaltState haltState(STOP_INLINEBREAKPOINT, m_functionBody);
  404. this->scriptContext->GetDebugContext()->GetProbeContainer()->DispatchInlineBreakpoint(&haltState);
  405. #endif
  406. #if ENABLE_TTD
  407. if(bpTaken && this->scriptContext->GetThreadContext()->IsRuntimeInTTDMode())
  408. {
  409. this->scriptContext->GetThreadContext()->TTDExecutionInfo->ProcessBPInfoPostBreak(this->m_functionBody);
  410. }
  411. #endif
  412. if (prevOffset != m_reader.GetCurrentOffset())
  413. {
  414. // The location of the statement has been changed, setnextstatement was called.
  415. ip = m_reader.GetIP();
  416. continue;
  417. }
  418. }
  419. #endif
  420. // Consume after dispatching
  421. m_reader.Empty(ip);
  422. }
  423. #else
  424. m_reader.Empty(ip);
  425. #endif
  426. break;
  427. }
  428. #endif
  429. default:
  430. // Help the C++ optimizer by declaring that the cases we
  431. // have above are sufficient
  432. AssertMsg(false, "dispatch to bad opcode");
  433. __assume(false);
  434. }
  435. }
  436. }
  437. #if defined (DBG)
  438. // Restore optimizations to what's specified by the /O switch.
  439. #pragma optimize("", on)
  440. #endif
  441. #undef READ_OP
  442. #undef READ_EXT_OP
  443. #undef TRACING_FUNC
  444. #undef DEBUGGING_LOOP
  445. #undef INTERPRETERPROFILE
  446. #undef PROFILEDOP
  447. #undef INTERPRETER_OPCODE
  448. #undef CHECK_SWITCH_PROFILE_MODE
  449. #undef CHECK_YIELD_VALUE