From 8dbf087364637d572a3a0879bb64b5c0de269a8e Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Fri, 22 Sep 2023 09:16:11 -0600 Subject: [PATCH 01/14] Add jpy.byte_buffer() function --- src/main/c/jpy_jbyte_buffer.c | 23 +++++++++++++ src/main/c/jpy_jbyte_buffer.h | 44 +++++++++++++++++++++++++ src/main/c/jpy_jobj.c | 13 ++++++-- src/main/c/jpy_module.c | 62 +++++++++++++++++++++++++++++++++++ src/main/c/jpy_module.h | 1 + 5 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 src/main/c/jpy_jbyte_buffer.c create mode 100644 src/main/c/jpy_jbyte_buffer.h diff --git a/src/main/c/jpy_jbyte_buffer.c b/src/main/c/jpy_jbyte_buffer.c new file mode 100644 index 00000000..63dd8179 --- /dev/null +++ b/src/main/c/jpy_jbyte_buffer.c @@ -0,0 +1,23 @@ +/* + * Copyright 2023 JPY-CONSORTIUM Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jpy_module.h" +#include "jpy_diag.h" +#include "jpy_jarray.h" +#include "jpy_jbyte_buffer.h" + +/* This file for now is just a place-holder for future JPy_ByteBufferWrapper specific functions. + */ \ No newline at end of file diff --git a/src/main/c/jpy_jbyte_buffer.h b/src/main/c/jpy_jbyte_buffer.h new file mode 100644 index 00000000..d400769a --- /dev/null +++ b/src/main/c/jpy_jbyte_buffer.h @@ -0,0 +1,44 @@ +/* + * Copyright 2023 JPY-CONSORTIUM Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef JPY_JBYTE_BUFFER_H +#define JPY_JBYTE_BUFFER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "jpy_compat.h" + +/** + * The Java ByteBuffer representation in Python. + * + * IMPORTANT: JPy_JByteBufferWrapper must only differ from the JPy_JObj structure by the 'obj' member + * since we use the same basic type, name JPy_JType for it. DON'T ever change member positions! + * @see JPy_JObj + */ +typedef struct JPy_JByteBufferWrapper +{ + PyObject_HEAD + jobject objectRef; + Py_buffer *pyBuffer; +} +JPy_JByteBufferWrapper; + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* !JPY_JBYTE_BUFFER_H */ diff --git a/src/main/c/jpy_jobj.c b/src/main/c/jpy_jobj.c index 579bdce9..84a4482f 100644 --- a/src/main/c/jpy_jobj.c +++ b/src/main/c/jpy_jobj.c @@ -20,6 +20,7 @@ #include "jpy_module.h" #include "jpy_diag.h" #include "jpy_jarray.h" +#include "jpy_jbyte_buffer.h" #include "jpy_jtype.h" #include "jpy_jobj.h" #include "jpy_jmethod.h" @@ -181,8 +182,12 @@ void JObj_dealloc(JPy_JObj* self) if (array->buf != NULL) { JArray_ReleaseJavaArrayElements(array, array->javaType); } - - } + } else if (jtype == JPy_JByteBuffer) { + JPy_JByteBufferWrapper* byteBufferWrapper; + byteBufferWrapper = (JPy_JByteBufferWrapper *) self; + PyBuffer_Release(byteBufferWrapper->pyBuffer); + PyMem_Free(byteBufferWrapper->pyBuffer); + } jenv = JPy_GetJNIEnv(); if (jenv != NULL) { @@ -707,9 +712,11 @@ int JType_InitSlots(JPy_JType* type) PyTypeObject* typeObj; jboolean isArray; jboolean isPrimitiveArray; + jboolean isByteBuffer; isArray = type->componentType != NULL; isPrimitiveArray = isArray && type->componentType->isPrimitive; + isByteBuffer = type == JPy_JByteBuffer; typeObj = JTYPE_AS_PYTYPE(type); @@ -727,7 +734,7 @@ int JType_InitSlots(JPy_JType* type) //Py_SET_TYPE(type, &JType_Type); //Py_SET_SIZE(type, sizeof (JPy_JType)); - typeObj->tp_basicsize = isPrimitiveArray ? sizeof (JPy_JArray) : sizeof (JPy_JObj); + typeObj->tp_basicsize = isPrimitiveArray ? sizeof (JPy_JArray) : (isByteBuffer ? sizeof(JPy_JByteBufferWrapper) : sizeof (JPy_JObj)); typeObj->tp_itemsize = 0; typeObj->tp_base = type->superType != NULL ? JTYPE_AS_PYTYPE(type->superType) : &JType_Type; //typeObj->tp_base = (PyTypeObject*) type->superType; diff --git a/src/main/c/jpy_module.c b/src/main/c/jpy_module.c index e8716fca..b3fddb4f 100644 --- a/src/main/c/jpy_module.c +++ b/src/main/c/jpy_module.c @@ -26,6 +26,7 @@ #include "jpy_jobj.h" #include "jpy_conv.h" #include "jpy_compat.h" +#include "jpy_jbyte_buffer.h" #include @@ -38,6 +39,7 @@ PyObject* JPy_destroy_jvm(PyObject* self, PyObject* args); PyObject* JPy_get_type(PyObject* self, PyObject* args, PyObject* kwds); PyObject* JPy_cast(PyObject* self, PyObject* args); PyObject* JPy_array(PyObject* self, PyObject* args); +PyObject* JPy_byte_buffer(PyObject* self, PyObject* args); static PyMethodDef JPy_Functions[] = { @@ -63,6 +65,9 @@ static PyMethodDef JPy_Functions[] = { "array(name, init) - Return a new Java array of given Java type (type name or type object) and initializer (array length or sequence). " "Possible primitive types are 'boolean', 'byte', 'char', 'short', 'int', 'long', 'float', and 'double'."}, + {"byte_buffer", JPy_byte_buffer, METH_VARARGS, + "byte_buffer(obj) - Return a new Java direct ByteBuffer referring to the Py_buffer provided by obj via its implemented Buffer Protocol. "}, + {NULL, NULL, 0, NULL} /*Sentinel*/ }; @@ -126,6 +131,7 @@ JPy_JType* JPy_JPyObject = NULL; JPy_JType* JPy_JPyModule = NULL; JPy_JType* JPy_JThrowable = NULL; JPy_JType* JPy_JStackTraceElement = NULL; +JPy_JType* JPy_JByteBuffer = NULL; // java.lang.Comparable @@ -228,6 +234,7 @@ jclass JPy_Void_JClass = NULL; jclass JPy_String_JClass = NULL; jclass JPy_PyObject_JClass = NULL; jclass JPy_PyDictWrapper_JClass = NULL; +jclass JPy_ByteBuffer_JClass = NULL; jmethodID JPy_PyObject_GetPointer_MID = NULL; jmethodID JPy_PyObject_UnwrapProxy_SMID = NULL; @@ -660,6 +667,53 @@ PyObject* JPy_array(PyObject* self, PyObject* args) JPy_FRAME(PyObject*, NULL, JPy_array_internal(jenv, self, args), 16) } +PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args) +{ + jobject byteBufferRef; + PyObject* pyObj; + PyObject* newPyObj; + Py_buffer *pyBuffer; + JPy_JByteBufferWrapper* byteBufferWrapper; + + if (!PyArg_ParseTuple(args, "O:byte_buffer", &pyObj)) { + return NULL; + } + + if (PyObject_CheckBuffer(pyObj) == 0) { + PyErr_SetString(PyExc_ValueError, "byte_buffer: argument 1 must be a Python object that supports the buffer protocol"); + return NULL; + } + + pyBuffer = (Py_buffer *)PyMem_Malloc(sizeof(Py_buffer)); + if (pyBuffer == NULL) { + return PyErr_NoMemory(); + } + + if (PyObject_GetBuffer(pyObj, pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) { + PyErr_SetString(PyExc_ValueError, "byte_buffer: the Python object failed to return a contiguous buffer."); + return NULL; + } + + byteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, pyBuffer->buf, pyBuffer->len); + if (byteBufferRef == NULL) { + return PyErr_NoMemory(); + } + + newPyObj = JObj_New(jenv, byteBufferRef); + if (newPyObj == NULL) { + return NULL; + } + byteBufferWrapper = (JPy_JByteBufferWrapper *) newPyObj; + byteBufferWrapper->pyBuffer = pyBuffer; + return (PyObject *)byteBufferWrapper; + +} + +PyObject* JPy_byte_buffer(PyObject* self, PyObject* args) +{ + JPy_FRAME(PyObject*, NULL, JPy_byte_buffer_internal(jenv, self, args), 16) +} + JPy_JType* JPy_GetNonObjectJType(JNIEnv* jenv, jclass classRef) { jclass primClassRef; @@ -927,6 +981,7 @@ int JPy_InitGlobalVars(JNIEnv* jenv) DEFINE_CLASS(JPy_String_JClass, "java/lang/String"); DEFINE_CLASS(JPy_Throwable_JClass, "java/lang/Throwable"); DEFINE_CLASS(JPy_StackTraceElement_JClass, "java/lang/StackTraceElement"); + DEFINE_CLASS(JPy_ByteBuffer_JClass, "java/nio/ByteBuffer"); // Non-Object types: Primitive types and void. DEFINE_NON_OBJECT_TYPE(JPy_JBoolean, JPy_Boolean_JClass); @@ -953,6 +1008,8 @@ int JPy_InitGlobalVars(JNIEnv* jenv) DEFINE_OBJECT_TYPE(JPy_JDoubleObj, JPy_Double_JClass); // Other objects. DEFINE_OBJECT_TYPE(JPy_JString, JPy_String_JClass); + DEFINE_OBJECT_TYPE(JPy_JByteBuffer, JPy_ByteBuffer_JClass); + DEFINE_OBJECT_TYPE(JPy_JThrowable, JPy_Throwable_JClass); DEFINE_OBJECT_TYPE(JPy_JStackTraceElement, JPy_StackTraceElement_JClass); DEFINE_METHOD(JPy_Throwable_getCause_MID, JPy_Throwable_JClass, "getCause", "()Ljava/lang/Throwable;"); @@ -994,6 +1051,7 @@ void JPy_ClearGlobalVars(JNIEnv* jenv) (*jenv)->DeleteGlobalRef(jenv, JPy_Number_JClass); (*jenv)->DeleteGlobalRef(jenv, JPy_Void_JClass); (*jenv)->DeleteGlobalRef(jenv, JPy_String_JClass); + (*jenv)->DeleteGlobalRef(jenv, JPy_ByteBuffer_JClass); } JPy_Comparable_JClass = NULL; @@ -1014,6 +1072,7 @@ void JPy_ClearGlobalVars(JNIEnv* jenv) JPy_Number_JClass = NULL; JPy_Void_JClass = NULL; JPy_String_JClass = NULL; + JPy_ByteBuffer_JClass = NULL; JPy_Object_ToString_MID = NULL; JPy_Object_HashCode_MID = NULL; @@ -1061,6 +1120,8 @@ void JPy_ClearGlobalVars(JNIEnv* jenv) JPy_XDECREF(JPy_JFloat); JPy_XDECREF(JPy_JDouble); JPy_XDECREF(JPy_JVoid); + JPy_XDECREF(JPy_JString); + JPy_XDECREF(JPy_JByteBuffer); JPy_XDECREF(JPy_JBooleanObj); JPy_XDECREF(JPy_JCharacterObj); JPy_XDECREF(JPy_JByteObj); @@ -1082,6 +1143,7 @@ void JPy_ClearGlobalVars(JNIEnv* jenv) JPy_JDouble = NULL; JPy_JVoid = NULL; JPy_JString = NULL; + JPy_JByteBuffer = NULL; JPy_JBooleanObj = NULL; JPy_JCharacterObj = NULL; JPy_JByteObj = NULL; diff --git a/src/main/c/jpy_module.h b/src/main/c/jpy_module.h index 36b48f31..ebe45c08 100644 --- a/src/main/c/jpy_module.h +++ b/src/main/c/jpy_module.h @@ -156,6 +156,7 @@ extern struct JPy_JType* JPy_JClass; extern struct JPy_JType* JPy_JString; extern struct JPy_JType* JPy_JPyObject; extern struct JPy_JType* JPy_JPyModule; +extern struct JPy_JType* JPy_JByteBuffer; // java.lang.Comparable extern jclass JPy_Comparable_JClass; From 58d345debedd832df26c18dea68aa21b8d358fc7 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Fri, 22 Sep 2023 13:41:43 -0600 Subject: [PATCH 02/14] Fix memory leak when error occurs --- src/main/c/jpy_jbyte_buffer.h | 2 +- src/main/c/jpy_jobj.c | 9 +++++++-- src/main/c/jpy_module.c | 3 +++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/c/jpy_jbyte_buffer.h b/src/main/c/jpy_jbyte_buffer.h index d400769a..8572ff85 100644 --- a/src/main/c/jpy_jbyte_buffer.h +++ b/src/main/c/jpy_jbyte_buffer.h @@ -26,7 +26,7 @@ extern "C" { /** * The Java ByteBuffer representation in Python. * - * IMPORTANT: JPy_JByteBufferWrapper must only differ from the JPy_JObj structure by the 'obj' member + * IMPORTANT: JPy_JByteBufferWrapper must only differ from the JPy_JObj structure by the 'pyBuffer' member * since we use the same basic type, name JPy_JType for it. DON'T ever change member positions! * @see JPy_JObj */ diff --git a/src/main/c/jpy_jobj.c b/src/main/c/jpy_jobj.c index 84a4482f..1cecd907 100644 --- a/src/main/c/jpy_jobj.c +++ b/src/main/c/jpy_jobj.c @@ -716,7 +716,6 @@ int JType_InitSlots(JPy_JType* type) isArray = type->componentType != NULL; isPrimitiveArray = isArray && type->componentType->isPrimitive; - isByteBuffer = type == JPy_JByteBuffer; typeObj = JTYPE_AS_PYTYPE(type); @@ -734,7 +733,13 @@ int JType_InitSlots(JPy_JType* type) //Py_SET_TYPE(type, &JType_Type); //Py_SET_SIZE(type, sizeof (JPy_JType)); - typeObj->tp_basicsize = isPrimitiveArray ? sizeof (JPy_JArray) : (isByteBuffer ? sizeof(JPy_JByteBufferWrapper) : sizeof (JPy_JObj)); + if (isPrimitiveArray) { + typeObj->tp_basicsize = sizeof(JPy_JArray); + } else if (type == JPy_JByteBuffer) { + typeObj->tp_basicsize = sizeof(JPy_JByteBufferWrapper); + } else { + typeObj->tp_basicsize = sizeof(JPy_JObj); + } typeObj->tp_itemsize = 0; typeObj->tp_base = type->superType != NULL ? JTYPE_AS_PYTYPE(type->superType) : &JType_Type; //typeObj->tp_base = (PyTypeObject*) type->superType; diff --git a/src/main/c/jpy_module.c b/src/main/c/jpy_module.c index b3fddb4f..7c9a1ccf 100644 --- a/src/main/c/jpy_module.c +++ b/src/main/c/jpy_module.c @@ -691,16 +691,19 @@ PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args) if (PyObject_GetBuffer(pyObj, pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) { PyErr_SetString(PyExc_ValueError, "byte_buffer: the Python object failed to return a contiguous buffer."); + PyMem_Free(pyBuffer); return NULL; } byteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, pyBuffer->buf, pyBuffer->len); if (byteBufferRef == NULL) { + PyMem_Free(pyBuffer); return PyErr_NoMemory(); } newPyObj = JObj_New(jenv, byteBufferRef); if (newPyObj == NULL) { + PyMem_Free(pyBuffer); return NULL; } byteBufferWrapper = (JPy_JByteBufferWrapper *) newPyObj; From 56c0cbdf14f8bbbc8eca782fcb5a4543878a2363 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Fri, 22 Sep 2023 14:11:53 -0600 Subject: [PATCH 03/14] Fix potential memory leak with PyBuffer_release --- src/main/c/jpy_module.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/c/jpy_module.c b/src/main/c/jpy_module.c index 7c9a1ccf..59f60416 100644 --- a/src/main/c/jpy_module.c +++ b/src/main/c/jpy_module.c @@ -697,12 +697,14 @@ PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args) byteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, pyBuffer->buf, pyBuffer->len); if (byteBufferRef == NULL) { + PyBuffer_Release(pyBuffer); PyMem_Free(pyBuffer); return PyErr_NoMemory(); } newPyObj = JObj_New(jenv, byteBufferRef); if (newPyObj == NULL) { + PyBuffer_Release(pyBuffer); PyMem_Free(pyBuffer); return NULL; } From db5c2f043a94d32601fcecc34ed8860ae50489ac Mon Sep 17 00:00:00 2001 From: Jianfeng Mao <4297243+jmao-denver@users.noreply.github.com> Date: Thu, 7 Dec 2023 08:35:15 -0700 Subject: [PATCH 04/14] Update src/main/c/jpy_jbyte_buffer.c Co-authored-by: Chip Kent <5250374+chipkent@users.noreply.github.com> --- src/main/c/jpy_jbyte_buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/c/jpy_jbyte_buffer.c b/src/main/c/jpy_jbyte_buffer.c index 63dd8179..66d04e4b 100644 --- a/src/main/c/jpy_jbyte_buffer.c +++ b/src/main/c/jpy_jbyte_buffer.c @@ -19,5 +19,6 @@ #include "jpy_jarray.h" #include "jpy_jbyte_buffer.h" -/* This file for now is just a place-holder for future JPy_ByteBufferWrapper specific functions. +/* + * This file for now is just a place-holder for future JPy_ByteBufferWrapper specific functions. */ \ No newline at end of file From 9fe3362b45cb3988e543aec05491c14e06a084bf Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Mon, 11 Dec 2023 15:17:27 -0700 Subject: [PATCH 05/14] Auto perform buffer->ByteBuffer conv for args --- src/main/c/jpy_conv.c | 35 ++++++++++++++++++++++++++++++ src/main/c/jpy_conv.h | 5 +++++ src/main/c/jpy_jobj.c | 1 - src/main/c/jpy_jtype.c | 48 +++++++++++++++++++++++++++++++++++++++++ src/main/c/jpy_module.c | 25 +++++++-------------- src/main/c/jpy_module.h | 3 +++ 6 files changed, 99 insertions(+), 18 deletions(-) diff --git a/src/main/c/jpy_conv.c b/src/main/c/jpy_conv.c index 1af0c8d4..9ca13c68 100644 --- a/src/main/c/jpy_conv.c +++ b/src/main/c/jpy_conv.c @@ -294,3 +294,38 @@ int JPy_AsJString(JNIEnv* jenv, PyObject* arg, jstring* stringRef) return 0; } +int JPy_AsJByteBuffer(JNIEnv* jenv, PyObject* pyObj, Py_buffer** pyBuffer, jobject* byteBufferRef) +{ + jobject tmpByteBufferRef; + + *pyBuffer = (Py_buffer *)PyMem_Malloc(sizeof(Py_buffer)); + if (*pyBuffer == NULL) { + PyErr_NoMemory(); + return -1; + } + + if (PyObject_GetBuffer(pyObj, *pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) { + PyErr_SetString(PyExc_ValueError, "byte_buffer: the Python object failed to return a contiguous buffer."); + PyMem_Free(*pyBuffer); + return -1; + } + + tmpByteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, (*pyBuffer)->buf, (*pyBuffer)->len); + if (tmpByteBufferRef == NULL) { + PyBuffer_Release(*pyBuffer); + PyMem_Free(*pyBuffer); + PyErr_NoMemory(); + return -1; + } + + *byteBufferRef = (*jenv)->CallObjectMethod(jenv, tmpByteBufferRef, JPy_ByteBuffer_AsReadOnlyBuffer_MID); + if (*byteBufferRef == NULL) { + PyBuffer_Release(*pyBuffer); + PyMem_Free(*pyBuffer); + JPy_DELETE_LOCAL_REF(tmpByteBufferRef); + PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a read-only ByteBuffer instance."); + return -1; + } + + return 0; +} diff --git a/src/main/c/jpy_conv.h b/src/main/c/jpy_conv.h index f1dfab64..3e145dd9 100644 --- a/src/main/c/jpy_conv.h +++ b/src/main/c/jpy_conv.h @@ -84,6 +84,11 @@ PyObject* JPy_FromJObjectWithType(JNIEnv* jenv, jobject objectRef, JPy_JType* ty */ int JPy_AsJString(JNIEnv* jenv, PyObject* pyObj, jstring* stringRef); +/** + * Convert Python buffer object to Java ByteBuffer (direct) which shares the underlying buffer in a read-only way.. + */ +int JPy_AsJByteBuffer(JNIEnv* jenv, PyObject* pyObj, Py_buffer **pyBuffer, jobject* byteBufferRef); + /** * Convert any Python objects to Java object. * diff --git a/src/main/c/jpy_jobj.c b/src/main/c/jpy_jobj.c index 1cecd907..cb401ceb 100644 --- a/src/main/c/jpy_jobj.c +++ b/src/main/c/jpy_jobj.c @@ -712,7 +712,6 @@ int JType_InitSlots(JPy_JType* type) PyTypeObject* typeObj; jboolean isArray; jboolean isPrimitiveArray; - jboolean isByteBuffer; isArray = type->componentType != NULL; isPrimitiveArray = isArray && type->componentType->isPrimitive; diff --git a/src/main/c/jpy_jtype.c b/src/main/c/jpy_jtype.c index 04843171..1e87ccdf 100644 --- a/src/main/c/jpy_jtype.c +++ b/src/main/c/jpy_jtype.c @@ -42,6 +42,7 @@ void JType_InitMethodParamDescriptorFunctions(JPy_JType* type, JPy_JMethod* meth int JType_ProcessField(JNIEnv* jenv, JPy_JType* declaringType, PyObject* fieldKey, const char* fieldName, jclass fieldClassRef, jboolean isStatic, jboolean isFinal, jfieldID fid); void JType_DisposeLocalObjectRefArg(JNIEnv* jenv, jvalue* value, void* data); void JType_DisposeReadOnlyBufferArg(JNIEnv* jenv, jvalue* value, void* data); +void JType_DisposeReadOnlyByteBufferArg(JNIEnv* jenv, jvalue* value, void* data); void JType_DisposeWritableBufferArg(JNIEnv* jenv, jvalue* value, void* data); @@ -1652,6 +1653,31 @@ int JType_ConvertPyArgToJStringArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescr return JPy_AsJString(jenv, pyArg, &value->l); } +int JType_MatchPyArgAsJByteBufferParam(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg) +{ + if (pyArg == Py_None) { + // Signal it is possible, but give low priority since we cannot perform any type checks on 'None' + return 1; + } + + if (PyObject_CheckBuffer(pyArg) == 1) { + return 100; + } + return 0; +} + +int JType_ConvertPyArgToJByteBufferArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, jvalue* value, JPy_ArgDisposer* disposer) +{ + Py_buffer *pyBuffer; + int ret; + + ret = JPy_AsJByteBuffer(jenv, pyArg, &pyBuffer, &value->l); + + disposer->data = pyBuffer; + disposer->DisposeArg = JType_DisposeReadOnlyByteBufferArg; + +} + int JType_ConvertPyArgToJPyObjectArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, jvalue* value, JPy_ArgDisposer* disposer) { disposer->data = NULL; @@ -2368,6 +2394,25 @@ void JType_DisposeLocalObjectRefArg(JNIEnv* jenv, jvalue* value, void* data) } } +void JType_DisposeReadOnlyByteBufferArg(JNIEnv* jenv, jvalue* value, void* data) +{ + Py_buffer* pyBuffer; + jobject jByteBuffer; + + pyBuffer = (Py_buffer*) data; + jByteBuffer = (jobject) value->l; + + JPy_DIAG_PRINT(JPy_DIAG_F_MEM, "JType_DisposeReadOnlyByteBufferArg: pyBuffer=%p, jByteBuffer=%p\n", pyBuffer, jByteBuffer); + + if (pyBuffer != NULL) { + PyBuffer_Release(pyBuffer); + PyMem_Del(pyBuffer); + } + if (jByteBuffer != NULL) { + JPy_DELETE_LOCAL_REF(jByteBuffer); + } +} + void JType_DisposeReadOnlyBufferArg(JNIEnv* jenv, jvalue* value, void* data) { Py_buffer* pyBuffer; @@ -2451,6 +2496,9 @@ void JType_InitParamDescriptorFunctions(JPy_ParamDescriptor* paramDescriptor, jb } else if (paramType == JPy_JString) { paramDescriptor->MatchPyArg = JType_MatchPyArgAsJStringParam; paramDescriptor->ConvertPyArg = JType_ConvertPyArgToJStringArg; + } else if (paramType == JPy_JByteBuffer) { + paramDescriptor->MatchPyArg = JType_MatchPyArgAsJByteBufferParam; + paramDescriptor->ConvertPyArg = JType_ConvertPyArgToJByteBufferArg; //} else if (paramType == JPy_JMap) { //} else if (paramType == JPy_JList) { //} else if (paramType == JPy_JSet) { diff --git a/src/main/c/jpy_module.c b/src/main/c/jpy_module.c index 59f60416..9256442c 100644 --- a/src/main/c/jpy_module.c +++ b/src/main/c/jpy_module.c @@ -133,7 +133,6 @@ JPy_JType* JPy_JThrowable = NULL; JPy_JType* JPy_JStackTraceElement = NULL; JPy_JType* JPy_JByteBuffer = NULL; - // java.lang.Comparable jclass JPy_Comparable_JClass = NULL; jmethodID JPy_Comparable_CompareTo_MID = NULL; @@ -235,6 +234,7 @@ jclass JPy_String_JClass = NULL; jclass JPy_PyObject_JClass = NULL; jclass JPy_PyDictWrapper_JClass = NULL; jclass JPy_ByteBuffer_JClass = NULL; +jmethodID JPy_ByteBuffer_AsReadOnlyBuffer_MID = NULL; jmethodID JPy_PyObject_GetPointer_MID = NULL; jmethodID JPy_PyObject_UnwrapProxy_SMID = NULL; @@ -684,34 +684,22 @@ PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args) return NULL; } - pyBuffer = (Py_buffer *)PyMem_Malloc(sizeof(Py_buffer)); - if (pyBuffer == NULL) { - return PyErr_NoMemory(); - } - - if (PyObject_GetBuffer(pyObj, pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) { - PyErr_SetString(PyExc_ValueError, "byte_buffer: the Python object failed to return a contiguous buffer."); - PyMem_Free(pyBuffer); + if (JPy_AsJByteBuffer(jenv, pyObj, &pyBuffer, &byteBufferRef) == -1) { return NULL; } - byteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, pyBuffer->buf, pyBuffer->len); - if (byteBufferRef == NULL) { - PyBuffer_Release(pyBuffer); - PyMem_Free(pyBuffer); - return PyErr_NoMemory(); - } - newPyObj = JObj_New(jenv, byteBufferRef); if (newPyObj == NULL) { + PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a ByteBufferWrapper instance."); PyBuffer_Release(pyBuffer); PyMem_Free(pyBuffer); + JPy_DELETE_LOCAL_REF(byteBufferRef); return NULL; } + byteBufferWrapper = (JPy_JByteBufferWrapper *) newPyObj; byteBufferWrapper->pyBuffer = pyBuffer; return (PyObject *)byteBufferWrapper; - } PyObject* JPy_byte_buffer(PyObject* self, PyObject* args) @@ -987,6 +975,8 @@ int JPy_InitGlobalVars(JNIEnv* jenv) DEFINE_CLASS(JPy_Throwable_JClass, "java/lang/Throwable"); DEFINE_CLASS(JPy_StackTraceElement_JClass, "java/lang/StackTraceElement"); DEFINE_CLASS(JPy_ByteBuffer_JClass, "java/nio/ByteBuffer"); + DEFINE_METHOD(JPy_ByteBuffer_AsReadOnlyBuffer_MID, JPy_ByteBuffer_JClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); + // Non-Object types: Primitive types and void. DEFINE_NON_OBJECT_TYPE(JPy_JBoolean, JPy_Boolean_JClass); @@ -1115,6 +1105,7 @@ void JPy_ClearGlobalVars(JNIEnv* jenv) JPy_Number_DoubleValue_MID = NULL; JPy_PyObject_GetPointer_MID = NULL; JPy_PyObject_UnwrapProxy_SMID = NULL; + JPy_ByteBuffer_AsReadOnlyBuffer_MID = NULL; JPy_XDECREF(JPy_JBoolean); JPy_XDECREF(JPy_JChar); diff --git a/src/main/c/jpy_module.h b/src/main/c/jpy_module.h index ebe45c08..1607681f 100644 --- a/src/main/c/jpy_module.h +++ b/src/main/c/jpy_module.h @@ -251,6 +251,9 @@ extern jmethodID JPy_Number_DoubleValue_MID; extern jclass JPy_String_JClass; extern jclass JPy_Void_JClass; +extern jclass JPy_ByteBuffer_JClass; +extern jmethodID JPy_ByteBuffer_AsReadOnlyBuffer_MID; + extern jclass JPy_PyObject_JClass; extern jmethodID JPy_PyObject_GetPointer_MID; extern jmethodID JPy_PyObject_UnwrapProxy_SMID; From 4e9b1fccbf0d922de8b0223f47ac1b85fad4ef43 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Wed, 13 Dec 2023 13:27:32 -0700 Subject: [PATCH 06/14] Refactor code in preparation for varargs support --- src/main/c/jpy_conv.c | 36 ------------ src/main/c/jpy_conv.h | 5 -- src/main/c/jpy_jtype.c | 119 ++++++++++++++++++++++++++++++++++------ src/main/c/jpy_jtype.h | 2 + src/main/c/jpy_module.c | 17 +----- 5 files changed, 105 insertions(+), 74 deletions(-) diff --git a/src/main/c/jpy_conv.c b/src/main/c/jpy_conv.c index 9ca13c68..e7d64534 100644 --- a/src/main/c/jpy_conv.c +++ b/src/main/c/jpy_conv.c @@ -293,39 +293,3 @@ int JPy_AsJString(JNIEnv* jenv, PyObject* arg, jstring* stringRef) return 0; } - -int JPy_AsJByteBuffer(JNIEnv* jenv, PyObject* pyObj, Py_buffer** pyBuffer, jobject* byteBufferRef) -{ - jobject tmpByteBufferRef; - - *pyBuffer = (Py_buffer *)PyMem_Malloc(sizeof(Py_buffer)); - if (*pyBuffer == NULL) { - PyErr_NoMemory(); - return -1; - } - - if (PyObject_GetBuffer(pyObj, *pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) { - PyErr_SetString(PyExc_ValueError, "byte_buffer: the Python object failed to return a contiguous buffer."); - PyMem_Free(*pyBuffer); - return -1; - } - - tmpByteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, (*pyBuffer)->buf, (*pyBuffer)->len); - if (tmpByteBufferRef == NULL) { - PyBuffer_Release(*pyBuffer); - PyMem_Free(*pyBuffer); - PyErr_NoMemory(); - return -1; - } - - *byteBufferRef = (*jenv)->CallObjectMethod(jenv, tmpByteBufferRef, JPy_ByteBuffer_AsReadOnlyBuffer_MID); - if (*byteBufferRef == NULL) { - PyBuffer_Release(*pyBuffer); - PyMem_Free(*pyBuffer); - JPy_DELETE_LOCAL_REF(tmpByteBufferRef); - PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a read-only ByteBuffer instance."); - return -1; - } - - return 0; -} diff --git a/src/main/c/jpy_conv.h b/src/main/c/jpy_conv.h index 3e145dd9..f1dfab64 100644 --- a/src/main/c/jpy_conv.h +++ b/src/main/c/jpy_conv.h @@ -84,11 +84,6 @@ PyObject* JPy_FromJObjectWithType(JNIEnv* jenv, jobject objectRef, JPy_JType* ty */ int JPy_AsJString(JNIEnv* jenv, PyObject* pyObj, jstring* stringRef); -/** - * Convert Python buffer object to Java ByteBuffer (direct) which shares the underlying buffer in a read-only way.. - */ -int JPy_AsJByteBuffer(JNIEnv* jenv, PyObject* pyObj, Py_buffer **pyBuffer, jobject* byteBufferRef); - /** * Convert any Python objects to Java object. * diff --git a/src/main/c/jpy_jtype.c b/src/main/c/jpy_jtype.c index 1e87ccdf..a327accb 100644 --- a/src/main/c/jpy_jtype.c +++ b/src/main/c/jpy_jtype.c @@ -23,6 +23,7 @@ #include "jpy_jfield.h" #include "jpy_jmethod.h" #include "jpy_jobj.h" +#include "jpy_jbyte_buffer.h" #include "jpy_conv.h" #include "jpy_compat.h" @@ -42,7 +43,7 @@ void JType_InitMethodParamDescriptorFunctions(JPy_JType* type, JPy_JMethod* meth int JType_ProcessField(JNIEnv* jenv, JPy_JType* declaringType, PyObject* fieldKey, const char* fieldName, jclass fieldClassRef, jboolean isStatic, jboolean isFinal, jfieldID fid); void JType_DisposeLocalObjectRefArg(JNIEnv* jenv, jvalue* value, void* data); void JType_DisposeReadOnlyBufferArg(JNIEnv* jenv, jvalue* value, void* data); -void JType_DisposeReadOnlyByteBufferArg(JNIEnv* jenv, jvalue* value, void* data); +void JType_DisposeByteBufferArg(JNIEnv* jenv, jvalue* value, void* data); void JType_DisposeWritableBufferArg(JNIEnv* jenv, jvalue* value, void* data); @@ -1663,19 +1664,76 @@ int JType_MatchPyArgAsJByteBufferParam(JNIEnv* jenv, JPy_ParamDescriptor* paramD if (PyObject_CheckBuffer(pyArg) == 1) { return 100; } - return 0; + + return JType_MatchPyArgAsJObject(jenv, paramDescriptor->type, pyArg); } -int JType_ConvertPyArgToJByteBufferArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, jvalue* value, JPy_ArgDisposer* disposer) +PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj) { + jobject byteBufferRef, tmpByteBufferRef; Py_buffer *pyBuffer; - int ret; - ret = JPy_AsJByteBuffer(jenv, pyArg, &pyBuffer, &value->l); + pyBuffer = (Py_buffer *)PyMem_Malloc(sizeof(Py_buffer)); + if (pyBuffer == NULL) { + PyErr_NoMemory(); + return NULL; + } + + if (PyObject_GetBuffer(pyObj, pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) { + PyErr_SetString(PyExc_ValueError, "byte_buffer: the Python object failed to return a contiguous buffer."); + PyMem_Free(pyBuffer); + return NULL; + } + + tmpByteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, pyBuffer->buf, pyBuffer->len); + if (tmpByteBufferRef == NULL) { + PyBuffer_Release(pyBuffer); + PyMem_Free(pyBuffer); + PyErr_NoMemory(); + return NULL; + } - disposer->data = pyBuffer; - disposer->DisposeArg = JType_DisposeReadOnlyByteBufferArg; + byteBufferRef = (*jenv)->CallObjectMethod(jenv, tmpByteBufferRef, JPy_ByteBuffer_AsReadOnlyBuffer_MID); + if (byteBufferRef == NULL) { + PyBuffer_Release(pyBuffer); + PyMem_Free(pyBuffer); + JPy_DELETE_LOCAL_REF(tmpByteBufferRef); + PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a read-only ByteBuffer instance."); + return NULL; + } + JPy_DELETE_LOCAL_REF(tmpByteBufferRef); + PyObject *newPyObj = JObj_New(jenv, byteBufferRef); + if (newPyObj == NULL) { + PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a ByteBufferWrapper instance."); + PyBuffer_Release(pyBuffer); + PyMem_Free(pyBuffer); + JPy_DELETE_LOCAL_REF(byteBufferRef); + return NULL; + } + JPy_DELETE_LOCAL_REF(byteBufferRef); + + JPy_JByteBufferWrapper* byteBufferWrapper = (JPy_JByteBufferWrapper *) newPyObj; + byteBufferWrapper->pyBuffer = pyBuffer; + return (PyObject *)byteBufferWrapper; +} + +int JType_ConvertPyArgToJByteBufferArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, jvalue* value, JPy_ArgDisposer* disposer) +{ + if (PyObject_CheckBuffer(pyArg)) { + disposer->data = JType_CreateJavaByteBufferWrapper(jenv, pyArg); + disposer->DisposeArg = JType_DisposeByteBufferArg; + JPy_JObj* obj = (JPy_JObj*) disposer->data; + value->l = obj->objectRef; + } else if (JObj_Check(pyArg)) { + JPy_JObj* obj = (JPy_JObj*) pyArg; + value->l = obj->objectRef; + disposer->data = NULL; + disposer->DisposeArg = NULL; + } else { + return -1; + } + return 0; } int JType_ConvertPyArgToJPyObjectArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, jvalue* value, JPy_ArgDisposer* disposer) @@ -1761,6 +1819,35 @@ int JType_MatchVarArgPyArgAsJStringParam(JNIEnv* jenv, JPy_ParamDescriptor* para return minMatch; } +int JType_MatchVarArgPyArgAsJByteBufferParam(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, int idx) +{ + Py_ssize_t argCount = PyTuple_Size(pyArg); + Py_ssize_t remaining = (argCount - idx); + + JPy_JType *componentType = paramDescriptor->type->componentType; + int minMatch = 100; + int ii; + + if (componentType != JPy_JByteBuffer) { + return 0; + } + + if (remaining == 0) { + return 10; + } + + for (ii = 0; ii < remaining; ii++) { + PyObject *unpack = PyTuple_GetItem(pyArg, idx + ii); + int matchValue = JType_MatchPyArgAsJByteBufferParam(jenv, paramDescriptor, unpack); + if (matchValue == 0) { + return 0; + } + minMatch = matchValue < minMatch ? matchValue : minMatch; + } + + return minMatch; +} + int JType_MatchVarArgPyArgAsJPyObjectParam(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, int idx) { Py_ssize_t argCount = PyTuple_Size(pyArg); @@ -2394,23 +2481,19 @@ void JType_DisposeLocalObjectRefArg(JNIEnv* jenv, jvalue* value, void* data) } } -void JType_DisposeReadOnlyByteBufferArg(JNIEnv* jenv, jvalue* value, void* data) +void JType_DisposeByteBufferArg(JNIEnv* jenv, jvalue* value, void* data) { - Py_buffer* pyBuffer; - jobject jByteBuffer; - pyBuffer = (Py_buffer*) data; - jByteBuffer = (jobject) value->l; + PyObject* byteBufferWrapper = (PyObject*) data; + jobject jByteBuffer = (jobject) value->l; - JPy_DIAG_PRINT(JPy_DIAG_F_MEM, "JType_DisposeReadOnlyByteBufferArg: pyBuffer=%p, jByteBuffer=%p\n", pyBuffer, jByteBuffer); + JPy_DIAG_PRINT(JPy_DIAG_F_MEM, "JType_DisposeByteBufferArg: byteBufferWrapper=%p, jByteBuffer=%p\n", byteBufferWrapper, jByteBuffer); - if (pyBuffer != NULL) { - PyBuffer_Release(pyBuffer); - PyMem_Del(pyBuffer); - } if (jByteBuffer != NULL) { JPy_DELETE_LOCAL_REF(jByteBuffer); } + + JPy_DECREF(byteBufferWrapper); } void JType_DisposeReadOnlyBufferArg(JNIEnv* jenv, jvalue* value, void* data) @@ -2530,6 +2613,8 @@ void JType_InitParamDescriptorFunctions(JPy_ParamDescriptor* paramDescriptor, jb paramDescriptor->MatchVarArgPyArg = JType_MatchVarArgPyArgAsJDoubleParam; } else if (paramType->componentType == JPy_JString) { paramDescriptor->MatchVarArgPyArg = JType_MatchVarArgPyArgAsJStringParam; + } else if (paramType->componentType == JPy_JByteBuffer) { + paramDescriptor->MatchVarArgPyArg = JType_MatchVarArgPyArgAsJByteBufferParam; } else if (paramType->componentType == JPy_JPyObject) { paramDescriptor->MatchVarArgPyArg = JType_MatchVarArgPyArgAsJPyObjectParam; } else { diff --git a/src/main/c/jpy_jtype.h b/src/main/c/jpy_jtype.h index 889a40d3..1d8da2f8 100644 --- a/src/main/c/jpy_jtype.h +++ b/src/main/c/jpy_jtype.h @@ -135,6 +135,8 @@ int JType_CreateJavaPyObject(JNIEnv* jenv, JPy_JType* type, PyObject* pyArg, job int JType_CreateJavaArray(JNIEnv* jenv, JPy_JType* componentType, PyObject* pyArg, jobject* objectRef, jboolean allowObjectWrapping); +PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj); + // Non-API. Defined in jpy_jobj.c int JType_InitSlots(JPy_JType* type); // Non-API. Defined in jpy_jtype.c diff --git a/src/main/c/jpy_module.c b/src/main/c/jpy_module.c index 9256442c..200f50ba 100644 --- a/src/main/c/jpy_module.c +++ b/src/main/c/jpy_module.c @@ -684,22 +684,7 @@ PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args) return NULL; } - if (JPy_AsJByteBuffer(jenv, pyObj, &pyBuffer, &byteBufferRef) == -1) { - return NULL; - } - - newPyObj = JObj_New(jenv, byteBufferRef); - if (newPyObj == NULL) { - PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a ByteBufferWrapper instance."); - PyBuffer_Release(pyBuffer); - PyMem_Free(pyBuffer); - JPy_DELETE_LOCAL_REF(byteBufferRef); - return NULL; - } - - byteBufferWrapper = (JPy_JByteBufferWrapper *) newPyObj; - byteBufferWrapper->pyBuffer = pyBuffer; - return (PyObject *)byteBufferWrapper; + return JType_CreateJavaByteBufferWrapper(jenv, pyObj); } PyObject* JPy_byte_buffer(PyObject* self, PyObject* args) From 5c7749428f33b361e6560da3811b574f68684d91 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Thu, 14 Dec 2023 08:17:30 -0700 Subject: [PATCH 07/14] No support of varargs of Python buffer objects --- src/main/c/jpy_jtype.c | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/src/main/c/jpy_jtype.c b/src/main/c/jpy_jtype.c index a327accb..f4158487 100644 --- a/src/main/c/jpy_jtype.c +++ b/src/main/c/jpy_jtype.c @@ -1819,35 +1819,6 @@ int JType_MatchVarArgPyArgAsJStringParam(JNIEnv* jenv, JPy_ParamDescriptor* para return minMatch; } -int JType_MatchVarArgPyArgAsJByteBufferParam(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, int idx) -{ - Py_ssize_t argCount = PyTuple_Size(pyArg); - Py_ssize_t remaining = (argCount - idx); - - JPy_JType *componentType = paramDescriptor->type->componentType; - int minMatch = 100; - int ii; - - if (componentType != JPy_JByteBuffer) { - return 0; - } - - if (remaining == 0) { - return 10; - } - - for (ii = 0; ii < remaining; ii++) { - PyObject *unpack = PyTuple_GetItem(pyArg, idx + ii); - int matchValue = JType_MatchPyArgAsJByteBufferParam(jenv, paramDescriptor, unpack); - if (matchValue == 0) { - return 0; - } - minMatch = matchValue < minMatch ? matchValue : minMatch; - } - - return minMatch; -} - int JType_MatchVarArgPyArgAsJPyObjectParam(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, int idx) { Py_ssize_t argCount = PyTuple_Size(pyArg); @@ -2613,8 +2584,6 @@ void JType_InitParamDescriptorFunctions(JPy_ParamDescriptor* paramDescriptor, jb paramDescriptor->MatchVarArgPyArg = JType_MatchVarArgPyArgAsJDoubleParam; } else if (paramType->componentType == JPy_JString) { paramDescriptor->MatchVarArgPyArg = JType_MatchVarArgPyArgAsJStringParam; - } else if (paramType->componentType == JPy_JByteBuffer) { - paramDescriptor->MatchVarArgPyArg = JType_MatchVarArgPyArgAsJByteBufferParam; } else if (paramType->componentType == JPy_JPyObject) { paramDescriptor->MatchVarArgPyArg = JType_MatchVarArgPyArgAsJPyObjectParam; } else { From a5933600acd519f1f8a7cb19d2dae93961ed94d7 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Thu, 14 Dec 2023 08:33:34 -0700 Subject: [PATCH 08/14] Tidy up a bit --- src/main/c/jpy_jtype.c | 9 +++++---- src/main/c/jpy_module.c | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/c/jpy_jtype.c b/src/main/c/jpy_jtype.c index f4158487..679bb489 100644 --- a/src/main/c/jpy_jtype.c +++ b/src/main/c/jpy_jtype.c @@ -1680,7 +1680,7 @@ PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj) } if (PyObject_GetBuffer(pyObj, pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) { - PyErr_SetString(PyExc_ValueError, "byte_buffer: the Python object failed to return a contiguous buffer."); + PyErr_SetString(PyExc_ValueError, "JType_CreateJavaByteBufferWrapper: the Python object failed to return a contiguous buffer."); PyMem_Free(pyBuffer); return NULL; } @@ -1726,11 +1726,13 @@ int JType_ConvertPyArgToJByteBufferArg(JNIEnv* jenv, JPy_ParamDescriptor* paramD JPy_JObj* obj = (JPy_JObj*) disposer->data; value->l = obj->objectRef; } else if (JObj_Check(pyArg)) { - JPy_JObj* obj = (JPy_JObj*) pyArg; - value->l = obj->objectRef; disposer->data = NULL; + // If it is a wrapped Java object, it is always a global reference, so don't dispose it disposer->DisposeArg = NULL; + JPy_JObj* obj = (JPy_JObj*) pyArg; + value->l = obj->objectRef; } else { + PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: Python argument incorrectly matched to Java ByteBuffer parameter."); return -1; } return 0; @@ -2454,7 +2456,6 @@ void JType_DisposeLocalObjectRefArg(JNIEnv* jenv, jvalue* value, void* data) void JType_DisposeByteBufferArg(JNIEnv* jenv, jvalue* value, void* data) { - PyObject* byteBufferWrapper = (PyObject*) data; jobject jByteBuffer = (jobject) value->l; diff --git a/src/main/c/jpy_module.c b/src/main/c/jpy_module.c index 200f50ba..e389eb1d 100644 --- a/src/main/c/jpy_module.c +++ b/src/main/c/jpy_module.c @@ -680,7 +680,7 @@ PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args) } if (PyObject_CheckBuffer(pyObj) == 0) { - PyErr_SetString(PyExc_ValueError, "byte_buffer: argument 1 must be a Python object that supports the buffer protocol"); + PyErr_SetString(PyExc_ValueError, "byte_buffer: argument 1 must be a Python object that supports the buffer protocol."); return NULL; } From 33790bae94b5b81b9963445a9a4877b01e7eba88 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Tue, 19 Dec 2023 19:02:22 -0700 Subject: [PATCH 09/14] Fix a type-checking error in dealloc --- src/main/c/jpy_jobj.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/c/jpy_jobj.c b/src/main/c/jpy_jobj.c index cb401ceb..5a504512 100644 --- a/src/main/c/jpy_jobj.c +++ b/src/main/c/jpy_jobj.c @@ -64,9 +64,13 @@ PyObject* JObj_FromType(JNIEnv* jenv, JPy_JType* type, jobject objectRef) array = (JPy_JArray*) obj; array->bufferExportCount = 0; array->buf = NULL; + } else if ((*jenv)->IsInstanceOf(jenv, objectRef, JPy_ByteBuffer_JClass)) { + JPy_JByteBufferWrapper *byteBufferWrapper = (JPy_JByteBufferWrapper *) obj; + byteBufferWrapper->pyBuffer = NULL; } - // we check the type translations dictionary for a callable for this java type name, + +// we check the type translations dictionary for a callable for this java type name, // and apply the returned callable to the wrapped object callable = PyDict_GetItemString(JPy_Type_Translations, type->javaName); if (callable != NULL) { @@ -172,6 +176,8 @@ void JObj_dealloc(JPy_JObj* self) JNIEnv* jenv; JPy_JType* jtype; + jenv = JPy_GetJNIEnv(); + JPy_DIAG_PRINT(JPy_DIAG_F_MEM, "JObj_dealloc: releasing instance of %s, self->objectRef=%p\n", Py_TYPE(self)->tp_name, self->objectRef); jtype = (JPy_JType *)Py_TYPE(self); @@ -182,14 +188,14 @@ void JObj_dealloc(JPy_JObj* self) if (array->buf != NULL) { JArray_ReleaseJavaArrayElements(array, array->javaType); } - } else if (jtype == JPy_JByteBuffer) { - JPy_JByteBufferWrapper* byteBufferWrapper; - byteBufferWrapper = (JPy_JByteBufferWrapper *) self; - PyBuffer_Release(byteBufferWrapper->pyBuffer); - PyMem_Free(byteBufferWrapper->pyBuffer); + } else if ((*jenv)->IsInstanceOf(jenv, self->objectRef, JPy_ByteBuffer_JClass)) { + JPy_JByteBufferWrapper *byteBufferWrapper = (JPy_JByteBufferWrapper *) self; + if (byteBufferWrapper->pyBuffer != NULL) { + PyBuffer_Release(byteBufferWrapper->pyBuffer); + PyMem_Free(byteBufferWrapper->pyBuffer); + } } - jenv = JPy_GetJNIEnv(); if (jenv != NULL) { if (self->objectRef != NULL) { (*jenv)->DeleteGlobalRef(jenv, self->objectRef); From 898f6a5dc1869dfa36f392b1a4b6ffe12af20be1 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Wed, 20 Dec 2023 12:51:31 -0700 Subject: [PATCH 10/14] Remove auto-conversion --- src/main/c/jpy_jtype.c | 26 +------------------------- src/main/c/jpy_module.c | 3 ++- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/src/main/c/jpy_jtype.c b/src/main/c/jpy_jtype.c index 679bb489..e8dda383 100644 --- a/src/main/c/jpy_jtype.c +++ b/src/main/c/jpy_jtype.c @@ -43,7 +43,6 @@ void JType_InitMethodParamDescriptorFunctions(JPy_JType* type, JPy_JMethod* meth int JType_ProcessField(JNIEnv* jenv, JPy_JType* declaringType, PyObject* fieldKey, const char* fieldName, jclass fieldClassRef, jboolean isStatic, jboolean isFinal, jfieldID fid); void JType_DisposeLocalObjectRefArg(JNIEnv* jenv, jvalue* value, void* data); void JType_DisposeReadOnlyBufferArg(JNIEnv* jenv, jvalue* value, void* data); -void JType_DisposeByteBufferArg(JNIEnv* jenv, jvalue* value, void* data); void JType_DisposeWritableBufferArg(JNIEnv* jenv, jvalue* value, void* data); @@ -1661,10 +1660,6 @@ int JType_MatchPyArgAsJByteBufferParam(JNIEnv* jenv, JPy_ParamDescriptor* paramD return 1; } - if (PyObject_CheckBuffer(pyArg) == 1) { - return 100; - } - return JType_MatchPyArgAsJObject(jenv, paramDescriptor->type, pyArg); } @@ -1720,12 +1715,7 @@ PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj) int JType_ConvertPyArgToJByteBufferArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, jvalue* value, JPy_ArgDisposer* disposer) { - if (PyObject_CheckBuffer(pyArg)) { - disposer->data = JType_CreateJavaByteBufferWrapper(jenv, pyArg); - disposer->DisposeArg = JType_DisposeByteBufferArg; - JPy_JObj* obj = (JPy_JObj*) disposer->data; - value->l = obj->objectRef; - } else if (JObj_Check(pyArg)) { + if (JObj_Check(pyArg)) { disposer->data = NULL; // If it is a wrapped Java object, it is always a global reference, so don't dispose it disposer->DisposeArg = NULL; @@ -2454,20 +2444,6 @@ void JType_DisposeLocalObjectRefArg(JNIEnv* jenv, jvalue* value, void* data) } } -void JType_DisposeByteBufferArg(JNIEnv* jenv, jvalue* value, void* data) -{ - PyObject* byteBufferWrapper = (PyObject*) data; - jobject jByteBuffer = (jobject) value->l; - - JPy_DIAG_PRINT(JPy_DIAG_F_MEM, "JType_DisposeByteBufferArg: byteBufferWrapper=%p, jByteBuffer=%p\n", byteBufferWrapper, jByteBuffer); - - if (jByteBuffer != NULL) { - JPy_DELETE_LOCAL_REF(jByteBuffer); - } - - JPy_DECREF(byteBufferWrapper); -} - void JType_DisposeReadOnlyBufferArg(JNIEnv* jenv, jvalue* value, void* data) { Py_buffer* pyBuffer; diff --git a/src/main/c/jpy_module.c b/src/main/c/jpy_module.c index e389eb1d..ea5cf0bf 100644 --- a/src/main/c/jpy_module.c +++ b/src/main/c/jpy_module.c @@ -66,7 +66,8 @@ static PyMethodDef JPy_Functions[] = { "Possible primitive types are 'boolean', 'byte', 'char', 'short', 'int', 'long', 'float', and 'double'."}, {"byte_buffer", JPy_byte_buffer, METH_VARARGS, - "byte_buffer(obj) - Return a new Java direct ByteBuffer referring to the Py_buffer provided by obj via its implemented Buffer Protocol. "}, + "byte_buffer(obj) - Return a new Java direct ByteBuffer sharing the same underlying buffer of obj via its implemented Buffer Protocol. The Java direct ByteBuffer is read-only" + "and is only safe to access in Java (e.g. as an argument to a Java method) when it is also referenced in Python."}, {NULL, NULL, 0, NULL} /*Sentinel*/ }; From 178e2b0d593732c91b1a8c0f6c1f8d01da6aa5ca Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Fri, 22 Dec 2023 11:05:42 -0700 Subject: [PATCH 11/14] Remove unused code and improve docstring --- src/main/c/jpy_jobj.c | 7 ++-- src/main/c/jpy_jtype.c | 79 ----------------------------------------- src/main/c/jpy_jtype.h | 2 -- src/main/c/jpy_module.c | 58 ++++++++++++++++++++++++++++-- 4 files changed, 61 insertions(+), 85 deletions(-) diff --git a/src/main/c/jpy_jobj.c b/src/main/c/jpy_jobj.c index 5a504512..23846ddd 100644 --- a/src/main/c/jpy_jobj.c +++ b/src/main/c/jpy_jobj.c @@ -65,7 +65,9 @@ PyObject* JObj_FromType(JNIEnv* jenv, JPy_JType* type, jobject objectRef) array->bufferExportCount = 0; array->buf = NULL; } else if ((*jenv)->IsInstanceOf(jenv, objectRef, JPy_ByteBuffer_JClass)) { - JPy_JByteBufferWrapper *byteBufferWrapper = (JPy_JByteBufferWrapper *) obj; + JPy_JByteBufferWrapper *byteBufferWrapper; + + byteBufferWrapper = (JPy_JByteBufferWrapper *) obj; byteBufferWrapper->pyBuffer = NULL; } @@ -189,7 +191,8 @@ void JObj_dealloc(JPy_JObj* self) JArray_ReleaseJavaArrayElements(array, array->javaType); } } else if ((*jenv)->IsInstanceOf(jenv, self->objectRef, JPy_ByteBuffer_JClass)) { - JPy_JByteBufferWrapper *byteBufferWrapper = (JPy_JByteBufferWrapper *) self; + JPy_JByteBufferWrapper *byteBufferWrapper; + byteBufferWrapper = (JPy_JByteBufferWrapper *) self; if (byteBufferWrapper->pyBuffer != NULL) { PyBuffer_Release(byteBufferWrapper->pyBuffer); PyMem_Free(byteBufferWrapper->pyBuffer); diff --git a/src/main/c/jpy_jtype.c b/src/main/c/jpy_jtype.c index e8dda383..5fff4e11 100644 --- a/src/main/c/jpy_jtype.c +++ b/src/main/c/jpy_jtype.c @@ -1653,81 +1653,6 @@ int JType_ConvertPyArgToJStringArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescr return JPy_AsJString(jenv, pyArg, &value->l); } -int JType_MatchPyArgAsJByteBufferParam(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg) -{ - if (pyArg == Py_None) { - // Signal it is possible, but give low priority since we cannot perform any type checks on 'None' - return 1; - } - - return JType_MatchPyArgAsJObject(jenv, paramDescriptor->type, pyArg); -} - -PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj) -{ - jobject byteBufferRef, tmpByteBufferRef; - Py_buffer *pyBuffer; - - pyBuffer = (Py_buffer *)PyMem_Malloc(sizeof(Py_buffer)); - if (pyBuffer == NULL) { - PyErr_NoMemory(); - return NULL; - } - - if (PyObject_GetBuffer(pyObj, pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) { - PyErr_SetString(PyExc_ValueError, "JType_CreateJavaByteBufferWrapper: the Python object failed to return a contiguous buffer."); - PyMem_Free(pyBuffer); - return NULL; - } - - tmpByteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, pyBuffer->buf, pyBuffer->len); - if (tmpByteBufferRef == NULL) { - PyBuffer_Release(pyBuffer); - PyMem_Free(pyBuffer); - PyErr_NoMemory(); - return NULL; - } - - byteBufferRef = (*jenv)->CallObjectMethod(jenv, tmpByteBufferRef, JPy_ByteBuffer_AsReadOnlyBuffer_MID); - if (byteBufferRef == NULL) { - PyBuffer_Release(pyBuffer); - PyMem_Free(pyBuffer); - JPy_DELETE_LOCAL_REF(tmpByteBufferRef); - PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a read-only ByteBuffer instance."); - return NULL; - } - JPy_DELETE_LOCAL_REF(tmpByteBufferRef); - - PyObject *newPyObj = JObj_New(jenv, byteBufferRef); - if (newPyObj == NULL) { - PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a ByteBufferWrapper instance."); - PyBuffer_Release(pyBuffer); - PyMem_Free(pyBuffer); - JPy_DELETE_LOCAL_REF(byteBufferRef); - return NULL; - } - JPy_DELETE_LOCAL_REF(byteBufferRef); - - JPy_JByteBufferWrapper* byteBufferWrapper = (JPy_JByteBufferWrapper *) newPyObj; - byteBufferWrapper->pyBuffer = pyBuffer; - return (PyObject *)byteBufferWrapper; -} - -int JType_ConvertPyArgToJByteBufferArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, jvalue* value, JPy_ArgDisposer* disposer) -{ - if (JObj_Check(pyArg)) { - disposer->data = NULL; - // If it is a wrapped Java object, it is always a global reference, so don't dispose it - disposer->DisposeArg = NULL; - JPy_JObj* obj = (JPy_JObj*) pyArg; - value->l = obj->objectRef; - } else { - PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: Python argument incorrectly matched to Java ByteBuffer parameter."); - return -1; - } - return 0; -} - int JType_ConvertPyArgToJPyObjectArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg, jvalue* value, JPy_ArgDisposer* disposer) { disposer->data = NULL; @@ -1735,7 +1660,6 @@ int JType_ConvertPyArgToJPyObjectArg(JNIEnv* jenv, JPy_ParamDescriptor* paramDes return JType_CreateJavaPyObject(jenv, JPy_JPyObject, pyArg, &value->l); } - int JType_MatchPyArgAsJPyObjectParam(JNIEnv* jenv, JPy_ParamDescriptor* paramDescriptor, PyObject* pyArg) { // We can always turn a python object into a PyObject @@ -2527,9 +2451,6 @@ void JType_InitParamDescriptorFunctions(JPy_ParamDescriptor* paramDescriptor, jb } else if (paramType == JPy_JString) { paramDescriptor->MatchPyArg = JType_MatchPyArgAsJStringParam; paramDescriptor->ConvertPyArg = JType_ConvertPyArgToJStringArg; - } else if (paramType == JPy_JByteBuffer) { - paramDescriptor->MatchPyArg = JType_MatchPyArgAsJByteBufferParam; - paramDescriptor->ConvertPyArg = JType_ConvertPyArgToJByteBufferArg; //} else if (paramType == JPy_JMap) { //} else if (paramType == JPy_JList) { //} else if (paramType == JPy_JSet) { diff --git a/src/main/c/jpy_jtype.h b/src/main/c/jpy_jtype.h index 1d8da2f8..889a40d3 100644 --- a/src/main/c/jpy_jtype.h +++ b/src/main/c/jpy_jtype.h @@ -135,8 +135,6 @@ int JType_CreateJavaPyObject(JNIEnv* jenv, JPy_JType* type, PyObject* pyArg, job int JType_CreateJavaArray(JNIEnv* jenv, JPy_JType* componentType, PyObject* pyArg, jobject* objectRef, jboolean allowObjectWrapping); -PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj); - // Non-API. Defined in jpy_jobj.c int JType_InitSlots(JPy_JType* type); // Non-API. Defined in jpy_jtype.c diff --git a/src/main/c/jpy_module.c b/src/main/c/jpy_module.c index ea5cf0bf..662baa80 100644 --- a/src/main/c/jpy_module.c +++ b/src/main/c/jpy_module.c @@ -39,6 +39,7 @@ PyObject* JPy_destroy_jvm(PyObject* self, PyObject* args); PyObject* JPy_get_type(PyObject* self, PyObject* args, PyObject* kwds); PyObject* JPy_cast(PyObject* self, PyObject* args); PyObject* JPy_array(PyObject* self, PyObject* args); +PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj); PyObject* JPy_byte_buffer(PyObject* self, PyObject* args); @@ -66,8 +67,9 @@ static PyMethodDef JPy_Functions[] = { "Possible primitive types are 'boolean', 'byte', 'char', 'short', 'int', 'long', 'float', and 'double'."}, {"byte_buffer", JPy_byte_buffer, METH_VARARGS, - "byte_buffer(obj) - Return a new Java direct ByteBuffer sharing the same underlying buffer of obj via its implemented Buffer Protocol. The Java direct ByteBuffer is read-only" - "and is only safe to access in Java (e.g. as an argument to a Java method) when it is also referenced in Python."}, + "byte_buffer(obj) - Return a new Java direct ByteBuffer sharing the same underlying, contiguous buffer of obj via its implemented Buffer Protocol. The resulting PYObject must live " + "longer than the Java object to ensure the underlying data remains valid. In most cases, this means that java functions called in this manner must not keep any references" + " to the ByteBuffer"}, {NULL, NULL, 0, NULL} /*Sentinel*/ }; @@ -668,6 +670,58 @@ PyObject* JPy_array(PyObject* self, PyObject* args) JPy_FRAME(PyObject*, NULL, JPy_array_internal(jenv, self, args), 16) } +PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj) +{ + jobject byteBufferRef, tmpByteBufferRef; + Py_buffer *pyBuffer; + PyObject *newPyObj; + JPy_JByteBufferWrapper* byteBufferWrapper; + + pyBuffer = (Py_buffer *)PyMem_Malloc(sizeof(Py_buffer)); + if (pyBuffer == NULL) { + PyErr_NoMemory(); + return NULL; + } + + if (PyObject_GetBuffer(pyObj, pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) { + PyErr_SetString(PyExc_ValueError, "JType_CreateJavaByteBufferWrapper: the Python object failed to return a contiguous buffer."); + PyMem_Free(pyBuffer); + return NULL; + } + + tmpByteBufferRef = (*jenv)->NewDirectByteBuffer(jenv, pyBuffer->buf, pyBuffer->len); + if (tmpByteBufferRef == NULL) { + PyBuffer_Release(pyBuffer); + PyMem_Free(pyBuffer); + PyErr_NoMemory(); + return NULL; + } + + byteBufferRef = (*jenv)->CallObjectMethod(jenv, tmpByteBufferRef, JPy_ByteBuffer_AsReadOnlyBuffer_MID); + if (byteBufferRef == NULL) { + PyBuffer_Release(pyBuffer); + PyMem_Free(pyBuffer); + JPy_DELETE_LOCAL_REF(tmpByteBufferRef); + PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a read-only ByteBuffer instance."); + return NULL; + } + JPy_DELETE_LOCAL_REF(tmpByteBufferRef); + + newPyObj = JObj_New(jenv, byteBufferRef); + if (newPyObj == NULL) { + PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a ByteBufferWrapper instance."); + PyBuffer_Release(pyBuffer); + PyMem_Free(pyBuffer); + JPy_DELETE_LOCAL_REF(byteBufferRef); + return NULL; + } + JPy_DELETE_LOCAL_REF(byteBufferRef); + + byteBufferWrapper = (JPy_JByteBufferWrapper *) newPyObj; + byteBufferWrapper->pyBuffer = pyBuffer; + return (PyObject *)byteBufferWrapper; +} + PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args) { jobject byteBufferRef; From 0e97d0c3fc92294402b7b93f9003b7442f803f33 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Fri, 29 Dec 2023 10:26:32 -0700 Subject: [PATCH 12/14] Add and use JByteBuffer_Check for cstr/dstr --- src/main/c/jpy_jobj.c | 19 ++++++++++++++----- src/main/c/jpy_jobj.h | 2 ++ src/main/c/jpy_module.c | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/c/jpy_jobj.c b/src/main/c/jpy_jobj.c index 23846ddd..adf76eed 100644 --- a/src/main/c/jpy_jobj.c +++ b/src/main/c/jpy_jobj.c @@ -64,7 +64,7 @@ PyObject* JObj_FromType(JNIEnv* jenv, JPy_JType* type, jobject objectRef) array = (JPy_JArray*) obj; array->bufferExportCount = 0; array->buf = NULL; - } else if ((*jenv)->IsInstanceOf(jenv, objectRef, JPy_ByteBuffer_JClass)) { + } else if (JByteBuffer_Check(type)) { JPy_JByteBufferWrapper *byteBufferWrapper; byteBufferWrapper = (JPy_JByteBufferWrapper *) obj; @@ -178,8 +178,6 @@ void JObj_dealloc(JPy_JObj* self) JNIEnv* jenv; JPy_JType* jtype; - jenv = JPy_GetJNIEnv(); - JPy_DIAG_PRINT(JPy_DIAG_F_MEM, "JObj_dealloc: releasing instance of %s, self->objectRef=%p\n", Py_TYPE(self)->tp_name, self->objectRef); jtype = (JPy_JType *)Py_TYPE(self); @@ -190,7 +188,7 @@ void JObj_dealloc(JPy_JObj* self) if (array->buf != NULL) { JArray_ReleaseJavaArrayElements(array, array->javaType); } - } else if ((*jenv)->IsInstanceOf(jenv, self->objectRef, JPy_ByteBuffer_JClass)) { + } else if (JByteBuffer_Check(jtype)) { JPy_JByteBufferWrapper *byteBufferWrapper; byteBufferWrapper = (JPy_JByteBufferWrapper *) self; if (byteBufferWrapper->pyBuffer != NULL) { @@ -199,6 +197,7 @@ void JObj_dealloc(JPy_JObj* self) } } + jenv = JPy_GetJNIEnv(); if (jenv != NULL) { if (self->objectRef != NULL) { (*jenv)->DeleteGlobalRef(jenv, self->objectRef); @@ -743,7 +742,7 @@ int JType_InitSlots(JPy_JType* type) if (isPrimitiveArray) { typeObj->tp_basicsize = sizeof(JPy_JArray); - } else if (type == JPy_JByteBuffer) { + } else if (JByteBuffer_Check(type)) { typeObj->tp_basicsize = sizeof(JPy_JByteBufferWrapper); } else { typeObj->tp_basicsize = sizeof(JPy_JObj); @@ -842,3 +841,13 @@ int JType_Check(PyObject* arg) return PyType_Check(arg) && JPY_IS_JTYPE(arg); } +int JByteBuffer_Check(JPy_JType* type) { + while (type != NULL) { + if (type == JPy_JByteBuffer || strcmp(type->javaName, "java.nio.ByteBuffer") == 0) { + JPy_DIAG_PRINT(JPy_DIAG_F_TYPE, "JByteBuffer_Check: java ByteBuffer or its sub-type (%s) found.\n", type->javaName); + return -1; + } + type = type->superType; + } + return 0; +} diff --git a/src/main/c/jpy_jobj.h b/src/main/c/jpy_jobj.h index 3454f307..5b740df3 100644 --- a/src/main/c/jpy_jobj.h +++ b/src/main/c/jpy_jobj.h @@ -40,6 +40,8 @@ JPy_JObj; int JObj_Check(PyObject* arg); +int JByteBuffer_Check(JPy_JType* type); + PyObject* JObj_New(JNIEnv* jenv, jobject objectRef); PyObject* JObj_FromType(JNIEnv* jenv, JPy_JType* type, jobject objectRef); diff --git a/src/main/c/jpy_module.c b/src/main/c/jpy_module.c index 662baa80..3aa17e11 100644 --- a/src/main/c/jpy_module.c +++ b/src/main/c/jpy_module.c @@ -702,7 +702,7 @@ PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj) PyBuffer_Release(pyBuffer); PyMem_Free(pyBuffer); JPy_DELETE_LOCAL_REF(tmpByteBufferRef); - PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a read-only ByteBuffer instance."); + PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a read-only direct ByteBuffer instance."); return NULL; } JPy_DELETE_LOCAL_REF(tmpByteBufferRef); From 81482f50fc21e3dc01b664f6b85efb43c80f6b20 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Wed, 3 Jan 2024 10:53:43 -0700 Subject: [PATCH 13/14] Naming change --- src/main/c/jpy_jbyte_buffer.c | 2 +- src/main/c/jpy_jbyte_buffer.h | 6 +++--- src/main/c/jpy_jobj.c | 18 +++++++++--------- src/main/c/jpy_module.c | 20 ++++++++++---------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/main/c/jpy_jbyte_buffer.c b/src/main/c/jpy_jbyte_buffer.c index 66d04e4b..f443646f 100644 --- a/src/main/c/jpy_jbyte_buffer.c +++ b/src/main/c/jpy_jbyte_buffer.c @@ -20,5 +20,5 @@ #include "jpy_jbyte_buffer.h" /* - * This file for now is just a place-holder for future JPy_ByteBufferWrapper specific functions. + * This file for now is just a place-holder for future JPy_JByteBufferObj specific functions. */ \ No newline at end of file diff --git a/src/main/c/jpy_jbyte_buffer.h b/src/main/c/jpy_jbyte_buffer.h index 8572ff85..6b44cb3d 100644 --- a/src/main/c/jpy_jbyte_buffer.h +++ b/src/main/c/jpy_jbyte_buffer.h @@ -26,17 +26,17 @@ extern "C" { /** * The Java ByteBuffer representation in Python. * - * IMPORTANT: JPy_JByteBufferWrapper must only differ from the JPy_JObj structure by the 'pyBuffer' member + * IMPORTANT: JPy_JByteBufferObj must only differ from the JPy_JObj structure by the 'pyBuffer' member * since we use the same basic type, name JPy_JType for it. DON'T ever change member positions! * @see JPy_JObj */ -typedef struct JPy_JByteBufferWrapper +typedef struct JPy_JByteBufferObj { PyObject_HEAD jobject objectRef; Py_buffer *pyBuffer; } -JPy_JByteBufferWrapper; +JPy_JByteBufferObj; #ifdef __cplusplus } /* extern "C" */ diff --git a/src/main/c/jpy_jobj.c b/src/main/c/jpy_jobj.c index adf76eed..e7fcf66c 100644 --- a/src/main/c/jpy_jobj.c +++ b/src/main/c/jpy_jobj.c @@ -65,10 +65,10 @@ PyObject* JObj_FromType(JNIEnv* jenv, JPy_JType* type, jobject objectRef) array->bufferExportCount = 0; array->buf = NULL; } else if (JByteBuffer_Check(type)) { - JPy_JByteBufferWrapper *byteBufferWrapper; + JPy_JByteBufferObj *byteBuffer; - byteBufferWrapper = (JPy_JByteBufferWrapper *) obj; - byteBufferWrapper->pyBuffer = NULL; + byteBuffer = (JPy_JByteBufferObj *) obj; + byteBuffer->pyBuffer = NULL; } @@ -189,11 +189,11 @@ void JObj_dealloc(JPy_JObj* self) JArray_ReleaseJavaArrayElements(array, array->javaType); } } else if (JByteBuffer_Check(jtype)) { - JPy_JByteBufferWrapper *byteBufferWrapper; - byteBufferWrapper = (JPy_JByteBufferWrapper *) self; - if (byteBufferWrapper->pyBuffer != NULL) { - PyBuffer_Release(byteBufferWrapper->pyBuffer); - PyMem_Free(byteBufferWrapper->pyBuffer); + JPy_JByteBufferObj *byteBuffer; + byteBuffer = (JPy_JByteBufferObj *) self; + if (byteBuffer->pyBuffer != NULL) { + PyBuffer_Release(byteBuffer->pyBuffer); + PyMem_Free(byteBuffer->pyBuffer); } } @@ -743,7 +743,7 @@ int JType_InitSlots(JPy_JType* type) if (isPrimitiveArray) { typeObj->tp_basicsize = sizeof(JPy_JArray); } else if (JByteBuffer_Check(type)) { - typeObj->tp_basicsize = sizeof(JPy_JByteBufferWrapper); + typeObj->tp_basicsize = sizeof(JPy_JByteBufferObj); } else { typeObj->tp_basicsize = sizeof(JPy_JObj); } diff --git a/src/main/c/jpy_module.c b/src/main/c/jpy_module.c index 3aa17e11..687ea312 100644 --- a/src/main/c/jpy_module.c +++ b/src/main/c/jpy_module.c @@ -39,7 +39,7 @@ PyObject* JPy_destroy_jvm(PyObject* self, PyObject* args); PyObject* JPy_get_type(PyObject* self, PyObject* args, PyObject* kwds); PyObject* JPy_cast(PyObject* self, PyObject* args); PyObject* JPy_array(PyObject* self, PyObject* args); -PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj); +PyObject* JType_CreateJavaByteBufferObj(JNIEnv* jenv, PyObject* pyObj); PyObject* JPy_byte_buffer(PyObject* self, PyObject* args); @@ -670,12 +670,12 @@ PyObject* JPy_array(PyObject* self, PyObject* args) JPy_FRAME(PyObject*, NULL, JPy_array_internal(jenv, self, args), 16) } -PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj) +PyObject* JType_CreateJavaByteBufferObj(JNIEnv* jenv, PyObject* pyObj) { jobject byteBufferRef, tmpByteBufferRef; Py_buffer *pyBuffer; PyObject *newPyObj; - JPy_JByteBufferWrapper* byteBufferWrapper; + JPy_JByteBufferObj* byteBuffer; pyBuffer = (Py_buffer *)PyMem_Malloc(sizeof(Py_buffer)); if (pyBuffer == NULL) { @@ -684,7 +684,7 @@ PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj) } if (PyObject_GetBuffer(pyObj, pyBuffer, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) != 0) { - PyErr_SetString(PyExc_ValueError, "JType_CreateJavaByteBufferWrapper: the Python object failed to return a contiguous buffer."); + PyErr_SetString(PyExc_ValueError, "JType_CreateJavaByteBufferObj: the Python object failed to return a contiguous buffer."); PyMem_Free(pyBuffer); return NULL; } @@ -709,7 +709,7 @@ PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj) newPyObj = JObj_New(jenv, byteBufferRef); if (newPyObj == NULL) { - PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a ByteBufferWrapper instance."); + PyErr_SetString(PyExc_RuntimeError, "jpy: internal error: failed to create a byteBuffer instance."); PyBuffer_Release(pyBuffer); PyMem_Free(pyBuffer); JPy_DELETE_LOCAL_REF(byteBufferRef); @@ -717,9 +717,9 @@ PyObject* JType_CreateJavaByteBufferWrapper(JNIEnv* jenv, PyObject* pyObj) } JPy_DELETE_LOCAL_REF(byteBufferRef); - byteBufferWrapper = (JPy_JByteBufferWrapper *) newPyObj; - byteBufferWrapper->pyBuffer = pyBuffer; - return (PyObject *)byteBufferWrapper; + byteBuffer = (JPy_JByteBufferObj *) newPyObj; + byteBuffer->pyBuffer = pyBuffer; + return (PyObject *)byteBuffer; } PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args) @@ -728,7 +728,7 @@ PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args) PyObject* pyObj; PyObject* newPyObj; Py_buffer *pyBuffer; - JPy_JByteBufferWrapper* byteBufferWrapper; + JPy_JByteBufferObj* byteBuffer; if (!PyArg_ParseTuple(args, "O:byte_buffer", &pyObj)) { return NULL; @@ -739,7 +739,7 @@ PyObject* JPy_byte_buffer_internal(JNIEnv* jenv, PyObject* self, PyObject* args) return NULL; } - return JType_CreateJavaByteBufferWrapper(jenv, pyObj); + return JType_CreateJavaByteBufferObj(jenv, pyObj); } PyObject* JPy_byte_buffer(PyObject* self, PyObject* args) From 2b33e43813b566779429d85af5541f1ed5f20cd5 Mon Sep 17 00:00:00 2001 From: jianfengmao Date: Wed, 3 Jan 2024 13:53:38 -0700 Subject: [PATCH 14/14] Remove unnecessary decl --- src/main/c/jpy_module.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/c/jpy_module.c b/src/main/c/jpy_module.c index 687ea312..ccf8563f 100644 --- a/src/main/c/jpy_module.c +++ b/src/main/c/jpy_module.c @@ -39,7 +39,6 @@ PyObject* JPy_destroy_jvm(PyObject* self, PyObject* args); PyObject* JPy_get_type(PyObject* self, PyObject* args, PyObject* kwds); PyObject* JPy_cast(PyObject* self, PyObject* args); PyObject* JPy_array(PyObject* self, PyObject* args); -PyObject* JType_CreateJavaByteBufferObj(JNIEnv* jenv, PyObject* pyObj); PyObject* JPy_byte_buffer(PyObject* self, PyObject* args);