blob: b0997b15a1d6dec0228f8c99aa5fea10929727e5 [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
Jack Palevich46d25a32009-05-07 18:28:29 -0700457 // emitBoundsChecks(jfunc, out, iii);
458 emitFunctionCall(jfunc, out, iii, false);
459
460 // Set the pointer after we call the native code, so that if
461 // the native code throws an exception we don't modify the
462 // pointer. We assume that the native code is written so that
463 // if an exception is thrown, then the underlying glXXXPointer
464 // function will not have been called.
465
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800466 String fname = jfunc.getName();
467 if (isPointerFunc) {
468 // TODO - deal with VBO variants
469 if (fname.equals("glColorPointer")) {
470 out.println(iii + "if ((size == 4) &&");
471 out.println(iii + " ((type == GL_FLOAT) ||");
472 out.println(iii + " (type == GL_UNSIGNED_BYTE) ||");
473 out.println(iii + " (type == GL_FIXED)) &&");
474 out.println(iii + " (stride >= 0)) {");
475 out.println(iii + indent + "_colorPointer = pointer;");
476 out.println(iii + "}");
477 } else if (fname.equals("glNormalPointer")) {
478 out.println(iii + "if (((type == GL_FLOAT) ||");
479 out.println(iii + " (type == GL_BYTE) ||");
480 out.println(iii + " (type == GL_SHORT) ||");
481 out.println(iii + " (type == GL_FIXED)) &&");
482 out.println(iii + " (stride >= 0)) {");
483 out.println(iii + indent + "_normalPointer = pointer;");
484 out.println(iii + "}");
485 } else if (fname.equals("glTexCoordPointer")) {
486 out.println(iii + "if (((size == 2) ||");
487 out.println(iii + " (size == 3) ||");
488 out.println(iii + " (size == 4)) &&");
489 out.println(iii + " ((type == GL_FLOAT) ||");
490 out.println(iii + " (type == GL_BYTE) ||");
491 out.println(iii + " (type == GL_SHORT) ||");
492 out.println(iii + " (type == GL_FIXED)) &&");
493 out.println(iii + " (stride >= 0)) {");
494 out.println(iii + indent + "_texCoordPointer = pointer;");
495 out.println(iii + "}");
496 } else if (fname.equals("glVertexPointer")) {
497 out.println(iii + "if (((size == 2) ||");
498 out.println(iii + " (size == 3) ||");
499 out.println(iii + " (size == 4)) &&");
500 out.println(iii + " ((type == GL_FLOAT) ||");
501 out.println(iii + " (type == GL_BYTE) ||");
502 out.println(iii + " (type == GL_SHORT) ||");
503 out.println(iii + " (type == GL_FIXED)) &&");
504 out.println(iii + " (stride >= 0)) {");
505 out.println(iii + indent + "_vertexPointer = pointer;");
506 out.println(iii + "}");
507 }
508 }
509
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800510 boolean isVoid = jfunc.getType().isVoid();
511
512 if (!isVoid) {
513 out.println(indent + indent + "return _returnValue;");
514 }
515 out.println(indent + "}");
516 }
517 out.println();
518 }
519
Jack Palevichffac1ef2009-04-14 19:00:09 -0700520 public void addNativeRegistration(String s) {
521 nativeRegistrations.add(s);
522 }
523
Jack Palevich427f5852009-04-15 19:13:17 -0700524 public void emitNativeRegistration(String registrationFunctionName,
525 PrintStream cStream) {
Jack Palevichffac1ef2009-04-14 19:00:09 -0700526 cStream.println("static const char *classPathName = \"" +
527 mClassPathName +
528 "\";");
529 cStream.println();
530
531 cStream.println("static JNINativeMethod methods[] = {");
532
533 cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },");
534
535 Iterator<String> i = nativeRegistrations.iterator();
536 while (i.hasNext()) {
537 cStream.println(i.next());
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800538 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700539
Jack Palevichffac1ef2009-04-14 19:00:09 -0700540 cStream.println("};");
541 cStream.println();
542
543
Jack Palevich427f5852009-04-15 19:13:17 -0700544 cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)");
Jack Palevichffac1ef2009-04-14 19:00:09 -0700545 cStream.println("{");
546 cStream.println(indent +
547 "int err;");
548
549 cStream.println(indent +
550 "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));");
551
552 cStream.println(indent + "return err;");
553 cStream.println("}");
554 }
555
556 public JniCodeEmitter() {
557 super();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800558 }
559
560 String getJniType(JType jType) {
561 if (jType.isVoid()) {
562 return "void";
563 }
564
565 String baseType = jType.getBaseType();
566 if (jType.isPrimitive()) {
567 if (baseType.equals("String")) {
568 return "jstring";
569 } else {
570 return "j" + baseType;
571 }
572 } else if (jType.isArray()) {
573 return "j" + baseType + "Array";
574 } else {
575 return "jobject";
576 }
577 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700578
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800579 String getJniMangledName(String name) {
580 name = name.replaceAll("_", "_1");
581 name = name.replaceAll(";", "_2");
582 name = name.replaceAll("\\[", "_3");
583 return name;
584 }
585
586 public void emitJniCode(JFunc jfunc, PrintStream out) {
587 CFunc cfunc = jfunc.getCFunc();
Jack Palevich6cbca502009-04-13 16:22:25 -0700588
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800589 // Emit comment identifying original C function
590 //
591 // Example:
592 //
593 // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
594 //
595 out.println("/* " + cfunc.getOriginal() + " */");
596
597 // Emit JNI signature (name)
598 //
599 // Example:
600 //
601 // void
602 // android_glClipPlanef__I_3FI
603 //
604
605 String outName = "android_" + jfunc.getName();
606 boolean isPointerFunc = outName.endsWith("Pointer") &&
607 jfunc.getCFunc().hasPointerArg();
608 boolean isVBOPointerFunc = (outName.endsWith("Pointer") ||
609 outName.endsWith("DrawElements")) &&
610 !jfunc.getCFunc().hasPointerArg();
611 if (isPointerFunc) {
612 outName += "Bounds";
613 }
614
615 out.print("static ");
616 out.println(getJniType(jfunc.getType()));
617 out.print(outName);
618
619 String rsignature = getJniName(jfunc.getType());
620
621 String signature = "";
622 int numArgs = jfunc.getNumArgs();
623 for (int i = 0; i < numArgs; i++) {
624 JType argType = jfunc.getArgType(i);
625 signature += getJniName(argType);
626 }
627 if (isPointerFunc) {
628 signature += "I";
629 }
630
631 // Append signature to function name
Jack Palevich6cbca502009-04-13 16:22:25 -0700632 String sig = getJniMangledName(signature).replace('.', '_');
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800633 out.print("__" + sig);
634 outName += "__" + sig;
Jack Palevich6cbca502009-04-13 16:22:25 -0700635
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800636 signature = signature.replace('.', '/');
637 rsignature = rsignature.replace('.', '/');
Jack Palevich6cbca502009-04-13 16:22:25 -0700638
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800639 out.println();
640 if (rsignature.length() == 0) {
641 rsignature = "V";
642 }
643
644 String s = "{\"" +
645 jfunc.getName() +
646 (isPointerFunc ? "Bounds" : "") +
647 "\", \"(" + signature +")" +
648 rsignature +
649 "\", (void *) " +
650 outName +
651 " },";
652 nativeRegistrations.add(s);
653
654 List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
655 int numBufferArgs = 0;
656 List<String> bufferArgNames = new ArrayList<String>();
657
658 // Emit JNI signature (arguments)
659 //
660 // Example:
661 //
662 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) {
663 //
664 out.print(" (JNIEnv *_env, jobject _this");
665 for (int i = 0; i < numArgs; i++) {
666 out.print(", ");
667 JType argType = jfunc.getArgType(i);
668 String suffix;
669 if (!argType.isPrimitive()) {
670 if (argType.isArray()) {
671 suffix = "_ref";
672 } else {
673 suffix = "_buf";
674 }
675 nonPrimitiveArgs.add(new Integer(i));
676 if (jfunc.getArgType(i).isBuffer()) {
677 int cIndex = jfunc.getArgCIndex(i);
678 String cname = cfunc.getArgName(cIndex);
679 bufferArgNames.add(cname);
680 numBufferArgs++;
681 }
682 } else {
683 suffix = "";
684 }
685
686 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
687 }
688 if (isPointerFunc) {
689 out.print(", jint remaining");
690 }
691 out.println(") {");
Jack Palevich6cbca502009-04-13 16:22:25 -0700692
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800693 int numArrays = 0;
694 int numBuffers = 0;
695 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
696 int idx = nonPrimitiveArgs.get(i).intValue();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800697 if (jfunc.getArgType(idx).isArray()) {
698 ++numArrays;
699 }
700 if (jfunc.getArgType(idx).isBuffer()) {
701 ++numBuffers;
702 }
703 }
704
705 // Emit method body
706
707 // Emit local variable declarations for _exception and _returnValue
708 //
709 // Example:
710 //
711 // android::gl::ogles_context_t *ctx;
Jack Palevich6cbca502009-04-13 16:22:25 -0700712 //
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800713 // jint _exception;
714 // GLenum _returnValue;
715 //
716 CType returnType = cfunc.getType();
717 boolean isVoid = returnType.isVoid();
718
719 boolean isUnsupported = isUnsupportedFunc(cfunc);
720 if (isUnsupported) {
721 out.println(indent +
722 "_env->ThrowNew(UOEClass,");
723 out.println(indent +
724 " \"" + cfunc.getName() + "\");");
725 if (!isVoid) {
726 String retval = getErrorReturnValue(cfunc);
727 out.println(indent + "return " + retval + ";");
728 }
729 out.println("}");
730 out.println();
731 return;
732 }
733
734 if (mUseContextPointer) {
735 out.println(indent +
736 "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
737 }
738
739 boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) &&
740 hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs);
741 // mChecker.getChecks(cfunc.getName()) != null
742
743 // Emit an _exeption variable if there will be error checks
744 if (emitExceptionCheck) {
745 out.println(indent + "jint _exception = 0;");
746 }
747
748 // Emit a single _array or multiple _XXXArray variables
749 if (numBufferArgs == 1) {
750 out.println(indent + "jarray _array = (jarray) 0;");
751 } else {
752 for (int i = 0; i < numBufferArgs; i++) {
753 out.println(indent + "jarray _" + bufferArgNames.get(i) +
754 "Array = (jarray) 0;");
755 }
756 }
757 if (!isVoid) {
758 String retval = getErrorReturnValue(cfunc);
759 if (retval != null) {
760 out.println(indent + returnType.getDeclaration() +
761 " _returnValue = " + retval + ";");
762 } else {
763 out.println(indent + returnType.getDeclaration() +
764 " _returnValue;");
765 }
766 }
767
768 // Emit local variable declarations for pointer arguments
769 //
770 // Example:
771 //
772 // GLfixed *eqn_base;
773 // GLfixed *eqn;
774 //
775 String offset = "offset";
776 String remaining = "_remaining";
777 if (nonPrimitiveArgs.size() > 0) {
778 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
779 int idx = nonPrimitiveArgs.get(i).intValue();
780 int cIndex = jfunc.getArgCIndex(idx);
781 String cname = cfunc.getArgName(cIndex);
782
783 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
784 String decl = type.getDeclaration();
785 if (jfunc.getArgType(idx).isArray()) {
786 out.println(indent +
787 decl +
788 (decl.endsWith("*") ? "" : " ") +
789 jfunc.getArgName(idx) +
790 "_base = (" + decl + ") 0;");
791 }
792 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
793 "_" + cname + "Remaining";
794 out.println(indent +
795 "jint " + remaining + ";");
796 out.println(indent +
797 decl +
798 (decl.endsWith("*") ? "" : " ") +
Jack Palevich6cbca502009-04-13 16:22:25 -0700799 jfunc.getArgName(idx) +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800800 " = (" + decl + ") 0;");
801 }
802
803 out.println();
804 }
805
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800806 // Emit 'GetPrimitiveArrayCritical' for arrays
807 // Emit 'GetPointer' calls for Buffer pointers
808 int bufArgIdx = 0;
809 if (nonPrimitiveArgs.size() > 0) {
810 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
811 int idx = nonPrimitiveArgs.get(i).intValue();
812 int cIndex = jfunc.getArgCIndex(idx);
Jack Palevich6cbca502009-04-13 16:22:25 -0700813
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800814 String cname = cfunc.getArgName(cIndex);
815 offset = numArrays <= 1 ? "offset" :
816 cname + "Offset";
817 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
818 "_" + cname + "Remaining";
819
820 if (jfunc.getArgType(idx).isArray()) {
821 out.println(indent +
Jack Palevich6cbca502009-04-13 16:22:25 -0700822 "if (!" +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800823 cname +
824 "_ref) {");
825 if (emitExceptionCheck) {
826 out.println(indent + indent + "_exception = 1;");
827 }
828 out.println(indent + " " +
829 (mUseCPlusPlus ? "_env" : "(*_env)") +
830 "->ThrowNew(" +
831 (mUseCPlusPlus ? "" : "_env, ") +
832 "IAEClass, " +
833 "\"" + cname +
834 " == null\");");
835 out.println(indent + " goto exit;");
836 needsExit = true;
837 out.println(indent + "}");
838
839 out.println(indent + "if (" + offset + " < 0) {");
840 if (emitExceptionCheck) {
841 out.println(indent + indent + "_exception = 1;");
842 }
843 out.println(indent + " " +
844 (mUseCPlusPlus ? "_env" : "(*_env)") +
845 "->ThrowNew(" +
846 (mUseCPlusPlus ? "" : "_env, ") +
847 "IAEClass, " +
848 "\"" + offset + " < 0\");");
849 out.println(indent + " goto exit;");
850 needsExit = true;
851 out.println(indent + "}");
852
853 out.println(indent + remaining + " = " +
Jack Palevich6cbca502009-04-13 16:22:25 -0700854 (mUseCPlusPlus ? "_env" : "(*_env)") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800855 "->GetArrayLength(" +
856 (mUseCPlusPlus ? "" : "_env, ") +
857 cname + "_ref) - " + offset + ";");
858
859 emitNativeBoundsChecks(cfunc, cname, out, false,
860 emitExceptionCheck,
861 offset, remaining, " ");
862
863 out.println(indent +
864 cname +
865 "_base = (" +
866 cfunc.getArgType(cIndex).getDeclaration() +
867 ")");
868 out.println(indent + " " +
869 (mUseCPlusPlus ? "_env" : "(*_env)") +
870 "->GetPrimitiveArrayCritical(" +
Jack Palevich6cbca502009-04-13 16:22:25 -0700871 (mUseCPlusPlus ? "" : "_env, ") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800872 jfunc.getArgName(idx) +
873 "_ref, (jboolean *)0);");
874 out.println(indent +
875 cname + " = " + cname + "_base + " + offset +
876 ";");
877 out.println();
878 } else {
879 String array = numBufferArgs <= 1 ? "_array" :
880 "_" + bufferArgNames.get(bufArgIdx++) + "Array";
881
Jack Palevich46d25a32009-05-07 18:28:29 -0700882 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800883 if (nullAllowed) {
884 out.println(indent + "if (" + cname + "_buf) {");
885 out.print(indent);
886 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700887
Jack Palevich46d25a32009-05-07 18:28:29 -0700888 if (isPointerFunc) {
889 out.println(indent +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800890 cname +
891 " = (" +
892 cfunc.getArgType(cIndex).getDeclaration() +
Jack Palevich46d25a32009-05-07 18:28:29 -0700893 ") _env->GetDirectBufferAddress(" +
894 (mUseCPlusPlus ? "" : "_env, ") +
895 cname + "_buf);");
896 String iii = " ";
897 out.println(iii + indent + "if ( ! " + cname + " ) {");
898 out.println(iii + iii + indent +
899 (mUseCPlusPlus ? "_env" : "(*_env)") +
900 "->ThrowNew(" +
901 (mUseCPlusPlus ? "" : "_env, ") +
902 "IAEClass, \"Must use a native order direct Buffer\");");
903 out.println(iii + iii + indent + "return;");
904 out.println(iii + indent + "}");
905 } else {
906 out.println(indent +
907 cname +
908 " = (" +
909 cfunc.getArgType(cIndex).getDeclaration() +
910 ")getPointer(_env, " +
911 cname +
912 "_buf, &" + array + ", &" + remaining +
913 ");");
914 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800915
916 if (nullAllowed) {
917 out.println(indent + "}");
918 }
919
920 emitNativeBoundsChecks(cfunc, cname, out, true,
921 emitExceptionCheck,
922 offset, remaining, " ");
923 }
924 }
925 }
926
927 if (!isVoid) {
928 out.print(indent + "_returnValue = ");
929 } else {
930 out.print(indent);
931 }
932 String name = cfunc.getName();
933
934 if (mUseContextPointer) {
935 name = name.substring(2, name.length()); // Strip off 'gl' prefix
936 name = name.substring(0, 1).toLowerCase() +
937 name.substring(1, name.length());
938 out.print("ctx->procs.");
939 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700940
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800941 out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
942
Jack Palevich6cbca502009-04-13 16:22:25 -0700943 numArgs = cfunc.getNumArgs();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800944 if (numArgs == 0) {
945 if (mUseContextPointer) {
946 out.println("ctx);");
947 } else {
948 out.println(");");
949 }
950 } else {
951 if (mUseContextPointer) {
952 out.println("ctx,");
953 } else {
954 out.println();
955 }
956 for (int i = 0; i < numArgs; i++) {
957 String typecast;
958 if (i == numArgs - 1 && isVBOPointerFunc) {
959 typecast = "const GLvoid *";
960 } else {
961 typecast = cfunc.getArgType(i).getDeclaration();
962 }
963 out.print(indent + indent +
964 "(" +
965 typecast +
966 ")" +
967 cfunc.getArgName(i));
968
969 if (i == numArgs - 1) {
970 if (isPointerFunc) {
971 out.println(",");
972 out.println(indent + indent + "(GLsizei)remaining");
973 } else {
974 out.println();
975 }
976 } else {
977 out.println(",");
978 }
979 }
980 out.println(indent + ");");
981 }
982
983 if (needsExit) {
984 out.println();
985 out.println("exit:");
986 needsExit = false;
987 }
988
989 bufArgIdx = 0;
990 if (nonPrimitiveArgs.size() > 0) {
991 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
992 int idx = nonPrimitiveArgs.get(i).intValue();
993
994 int cIndex = jfunc.getArgCIndex(idx);
995 if (jfunc.getArgType(idx).isArray()) {
Jack Palevich6cbca502009-04-13 16:22:25 -0700996
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800997 // If the argument is 'const', GL will not write to it.
998 // In this case, we can use the 'JNI_ABORT' flag to avoid
999 // the need to write back to the Java array
1000 out.println(indent +
1001 "if (" + jfunc.getArgName(idx) + "_base) {");
1002 out.println(indent + indent +
1003 (mUseCPlusPlus ? "_env" : "(*_env)") +
1004 "->ReleasePrimitiveArrayCritical(" +
Jack Palevich6cbca502009-04-13 16:22:25 -07001005 (mUseCPlusPlus ? "" : "_env, ") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001006 jfunc.getArgName(idx) + "_ref, " +
1007 cfunc.getArgName(cIndex) +
1008 "_base,");
1009 out.println(indent + indent + indent +
1010 (cfunc.getArgType(cIndex).isConst() ?
1011 "JNI_ABORT" :
1012 "_exception ? JNI_ABORT: 0") +
1013 ");");
1014 out.println(indent + "}");
1015 } else if (jfunc.getArgType(idx).isBuffer()) {
Jack Palevich46d25a32009-05-07 18:28:29 -07001016 if (! isPointerFunc) {
1017 String array = numBufferArgs <= 1 ? "_array" :
1018 "_" + bufferArgNames.get(bufArgIdx++) + "Array";
1019 out.println(indent + "if (" + array + ") {");
1020 out.println(indent + indent +
1021 "releasePointer(_env, " + array + ", " +
1022 cfunc.getArgName(cIndex) +
1023 ", " +
1024 (cfunc.getArgType(cIndex).isConst() ?
1025 "JNI_FALSE" : "_exception ? JNI_FALSE :" +
1026 " JNI_TRUE") +
1027 ");");
1028 out.println(indent + "}");
1029 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001030 }
1031 }
1032 }
1033
1034 if (!isVoid) {
1035 out.println(indent + "return _returnValue;");
1036 }
1037
1038 out.println("}");
1039 out.println();
1040 }
1041
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001042}