// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// Runtime headers
#include "common.h"
#include "dllimport.h"

#include "interoplibinterface.h"

using ManagedToNativeExceptionCallback = Interop::ManagedToNativeExceptionCallback;

bool Interop::ShouldCheckForPendingException(_In_ NDirectMethodDesc* md)
{
    CONTRACTL
    {
        NOTHROW;
        GC_NOTRIGGER;
        PRECONDITION(md != NULL);
    }
    CONTRACTL_END;

#ifdef FEATURE_OBJCMARSHAL
    PTR_CUTF8 libraryName = md->GetLibNameRaw();
    PTR_CUTF8 entrypointName = md->GetEntrypointName();
    if (libraryName == NULL || entrypointName == NULL)
        return false;

    if (ObjCMarshalNative::IsRuntimeMessageSendFunction(libraryName, entrypointName))
        return true;
#endif // FEATURE_OBJCMARSHAL

    return false;
}

ManagedToNativeExceptionCallback Interop::GetPropagatingExceptionCallback(
    _In_ EECodeInfo* codeInfo,
    _In_ OBJECTHANDLE throwable,
    _Outptr_ void** context)
{
    CONTRACT(ManagedToNativeExceptionCallback)
    {
        NOTHROW;
        MODE_PREEMPTIVE;
        PRECONDITION(codeInfo != NULL);
        PRECONDITION(throwable != NULL);
        PRECONDITION(context != NULL);
    }
    CONTRACT_END;

    ManagedToNativeExceptionCallback callback = NULL;
    *context = NULL;

#ifdef FEATURE_OBJCMARSHAL
    EX_TRY
    {
        callback = (ManagedToNativeExceptionCallback)ObjCMarshalNative::GetPropagatingExceptionCallback(
            codeInfo,
            throwable,
            context);
    }
    EX_CATCH
    {
        EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(
            COR_E_EXECUTIONENGINE,
            W("Unhandled managed exception handler threw an exception."));
    }
    EX_END_CATCH_UNREACHABLE;
#endif // FEATURE_OBJCMARSHAL

    RETURN callback;
}

void Interop::OnGCStarted(_In_ int nCondemnedGeneration)
{
    CONTRACTL
    {
        NOTHROW;
        GC_NOTRIGGER;
    }
    CONTRACTL_END;

    //
    // Note that we could get nested GCStart/GCEnd calls, such as:
    // GCStart for Gen 2 background GC
    //    GCStart for Gen 0/1 foreground GC
    //    GCEnd   for Gen 0/1 foreground GC
    //    ...
    // GCEnd for Gen 2 background GC
    //
    // The nCondemnedGeneration >= 2 check takes care of this nesting problem
    //
    // See Interop::OnGCFinished()
    if (nCondemnedGeneration >= 2)
    {
#ifdef FEATURE_COMWRAPPERS
        ComWrappersNative::OnFullGCStarted();
#endif // FEATURE_COMWRAPPERS
    }
}

void Interop::OnGCFinished(_In_ int nCondemnedGeneration)
{
    CONTRACTL
    {
        NOTHROW;
        GC_NOTRIGGER;
    }
    CONTRACTL_END;

    // See Interop::OnGCStarted()
    if (nCondemnedGeneration >= 2)
    {
#ifdef FEATURE_COMWRAPPERS
        ComWrappersNative::OnFullGCFinished();
#endif // FEATURE_COMWRAPPERS
    }
}

void Interop::OnBeforeGCScanRoots(_In_ bool isConcurrent)
{
    CONTRACTL
    {
        NOTHROW;
        GC_NOTRIGGER;
    }
    CONTRACTL_END;

#ifdef FEATURE_OBJCMARSHAL
    // The Objective-C interop begin/end for reference counted
    // handles only occurs in non-concurrent scenarios. This contract
    // is because of the potential for locking as a synchronization
    // mechanism for Objective-C lifetime management.
    if (!isConcurrent)
        ObjCMarshalNative::BeforeRefCountedHandleCallbacks();
#endif // FEATURE_OBJCMARSHAL
}

void Interop::OnAfterGCScanRoots(_In_ bool isConcurrent)
{
    CONTRACTL
    {
        NOTHROW;
        GC_NOTRIGGER;
    }
    CONTRACTL_END;

#ifdef FEATURE_COMWRAPPERS
    ComWrappersNative::AfterRefCountedHandleCallbacks();
#endif // FEATURE_COMWRAPPERS

#ifdef FEATURE_OBJCMARSHAL
    // See Interop::OnBeforeGCScanRoots for why non-concurrent.
    if (!isConcurrent)
        ObjCMarshalNative::AfterRefCountedHandleCallbacks();
#endif // FEATURE_OBJCMARSHAL
}
