Var JavascriptExternalFunction::ExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...) { RUNTIME_ARGUMENTS(args, callInfo); JavascriptExternalFunction* externalFunction = static_cast<JavascriptExternalFunction*>(function); // Deferred constructors which are not callable fall back to using the RecyclableObject::DefaultEntryPoint. In order to call // this function we have to be inside script so all this and return before doing any of the external call preparation. if (externalFunction->nativeMethod == Js::RecyclableObject::DefaultExternalEntryPoint) { return Js::RecyclableObject::DefaultExternalEntryPoint(function, callInfo, args.Values); } ScriptContext * scriptContext = externalFunction->type->GetScriptContext(); #ifdef ENABLE_DIRECTCALL_TELEMETRY DirectCallTelemetry::AutoLogger logger(scriptContext, externalFunction, &args); #endif externalFunction->PrepareExternalCall(&args); Var result = nullptr; BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext) { // Don't do stack probe since BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION does that for us already result = externalFunction->nativeMethod(function, callInfo, args.Values); } END_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext); return externalFunction->FinishExternalCall(result); }
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); }
Var JavascriptExternalFunction::ExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...) { ARGUMENTS(args, callInfo); JavascriptExternalFunction* externalFunction = static_cast<JavascriptExternalFunction*>(function); ScriptContext * scriptContext = externalFunction->type->GetScriptContext(); #ifdef ENABLE_DIRECTCALL_TELEMETRY DirectCallTelemetry::AutoLogger logger(scriptContext, externalFunction, &args); #endif externalFunction->PrepareExternalCall(&args); #if ENABLE_TTD Var result = nullptr; if(scriptContext->ShouldPerformRecordOrReplayAction()) { result = JavascriptExternalFunction::HandleRecordReplayExternalFunction_Thunk(externalFunction, callInfo, args, scriptContext); } else { BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext) { // Don't do stack probe since BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION does that for us already result = externalFunction->nativeMethod(function, callInfo, args.Values); } END_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext); } #else Var result = nullptr; BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext) { // Don't do stack probe since BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION does that for us already result = externalFunction->nativeMethod(function, callInfo, args.Values); } END_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext); #endif if (result == nullptr) { #pragma warning(push) #pragma warning(disable:6011) // scriptContext cannot be null here result = scriptContext->GetLibrary()->GetUndefined(); #pragma warning(pop) } else { 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); 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; }