diff --git a/src/coreclr/src/vm/dllimport.cpp b/src/coreclr/src/vm/dllimport.cpp index 259af70a1e62d..01dbcd0cfcc86 100644 --- a/src/coreclr/src/vm/dllimport.cpp +++ b/src/coreclr/src/vm/dllimport.cpp @@ -2247,7 +2247,7 @@ DWORD NDirectStubLinker::EmitProfilerBeginTransitionCallback(ILCodeStream* pcsEm else { // we use a null pThread to indicate reverse interop - pcsEmit->EmitLDC(NULL); + pcsEmit->EmitLoadNullPtr(); } // In the unmanaged delegate case, we need the "this" object to retrieve the MD @@ -2269,8 +2269,9 @@ DWORD NDirectStubLinker::EmitProfilerBeginTransitionCallback(ILCodeStream* pcsEm } else { - pcsEmit->EmitLDC(NULL); + pcsEmit->EmitLDNULL(); } + pcsEmit->EmitCALL(METHOD__STUBHELPERS__PROFILER_BEGIN_TRANSITION_CALLBACK, 3, 1); // Store the MD for StubHelpers::ProfilerLeaveCallback(). @@ -2287,7 +2288,7 @@ void NDirectStubLinker::EmitProfilerEndTransitionCallback(ILCodeStream* pcsEmit, if (SF_IsReverseStub(dwStubFlags)) { // we use a null pThread to indicate reverse interop - pcsEmit->EmitLDC(NULL); + pcsEmit->EmitLoadNullPtr(); } else { diff --git a/src/tests/profiler/native/CMakeLists.txt b/src/tests/profiler/native/CMakeLists.txt index 1ce4332cf73f5..73af9302647b8 100644 --- a/src/tests/profiler/native/CMakeLists.txt +++ b/src/tests/profiler/native/CMakeLists.txt @@ -15,6 +15,7 @@ set(SOURCES getappdomainstaticaddress/getappdomainstaticaddress.cpp eltprofiler/slowpatheltprofiler.cpp releaseondetach/releaseondetach.cpp + transitions/transitions.cpp profiler.def profiler.cpp classfactory.cpp diff --git a/src/tests/profiler/native/classfactory.cpp b/src/tests/profiler/native/classfactory.cpp index 1e4d430e0ff61..aab949308ea82 100644 --- a/src/tests/profiler/native/classfactory.cpp +++ b/src/tests/profiler/native/classfactory.cpp @@ -11,6 +11,7 @@ #include "eltprofiler/slowpatheltprofiler.h" #include "gcprofiler/gcprofiler.h" #include "releaseondetach/releaseondetach.h" +#include "transitions/transitions.h" ClassFactory::ClassFactory(REFCLSID clsid) : refCount(0), clsid(clsid) { @@ -67,7 +68,8 @@ HRESULT STDMETHODCALLTYPE ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFI new GetAppDomainStaticAddress(), new SlowPathELTProfiler(), new GCProfiler(), - new ReleaseOnDetach() + new ReleaseOnDetach(), + new Transitions() // add new profilers here }; diff --git a/src/tests/profiler/native/profiler.def b/src/tests/profiler/native/profiler.def index 590fe13799c8a..38cdf6c0f5af1 100644 --- a/src/tests/profiler/native/profiler.def +++ b/src/tests/profiler/native/profiler.def @@ -4,4 +4,5 @@ EXPORTS DllGetClassObject PRIVATE DllCanUnloadNow PRIVATE PassBoolToProfiler PRIVATE + DoPInvoke PRIVATE diff --git a/src/tests/profiler/native/transitions/transitions.cpp b/src/tests/profiler/native/transitions/transitions.cpp new file mode 100644 index 0000000000000..2f504c70007bc --- /dev/null +++ b/src/tests/profiler/native/transitions/transitions.cpp @@ -0,0 +1,85 @@ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "transitions.h" + +Transitions::Transitions() : + _failures(0), + _sawEnter(false), + _sawLeave(false) +{ + +} + +GUID Transitions::GetClsid() +{ + // {027AD7BB-578E-4921-B29F-B540363D83EC} + GUID clsid = { 0x027AD7BB, 0x578E, 0x4921, { 0xB2, 0x9F, 0xB5, 0x40, 0x36, 0x3D, 0x83, 0xEC } }; + return clsid; +} + +HRESULT Transitions::Initialize(IUnknown* pICorProfilerInfoUnk) +{ + Profiler::Initialize(pICorProfilerInfoUnk); + + HRESULT hr = S_OK; + if (FAILED(hr = pCorProfilerInfo->SetEventMask2(COR_PRF_MONITOR_CODE_TRANSITIONS | COR_PRF_DISABLE_INLINING, 0))) + { + _failures++; + printf("FAIL: ICorProfilerInfo::SetEventMask2() failed hr=0x%x", hr); + return hr; + } + + return S_OK; +} + +HRESULT Transitions::Shutdown() +{ + Profiler::Shutdown(); + + if (_failures == 0 && _sawEnter && _sawLeave) + { + // If we're here, that means we were Released enough to trigger the destructor + printf("PROFILER TEST PASSES\n"); + } + else + { + auto boolFmt = [](bool b) { return b ? "true" : "false"; }; + printf("Test failed _failures=%d _sawEnter=%s _sawLeave=%s\n", + _failures.load(), boolFmt(_sawEnter), boolFmt(_sawLeave)); + } + + return S_OK; +} + +extern "C" EXPORT void STDMETHODCALLTYPE DoPInvoke(int i) +{ + printf("PInvoke received i=%d\n", i); +} + +HRESULT Transitions::UnmanagedToManagedTransition(FunctionID functionID, COR_PRF_TRANSITION_REASON reason) +{ + if (FunctionIsTargetFunction(functionID)) + { + _sawEnter = true; + } + + return S_OK; +} + +HRESULT Transitions::ManagedToUnmanagedTransition(FunctionID functionID, COR_PRF_TRANSITION_REASON reason) +{ + if (FunctionIsTargetFunction(functionID)) + { + _sawLeave = true; + } + + return S_OK; +} + +bool Transitions::FunctionIsTargetFunction(FunctionID functionID) +{ + String name = GetFunctionIDName(functionID); + return name == WCHAR("DoPInvoke"); +} \ No newline at end of file diff --git a/src/tests/profiler/native/transitions/transitions.h b/src/tests/profiler/native/transitions/transitions.h new file mode 100644 index 0000000000000..0ddf19ac51d88 --- /dev/null +++ b/src/tests/profiler/native/transitions/transitions.h @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma once + +#include "../profiler.h" + +class Transitions : public Profiler +{ +public: + Transitions(); + virtual ~Transitions() = default; + + virtual GUID GetClsid(); + virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk); + virtual HRESULT STDMETHODCALLTYPE Shutdown(); + virtual HRESULT STDMETHODCALLTYPE UnmanagedToManagedTransition(FunctionID functionID, COR_PRF_TRANSITION_REASON reason); + virtual HRESULT STDMETHODCALLTYPE ManagedToUnmanagedTransition(FunctionID functionID, COR_PRF_TRANSITION_REASON reason); + +private: + std::atomic _failures; + std::atomic _sawEnter; + std::atomic _sawLeave; + + bool FunctionIsTargetFunction(FunctionID functionID); +}; diff --git a/src/tests/profiler/transitions/transitions.cs b/src/tests/profiler/transitions/transitions.cs new file mode 100644 index 0000000000000..e250066f85ee3 --- /dev/null +++ b/src/tests/profiler/transitions/transitions.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +namespace Profiler.Tests +{ + class GCTests + { + static readonly Guid TransitionsGuid = new Guid("027AD7BB-578E-4921-B29F-B540363D83EC"); + + [DllImport("Profiler")] + public static extern void DoPInvoke(int i); + + public static int RunTest(String[] args) + { + DoPInvoke(13); + + return 100; + } + + public static int Main(string[] args) + { + if (args.Length > 0 && args[0].Equals("RunTest", StringComparison.OrdinalIgnoreCase)) + { + return RunTest(args); + } + + return ProfilerTestRunner.Run(profileePath: System.Reflection.Assembly.GetExecutingAssembly().Location, + testName: "Transitions", + profilerClsid: TransitionsGuid); + } + } +} diff --git a/src/tests/profiler/transitions/transitions.csproj b/src/tests/profiler/transitions/transitions.csproj new file mode 100644 index 0000000000000..c7b6a7b209a09 --- /dev/null +++ b/src/tests/profiler/transitions/transitions.csproj @@ -0,0 +1,15 @@ + + + .NETCoreApp + exe + BuildAndRun + true + 0 + + + + + + + +