LeaveScriptObject.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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. #pragma once
  6. //----------------------------------
  7. // EnterScriptStart/EnterScriptEnd
  8. //----------------------------------
  9. #if defined(DBG) && defined(_M_IX86) && defined(_MSC_VER)
  10. #define SAVE_FS0() __entryExitRecord.scriptEntryFS0 = (void*)__readfsdword(0)
  11. #else
  12. #define SAVE_FS0()
  13. #endif
  14. #define BEGIN_ENTER_SCRIPT_EX(scriptContext, doCleanup, isCallRoot, hasCaller, isScript) \
  15. { \
  16. Js::ScriptContext* __localScriptContext = scriptContext; \
  17. Js::ScriptEntryExitRecord __entryExitRecord = {0}; \
  18. SAVE_FS0(); \
  19. Js::EnterScriptObject __enterScriptObject = Js::EnterScriptObject(__localScriptContext, &__entryExitRecord, \
  20. _ReturnAddress(), _AddressOfReturnAddress(), doCleanup, isCallRoot, hasCaller); \
  21. __localScriptContext->OnScriptStart(isCallRoot, isScript); \
  22. __enterScriptObject.VerifyEnterScript();
  23. #define BEGIN_ENTER_SCRIPT(scriptContext, doCleanup, isCallRoot, hasCaller) \
  24. BEGIN_ENTER_SCRIPT_EX(scriptContext, doCleanup, isCallRoot, hasCaller, /*isScript*/true) \
  25. #define END_ENTER_SCRIPT \
  26. }
  27. //---------------------------------------------------------------------
  28. // EnterScriptStart/EnterScriptEnd with javascript exception handling
  29. //---------------------------------------------------------------------
  30. #define BEGIN_JS_RUNTIME_CALL_EX(scriptContext, doCleanup) \
  31. BEGIN_ENTER_SCRIPT(scriptContext, doCleanup, /*isCallRoot*/ false, /*hasCaller*/false) \
  32. {
  33. #define BEGIN_JS_RUNTIME_CALLROOT_EX(scriptContext, hasCaller) \
  34. BEGIN_ENTER_SCRIPT(scriptContext, /*doCleanup*/ true, /*isCallRoot*/ true, hasCaller) \
  35. {
  36. #define BEGIN_JS_RUNTIME_CALL(scriptContext) \
  37. BEGIN_JS_RUNTIME_CALL_EX(scriptContext, /*doCleanup*/ true)
  38. // Use _NOT_SCRIPT to indicate we are not really starting script, avoid certain risky/lengthy work.
  39. #define BEGIN_JS_RUNTIME_CALL_NOT_SCRIPT(scriptContext) \
  40. BEGIN_ENTER_SCRIPT_EX(scriptContext, /*doCleanup*/false, /*isCallRoot*/false, /*hasCaller*/false, /*isScript*/false) \
  41. {
  42. #define END_JS_RUNTIME_CALL(scriptContext) \
  43. } \
  44. END_ENTER_SCRIPT
  45. #define BEGIN_JS_RUNTIME_CALL_EX_AND_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT(scriptContext, doCleanup) \
  46. BEGIN_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT \
  47. BEGIN_ENTER_SCRIPT(scriptContext, doCleanup, /*isCallRoot*/ false, /*hasCaller*/false) \
  48. { \
  49. IGNORE_STACKWALK_EXCEPTION(scriptContext); \
  50. #define BEGIN_JS_RUNTIME_CALL_EX_AND_TRANSLATE_AND_GET_EXCEPTION_AND_ERROROBJECT_TO_HRESULT(scriptContext, doCleanup) \
  51. BEGIN_JS_RUNTIME_CALL_EX_AND_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT(scriptContext, doCleanup) \
  52. #define BEGIN_JS_RUNTIME_CALL_EX_AND_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_NESTED(scriptContext, doCleanup) \
  53. BEGIN_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_NESTED \
  54. BEGIN_ENTER_SCRIPT(scriptContext, doCleanup, /*isCallRoot*/ false, /*hasCaller*/false) \
  55. { \
  56. #define END_JS_RUNTIME_CALL_AND_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT(hr) \
  57. } \
  58. END_ENTER_SCRIPT \
  59. END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr) \
  60. END_TRANSLATE_ERROROBJECT_TO_HRESULT(hr) \
  61. CATCH_UNHANDLED_EXCEPTION(hr)
  62. #define END_JS_RUNTIME_CALL_AND_TRANSLATE_AND_GET_EXCEPTION_AND_ERROROBJECT_TO_HRESULT(hr, scriptContext, exceptionObject) \
  63. } \
  64. END_ENTER_SCRIPT \
  65. END_TRANSLATE_KNOWN_EXCEPTION_TO_HRESULT(hr) \
  66. END_GET_ERROROBJECT(hr, scriptContext, exceptionObject) \
  67. CATCH_UNHANDLED_EXCEPTION(hr)
  68. #define BEGIN_JS_RUNTIME_CALL_EX_AND_TRANSLATE_OOM_TO_HRESULT(scriptContext, doCleanup, hasCaller) \
  69. BEGIN_TRANSLATE_OOM_TO_HRESULT \
  70. BEGIN_ENTER_SCRIPT(scriptContext, doCleanup, /*isCallRoot*/ false, hasCaller) \
  71. {
  72. #define END_JS_RUNTIME_CALL_AND_TRANSLATE_OOM_TO_HRESULT(hr) \
  73. } \
  74. END_ENTER_SCRIPT \
  75. END_TRANSLATE_OOM_TO_HRESULT(hr)
  76. #define END_TRANSLATE_SO_OOM_JSEXCEPTION(hr) \
  77. } \
  78. catch (const JavascriptException& err) \
  79. { \
  80. err.GetAndClear(); \
  81. } \
  82. catch (Js::OutOfMemoryException) \
  83. { \
  84. } \
  85. catch (Js::StackOverflowException) \
  86. { \
  87. } \
  88. catch (...) \
  89. { \
  90. AssertMsg(false, "this exception didn't get handled"); \
  91. hr = E_FAIL; \
  92. } \
  93. }
  94. #ifdef CHECK_STACKWALK_EXCEPTION
  95. #define IGNORE_STACKWALK_EXCEPTION(scriptContext) \
  96. scriptContext->SetIgnoreStackWalkException();
  97. #else
  98. #define IGNORE_STACKWALK_EXCEPTION(scriptContext)
  99. #endif
  100. // For debugging scenarios where execution will go to debugging manager and come back to engine again, enforce the current EER to have
  101. // 'hasCaller' property set, which will enable the stack walking across frames.
  102. #define ENFORCE_ENTRYEXITRECORD_HASCALLER(scriptContext) \
  103. scriptContext->EnforceEERHasCaller();
  104. namespace Js
  105. {
  106. class EnterScriptObject
  107. {
  108. private:
  109. ScriptEntryExitRecord* entryExitRecord;
  110. bool doCleanup;
  111. bool isCallRoot;
  112. bool hasForcedEnter; // due to debugging.
  113. ScriptContext* scriptContext;
  114. HRESULT hr; // we need to throw outside of constructor
  115. JavascriptLibrary* library; // stack pin the library.
  116. public:
  117. EnterScriptObject(ScriptContext* scriptContext, ScriptEntryExitRecord* entryExitRecord,
  118. void * returnAddress, void * addrOfReturnAddress, bool doCleanup, bool isCallRoot, bool hasCaller);
  119. void VerifyEnterScript();
  120. ~EnterScriptObject();
  121. };
  122. template<bool stackProbe, bool leaveForHost, bool isFPUControlRestoreNeeded>
  123. class LeaveScriptObject
  124. {
  125. private:
  126. ScriptContext *const scriptContext;
  127. void *const frameAddress;
  128. bool leftScript;
  129. SmartFPUControlT<isFPUControlRestoreNeeded> savedFPUControl;
  130. DECLARE_EXCEPTION_CHECK_DATA;
  131. public:
  132. LeaveScriptObject(ScriptContext *const scriptContext, void *const frameAddress)
  133. : scriptContext(scriptContext),
  134. frameAddress(frameAddress),
  135. savedFPUControl()
  136. {
  137. leftScript = scriptContext->LeaveScriptStart<stackProbe, leaveForHost>(frameAddress);
  138. // We should be in script when we leave
  139. Assert(leftScript);
  140. SAVE_EXCEPTION_CHECK;
  141. }
  142. ~LeaveScriptObject()
  143. {
  144. // We should be in script when we leave
  145. Assert(leftScript);
  146. RESTORE_EXCEPTION_CHECK;
  147. if(leftScript)
  148. {
  149. scriptContext->LeaveScriptEnd<leaveForHost>(frameAddress);
  150. }
  151. }
  152. };
  153. }