https://github.com/mozilla/gecko-dev
Raw File
Tip revision: 79149ff2397791525200c0fc51ff128b15f6b350 authored by ffxbld on 06 July 2015, 01:07:43 UTC
Added FENNEC_39_0_1_RELEASE FENNEC_39_0_1_BUILD1 tag(s) for changeset 1d1e6d6573a3. DONTBUILD CLOSED TREE a=release
Tip revision: 79149ff
JNI.jsm
// JavaScript to Java bridge via the Java Native Interface
// Allows calling into Android SDK from JavaScript in Firefox Add-On.
// Released into the public domain.
//  C. Scott Ananian <cscott@laptop.org> (http://cscott.net)

// NOTE: All changes to this file should first be pushed to the repo at:
// https://github.com/cscott/skeleton-addon-fxandroid/tree/jni

var EXPORTED_SYMBOLS = ["JNI","android_log"];

Components.utils.import("resource://gre/modules/ctypes.jsm")

var liblog = ctypes.open('liblog.so');
var android_log = liblog.declare("__android_log_write",
                             ctypes.default_abi,
                             ctypes.int32_t,
                             ctypes.int32_t,
                             ctypes.char.ptr,
                             ctypes.char.ptr);

var libxul = ctypes.open('libxul.so');

var jenvptr = ctypes.voidptr_t;
var jclass = ctypes.voidptr_t;
var jobject = ctypes.voidptr_t;
var jvalue = ctypes.voidptr_t;
var jmethodid = ctypes.voidptr_t;
var jfieldid = ctypes.voidptr_t;

var jboolean = ctypes.uint8_t;
var jbyte = ctypes.int8_t;
var jchar = ctypes.uint16_t;
var jshort = ctypes.int16_t;
var jint = ctypes.int32_t;
var jlong = ctypes.int64_t;
var jfloat = ctypes.float32_t;
var jdouble = ctypes.float64_t;

var jsize = jint;
var jstring = jobject;
var jarray = jobject;
var jthrowable = jobject;

