Minor tweaks and optimizations in the JNI bindings.
FossilOrigin-Name: 41fb5898f1a78d9fd85a020e28a6048a7359b54e35632e9072917cbdbcd8b07d
This commit is contained in:
parent
502a5c2e26
commit
13b059025f
@ -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:
|
||||
|
@ -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; }
|
||||
}
|
||||
|
@ -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;}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
20
manifest
20
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.
|
||||
|
@ -1 +1 @@
|
||||
16ff167691733350907d2d995c774a885214acd0fe8ec491c16b786f00fe85d4
|
||||
41fb5898f1a78d9fd85a020e28a6048a7359b54e35632e9072917cbdbcd8b07d
|
Loading…
Reference in New Issue
Block a user