From: stephan Date: Sun, 30 Jul 2023 13:30:52 +0000 (+0000) Subject: Minor tweaks and optimizations in the JNI bindings. X-Git-Tag: version-3.43.0~47^2~126 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=13b059025f2eb5d714c159139c40793d89199ef2;p=thirdparty%2Fsqlite.git Minor tweaks and optimizations in the JNI bindings. FossilOrigin-Name: 41fb5898f1a78d9fd85a020e28a6048a7359b54e35632e9072917cbdbcd8b07d --- diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 1f7c5bb003..8db9416394 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -285,8 +285,7 @@ struct NphCacheLine { from the ClassNames struct. */; jclass klazz /* global ref to concrete NativePointerHolder class */; jmethodID midCtor /* klazz's constructor */; - jmethodID midSet /* NativePointerHolder.setNativePointer() */; - jmethodID midGet /* NativePointerHolder.getNativePointer() */; + jfieldID fidValue /* NativePointerHolder.nativePointer and OutputPointer.X.value */; jfieldID fidSetAgg /* sqlite3_context::aggregateContext */; }; @@ -565,11 +564,12 @@ static struct NphCacheLine * S3Global_nph_cache(JNIEnv *env, const char *zClassN for( i = 0; i < NphCache_SIZE; ++i ){ cacheLine = &envRow->nph[i]; if(zClassName == cacheLine->zClassName){ -#if 0 +#define DUMP_NPH_CACHES 0 +#if DUMP_NPH_CACHES static unsigned int n = 0; - MARKER(("Cache hit #%u %s klazz@%p getter@%p, setter@%p, ctor@%p\n", - ++n, zClassName, cacheLine->klazz, cacheLine->midGet, - cacheLine->midSet, cacheLine->midCtor)); + MARKER(("Cache hit #%u %s klazz@%p nativePointer field@%p, ctor@%p\n", + ++n, zClassName, cacheLine->klazz, cacheLine->fidValue, + cacheLine->midCtor)); #endif assert(cacheLine->klazz); return cacheLine; @@ -580,18 +580,27 @@ static struct NphCacheLine * S3Global_nph_cache(JNIEnv *env, const char *zClassN if(freeSlot){ freeSlot->zClassName = zClassName; freeSlot->klazz = REF_G((*env)->FindClass(env, zClassName)); -#if 0 +#if DUMP_NPH_CACHES static unsigned int cacheMisses = 0; - MARKER(("Cache miss #%u %s klazz@%p getter@%p, setter@%p, ctor@%p\n", + MARKER(("Cache miss #%u %s klazz@%p nativePointer field@%p, ctor@%p\n", ++cacheMisses, zClassName, freeSlot->klazz, - freeSlot->midGet, freeSlot->midSet, freeSlot->midCtor)); + freeSlot->fidValue, freeSlot->midCtor)); #endif +#undef DUMP_NPH_CACHES }else{ (*env)->FatalError(env, "MAINTENANCE REQUIRED: NphCache_SIZE is too low."); } return freeSlot; } +static jfieldID getNativePointerField(JNIEnv *env, jclass klazz){ + jfieldID rv = (*env)->GetFieldID(env, klazz, "nativePointer", "J"); + IFTHREW{ + (*env)->FatalError(env, "Maintenance required: missing nativePointer field."); + } + return rv; +} + /** Sets a native ptr value in NativePointerHolder object ppOut. zClassName must be a static string so we can use its address @@ -599,24 +608,24 @@ static struct NphCacheLine * S3Global_nph_cache(JNIEnv *env, const char *zClassN */ static void setNativePointer(JNIEnv * env, jobject ppOut, void * p, const char *zClassName){ - jmethodID setter = 0; + jfieldID setter = 0; struct NphCacheLine * const cacheLine = S3Global_nph_cache(env, zClassName); - if(cacheLine && cacheLine->klazz && cacheLine->midSet){ + if(cacheLine && cacheLine->klazz && cacheLine->fidValue){ assert(zClassName == cacheLine->zClassName); - setter = cacheLine->midSet; + setter = cacheLine->fidValue; assert(setter); }else{ jclass const klazz = cacheLine ? cacheLine->klazz : (*env)->GetObjectClass(env, ppOut); - setter = (*env)->GetMethodID(env, klazz, "setNativePointer", "(J)V"); + setter = getNativePointerField(env, klazz); if(cacheLine){ assert(cacheLine->klazz); - assert(!cacheLine->midSet); + assert(!cacheLine->fidValue); assert(zClassName == cacheLine->zClassName); - cacheLine->midSet = setter; + cacheLine->fidValue = setter; } } - (*env)->CallVoidMethod(env, ppOut, setter, (jlong)p); + (*env)->SetLongField(env, ppOut, setter, (jlong)p); IFTHREW_REPORT; } @@ -628,22 +637,22 @@ static void setNativePointer(JNIEnv * env, jobject ppOut, void * p, static void * getNativePointer(JNIEnv * env, jobject pObj, const char *zClassName){ if( 0==pObj ) return 0; else{ - jmethodID getter = 0; + jfieldID getter = 0; void * rv = 0; struct NphCacheLine * const cacheLine = S3Global_nph_cache(env, zClassName); - if(cacheLine && cacheLine->midGet){ - getter = cacheLine->midGet; + if(cacheLine && cacheLine->fidValue){ + getter = cacheLine->fidValue; }else{ jclass const klazz = cacheLine ? cacheLine->klazz : (*env)->GetObjectClass(env, pObj); - getter = (*env)->GetMethodID(env, klazz, "getNativePointer", "()J"); + getter = getNativePointerField(env, klazz); if(cacheLine){ assert(cacheLine->klazz); assert(zClassName == cacheLine->zClassName); - cacheLine->midGet = getter; + cacheLine->fidValue = getter; } } - rv = (void*)(*env)->CallLongMethod(env, pObj, getter); + rv = (void*)(*env)->GetLongField(env, pObj, getter); IFTHREW_REPORT; return rv; } @@ -845,34 +854,23 @@ static int udf_setAggregateContext(JNIEnv * env, jobject jCx, /* Sets a native int32 value in OutputPointer.Int32 object ppOut. */ static void setOutputInt32(JNIEnv * env, jobject ppOut, int v){ - jmethodID setter = 0; + jfieldID setter = 0; struct NphCacheLine * const cacheLine = S3Global_nph_cache(env, ClassNames.OutputPointer_Int32); - if(cacheLine && cacheLine->klazz && cacheLine->midSet){ - setter = cacheLine->midSet; + if(cacheLine && cacheLine->klazz && cacheLine->fidValue){ + setter = cacheLine->fidValue; }else{ const jclass klazz = (*env)->GetObjectClass(env, ppOut); - setter = (*env)->GetMethodID(env, klazz, "setValue", "(I)V"); + setter = (*env)->GetFieldID(env, klazz, "value", "I"); if(cacheLine){ - assert(!cacheLine->midSet); - cacheLine->midSet = setter; + assert(!cacheLine->fidValue); + cacheLine->fidValue = setter; } } - (*env)->CallVoidMethod(env, ppOut, setter, (jint)v); + (*env)->SetIntField(env, ppOut, setter, (jint)v); IFTHREW_REPORT; } -#if 0 -/* Fetches a native int32 value from OutputPointer.Int32 object pObj. */ -static int getOutputInt(JNIEnv * env, jobject pObj){ - const jclass klazz = (*env)->GetObjectClass(env, pObj); - const jmethodID getter = - (*env)->GetMethodID(env, klazz, "getValue", "(V)I;"); - return (int)(*env)->CallIntMethod(env, pObj, getter); -} -#define VAL_GET_INT(OBJ) getOutputInt(env, OBJ) -#endif - static int encodingTypeIsValid(int eTextRep){ switch(eTextRep){ case SQLITE_UTF8: case SQLITE_UTF16: diff --git a/ext/jni/src/org/sqlite/jni/NativePointerHolder.java b/ext/jni/src/org/sqlite/jni/NativePointerHolder.java index d6543baf57..afe2618a00 100644 --- a/ext/jni/src/org/sqlite/jni/NativePointerHolder.java +++ b/ext/jni/src/org/sqlite/jni/NativePointerHolder.java @@ -23,18 +23,11 @@ package org.sqlite.jni; NativePointerHolder is not inadvertently passed to an incompatible function signature. - These objects are not intended to _own_ the pointer they refer to. - They are intended to simply communicate that pointer between C and - Java. + These objects do not _own_ the pointer they refer to. They are + intended simply to communicate that pointer between C and Java. */ public class NativePointerHolder { - private long pointer; - public NativePointerHolder(long pointer){ - this.pointer = pointer; - } - public NativePointerHolder(){ - this.pointer = 0; - } - public final long getNativePointer(){ return pointer; } - public final void setNativePointer(long p){ pointer = p; } + //! Only set from JNI, where access permissions don't matter. + private long nativePointer = 0; + public final long getNativePointer(){ return nativePointer; } } diff --git a/ext/jni/src/org/sqlite/jni/OutputPointer.java b/ext/jni/src/org/sqlite/jni/OutputPointer.java index f4f2269a10..ee308ce669 100644 --- a/ext/jni/src/org/sqlite/jni/OutputPointer.java +++ b/ext/jni/src/org/sqlite/jni/OutputPointer.java @@ -25,12 +25,10 @@ package org.sqlite.jni; public final class OutputPointer { public static final class Int32 { private int value; - public final void setValue(int v){value = v;} public final int getValue(){return value;} } public static final class Int64 { private long value; - public final void setValue(long v){value = v;} public final long getValue(){return value;} } } diff --git a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java index bdf89a3d01..f639f6ae7a 100644 --- a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java +++ b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java @@ -154,9 +154,6 @@ public final class SQLite3Jni { public static native int sqlite3_close_v2(@NotNull sqlite3 db); - //TODO? public static native int sqlite3_collation_needed(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const char*)); - //TODO? public static native int sqlite3_collation_needed16(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*)); - public static native byte[] sqlite3_column_blob(@NotNull sqlite3_stmt stmt, int ndx); public static native int sqlite3_column_bytes(@NotNull sqlite3_stmt stmt, int ndx); @@ -214,7 +211,8 @@ public final class SQLite3Jni { the db if the db uses the default encoding of UTF-8. To extract _standard_ UTF-8, use sqlite3_column_text_utf8(). - This API includes no functions for working with Modified UTF-8. + This API includes no functions for working with Java's Modified + UTF-8. [^1]: https://stackoverflow.com/questions/7921016 */ @@ -226,8 +224,43 @@ public final class SQLite3Jni { */ public static native byte[] sqlite3_column_text_utf8(@NotNull sqlite3_stmt stmt, int ndx); - //TODO public static native ?type? sqlite3_column_text16(@NotNull sqlite3_stmt stmt, int ndx); - //TODO: public static Object sqlite3_column_to_java(@NotNull sqlite3_value v){...} + + // The real utility of this function is questionable. + // /** + // Returns a Java value representation based on the value of + // sqlite_value_type(). For integer types it returns either Integer + // or Long, depending on whether the value will fit in an + // Integer. For floating-point values it always returns type Double. + + // If the column was bound using sqlite3_result_java_object() then + // that value, as an Object, is returned. + // */ + // public static Object sqlite3_column_to_java(@NotNull sqlite3_stmt stmt, + // int ndx){ + // sqlite3_value v = sqlite3_column_value(stmt, ndx); + // Object rv = null; + // if(null == v) return v; + // v = sqlite3_value_dup(v)/*need a protected value*/; + // if(null == v) return v /* OOM error in C */; + // if(112/* 'p' */ == sqlite3_value_subtype(v)){ + // rv = sqlite3_value_java_object(v); + // }else{ + // switch(sqlite3_value_type(v)){ + // case SQLITE_INTEGER: { + // final long i = sqlite3_value_int64(v); + // rv = (i<=0x7fffffff && i>=-0x7fffffff-1) + // ? new Integer((int)i) : new Long(i); + // break; + // } + // case SQLITE_FLOAT: rv = new Double(sqlite3_value_double(v)); break; + // case SQLITE_BLOB: rv = sqlite3_value_blob(v); break; + // case SQLITE_TEXT: rv = sqlite3_value_text(v); break; + // default: break; + // } + // } + // sqlite3_value_free(v); + // return rv; + // } public static native int sqlite3_column_type(@NotNull sqlite3_stmt stmt, int ndx); @@ -476,6 +509,8 @@ public final class SQLite3Jni { allocate such strings and store them somewhere for long-term use (leaking them more likely than not). Even then, passing around a pointer via Java like that has little practical use. + + Note that there is no sqlite3_bind_java_object() counterpart. */ public static native void sqlite3_result_java_object(@NotNull sqlite3_context cx, @NotNull Object o); diff --git a/ext/jni/src/org/sqlite/jni/Tester1.java b/ext/jni/src/org/sqlite/jni/Tester1.java index 287b61a76a..30b136d474 100644 --- a/ext/jni/src/org/sqlite/jni/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/Tester1.java @@ -483,7 +483,7 @@ public class Tester1 { private static void testUdfJavaObject(){ final sqlite3 db = createNewDb(); - final ValueHolder testResult = new ValueHolder<>(42L); + final ValueHolder testResult = new ValueHolder<>(db); SQLFunction func = new SQLFunction.Scalar(){ public void xFunc(sqlite3_context cx, sqlite3_value args[]){ sqlite3_result_java_object(cx, testResult.value); @@ -494,14 +494,16 @@ public class Tester1 { sqlite3_stmt stmt = new sqlite3_stmt(); sqlite3_prepare(db, "select myfunc()", stmt); affirm( 0 != stmt.getNativePointer() ); + affirm( testResult.value == db ); int n = 0; if( SQLITE_ROW == sqlite3_step(stmt) ){ - sqlite3_value v = sqlite3_column_value(stmt, 0); + final sqlite3_value v = sqlite3_column_value(stmt, 0); affirm( testResult.value == sqlite3_value_java_object(v) ); - affirm( testResult.value == sqlite3_value_java_casted(v, Long.class) ); + affirm( testResult.value == sqlite3_value_java_casted(v, sqlite3.class) ); affirm( testResult.value == sqlite3_value_java_casted(v, testResult.value.getClass()) ); - affirm( null == sqlite3_value_java_casted(v, Double.class) ); + affirm( testResult.value == sqlite3_value_java_casted(v, Object.class) ); + affirm( null == sqlite3_value_java_casted(v, String.class) ); ++n; } sqlite3_finalize(stmt); diff --git a/manifest b/manifest index 4ba95e2df1..7c0eac5fdf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bind\ssqlite3_collation_needed()\sto\sJNI.\sRelated\sadjacent\scleanups\sand\sfixes. -D 2023-07-30T11:36:41.439 +C Minor\stweaks\sand\soptimizations\sin\sthe\sJNI\sbindings. +D 2023-07-30T13:30:52.663 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -232,19 +232,19 @@ F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 F ext/jni/GNUmakefile 56a014dbff9516774d895ec1ae9df0ed442765b556f79a0fc0b5bc438217200d F ext/jni/README.md c0e6e80935e7761acead89b69c87765b23a6bcb2858c321c3d05681fd338292a -F ext/jni/src/c/sqlite3-jni.c 1934a72f33fe356d8af810a8a662dd8109026cd0bbf298dda1fe8bd1146603ad +F ext/jni/src/c/sqlite3-jni.c d3ce5d96feb5eebf8dd171f041704798f3d0a5da1ee93a43788059d1d9f167ff F ext/jni/src/c/sqlite3-jni.h 28def286ee305c1c89a43ac5918a6862d985d0534f7ccbbd74df4885d3918b73 F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1 F ext/jni/src/org/sqlite/jni/CollationNeeded.java ebc7cd96d46a70daa76016a308e80f70a3f21d3282787c8d139aa840fdcb1bd7 F ext/jni/src/org/sqlite/jni/CommitHook.java 87c6a8e5138c61a8eeff018fe16d23f29219150239746032687f245938baca1a -F ext/jni/src/org/sqlite/jni/NativePointerHolder.java 70dc7bc41f80352ff3d4331e2e24f45fcd23353b3641e2f68a81bd8262215861 -F ext/jni/src/org/sqlite/jni/OutputPointer.java 08a752b58a33696c5eaf0eb9361a0966b188dec40f4a3613eb133123951f6c5f +F ext/jni/src/org/sqlite/jni/NativePointerHolder.java 9c5d901cce4f7e57c3d623f4e2476f9f79a8eed6e51b2a603f37866018e040ee +F ext/jni/src/org/sqlite/jni/OutputPointer.java a5cb651df3b3adb65a9aca6cf9a094dea1346fc9ee5f341f79276348ac268351 F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5979450e996416d28543f1d42634d308439565a99332a8bd84e424af667116cc F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564 F ext/jni/src/org/sqlite/jni/SQLFunction.java 663a4e479ec65bfbf893586439e12d30b8237898064a22ab64f5658b57315f37 -F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 2c4564b19f5366927c9a5062e36ffb7744e7f69d00b3f8ce35fe59b2f3d60698 -F ext/jni/src/org/sqlite/jni/Tester1.java a89a87f8debd89f3488a65cb42af8e14fb0150b05d5a4a3592fb86d0cfda3287 +F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 42ca7686d009a56e4f5ceb74a0bd32ca69c025f2bf30d3e906696ad36ac72510 +F ext/jni/src/org/sqlite/jni/Tester1.java 1690172fccafbf8d8170b55b950003db182265c26dbb5a510122ec46a44d2611 F ext/jni/src/org/sqlite/jni/Tracer.java c2fe1eba4a76581b93b375a7b95ab1919e5ae60accfb06d6beb067b033e9bae1 F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d F ext/jni/src/org/sqlite/jni/ValueHolder.java f022873abaabf64f3dd71ab0d6037c6e71cece3b8819fa10bf26a5461dc973ee @@ -2071,8 +2071,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7ac6614e69b03304d09745619ed83f12c7eb775aaf4a636a79289b01642ddd14 -R fe2ec7cfe7eced93fd3b168114e0d2e0 +P 16ff167691733350907d2d995c774a885214acd0fe8ec491c16b786f00fe85d4 +R fed5a38c4ce39785114a9bf68d9f61c4 U stephan -Z 9246dbb52619ce19a9defcf2e690b44f +Z a065a6cc3e3d2dbbd261c22dc07adbce # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index dce9f4cf7d..8c31c2b9aa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -16ff167691733350907d2d995c774a885214acd0fe8ec491c16b786f00fe85d4 \ No newline at end of file +41fb5898f1a78d9fd85a020e28a6048a7359b54e35632e9072917cbdbcd8b07d \ No newline at end of file