var JNINativeInterface = new ctypes.StructType(
    "JNINativeInterface",
    [{reserved0: ctypes.voidptr_t},
     {reserved1: ctypes.voidptr_t},
     {reserved2: ctypes.voidptr_t},
     {reserved3: ctypes.voidptr_t},
     {GetVersion: new ctypes.FunctionType(ctypes.default_abi,
                                          ctypes.int32_t,
                                          [ctypes.voidptr_t]).ptr},
     {DefineClass: new ctypes.FunctionType(ctypes.default_abi,
                                           jclass,
                                           [jenvptr, ctypes.char.ptr, jobject,
                                            jbyte.array(), jsize]).ptr},
     {FindClass: new ctypes.FunctionType(ctypes.default_abi,
                                         jclass,
                                         [jenvptr,
                                          ctypes.char.ptr]).ptr},
     {FromReflectedMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                   jmethodid,
                                                   [jenvptr, jobject]).ptr},
     {FromReflectedField: new ctypes.FunctionType(ctypes.default_abi,
                                                  jfieldid,
                                                  [jenvptr, jobject]).ptr},
     {ToReflectedMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                 jobject,
                                                 [jenvptr, jclass,
                                                  jmethodid]).ptr},
     {GetSuperclass: new ctypes.FunctionType(ctypes.default_abi,
                                             jclass, [jenvptr, jclass]).ptr},
     {IsAssignableFrom: new ctypes.FunctionType(ctypes.default_abi,
                                                jboolean,
                                                [jenvptr, jclass, jclass]).ptr},
     {ToReflectedField: new ctypes.FunctionType(ctypes.default_abi,
                                                jobject,
                                                [jenvptr, jclass,
                                                 jfieldid]).ptr},
     {Throw: new ctypes.FunctionType(ctypes.default_abi,
                                     jint, [jenvptr, jthrowable]).ptr},
     {ThrowNew: new ctypes.FunctionType(ctypes.default_abi,
                                        jint, [jenvptr, jclass,
                                               ctypes.char.ptr]).ptr},
     {ExceptionOccurred: new ctypes.FunctionType(ctypes.default_abi,
                                                 jthrowable, [jenvptr]).ptr},
     {ExceptionDescribe: new ctypes.FunctionType(ctypes.default_abi,
                                                 ctypes.void_t, [jenvptr]).ptr},
     {ExceptionClear: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t, [jenvptr]).ptr},
     {FatalError: new ctypes.FunctionType(ctypes.default_abi,
                                          ctypes.void_t,
                                          [jenvptr,
                                           ctypes.char.ptr]).ptr},
     {PushLocalFrame: new ctypes.FunctionType(ctypes.default_abi,
                                              jint,
                                              [jenvptr, jint]).ptr},
     {PopLocalFrame: new ctypes.FunctionType(ctypes.default_abi,
                                             jobject,
                                             [jenvptr, jobject]).ptr},
     {NewGlobalRef: new ctypes.FunctionType(ctypes.default_abi,
                                            jobject, [jenvptr, jobject]).ptr},
     {DeleteGlobalRef: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr,
                                               jobject]).ptr},
     {DeleteLocalRef: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr,
                                               jobject]).ptr},
     {IsSameObject: new ctypes.FunctionType(ctypes.default_abi,
                                            jboolean,
                                            [jenvptr, jobject, jobject]).ptr},
     {NewLocalRef: new ctypes.FunctionType(ctypes.default_abi,
                                            jobject, [jenvptr, jobject]).ptr},
     {EnsureLocalCapacity: new ctypes.FunctionType(ctypes.default_abi,
                                                   jint, [jenvptr, jint]).ptr},
     {AllocObject: new ctypes.FunctionType(ctypes.default_abi,
                                           jobject, [jenvptr, jclass]).ptr},
     {NewObject: new ctypes.FunctionType(ctypes.default_abi,
                                         jobject,
                                         [jenvptr,
                                          jclass,
                                          jmethodid,
                                          "..."]).ptr},
     {NewObjectV: ctypes.voidptr_t},
     {NewObjectA: ctypes.voidptr_t},
     {GetObjectClass: new ctypes.FunctionType(ctypes.default_abi,
                                              jclass,
                                              [jenvptr, jobject]).ptr},
     {IsInstanceOf: new ctypes.FunctionType(ctypes.default_abi,
                                            jboolean,
                                            [jenvptr, jobject, jclass]).ptr},
     {GetMethodID: new ctypes.FunctionType(ctypes.default_abi,
                                           jmethodid,
                                           [jenvptr,
                                            jclass,
                                            ctypes.char.ptr,
                                            ctypes.char.ptr]).ptr},
     {CallObjectMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                jobject,
                                                [jenvptr, jobject, jmethodid,
                                                 "..."]).ptr},
     {CallObjectMethodV: ctypes.voidptr_t},
     {CallObjectMethodA: ctypes.voidptr_t},
     {CallBooleanMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                 jboolean,
                                                 [jenvptr,
                                                  jobject,
                                                  jmethodid,
                                                  "..."]).ptr},
     {CallBooleanMethodV: ctypes.voidptr_t},
     {CallBooleanMethodA: ctypes.voidptr_t},
     {CallByteMethod: new ctypes.FunctionType(ctypes.default_abi,
                                              jbyte,
                                              [jenvptr,
                                               jobject,
                                               jmethodid,
                                               "..."]).ptr},
     {CallByteMethodV: ctypes.voidptr_t},
     {CallByteMethodA: ctypes.voidptr_t},
     {CallCharMethod: new ctypes.FunctionType(ctypes.default_abi,
                                              jchar,
                                              [jenvptr,
                                               jobject,
                                               jmethodid,
                                               "..."]).ptr},
     {CallCharMethodV: ctypes.voidptr_t},
     {CallCharMethodA: ctypes.voidptr_t},
     {CallShortMethod: new ctypes.FunctionType(ctypes.default_abi,
                                               jshort,
                                               [jenvptr,
                                                jobject,
                                                jmethodid,
                                                "..."]).ptr},
     {CallShortMethodV: ctypes.voidptr_t},
     {CallShortMethodA: ctypes.voidptr_t},
     {CallIntMethod: new ctypes.FunctionType(ctypes.default_abi,
                                             jint,
                                             [jenvptr,
                                              jobject,
                                              jmethodid,
                                              "..."]).ptr},
     {CallIntMethodV: ctypes.voidptr_t},
     {CallIntMethodA: ctypes.voidptr_t},
     {CallLongMethod: new ctypes.FunctionType(ctypes.default_abi,
                                              jlong,
                                              [jenvptr,
                                               jobject,
                                               jmethodid,
                                               "..."]).ptr},
     {CallLongMethodV: ctypes.voidptr_t},
     {CallLongMethodA: ctypes.voidptr_t},
     {CallFloatMethod: new ctypes.FunctionType(ctypes.default_abi,
                                               jfloat,
                                               [jenvptr,
                                                jobject,
                                                jmethodid,
                                                "..."]).ptr},
     {CallFloatMethodV: ctypes.voidptr_t},
     {CallFloatMethodA: ctypes.voidptr_t},
     {CallDoubleMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                jdouble,
                                                [jenvptr,
                                                 jobject,
                                                 jmethodid,
                                                 "..."]).ptr},
     {CallDoubleMethodV: ctypes.voidptr_t},
     {CallDoubleMethodA: ctypes.voidptr_t},
     {CallVoidMethod: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr,
                                               jobject,
                                               jmethodid,
                                               "..."]).ptr},
     {CallVoidMethodV: ctypes.voidptr_t},
     {CallVoidMethodA: ctypes.voidptr_t},
     {CallNonvirtualObjectMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                          jobject,
                                                          [jenvptr, jobject,
                                                           jclass, jmethodid,
                                                           "..."]).ptr},
     {CallNonvirtualObjectMethodV: ctypes.voidptr_t},
     {CallNonvirtualObjectMethodA: ctypes.voidptr_t},
     {CallNonvirtualBooleanMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                           jboolean,
                                                           [jenvptr, jobject,
                                                            jclass, jmethodid,
                                                            "..."]).ptr},
     {CallNonvirtualBooleanMethodV: ctypes.voidptr_t},
     {CallNonvirtualBooleanMethodA: ctypes.voidptr_t},
     {CallNonvirtualByteMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                        jbyte,
                                                        [jenvptr, jobject,
                                                         jclass, jmethodid,
                                                         "..."]).ptr},
     {CallNonvirtualByteMethodV: ctypes.voidptr_t},
     {CallNonvirtualByteMethodA: ctypes.voidptr_t},
     {CallNonvirtualCharMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                        jchar,
                                                        [jenvptr, jobject,
                                                         jclass, jmethodid,
                                                         "..."]).ptr},
     {CallNonvirtualCharMethodV: ctypes.voidptr_t},
     {CallNonvirtualCharMethodA: ctypes.voidptr_t},
     {CallNonvirtualShortMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                         jshort,
                                                         [jenvptr, jobject,
                                                          jclass, jmethodid,
                                                          "..."]).ptr},
     {CallNonvirtualShortMethodV: ctypes.voidptr_t},
     {CallNonvirtualShortMethodA: ctypes.voidptr_t},
     {CallNonvirtualIntMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                       jint,
                                                       [jenvptr, jobject,
                                                        jclass, jmethodid,
                                                        "..."]).ptr},
     {CallNonvirtualIntMethodV: ctypes.voidptr_t},
     {CallNonvirtualIntMethodA: ctypes.voidptr_t},
     {CallNonvirtualLongMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                        jlong,
                                                        [jenvptr, jobject,
                                                         jclass, jmethodid,
                                                         "..."]).ptr},
     {CallNonvirtualLongMethodV: ctypes.voidptr_t},
     {CallNonvirtualLongMethodA: ctypes.voidptr_t},
     {CallNonvirtualFloatMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                         jfloat,
                                                         [jenvptr, jobject,
                                                          jclass, jmethodid,
                                                          "..."]).ptr},
     {CallNonvirtualFloatMethodV: ctypes.voidptr_t},
     {CallNonvirtualFloatMethodA: ctypes.voidptr_t},
     {CallNonvirtualDoubleMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                          jdouble,
                                                          [jenvptr, jobject,
                                                           jclass, jmethodid,
                                                           "..."]).ptr},
     {CallNonvirtualDoubleMethodV: ctypes.voidptr_t},
     {CallNonvirtualDoubleMethodA: ctypes.voidptr_t},
     {CallNonvirtualVoidMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                        ctypes.void_t,
                                                        [jenvptr, jobject,
                                                         jclass, jmethodid,
                                                         "..."]).ptr},
     {CallNonvirtualVoidMethodV: ctypes.voidptr_t},
     {CallNonvirtualVoidMethodA: ctypes.voidptr_t},
     {GetFieldID: new ctypes.FunctionType(ctypes.default_abi,
                                          jfieldid,
                                          [jenvptr, jclass,
                                           ctypes.char.ptr,
                                           ctypes.char.ptr]).ptr},
     {GetObjectField: new ctypes.FunctionType(ctypes.default_abi,
                                              jobject,
                                              [jenvptr, jobject,
                                               jfieldid]).ptr},
     {GetBooleanField: new ctypes.FunctionType(ctypes.default_abi,
                                               jboolean,
                                               [jenvptr, jobject,
                                                jfieldid]).ptr},
     {GetByteField: new ctypes.FunctionType(ctypes.default_abi,
                                            jbyte,
                                            [jenvptr, jobject,
                                             jfieldid]).ptr},
     {GetCharField: new ctypes.FunctionType(ctypes.default_abi,
                                            jchar,
                                            [jenvptr, jobject,
                                             jfieldid]).ptr},
     {GetShortField: new ctypes.FunctionType(ctypes.default_abi,
                                             jshort,
                                             [jenvptr, jobject,
                                              jfieldid]).ptr},
     {GetIntField: new ctypes.FunctionType(ctypes.default_abi,
                                           jint,
                                           [jenvptr, jobject,
                                            jfieldid]).ptr},
     {GetLongField: new ctypes.FunctionType(ctypes.default_abi,
                                            jlong,
                                            [jenvptr, jobject,
                                             jfieldid]).ptr},
     {GetFloatField: new ctypes.FunctionType(ctypes.default_abi,
                                             jfloat,
                                             [jenvptr, jobject,
                                              jfieldid]).ptr},
     {GetDoubleField: new ctypes.FunctionType(ctypes.default_abi,
                                              jdouble,
                                              [jenvptr, jobject,
                                               jfieldid]).ptr},
     {SetObjectField: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr, jobject,
                                               jfieldid, jobject]).ptr},
     {SetBooleanField: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr, jobject,
                                               jfieldid, jboolean]).ptr},
     {SetByteField: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr, jobject,
                                               jfieldid, jbyte]).ptr},
     {SetCharField: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr, jobject,
                                               jfieldid, jchar]).ptr},
     {SetShortField: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr, jobject,
                                               jfieldid, jshort]).ptr},
     {SetIntField: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr, jobject,
                                               jfieldid, jint]).ptr},
     {SetLongField: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr, jobject,
                                               jfieldid, jlong]).ptr},
     {SetFloatField: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr, jobject,
                                               jfieldid, jfloat]).ptr},
     {SetDoubleField: new ctypes.FunctionType(ctypes.default_abi,
                                              ctypes.void_t,
                                              [jenvptr, jobject,
                                               jfieldid, jdouble]).ptr},
     {GetStaticMethodID: new ctypes.FunctionType(ctypes.default_abi,
                                           jmethodid,
                                           [jenvptr,
                                            jclass,
                                            ctypes.char.ptr,
                                            ctypes.char.ptr]).ptr},
     {CallStaticObjectMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                      jobject,
                                                      [jenvptr, jclass,
                                                       jmethodid,
                                                       "..."]).ptr},
     {CallStaticObjectMethodV: ctypes.voidptr_t},
     {CallStaticObjectMethodA: ctypes.voidptr_t},
     {CallStaticBooleanMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                       jboolean,
                                                       [jenvptr, jclass,
                                                        jmethodid,
                                                        "..."]).ptr},
     {CallStaticBooleanMethodV: ctypes.voidptr_t},
     {CallStaticBooleanMethodA: ctypes.voidptr_t},
     {CallStaticByteMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                    jbyte,
                                                    [jenvptr, jclass,
                                                     jmethodid,
                                                     "..."]).ptr},
     {CallStaticByteMethodV: ctypes.voidptr_t},
     {CallStaticByteMethodA: ctypes.voidptr_t},
     {CallStaticCharMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                    jchar,
                                                    [jenvptr, jclass,
                                                     jmethodid,
                                                     "..."]).ptr},
     {CallStaticCharMethodV: ctypes.voidptr_t},
     {CallStaticCharMethodA: ctypes.voidptr_t},
     {CallStaticShortMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                     jshort,
                                                     [jenvptr, jclass,
                                                      jmethodid,
                                                      "..."]).ptr},
     {CallStaticShortMethodV: ctypes.voidptr_t},
     {CallStaticShortMethodA: ctypes.voidptr_t},
     {CallStaticIntMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                   jint,
                                                   [jenvptr, jclass,
                                                    jmethodid,
                                                    "..."]).ptr},
     {CallStaticIntMethodV: ctypes.voidptr_t},
     {CallStaticIntMethodA: ctypes.voidptr_t},
     {CallStaticLongMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                    jlong,
                                                    [jenvptr, jclass,
                                                     jmethodid,
                                                     "..."]).ptr},
     {CallStaticLongMethodV: ctypes.voidptr_t},
     {CallStaticLongMethodA: ctypes.voidptr_t},
     {CallStaticFloatMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                     jfloat,
                                                     [jenvptr, jclass,
                                                      jmethodid,
                                                      "..."]).ptr},
     {CallStaticFloatMethodV: ctypes.voidptr_t},
     {CallStaticFloatMethodA: ctypes.voidptr_t},
     {CallStaticDoubleMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                      jdouble,
                                                      [jenvptr, jclass,
                                                       jmethodid,
                                                       "..."]).ptr},
     {CallStaticDoubleMethodV: ctypes.voidptr_t},
     {CallStaticDoubleMethodA: ctypes.voidptr_t},
     {CallStaticVoidMethod: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jclass,
                                                     jmethodid,
                                                     "..."]).ptr},
     {CallStaticVoidMethodV: ctypes.voidptr_t},
     {CallStaticVoidMethodA: ctypes.voidptr_t},
     {GetStaticFieldID: new ctypes.FunctionType(ctypes.default_abi,
                                                jfieldid,
                                                [jenvptr, jclass,
                                                 ctypes.char.ptr,
                                                 ctypes.char.ptr]).ptr},
     {GetStaticObjectField: new ctypes.FunctionType(ctypes.default_abi,
                                                    jobject,
                                                    [jenvptr, jclass,
                                                     jfieldid]).ptr},
     {GetStaticBooleanField: new ctypes.FunctionType(ctypes.default_abi,
                                                     jboolean,
                                                     [jenvptr, jclass,
                                                      jfieldid]).ptr},
     {GetStaticByteField: new ctypes.FunctionType(ctypes.default_abi,
                                                  jbyte,
                                                  [jenvptr, jclass,
                                                   jfieldid]).ptr},
     {GetStaticCharField: new ctypes.FunctionType(ctypes.default_abi,
                                                  jchar,
                                                  [jenvptr, jclass,
                                                   jfieldid]).ptr},
     {GetStaticShortField: new ctypes.FunctionType(ctypes.default_abi,
                                                   jshort,
                                                   [jenvptr, jclass,
                                                    jfieldid]).ptr},
     {GetStaticIntField: new ctypes.FunctionType(ctypes.default_abi,
                                                 jint,
                                                 [jenvptr, jclass,
                                                  jfieldid]).ptr},
     {GetStaticLongField: new ctypes.FunctionType(ctypes.default_abi,
                                                  jlong,
                                                  [jenvptr, jclass,
                                                   jfieldid]).ptr},
     {GetStaticFloatField: new ctypes.FunctionType(ctypes.default_abi,
                                                   jfloat,
                                                   [jenvptr, jclass,
                                                    jfieldid]).ptr},
     {GetStaticDoubleField: new ctypes.FunctionType(ctypes.default_abi,
                                                    jdouble,
                                                    [jenvptr, jclass,
                                                     jfieldid]).ptr},
     {SetStaticObjectField: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jclass,
                                                     jfieldid, jobject]).ptr},
     {SetStaticBooleanField: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jclass,
                                                     jfieldid, jboolean]).ptr},
     {SetStaticByteField: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jclass,
                                                     jfieldid, jbyte]).ptr},
     {SetStaticCharField: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jclass,
                                                     jfieldid, jchar]).ptr},
     {SetStaticShortField: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jclass,
                                                     jfieldid, jshort]).ptr},
     {SetStaticIntField: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jclass,
                                                     jfieldid, jint]).ptr},
     {SetStaticLongField: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jclass,
                                                     jfieldid, jlong]).ptr},
     {SetStaticFloatField: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jclass,
                                                     jfieldid, jfloat]).ptr},
     {SetStaticDoubleField: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jclass,
                                                     jfieldid, jdouble]).ptr},

     {NewString: new ctypes.FunctionType(ctypes.default_abi,
                                         jstring,
                                         [jenvptr, jchar.ptr, jsize]).ptr},
     {GetStringLength: new ctypes.FunctionType(ctypes.default_abi,
                                               jsize,
                                               [jenvptr, jstring]).ptr},
     {GetStringChars: new ctypes.FunctionType(ctypes.default_abi,
                                              jchar.ptr,
                                              [jenvptr, jstring,
                                               jboolean.ptr]).ptr},
     {ReleaseStringChars: new ctypes.FunctionType(ctypes.default_abi,
                                                  ctypes.void_t,
                                                  [jenvptr, jstring,
                                                   jchar.ptr]).ptr},

     {NewStringUTF: new ctypes.FunctionType(ctypes.default_abi,
                                            jstring,
                                            [jenvptr,
                                             ctypes.char.ptr]).ptr},
     {GetStringUTFLength: new ctypes.FunctionType(ctypes.default_abi,
                                                  jsize,
                                                  [jenvptr, jstring]).ptr},
     {GetStringUTFChars: new ctypes.FunctionType(ctypes.default_abi,
                                                 ctypes.char.ptr,
                                                 [jenvptr, jstring,
                                                  jboolean.ptr]).ptr},
     {ReleaseStringUTFChars: new ctypes.FunctionType(ctypes.default_abi,
                                                     ctypes.void_t,
                                                     [jenvptr, jstring,
                                                      ctypes.char.ptr]).ptr},
     {GetArrayLength: new ctypes.FunctionType(ctypes.default_abi,
                                              jsize,
                                              [jenvptr, jarray]).ptr},
     {NewObjectArray: new ctypes.FunctionType(ctypes.default_abi,
                                              jarray,
                                              [jenvptr, jsize,
                                               jclass, jobject]).ptr},
     {GetObjectArrayElement: new ctypes.FunctionType(ctypes.default_abi,
                                                     jobject,
                                                     [jenvptr, jarray,
                                                      jsize]).ptr},
     {SetObjectArrayElement: new ctypes.FunctionType(ctypes.default_abi,
                                                     ctypes.void_t,
                                                     [jenvptr, jarray,
                                                      jsize, jobject]).ptr},
     {NewBooleanArray: new ctypes.FunctionType(ctypes.default_abi,
                                               jarray,
                                               [jenvptr, jsize]).ptr},
     {NewByteArray: new ctypes.FunctionType(ctypes.default_abi,
                                            jarray,
                                            [jenvptr, jsize]).ptr},
     {NewCharArray: new ctypes.FunctionType(ctypes.default_abi,
                                            jarray,
                                            [jenvptr, jsize]).ptr},
     {NewShortArray: new ctypes.FunctionType(ctypes.default_abi,
                                             jarray,
                                             [jenvptr, jsize]).ptr},
     {NewIntArray: new ctypes.FunctionType(ctypes.default_abi,
                                           jarray,
                                           [jenvptr, jsize]).ptr},
     {NewLongArray: new ctypes.FunctionType(ctypes.default_abi,
                                            jarray,
                                            [jenvptr, jsize]).ptr},
     {NewFloatArray: new ctypes.FunctionType(ctypes.default_abi,
                                             jarray,
                                             [jenvptr, jsize]).ptr},
     {NewDoubleArray: new ctypes.FunctionType(ctypes.default_abi,
                                              jarray,
                                              [jenvptr, jsize]).ptr},
     {GetBooleanArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                       jboolean.ptr,
                                                       [jenvptr, jarray,
                                                        jboolean.ptr]).ptr},
     {GetByteArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                    jbyte.ptr,
                                                    [jenvptr, jarray,
                                                     jboolean.ptr]).ptr},
     {GetCharArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                    jchar.ptr,
                                                    [jenvptr, jarray,
                                                     jboolean.ptr]).ptr},
     {GetShortArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                     jshort.ptr,
                                                     [jenvptr, jarray,
                                                      jboolean.ptr]).ptr},
     {GetIntArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                   jint.ptr,
                                                   [jenvptr, jarray,
                                                    jboolean.ptr]).ptr},
     {GetLongArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                    jlong.ptr,
                                                    [jenvptr, jarray,
                                                     jboolean.ptr]).ptr},
     {GetFloatArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                     jfloat.ptr,
                                                     [jenvptr, jarray,
                                                      jboolean.ptr]).ptr},
     {GetDoubleArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                      jdouble.ptr,
                                                      [jenvptr, jarray,
                                                       jboolean.ptr]).ptr},
     {ReleaseBooleanArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                           ctypes.void_t,
                                                           [jenvptr, jarray,
                                                            jboolean.ptr,
                                                            jint]).ptr},
     {ReleaseByteArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                        ctypes.void_t,
                                                        [jenvptr, jarray,
                                                         jbyte.ptr,
                                                         jint]).ptr},
     {ReleaseCharArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                        ctypes.void_t,
                                                        [jenvptr, jarray,
                                                         jchar.ptr,
                                                         jint]).ptr},
     {ReleaseShortArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                         ctypes.void_t,
                                                         [jenvptr, jarray,
                                                          jshort.ptr,
                                                          jint]).ptr},
     {ReleaseIntArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                       ctypes.void_t,
                                                       [jenvptr, jarray,
                                                        jint.ptr,
                                                        jint]).ptr},
     {ReleaseLongArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                        ctypes.void_t,
                                                        [jenvptr, jarray,
                                                         jlong.ptr,
                                                         jint]).ptr},
     {ReleaseFloatArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                         ctypes.void_t,
                                                         [jenvptr, jarray,
                                                          jfloat.ptr,
                                                          jint]).ptr},
     {ReleaseDoubleArrayElements: new ctypes.FunctionType(ctypes.default_abi,
                                                          ctypes.void_t,
                                                          [jenvptr, jarray,
                                                           jdouble.ptr,
                                                           jint]).ptr},
     {GetBooleanArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                     ctypes.void_t,
                                                     [jenvptr, jarray,
                                                      jsize, jsize,
                                                      jboolean.array()]).ptr},
     {GetByteArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                     ctypes.void_t,
                                                     [jenvptr, jarray,
                                                      jsize, jsize,
                                                      jbyte.array()]).ptr},
     {GetCharArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                  ctypes.void_t,
                                                  [jenvptr, jarray,
                                                   jsize, jsize,
                                                   jchar.array()]).ptr},
     {GetShortArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                   ctypes.void_t,
                                                   [jenvptr, jarray,
                                                    jsize, jsize,
                                                    jshort.array()]).ptr},
     {GetIntArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                 ctypes.void_t,
                                                 [jenvptr, jarray,
                                                  jsize, jsize,
                                                  jint.array()]).ptr},
     {GetLongArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                  ctypes.void_t,
                                                  [jenvptr, jarray,
                                                   jsize, jsize,
                                                   jlong.array()]).ptr},
     {GetFloatArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                   ctypes.void_t,
                                                   [jenvptr, jarray,
                                                    jsize, jsize,
                                                    jfloat.array()]).ptr},
     {GetDoubleArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jarray,
                                                     jsize, jsize,
                                                     jdouble.array()]).ptr},
     {SetBooleanArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                     ctypes.void_t,
                                                     [jenvptr, jarray,
                                                      jsize, jsize,
                                                      jboolean.array()]).ptr},
     {SetByteArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                  ctypes.void_t,
                                                  [jenvptr, jarray,
                                                   jsize, jsize,
                                                   jbyte.array()]).ptr},
     {SetCharArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                  ctypes.void_t,
                                                  [jenvptr, jarray,
                                                   jsize, jsize,
                                                   jchar.array()]).ptr},
     {SetShortArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                   ctypes.void_t,
                                                   [jenvptr, jarray,
                                                    jsize, jsize,
                                                    jshort.array()]).ptr},
     {SetIntArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                 ctypes.void_t,
                                                 [jenvptr, jarray,
                                                  jsize, jsize,
                                                  jint.array()]).ptr},
     {SetLongArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                  ctypes.void_t,
                                                  [jenvptr, jarray,
                                                   jsize, jsize,
                                                   jlong.array()]).ptr},
     {SetFloatArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                   ctypes.void_t,
                                                   [jenvptr, jarray,
                                                    jsize, jsize,
                                                    jfloat.array()]).ptr},
     {SetDoubleArrayRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                    ctypes.void_t,
                                                    [jenvptr, jarray,
                                                     jsize, jsize,
                                                     jdouble.array()]).ptr},
     {RegisterNatives: ctypes.voidptr_t},
     {UnregisterNatives: ctypes.voidptr_t},
     {MonitorEnter: new ctypes.FunctionType(ctypes.default_abi,
                                            jint, [jenvptr, jobject]).ptr},
     {MonitorExit: new ctypes.FunctionType(ctypes.default_abi,
                                            jint, [jenvptr, jobject]).ptr},
     {GetJavaVM: ctypes.voidptr_t},
     {GetStringRegion: new ctypes.FunctionType(ctypes.default_abi,
                                               ctypes.void_t,
                                               [jenvptr, jstring,
                                                jsize, jsize,
                                                jchar.array()]).ptr},
     {GetStringUTFRegion: new ctypes.FunctionType(ctypes.default_abi,
                                                  ctypes.void_t,
                                                  [jenvptr, jstring,
                                                   jsize, jsize,
                                                   ctypes.char.array()]).ptr},
     {GetPrimitiveArrayCritical: ctypes.voidptr_t},
     {ReleasePrimitiveArrayCritical: ctypes.voidptr_t},
     {GetStringCritical: ctypes.voidptr_t},
     {ReleaseStringCritical: ctypes.voidptr_t},
     {NewWeakGlobalRef: ctypes.voidptr_t},
     {DeleteWeakGlobalRef: ctypes.voidptr_t},
     {ExceptionCheck: new ctypes.FunctionType(ctypes.default_abi,
                                              jboolean, [jenvptr]).ptr},
     {NewDirectByteBuffer: ctypes.voidptr_t},
     {GetDirectBufferAddress: ctypes.voidptr_t},
     {GetDirectBufferCapacity: ctypes.voidptr_t},
     {GetObjectRefType: ctypes.voidptr_t}]
);

