mobile/android/modules/JNI.jsm

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:6d413752817d
1 /* Very basic JNI support for JS
2 *
3 * Example Usage:
4 * let jni = new JNI();
5 * cls = jni.findClass("org/mozilla/gecko/GeckoAppShell");
6 * method = jni.getStaticMethodID(cls, "getPreferredIconSize", "(I)I");
7 *
8 * let val = jni.callStaticIntMethod(cls, method, 3);
9 * // close the jni library when you are done
10 * jni.close();
11 *
12 * Note: the getters in this file are deleted and replaced with static
13 * values once computed, as in, for example
14 * http://code.activestate.com/recipes/577310-using-a-getter-for-a-one-time-calculation-of-a-jav/
15 */
16 this.EXPORTED_SYMBOLS = ["JNI"];
17
18 Components.utils.import("resource://gre/modules/ctypes.jsm")
19 Components.utils.import("resource://gre/modules/Services.jsm")
20
21 this.JNI = function JNI() { }
22
23 JNI.prototype = {
24 get lib() {
25 delete this.lib;
26 return this.lib = ctypes.open("libxul.so");
27 },
28
29 getType: function(aType) {
30 switch(aType) {
31 case "B": return ctypes.char;
32 case "C": return ctypes.char;
33 case "D": return ctypes.double;
34 case "F": return ctypes.float;
35 case "I": return ctypes.int32_t;
36 case "J": return ctypes.int64_t;
37 case "S": return ctypes.int16_t;
38 case "V": return ctypes.void_t;
39 case "Z": return ctypes.bool;
40 default: return this.types.jobject
41 }
42 },
43
44 getArgs: function(aMethod, aArgs) {
45 if (aArgs.length != aMethod.parameters.length)
46 throw ("Incorrect number of arguments passed to " + aMethod.name);
47
48 // Convert arguments to an array of jvalue objects
49 let modifiedArgs = new ctypes.ArrayType(this.types.jvalue, aMethod.parameters.length)();
50 for (let i = 0; i < aMethod.parameters.length; i++) {
51 let parameter = aMethod.parameters[i];
52 let arg = new this.types.jvalue();
53
54 if (aArgs[i] instanceof Array || parameter[0] == "[")
55 throw "No support for array arguments yet";
56 else
57 ctypes.cast(arg, this.getType(parameter)).value = aArgs[i];
58
59 modifiedArgs[i] = arg;
60 }
61
62 return modifiedArgs;
63 },
64
65 types: {
66 jobject: ctypes.StructType("_jobject").ptr,
67 jclass: ctypes.StructType("_jobject").ptr,
68 jmethodID: ctypes.StructType("jmethodID").ptr,
69 jvalue: ctypes.double
70 },
71
72 get _findClass() {
73 delete this._findClass;
74 return this._findClass = this.lib.declare("jsjni_FindClass",
75 ctypes.default_abi,
76 this.types.jclass,
77 ctypes.char.ptr);
78 },
79
80 findClass: function(name) {
81 let ret = this._findClass(name);
82 if (this.exceptionCheck())
83 throw("Can't find class " + name);
84 return ret;
85 },
86
87 get _getStaticMethodID() {
88 delete this._getStaticMethodID;
89 return this._getStaticMethodID = this.lib.declare("jsjni_GetStaticMethodID",
90 ctypes.default_abi,
91 this.types.jmethodID,
92 this.types.jclass, // class
93 ctypes.char.ptr, // method name
94 ctypes.char.ptr); // signature
95 },
96
97 getStaticMethodID: function(aClass, aName, aSignature) {
98 let ret = this._getStaticMethodID(aClass, aName, aSignature);
99 if (this.exceptionCheck())
100 throw("Can't find method " + aName);
101 return new jMethod(aName, ret, aSignature);
102 },
103
104 get _exceptionCheck() {
105 delete this._exceptionCheck;
106 return this._exceptionCheck = this.lib.declare("jsjni_ExceptionCheck",
107 ctypes.default_abi,
108 ctypes.bool);
109 },
110
111 exceptionCheck: function() {
112 return this._exceptionCheck();
113 },
114
115 get _callStaticVoidMethod() {
116 delete this._callStaticVoidMethod;
117 return this._callStaticVoidMethod = this.lib.declare("jsjni_CallStaticVoidMethodA",
118 ctypes.default_abi,
119 ctypes.void_t,
120 this.types.jclass,
121 this.types.jmethodID,
122 this.types.jvalue.ptr);
123 },
124
125 callStaticVoidMethod: function(aClass, aMethod) {
126 let args = Array.prototype.slice.apply(arguments, [2]);
127 this._callStaticVoidMethod(aClass, aMethod.methodId, this.getArgs(aMethod, args));
128 if (this.exceptionCheck())
129 throw("Error calling static void method");
130 },
131
132 get _callStaticIntMethod() {
133 delete this._callStaticIntMethod;
134 return this._callStaticIntMethod = this.lib.declare("jsjni_CallStaticIntMethodA",
135 ctypes.default_abi,
136 ctypes.int,
137 this.types.jclass,
138 this.types.jmethodID,
139 this.types.jvalue.ptr);
140 },
141
142 callStaticIntMethod: function(aClass, aMethod) {
143 let args = Array.prototype.slice.apply(arguments, [2]);
144 let ret = this._callStaticIntMethod(aClass, aMethod.methodId, this.getArgs(aMethod, args));
145 if (this.exceptionCheck())
146 throw("Error calling static int method");
147 return ret;
148 },
149
150 close: function() {
151 this.lib.close();
152 },
153 }
154
155 function jMethod(name, jMethodId, signature) {
156 this.name = name;
157 this.methodId = jMethodId;
158 this.signature = signature;
159 }
160
161 jMethod.prototype = {
162 parameters: [],
163 returnType: null,
164 _signature: "",
165
166 // this just splits up the return value from the parameters
167 signatureRegExp: /^\(([^\)]*)\)(.*)$/,
168
169 // This splits up the actual parameters
170 parameterRegExp: /(\[*)(B|C|D|F|I|J|S|V|Z|L[^;]*;)/y,
171
172 parseSignature: function(aSignature) {
173 let [, parameters, returnType] = this.signatureRegExp.exec(aSignature);
174
175 // parse the parameters that should be passed to this method
176 if (parameters) {
177 let parameter = this.parameterRegExp.exec(parameters);
178 while (parameter) {
179 this.parameters.push(parameter[0]);
180 parameter = this.parameterRegExp.exec(parameters);
181 }
182 } else {
183 this.parameters = [];
184 }
185
186 // parse the return type
187 this.returnType = returnType;
188 },
189
190 _signature: "",
191 get signature() { return this._signature; },
192 set signature(val) {
193 this.parameters = [];
194 this.returnType = null;
195 this.parseSignature(val);
196 }
197 }

mercurial