]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Minor tweaks and optimizations in the JNI bindings.
authorstephan <stephan@noemail.net>
Sun, 30 Jul 2023 13:30:52 +0000 (13:30 +0000)
committerstephan <stephan@noemail.net>
Sun, 30 Jul 2023 13:30:52 +0000 (13:30 +0000)
FossilOrigin-Name: 41fb5898f1a78d9fd85a020e28a6048a7359b54e35632e9072917cbdbcd8b07d

ext/jni/src/c/sqlite3-jni.c
ext/jni/src/org/sqlite/jni/NativePointerHolder.java
ext/jni/src/org/sqlite/jni/OutputPointer.java
ext/jni/src/org/sqlite/jni/SQLite3Jni.java
ext/jni/src/org/sqlite/jni/Tester1.java
manifest
manifest.uuid

index 1f7c5bb00369ff9a8dbe38eff15df3d0c47b635d..8db9416394399645c88313c4aaba4085f8839e2e 100644 (file)
@@ -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:
index d6543baf57181fabba1d18778f16cd3160633c51..afe2618a003d2d4e28427e1c284eb496c3997956 100644 (file)
@@ -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<ContextType> {
-  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; }
 }
index f4f2269a108ab3d3a7f74ccbdda96086e4e66663..ee308ce6699ff1e90a40e6e78420c7b352a2aca5 100644 (file)
@@ -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;}
   }
 }
index bdf89a3d01e343a229ae90a74876fb414e2fe663..f639f6ae7a0faab33b51e494c93c46203f18d025 100644 (file)
@@ -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);
index 287b61a76abdfe51e0d3f14476b07f3933b066f5..30b136d47424f8c1ca74b51f3d759483221f67db 100644 (file)
@@ -483,7 +483,7 @@ public class Tester1 {
 
   private static void testUdfJavaObject(){
     final sqlite3 db = createNewDb();
-    final ValueHolder<Long> testResult = new ValueHolder<>(42L);
+    final ValueHolder<sqlite3> 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);
index 4ba95e2df1fc60e7740a286ddc9dfbeaec63f8c5..7c0eac5fdfb58059cc225f0f2431c5d7892ae5b2 100644 (file)
--- 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.
index dce9f4cf7d7feba931a826d6826a766ccdfc7d7f..8c31c2b9aaa08572dea5c2548e86d86eab161682 100644 (file)
@@ -1 +1 @@
-16ff167691733350907d2d995c774a885214acd0fe8ec491c16b786f00fe85d4
\ No newline at end of file
+41fb5898f1a78d9fd85a020e28a6048a7359b54e35632e9072917cbdbcd8b07d
\ No newline at end of file