CLI calli на x64 соглашение о вызовах - PullRequest
0 голосов
/ 11 сентября 2018

Calli код операции требует соглашения о вызовах.По умолчанию это stdcall, в то время как extern "C" в нативных библиотеках использует cdecl.

JIT недавно разрешено для встроенных методов с calli, но только с по умолчаниюсоглашение о вызовах .Когда я вызываю метод с calli без unmanaged cdecl, он работает на x64, а производительность на 58% быстрее, чем DllImport, и в 2,2 раза быстрее, чем unmanaged function pointer.(на netcoreapp2.1, на net471 разница больше: 82% и 5,5x) Когда я запускаю метод с calli unmanaged cdecl, производительность находится на уровне DllImport (примерно на 1% медленнее).

Я прочитал , что на x64 больше нет путаницы с stdcall против cdecl, и все методы используют cdecl (или fastcall, видно, что в другом месте, не могу найти ссылку).Разница относится только к x86, где мой вызов без unmanaged cdecl действительно приводит к сбою приложения с segfault.

Рассматриваемый метод следующий .Для тестов я использую собственный метод noop только для измерения собственных издержек вызова.

  .method public hidebysig static int32 CalliCompress(uint8* source, native int sourceLength, uint8* destination, native int destinationLength, int32 clevel, native int functionPtr) cil managed aggressiveinlining
  {
    .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor()
             = {}
    // 
    .maxstack  6
    ldarg.0
    ldarg.1
    ldarg.2
    ldarg.3
    ldarg 4
    ldarg 5
    calli unmanaged cdecl int32 (uint8* source, native int sourceLength, uint8* destination, native int destinationLength, int32 clevel) 
    ret
  }

Мои вопросы:

1) Безопасно ли пропускать unmanaged cdecl после calli при x64«по замыслу» или мне просто повезло с этим примером?Если на x64 все вызовы cdecl, то я мог бы использовать JIT , обрабатывая поля static readonly как константы и отправлять их соответствующим методам бесплатно, просто используя if(IntPtr.Size == 8) {..call fast method..}else{..use unmanaged cdecl..}

2) Что означает caller or callee cleans the stack имею в виду?Моя нативная функция возвращает int, который находится в стеке после вызова.Это проблема того, кто удаляет этот int из стека?Или есть какая-то другая работа со стеком внутри нативной функции?Я контролирую нативную функцию и могу вернуть значение через параметр ref - не сделает ли это проблему с очисткой стека несущественной, так как во время вызова не производится никаких изменений стека?

1 Ответ

0 голосов
/ 18 сентября 2018

Ответ таков: это небезопасно. См. Это обсуждение в dotnet / coreclr : https://github.com/dotnet/coreclr/issues/19997

...