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);
    }
Exemplo n.º 2
0
 // 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;
    }