
On 2019-03-01, Neil Schemenauer wrote:
Maybe we could have it both ways (binary compatiblity or lower overhead). Use an inline function like the following:
static inline void DoSomething(JNIEnv *env, jobject obj) {
#ifdef STABLE_BINARY_INTERFACE ((*env)->DoSomething(env, ob)) #else ... inline implementation of env->DoSomething #fi }
I was thinking about this and had a refinement idea. Can we have an extension API with most of the benefits of inline code but still retain binary compatibility if the extension is used with a different VM or a different version of the VM? Keep a flag in the 'env' struct to record if the inline code can be used (e.g. abi_flags). That flags can be set when the extension initializes itself. If the extension was compiled with a non-compatible VM, flags would be false. Then, the API functions can do the following:
static inline void
DoSomething(JNIEnv *env, jobject obj)
{
if ((*env)->abi_flags & ABI_INLINE_OKAY) {
... inline implementation of env->DoSomething
}
else {
((*env)->DoSomething(env, ob))
}
}
I think this could provide a performance boost. The value of abi_flags should be in L1 cache or maybe even a register. The branch prediction should have no trouble to predict the 'if'. We would need to write some benchmarks to determine if this is a really a win.
As a concrete example of a function like PyList_GET_ITEM():
// note that 'list' must be a list object, no type checking
static inline PyHandle
PyHandle_ListGetItem(PyEnv *env, PyHandle list, ssize_t i)
{
if ((*env)->abi_flags & ABI_INLINE_OKAY) {
PyObject *op = ((PyListObject *)list)->ob_item[i];
Py_INCREF(op); // unlike PyList_GET_ITEM(), not borrowed
return (PyHandle)op;
}
else {
return ((*env)->ListGetItem(env, list, i));
}
}
Regards,
Neil