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); }