var GetJNIForThread = libxul.declare("GetJNIForThread",
                                     ctypes.default_abi,
                                     JNINativeInterface.ptr.ptr);

var registry = Object.create(null);
var classes = Object.create(null);

function JNIUnloadClasses(jenv) {
  Object.getOwnPropertyNames(registry).forEach(function(classname) {
    var jcls = unwrap(registry[classname]);
    jenv.contents.contents.DeleteGlobalRef(jenv, jcls);

    // Purge the registry, so we don't try to reuse stale global references
    // in JNI calls and we garbage-collect the JS global reference objects.
    delete registry[classname];
  });

  // The refs also get added to the 'classes' object, so we should purge it too.
  // That object is a hierarchical data structure organized by class path parts,
  // but deleting its own properties should be sufficient to break its refs.
  Object.getOwnPropertyNames(classes).forEach(function(topLevelPart) {
    delete classes[topLevelPart];
  });
}

var PREFIX = 'js#';
// this regex matches one component of a type signature:
// any number of array modifiers, followed by either a
// primitive type character or L<classname>;
var sigRegex = () => /\[*([VZBCSIJFD]|L([^.\/;]+(\/[^.\/;]+)*);)/g;
var ensureSig = function(classname_or_signature) {
    // convert a classname into a signature,
    // leaving unchanged signatures.  We assume that
    // anything not a valid signature is a classname.
  var m = sigRegex().exec(classname_or_signature);
  return (m && m[0] === classname_or_signature) ? classname_or_signature :
    'L' + classname_or_signature.replace(/\./g, '/') + ';';
};
var wrap = function(obj, classSig) {
  if (!classSig) { return obj; }
  // don't wrap primitive types.
  if (classSig.charAt(0)!=='L' &&
      classSig.charAt(0)!=='[') { return obj; }
  var proto = registry[classSig][PREFIX+'proto'];
  return new proto(obj);
};
var unwrap = function(obj, opt_jenv, opt_ctype) {
  if (obj && typeof(obj)==='object' && (PREFIX+'obj') in obj) {
    return obj[PREFIX+'obj'];
  } else if (opt_jenv && opt_ctype) {
    if (opt_ctype !== jobject)
      return opt_ctype(obj); // cast to given primitive ctype
    if (typeof(obj)==='string')
      return unwrap(JNINewString(opt_jenv, obj)); // create Java String
  }
  return obj;
};
var ensureLoaded = function(jenv, classSig) {
  if (!Object.hasOwnProperty.call(registry, classSig)) {
    JNILoadClass(jenv, classSig);
  }
  return registry[classSig];
};

function JNINewString(jenv, value) {
  var s = jenv.contents.contents.NewStringUTF(jenv, ctypes.char.array()(value));
  ensureLoaded(jenv, "Ljava/lang/String;");
  return wrap(s, "Ljava/lang/String;");
}

function JNIReadString(jenv, jstring_value) {
  var val = unwrap(jstring_value);
  if ((!val) || val.isNull()) { return null; }
  var chars = jenv.contents.contents.GetStringUTFChars(jenv, val, null);
  var result = chars.readString();
  jenv.contents.contents.ReleaseStringUTFChars(jenv, val, chars);
  return result;
}

var sigInfo = {
  'V': { name: 'Void', longName: 'Void', ctype: ctypes.void_t },
  'Z': { name: 'Boolean', longName: 'Boolean', ctype: jboolean },
  'B': { name: 'Byte', longName: 'Byte', ctype: jbyte },
  'C': { name: 'Char', longName: 'Char', ctype: jchar },
  'S': { name: 'Short', longName: 'Short', ctype: jshort },
  'I': { name: 'Int', longName: 'Integer', ctype: jint },
  'J': { name: 'Long', longName: 'Long', ctype: jlong },
  'F': { name: 'Float', longName: 'Float', ctype: jfloat },
  'D': { name: 'Double', longName: 'Double', ctype: jdouble },
  'L': { name: 'Object', longName: 'Object', ctype: jobject },
  '[': { name: 'Object', longName: 'Object', ctype: jarray }
};

var sig2type = function(sig) { return sigInfo[sig.charAt(0)].name; };
var sig2ctype = function(sig) { return sigInfo[sig.charAt(0)].ctype; };
var sig2prim = function(sig) { return sigInfo[sig.charAt(0)].longName; };

// return the class object for a signature string.
// allocates 1 or 2 local refs
function JNIClassObj(jenv, classSig) {
    var jenvpp = function() { return jenv.contents.contents; };
    // Deal with funny calling convention of JNI FindClass method.
    // Classes get the leading & trailing chars stripped; primitives
    // have to be looked up via their wrapper type.
    var prim = function(ty) {
        var jcls = jenvpp().FindClass(jenv, "java/lang/"+ty);
        var jfld = jenvpp().GetStaticFieldID(jenv, jcls, "TYPE",
                                             "Ljava/lang/Class;");
        return jenvpp().GetStaticObjectField(jenv, jcls, jfld);
    };
    switch (classSig.charAt(0)) {
    case '[':
        return jenvpp().FindClass(jenv, classSig);
    case 'L':
        classSig = classSig.substring(1, classSig.indexOf(';'));
        return jenvpp().FindClass(jenv, classSig);
    default:
      return prim(sig2prim(classSig));
    }
}

// return the signature string for a Class object.
// allocates 2 local refs
function JNIClassSig(jenv, jcls) {
  var jenvpp = function() { return jenv.contents.contents; };
  var jclscls = jenvpp().FindClass(jenv, "java/lang/Class");
  var jmtd = jenvpp().GetMethodID(jenv, jclscls,
                                  "getName", "()Ljava/lang/String;");
  var name = jenvpp().CallObjectMethod(jenv, jcls, jmtd);
  name = JNIReadString(jenv, name);
  // API is weird.  Make sure we're using slashes not dots
  name = name.replace(/\./g, '/');
  // special case primitives, arrays
  if (name.charAt(0)==='[') return name;
  switch(name) {
  case 'void': return 'V';
  case 'boolean': return 'Z';
  case 'byte': return 'B';
  case 'char': return 'C';
  case 'short': return 'S';
  case 'int': return 'I';
  case 'long': return 'J';
  case 'float': return 'F';
  case 'double': return 'D';
  default:
    return 'L' + name + ';';
  }
}

// create dispatch method
// we resolve overloaded methods only by # of arguments.  If you need
// further resolution, use the 'long form' of the method name, ie:
//    obj['toString()Ljava/lang/String'].call(obj);
var overloadFunc = function(basename) {
  return function() {
    return this[basename+'('+arguments.length+')'].apply(this, arguments);
  };
};

// Create appropriate wrapper fields/methods for a Java class.
function JNILoadClass(jenv, classSig, opt_props) {
  var jenvpp = function() { return jenv.contents.contents; };
  var props = opt_props || {};

  // allocate a local reference frame with enough space
  // this class (1 or 2 local refs) plus superclass (3 refs)
  // plus array element class (1 or 2 local refs)
  var numLocals = 7;
  jenvpp().PushLocalFrame(jenv, numLocals);

  var jcls;
  if (Object.hasOwnProperty.call(registry, classSig)) {
    jcls = unwrap(registry[classSig]);
  } else {
    jcls = jenvpp().NewGlobalRef(jenv, JNIClassObj(jenv, classSig));

    // get name of superclass
    var jsuper = jenvpp().GetSuperclass(jenv, jcls);
    if (jsuper.isNull()) {
      jsuper = null;
    } else {
      jsuper = JNIClassSig(jenv, jsuper);
    }

    registry[classSig] = Object.create(jsuper?ensureLoaded(jenv, jsuper):null);
    registry[classSig][PREFIX+'obj'] = jcls; // global ref, persistent.
    registry[classSig][PREFIX+'proto'] =
      function(o) { this[PREFIX+'obj'] = o; };
    registry[classSig][PREFIX+'proto'].prototype =
      Object.create(jsuper ?
                    ensureLoaded(jenv, jsuper)[PREFIX+'proto'].prototype :
                    null);
    // Add a __cast__ method to the wrapper corresponding to the class
    registry[classSig].__cast__ = function(obj) {
      return wrap(unwrap(obj), classSig);
    };

    // make wrapper accessible via the classes object.
    var path = sig2type(classSig).toLowerCase();
    if (classSig.charAt(0)==='L') {
      path = classSig.substring(1, classSig.length-1);
    }
    if (classSig.charAt(0)!=='[') {
      var root = classes, i;
      var parts = path.split('/');
      for (i = 0; i < parts.length-1; i++) {
        if (!Object.hasOwnProperty.call(root, parts[i])) {
          root[parts[i]] = Object.create(null);
        }
        root = root[parts[i]];
      }
      root[parts[parts.length-1]] = registry[classSig];
    }
  }

  var r = registry[classSig];
  var rpp = r[PREFIX+'proto'].prototype;

  if (classSig.charAt(0)==='[') {
    // add 'length' field for arrays
    Object.defineProperty(rpp, 'length', {
      get: function() {
        return jenvpp().GetArrayLength(jenv, unwrap(this));
      }
    });
    // add 'get' and 'set' methods, 'new' constructor
    var elemSig = classSig.substring(1);
    ensureLoaded(jenv, elemSig);

    registry[elemSig].__array__ = r;
    if (!Object.hasOwnProperty.call(registry[elemSig], 'array'))
      registry[elemSig].array = r;

    if (elemSig.charAt(0)==='L' || elemSig.charAt(0)==='[') {
      var elemClass = unwrap(registry[elemSig]);

      rpp.get = function(idx) {
        return wrap(jenvpp().GetObjectArrayElement(jenv, unwrap(this), idx),
                    elemSig);
      };
      rpp.set = function(idx, value) {
        jenvpp().SetObjectArrayElement(jenv, unwrap(this), idx,
                                       unwrap(value, jenv, jobject));
      };
      rpp.getElements = function(start, len) {
        var i, r=[];
        for (i=0; i<len; i++) { r.push(this.get(start+i)); }
        return r;
      };
      rpp.setElements = function(start, vals) {
        vals.forEach(function(v, i) { this.set(start+i, v); }.bind(this));
      };
      r['new'] = function(length) {
        return wrap(jenvpp().NewObjectArray(jenv, length, elemClass, null),
                    classSig);
      };
    } else {
      var ty = sig2type(elemSig), ctype = sig2ctype(elemSig);
      var constructor = "New"+ty+"Array";
      var getter = "Get"+ty+"ArrayRegion";
      var setter = "Set"+ty+"ArrayRegion";
      rpp.get = function(idx) { return this.getElements(idx, 1)[0]; };
      rpp.set = function(idx, val) { this.setElements(idx, [val]); };
      rpp.getElements = function(start, len) {
        var j = jenvpp();
        var buf = new (ctype.array())(len);
        j[getter].call(j, jenv, unwrap(this), start, len, buf);
        return buf;
      };
      rpp.setElements = function(start, vals) {
        var j = jenvpp();
        j[setter].call(j, jenv, unwrap(this), start, vals.length,
                       ctype.array()(vals));
      };
      r['new'] = function(length) {
        var j = jenvpp();
        return wrap(j[constructor].call(j, jenv, length), classSig);
      };
    }
  }

  (props.static_fields || []).forEach(function(fld) {
    var jfld = jenvpp().GetStaticFieldID(jenv, jcls, fld.name, fld.sig);
    var ty = sig2type(fld.sig), nm = fld.sig;
    var getter = "GetStatic"+ty+"Field", setter = "SetStatic"+ty+"Field";
    ensureLoaded(jenv, nm);
    var props =  {
      get: function() {
        var j = jenvpp();
        return wrap(j[getter].call(j, jenv, jcls, jfld), nm);
      },
      set: function(newValue) {
        var j = jenvpp();
        j[setter].call(j, jenv, jcls, jfld, unwrap(newValue));
      }
    };
    Object.defineProperty(r, fld.name, props);
    // add static fields to object instances, too.
    Object.defineProperty(rpp, fld.name, props);
  });
  (props.static_methods || []).forEach(function(mtd) {
    var jmtd = jenvpp().GetStaticMethodID(jenv, jcls, mtd.name, mtd.sig);
    var argctypes = mtd.sig.match(sigRegex()).map(s => sig2ctype(s));
    var returnSig = mtd.sig.substring(mtd.sig.indexOf(')')+1);
    var ty = sig2type(returnSig), nm = returnSig;
    var call = "CallStatic"+ty+"Method";
    ensureLoaded(jenv, nm);
    r[mtd.name] = rpp[mtd.name] = overloadFunc(mtd.name);
    r[mtd.name + mtd.sig] = r[mtd.name+'('+(argctypes.length-1)+')'] =
    // add static methods to object instances, too.
    rpp[mtd.name + mtd.sig] = rpp[mtd.name+'('+(argctypes.length-1)+')'] = function() {
      var i, j = jenvpp();
      var args = [jenv, jcls, jmtd];
      for (i=0; i<arguments.length; i++) {
        args.push(unwrap(arguments[i], jenv, argctypes[i]));
      }
      return wrap(j[call].apply(j, args), nm);
    };
  });
  (props.constructors || []).forEach(function(mtd) {
    mtd.name = "<init>";
    var jmtd = jenvpp().GetMethodID(jenv, jcls, mtd.name, mtd.sig);
    var argctypes = mtd.sig.match(sigRegex()).map(s => sig2ctype(s));
    var returnSig = mtd.sig.substring(mtd.sig.indexOf(')')+1);

    r['new'] = overloadFunc('new');
    r['new'+mtd.sig] = r['new('+(argctypes.length-1)+')'] = function() {
      var i, j = jenvpp();
      var args = [jenv, jcls, jmtd];
      for (i=0; i<arguments.length; i++) {
        args.push(unwrap(arguments[i], jenv, argctypes[i]));
      }
      return wrap(j.NewObject.apply(j, args), classSig);
    };
  });
  (props.fields || []).forEach(function(fld) {
    var jfld = jenvpp().GetFieldID(jenv, jcls, fld.name, fld.sig);
    var ty = sig2type(fld.sig), nm = fld.sig;
    var getter = "Get"+ty+"Field", setter = "Set"+ty+"Field";
    ensureLoaded(jenv, nm);
    Object.defineProperty(rpp, fld.name, {
      get: function() {
        var j = jenvpp();
        return wrap(j[getter].call(j, jenv, unwrap(this), jfld), nm);
      },
      set: function(newValue) {
        var j = jenvpp();
        j[setter].call(j, jenv, unwrap(this), jfld, unwrap(newValue));
      }
    });
  });
  (props.methods || []).forEach(function(mtd) {
    var jmtd = jenvpp().GetMethodID(jenv, jcls, mtd.name, mtd.sig);
    var argctypes = mtd.sig.match(sigRegex()).map(s => sig2ctype(s));
    var returnSig = mtd.sig.substring(mtd.sig.indexOf(')')+1);
    var ty = sig2type(returnSig), nm = returnSig;
    var call = "Call"+ty+"Method";
    ensureLoaded(jenv, nm);
    rpp[mtd.name] = overloadFunc(mtd.name);
    rpp[mtd.name + mtd.sig] = rpp[mtd.name+'('+(argctypes.length-1)+')'] = function() {
      var i, j = jenvpp();
      var args = [jenv, unwrap(this), jmtd];
      for (i=0; i<arguments.length; i++) {
        args.push(unwrap(arguments[i], jenv, argctypes[i]));
      }
      return wrap(j[call].apply(j, args), nm);
    };
  });
  jenvpp().PopLocalFrame(jenv, null);
  return r;
}

// exported object
var JNI = {
  // primitive types
  jboolean: jboolean,
  jbyte: jbyte,
  jchar: jchar,
  jshort: jshort,
  jint: jint,
  jlong: jlong,
  jfloat: jfloat,
  jdouble: jdouble,
  jsize: jsize,

  // class registry
  classes: classes,

  // methods
  GetForThread: GetJNIForThread,
  NewString: JNINewString,
  ReadString: JNIReadString,
  LoadClass: function(jenv, classname_or_signature, props) {
    return JNILoadClass(jenv, ensureSig(classname_or_signature), props);
  },
  UnloadClasses: JNIUnloadClasses
};
back to top