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 - не сделает ли это проблему с очисткой стека несущественной, так как во время вызова не производится никаких изменений стека?