blob: ef0dbd06470914816649fae3c5f7ac56d8f76938 [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001import java.io.PrintStream;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08002import java.util.ArrayList;
3import java.util.HashSet;
4import java.util.Iterator;
5import java.util.List;
6
Jack Palevichffac1ef2009-04-14 19:00:09 -07007public class JniCodeEmitter {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08008
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08009 static final boolean mUseCPlusPlus = true;
Jack Palevichffac1ef2009-04-14 19:00:09 -070010 protected boolean mUseContextPointer = true;
Jack Palevich427f5852009-04-15 19:13:17 -070011 protected boolean mUseStaticMethods = false;
Jack Palevichffac1ef2009-04-14 19:00:09 -070012 protected String mClassPathName;
13 protected ParameterChecker mChecker;
14 protected List<String> nativeRegistrations = new ArrayList<String>();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080015 boolean needsExit;
Jack Palevichffac1ef2009-04-14 19:00:09 -070016 protected static String indent = " ";
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080017 HashSet<String> mFunctionsEmitted = new HashSet<String>();
18
Jack Palevichffac1ef2009-04-14 19:00:09 -070019 public static String getJniName(JType jType) {
20 String jniName = "";
21 if (jType.isClass()) {
22 return "L" + jType.getBaseType() + ";";
23 } else if (jType.isArray()) {
24 jniName = "[";
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080025 }
Jack Palevichffac1ef2009-04-14 19:00:09 -070026
27 String baseType = jType.getBaseType();
28 if (baseType.equals("int")) {
29 jniName += "I";
30 } else if (baseType.equals("float")) {
31 jniName += "F";
32 } else if (baseType.equals("boolean")) {
33 jniName += "Z";
34 } else if (baseType.equals("short")) {
35 jniName += "S";
36 } else if (baseType.equals("long")) {
37 jniName += "L";
38 } else if (baseType.equals("byte")) {
39 jniName += "B";
40 }
41 return jniName;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080042 }
43
Jack Palevichffac1ef2009-04-14 19:00:09 -070044
45 public void emitCode(CFunc cfunc, String original,
46 PrintStream javaInterfaceStream,
47 PrintStream javaImplStream,
48 PrintStream cStream) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080049 JFunc jfunc;
50 String signature;
51 boolean duplicate;
Jack Palevich6cbca502009-04-13 16:22:25 -070052
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080053 if (cfunc.hasTypedPointerArg()) {
54 jfunc = JFunc.convert(cfunc, true);
55
56 // Don't emit duplicate functions
57 // These may appear because they are defined in multiple
58 // Java interfaces (e.g., GL11/GL11ExtensionPack)
59 signature = jfunc.toString();
60 duplicate = false;
61 if (mFunctionsEmitted.contains(signature)) {
62 duplicate = true;
63 } else {
64 mFunctionsEmitted.add(signature);
65 }
66
67 if (!duplicate) {
Jack Palevichffac1ef2009-04-14 19:00:09 -070068 emitNativeDeclaration(jfunc, javaImplStream);
69 emitJavaCode(jfunc, javaImplStream);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080070 }
Jack Palevich427f5852009-04-15 19:13:17 -070071 if (javaInterfaceStream != null) {
72 emitJavaInterfaceCode(jfunc, javaInterfaceStream);
73 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080074 if (!duplicate) {
Jack Palevichffac1ef2009-04-14 19:00:09 -070075 emitJniCode(jfunc, cStream);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080076 }
77 }
78
79 jfunc = JFunc.convert(cfunc, false);
80
81 signature = jfunc.toString();
82 duplicate = false;
83 if (mFunctionsEmitted.contains(signature)) {
84 duplicate = true;
85 } else {
86 mFunctionsEmitted.add(signature);
87 }
88
89 if (!duplicate) {
Jack Palevichffac1ef2009-04-14 19:00:09 -070090 emitNativeDeclaration(jfunc, javaImplStream);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080091 }
Jack Palevich427f5852009-04-15 19:13:17 -070092 if (javaInterfaceStream != null) {
93 emitJavaInterfaceCode(jfunc, javaInterfaceStream);
94 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080095 if (!duplicate) {
Jack Palevichffac1ef2009-04-14 19:00:09 -070096 emitJavaCode(jfunc, javaImplStream);
97 emitJniCode(jfunc, cStream);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080098 }
99 }
100
101 public void emitNativeDeclaration(JFunc jfunc, PrintStream out) {
102 out.println(" // C function " + jfunc.getCFunc().getOriginal());
103 out.println();
104
105 emitFunction(jfunc, out, true, false);
106 }
107
108 public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) {
109 emitFunction(jfunc, out, false, true);
110 }
111
112 public void emitJavaCode(JFunc jfunc, PrintStream out) {
113 emitFunction(jfunc, out, false, false);
114 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700115
Jack Palevichffac1ef2009-04-14 19:00:09 -0700116 void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800117 boolean isVoid = jfunc.getType().isVoid();
118 boolean isPointerFunc = jfunc.getName().endsWith("Pointer") &&
119 jfunc.getCFunc().hasPointerArg();
120
121 if (!isVoid) {
122 out.println(iii +
123 jfunc.getType() + " _returnValue;");
124 }
125 out.println(iii +
126 (isVoid ? "" : "_returnValue = ") +
127 jfunc.getName() +
128 (isPointerFunc ? "Bounds" : "" ) +
129 "(");
Jack Palevich6cbca502009-04-13 16:22:25 -0700130
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800131 int numArgs = jfunc.getNumArgs();
132 for (int i = 0; i < numArgs; i++) {
133 String argName = jfunc.getArgName(i);
134 JType argType = jfunc.getArgType(i);
135
136 if (grabArray && argType.isTypedBuffer()) {
137 String typeName = argType.getBaseType();
138 typeName = typeName.substring(9, typeName.length() - 6);
139 out.println(iii + indent + "get" + typeName + "Array(" + argName + "),");
Jack Palevich6cbca502009-04-13 16:22:25 -0700140 out.print(iii + indent + "getOffset(" + argName + ")");
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800141 } else {
142 out.print(iii + indent + argName);
143 }
144 if (i == numArgs - 1) {
145 if (isPointerFunc) {
146 out.println(",");
147 out.println(iii + indent + argName + ".remaining()");
148 } else {
149 out.println();
150 }
151 } else {
152 out.println(",");
153 }
154 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700155
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800156 out.println(iii + ");");
157 }
158
Jack Palevichffac1ef2009-04-14 19:00:09 -0700159 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
160 String iii) {
161 printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
162 "offset", "_remaining", iii);
163 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800164
Jack Palevichffac1ef2009-04-14 19:00:09 -0700165 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
166 String offset, String remaining, String iii) {
167 out.println(iii + " default:");
168 out.println(iii + " _needed = 0;");
169 out.println(iii + " break;");
170 out.println(iii + "}");
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800171
Jack Palevichffac1ef2009-04-14 19:00:09 -0700172 out.println(iii + "if (" + remaining + " < _needed) {");
173 if (emitExceptionCheck) {
174 out.println(iii + indent + "_exception = 1;");
175 }
176 out.println(iii + indent +
177 (mUseCPlusPlus ? "_env" : "(*_env)") +
178 "->ThrowNew(" +
179 (mUseCPlusPlus ? "" : "_env, ") +
180 "IAEClass, " +
181 "\"" +
182 (isBuffer ?
183 "remaining()" : "length - " + offset) +
184 " < needed\");");
185 out.println(iii + indent + "goto exit;");
186 needsExit = true;
187 out.println(iii + "}");
188 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800189
190 boolean isNullAllowed(CFunc cfunc) {
191 String[] checks = mChecker.getChecks(cfunc.getName());
192 int index = 1;
193 if (checks != null) {
194 while (index < checks.length) {
195 if (checks[index].equals("return")) {
196 index += 2;
197 } else if (checks[index].startsWith("check")) {
198 index += 3;
199 } else if (checks[index].equals("ifcheck")) {
200 index += 5;
201 } else if (checks[index].equals("unsupported")) {
202 index += 1;
203 } else if (checks[index].equals("nullAllowed")) {
204 return true;
205 } else {
206 System.out.println("Error: unknown keyword \"" +
207 checks[index] + "\"");
208 System.exit(0);
209 }
210 }
211 }
212 return false;
213 }
214
215 String getErrorReturnValue(CFunc cfunc) {
216 CType returnType = cfunc.getType();
217 boolean isVoid = returnType.isVoid();
218 if (isVoid) {
219 return null;
220 }
221
222 String[] checks = mChecker.getChecks(cfunc.getName());
223
224 int index = 1;
225 if (checks != null) {
226 while (index < checks.length) {
227 if (checks[index].equals("return")) {
228 return checks[index + 1];
229 } else if (checks[index].startsWith("check")) {
230 index += 3;
231 } else if (checks[index].equals("ifcheck")) {
232 index += 5;
233 } else if (checks[index].equals("unsupported")) {
234 index += 1;
235 } else if (checks[index].equals("nullAllowed")) {
236 index += 1;
237 } else {
238 System.out.println("Error: unknown keyword \"" +
239 checks[index] + "\"");
240 System.exit(0);
241 }
242 }
243 }
244
245 return null;
246 }
247
248 boolean isUnsupportedFunc(CFunc cfunc) {
249 String[] checks = mChecker.getChecks(cfunc.getName());
250 int index = 1;
251 if (checks != null) {
252 while (index < checks.length) {
253 if (checks[index].equals("unsupported")) {
254 return true;
255 } else if (checks[index].equals("return")) {
256 index += 2;
257 } else if (checks[index].startsWith("check")) {
258 index += 3;
259 } else if (checks[index].equals("ifcheck")) {
260 index += 5;
261 } else if (checks[index].equals("nullAllowed")) {
262 index += 1;
263 } else {
264 System.out.println("Error: unknown keyword \"" +
265 checks[index] + "\"");
266 System.exit(0);
267 }
268 }
269 }
270 return false;
271 }
272
273 void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
Jack Palevichffac1ef2009-04-14 19:00:09 -0700274 boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800275
Jack Palevichffac1ef2009-04-14 19:00:09 -0700276 String[] checks = mChecker.getChecks(cfunc.getName());
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800277
Jack Palevichffac1ef2009-04-14 19:00:09 -0700278 boolean lastWasIfcheck = false;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800279
Jack Palevichffac1ef2009-04-14 19:00:09 -0700280 int index = 1;
281 if (checks != null) {
282 while (index < checks.length) {
283 if (checks[index].startsWith("check")) {
284 if (lastWasIfcheck) {
285 printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
286 offset, remaining, iii);
287 }
288 lastWasIfcheck = false;
289 if (cname != null && !cname.equals(checks[index + 1])) {
290 index += 3;
291 continue;
292 }
293 out.println(iii + "if (" + remaining + " < " +
294 checks[index + 2] +
295 ") {");
296 if (emitExceptionCheck) {
297 out.println(iii + indent + "_exception = 1;");
298 }
299 String exceptionClassName = "IAEClass";
300 // If the "check" keyword was of the form
301 // "check_<class name>", use the class name in the
302 // exception to be thrown
303 int underscore = checks[index].indexOf('_');
304 if (underscore >= 0) {
305 exceptionClassName = checks[index].substring(underscore + 1) + "Class";
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800306 }
Jack Palevichffac1ef2009-04-14 19:00:09 -0700307 out.println(iii + indent +
308 (mUseCPlusPlus ? "_env" : "(*_env)") +
309 "->ThrowNew(" +
310 (mUseCPlusPlus ? "" : "_env, ") +
311 exceptionClassName + ", " +
312 "\"" +
313 (isBuffer ?
314 "remaining()" : "length - " + offset) +
315 " < " + checks[index + 2] +
316 "\");");
317
318 out.println(iii + indent + "goto exit;");
319 needsExit = true;
320 out.println(iii + "}");
321
322 index += 3;
323 } else if (checks[index].equals("ifcheck")) {
324 String[] matches = checks[index + 4].split(",");
325
326 if (!lastWasIfcheck) {
327 out.println(iii + "int _needed;");
328 out.println(iii +
329 "switch (" +
330 checks[index + 3] +
331 ") {");
332 }
333
334 for (int i = 0; i < matches.length; i++) {
335 out.println("#if defined(" + matches[i] + ")");
336 out.println(iii +
337 " case " +
338 matches[i] +
339 ":");
340 out.println("#endif // defined(" + matches[i] + ")");
341 }
342 out.println(iii +
343 " _needed = " +
344 checks[index + 2] +
345 ";");
346 out.println(iii +
347 " break;");
348
349 lastWasIfcheck = true;
350 index += 5;
351 } else if (checks[index].equals("return")) {
352 // ignore
353 index += 2;
354 } else if (checks[index].equals("unsupported")) {
355 // ignore
356 index += 1;
357 } else if (checks[index].equals("nullAllowed")) {
358 // ignore
359 index += 1;
360 } else {
361 System.out.println("Error: unknown keyword \"" +
362 checks[index] + "\"");
363 System.exit(0);
364 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800365 }
Jack Palevichffac1ef2009-04-14 19:00:09 -0700366 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800367
Jack Palevichffac1ef2009-04-14 19:00:09 -0700368 if (lastWasIfcheck) {
369 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800370 }
371 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800372
Jack Palevichffac1ef2009-04-14 19:00:09 -0700373 boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800374 if (nonPrimitiveArgs.size() > 0) {
375 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
376 int idx = nonPrimitiveArgs.get(i).intValue();
377 int cIndex = jfunc.getArgCIndex(idx);
378 if (jfunc.getArgType(idx).isArray()) {
379 if (!cfunc.getArgType(cIndex).isConst()) {
380 return true;
381 }
382 } else if (jfunc.getArgType(idx).isBuffer()) {
383 if (!cfunc.getArgType(cIndex).isConst()) {
384 return true;
385 }
386 }
387 }
388 }
389
390 return false;
391 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700392
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800393 /**
394 * Emit a function in several variants:
395 *
396 * if nativeDecl: public native <returntype> func(args);
397 *
398 * if !nativeDecl:
399 * if interfaceDecl: public <returntype> func(args);
400 * if !interfaceDecl: public <returntype> func(args) { body }
401 */
Jack Palevichffac1ef2009-04-14 19:00:09 -0700402 void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800403 boolean isPointerFunc =
404 jfunc.getName().endsWith("Pointer") &&
405 jfunc.getCFunc().hasPointerArg();
406
407 if (!nativeDecl && !interfaceDecl && !isPointerFunc) {
408 // If it's not a pointer function, we've already emitted it
409 // with nativeDecl == true
410 return;
411 }
412
Jack Palevich427f5852009-04-15 19:13:17 -0700413 String maybeStatic = mUseStaticMethods ? "static " : "";
414
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800415 if (isPointerFunc) {
416 out.println(indent +
Jack Palevich427f5852009-04-15 19:13:17 -0700417 (nativeDecl ? "private " + maybeStatic +"native " :
418 (interfaceDecl ? "" : "public ") + maybeStatic) +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800419 jfunc.getType() + " " +
420 jfunc.getName() +
421 (nativeDecl ? "Bounds" : "") +
422 "(");
423 } else {
424 out.println(indent +
Jack Palevich427f5852009-04-15 19:13:17 -0700425 (nativeDecl ? "public " + maybeStatic +"native " :
426 (interfaceDecl ? "" : "public ") + maybeStatic) +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800427 jfunc.getType() + " " +
428 jfunc.getName() +
429 "(");
430 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700431
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800432 int numArgs = jfunc.getNumArgs();
433 for (int i = 0; i < numArgs; i++) {
434 String argName = jfunc.getArgName(i);
435 JType argType = jfunc.getArgType(i);
Jack Palevich6cbca502009-04-13 16:22:25 -0700436
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800437 out.print(indent + indent + argType + " " + argName);
438 if (i == numArgs - 1) {
439 if (isPointerFunc && nativeDecl) {
440 out.println(",");
441 out.println(indent + indent + "int remaining");
442 } else {
443 out.println();
444 }
445 } else {
446 out.println(",");
447 }
448 }
449
450 if (nativeDecl || interfaceDecl) {
451 out.println(indent + ");");
452 } else {
453 out.println(indent + ") {");
454
455 String iii = indent + indent;
456
457 String fname = jfunc.getName();
458 if (isPointerFunc) {
459 // TODO - deal with VBO variants
460 if (fname.equals("glColorPointer")) {
461 out.println(iii + "if ((size == 4) &&");
462 out.println(iii + " ((type == GL_FLOAT) ||");
463 out.println(iii + " (type == GL_UNSIGNED_BYTE) ||");
464 out.println(iii + " (type == GL_FIXED)) &&");
465 out.println(iii + " (stride >= 0)) {");
466 out.println(iii + indent + "_colorPointer = pointer;");
467 out.println(iii + "}");
468 } else if (fname.equals("glNormalPointer")) {
469 out.println(iii + "if (((type == GL_FLOAT) ||");
470 out.println(iii + " (type == GL_BYTE) ||");
471 out.println(iii + " (type == GL_SHORT) ||");
472 out.println(iii + " (type == GL_FIXED)) &&");
473 out.println(iii + " (stride >= 0)) {");
474 out.println(iii + indent + "_normalPointer = pointer;");
475 out.println(iii + "}");
476 } else if (fname.equals("glTexCoordPointer")) {
477 out.println(iii + "if (((size == 2) ||");
478 out.println(iii + " (size == 3) ||");
479 out.println(iii + " (size == 4)) &&");
480 out.println(iii + " ((type == GL_FLOAT) ||");
481 out.println(iii + " (type == GL_BYTE) ||");
482 out.println(iii + " (type == GL_SHORT) ||");
483 out.println(iii + " (type == GL_FIXED)) &&");
484 out.println(iii + " (stride >= 0)) {");
485 out.println(iii + indent + "_texCoordPointer = pointer;");
486 out.println(iii + "}");
487 } else if (fname.equals("glVertexPointer")) {
488 out.println(iii + "if (((size == 2) ||");
489 out.println(iii + " (size == 3) ||");
490 out.println(iii + " (size == 4)) &&");
491 out.println(iii + " ((type == GL_FLOAT) ||");
492 out.println(iii + " (type == GL_BYTE) ||");
493 out.println(iii + " (type == GL_SHORT) ||");
494 out.println(iii + " (type == GL_FIXED)) &&");
495 out.println(iii + " (stride >= 0)) {");
496 out.println(iii + indent + "_vertexPointer = pointer;");
497 out.println(iii + "}");
498 }
499 }
500
501 // emitBoundsChecks(jfunc, out, iii);
502 emitFunctionCall(jfunc, out, iii, false);
503
504 boolean isVoid = jfunc.getType().isVoid();
505
506 if (!isVoid) {
507 out.println(indent + indent + "return _returnValue;");
508 }
509 out.println(indent + "}");
510 }
511 out.println();
512 }
513
Jack Palevichffac1ef2009-04-14 19:00:09 -0700514 public void addNativeRegistration(String s) {
515 nativeRegistrations.add(s);
516 }
517
Jack Palevich427f5852009-04-15 19:13:17 -0700518 public void emitNativeRegistration(String registrationFunctionName,
519 PrintStream cStream) {
Jack Palevichffac1ef2009-04-14 19:00:09 -0700520 cStream.println("static const char *classPathName = \"" +
521 mClassPathName +
522 "\";");
523 cStream.println();
524
525 cStream.println("static JNINativeMethod methods[] = {");
526
527 cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },");
528
529 Iterator<String> i = nativeRegistrations.iterator();
530 while (i.hasNext()) {
531 cStream.println(i.next());
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800532 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700533
Jack Palevichffac1ef2009-04-14 19:00:09 -0700534 cStream.println("};");
535 cStream.println();
536
537
Jack Palevich427f5852009-04-15 19:13:17 -0700538 cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)");
Jack Palevichffac1ef2009-04-14 19:00:09 -0700539 cStream.println("{");
540 cStream.println(indent +
541 "int err;");
542
543 cStream.println(indent +
544 "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));");
545
546 cStream.println(indent + "return err;");
547 cStream.println("}");
548 }
549
550 public JniCodeEmitter() {
551 super();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800552 }
553
554 String getJniType(JType jType) {
555 if (jType.isVoid()) {
556 return "void";
557 }
558
559 String baseType = jType.getBaseType();
560 if (jType.isPrimitive()) {
561 if (baseType.equals("String")) {
562 return "jstring";
563 } else {
564 return "j" + baseType;
565 }
566 } else if (jType.isArray()) {
567 return "j" + baseType + "Array";
568 } else {
569 return "jobject";
570 }
571 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700572
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800573 String getJniMangledName(String name) {
574 name = name.replaceAll("_", "_1");
575 name = name.replaceAll(";", "_2");
576 name = name.replaceAll("\\[", "_3");
577 return name;
578 }
579
580 public void emitJniCode(JFunc jfunc, PrintStream out) {
581 CFunc cfunc = jfunc.getCFunc();
Jack Palevich6cbca502009-04-13 16:22:25 -0700582
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800583 // Emit comment identifying original C function
584 //
585 // Example:
586 //
587 // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
588 //
589 out.println("/* " + cfunc.getOriginal() + " */");
590
591 // Emit JNI signature (name)
592 //
593 // Example:
594 //
595 // void
596 // android_glClipPlanef__I_3FI
597 //
598
599 String outName = "android_" + jfunc.getName();
600 boolean isPointerFunc = outName.endsWith("Pointer") &&
601 jfunc.getCFunc().hasPointerArg();
602 boolean isVBOPointerFunc = (outName.endsWith("Pointer") ||
603 outName.endsWith("DrawElements")) &&
604 !jfunc.getCFunc().hasPointerArg();
605 if (isPointerFunc) {
606 outName += "Bounds";
607 }
608
609 out.print("static ");
610 out.println(getJniType(jfunc.getType()));
611 out.print(outName);
612
613 String rsignature = getJniName(jfunc.getType());
614
615 String signature = "";
616 int numArgs = jfunc.getNumArgs();
617 for (int i = 0; i < numArgs; i++) {
618 JType argType = jfunc.getArgType(i);
619 signature += getJniName(argType);
620 }
621 if (isPointerFunc) {
622 signature += "I";
623 }
624
625 // Append signature to function name
Jack Palevich6cbca502009-04-13 16:22:25 -0700626 String sig = getJniMangledName(signature).replace('.', '_');
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800627 out.print("__" + sig);
628 outName += "__" + sig;
Jack Palevich6cbca502009-04-13 16:22:25 -0700629
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800630 signature = signature.replace('.', '/');
631 rsignature = rsignature.replace('.', '/');
Jack Palevich6cbca502009-04-13 16:22:25 -0700632
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800633 out.println();
634 if (rsignature.length() == 0) {
635 rsignature = "V";
636 }
637
638 String s = "{\"" +
639 jfunc.getName() +
640 (isPointerFunc ? "Bounds" : "") +
641 "\", \"(" + signature +")" +
642 rsignature +
643 "\", (void *) " +
644 outName +
645 " },";
646 nativeRegistrations.add(s);
647
648 List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
649 int numBufferArgs = 0;
650 List<String> bufferArgNames = new ArrayList<String>();
651
652 // Emit JNI signature (arguments)
653 //
654 // Example:
655 //
656 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) {
657 //
658 out.print(" (JNIEnv *_env, jobject _this");
659 for (int i = 0; i < numArgs; i++) {
660 out.print(", ");
661 JType argType = jfunc.getArgType(i);
662 String suffix;
663 if (!argType.isPrimitive()) {
664 if (argType.isArray()) {
665 suffix = "_ref";
666 } else {
667 suffix = "_buf";
668 }
669 nonPrimitiveArgs.add(new Integer(i));
670 if (jfunc.getArgType(i).isBuffer()) {
671 int cIndex = jfunc.getArgCIndex(i);
672 String cname = cfunc.getArgName(cIndex);
673 bufferArgNames.add(cname);
674 numBufferArgs++;
675 }
676 } else {
677 suffix = "";
678 }
679
680 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
681 }
682 if (isPointerFunc) {
683 out.print(", jint remaining");
684 }
685 out.println(") {");
Jack Palevich6cbca502009-04-13 16:22:25 -0700686
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800687 int numArrays = 0;
688 int numBuffers = 0;
689 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
690 int idx = nonPrimitiveArgs.get(i).intValue();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800691 if (jfunc.getArgType(idx).isArray()) {
692 ++numArrays;
693 }
694 if (jfunc.getArgType(idx).isBuffer()) {
695 ++numBuffers;
696 }
697 }
698
699 // Emit method body
700
701 // Emit local variable declarations for _exception and _returnValue
702 //
703 // Example:
704 //
705 // android::gl::ogles_context_t *ctx;
Jack Palevich6cbca502009-04-13 16:22:25 -0700706 //
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800707 // jint _exception;
708 // GLenum _returnValue;
709 //
710 CType returnType = cfunc.getType();
711 boolean isVoid = returnType.isVoid();
712
713 boolean isUnsupported = isUnsupportedFunc(cfunc);
714 if (isUnsupported) {
715 out.println(indent +
716 "_env->ThrowNew(UOEClass,");
717 out.println(indent +
718 " \"" + cfunc.getName() + "\");");
719 if (!isVoid) {
720 String retval = getErrorReturnValue(cfunc);
721 out.println(indent + "return " + retval + ";");
722 }
723 out.println("}");
724 out.println();
725 return;
726 }
727
728 if (mUseContextPointer) {
729 out.println(indent +
730 "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
731 }
732
733 boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) &&
734 hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs);
735 // mChecker.getChecks(cfunc.getName()) != null
736
737 // Emit an _exeption variable if there will be error checks
738 if (emitExceptionCheck) {
739 out.println(indent + "jint _exception = 0;");
740 }
741
742 // Emit a single _array or multiple _XXXArray variables
743 if (numBufferArgs == 1) {
744 out.println(indent + "jarray _array = (jarray) 0;");
745 } else {
746 for (int i = 0; i < numBufferArgs; i++) {
747 out.println(indent + "jarray _" + bufferArgNames.get(i) +
748 "Array = (jarray) 0;");
749 }
750 }
751 if (!isVoid) {
752 String retval = getErrorReturnValue(cfunc);
753 if (retval != null) {
754 out.println(indent + returnType.getDeclaration() +
755 " _returnValue = " + retval + ";");
756 } else {
757 out.println(indent + returnType.getDeclaration() +
758 " _returnValue;");
759 }
760 }
761
762 // Emit local variable declarations for pointer arguments
763 //
764 // Example:
765 //
766 // GLfixed *eqn_base;
767 // GLfixed *eqn;
768 //
769 String offset = "offset";
770 String remaining = "_remaining";
771 if (nonPrimitiveArgs.size() > 0) {
772 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
773 int idx = nonPrimitiveArgs.get(i).intValue();
774 int cIndex = jfunc.getArgCIndex(idx);
775 String cname = cfunc.getArgName(cIndex);
776
777 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
778 String decl = type.getDeclaration();
779 if (jfunc.getArgType(idx).isArray()) {
780 out.println(indent +
781 decl +
782 (decl.endsWith("*") ? "" : " ") +
783 jfunc.getArgName(idx) +
784 "_base = (" + decl + ") 0;");
785 }
786 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
787 "_" + cname + "Remaining";
788 out.println(indent +
789 "jint " + remaining + ";");
790 out.println(indent +
791 decl +
792 (decl.endsWith("*") ? "" : " ") +
Jack Palevich6cbca502009-04-13 16:22:25 -0700793 jfunc.getArgName(idx) +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800794 " = (" + decl + ") 0;");
795 }
796
797 out.println();
798 }
799
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800800 // Emit 'GetPrimitiveArrayCritical' for arrays
801 // Emit 'GetPointer' calls for Buffer pointers
802 int bufArgIdx = 0;
803 if (nonPrimitiveArgs.size() > 0) {
804 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
805 int idx = nonPrimitiveArgs.get(i).intValue();
806 int cIndex = jfunc.getArgCIndex(idx);
Jack Palevich6cbca502009-04-13 16:22:25 -0700807
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800808 String cname = cfunc.getArgName(cIndex);
809 offset = numArrays <= 1 ? "offset" :
810 cname + "Offset";
811 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
812 "_" + cname + "Remaining";
813
814 if (jfunc.getArgType(idx).isArray()) {
815 out.println(indent +
Jack Palevich6cbca502009-04-13 16:22:25 -0700816 "if (!" +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800817 cname +
818 "_ref) {");
819 if (emitExceptionCheck) {
820 out.println(indent + indent + "_exception = 1;");
821 }
822 out.println(indent + " " +
823 (mUseCPlusPlus ? "_env" : "(*_env)") +
824 "->ThrowNew(" +
825 (mUseCPlusPlus ? "" : "_env, ") +
826 "IAEClass, " +
827 "\"" + cname +
828 " == null\");");
829 out.println(indent + " goto exit;");
830 needsExit = true;
831 out.println(indent + "}");
832
833 out.println(indent + "if (" + offset + " < 0) {");
834 if (emitExceptionCheck) {
835 out.println(indent + indent + "_exception = 1;");
836 }
837 out.println(indent + " " +
838 (mUseCPlusPlus ? "_env" : "(*_env)") +
839 "->ThrowNew(" +
840 (mUseCPlusPlus ? "" : "_env, ") +
841 "IAEClass, " +
842 "\"" + offset + " < 0\");");
843 out.println(indent + " goto exit;");
844 needsExit = true;
845 out.println(indent + "}");
846
847 out.println(indent + remaining + " = " +
Jack Palevich6cbca502009-04-13 16:22:25 -0700848 (mUseCPlusPlus ? "_env" : "(*_env)") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800849 "->GetArrayLength(" +
850 (mUseCPlusPlus ? "" : "_env, ") +
851 cname + "_ref) - " + offset + ";");
852
853 emitNativeBoundsChecks(cfunc, cname, out, false,
854 emitExceptionCheck,
855 offset, remaining, " ");
856
857 out.println(indent +
858 cname +
859 "_base = (" +
860 cfunc.getArgType(cIndex).getDeclaration() +
861 ")");
862 out.println(indent + " " +
863 (mUseCPlusPlus ? "_env" : "(*_env)") +
864 "->GetPrimitiveArrayCritical(" +
Jack Palevich6cbca502009-04-13 16:22:25 -0700865 (mUseCPlusPlus ? "" : "_env, ") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800866 jfunc.getArgName(idx) +
867 "_ref, (jboolean *)0);");
868 out.println(indent +
869 cname + " = " + cname + "_base + " + offset +
870 ";");
871 out.println();
872 } else {
873 String array = numBufferArgs <= 1 ? "_array" :
874 "_" + bufferArgNames.get(bufArgIdx++) + "Array";
875
876 boolean nullAllowed = isNullAllowed(cfunc);
877 if (nullAllowed) {
878 out.println(indent + "if (" + cname + "_buf) {");
879 out.print(indent);
880 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700881
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800882 out.println(indent +
883 cname +
884 " = (" +
885 cfunc.getArgType(cIndex).getDeclaration() +
886 ")getPointer(_env, " +
887 cname +
888 "_buf, &" + array + ", &" + remaining + ");");
889
890 if (nullAllowed) {
891 out.println(indent + "}");
892 }
893
894 emitNativeBoundsChecks(cfunc, cname, out, true,
895 emitExceptionCheck,
896 offset, remaining, " ");
897 }
898 }
899 }
900
901 if (!isVoid) {
902 out.print(indent + "_returnValue = ");
903 } else {
904 out.print(indent);
905 }
906 String name = cfunc.getName();
907
908 if (mUseContextPointer) {
909 name = name.substring(2, name.length()); // Strip off 'gl' prefix
910 name = name.substring(0, 1).toLowerCase() +
911 name.substring(1, name.length());
912 out.print("ctx->procs.");
913 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700914
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800915 out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
916
Jack Palevich6cbca502009-04-13 16:22:25 -0700917 numArgs = cfunc.getNumArgs();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800918 if (numArgs == 0) {
919 if (mUseContextPointer) {
920 out.println("ctx);");
921 } else {
922 out.println(");");
923 }
924 } else {
925 if (mUseContextPointer) {
926 out.println("ctx,");
927 } else {
928 out.println();
929 }
930 for (int i = 0; i < numArgs; i++) {
931 String typecast;
932 if (i == numArgs - 1 && isVBOPointerFunc) {
933 typecast = "const GLvoid *";
934 } else {
935 typecast = cfunc.getArgType(i).getDeclaration();
936 }
937 out.print(indent + indent +
938 "(" +
939 typecast +
940 ")" +
941 cfunc.getArgName(i));
942
943 if (i == numArgs - 1) {
944 if (isPointerFunc) {
945 out.println(",");
946 out.println(indent + indent + "(GLsizei)remaining");
947 } else {
948 out.println();
949 }
950 } else {
951 out.println(",");
952 }
953 }
954 out.println(indent + ");");
955 }
956
957 if (needsExit) {
958 out.println();
959 out.println("exit:");
960 needsExit = false;
961 }
962
963 bufArgIdx = 0;
964 if (nonPrimitiveArgs.size() > 0) {
965 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
966 int idx = nonPrimitiveArgs.get(i).intValue();
967
968 int cIndex = jfunc.getArgCIndex(idx);
969 if (jfunc.getArgType(idx).isArray()) {
Jack Palevich6cbca502009-04-13 16:22:25 -0700970
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800971 // If the argument is 'const', GL will not write to it.
972 // In this case, we can use the 'JNI_ABORT' flag to avoid
973 // the need to write back to the Java array
974 out.println(indent +
975 "if (" + jfunc.getArgName(idx) + "_base) {");
976 out.println(indent + indent +
977 (mUseCPlusPlus ? "_env" : "(*_env)") +
978 "->ReleasePrimitiveArrayCritical(" +
Jack Palevich6cbca502009-04-13 16:22:25 -0700979 (mUseCPlusPlus ? "" : "_env, ") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800980 jfunc.getArgName(idx) + "_ref, " +
981 cfunc.getArgName(cIndex) +
982 "_base,");
983 out.println(indent + indent + indent +
984 (cfunc.getArgType(cIndex).isConst() ?
985 "JNI_ABORT" :
986 "_exception ? JNI_ABORT: 0") +
987 ");");
988 out.println(indent + "}");
989 } else if (jfunc.getArgType(idx).isBuffer()) {
990 String array = numBufferArgs <= 1 ? "_array" :
991 "_" + bufferArgNames.get(bufArgIdx++) + "Array";
992 out.println(indent + "if (" + array + ") {");
993 out.println(indent + indent +
994 "releasePointer(_env, " + array + ", " +
995 cfunc.getArgName(cIndex) +
996 ", " +
997 (cfunc.getArgType(cIndex).isConst() ?
998 "JNI_FALSE" : "_exception ? JNI_FALSE : JNI_TRUE") +
999 ");");
1000 out.println(indent + "}");
1001 }
1002 }
1003 }
1004
1005 if (!isVoid) {
1006 out.println(indent + "return _returnValue;");
1007 }
1008
1009 out.println("}");
1010 out.println();
1011 }
1012
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001013}