Var JavascriptExternalFunction::StdCallExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...) { RUNTIME_ARGUMENTS(args, callInfo); JavascriptExternalFunction* externalFunction = static_cast<JavascriptExternalFunction*>(function); externalFunction->PrepareExternalCall(&args); ScriptContext * scriptContext = externalFunction->type->GetScriptContext(); AnalysisAssert(scriptContext); Var result = NULL; BEGIN_LEAVE_SCRIPT(scriptContext) { result = externalFunction->stdCallNativeMethod(function, ((callInfo.Flags & CallFlags_New) != 0), args.Values, args.Info.Count, externalFunction->callbackState); } END_LEAVE_SCRIPT(scriptContext); if (result != nullptr && !Js::TaggedNumber::Is(result)) { if (!Js::RecyclableObject::Is(result)) { Js::Throw::InternalError(); } Js::RecyclableObject * obj = Js::RecyclableObject::FromVar(result); // For JSRT, we could get result marshalled in different context. bool isJSRT = !(scriptContext->GetThreadContext()->GetIsThreadBound()); if (!isJSRT && obj->GetScriptContext() != scriptContext) { Js::Throw::InternalError(); } } if (scriptContext->HasRecordedException()) { bool considerPassingToDebugger = false; JavascriptExceptionObject* recordedException = scriptContext->GetAndClearRecordedException(&considerPassingToDebugger); if (recordedException != nullptr) { // If this is script termination, then throw ScriptAbortExceptio, else throw normal Exception object. if (recordedException == scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject()) { throw Js::ScriptAbortException(); } else { JavascriptExceptionOperators::RethrowExceptionObject(recordedException, scriptContext, considerPassingToDebugger); } } } return externalFunction->FinishExternalCall(result); }
// static Var CrossSite::MarshalVar(ScriptContext* scriptContext, Var value, bool fRequestWrapper) { // value might be null from disable implicit call if (value == nullptr || Js::TaggedNumber::Is(value)) { return value; } Js::RecyclableObject* object = RecyclableObject::UnsafeFromVar(value); if (fRequestWrapper || scriptContext != object->GetScriptContext()) { return MarshalVarInner(scriptContext, object, fRequestWrapper); } return value; }
Var JavascriptExternalFunction::StdCallExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...) { ARGUMENTS(args, callInfo); JavascriptExternalFunction* externalFunction = static_cast<JavascriptExternalFunction*>(function); externalFunction->PrepareExternalCall(&args); ScriptContext * scriptContext = externalFunction->type->GetScriptContext(); AnalysisAssert(scriptContext); if (args.Info.Count > USHORT_MAX) { // Due to compat reasons, stdcall external functions expect a ushort count of args. // To support more than this we will need a new API. Js::JavascriptError::ThrowTypeError(scriptContext, JSERR_ArgListTooLarge); } Var result = nullptr; Assert(callInfo.Count > 0); StdCallJavascriptMethodInfo info = { args[0], args.HasNewTarget() ? args.GetNewTarget() : args.IsNewCall() ? function : scriptContext->GetLibrary()->GetUndefined(), args.IsNewCall() }; #if ENABLE_TTD if(scriptContext->ShouldPerformRecordOrReplayAction()) { result = JavascriptExternalFunction::HandleRecordReplayExternalFunction_StdThunk(function, callInfo, args, scriptContext); } else { BEGIN_LEAVE_SCRIPT(scriptContext) { result = externalFunction->stdCallNativeMethod(function, args.Values, static_cast<USHORT>(args.Info.Count), &info, externalFunction->callbackState); } END_LEAVE_SCRIPT(scriptContext); } #else BEGIN_LEAVE_SCRIPT(scriptContext) { result = externalFunction->stdCallNativeMethod(function, args.Values, static_cast<USHORT>(args.Info.Count), &info, externalFunction->callbackState); } END_LEAVE_SCRIPT(scriptContext); #endif bool marshallingMayBeNeeded = false; if (result != nullptr) { marshallingMayBeNeeded = Js::RecyclableObject::Is(result); if (marshallingMayBeNeeded) { Js::RecyclableObject * obj = Js::RecyclableObject::FromVar(result); // For JSRT, we could get result marshalled in different context. bool isJSRT = scriptContext->GetThreadContext()->IsJSRT(); marshallingMayBeNeeded = obj->GetScriptContext() != scriptContext; if (!isJSRT && marshallingMayBeNeeded) { Js::Throw::InternalError(); } } } if (scriptContext->HasRecordedException()) { bool considerPassingToDebugger = false; JavascriptExceptionObject* recordedException = scriptContext->GetAndClearRecordedException(&considerPassingToDebugger); if (recordedException != nullptr) { // If this is script termination, then throw ScriptAbortExceptio, else throw normal Exception object. if (recordedException == scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject()) { throw Js::ScriptAbortException(); } else { JavascriptExceptionOperators::RethrowExceptionObject(recordedException, scriptContext, considerPassingToDebugger); } } } if (result == nullptr) { result = scriptContext->GetLibrary()->GetUndefined(); } else if (marshallingMayBeNeeded) { result = CrossSite::MarshalVar(scriptContext, result); } return result; }
Var JavascriptExternalFunction::StdCallExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...) { ARGUMENTS(args, callInfo); JavascriptExternalFunction* externalFunction = static_cast<JavascriptExternalFunction*>(function); externalFunction->PrepareExternalCall(&args); ScriptContext * scriptContext = externalFunction->type->GetScriptContext(); AnalysisAssert(scriptContext); Var result = NULL; #if ENABLE_TTD if(scriptContext->ShouldPerformRecordOrReplayAction()) { result = JavascriptExternalFunction::HandleRecordReplayExternalFunction_StdThunk(function, callInfo, args, scriptContext); } else { BEGIN_LEAVE_SCRIPT(scriptContext) { result = externalFunction->stdCallNativeMethod(function, ((callInfo.Flags & CallFlags_New) != 0), args.Values, args.Info.Count, externalFunction->callbackState); } END_LEAVE_SCRIPT(scriptContext); } #else BEGIN_LEAVE_SCRIPT(scriptContext) { result = externalFunction->stdCallNativeMethod(function, ((callInfo.Flags & CallFlags_New) != 0), args.Values, args.Info.Count, externalFunction->callbackState); } END_LEAVE_SCRIPT(scriptContext); #endif if (result != nullptr && !Js::TaggedNumber::Is(result)) { if (!Js::RecyclableObject::Is(result)) { Js::Throw::InternalError(); } Js::RecyclableObject * obj = Js::RecyclableObject::FromVar(result); // For JSRT, we could get result marshalled in different context. bool isJSRT = scriptContext->GetThreadContext()->IsJSRT(); if (!isJSRT && obj->GetScriptContext() != scriptContext) { Js::Throw::InternalError(); } } if (scriptContext->HasRecordedException()) { bool considerPassingToDebugger = false; JavascriptExceptionObject* recordedException = scriptContext->GetAndClearRecordedException(&considerPassingToDebugger); if (recordedException != nullptr) { // If this is script termination, then throw ScriptAbortExceptio, else throw normal Exception object. if (recordedException == scriptContext->GetThreadContext()->GetPendingTerminatedErrorObject()) { throw Js::ScriptAbortException(); } else { JavascriptExceptionOperators::RethrowExceptionObject(recordedException, scriptContext, considerPassingToDebugger); } } } if (result == nullptr) { result = scriptContext->GetLibrary()->GetUndefined(); } else { result = CrossSite::MarshalVar(scriptContext, result); } return result; }