JsrtInternal.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  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. #include "JsrtExceptionBase.h"
  7. #include "Exceptions/EvalDisabledException.h"
  8. //A class to ensure that even when exceptions are thrown we update any event recording info we were in the middle of
  9. #if ENABLE_TTD
  10. typedef TTD::TTDJsRTActionResultAutoRecorder TTDRecorder;
  11. #else
  12. typedef struct {} TTDRecorder;
  13. #endif
  14. #ifdef NTBUILD // non-browser
  15. #define JSRT_VERIFY_RUNTIME_STATE
  16. #endif
  17. // JSRT Unsafe mode leaves runtime health-state responsibility to the host
  18. #ifndef JSRT_VERIFY_RUNTIME_STATE
  19. #define JSRT_MAYBE_TRUE false
  20. #else
  21. #define JSRT_MAYBE_TRUE true
  22. #endif
  23. #define PARAM_NOT_NULL(p) \
  24. if (p == nullptr) \
  25. { \
  26. return JsErrorNullArgument; \
  27. }
  28. #define VALIDATE_JSREF(p) \
  29. if (p == JS_INVALID_REFERENCE) \
  30. { \
  31. return JsErrorInvalidArgument; \
  32. } \
  33. #define MARSHAL_OBJECT(p, scriptContext) \
  34. Js::RecyclableObject* __obj = Js::RecyclableObject::FromVar(p); \
  35. if (__obj->GetScriptContext() != scriptContext) \
  36. { \
  37. if(__obj->GetScriptContext()->GetThreadContext() != scriptContext->GetThreadContext()) \
  38. { \
  39. return JsErrorWrongRuntime; \
  40. } \
  41. p = Js::CrossSite::MarshalVar(scriptContext, __obj); \
  42. }
  43. #define VALIDATE_INCOMING_RUNTIME_HANDLE(p) \
  44. { \
  45. if (p == JS_INVALID_RUNTIME_HANDLE) \
  46. { \
  47. return JsErrorInvalidArgument; \
  48. } \
  49. }
  50. #define VALIDATE_INCOMING_PROPERTYID(p) \
  51. { \
  52. if (p == JS_INVALID_REFERENCE || \
  53. Js::IsInternalPropertyId(((Js::PropertyRecord *)p)->GetPropertyId())) \
  54. { \
  55. return JsErrorInvalidArgument; \
  56. } \
  57. }
  58. #define VALIDATE_INCOMING_REFERENCE(p, scriptContext) \
  59. { \
  60. VALIDATE_JSREF(p); \
  61. if (Js::RecyclableObject::Is(p)) \
  62. { \
  63. MARSHAL_OBJECT(p, scriptContext) \
  64. } \
  65. }
  66. #define VALIDATE_INCOMING_OBJECT(p, scriptContext) \
  67. { \
  68. VALIDATE_JSREF(p); \
  69. if (!Js::JavascriptOperators::IsObject(p)) \
  70. { \
  71. return JsErrorArgumentNotObject; \
  72. } \
  73. MARSHAL_OBJECT(p, scriptContext) \
  74. }
  75. #define VALIDATE_INCOMING_RECYCLABLE(p, scriptContext) \
  76. { \
  77. VALIDATE_JSREF(p); \
  78. if (!Js::RecyclableObject::Is(p)) \
  79. { \
  80. return JsErrorInvalidArgument; \
  81. } \
  82. MARSHAL_OBJECT(p, scriptContext) \
  83. }
  84. #define VALIDATE_INCOMING_OBJECT_OR_NULL(p, scriptContext) \
  85. { \
  86. VALIDATE_JSREF(p); \
  87. if (!Js::JavascriptOperators::IsObjectOrNull(p)) \
  88. { \
  89. return JsErrorArgumentNotObject; \
  90. } \
  91. MARSHAL_OBJECT(p, scriptContext) \
  92. }
  93. #define VALIDATE_INCOMING_FUNCTION(p, scriptContext) \
  94. { \
  95. VALIDATE_JSREF(p); \
  96. if (!Js::JavascriptFunction::Is(p)) \
  97. { \
  98. return JsErrorInvalidArgument; \
  99. } \
  100. MARSHAL_OBJECT(p, scriptContext) \
  101. }
  102. template <class Fn>
  103. JsErrorCode GlobalAPIWrapper_Core(Fn fn)
  104. {
  105. JsErrorCode errCode = JsNoError;
  106. try
  107. {
  108. // For now, treat this like an out of memory; consider if we should do something else here.
  109. AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
  110. errCode = fn();
  111. // These are error codes that should only be produced by the wrappers and should never
  112. // be produced by the internal calls.
  113. Assert(errCode != JsErrorFatal &&
  114. errCode != JsErrorNoCurrentContext &&
  115. errCode != JsErrorInExceptionState &&
  116. errCode != JsErrorInDisabledState &&
  117. errCode != JsErrorOutOfMemory &&
  118. errCode != JsErrorScriptException &&
  119. errCode != JsErrorScriptTerminated);
  120. }
  121. CATCH_STATIC_JAVASCRIPT_EXCEPTION_OBJECT(errCode)
  122. CATCH_OTHER_EXCEPTIONS(errCode)
  123. return errCode;
  124. }
  125. template <class Fn>
  126. JsErrorCode GlobalAPIWrapper(Fn fn)
  127. {
  128. TTDRecorder _actionEntryPopper;
  129. JsErrorCode errCode = GlobalAPIWrapper_Core([&fn, &_actionEntryPopper]() -> JsErrorCode
  130. {
  131. return fn(_actionEntryPopper);
  132. });
  133. #if ENABLE_TTD
  134. _actionEntryPopper.CompleteWithStatusCode(errCode);
  135. #endif
  136. return errCode;
  137. }
  138. template <class Fn>
  139. JsErrorCode GlobalAPIWrapper_NoRecord(Fn fn)
  140. {
  141. return GlobalAPIWrapper_Core([&fn]() -> JsErrorCode
  142. {
  143. return fn();
  144. });
  145. }
  146. JsErrorCode CheckContext(JsrtContext *currentContext, bool verifyRuntimeState, bool allowInObjectBeforeCollectCallback = false);
  147. template <bool verifyRuntimeState, class Fn>
  148. JsErrorCode ContextAPIWrapper_Core(Fn fn)
  149. {
  150. JsrtContext *currentContext = JsrtContext::GetCurrent();
  151. JsErrorCode errCode = CheckContext(currentContext, verifyRuntimeState);
  152. if(errCode != JsNoError)
  153. {
  154. return errCode;
  155. }
  156. Js::ScriptContext *scriptContext = currentContext->GetScriptContext();
  157. try
  158. {
  159. AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_JavascriptException));
  160. // Enter script
  161. BEGIN_ENTER_SCRIPT(scriptContext, true, true, true)
  162. {
  163. errCode = fn(scriptContext);
  164. }
  165. END_ENTER_SCRIPT
  166. // These are error codes that should only be produced by the wrappers and should never
  167. // be produced by the internal calls.
  168. Assert(errCode != JsErrorFatal &&
  169. errCode != JsErrorNoCurrentContext &&
  170. errCode != JsErrorInExceptionState &&
  171. errCode != JsErrorInDisabledState &&
  172. errCode != JsErrorOutOfMemory &&
  173. errCode != JsErrorScriptException &&
  174. errCode != JsErrorScriptTerminated);
  175. }
  176. catch(Js::OutOfMemoryException)
  177. {
  178. errCode = JsErrorOutOfMemory;
  179. }
  180. catch(const Js::JavascriptException& err)
  181. {
  182. scriptContext->GetThreadContext()->SetRecordedException(err.GetAndClear());
  183. errCode = JsErrorScriptException;
  184. }
  185. catch(Js::ScriptAbortException)
  186. {
  187. Assert(scriptContext->GetThreadContext()->GetRecordedException() == nullptr);
  188. scriptContext->GetThreadContext()->SetRecordedException(scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject());
  189. errCode = JsErrorScriptTerminated;
  190. }
  191. catch(Js::EvalDisabledException)
  192. {
  193. errCode = JsErrorScriptEvalDisabled;
  194. }
  195. CATCH_OTHER_EXCEPTIONS(errCode)
  196. return errCode;
  197. }
  198. template <bool verifyRuntimeState, class Fn>
  199. JsErrorCode ContextAPIWrapper(Fn fn)
  200. {
  201. TTDRecorder _actionEntryPopper;
  202. JsErrorCode errCode = ContextAPIWrapper_Core<verifyRuntimeState>([&fn, &_actionEntryPopper](Js::ScriptContext* scriptContext) -> JsErrorCode
  203. {
  204. return fn(scriptContext, _actionEntryPopper);
  205. });
  206. #if ENABLE_TTD
  207. _actionEntryPopper.CompleteWithStatusCode(errCode);
  208. #endif
  209. return errCode;
  210. }
  211. template <bool verifyRuntimeState, class Fn>
  212. JsErrorCode ContextAPIWrapper_NoRecord(Fn fn)
  213. {
  214. return ContextAPIWrapper_Core<verifyRuntimeState>([&fn](Js::ScriptContext* scriptContext) -> JsErrorCode
  215. {
  216. return fn(scriptContext);
  217. });
  218. }
  219. // allowInObjectBeforeCollectCallback only when current API is guaranteed not to do recycler allocation.
  220. template <class Fn>
  221. JsErrorCode ContextAPINoScriptWrapper_Core(Fn fn, bool allowInObjectBeforeCollectCallback = false,
  222. bool scriptExceptionAllowed = false)
  223. {
  224. JsrtContext *currentContext = JsrtContext::GetCurrent();
  225. JsErrorCode errCode = CheckContext(currentContext, /*verifyRuntimeState*/JSRT_MAYBE_TRUE,
  226. allowInObjectBeforeCollectCallback);
  227. if(errCode != JsNoError)
  228. {
  229. return errCode;
  230. }
  231. Js::ScriptContext *scriptContext = currentContext->GetScriptContext();
  232. try
  233. {
  234. // For now, treat this like an out of memory; consider if we should do something else here.
  235. AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
  236. errCode = fn(scriptContext);
  237. // These are error codes that should only be produced by the wrappers and should never
  238. // be produced by the internal calls.
  239. Assert(errCode != JsErrorFatal &&
  240. errCode != JsErrorNoCurrentContext &&
  241. errCode != JsErrorInExceptionState &&
  242. errCode != JsErrorInDisabledState &&
  243. errCode != JsErrorOutOfMemory &&
  244. (scriptExceptionAllowed || errCode != JsErrorScriptException) &&
  245. errCode != JsErrorScriptTerminated);
  246. }
  247. CATCH_STATIC_JAVASCRIPT_EXCEPTION_OBJECT(errCode)
  248. catch(const Js::JavascriptException& err)
  249. {
  250. AssertMsg(false, "Should never get JavascriptExceptionObject for ContextAPINoScriptWrapper.");
  251. scriptContext->GetThreadContext()->SetRecordedException(err.GetAndClear());
  252. errCode = JsErrorScriptException;
  253. }
  254. catch(Js::ScriptAbortException)
  255. {
  256. Assert(scriptContext->GetThreadContext()->GetRecordedException() == nullptr);
  257. scriptContext->GetThreadContext()->SetRecordedException(scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject());
  258. errCode = JsErrorScriptTerminated;
  259. }
  260. CATCH_OTHER_EXCEPTIONS(errCode)
  261. return errCode;
  262. }
  263. template <class Fn>
  264. JsErrorCode ContextAPINoScriptWrapper(Fn fn, bool allowInObjectBeforeCollectCallback = false, bool scriptExceptionAllowed = false)
  265. {
  266. TTDRecorder _actionEntryPopper;
  267. JsErrorCode errCode = ContextAPINoScriptWrapper_Core([&fn, &_actionEntryPopper](Js::ScriptContext* scriptContext) -> JsErrorCode
  268. {
  269. return fn(scriptContext, _actionEntryPopper);
  270. }, allowInObjectBeforeCollectCallback, scriptExceptionAllowed);
  271. #if ENABLE_TTD
  272. _actionEntryPopper.CompleteWithStatusCode(errCode);
  273. #endif
  274. return errCode;
  275. }
  276. template <class Fn>
  277. JsErrorCode ContextAPINoScriptWrapper_NoRecord(Fn fn, bool allowInObjectBeforeCollectCallback = false, bool scriptExceptionAllowed = false)
  278. {
  279. return ContextAPINoScriptWrapper_Core([&fn](Js::ScriptContext* scriptContext) -> JsErrorCode
  280. {
  281. return fn(scriptContext);
  282. }, allowInObjectBeforeCollectCallback, scriptExceptionAllowed);
  283. }
  284. template <class Fn>
  285. JsErrorCode SetContextAPIWrapper(JsrtContext* newContext, Fn fn)
  286. {
  287. JsrtContext* oldContext = JsrtContext::GetCurrent();
  288. Js::ScriptContext* scriptContext = newContext->GetScriptContext();
  289. JsErrorCode errorCode = JsNoError;
  290. try
  291. {
  292. // For now, treat this like an out of memory; consider if we should do something else here.
  293. AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow | ExceptionType_JavascriptException));
  294. if (JsrtContext::TrySetCurrent(newContext))
  295. {
  296. // Enter script
  297. BEGIN_ENTER_SCRIPT(scriptContext, true, true, true)
  298. {
  299. errorCode = fn(scriptContext);
  300. }
  301. END_ENTER_SCRIPT
  302. }
  303. else
  304. {
  305. errorCode = JsErrorWrongThread;
  306. }
  307. // These are error codes that should only be produced by the wrappers and should never
  308. // be produced by the internal calls.
  309. Assert(errorCode != JsErrorFatal &&
  310. errorCode != JsErrorNoCurrentContext &&
  311. errorCode != JsErrorInExceptionState &&
  312. errorCode != JsErrorInDisabledState &&
  313. errorCode != JsErrorOutOfMemory &&
  314. errorCode != JsErrorScriptException &&
  315. errorCode != JsErrorScriptTerminated);
  316. }
  317. catch (Js::OutOfMemoryException)
  318. {
  319. errorCode = JsErrorOutOfMemory;
  320. }
  321. catch (const Js::JavascriptException& err)
  322. {
  323. scriptContext->GetThreadContext()->SetRecordedException(err.GetAndClear());
  324. errorCode = JsErrorScriptException;
  325. }
  326. catch (Js::ScriptAbortException)
  327. {
  328. Assert(scriptContext->GetThreadContext()->GetRecordedException() == nullptr);
  329. scriptContext->GetThreadContext()->SetRecordedException(scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject());
  330. errorCode = JsErrorScriptTerminated;
  331. }
  332. catch (Js::EvalDisabledException)
  333. {
  334. errorCode = JsErrorScriptEvalDisabled;
  335. }
  336. catch (Js::StackOverflowException)
  337. {
  338. return JsErrorOutOfMemory;
  339. }
  340. CATCH_OTHER_EXCEPTIONS(errorCode)
  341. AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
  342. JsrtContext::TrySetCurrent(oldContext);
  343. return errorCode;
  344. }
  345. void HandleScriptCompileError(Js::ScriptContext * scriptContext, CompileScriptException * se, const WCHAR * sourceUrl = nullptr);
  346. #if DBG
  347. #define _PREPARE_RETURN_NO_EXCEPTION __debugCheckNoException.hasException = false;
  348. #else
  349. #define _PREPARE_RETURN_NO_EXCEPTION
  350. #endif
  351. #define BEGIN_JSRT_NO_EXCEPTION BEGIN_NO_EXCEPTION
  352. #define END_JSRT_NO_EXCEPTION END_NO_EXCEPTION return JsNoError;
  353. #define RETURN_NO_EXCEPTION(x) _PREPARE_RETURN_NO_EXCEPTION return x
  354. ////
  355. //Define compact TTD macros for use in the JSRT API's
  356. //A class to ensure that even when exceptions are thrown we update any event recording info we were in the middle of
  357. #if ENABLE_TTD
  358. #define PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(CTX) (CTX)->ShouldPerformRecordAction()
  359. #define PERFORM_JSRT_TTD_RECORD_ACTION(CTX, ACTION_CODE, ...) \
  360. if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(CTX)) \
  361. { \
  362. (CTX)->GetThreadContext()->TTDLog->##ACTION_CODE##(_actionEntryPopper, ##__VA_ARGS__); \
  363. }
  364. #define PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(CTX, RESULT) if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(CTX)) \
  365. { \
  366. _actionEntryPopper.SetResult(RESULT); \
  367. }
  368. //TODO: find and replace all of the occourences of this in jsrt.cpp
  369. #define PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(CTX) if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(CTX)) { AssertMsg(false, "Need to implement support here!!!"); }
  370. #else
  371. #define PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(CTX) false
  372. #define PERFORM_JSRT_TTD_RECORD_ACTION(CTX, ACTION_CODE, ...)
  373. #define PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(CTX, RESULT)
  374. #define PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(CTX)
  375. #endif