blob: 33b9a3e538f617d6a8704146eaf197f4d8f8fa9c [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001import java.io.PrintStream;
2import java.io.FileNotFoundException;
3import java.io.FileOutputStream;
4import java.util.ArrayList;
5import java.util.HashSet;
6import java.util.Iterator;
7import java.util.List;
8
9/**
10 * Emits a Java interface and Java & C implementation for a C function.
11 *
12 * <p> The Java interface will have Buffer and array variants for functions that
13 * have a typed pointer argument. The array variant will convert a single "<type> *data"
14 * argument to a pair of arguments "<type>[] data, int offset".
15 */
16public class JniCodeEmitter implements CodeEmitter {
17
18 // If true, use C++ style for calling through a JNIEnv *:
19 // env->Func(...)
20 // If false, use C style:
21 // (*env)->Func(env, ...)
22 static final boolean mUseCPlusPlus = true;
23
24 boolean mUseContextPointer = true;
25
26 String mClassPathName;
27
28 ParameterChecker mChecker;
29 PrintStream mJava10InterfaceStream;
30 PrintStream mJava10ExtInterfaceStream;
31 PrintStream mJava11InterfaceStream;
32 PrintStream mJava11ExtInterfaceStream;
33 PrintStream mJava11ExtPackInterfaceStream;
34 PrintStream mJavaImplStream;
35 PrintStream mCStream;
36
37 PrintStream mJavaInterfaceStream;
38
39 List<String> nativeRegistrations = new ArrayList<String>();
40
41 boolean needsExit;
42
43 static String indent = " ";
44
45 HashSet<String> mFunctionsEmitted = new HashSet<String>();
46
47 /**
48 * @param java10InterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 functions
49 * @param java10ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 extension functions
50 * @param java11InterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 functions
51 * @param java11ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension functions
52 * @param java11ExtPackInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension Pack functions
53 * @param javaImplStream the PrintStream to which to emit the Java implementation
54 * @param cStream the PrintStream to which to emit the C implementation
55 */
56 public JniCodeEmitter(String classPathName,
57 ParameterChecker checker,
58 PrintStream java10InterfaceStream,
59 PrintStream java10ExtInterfaceStream,
60 PrintStream java11InterfaceStream,
61 PrintStream java11ExtInterfaceStream,
62 PrintStream java11ExtPackInterfaceStream,
63 PrintStream javaImplStream,
64 PrintStream cStream,
65 boolean useContextPointer) {
66 mClassPathName = classPathName;
67 mChecker = checker;
68 mJava10InterfaceStream = java10InterfaceStream;
69 mJava10ExtInterfaceStream = java10ExtInterfaceStream;
70 mJava11InterfaceStream = java11InterfaceStream;
71 mJava11ExtInterfaceStream = java11ExtInterfaceStream;
72 mJava11ExtPackInterfaceStream = java11ExtPackInterfaceStream;
73 mJavaImplStream = javaImplStream;
74 mCStream = cStream;
75 mUseContextPointer = useContextPointer;
76 }
77
78 public void setVersion(int version, boolean ext, boolean pack) {
79 if (version == 0) {
80 mJavaInterfaceStream = ext ? mJava10ExtInterfaceStream :
81 mJava10InterfaceStream;
82 } else if (version == 1) {
83 mJavaInterfaceStream = ext ?
84 (pack ? mJava11ExtPackInterfaceStream :
85 mJava11ExtInterfaceStream) :
86 mJava11InterfaceStream;
87 } else {
88 throw new RuntimeException("Bad version: " + version);
89 }
90 }
91
92 public void emitCode(CFunc cfunc, String original) {
93 JFunc jfunc;
94 String signature;
95 boolean duplicate;
96
97 if (cfunc.hasTypedPointerArg()) {
98 jfunc = JFunc.convert(cfunc, true);
99
100 // Don't emit duplicate functions
101 // These may appear because they are defined in multiple
102 // Java interfaces (e.g., GL11/GL11ExtensionPack)
103 signature = jfunc.toString();
104 duplicate = false;
105 if (mFunctionsEmitted.contains(signature)) {
106 duplicate = true;
107 } else {
108 mFunctionsEmitted.add(signature);
109 }
110
111 if (!duplicate) {
112 emitNativeDeclaration(jfunc, mJavaImplStream);
113 emitJavaCode(jfunc, mJavaImplStream);
114 }
115 emitJavaInterfaceCode(jfunc, mJavaInterfaceStream);
116 if (!duplicate) {
117 emitJniCode(jfunc, mCStream);
118 }
119 }
120
121 jfunc = JFunc.convert(cfunc, false);
122
123 signature = jfunc.toString();
124 duplicate = false;
125 if (mFunctionsEmitted.contains(signature)) {
126 duplicate = true;
127 } else {
128 mFunctionsEmitted.add(signature);
129 }
130
131 if (!duplicate) {
132 emitNativeDeclaration(jfunc, mJavaImplStream);
133 }
134 emitJavaInterfaceCode(jfunc, mJavaInterfaceStream);
135 if (!duplicate) {
136 emitJavaCode(jfunc, mJavaImplStream);
137 emitJniCode(jfunc, mCStream);
138 }
139 }
140
141 public void emitNativeDeclaration(JFunc jfunc, PrintStream out) {
142 out.println(" // C function " + jfunc.getCFunc().getOriginal());
143 out.println();
144
145 emitFunction(jfunc, out, true, false);
146 }
147
148 public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) {
149 emitFunction(jfunc, out, false, true);
150 }
151
152 public void emitJavaCode(JFunc jfunc, PrintStream out) {
153 emitFunction(jfunc, out, false, false);
154 }
155
156 void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray ) {
157 boolean isVoid = jfunc.getType().isVoid();
158 boolean isPointerFunc = jfunc.getName().endsWith("Pointer") &&
159 jfunc.getCFunc().hasPointerArg();
160
161 if (!isVoid) {
162 out.println(iii +
163 jfunc.getType() + " _returnValue;");
164 }
165 out.println(iii +
166 (isVoid ? "" : "_returnValue = ") +
167 jfunc.getName() +
168 (isPointerFunc ? "Bounds" : "" ) +
169 "(");
170
171 int numArgs = jfunc.getNumArgs();
172 for (int i = 0; i < numArgs; i++) {
173 String argName = jfunc.getArgName(i);
174 JType argType = jfunc.getArgType(i);
175
176 if (grabArray && argType.isTypedBuffer()) {
177 String typeName = argType.getBaseType();
178 typeName = typeName.substring(9, typeName.length() - 6);
179 out.println(iii + indent + "get" + typeName + "Array(" + argName + "),");
180 out.print(iii + indent + "getOffset(" + argName + ")");
181 } else {
182 out.print(iii + indent + argName);
183 }
184 if (i == numArgs - 1) {
185 if (isPointerFunc) {
186 out.println(",");
187 out.println(iii + indent + argName + ".remaining()");
188 } else {
189 out.println();
190 }
191 } else {
192 out.println(",");
193 }
194 }
195
196 out.println(iii + ");");
197 }
198
199 void printIfcheckPostamble(PrintStream out, boolean isBuffer,
200 boolean emitExceptionCheck, String iii) {
201 printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
202 "offset", "_remaining", iii);
203 }
204
205 void printIfcheckPostamble(PrintStream out, boolean isBuffer,
206 boolean emitExceptionCheck,
207 String offset, String remaining, String iii) {
208 out.println(iii + " default:");
209 out.println(iii + " _needed = 0;");
210 out.println(iii + " break;");
211 out.println(iii + "}");
212
213 out.println(iii + "if (" + remaining + " < _needed) {");
214 if (emitExceptionCheck) {
215 out.println(iii + indent + "_exception = 1;");
216 }
217 out.println(iii + indent +
218 (mUseCPlusPlus ? "_env" : "(*_env)") +
219 "->ThrowNew(" +
220 (mUseCPlusPlus ? "" : "_env, ") +
221 "IAEClass, " +
222 "\"" +
223 (isBuffer ?
224 "remaining()" : "length - " + offset) +
225 " < needed\");");
226 out.println(iii + indent + "goto exit;");
227 needsExit = true;
228 out.println(iii + "}");
229 }
230
231 boolean isNullAllowed(CFunc cfunc) {
232 String[] checks = mChecker.getChecks(cfunc.getName());
233 int index = 1;
234 if (checks != null) {
235 while (index < checks.length) {
236 if (checks[index].equals("return")) {
237 index += 2;
238 } else if (checks[index].startsWith("check")) {
239 index += 3;
240 } else if (checks[index].equals("ifcheck")) {
241 index += 5;
242 } else if (checks[index].equals("unsupported")) {
243 index += 1;
244 } else if (checks[index].equals("nullAllowed")) {
245 return true;
246 } else {
247 System.out.println("Error: unknown keyword \"" +
248 checks[index] + "\"");
249 System.exit(0);
250 }
251 }
252 }
253 return false;
254 }
255
256 String getErrorReturnValue(CFunc cfunc) {
257 CType returnType = cfunc.getType();
258 boolean isVoid = returnType.isVoid();
259 if (isVoid) {
260 return null;
261 }
262
263 String[] checks = mChecker.getChecks(cfunc.getName());
264
265 int index = 1;
266 if (checks != null) {
267 while (index < checks.length) {
268 if (checks[index].equals("return")) {
269 return checks[index + 1];
270 } else if (checks[index].startsWith("check")) {
271 index += 3;
272 } else if (checks[index].equals("ifcheck")) {
273 index += 5;
274 } else if (checks[index].equals("unsupported")) {
275 index += 1;
276 } else if (checks[index].equals("nullAllowed")) {
277 index += 1;
278 } else {
279 System.out.println("Error: unknown keyword \"" +
280 checks[index] + "\"");
281 System.exit(0);
282 }
283 }
284 }
285
286 return null;
287 }
288
289 boolean isUnsupportedFunc(CFunc cfunc) {
290 String[] checks = mChecker.getChecks(cfunc.getName());
291 int index = 1;
292 if (checks != null) {
293 while (index < checks.length) {
294 if (checks[index].equals("unsupported")) {
295 return true;
296 } else if (checks[index].equals("return")) {
297 index += 2;
298 } else if (checks[index].startsWith("check")) {
299 index += 3;
300 } else if (checks[index].equals("ifcheck")) {
301 index += 5;
302 } else if (checks[index].equals("nullAllowed")) {
303 index += 1;
304 } else {
305 System.out.println("Error: unknown keyword \"" +
306 checks[index] + "\"");
307 System.exit(0);
308 }
309 }
310 }
311 return false;
312 }
313
314 void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
315 boolean isBuffer, boolean emitExceptionCheck,
316 String offset, String remaining, String iii) {
317 CType returnType = cfunc.getType();
318 boolean isVoid = returnType.isVoid();
319
320 String[] checks = mChecker.getChecks(cfunc.getName());
321 String checkVar;
322 String retval = getErrorReturnValue(cfunc);
323
324 boolean lastWasIfcheck = false;
325
326 int index = 1;
327 if (checks != null) {
328 boolean remainingDeclared = false;
329 boolean nullCheckDeclared = false;
330 boolean offsetChecked = false;
331 while (index < checks.length) {
332 if (checks[index].startsWith("check")) {
333 if (lastWasIfcheck) {
334 printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
335 offset, remaining, iii);
336 }
337 lastWasIfcheck = false;
338 if (cname != null && !cname.equals(checks[index + 1])) {
339 index += 3;
340 continue;
341 }
342 out.println(iii + "if (" + remaining + " < " +
343 checks[index + 2] +
344 ") {");
345 if (emitExceptionCheck) {
346 out.println(iii + indent + "_exception = 1;");
347 }
348 String exceptionClassName = "IAEClass";
349 // If the "check" keyword was of the form
350 // "check_<class name>", use the class name in the
351 // exception to be thrown
352 int underscore = checks[index].indexOf('_');
353 if (underscore >= 0) {
354 exceptionClassName = checks[index].substring(underscore + 1) + "Class";
355 }
356 out.println(iii + indent +
357 (mUseCPlusPlus ? "_env" : "(*_env)") +
358 "->ThrowNew(" +
359 (mUseCPlusPlus ? "" : "_env, ") +
360 exceptionClassName + ", " +
361 "\"" +
362 (isBuffer ?
363 "remaining()" : "length - " + offset) +
364 " < " + checks[index + 2] +
365 "\");");
366
367 out.println(iii + indent + "goto exit;");
368 needsExit = true;
369 out.println(iii + "}");
370
371 index += 3;
372 } else if (checks[index].equals("ifcheck")) {
373 String[] matches = checks[index + 4].split(",");
374
375 if (!lastWasIfcheck) {
376 out.println(iii + "int _needed;");
377 out.println(iii +
378 "switch (" +
379 checks[index + 3] +
380 ") {");
381 }
382
383 for (int i = 0; i < matches.length; i++) {
384 out.println("#if defined(" + matches[i] + ")");
385 out.println(iii +
386 " case " +
387 matches[i] +
388 ":");
389 out.println("#endif // defined(" + matches[i] + ")");
390 }
391 out.println(iii +
392 " _needed = " +
393 checks[index + 2] +
394 ";");
395 out.println(iii +
396 " break;");
397
398 lastWasIfcheck = true;
399 index += 5;
400 } else if (checks[index].equals("return")) {
401 // ignore
402 index += 2;
403 } else if (checks[index].equals("unsupported")) {
404 // ignore
405 index += 1;
406 } else if (checks[index].equals("nullAllowed")) {
407 // ignore
408 index += 1;
409 } else {
410 System.out.println("Error: unknown keyword \"" +
411 checks[index] + "\"");
412 System.exit(0);
413 }
414 }
415 }
416
417 if (lastWasIfcheck) {
418 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
419 }
420 }
421
422 boolean hasNonConstArg(JFunc jfunc, CFunc cfunc,
423 List<Integer> nonPrimitiveArgs) {
424 if (nonPrimitiveArgs.size() > 0) {
425 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
426 int idx = nonPrimitiveArgs.get(i).intValue();
427 int cIndex = jfunc.getArgCIndex(idx);
428 if (jfunc.getArgType(idx).isArray()) {
429 if (!cfunc.getArgType(cIndex).isConst()) {
430 return true;
431 }
432 } else if (jfunc.getArgType(idx).isBuffer()) {
433 if (!cfunc.getArgType(cIndex).isConst()) {
434 return true;
435 }
436 }
437 }
438 }
439
440 return false;
441 }
442
443 /**
444 * Emit a function in several variants:
445 *
446 * if nativeDecl: public native <returntype> func(args);
447 *
448 * if !nativeDecl:
449 * if interfaceDecl: public <returntype> func(args);
450 * if !interfaceDecl: public <returntype> func(args) { body }
451 */
452 void emitFunction(JFunc jfunc,
453 PrintStream out,
454 boolean nativeDecl, boolean interfaceDecl) {
455 boolean isPointerFunc =
456 jfunc.getName().endsWith("Pointer") &&
457 jfunc.getCFunc().hasPointerArg();
458
459 if (!nativeDecl && !interfaceDecl && !isPointerFunc) {
460 // If it's not a pointer function, we've already emitted it
461 // with nativeDecl == true
462 return;
463 }
464
465 if (isPointerFunc) {
466 out.println(indent +
467 (nativeDecl ? "private native " :
468 (interfaceDecl ? "" : "public ")) +
469 jfunc.getType() + " " +
470 jfunc.getName() +
471 (nativeDecl ? "Bounds" : "") +
472 "(");
473 } else {
474 out.println(indent +
475 (nativeDecl ? "public native " :
476 (interfaceDecl ? "" : "public ")) +
477 jfunc.getType() + " " +
478 jfunc.getName() +
479 "(");
480 }
481
482 int numArgs = jfunc.getNumArgs();
483 for (int i = 0; i < numArgs; i++) {
484 String argName = jfunc.getArgName(i);
485 JType argType = jfunc.getArgType(i);
486
487 out.print(indent + indent + argType + " " + argName);
488 if (i == numArgs - 1) {
489 if (isPointerFunc && nativeDecl) {
490 out.println(",");
491 out.println(indent + indent + "int remaining");
492 } else {
493 out.println();
494 }
495 } else {
496 out.println(",");
497 }
498 }
499
500 if (nativeDecl || interfaceDecl) {
501 out.println(indent + ");");
502 } else {
503 out.println(indent + ") {");
504
505 String iii = indent + indent;
506
507 String fname = jfunc.getName();
508 if (isPointerFunc) {
509 // TODO - deal with VBO variants
510 if (fname.equals("glColorPointer")) {
511 out.println(iii + "if ((size == 4) &&");
512 out.println(iii + " ((type == GL_FLOAT) ||");
513 out.println(iii + " (type == GL_UNSIGNED_BYTE) ||");
514 out.println(iii + " (type == GL_FIXED)) &&");
515 out.println(iii + " (stride >= 0)) {");
516 out.println(iii + indent + "_colorPointer = pointer;");
517 out.println(iii + "}");
518 } else if (fname.equals("glNormalPointer")) {
519 out.println(iii + "if (((type == GL_FLOAT) ||");
520 out.println(iii + " (type == GL_BYTE) ||");
521 out.println(iii + " (type == GL_SHORT) ||");
522 out.println(iii + " (type == GL_FIXED)) &&");
523 out.println(iii + " (stride >= 0)) {");
524 out.println(iii + indent + "_normalPointer = pointer;");
525 out.println(iii + "}");
526 } else if (fname.equals("glTexCoordPointer")) {
527 out.println(iii + "if (((size == 2) ||");
528 out.println(iii + " (size == 3) ||");
529 out.println(iii + " (size == 4)) &&");
530 out.println(iii + " ((type == GL_FLOAT) ||");
531 out.println(iii + " (type == GL_BYTE) ||");
532 out.println(iii + " (type == GL_SHORT) ||");
533 out.println(iii + " (type == GL_FIXED)) &&");
534 out.println(iii + " (stride >= 0)) {");
535 out.println(iii + indent + "_texCoordPointer = pointer;");
536 out.println(iii + "}");
537 } else if (fname.equals("glVertexPointer")) {
538 out.println(iii + "if (((size == 2) ||");
539 out.println(iii + " (size == 3) ||");
540 out.println(iii + " (size == 4)) &&");
541 out.println(iii + " ((type == GL_FLOAT) ||");
542 out.println(iii + " (type == GL_BYTE) ||");
543 out.println(iii + " (type == GL_SHORT) ||");
544 out.println(iii + " (type == GL_FIXED)) &&");
545 out.println(iii + " (stride >= 0)) {");
546 out.println(iii + indent + "_vertexPointer = pointer;");
547 out.println(iii + "}");
548 }
549 }
550
551 // emitBoundsChecks(jfunc, out, iii);
552 emitFunctionCall(jfunc, out, iii, false);
553
554 boolean isVoid = jfunc.getType().isVoid();
555
556 if (!isVoid) {
557 out.println(indent + indent + "return _returnValue;");
558 }
559 out.println(indent + "}");
560 }
561 out.println();
562 }
563
564 public static String getJniName(JType jType) {
565 String jniName = "";
566 if (jType.isClass()) {
567 return "L" + jType.getBaseType() + ";";
568 } else if (jType.isArray()) {
569 jniName = "[";
570 }
571
572 String baseType = jType.getBaseType();
573 if (baseType.equals("int")) {
574 jniName += "I";
575 } else if (baseType.equals("float")) {
576 jniName += "F";
577 } else if (baseType.equals("boolean")) {
578 jniName += "Z";
579 } else if (baseType.equals("short")) {
580 jniName += "S";
581 } else if (baseType.equals("long")) {
582 jniName += "L";
583 } else if (baseType.equals("byte")) {
584 jniName += "B";
585 }
586 return jniName;
587 }
588
589 String getJniType(JType jType) {
590 if (jType.isVoid()) {
591 return "void";
592 }
593
594 String baseType = jType.getBaseType();
595 if (jType.isPrimitive()) {
596 if (baseType.equals("String")) {
597 return "jstring";
598 } else {
599 return "j" + baseType;
600 }
601 } else if (jType.isArray()) {
602 return "j" + baseType + "Array";
603 } else {
604 return "jobject";
605 }
606 }
607
608 String getJniMangledName(String name) {
609 name = name.replaceAll("_", "_1");
610 name = name.replaceAll(";", "_2");
611 name = name.replaceAll("\\[", "_3");
612 return name;
613 }
614
615 public void emitJniCode(JFunc jfunc, PrintStream out) {
616 CFunc cfunc = jfunc.getCFunc();
617
618 // Emit comment identifying original C function
619 //
620 // Example:
621 //
622 // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
623 //
624 out.println("/* " + cfunc.getOriginal() + " */");
625
626 // Emit JNI signature (name)
627 //
628 // Example:
629 //
630 // void
631 // android_glClipPlanef__I_3FI
632 //
633
634 String outName = "android_" + jfunc.getName();
635 boolean isPointerFunc = outName.endsWith("Pointer") &&
636 jfunc.getCFunc().hasPointerArg();
637 boolean isVBOPointerFunc = (outName.endsWith("Pointer") ||
638 outName.endsWith("DrawElements")) &&
639 !jfunc.getCFunc().hasPointerArg();
640 if (isPointerFunc) {
641 outName += "Bounds";
642 }
643
644 out.print("static ");
645 out.println(getJniType(jfunc.getType()));
646 out.print(outName);
647
648 String rsignature = getJniName(jfunc.getType());
649
650 String signature = "";
651 int numArgs = jfunc.getNumArgs();
652 for (int i = 0; i < numArgs; i++) {
653 JType argType = jfunc.getArgType(i);
654 signature += getJniName(argType);
655 }
656 if (isPointerFunc) {
657 signature += "I";
658 }
659
660 // Append signature to function name
661 String sig = getJniMangledName(signature).replace('.', '_');
662 out.print("__" + sig);
663 outName += "__" + sig;
664
665 signature = signature.replace('.', '/');
666 rsignature = rsignature.replace('.', '/');
667
668 out.println();
669 if (rsignature.length() == 0) {
670 rsignature = "V";
671 }
672
673 String s = "{\"" +
674 jfunc.getName() +
675 (isPointerFunc ? "Bounds" : "") +
676 "\", \"(" + signature +")" +
677 rsignature +
678 "\", (void *) " +
679 outName +
680 " },";
681 nativeRegistrations.add(s);
682
683 List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
684 int numBufferArgs = 0;
685 List<String> bufferArgNames = new ArrayList<String>();
686
687 // Emit JNI signature (arguments)
688 //
689 // Example:
690 //
691 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) {
692 //
693 out.print(" (JNIEnv *_env, jobject _this");
694 for (int i = 0; i < numArgs; i++) {
695 out.print(", ");
696 JType argType = jfunc.getArgType(i);
697 String suffix;
698 if (!argType.isPrimitive()) {
699 if (argType.isArray()) {
700 suffix = "_ref";
701 } else {
702 suffix = "_buf";
703 }
704 nonPrimitiveArgs.add(new Integer(i));
705 if (jfunc.getArgType(i).isBuffer()) {
706 int cIndex = jfunc.getArgCIndex(i);
707 String cname = cfunc.getArgName(cIndex);
708 bufferArgNames.add(cname);
709 numBufferArgs++;
710 }
711 } else {
712 suffix = "";
713 }
714
715 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
716 }
717 if (isPointerFunc) {
718 out.print(", jint remaining");
719 }
720 out.println(") {");
721
722 int numArrays = 0;
723 int numBuffers = 0;
724 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
725 int idx = nonPrimitiveArgs.get(i).intValue();
726 int cIndex = jfunc.getArgCIndex(idx);
727 String cname = cfunc.getArgName(cIndex);
728 if (jfunc.getArgType(idx).isArray()) {
729 ++numArrays;
730 }
731 if (jfunc.getArgType(idx).isBuffer()) {
732 ++numBuffers;
733 }
734 }
735
736 // Emit method body
737
738 // Emit local variable declarations for _exception and _returnValue
739 //
740 // Example:
741 //
742 // android::gl::ogles_context_t *ctx;
743 //
744 // jint _exception;
745 // GLenum _returnValue;
746 //
747 CType returnType = cfunc.getType();
748 boolean isVoid = returnType.isVoid();
749
750 boolean isUnsupported = isUnsupportedFunc(cfunc);
751 if (isUnsupported) {
752 out.println(indent +
753 "_env->ThrowNew(UOEClass,");
754 out.println(indent +
755 " \"" + cfunc.getName() + "\");");
756 if (!isVoid) {
757 String retval = getErrorReturnValue(cfunc);
758 out.println(indent + "return " + retval + ";");
759 }
760 out.println("}");
761 out.println();
762 return;
763 }
764
765 if (mUseContextPointer) {
766 out.println(indent +
767 "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
768 }
769
770 boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) &&
771 hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs);
772 // mChecker.getChecks(cfunc.getName()) != null
773
774 // Emit an _exeption variable if there will be error checks
775 if (emitExceptionCheck) {
776 out.println(indent + "jint _exception = 0;");
777 }
778
779 // Emit a single _array or multiple _XXXArray variables
780 if (numBufferArgs == 1) {
781 out.println(indent + "jarray _array = (jarray) 0;");
782 } else {
783 for (int i = 0; i < numBufferArgs; i++) {
784 out.println(indent + "jarray _" + bufferArgNames.get(i) +
785 "Array = (jarray) 0;");
786 }
787 }
788 if (!isVoid) {
789 String retval = getErrorReturnValue(cfunc);
790 if (retval != null) {
791 out.println(indent + returnType.getDeclaration() +
792 " _returnValue = " + retval + ";");
793 } else {
794 out.println(indent + returnType.getDeclaration() +
795 " _returnValue;");
796 }
797 }
798
799 // Emit local variable declarations for pointer arguments
800 //
801 // Example:
802 //
803 // GLfixed *eqn_base;
804 // GLfixed *eqn;
805 //
806 String offset = "offset";
807 String remaining = "_remaining";
808 if (nonPrimitiveArgs.size() > 0) {
809 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
810 int idx = nonPrimitiveArgs.get(i).intValue();
811 int cIndex = jfunc.getArgCIndex(idx);
812 String cname = cfunc.getArgName(cIndex);
813
814 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
815 String decl = type.getDeclaration();
816 if (jfunc.getArgType(idx).isArray()) {
817 out.println(indent +
818 decl +
819 (decl.endsWith("*") ? "" : " ") +
820 jfunc.getArgName(idx) +
821 "_base = (" + decl + ") 0;");
822 }
823 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
824 "_" + cname + "Remaining";
825 out.println(indent +
826 "jint " + remaining + ";");
827 out.println(indent +
828 decl +
829 (decl.endsWith("*") ? "" : " ") +
830 jfunc.getArgName(idx) +
831 " = (" + decl + ") 0;");
832 }
833
834 out.println();
835 }
836
837 String retval = isVoid ? "" : " _returnValue";
838
839 // Emit 'GetPrimitiveArrayCritical' for arrays
840 // Emit 'GetPointer' calls for Buffer pointers
841 int bufArgIdx = 0;
842 if (nonPrimitiveArgs.size() > 0) {
843 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
844 int idx = nonPrimitiveArgs.get(i).intValue();
845 int cIndex = jfunc.getArgCIndex(idx);
846
847 String cname = cfunc.getArgName(cIndex);
848 offset = numArrays <= 1 ? "offset" :
849 cname + "Offset";
850 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
851 "_" + cname + "Remaining";
852
853 if (jfunc.getArgType(idx).isArray()) {
854 out.println(indent +
855 "if (!" +
856 cname +
857 "_ref) {");
858 if (emitExceptionCheck) {
859 out.println(indent + indent + "_exception = 1;");
860 }
861 out.println(indent + " " +
862 (mUseCPlusPlus ? "_env" : "(*_env)") +
863 "->ThrowNew(" +
864 (mUseCPlusPlus ? "" : "_env, ") +
865 "IAEClass, " +
866 "\"" + cname +
867 " == null\");");
868 out.println(indent + " goto exit;");
869 needsExit = true;
870 out.println(indent + "}");
871
872 out.println(indent + "if (" + offset + " < 0) {");
873 if (emitExceptionCheck) {
874 out.println(indent + indent + "_exception = 1;");
875 }
876 out.println(indent + " " +
877 (mUseCPlusPlus ? "_env" : "(*_env)") +
878 "->ThrowNew(" +
879 (mUseCPlusPlus ? "" : "_env, ") +
880 "IAEClass, " +
881 "\"" + offset + " < 0\");");
882 out.println(indent + " goto exit;");
883 needsExit = true;
884 out.println(indent + "}");
885
886 out.println(indent + remaining + " = " +
887 (mUseCPlusPlus ? "_env" : "(*_env)") +
888 "->GetArrayLength(" +
889 (mUseCPlusPlus ? "" : "_env, ") +
890 cname + "_ref) - " + offset + ";");
891
892 emitNativeBoundsChecks(cfunc, cname, out, false,
893 emitExceptionCheck,
894 offset, remaining, " ");
895
896 out.println(indent +
897 cname +
898 "_base = (" +
899 cfunc.getArgType(cIndex).getDeclaration() +
900 ")");
901 out.println(indent + " " +
902 (mUseCPlusPlus ? "_env" : "(*_env)") +
903 "->GetPrimitiveArrayCritical(" +
904 (mUseCPlusPlus ? "" : "_env, ") +
905 jfunc.getArgName(idx) +
906 "_ref, (jboolean *)0);");
907 out.println(indent +
908 cname + " = " + cname + "_base + " + offset +
909 ";");
910 out.println();
911 } else {
912 String array = numBufferArgs <= 1 ? "_array" :
913 "_" + bufferArgNames.get(bufArgIdx++) + "Array";
914
915 boolean nullAllowed = isNullAllowed(cfunc);
916 if (nullAllowed) {
917 out.println(indent + "if (" + cname + "_buf) {");
918 out.print(indent);
919 }
920
921 out.println(indent +
922 cname +
923 " = (" +
924 cfunc.getArgType(cIndex).getDeclaration() +
925 ")getPointer(_env, " +
926 cname +
927 "_buf, &" + array + ", &" + remaining + ");");
928
929 if (nullAllowed) {
930 out.println(indent + "}");
931 }
932
933 emitNativeBoundsChecks(cfunc, cname, out, true,
934 emitExceptionCheck,
935 offset, remaining, " ");
936 }
937 }
938 }
939
940 if (!isVoid) {
941 out.print(indent + "_returnValue = ");
942 } else {
943 out.print(indent);
944 }
945 String name = cfunc.getName();
946
947 if (mUseContextPointer) {
948 name = name.substring(2, name.length()); // Strip off 'gl' prefix
949 name = name.substring(0, 1).toLowerCase() +
950 name.substring(1, name.length());
951 out.print("ctx->procs.");
952 }
953
954 out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
955
956 numArgs = cfunc.getNumArgs();
957 if (numArgs == 0) {
958 if (mUseContextPointer) {
959 out.println("ctx);");
960 } else {
961 out.println(");");
962 }
963 } else {
964 if (mUseContextPointer) {
965 out.println("ctx,");
966 } else {
967 out.println();
968 }
969 for (int i = 0; i < numArgs; i++) {
970 String typecast;
971 if (i == numArgs - 1 && isVBOPointerFunc) {
972 typecast = "const GLvoid *";
973 } else {
974 typecast = cfunc.getArgType(i).getDeclaration();
975 }
976 out.print(indent + indent +
977 "(" +
978 typecast +
979 ")" +
980 cfunc.getArgName(i));
981
982 if (i == numArgs - 1) {
983 if (isPointerFunc) {
984 out.println(",");
985 out.println(indent + indent + "(GLsizei)remaining");
986 } else {
987 out.println();
988 }
989 } else {
990 out.println(",");
991 }
992 }
993 out.println(indent + ");");
994 }
995
996 if (needsExit) {
997 out.println();
998 out.println("exit:");
999 needsExit = false;
1000 }
1001
1002 bufArgIdx = 0;
1003 if (nonPrimitiveArgs.size() > 0) {
1004 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
1005 int idx = nonPrimitiveArgs.get(i).intValue();
1006
1007 int cIndex = jfunc.getArgCIndex(idx);
1008 if (jfunc.getArgType(idx).isArray()) {
1009
1010 // If the argument is 'const', GL will not write to it.
1011 // In this case, we can use the 'JNI_ABORT' flag to avoid
1012 // the need to write back to the Java array
1013 out.println(indent +
1014 "if (" + jfunc.getArgName(idx) + "_base) {");
1015 out.println(indent + indent +
1016 (mUseCPlusPlus ? "_env" : "(*_env)") +
1017 "->ReleasePrimitiveArrayCritical(" +
1018 (mUseCPlusPlus ? "" : "_env, ") +
1019 jfunc.getArgName(idx) + "_ref, " +
1020 cfunc.getArgName(cIndex) +
1021 "_base,");
1022 out.println(indent + indent + indent +
1023 (cfunc.getArgType(cIndex).isConst() ?
1024 "JNI_ABORT" :
1025 "_exception ? JNI_ABORT: 0") +
1026 ");");
1027 out.println(indent + "}");
1028 } else if (jfunc.getArgType(idx).isBuffer()) {
1029 String array = numBufferArgs <= 1 ? "_array" :
1030 "_" + bufferArgNames.get(bufArgIdx++) + "Array";
1031 out.println(indent + "if (" + array + ") {");
1032 out.println(indent + indent +
1033 "releasePointer(_env, " + array + ", " +
1034 cfunc.getArgName(cIndex) +
1035 ", " +
1036 (cfunc.getArgType(cIndex).isConst() ?
1037 "JNI_FALSE" : "_exception ? JNI_FALSE : JNI_TRUE") +
1038 ");");
1039 out.println(indent + "}");
1040 }
1041 }
1042 }
1043
1044 if (!isVoid) {
1045 out.println(indent + "return _returnValue;");
1046 }
1047
1048 out.println("}");
1049 out.println();
1050 }
1051
1052 public void addNativeRegistration(String s) {
1053 nativeRegistrations.add(s);
1054 }
1055
1056 public void emitNativeRegistration() {
1057 mCStream.println("static const char *classPathName = \"" +
1058 mClassPathName +
1059 "\";");
1060 mCStream.println();
1061
1062 mCStream.println("static JNINativeMethod methods[] = {");
1063
1064 mCStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },");
1065
1066 Iterator<String> i = nativeRegistrations.iterator();
1067 while (i.hasNext()) {
1068 mCStream.println(i.next());
1069 }
1070
1071 mCStream.println("};");
1072 mCStream.println();
1073
1074
1075 mCStream.println("int register_com_google_android_gles_jni_GLImpl(JNIEnv *_env)");
1076 mCStream.println("{");
1077 mCStream.println(indent +
1078 "int err;");
1079
1080 mCStream.println(indent +
1081 "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));");
1082
1083 mCStream.println(indent + "return err;");
1084 mCStream.println("}");
1085 }
1086}