blob: 9d37607c851eaad6fc3319e0c1bee18272a671ab [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;
11 protected String mClassPathName;
12 protected ParameterChecker mChecker;
13 protected List<String> nativeRegistrations = new ArrayList<String>();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080014 boolean needsExit;
Jack Palevichffac1ef2009-04-14 19:00:09 -070015 protected static String indent = " ";
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080016 HashSet<String> mFunctionsEmitted = new HashSet<String>();
17
Jack Palevichffac1ef2009-04-14 19:00:09 -070018 public static String getJniName(JType jType) {
19 String jniName = "";
20 if (jType.isClass()) {
21 return "L" + jType.getBaseType() + ";";
22 } else if (jType.isArray()) {
23 jniName = "[";
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080024 }
Jack Palevichffac1ef2009-04-14 19:00:09 -070025
26 String baseType = jType.getBaseType();
27 if (baseType.equals("int")) {
28 jniName += "I";
29 } else if (baseType.equals("float")) {
30 jniName += "F";
31 } else if (baseType.equals("boolean")) {
32 jniName += "Z";
33 } else if (baseType.equals("short")) {
34 jniName += "S";
35 } else if (baseType.equals("long")) {
36 jniName += "L";
37 } else if (baseType.equals("byte")) {
38 jniName += "B";
39 }
40 return jniName;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080041 }
42
Jack Palevichffac1ef2009-04-14 19:00:09 -070043
44 public void emitCode(CFunc cfunc, String original,
45 PrintStream javaInterfaceStream,
46 PrintStream javaImplStream,
47 PrintStream cStream) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080048 JFunc jfunc;
49 String signature;
50 boolean duplicate;
Jack Palevich6cbca502009-04-13 16:22:25 -070051
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080052 if (cfunc.hasTypedPointerArg()) {
53 jfunc = JFunc.convert(cfunc, true);
54
55 // Don't emit duplicate functions
56 // These may appear because they are defined in multiple
57 // Java interfaces (e.g., GL11/GL11ExtensionPack)
58 signature = jfunc.toString();
59 duplicate = false;
60 if (mFunctionsEmitted.contains(signature)) {
61 duplicate = true;
62 } else {
63 mFunctionsEmitted.add(signature);
64 }
65
66 if (!duplicate) {
Jack Palevichffac1ef2009-04-14 19:00:09 -070067 emitNativeDeclaration(jfunc, javaImplStream);
68 emitJavaCode(jfunc, javaImplStream);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080069 }
Jack Palevichffac1ef2009-04-14 19:00:09 -070070 emitJavaInterfaceCode(jfunc, javaInterfaceStream);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080071 if (!duplicate) {
Jack Palevichffac1ef2009-04-14 19:00:09 -070072 emitJniCode(jfunc, cStream);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080073 }
74 }
75
76 jfunc = JFunc.convert(cfunc, false);
77
78 signature = jfunc.toString();
79 duplicate = false;
80 if (mFunctionsEmitted.contains(signature)) {
81 duplicate = true;
82 } else {
83 mFunctionsEmitted.add(signature);
84 }
85
86 if (!duplicate) {
Jack Palevichffac1ef2009-04-14 19:00:09 -070087 emitNativeDeclaration(jfunc, javaImplStream);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080088 }
Jack Palevichffac1ef2009-04-14 19:00:09 -070089 emitJavaInterfaceCode(jfunc, javaInterfaceStream);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080090 if (!duplicate) {
Jack Palevichffac1ef2009-04-14 19:00:09 -070091 emitJavaCode(jfunc, javaImplStream);
92 emitJniCode(jfunc, cStream);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080093 }
94 }
95
96 public void emitNativeDeclaration(JFunc jfunc, PrintStream out) {
97 out.println(" // C function " + jfunc.getCFunc().getOriginal());
98 out.println();
99
100 emitFunction(jfunc, out, true, false);
101 }
102
103 public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) {
104 emitFunction(jfunc, out, false, true);
105 }
106
107 public void emitJavaCode(JFunc jfunc, PrintStream out) {
108 emitFunction(jfunc, out, false, false);
109 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700110
Jack Palevichffac1ef2009-04-14 19:00:09 -0700111 void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800112 boolean isVoid = jfunc.getType().isVoid();
113 boolean isPointerFunc = jfunc.getName().endsWith("Pointer") &&
114 jfunc.getCFunc().hasPointerArg();
115
116 if (!isVoid) {
117 out.println(iii +
118 jfunc.getType() + " _returnValue;");
119 }
120 out.println(iii +
121 (isVoid ? "" : "_returnValue = ") +
122 jfunc.getName() +
123 (isPointerFunc ? "Bounds" : "" ) +
124 "(");
Jack Palevich6cbca502009-04-13 16:22:25 -0700125
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800126 int numArgs = jfunc.getNumArgs();
127 for (int i = 0; i < numArgs; i++) {
128 String argName = jfunc.getArgName(i);
129 JType argType = jfunc.getArgType(i);
130
131 if (grabArray && argType.isTypedBuffer()) {
132 String typeName = argType.getBaseType();
133 typeName = typeName.substring(9, typeName.length() - 6);
134 out.println(iii + indent + "get" + typeName + "Array(" + argName + "),");
Jack Palevich6cbca502009-04-13 16:22:25 -0700135 out.print(iii + indent + "getOffset(" + argName + ")");
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800136 } else {
137 out.print(iii + indent + argName);
138 }
139 if (i == numArgs - 1) {
140 if (isPointerFunc) {
141 out.println(",");
142 out.println(iii + indent + argName + ".remaining()");
143 } else {
144 out.println();
145 }
146 } else {
147 out.println(",");
148 }
149 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700150
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800151 out.println(iii + ");");
152 }
153
Jack Palevichffac1ef2009-04-14 19:00:09 -0700154 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
155 String iii) {
156 printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
157 "offset", "_remaining", iii);
158 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800159
Jack Palevichffac1ef2009-04-14 19:00:09 -0700160 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
161 String offset, String remaining, String iii) {
162 out.println(iii + " default:");
163 out.println(iii + " _needed = 0;");
164 out.println(iii + " break;");
165 out.println(iii + "}");
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800166
Jack Palevichffac1ef2009-04-14 19:00:09 -0700167 out.println(iii + "if (" + remaining + " < _needed) {");
168 if (emitExceptionCheck) {
169 out.println(iii + indent + "_exception = 1;");
170 }
171 out.println(iii + indent +
172 (mUseCPlusPlus ? "_env" : "(*_env)") +
173 "->ThrowNew(" +
174 (mUseCPlusPlus ? "" : "_env, ") +
175 "IAEClass, " +
176 "\"" +
177 (isBuffer ?
178 "remaining()" : "length - " + offset) +
179 " < needed\");");
180 out.println(iii + indent + "goto exit;");
181 needsExit = true;
182 out.println(iii + "}");
183 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800184
185 boolean isNullAllowed(CFunc cfunc) {
186 String[] checks = mChecker.getChecks(cfunc.getName());
187 int index = 1;
188 if (checks != null) {
189 while (index < checks.length) {
190 if (checks[index].equals("return")) {
191 index += 2;
192 } else if (checks[index].startsWith("check")) {
193 index += 3;
194 } else if (checks[index].equals("ifcheck")) {
195 index += 5;
196 } else if (checks[index].equals("unsupported")) {
197 index += 1;
198 } else if (checks[index].equals("nullAllowed")) {
199 return true;
200 } else {
201 System.out.println("Error: unknown keyword \"" +
202 checks[index] + "\"");
203 System.exit(0);
204 }
205 }
206 }
207 return false;
208 }
209
210 String getErrorReturnValue(CFunc cfunc) {
211 CType returnType = cfunc.getType();
212 boolean isVoid = returnType.isVoid();
213 if (isVoid) {
214 return null;
215 }
216
217 String[] checks = mChecker.getChecks(cfunc.getName());
218
219 int index = 1;
220 if (checks != null) {
221 while (index < checks.length) {
222 if (checks[index].equals("return")) {
223 return checks[index + 1];
224 } else if (checks[index].startsWith("check")) {
225 index += 3;
226 } else if (checks[index].equals("ifcheck")) {
227 index += 5;
228 } else if (checks[index].equals("unsupported")) {
229 index += 1;
230 } else if (checks[index].equals("nullAllowed")) {
231 index += 1;
232 } else {
233 System.out.println("Error: unknown keyword \"" +
234 checks[index] + "\"");
235 System.exit(0);
236 }
237 }
238 }
239
240 return null;
241 }
242
243 boolean isUnsupportedFunc(CFunc cfunc) {
244 String[] checks = mChecker.getChecks(cfunc.getName());
245 int index = 1;
246 if (checks != null) {
247 while (index < checks.length) {
248 if (checks[index].equals("unsupported")) {
249 return true;
250 } else if (checks[index].equals("return")) {
251 index += 2;
252 } else if (checks[index].startsWith("check")) {
253 index += 3;
254 } else if (checks[index].equals("ifcheck")) {
255 index += 5;
256 } else if (checks[index].equals("nullAllowed")) {
257 index += 1;
258 } else {
259 System.out.println("Error: unknown keyword \"" +
260 checks[index] + "\"");
261 System.exit(0);
262 }
263 }
264 }
265 return false;
266 }
267
268 void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
Jack Palevichffac1ef2009-04-14 19:00:09 -0700269 boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800270
Jack Palevichffac1ef2009-04-14 19:00:09 -0700271 String[] checks = mChecker.getChecks(cfunc.getName());
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800272
Jack Palevichffac1ef2009-04-14 19:00:09 -0700273 boolean lastWasIfcheck = false;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800274
Jack Palevichffac1ef2009-04-14 19:00:09 -0700275 int index = 1;
276 if (checks != null) {
277 while (index < checks.length) {
278 if (checks[index].startsWith("check")) {
279 if (lastWasIfcheck) {
280 printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
281 offset, remaining, iii);
282 }
283 lastWasIfcheck = false;
284 if (cname != null && !cname.equals(checks[index + 1])) {
285 index += 3;
286 continue;
287 }
288 out.println(iii + "if (" + remaining + " < " +
289 checks[index + 2] +
290 ") {");
291 if (emitExceptionCheck) {
292 out.println(iii + indent + "_exception = 1;");
293 }
294 String exceptionClassName = "IAEClass";
295 // If the "check" keyword was of the form
296 // "check_<class name>", use the class name in the
297 // exception to be thrown
298 int underscore = checks[index].indexOf('_');
299 if (underscore >= 0) {
300 exceptionClassName = checks[index].substring(underscore + 1) + "Class";
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800301 }
Jack Palevichffac1ef2009-04-14 19:00:09 -0700302 out.println(iii + indent +
303 (mUseCPlusPlus ? "_env" : "(*_env)") +
304 "->ThrowNew(" +
305 (mUseCPlusPlus ? "" : "_env, ") +
306 exceptionClassName + ", " +
307 "\"" +
308 (isBuffer ?
309 "remaining()" : "length - " + offset) +
310 " < " + checks[index + 2] +
311 "\");");
312
313 out.println(iii + indent + "goto exit;");
314 needsExit = true;
315 out.println(iii + "}");
316
317 index += 3;
318 } else if (checks[index].equals("ifcheck")) {
319 String[] matches = checks[index + 4].split(",");
320
321 if (!lastWasIfcheck) {
322 out.println(iii + "int _needed;");
323 out.println(iii +
324 "switch (" +
325 checks[index + 3] +
326 ") {");
327 }
328
329 for (int i = 0; i < matches.length; i++) {
330 out.println("#if defined(" + matches[i] + ")");
331 out.println(iii +
332 " case " +
333 matches[i] +
334 ":");
335 out.println("#endif // defined(" + matches[i] + ")");
336 }
337 out.println(iii +
338 " _needed = " +
339 checks[index + 2] +
340 ";");
341 out.println(iii +
342 " break;");
343
344 lastWasIfcheck = true;
345 index += 5;
346 } else if (checks[index].equals("return")) {
347 // ignore
348 index += 2;
349 } else if (checks[index].equals("unsupported")) {
350 // ignore
351 index += 1;
352 } else if (checks[index].equals("nullAllowed")) {
353 // ignore
354 index += 1;
355 } else {
356 System.out.println("Error: unknown keyword \"" +
357 checks[index] + "\"");
358 System.exit(0);
359 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800360 }
Jack Palevichffac1ef2009-04-14 19:00:09 -0700361 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800362
Jack Palevichffac1ef2009-04-14 19:00:09 -0700363 if (lastWasIfcheck) {
364 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800365 }
366 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800367
Jack Palevichffac1ef2009-04-14 19:00:09 -0700368 boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800369 if (nonPrimitiveArgs.size() > 0) {
370 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
371 int idx = nonPrimitiveArgs.get(i).intValue();
372 int cIndex = jfunc.getArgCIndex(idx);
373 if (jfunc.getArgType(idx).isArray()) {
374 if (!cfunc.getArgType(cIndex).isConst()) {
375 return true;
376 }
377 } else if (jfunc.getArgType(idx).isBuffer()) {
378 if (!cfunc.getArgType(cIndex).isConst()) {
379 return true;
380 }
381 }
382 }
383 }
384
385 return false;
386 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700387
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800388 /**
389 * Emit a function in several variants:
390 *
391 * if nativeDecl: public native <returntype> func(args);
392 *
393 * if !nativeDecl:
394 * if interfaceDecl: public <returntype> func(args);
395 * if !interfaceDecl: public <returntype> func(args) { body }
396 */
Jack Palevichffac1ef2009-04-14 19:00:09 -0700397 void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800398 boolean isPointerFunc =
399 jfunc.getName().endsWith("Pointer") &&
400 jfunc.getCFunc().hasPointerArg();
401
402 if (!nativeDecl && !interfaceDecl && !isPointerFunc) {
403 // If it's not a pointer function, we've already emitted it
404 // with nativeDecl == true
405 return;
406 }
407
408 if (isPointerFunc) {
409 out.println(indent +
410 (nativeDecl ? "private native " :
411 (interfaceDecl ? "" : "public ")) +
412 jfunc.getType() + " " +
413 jfunc.getName() +
414 (nativeDecl ? "Bounds" : "") +
415 "(");
416 } else {
417 out.println(indent +
418 (nativeDecl ? "public native " :
419 (interfaceDecl ? "" : "public ")) +
420 jfunc.getType() + " " +
421 jfunc.getName() +
422 "(");
423 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700424
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800425 int numArgs = jfunc.getNumArgs();
426 for (int i = 0; i < numArgs; i++) {
427 String argName = jfunc.getArgName(i);
428 JType argType = jfunc.getArgType(i);
Jack Palevich6cbca502009-04-13 16:22:25 -0700429
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800430 out.print(indent + indent + argType + " " + argName);
431 if (i == numArgs - 1) {
432 if (isPointerFunc && nativeDecl) {
433 out.println(",");
434 out.println(indent + indent + "int remaining");
435 } else {
436 out.println();
437 }
438 } else {
439 out.println(",");
440 }
441 }
442
443 if (nativeDecl || interfaceDecl) {
444 out.println(indent + ");");
445 } else {
446 out.println(indent + ") {");
447
448 String iii = indent + indent;
449
450 String fname = jfunc.getName();
451 if (isPointerFunc) {
452 // TODO - deal with VBO variants
453 if (fname.equals("glColorPointer")) {
454 out.println(iii + "if ((size == 4) &&");
455 out.println(iii + " ((type == GL_FLOAT) ||");
456 out.println(iii + " (type == GL_UNSIGNED_BYTE) ||");
457 out.println(iii + " (type == GL_FIXED)) &&");
458 out.println(iii + " (stride >= 0)) {");
459 out.println(iii + indent + "_colorPointer = pointer;");
460 out.println(iii + "}");
461 } else if (fname.equals("glNormalPointer")) {
462 out.println(iii + "if (((type == GL_FLOAT) ||");
463 out.println(iii + " (type == GL_BYTE) ||");
464 out.println(iii + " (type == GL_SHORT) ||");
465 out.println(iii + " (type == GL_FIXED)) &&");
466 out.println(iii + " (stride >= 0)) {");
467 out.println(iii + indent + "_normalPointer = pointer;");
468 out.println(iii + "}");
469 } else if (fname.equals("glTexCoordPointer")) {
470 out.println(iii + "if (((size == 2) ||");
471 out.println(iii + " (size == 3) ||");
472 out.println(iii + " (size == 4)) &&");
473 out.println(iii + " ((type == GL_FLOAT) ||");
474 out.println(iii + " (type == GL_BYTE) ||");
475 out.println(iii + " (type == GL_SHORT) ||");
476 out.println(iii + " (type == GL_FIXED)) &&");
477 out.println(iii + " (stride >= 0)) {");
478 out.println(iii + indent + "_texCoordPointer = pointer;");
479 out.println(iii + "}");
480 } else if (fname.equals("glVertexPointer")) {
481 out.println(iii + "if (((size == 2) ||");
482 out.println(iii + " (size == 3) ||");
483 out.println(iii + " (size == 4)) &&");
484 out.println(iii + " ((type == GL_FLOAT) ||");
485 out.println(iii + " (type == GL_BYTE) ||");
486 out.println(iii + " (type == GL_SHORT) ||");
487 out.println(iii + " (type == GL_FIXED)) &&");
488 out.println(iii + " (stride >= 0)) {");
489 out.println(iii + indent + "_vertexPointer = pointer;");
490 out.println(iii + "}");
491 }
492 }
493
494 // emitBoundsChecks(jfunc, out, iii);
495 emitFunctionCall(jfunc, out, iii, false);
496
497 boolean isVoid = jfunc.getType().isVoid();
498
499 if (!isVoid) {
500 out.println(indent + indent + "return _returnValue;");
501 }
502 out.println(indent + "}");
503 }
504 out.println();
505 }
506
Jack Palevichffac1ef2009-04-14 19:00:09 -0700507 public void addNativeRegistration(String s) {
508 nativeRegistrations.add(s);
509 }
510
511 public void emitNativeRegistration(PrintStream cStream) {
512 cStream.println("static const char *classPathName = \"" +
513 mClassPathName +
514 "\";");
515 cStream.println();
516
517 cStream.println("static JNINativeMethod methods[] = {");
518
519 cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },");
520
521 Iterator<String> i = nativeRegistrations.iterator();
522 while (i.hasNext()) {
523 cStream.println(i.next());
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800524 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700525
Jack Palevichffac1ef2009-04-14 19:00:09 -0700526 cStream.println("};");
527 cStream.println();
528
529
530 cStream.println("int register_com_google_android_gles_jni_GLImpl(JNIEnv *_env)");
531 cStream.println("{");
532 cStream.println(indent +
533 "int err;");
534
535 cStream.println(indent +
536 "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));");
537
538 cStream.println(indent + "return err;");
539 cStream.println("}");
540 }
541
542 public JniCodeEmitter() {
543 super();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800544 }
545
546 String getJniType(JType jType) {
547 if (jType.isVoid()) {
548 return "void";
549 }
550
551 String baseType = jType.getBaseType();
552 if (jType.isPrimitive()) {
553 if (baseType.equals("String")) {
554 return "jstring";
555 } else {
556 return "j" + baseType;
557 }
558 } else if (jType.isArray()) {
559 return "j" + baseType + "Array";
560 } else {
561 return "jobject";
562 }
563 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700564
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800565 String getJniMangledName(String name) {
566 name = name.replaceAll("_", "_1");
567 name = name.replaceAll(";", "_2");
568 name = name.replaceAll("\\[", "_3");
569 return name;
570 }
571
572 public void emitJniCode(JFunc jfunc, PrintStream out) {
573 CFunc cfunc = jfunc.getCFunc();
Jack Palevich6cbca502009-04-13 16:22:25 -0700574
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800575 // Emit comment identifying original C function
576 //
577 // Example:
578 //
579 // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
580 //
581 out.println("/* " + cfunc.getOriginal() + " */");
582
583 // Emit JNI signature (name)
584 //
585 // Example:
586 //
587 // void
588 // android_glClipPlanef__I_3FI
589 //
590
591 String outName = "android_" + jfunc.getName();
592 boolean isPointerFunc = outName.endsWith("Pointer") &&
593 jfunc.getCFunc().hasPointerArg();
594 boolean isVBOPointerFunc = (outName.endsWith("Pointer") ||
595 outName.endsWith("DrawElements")) &&
596 !jfunc.getCFunc().hasPointerArg();
597 if (isPointerFunc) {
598 outName += "Bounds";
599 }
600
601 out.print("static ");
602 out.println(getJniType(jfunc.getType()));
603 out.print(outName);
604
605 String rsignature = getJniName(jfunc.getType());
606
607 String signature = "";
608 int numArgs = jfunc.getNumArgs();
609 for (int i = 0; i < numArgs; i++) {
610 JType argType = jfunc.getArgType(i);
611 signature += getJniName(argType);
612 }
613 if (isPointerFunc) {
614 signature += "I";
615 }
616
617 // Append signature to function name
Jack Palevich6cbca502009-04-13 16:22:25 -0700618 String sig = getJniMangledName(signature).replace('.', '_');
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800619 out.print("__" + sig);
620 outName += "__" + sig;
Jack Palevich6cbca502009-04-13 16:22:25 -0700621
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800622 signature = signature.replace('.', '/');
623 rsignature = rsignature.replace('.', '/');
Jack Palevich6cbca502009-04-13 16:22:25 -0700624
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800625 out.println();
626 if (rsignature.length() == 0) {
627 rsignature = "V";
628 }
629
630 String s = "{\"" +
631 jfunc.getName() +
632 (isPointerFunc ? "Bounds" : "") +
633 "\", \"(" + signature +")" +
634 rsignature +
635 "\", (void *) " +
636 outName +
637 " },";
638 nativeRegistrations.add(s);
639
640 List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
641 int numBufferArgs = 0;
642 List<String> bufferArgNames = new ArrayList<String>();
643
644 // Emit JNI signature (arguments)
645 //
646 // Example:
647 //
648 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) {
649 //
650 out.print(" (JNIEnv *_env, jobject _this");
651 for (int i = 0; i < numArgs; i++) {
652 out.print(", ");
653 JType argType = jfunc.getArgType(i);
654 String suffix;
655 if (!argType.isPrimitive()) {
656 if (argType.isArray()) {
657 suffix = "_ref";
658 } else {
659 suffix = "_buf";
660 }
661 nonPrimitiveArgs.add(new Integer(i));
662 if (jfunc.getArgType(i).isBuffer()) {
663 int cIndex = jfunc.getArgCIndex(i);
664 String cname = cfunc.getArgName(cIndex);
665 bufferArgNames.add(cname);
666 numBufferArgs++;
667 }
668 } else {
669 suffix = "";
670 }
671
672 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
673 }
674 if (isPointerFunc) {
675 out.print(", jint remaining");
676 }
677 out.println(") {");
Jack Palevich6cbca502009-04-13 16:22:25 -0700678
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800679 int numArrays = 0;
680 int numBuffers = 0;
681 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
682 int idx = nonPrimitiveArgs.get(i).intValue();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800683 if (jfunc.getArgType(idx).isArray()) {
684 ++numArrays;
685 }
686 if (jfunc.getArgType(idx).isBuffer()) {
687 ++numBuffers;
688 }
689 }
690
691 // Emit method body
692
693 // Emit local variable declarations for _exception and _returnValue
694 //
695 // Example:
696 //
697 // android::gl::ogles_context_t *ctx;
Jack Palevich6cbca502009-04-13 16:22:25 -0700698 //
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800699 // jint _exception;
700 // GLenum _returnValue;
701 //
702 CType returnType = cfunc.getType();
703 boolean isVoid = returnType.isVoid();
704
705 boolean isUnsupported = isUnsupportedFunc(cfunc);
706 if (isUnsupported) {
707 out.println(indent +
708 "_env->ThrowNew(UOEClass,");
709 out.println(indent +
710 " \"" + cfunc.getName() + "\");");
711 if (!isVoid) {
712 String retval = getErrorReturnValue(cfunc);
713 out.println(indent + "return " + retval + ";");
714 }
715 out.println("}");
716 out.println();
717 return;
718 }
719
720 if (mUseContextPointer) {
721 out.println(indent +
722 "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
723 }
724
725 boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) &&
726 hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs);
727 // mChecker.getChecks(cfunc.getName()) != null
728
729 // Emit an _exeption variable if there will be error checks
730 if (emitExceptionCheck) {
731 out.println(indent + "jint _exception = 0;");
732 }
733
734 // Emit a single _array or multiple _XXXArray variables
735 if (numBufferArgs == 1) {
736 out.println(indent + "jarray _array = (jarray) 0;");
737 } else {
738 for (int i = 0; i < numBufferArgs; i++) {
739 out.println(indent + "jarray _" + bufferArgNames.get(i) +
740 "Array = (jarray) 0;");
741 }
742 }
743 if (!isVoid) {
744 String retval = getErrorReturnValue(cfunc);
745 if (retval != null) {
746 out.println(indent + returnType.getDeclaration() +
747 " _returnValue = " + retval + ";");
748 } else {
749 out.println(indent + returnType.getDeclaration() +
750 " _returnValue;");
751 }
752 }
753
754 // Emit local variable declarations for pointer arguments
755 //
756 // Example:
757 //
758 // GLfixed *eqn_base;
759 // GLfixed *eqn;
760 //
761 String offset = "offset";
762 String remaining = "_remaining";
763 if (nonPrimitiveArgs.size() > 0) {
764 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
765 int idx = nonPrimitiveArgs.get(i).intValue();
766 int cIndex = jfunc.getArgCIndex(idx);
767 String cname = cfunc.getArgName(cIndex);
768
769 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
770 String decl = type.getDeclaration();
771 if (jfunc.getArgType(idx).isArray()) {
772 out.println(indent +
773 decl +
774 (decl.endsWith("*") ? "" : " ") +
775 jfunc.getArgName(idx) +
776 "_base = (" + decl + ") 0;");
777 }
778 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
779 "_" + cname + "Remaining";
780 out.println(indent +
781 "jint " + remaining + ";");
782 out.println(indent +
783 decl +
784 (decl.endsWith("*") ? "" : " ") +
Jack Palevich6cbca502009-04-13 16:22:25 -0700785 jfunc.getArgName(idx) +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800786 " = (" + decl + ") 0;");
787 }
788
789 out.println();
790 }
791
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800792 // Emit 'GetPrimitiveArrayCritical' for arrays
793 // Emit 'GetPointer' calls for Buffer pointers
794 int bufArgIdx = 0;
795 if (nonPrimitiveArgs.size() > 0) {
796 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
797 int idx = nonPrimitiveArgs.get(i).intValue();
798 int cIndex = jfunc.getArgCIndex(idx);
Jack Palevich6cbca502009-04-13 16:22:25 -0700799
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800800 String cname = cfunc.getArgName(cIndex);
801 offset = numArrays <= 1 ? "offset" :
802 cname + "Offset";
803 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
804 "_" + cname + "Remaining";
805
806 if (jfunc.getArgType(idx).isArray()) {
807 out.println(indent +
Jack Palevich6cbca502009-04-13 16:22:25 -0700808 "if (!" +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800809 cname +
810 "_ref) {");
811 if (emitExceptionCheck) {
812 out.println(indent + indent + "_exception = 1;");
813 }
814 out.println(indent + " " +
815 (mUseCPlusPlus ? "_env" : "(*_env)") +
816 "->ThrowNew(" +
817 (mUseCPlusPlus ? "" : "_env, ") +
818 "IAEClass, " +
819 "\"" + cname +
820 " == null\");");
821 out.println(indent + " goto exit;");
822 needsExit = true;
823 out.println(indent + "}");
824
825 out.println(indent + "if (" + offset + " < 0) {");
826 if (emitExceptionCheck) {
827 out.println(indent + indent + "_exception = 1;");
828 }
829 out.println(indent + " " +
830 (mUseCPlusPlus ? "_env" : "(*_env)") +
831 "->ThrowNew(" +
832 (mUseCPlusPlus ? "" : "_env, ") +
833 "IAEClass, " +
834 "\"" + offset + " < 0\");");
835 out.println(indent + " goto exit;");
836 needsExit = true;
837 out.println(indent + "}");
838
839 out.println(indent + remaining + " = " +
Jack Palevich6cbca502009-04-13 16:22:25 -0700840 (mUseCPlusPlus ? "_env" : "(*_env)") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800841 "->GetArrayLength(" +
842 (mUseCPlusPlus ? "" : "_env, ") +
843 cname + "_ref) - " + offset + ";");
844
845 emitNativeBoundsChecks(cfunc, cname, out, false,
846 emitExceptionCheck,
847 offset, remaining, " ");
848
849 out.println(indent +
850 cname +
851 "_base = (" +
852 cfunc.getArgType(cIndex).getDeclaration() +
853 ")");
854 out.println(indent + " " +
855 (mUseCPlusPlus ? "_env" : "(*_env)") +
856 "->GetPrimitiveArrayCritical(" +
Jack Palevich6cbca502009-04-13 16:22:25 -0700857 (mUseCPlusPlus ? "" : "_env, ") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800858 jfunc.getArgName(idx) +
859 "_ref, (jboolean *)0);");
860 out.println(indent +
861 cname + " = " + cname + "_base + " + offset +
862 ";");
863 out.println();
864 } else {
865 String array = numBufferArgs <= 1 ? "_array" :
866 "_" + bufferArgNames.get(bufArgIdx++) + "Array";
867
868 boolean nullAllowed = isNullAllowed(cfunc);
869 if (nullAllowed) {
870 out.println(indent + "if (" + cname + "_buf) {");
871 out.print(indent);
872 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700873
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800874 out.println(indent +
875 cname +
876 " = (" +
877 cfunc.getArgType(cIndex).getDeclaration() +
878 ")getPointer(_env, " +
879 cname +
880 "_buf, &" + array + ", &" + remaining + ");");
881
882 if (nullAllowed) {
883 out.println(indent + "}");
884 }
885
886 emitNativeBoundsChecks(cfunc, cname, out, true,
887 emitExceptionCheck,
888 offset, remaining, " ");
889 }
890 }
891 }
892
893 if (!isVoid) {
894 out.print(indent + "_returnValue = ");
895 } else {
896 out.print(indent);
897 }
898 String name = cfunc.getName();
899
900 if (mUseContextPointer) {
901 name = name.substring(2, name.length()); // Strip off 'gl' prefix
902 name = name.substring(0, 1).toLowerCase() +
903 name.substring(1, name.length());
904 out.print("ctx->procs.");
905 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700906
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800907 out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
908
Jack Palevich6cbca502009-04-13 16:22:25 -0700909 numArgs = cfunc.getNumArgs();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800910 if (numArgs == 0) {
911 if (mUseContextPointer) {
912 out.println("ctx);");
913 } else {
914 out.println(");");
915 }
916 } else {
917 if (mUseContextPointer) {
918 out.println("ctx,");
919 } else {
920 out.println();
921 }
922 for (int i = 0; i < numArgs; i++) {
923 String typecast;
924 if (i == numArgs - 1 && isVBOPointerFunc) {
925 typecast = "const GLvoid *";
926 } else {
927 typecast = cfunc.getArgType(i).getDeclaration();
928 }
929 out.print(indent + indent +
930 "(" +
931 typecast +
932 ")" +
933 cfunc.getArgName(i));
934
935 if (i == numArgs - 1) {
936 if (isPointerFunc) {
937 out.println(",");
938 out.println(indent + indent + "(GLsizei)remaining");
939 } else {
940 out.println();
941 }
942 } else {
943 out.println(",");
944 }
945 }
946 out.println(indent + ");");
947 }
948
949 if (needsExit) {
950 out.println();
951 out.println("exit:");
952 needsExit = false;
953 }
954
955 bufArgIdx = 0;
956 if (nonPrimitiveArgs.size() > 0) {
957 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
958 int idx = nonPrimitiveArgs.get(i).intValue();
959
960 int cIndex = jfunc.getArgCIndex(idx);
961 if (jfunc.getArgType(idx).isArray()) {
Jack Palevich6cbca502009-04-13 16:22:25 -0700962
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800963 // If the argument is 'const', GL will not write to it.
964 // In this case, we can use the 'JNI_ABORT' flag to avoid
965 // the need to write back to the Java array
966 out.println(indent +
967 "if (" + jfunc.getArgName(idx) + "_base) {");
968 out.println(indent + indent +
969 (mUseCPlusPlus ? "_env" : "(*_env)") +
970 "->ReleasePrimitiveArrayCritical(" +
Jack Palevich6cbca502009-04-13 16:22:25 -0700971 (mUseCPlusPlus ? "" : "_env, ") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800972 jfunc.getArgName(idx) + "_ref, " +
973 cfunc.getArgName(cIndex) +
974 "_base,");
975 out.println(indent + indent + indent +
976 (cfunc.getArgType(cIndex).isConst() ?
977 "JNI_ABORT" :
978 "_exception ? JNI_ABORT: 0") +
979 ");");
980 out.println(indent + "}");
981 } else if (jfunc.getArgType(idx).isBuffer()) {
982 String array = numBufferArgs <= 1 ? "_array" :
983 "_" + bufferArgNames.get(bufArgIdx++) + "Array";
984 out.println(indent + "if (" + array + ") {");
985 out.println(indent + indent +
986 "releasePointer(_env, " + array + ", " +
987 cfunc.getArgName(cIndex) +
988 ", " +
989 (cfunc.getArgType(cIndex).isConst() ?
990 "JNI_FALSE" : "_exception ? JNI_FALSE : JNI_TRUE") +
991 ");");
992 out.println(indent + "}");
993 }
994 }
995 }
996
997 if (!isVoid) {
998 out.println(indent + "return _returnValue;");
999 }
1000
1001 out.println("}");
1002 out.println();
1003 }
1004
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001005}