| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #pragma once
- #include "JsrtExceptionBase.h"
- #include "Exceptions/EvalDisabledException.h"
- //A class to ensure that even when exceptions are thrown we update any event recording info we were in the middle of
- #if ENABLE_TTD
- typedef TTD::TTDJsRTActionResultAutoRecorder TTDRecorder;
- #else
- typedef struct {} TTDRecorder;
- #endif
- #define PARAM_NOT_NULL(p) \
- if (p == nullptr) \
- { \
- return JsErrorNullArgument; \
- }
- #define VALIDATE_JSREF(p) \
- if (p == JS_INVALID_REFERENCE) \
- { \
- return JsErrorInvalidArgument; \
- } \
- #define MARSHAL_OBJECT(p, scriptContext) \
- Js::RecyclableObject* __obj = Js::RecyclableObject::FromVar(p); \
- if (__obj->GetScriptContext() != scriptContext) \
- { \
- if(__obj->GetScriptContext()->GetThreadContext() != scriptContext->GetThreadContext()) \
- { \
- return JsErrorWrongRuntime; \
- } \
- p = Js::CrossSite::MarshalVar(scriptContext, __obj); \
- }
- #define VALIDATE_INCOMING_RUNTIME_HANDLE(p) \
- { \
- if (p == JS_INVALID_RUNTIME_HANDLE) \
- { \
- return JsErrorInvalidArgument; \
- } \
- }
- #define VALIDATE_INCOMING_PROPERTYID(p) \
- { \
- if (p == JS_INVALID_REFERENCE || \
- Js::IsInternalPropertyId(((Js::PropertyRecord *)p)->GetPropertyId())) \
- { \
- return JsErrorInvalidArgument; \
- } \
- }
- #define VALIDATE_INCOMING_REFERENCE(p, scriptContext) \
- { \
- VALIDATE_JSREF(p); \
- if (Js::RecyclableObject::Is(p)) \
- { \
- MARSHAL_OBJECT(p, scriptContext) \
- } \
- }
- #define VALIDATE_INCOMING_OBJECT(p, scriptContext) \
- { \
- VALIDATE_JSREF(p); \
- if (!Js::JavascriptOperators::IsObject(p)) \
- { \
- return JsErrorArgumentNotObject; \
- } \
- MARSHAL_OBJECT(p, scriptContext) \
- }
- #define VALIDATE_INCOMING_OBJECT_OR_NULL(p, scriptContext) \
- { \
- VALIDATE_JSREF(p); \
- if (!Js::JavascriptOperators::IsObjectOrNull(p)) \
- { \
- return JsErrorArgumentNotObject; \
- } \
- MARSHAL_OBJECT(p, scriptContext) \
- }
- #define VALIDATE_INCOMING_FUNCTION(p, scriptContext) \
- { \
- VALIDATE_JSREF(p); \
- if (!Js::JavascriptFunction::Is(p)) \
- { \
- return JsErrorInvalidArgument; \
- } \
- MARSHAL_OBJECT(p, scriptContext) \
- }
- template <class Fn>
- JsErrorCode GlobalAPIWrapper_Core(Fn fn)
- {
- JsErrorCode errCode = JsNoError;
- try
- {
- // For now, treat this like an out of memory; consider if we should do something else here.
- AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
- errCode = fn();
- // These are error codes that should only be produced by the wrappers and should never
- // be produced by the internal calls.
- Assert(errCode != JsErrorFatal &&
- errCode != JsErrorNoCurrentContext &&
- errCode != JsErrorInExceptionState &&
- errCode != JsErrorInDisabledState &&
- errCode != JsErrorOutOfMemory &&
- errCode != JsErrorScriptException &&
- errCode != JsErrorScriptTerminated);
- }
- CATCH_STATIC_JAVASCRIPT_EXCEPTION_OBJECT(errCode)
- CATCH_OTHER_EXCEPTIONS(errCode)
- return errCode;
- }
- template <class Fn>
- JsErrorCode GlobalAPIWrapper(Fn fn)
- {
- TTDRecorder _actionEntryPopper;
- JsErrorCode errCode = GlobalAPIWrapper_Core([&fn, &_actionEntryPopper]() -> JsErrorCode
- {
- return fn(_actionEntryPopper);
- });
- #if ENABLE_TTD
- _actionEntryPopper.CompleteWithStatusCode(errCode);
- #endif
- return errCode;
- }
- template <class Fn>
- JsErrorCode GlobalAPIWrapper_NoRecord(Fn fn)
- {
- return GlobalAPIWrapper_Core([&fn]() -> JsErrorCode
- {
- return fn();
- });
- }
- JsErrorCode CheckContext(JsrtContext *currentContext, bool verifyRuntimeState, bool allowInObjectBeforeCollectCallback = false);
- template <bool verifyRuntimeState, class Fn>
- JsErrorCode ContextAPIWrapper_Core(Fn fn)
- {
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- JsErrorCode errCode = CheckContext(currentContext, verifyRuntimeState);
- if(errCode != JsNoError)
- {
- return errCode;
- }
- Js::ScriptContext *scriptContext = currentContext->GetScriptContext();
- try
- {
- AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_JavascriptException));
- // Enter script
- BEGIN_ENTER_SCRIPT(scriptContext, true, true, true)
- {
- errCode = fn(scriptContext);
- }
- END_ENTER_SCRIPT
- // These are error codes that should only be produced by the wrappers and should never
- // be produced by the internal calls.
- Assert(errCode != JsErrorFatal &&
- errCode != JsErrorNoCurrentContext &&
- errCode != JsErrorInExceptionState &&
- errCode != JsErrorInDisabledState &&
- errCode != JsErrorOutOfMemory &&
- errCode != JsErrorScriptException &&
- errCode != JsErrorScriptTerminated);
- }
- catch(Js::OutOfMemoryException)
- {
- errCode = JsErrorOutOfMemory;
- }
- catch(const Js::JavascriptException& err)
- {
- scriptContext->GetThreadContext()->SetRecordedException(err.GetAndClear());
- errCode = JsErrorScriptException;
- }
- catch(Js::ScriptAbortException)
- {
- Assert(scriptContext->GetThreadContext()->GetRecordedException() == nullptr);
- scriptContext->GetThreadContext()->SetRecordedException(scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject());
- errCode = JsErrorScriptTerminated;
- }
- catch(Js::EvalDisabledException)
- {
- errCode = JsErrorScriptEvalDisabled;
- }
- CATCH_OTHER_EXCEPTIONS(errCode)
- return errCode;
- }
- template <bool verifyRuntimeState, class Fn>
- JsErrorCode ContextAPIWrapper(Fn fn)
- {
- TTDRecorder _actionEntryPopper;
- JsErrorCode errCode = ContextAPIWrapper_Core<verifyRuntimeState>([&fn, &_actionEntryPopper](Js::ScriptContext* scriptContext) -> JsErrorCode
- {
- return fn(scriptContext, _actionEntryPopper);
- });
- #if ENABLE_TTD
- _actionEntryPopper.CompleteWithStatusCode(errCode);
- #endif
- return errCode;
- }
- template <bool verifyRuntimeState, class Fn>
- JsErrorCode ContextAPIWrapper_NoRecord(Fn fn)
- {
- return ContextAPIWrapper_Core<verifyRuntimeState>([&fn](Js::ScriptContext* scriptContext) -> JsErrorCode
- {
- return fn(scriptContext);
- });
- }
- // allowInObjectBeforeCollectCallback only when current API is guaranteed not to do recycler allocation.
- template <class Fn>
- JsErrorCode ContextAPINoScriptWrapper_Core(Fn fn, bool allowInObjectBeforeCollectCallback = false, bool scriptExceptionAllowed = false)
- {
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- JsErrorCode errCode = CheckContext(currentContext, /*verifyRuntimeState*/true, allowInObjectBeforeCollectCallback);
- if(errCode != JsNoError)
- {
- return errCode;
- }
- Js::ScriptContext *scriptContext = currentContext->GetScriptContext();
- try
- {
- // For now, treat this like an out of memory; consider if we should do something else here.
- AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
- errCode = fn(scriptContext);
- // These are error codes that should only be produced by the wrappers and should never
- // be produced by the internal calls.
- Assert(errCode != JsErrorFatal &&
- errCode != JsErrorNoCurrentContext &&
- errCode != JsErrorInExceptionState &&
- errCode != JsErrorInDisabledState &&
- errCode != JsErrorOutOfMemory &&
- (scriptExceptionAllowed || errCode != JsErrorScriptException) &&
- errCode != JsErrorScriptTerminated);
- }
- CATCH_STATIC_JAVASCRIPT_EXCEPTION_OBJECT(errCode)
- catch(const Js::JavascriptException& err)
- {
- AssertMsg(false, "Should never get JavascriptExceptionObject for ContextAPINoScriptWrapper.");
- scriptContext->GetThreadContext()->SetRecordedException(err.GetAndClear());
- errCode = JsErrorScriptException;
- }
- catch(Js::ScriptAbortException)
- {
- Assert(scriptContext->GetThreadContext()->GetRecordedException() == nullptr);
- scriptContext->GetThreadContext()->SetRecordedException(scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject());
- errCode = JsErrorScriptTerminated;
- }
- CATCH_OTHER_EXCEPTIONS(errCode)
- return errCode;
- }
- template <class Fn>
- JsErrorCode ContextAPINoScriptWrapper(Fn fn, bool allowInObjectBeforeCollectCallback = false, bool scriptExceptionAllowed = false)
- {
- TTDRecorder _actionEntryPopper;
- JsErrorCode errCode = ContextAPINoScriptWrapper_Core([&fn, &_actionEntryPopper](Js::ScriptContext* scriptContext) -> JsErrorCode
- {
- return fn(scriptContext, _actionEntryPopper);
- }, allowInObjectBeforeCollectCallback, scriptExceptionAllowed);
- #if ENABLE_TTD
- _actionEntryPopper.CompleteWithStatusCode(errCode);
- #endif
- return errCode;
- }
- template <class Fn>
- JsErrorCode ContextAPINoScriptWrapper_NoRecord(Fn fn, bool allowInObjectBeforeCollectCallback = false, bool scriptExceptionAllowed = false)
- {
- return ContextAPINoScriptWrapper_Core([&fn](Js::ScriptContext* scriptContext) -> JsErrorCode
- {
- return fn(scriptContext);
- }, allowInObjectBeforeCollectCallback, scriptExceptionAllowed);
- }
- template <class Fn>
- JsErrorCode SetContextAPIWrapper(JsrtContext* newContext, Fn fn)
- {
- JsrtContext* oldContext = JsrtContext::GetCurrent();
- Js::ScriptContext* scriptContext = newContext->GetScriptContext();
- JsErrorCode errorCode = JsNoError;
- try
- {
- // For now, treat this like an out of memory; consider if we should do something else here.
- AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow | ExceptionType_JavascriptException));
- if (JsrtContext::TrySetCurrent(newContext))
- {
- // Enter script
- BEGIN_ENTER_SCRIPT(scriptContext, true, true, true)
- {
- errorCode = fn(scriptContext);
- }
- END_ENTER_SCRIPT
- }
- else
- {
- errorCode = JsErrorWrongThread;
- }
- // These are error codes that should only be produced by the wrappers and should never
- // be produced by the internal calls.
- Assert(errorCode != JsErrorFatal &&
- errorCode != JsErrorNoCurrentContext &&
- errorCode != JsErrorInExceptionState &&
- errorCode != JsErrorInDisabledState &&
- errorCode != JsErrorOutOfMemory &&
- errorCode != JsErrorScriptException &&
- errorCode != JsErrorScriptTerminated);
- }
- catch (Js::OutOfMemoryException)
- {
- errorCode = JsErrorOutOfMemory;
- }
- catch (const Js::JavascriptException& err)
- {
- scriptContext->GetThreadContext()->SetRecordedException(err.GetAndClear());
- errorCode = JsErrorScriptException;
- }
- catch (Js::ScriptAbortException)
- {
- Assert(scriptContext->GetThreadContext()->GetRecordedException() == nullptr);
- scriptContext->GetThreadContext()->SetRecordedException(scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject());
- errorCode = JsErrorScriptTerminated;
- }
- catch (Js::EvalDisabledException)
- {
- errorCode = JsErrorScriptEvalDisabled;
- }
- catch (Js::StackOverflowException)
- {
- return JsErrorOutOfMemory;
- }
- CATCH_OTHER_EXCEPTIONS(errorCode)
- JsrtContext::TrySetCurrent(oldContext);
- return errorCode;
- }
- void HandleScriptCompileError(Js::ScriptContext * scriptContext, CompileScriptException * se, const WCHAR * sourceUrl = nullptr);
- #if DBG
- #define _PREPARE_RETURN_NO_EXCEPTION __debugCheckNoException.hasException = false;
- #else
- #define _PREPARE_RETURN_NO_EXCEPTION
- #endif
- #define BEGIN_JSRT_NO_EXCEPTION BEGIN_NO_EXCEPTION
- #define END_JSRT_NO_EXCEPTION END_NO_EXCEPTION return JsNoError;
- #define RETURN_NO_EXCEPTION(x) _PREPARE_RETURN_NO_EXCEPTION return x
- ////
- //Define compact TTD macros for use in the JSRT API's
- //A class to ensure that even when exceptions are thrown we update any event recording info we were in the middle of
- #if ENABLE_TTD
- #define PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(CTX) (CTX)->ShouldPerformRecordAction()
- #define PERFORM_JSRT_TTD_RECORD_ACTION(CTX, ACTION_CODE, ...) \
- if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(CTX)) \
- { \
- (CTX)->GetThreadContext()->TTDLog->##ACTION_CODE##(_actionEntryPopper, ##__VA_ARGS__); \
- }
- #define PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(CTX, RESULT) if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(CTX)) \
- { \
- _actionEntryPopper.SetResult(RESULT); \
- }
- //TODO: find and replace all of the occourences of this in jsrt.cpp
- #define PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(CTX) if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(CTX)) { AssertMsg(false, "Need to implement support here!!!"); }
- #else
- #define PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(CTX) false
- #define PERFORM_JSRT_TTD_RECORD_ACTION(CTX, ACTION_CODE, ...)
- #define PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(CTX, RESULT)
- #define PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(CTX)
- #endif
|