• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 import java.io.PrintStream;
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.List;
22 
23 public class JniCodeEmitter {
24 
25     static final boolean mUseCPlusPlus = true;
26     protected boolean mUseContextPointer = true;
27     protected boolean mUseStaticMethods = false;
28     protected boolean mUseSimpleMethodNames = false;
29     protected boolean mUseHideCommentForAPI = false;
30     protected String mClassPathName;
31     protected ParameterChecker mChecker;
32     protected List<String> nativeRegistrations = new ArrayList<String>();
33     boolean needsExit;
34     protected static String indent = "    ";
35     HashSet<String> mFunctionsEmitted = new HashSet<String>();
36 
getJniName(JType jType)37     public static String getJniName(JType jType) {
38         String jniName = "";
39         if (jType.isEGLHandle()) {
40             return (jType.isArray() ? "[" : "" ) + "Landroid/opengl/" + jType.getBaseType() + ";";
41         } else if (jType.isClass()) {
42             return "L" + jType.getBaseType() + ";";
43         } else if (jType.isArray()) {
44             jniName = "[";
45         }
46 
47         String baseType = jType.getBaseType();
48         if (baseType.equals("int")) {
49             jniName += "I";
50         } else if (baseType.equals("float")) {
51             jniName += "F";
52         } else if (baseType.equals("boolean")) {
53             jniName += "Z";
54         } else if (baseType.equals("short")) {
55             jniName += "S";
56         } else if (baseType.equals("long")) {
57             jniName += "J";
58         } else if (baseType.equals("byte")) {
59             jniName += "B";
60         } else if (baseType.equals("String")) {
61             jniName += "Ljava/lang/String;";
62         } else if (baseType.equals("void")) {
63             // nothing.
64         } else {
65             throw new RuntimeException("Unknown primitive basetype " + baseType);
66         }
67         return jniName;
68     }
69 
emitCode(CFunc cfunc, String original, PrintStream javaInterfaceStream, PrintStream javaImplStream, PrintStream cStream)70     public void emitCode(CFunc cfunc, String original,
71             PrintStream javaInterfaceStream,
72             PrintStream javaImplStream,
73             PrintStream cStream) {
74         JFunc jfunc;
75         String signature;
76         boolean duplicate;
77 
78         if (cfunc.hasTypedPointerArg()) {
79             jfunc = JFunc.convert(cfunc, true);
80 
81             // Don't emit duplicate functions
82             // These may appear because they are defined in multiple
83             // Java interfaces (e.g., GL11/GL11ExtensionPack)
84             signature = jfunc.toString();
85             duplicate = false;
86             if (mFunctionsEmitted.contains(signature)) {
87                 duplicate = true;
88             } else {
89                 mFunctionsEmitted.add(signature);
90             }
91 
92             if (!duplicate) {
93                 emitNativeDeclaration(jfunc, javaImplStream);
94                 emitJavaCode(jfunc, javaImplStream);
95             }
96             if (javaInterfaceStream != null) {
97                 emitJavaInterfaceCode(jfunc, javaInterfaceStream);
98             }
99             if (!duplicate) {
100                 emitJniCode(jfunc, cStream);
101             }
102             // Don't create IOBuffer versions of the EGL functions
103             if (cfunc.hasEGLHandleArg()) {
104                 return;
105             }
106         }
107 
108         jfunc = JFunc.convert(cfunc, false);
109 
110         signature = jfunc.toString();
111         duplicate = false;
112         if (mFunctionsEmitted.contains(signature)) {
113             duplicate = true;
114         } else {
115             mFunctionsEmitted.add(signature);
116         }
117 
118         if (!duplicate) {
119             emitNativeDeclaration(jfunc, javaImplStream);
120         }
121         if (javaInterfaceStream != null) {
122             emitJavaInterfaceCode(jfunc, javaInterfaceStream);
123         }
124         if (!duplicate) {
125             emitJavaCode(jfunc, javaImplStream);
126             emitJniCode(jfunc, cStream);
127         }
128     }
129 
emitNativeDeclaration(JFunc jfunc, PrintStream out)130     public void emitNativeDeclaration(JFunc jfunc, PrintStream out) {
131         if (mUseHideCommentForAPI) {
132             out.println("    /* @hide C function " + jfunc.getCFunc().getOriginal() + " */");
133             out.println();
134         } else {
135             out.println("    // C function " + jfunc.getCFunc().getOriginal());
136             out.println();
137         }
138 
139         emitFunction(jfunc, out, true, false);
140     }
141 
emitJavaInterfaceCode(JFunc jfunc, PrintStream out)142     public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) {
143         emitFunction(jfunc, out, false, true);
144     }
145 
emitJavaCode(JFunc jfunc, PrintStream out)146     public void emitJavaCode(JFunc jfunc, PrintStream out) {
147         emitFunction(jfunc, out, false, false);
148     }
149 
isPointerFunc(JFunc jfunc)150     boolean isPointerFunc(JFunc jfunc) {
151         String name = jfunc.getName();
152         return (name.endsWith("Pointer") || name.endsWith("PointerOES"))
153             && jfunc.getCFunc().hasPointerArg();
154     }
155 
emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray)156     void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) {
157         boolean isVoid = jfunc.getType().isVoid();
158         boolean isPointerFunc = isPointerFunc(jfunc);
159 
160         if (!isVoid) {
161             out.println(iii +
162                         jfunc.getType() + " _returnValue;");
163         }
164         out.println(iii +
165                     (isVoid ? "" : "_returnValue = ") +
166                     jfunc.getName() +
167                     (isPointerFunc ? "Bounds" : "" ) +
168                     "(");
169 
170         int numArgs = jfunc.getNumArgs();
171         for (int i = 0; i < numArgs; i++) {
172             String argName = jfunc.getArgName(i);
173             JType argType = jfunc.getArgType(i);
174 
175             if (grabArray && argType.isTypedBuffer()) {
176                 String typeName = argType.getBaseType();
177                 typeName = typeName.substring(9, typeName.length() - 6);
178                 out.println(iii + indent + "get" + typeName + "Array(" + argName + "),");
179                 out.print(iii + indent + "getOffset(" + argName + ")");
180             } else {
181                 out.print(iii + indent + argName);
182             }
183             if (i == numArgs - 1) {
184                 if (isPointerFunc) {
185                     out.println(",");
186                     out.println(iii + indent + argName + ".remaining()");
187                 } else {
188                     out.println();
189                 }
190             } else {
191                 out.println(",");
192             }
193         }
194 
195         out.println(iii + ");");
196     }
197 
printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String iii)198     void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
199             String iii) {
200         printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
201                 "offset", "_remaining", iii);
202     }
203 
printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii)204     void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
205             String offset, String remaining, String iii) {
206         out.println(iii + "    default:");
207         out.println(iii + "        _needed = 1;");
208         out.println(iii + "        break;");
209         out.println(iii + "}");
210 
211         out.println(iii + "if (" + remaining + " < _needed) {");
212         out.println(iii + indent + "_exception = 1;");
213         out.println(iii + indent +
214                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
215         out.println(iii + indent +
216                 "_exceptionMessage = \"" +
217                 (isBuffer ? "remaining()" : "length - " + offset) +
218                 " < needed\";");
219         out.println(iii + indent + "goto exit;");
220         out.println(iii + "}");
221 
222         needsExit = true;
223     }
224 
isNullAllowed(CFunc cfunc)225     boolean isNullAllowed(CFunc cfunc) {
226         String[] checks = mChecker.getChecks(cfunc.getName());
227         int index = 1;
228         if (checks != null) {
229             while (index < checks.length) {
230                 if (checks[index].equals("nullAllowed")) {
231                     return true;
232                 } else {
233                     index = skipOneCheck(checks, index);
234                 }
235             }
236         }
237         return false;
238     }
239 
hasCheckTest(CFunc cfunc)240     boolean hasCheckTest(CFunc cfunc) {
241         String[] checks = mChecker.getChecks(cfunc.getName());
242         int index = 1;
243         if (checks != null) {
244             while (index < checks.length) {
245                 if (checks[index].startsWith("check")) {
246                     return true;
247                 } else {
248                     index = skipOneCheck(checks, index);
249                 }
250             }
251         }
252         return false;
253     }
254 
hasIfTest(CFunc cfunc)255     boolean hasIfTest(CFunc cfunc) {
256         String[] checks = mChecker.getChecks(cfunc.getName());
257         int index = 1;
258         if (checks != null) {
259             while (index < checks.length) {
260                 if (checks[index].startsWith("ifcheck")) {
261                     return true;
262                 } else {
263                     index = skipOneCheck(checks, index);
264                 }
265             }
266         }
267         return false;
268     }
269 
skipOneCheck(String[] checks, int index)270     int skipOneCheck(String[] checks, int index) {
271         if (checks[index].equals("return")) {
272             index += 2;
273         } else if (checks[index].startsWith("check")) {
274             index += 3;
275         } else if (checks[index].startsWith("sentinel")) {
276             index += 3;
277         } else if (checks[index].equals("ifcheck")) {
278             index += 5;
279         } else if (checks[index].equals("unsupported")) {
280             index += 1;
281         } else if (checks[index].equals("requires")) {
282             index += 2;
283         } else if (checks[index].equals("nullAllowed")) {
284             index += 1;
285         } else {
286             System.out.println("Error: unknown keyword \"" +
287                                checks[index] + "\"");
288             System.exit(0);
289         }
290 
291         return index;
292     }
293 
getErrorReturnValue(CFunc cfunc)294     String getErrorReturnValue(CFunc cfunc) {
295         CType returnType = cfunc.getType();
296         boolean isVoid = returnType.isVoid();
297         if (isVoid) {
298             return null;
299         }
300 
301         if (returnType.getBaseType().startsWith("EGL")) {
302             return "(" + returnType.getDeclaration() + ") 0";
303         }
304 
305         String[] checks = mChecker.getChecks(cfunc.getName());
306 
307         int index = 1;
308         if (checks != null) {
309             while (index < checks.length) {
310                 if (checks[index].equals("return")) {
311                     return checks[index + 1];
312                 } else {
313                     index = skipOneCheck(checks, index);
314                 }
315             }
316         }
317 
318         return null;
319     }
320 
isUnsupportedFunc(CFunc cfunc)321     boolean isUnsupportedFunc(CFunc cfunc) {
322         String[] checks = mChecker.getChecks(cfunc.getName());
323         int index = 1;
324         if (checks != null) {
325             while (index < checks.length) {
326                 if (checks[index].equals("unsupported")) {
327                     return true;
328                 } else {
329                     index = skipOneCheck(checks, index);
330                 }
331             }
332         }
333         return false;
334     }
335 
isRequiresFunc(CFunc cfunc)336     String isRequiresFunc(CFunc cfunc) {
337         String[] checks = mChecker.getChecks(cfunc.getName());
338         int index = 1;
339         if (checks != null) {
340             while (index < checks.length) {
341                 if (checks[index].equals("requires")) {
342                     return checks[index+1];
343                 } else {
344                     index = skipOneCheck(checks, index);
345                 }
346             }
347         }
348         return null;
349     }
350 
emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii)351     void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
352             boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) {
353 
354         String[] checks = mChecker.getChecks(cfunc.getName());
355 
356         boolean lastWasIfcheck = false;
357 
358         int index = 1;
359         if (checks != null) {
360             while (index < checks.length) {
361                 if (checks[index].startsWith("check")) {
362                     if (lastWasIfcheck) {
363                         printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
364                                 offset, remaining, iii);
365                     }
366                     lastWasIfcheck = false;
367                     if (cname != null && !cname.equals(checks[index + 1])) {
368                         index += 3;
369                         continue;
370                     }
371                     out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {");
372                     out.println(iii + indent + "_exception = 1;");
373                     String exceptionClassName = "java/lang/IllegalArgumentException";
374                     // If the "check" keyword was of the form
375                     // "check_<class name>", use the class name in the
376                     // exception to be thrown
377                     int underscore = checks[index].indexOf('_');
378                     if (underscore >= 0) {
379                         String abbr = checks[index].substring(underscore + 1);
380                         if (abbr.equals("AIOOBE")) {
381                             exceptionClassName = "java/lang/ArrayIndexOutOfBoundsException";
382                         } else {
383                             throw new RuntimeException("unknown exception abbreviation: " + abbr);
384                         }
385                     }
386                     out.println(iii + indent +
387                                 "_exceptionType = \""+exceptionClassName+"\";");
388                     out.println(iii + indent +
389                                "_exceptionMessage = \"" +
390                                (isBuffer ? "remaining()" : "length - " +
391                                offset) + " < " + checks[index + 2] +
392                                " < needed\";");
393 
394                     out.println(iii + indent + "goto exit;");
395                     out.println(iii + "}");
396 
397                     needsExit = true;
398 
399                     index += 3;
400                 } else if (checks[index].equals("ifcheck")) {
401                     String[] matches = checks[index + 4].split(",");
402 
403                     if (!lastWasIfcheck) {
404                         out.println(iii + "int _needed;");
405                         out.println(iii + "switch (" + checks[index + 3] + ") {");
406                     }
407 
408                     for (int i = 0; i < matches.length; i++) {
409                         out.println("#if defined(" + matches[i] + ")");
410                         out.println(iii + "    case " + matches[i] + ":");
411                         out.println("#endif // defined(" + matches[i] + ")");
412                     }
413                     out.println(iii + "        _needed = " + checks[index + 2] + ";");
414                     out.println(iii + "        break;");
415 
416                     lastWasIfcheck = true;
417                     index += 5;
418                 } else {
419                     index = skipOneCheck(checks, index);
420                 }
421             }
422         }
423 
424         if (lastWasIfcheck) {
425             printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
426         }
427     }
428 
emitSentinelCheck(CFunc cfunc, String cname, PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii)429     void emitSentinelCheck(CFunc cfunc, String cname, PrintStream out,
430             boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) {
431 
432         String[] checks = mChecker.getChecks(cfunc.getName());
433 
434         int index = 1;
435         if (checks != null) {
436             while (index < checks.length) {
437                 if (checks[index].startsWith("sentinel")) {
438                     if (cname != null && !cname.equals(checks[index + 1])) {
439                         index += 3;
440                         continue;
441                     }
442 
443                     out.println(iii + cname + "_sentinel = false;");
444                     out.println(iii + "for (int i = " + remaining +
445                                 " - 1; i >= 0; i--)  {");
446                     out.println(iii + indent + "if (" + cname +
447                                 "[i] == " + checks[index + 2] + "){");
448                     out.println(iii + indent + indent +
449                                 cname + "_sentinel = true;");
450                     out.println(iii + indent + indent + "break;");
451                     out.println(iii + indent + "}");
452                     out.println(iii + "}");
453                     out.println(iii +
454                                 "if (" + cname + "_sentinel == false) {");
455                     out.println(iii + indent + "_exception = 1;");
456                     out.println(iii + indent +
457                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
458                     out.println(iii + indent + "_exceptionMessage = \"" + cname +
459                                 " must contain " + checks[index + 2] + "!\";");
460                     out.println(iii + indent + "goto exit;");
461                     out.println(iii + "}");
462 
463                     needsExit = true;
464                     index += 3;
465                 } else {
466                     index = skipOneCheck(checks, index);
467                 }
468             }
469         }
470     }
471 
emitLocalVariablesForSentinel(CFunc cfunc, PrintStream out)472     void emitLocalVariablesForSentinel(CFunc cfunc, PrintStream out) {
473 
474         String[] checks = mChecker.getChecks(cfunc.getName());
475 
476         int index = 1;
477         if (checks != null) {
478             while (index < checks.length) {
479                 if (checks[index].startsWith("sentinel")) {
480                     String cname = checks[index + 1];
481                     out.println(indent + "bool " + cname + "_sentinel = false;");
482 
483                     index += 3;
484 
485                 } else {
486                     index = skipOneCheck(checks, index);
487                 }
488             }
489         }
490     }
491 
hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs)492     boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) {
493         if (nonPrimitiveArgs.size() > 0) {
494             for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
495                 int idx = nonPrimitiveArgs.get(i).intValue();
496                 int cIndex = jfunc.getArgCIndex(idx);
497                 if (jfunc.getArgType(idx).isArray()) {
498                     if (!cfunc.getArgType(cIndex).isConst()) {
499                         return true;
500                     }
501                 } else if (jfunc.getArgType(idx).isBuffer()) {
502                     if (!cfunc.getArgType(cIndex).isConst()) {
503                         return true;
504                     }
505                 }
506             }
507         }
508 
509         return false;
510     }
511 
512     /**
513      * Emit a function in several variants:
514      *
515      * if nativeDecl: public native <returntype> func(args);
516      *
517      * if !nativeDecl:
518      *   if interfaceDecl:  public <returntype> func(args);
519      *   if !interfaceDecl: public <returntype> func(args) { body }
520      */
emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl)521     void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) {
522         boolean isPointerFunc = isPointerFunc(jfunc);
523 
524         if (!nativeDecl && !interfaceDecl && !isPointerFunc) {
525             // If it's not a pointer function, we've already emitted it
526             // with nativeDecl == true
527             return;
528         }
529 
530         String maybeStatic = mUseStaticMethods ? "static " : "";
531 
532         if (isPointerFunc) {
533             out.println(indent +
534                         (nativeDecl ? "private " + maybeStatic +"native " :
535                          (interfaceDecl ? "" : "public ") + maybeStatic) +
536                         jfunc.getType() + " " +
537                         jfunc.getName() +
538                         (nativeDecl ? "Bounds" : "") +
539                         "(");
540         } else {
541             out.println(indent +
542                         (nativeDecl ? "public " + maybeStatic +"native " :
543                          (interfaceDecl ? "" : "public ") + maybeStatic) +
544                         jfunc.getType() + " " +
545                         jfunc.getName() +
546                         "(");
547         }
548 
549         int numArgs = jfunc.getNumArgs();
550         for (int i = 0; i < numArgs; i++) {
551             String argName = jfunc.getArgName(i);
552             JType argType = jfunc.getArgType(i);
553 
554             out.print(indent + indent + argType + " " + argName);
555             if (i == numArgs - 1) {
556                 if (isPointerFunc && nativeDecl) {
557                     out.println(",");
558                     out.println(indent + indent + "int remaining");
559                 } else {
560                     out.println();
561                 }
562             } else {
563                 out.println(",");
564             }
565         }
566 
567         if (nativeDecl || interfaceDecl) {
568             out.println(indent + ");");
569         } else {
570             out.println(indent + ") {");
571 
572             String iii = indent + indent;
573 
574             // emitBoundsChecks(jfunc, out, iii);
575             emitFunctionCall(jfunc, out, iii, false);
576 
577             // Set the pointer after we call the native code, so that if
578             // the native code throws an exception we don't modify the
579             // pointer. We assume that the native code is written so that
580             // if an exception is thrown, then the underlying glXXXPointer
581             // function will not have been called.
582 
583             String fname = jfunc.getName();
584             if (isPointerFunc) {
585                 // TODO - deal with VBO variants
586                 if (fname.equals("glColorPointer")) {
587                     out.println(iii + "if ((size == 4) &&");
588                     out.println(iii + "    ((type == GL_FLOAT) ||");
589                     out.println(iii + "     (type == GL_UNSIGNED_BYTE) ||");
590                     out.println(iii + "     (type == GL_FIXED)) &&");
591                     out.println(iii + "    (stride >= 0)) {");
592                     out.println(iii + indent + "_colorPointer = pointer;");
593                     out.println(iii + "}");
594                 } else if (fname.equals("glNormalPointer")) {
595                     out.println(iii + "if (((type == GL_FLOAT) ||");
596                     out.println(iii + "     (type == GL_BYTE) ||");
597                     out.println(iii + "     (type == GL_SHORT) ||");
598                     out.println(iii + "     (type == GL_FIXED)) &&");
599                     out.println(iii + "    (stride >= 0)) {");
600                     out.println(iii + indent + "_normalPointer = pointer;");
601                     out.println(iii + "}");
602                 } else if (fname.equals("glTexCoordPointer")) {
603                     out.println(iii + "if (((size == 2) ||");
604                     out.println(iii + "     (size == 3) ||");
605                     out.println(iii + "     (size == 4)) &&");
606                     out.println(iii + "    ((type == GL_FLOAT) ||");
607                     out.println(iii + "     (type == GL_BYTE) ||");
608                     out.println(iii + "     (type == GL_SHORT) ||");
609                     out.println(iii + "     (type == GL_FIXED)) &&");
610                     out.println(iii + "    (stride >= 0)) {");
611                     out.println(iii + indent + "_texCoordPointer = pointer;");
612                     out.println(iii + "}");
613                 } else if (fname.equals("glVertexPointer")) {
614                     out.println(iii + "if (((size == 2) ||");
615                     out.println(iii + "     (size == 3) ||");
616                     out.println(iii + "     (size == 4)) &&");
617                     out.println(iii + "    ((type == GL_FLOAT) ||");
618                     out.println(iii + "     (type == GL_BYTE) ||");
619                     out.println(iii + "     (type == GL_SHORT) ||");
620                     out.println(iii + "     (type == GL_FIXED)) &&");
621                     out.println(iii + "    (stride >= 0)) {");
622                     out.println(iii + indent + "_vertexPointer = pointer;");
623                     out.println(iii + "}");
624                 } else if (fname.equals("glPointSizePointerOES")) {
625                     out.println(iii + "if (((type == GL_FLOAT) ||");
626                     out.println(iii + "     (type == GL_FIXED)) &&");
627                     out.println(iii + "    (stride >= 0)) {");
628                     out.println(iii + indent + "_pointSizePointerOES = pointer;");
629                     out.println(iii + "}");
630                 } else if (fname.equals("glMatrixIndexPointerOES")) {
631                     out.println(iii + "if (((size == 2) ||");
632                     out.println(iii + "     (size == 3) ||");
633                     out.println(iii + "     (size == 4)) &&");
634                     out.println(iii + "    ((type == GL_FLOAT) ||");
635                     out.println(iii + "     (type == GL_BYTE) ||");
636                     out.println(iii + "     (type == GL_SHORT) ||");
637                     out.println(iii + "     (type == GL_FIXED)) &&");
638                     out.println(iii + "    (stride >= 0)) {");
639                     out.println(iii + indent + "_matrixIndexPointerOES = pointer;");
640                     out.println(iii + "}");
641                 } else if (fname.equals("glWeightPointer")) {
642                     out.println(iii + "if (((size == 2) ||");
643                     out.println(iii + "     (size == 3) ||");
644                     out.println(iii + "     (size == 4)) &&");
645                     out.println(iii + "    ((type == GL_FLOAT) ||");
646                     out.println(iii + "     (type == GL_BYTE) ||");
647                     out.println(iii + "     (type == GL_SHORT) ||");
648                     out.println(iii + "     (type == GL_FIXED)) &&");
649                     out.println(iii + "    (stride >= 0)) {");
650                     out.println(iii + indent + "_weightPointerOES = pointer;");
651                     out.println(iii + "}");
652                 }
653             }
654 
655             boolean isVoid = jfunc.getType().isVoid();
656 
657             if (!isVoid) {
658                 out.println(indent + indent + "return _returnValue;");
659             }
660             out.println(indent + "}");
661         }
662         out.println();
663     }
664 
addNativeRegistration(String s)665     public void addNativeRegistration(String s) {
666         nativeRegistrations.add(s);
667     }
668 
emitNativeRegistration(String registrationFunctionName, PrintStream cStream)669     public void emitNativeRegistration(String registrationFunctionName,
670             PrintStream cStream) {
671         cStream.println("static const char *classPathName = \"" +
672                         mClassPathName +
673                         "\";");
674         cStream.println();
675 
676         cStream.println("static JNINativeMethod methods[] = {");
677 
678         cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },");
679 
680         Iterator<String> i = nativeRegistrations.iterator();
681         while (i.hasNext()) {
682             cStream.println(i.next());
683         }
684 
685         cStream.println("};");
686         cStream.println();
687 
688 
689         cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)");
690         cStream.println("{");
691         cStream.println(indent +
692                         "int err;");
693 
694         cStream.println(indent +
695                         "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));");
696 
697         cStream.println(indent + "return err;");
698         cStream.println("}");
699     }
700 
JniCodeEmitter()701     public JniCodeEmitter() {
702         super();
703     }
704 
getJniType(JType jType)705     String getJniType(JType jType) {
706         if (jType.isVoid()) {
707             return "void";
708         }
709 
710         String baseType = jType.getBaseType();
711         if (jType.isPrimitive()) {
712             if (baseType.equals("String")) {
713                 return "jstring";
714             } else {
715                 return "j" + baseType;
716             }
717         } else if (jType.isArray()) {
718             return jType.isClass() ? "jobjectArray" : "j" + baseType + "Array";
719         } else {
720             return "jobject";
721         }
722     }
723 
getJniMangledName(String name)724     String getJniMangledName(String name) {
725         name = name.replaceAll("_", "_1");
726         name = name.replaceAll(";", "_2");
727         name = name.replaceAll("\\[", "_3");
728         return name;
729     }
730 
emitJniCode(JFunc jfunc, PrintStream out)731     public void emitJniCode(JFunc jfunc, PrintStream out) {
732         CFunc cfunc = jfunc.getCFunc();
733 
734         // Emit comment identifying original C function
735         //
736         // Example:
737         //
738         // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
739         //
740         out.println("/* " + cfunc.getOriginal() + " */");
741 
742         // Emit JNI signature (name)
743         //
744         // Example:
745         //
746         // void
747         // android_glClipPlanef__I_3FI
748         //
749 
750         String outName = "android_" + jfunc.getName();
751         boolean isPointerFunc = isPointerFunc(jfunc);
752         boolean isPointerOffsetFunc =
753             (outName.endsWith("Pointer") || outName.endsWith("PointerOES") ||
754              outName.endsWith("glDrawElements") ||
755              outName.endsWith("glDrawRangeElements") ||
756              outName.endsWith("glTexImage2D") ||
757              outName.endsWith("glTexSubImage2D") ||
758              outName.endsWith("glCompressedTexImage2D") ||
759              outName.endsWith("glCompressedTexSubImage2D") ||
760              outName.endsWith("glTexImage3D") ||
761              outName.endsWith("glTexSubImage3D") ||
762              outName.endsWith("glCompressedTexImage3D") ||
763              outName.endsWith("glCompressedTexSubImage3D") ||
764              outName.endsWith("glReadPixels"))
765             && !jfunc.getCFunc().hasPointerArg();
766         if (isPointerFunc) {
767             outName += "Bounds";
768         }
769 
770         out.print("static ");
771         out.println(getJniType(jfunc.getType()));
772         out.print(outName);
773 
774         String rsignature = getJniName(jfunc.getType());
775 
776         String signature = "";
777         int numArgs = jfunc.getNumArgs();
778         for (int i = 0; i < numArgs; i++) {
779             JType argType = jfunc.getArgType(i);
780             signature += getJniName(argType);
781         }
782         if (isPointerFunc) {
783             signature += "I";
784         }
785 
786         // Append signature to function name
787         String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_');
788         if (!mUseSimpleMethodNames) {
789             out.print("__" + sig);
790             outName += "__" + sig;
791         }
792 
793         signature = signature.replace('.', '/');
794         rsignature = rsignature.replace('.', '/');
795 
796         out.println();
797         if (rsignature.length() == 0) {
798             rsignature = "V";
799         }
800 
801         String s = "{\"" +
802             jfunc.getName() +
803             (isPointerFunc ? "Bounds" : "") +
804             "\", \"(" + signature +")" +
805             rsignature +
806             "\", (void *) " +
807             outName +
808             " },";
809         nativeRegistrations.add(s);
810 
811         List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
812         List<Integer> stringArgs = new ArrayList<Integer>();
813         int numBufferArgs = 0;
814         List<String> bufferArgNames = new ArrayList<String>();
815 
816         // Emit JNI signature (arguments)
817         //
818         // Example:
819         //
820         // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) {
821         //
822         out.print("  (JNIEnv *_env, jobject _this");
823         for (int i = 0; i < numArgs; i++) {
824             out.print(", ");
825             JType argType = jfunc.getArgType(i);
826             String suffix = "";
827             if (!argType.isPrimitive()) {
828                 if (argType.isArray()) {
829                     suffix = "_ref";
830                 } else if (argType.isBuffer()) {
831                     suffix = "_buf";
832                 }
833                 nonPrimitiveArgs.add(new Integer(i));
834                 if (jfunc.getArgType(i).isBuffer()) {
835                     int cIndex = jfunc.getArgCIndex(i);
836                     String cname = cfunc.getArgName(cIndex);
837                     bufferArgNames.add(cname);
838                     numBufferArgs++;
839                 }
840             }
841 
842             if (argType.isString()) {
843                 stringArgs.add(new Integer(i));
844             }
845 
846             out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
847         }
848         if (isPointerFunc) {
849             out.print(", jint remaining");
850         }
851         out.println(") {");
852 
853         int numArrays = 0;
854         int numBuffers = 0;
855         int numStrings = 0;
856         for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
857             int idx = nonPrimitiveArgs.get(i).intValue();
858             JType argType = jfunc.getArgType(idx);
859             if (argType.isArray()) {
860                 ++numArrays;
861             }
862             if (argType.isBuffer()) {
863                 ++numBuffers;
864             }
865             if (argType.isString()) {
866                 ++numStrings;
867             }
868         }
869 
870         // Emit method body
871 
872         // Emit local variable declarations for _exception and _returnValue
873         //
874         // Example:
875         //
876         // android::gl::ogles_context_t *ctx;
877         //
878         // jint _exception;
879         // GLenum _returnValue;
880         //
881         CType returnType = cfunc.getType();
882         boolean isVoid = returnType.isVoid();
883 
884         boolean isUnsupported = isUnsupportedFunc(cfunc);
885         if (isUnsupported) {
886             out.println(indent +
887                         "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
888             out.println(indent +
889                         "    \"" + cfunc.getName() + "\");");
890             if (!isVoid) {
891                 String retval = getErrorReturnValue(cfunc);
892                 if (cfunc.getType().isEGLHandle()) {
893                     String baseType = cfunc.getType().getBaseType().toLowerCase();
894                     out.println(indent +
895                                 "return toEGLHandle(_env, " + baseType + "Class, " +
896                                 baseType + "Constructor, " + retval + ");");
897                 } else {
898                     out.println(indent + "return " + retval + ";");
899                 }
900             }
901             out.println("}");
902             out.println();
903             return;
904         }
905 
906         String requiresExtension = isRequiresFunc(cfunc);
907         if (requiresExtension != null) {
908             out.println(indent +
909                         "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {");
910             out.println(indent + indent +
911                         "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
912             out.println(indent + indent +
913                         "    \"" + cfunc.getName() + "\");");
914             if (isVoid) {
915                 out.println(indent + indent + "    return;");
916             } else {
917                 String retval = getErrorReturnValue(cfunc);
918                 if (cfunc.getType().isEGLHandle()) {
919                     String baseType = cfunc.getType().getBaseType().toLowerCase();
920                     out.println(indent +
921                                 "return toEGLHandle(_env, " + baseType + "Class, " +
922                                 baseType + "Constructor, " + retval + ");");
923                 } else {
924                     out.println(indent + "return " + retval + ";");
925                 }
926             }
927             out.println(indent + "}");
928         }
929         if (mUseContextPointer) {
930             out.println(indent +
931                 "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
932         }
933 
934         boolean initializeReturnValue = stringArgs.size() > 0;
935         boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0)
936                                              && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs)
937                                                  || (cfunc.hasPointerArg() && numArrays > 0))
938                                          || hasCheckTest(cfunc)
939                                          || hasIfTest(cfunc))
940                                          || (stringArgs.size() > 0);
941         // mChecker.getChecks(cfunc.getName()) != null
942         // Emit an _exeption variable if there will be error checks
943         if (emitExceptionCheck) {
944             out.println(indent + "jint _exception = 0;");
945             out.println(indent + "const char * _exceptionType = NULL;");
946             out.println(indent + "const char * _exceptionMessage = NULL;");
947         }
948 
949         // Emit a single _array or multiple _XXXArray variables
950         if (numBufferArgs == 1) {
951                 out.println(indent + "jarray _array = (jarray) 0;");
952                 out.println(indent + "jint _bufferOffset = (jint) 0;");
953         } else {
954             for (int i = 0; i < numBufferArgs; i++) {
955                 out.println(indent + "jarray _" + bufferArgNames.get(i) +
956                             "Array = (jarray) 0;");
957                 out.println(indent + "jint _" + bufferArgNames.get(i) +
958                             "BufferOffset = (jint) 0;");
959             }
960         }
961         if (!isVoid) {
962             String retval = getErrorReturnValue(cfunc);
963             if (retval != null) {
964                 out.println(indent + returnType.getDeclaration() +
965                             " _returnValue = " + retval + ";");
966             } else if (initializeReturnValue) {
967                 out.println(indent + returnType.getDeclaration() +
968                             " _returnValue = 0;");
969             } else {
970                 out.println(indent + returnType.getDeclaration() +
971                             " _returnValue;");
972             }
973         }
974 
975         // Emit local variable declarations for EGL Handles
976         //
977         // Example:
978         //
979         // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface);
980         //
981         if (nonPrimitiveArgs.size() > 0) {
982             for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
983                 int idx = nonPrimitiveArgs.get(i).intValue();
984                 int cIndex = jfunc.getArgCIndex(idx);
985                 String cname = cfunc.getArgName(cIndex);
986 
987                 if (jfunc.getArgType(idx).isBuffer()
988                    || jfunc.getArgType(idx).isArray()
989                    || !jfunc.getArgType(idx).isEGLHandle())
990                     continue;
991 
992                 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
993                 String decl = type.getDeclaration();
994                 out.println(indent +
995                             decl + " " + cname + "_native = (" +
996                             decl + ") fromEGLHandle(_env, " +
997                             type.getBaseType().toLowerCase() +
998                             "GetHandleID, " + jfunc.getArgName(idx) +
999                             ");");
1000             }
1001         }
1002 
1003         // Emit local variable declarations for element/sentinel checks
1004         //
1005         // Example:
1006         //
1007         // bool attrib_list_sentinel_found = false;
1008         //
1009         emitLocalVariablesForSentinel(cfunc, out);
1010 
1011         // Emit local variable declarations for pointer arguments
1012         //
1013         // Example:
1014         //
1015         // GLfixed *eqn_base;
1016         // GLfixed *eqn;
1017         //
1018         String offset = "offset";
1019         String remaining = "_remaining";
1020         if (nonPrimitiveArgs.size() > 0) {
1021             for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
1022                 int idx = nonPrimitiveArgs.get(i).intValue();
1023                 int cIndex = jfunc.getArgCIndex(idx);
1024                 String cname = cfunc.getArgName(cIndex);
1025 
1026                 if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray())
1027                     continue;
1028 
1029                 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
1030                 String decl = type.getDeclaration();
1031                 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) {
1032                     out.println(indent +
1033                                 decl +
1034                                 (decl.endsWith("*") ? "" : " ") +
1035                                 jfunc.getArgName(idx) +
1036                                 "_base = (" + decl + ") 0;");
1037                 }
1038                 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
1039                     "_" + cname + "Remaining";
1040                 out.println(indent +
1041                             "jint " + remaining + ";");
1042                 out.println(indent +
1043                                 decl +
1044                                 (decl.endsWith("*") ? "" : " ") +
1045                                 jfunc.getArgName(idx) +
1046                                 " = (" + decl + ") 0;");
1047             }
1048 
1049             out.println();
1050         }
1051 
1052         // Emit local variable declaration for strings
1053         if (stringArgs.size() > 0) {
1054             for (int i = 0; i < stringArgs.size(); i++) {
1055                 int idx = stringArgs.get(i).intValue();
1056                 int cIndex = jfunc.getArgCIndex(idx);
1057                 String cname = cfunc.getArgName(cIndex);
1058 
1059                 out.println(indent + "const char* _native" + cname + " = 0;");
1060             }
1061 
1062             out.println();
1063         }
1064 
1065         // Null pointer checks and GetStringUTFChars
1066         if (stringArgs.size() > 0) {
1067             for (int i = 0; i < stringArgs.size(); i++) {
1068                 int idx = stringArgs.get(i).intValue();
1069                 int cIndex = jfunc.getArgCIndex(idx);
1070                 String cname = cfunc.getArgName(cIndex);
1071 
1072                 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
1073                 String decl = type.getDeclaration();
1074                 needsExit = true;
1075                 out.println(indent + "if (!" + cname + ") {");
1076                 out.println(indent + indent +
1077                             "_exceptionType = \"java/lang/IllegalArgumentException\";");
1078                 out.println(indent + indent +
1079                             "_exceptionMessage = \"" + cname + " == null\";");
1080                 out.println(indent + indent + "goto exit;");
1081                 out.println(indent + "}");
1082 
1083                 out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);");
1084             }
1085 
1086             out.println();
1087         }
1088 
1089         // Emit 'GetPrimitiveArrayCritical' for non-object arrays
1090         // Emit 'GetPointer' calls for Buffer pointers
1091         if (nonPrimitiveArgs.size() > 0) {
1092             for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
1093                 int idx = nonPrimitiveArgs.get(i).intValue();
1094                 int cIndex = jfunc.getArgCIndex(idx);
1095 
1096                 String cname = cfunc.getArgName(cIndex);
1097                 offset = numArrays <= 1 ? "offset" :
1098                     cname + "Offset";
1099                 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
1100                     "_" + cname + "Remaining";
1101 
1102                 if (jfunc.getArgType(idx).isArray()
1103                        && !jfunc.getArgType(idx).isEGLHandle()) {
1104                     needsExit = true;
1105                     out.println(indent + "if (!" + cname + "_ref) {");
1106                     out.println(indent + indent + "_exception = 1;");
1107                     out.println(indent + indent +
1108                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
1109                     out.println(indent + indent +
1110                                 "_exceptionMessage = \"" + cname +" == null\";");
1111                     out.println(indent + indent + "goto exit;");
1112                     out.println(indent + "}");
1113                     out.println(indent + "if (" + offset + " < 0) {");
1114                     out.println(indent + indent + "_exception = 1;");
1115                     out.println(indent + indent +
1116                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
1117                     out.println(indent + indent +
1118                                 "_exceptionMessage = \"" + offset +" < 0\";");
1119                     out.println(indent + indent + "goto exit;");
1120                     out.println(indent + "}");
1121 
1122                     out.println(indent + remaining + " = " +
1123                                     (mUseCPlusPlus ? "_env" : "(*_env)") +
1124                                     "->GetArrayLength(" +
1125                                     (mUseCPlusPlus ? "" : "_env, ") +
1126                                     cname + "_ref) - " + offset + ";");
1127 
1128                     emitNativeBoundsChecks(cfunc, cname, out, false,
1129                                            emitExceptionCheck,
1130                                            offset, remaining, "    ");
1131 
1132                     out.println(indent +
1133                                 cname +
1134                                 "_base = (" +
1135                                 cfunc.getArgType(cIndex).getDeclaration() +
1136                                 ")");
1137                     out.println(indent + "    " +
1138                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
1139                                 "->GetPrimitiveArrayCritical(" +
1140                                 (mUseCPlusPlus ? "" : "_env, ") +
1141                                 jfunc.getArgName(idx) +
1142                                 "_ref, (jboolean *)0);");
1143                     out.println(indent +
1144                                 cname + " = " + cname + "_base + " + offset + ";");
1145 
1146                     emitSentinelCheck(cfunc, cname, out, false,
1147                                       emitExceptionCheck, offset,
1148                                       remaining, indent);
1149                     out.println();
1150                 } else if (jfunc.getArgType(idx).isArray()
1151                               && jfunc.getArgType(idx).isEGLHandle()) {
1152                     needsExit = true;
1153                     out.println(indent + "if (!" + cname + "_ref) {");
1154                     out.println(indent + indent + "_exception = 1;");
1155                     out.println(indent + indent +
1156                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
1157                     out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";");
1158                     out.println(indent + indent + "goto exit;");
1159                     out.println(indent + "}");
1160                     out.println(indent + "if (" + offset + " < 0) {");
1161                     out.println(indent + indent + "_exception = 1;");
1162                     out.println(indent + indent +
1163                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
1164                     out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";");
1165                     out.println(indent + indent + "goto exit;");
1166                     out.println(indent + "}");
1167 
1168                     out.println(indent + remaining + " = " +
1169                                     (mUseCPlusPlus ? "_env" : "(*_env)") +
1170                                     "->GetArrayLength(" +
1171                                     (mUseCPlusPlus ? "" : "_env, ") +
1172                                     cname + "_ref) - " + offset + ";");
1173                     emitNativeBoundsChecks(cfunc, cname, out, false,
1174                                            emitExceptionCheck,
1175                                            offset, remaining, "    ");
1176                     out.println(indent +
1177                                 jfunc.getArgName(idx) + " = new " +
1178                                 cfunc.getArgType(cIndex).getBaseType() +
1179                                "["+ remaining + "];");
1180                     out.println();
1181                 } else if (jfunc.getArgType(idx).isBuffer()) {
1182                     String array = numBufferArgs <= 1 ? "_array" :
1183                         "_" + cfunc.getArgName(cIndex) + "Array";
1184                     String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
1185                         "_" + cfunc.getArgName(cIndex) + "BufferOffset";
1186 
1187                     boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc;
1188                     if (nullAllowed) {
1189                         out.println(indent + "if (" + cname + "_buf) {");
1190                         out.print(indent);
1191                     }
1192 
1193                     if (isPointerFunc) {
1194                         out.println(indent +
1195                                 cname +
1196                                 " = (" +
1197                                 cfunc.getArgType(cIndex).getDeclaration() +
1198                                 ") getDirectBufferPointer(_env, " +
1199                                 cname + "_buf);");
1200                         String iii = "    ";
1201                         out.println(iii + indent + "if ( ! " + cname + " ) {");
1202                         out.println(iii + indent + indent + "return;");
1203                         out.println(iii + indent + "}");
1204                     } else {
1205                         out.println(indent +
1206                                     cname +
1207                                     " = (" +
1208                                     cfunc.getArgType(cIndex).getDeclaration() +
1209                                     ")getPointer(_env, " +
1210                                     cname +
1211                                     "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset +
1212                                     ");");
1213                     }
1214 
1215                     emitNativeBoundsChecks(cfunc, cname, out, true,
1216                                            emitExceptionCheck,
1217                                            offset, remaining, nullAllowed ? "        " : "    ");
1218 
1219                     if (nullAllowed) {
1220                         out.println(indent + "}");
1221                     }
1222                 }
1223             }
1224         }
1225 
1226         // Emit 'GetPrimitiveArrayCritical' for pointers if needed
1227         if (nonPrimitiveArgs.size() > 0) {
1228             for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
1229                 int idx = nonPrimitiveArgs.get(i).intValue();
1230                 int cIndex = jfunc.getArgCIndex(idx);
1231 
1232                 if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue;
1233 
1234                 String cname = cfunc.getArgName(cIndex);
1235                 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
1236                             "_" + cname + "BufferOffset";
1237                 String array = numBufferArgs <= 1 ? "_array" :
1238                             "_" + cfunc.getArgName(cIndex) + "Array";
1239 
1240                 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc;
1241                 if (nullAllowed) {
1242                     out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {");
1243                 } else {
1244                     out.println(indent + "if (" + cname +" == NULL) {");
1245                 }
1246                 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);");
1247                 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");");
1248                 out.println(indent + "}");
1249              }
1250         }
1251 
1252 
1253         if (!isVoid) {
1254             out.print(indent + "_returnValue = ");
1255         } else {
1256             out.print(indent);
1257         }
1258         String name = cfunc.getName();
1259 
1260         if (mUseContextPointer) {
1261             name = name.substring(2, name.length()); // Strip off 'gl' prefix
1262             name = name.substring(0, 1).toLowerCase() +
1263                 name.substring(1, name.length());
1264             out.print("ctx->procs.");
1265         }
1266 
1267         out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
1268 
1269         numArgs = cfunc.getNumArgs();
1270         if (numArgs == 0) {
1271             if (mUseContextPointer) {
1272                 out.println("ctx);");
1273             } else {
1274                 out.println(");");
1275             }
1276         } else {
1277             if (mUseContextPointer) {
1278                 out.println("ctx,");
1279             } else {
1280                 out.println();
1281             }
1282             for (int i = 0; i < numArgs; i++) {
1283                 String typecast;
1284                 if (i == numArgs - 1 && isPointerOffsetFunc) {
1285                     typecast = "(GLvoid *)";
1286                 } else {
1287                     typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")";
1288                 }
1289                 out.print(indent + indent +
1290                           typecast);
1291 
1292                 if (cfunc.getArgType(i).isConstCharPointer()) {
1293                     out.print("_native");
1294                 }
1295 
1296                 if (cfunc.getArgType(i).isEGLHandle() &&
1297                     !cfunc.getArgType(i).isPointer()){
1298                     out.print(cfunc.getArgName(i)+"_native");
1299                 } else {
1300                     out.print(cfunc.getArgName(i));
1301                 }
1302 
1303                 if (i == numArgs - 1) {
1304                     if (isPointerFunc) {
1305                         out.println(",");
1306                         out.println(indent + indent + "(GLsizei)remaining");
1307                     } else {
1308                         out.println();
1309                     }
1310                 } else {
1311                     out.println(",");
1312                 }
1313             }
1314             out.println(indent + ");");
1315         }
1316 
1317         if (needsExit) {
1318             out.println();
1319             out.println("exit:");
1320             needsExit = false;
1321         }
1322 
1323 
1324         if (nonPrimitiveArgs.size() > 0) {
1325             for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
1326                 int idx = nonPrimitiveArgs.get(i).intValue();
1327 
1328                 int cIndex = jfunc.getArgCIndex(idx);
1329                 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) {
1330 
1331                     // If the argument is 'const', GL will not write to it.
1332                     // In this case, we can use the 'JNI_ABORT' flag to avoid
1333                     // the need to write back to the Java array
1334                     out.println(indent +
1335                                 "if (" + jfunc.getArgName(idx) + "_base) {");
1336                     out.println(indent + indent +
1337                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
1338                                 "->ReleasePrimitiveArrayCritical(" +
1339                                 (mUseCPlusPlus ? "" : "_env, ") +
1340                                 jfunc.getArgName(idx) + "_ref, " +
1341                                 cfunc.getArgName(cIndex) +
1342                                 "_base,");
1343                     out.println(indent + indent + indent +
1344                                 (cfunc.getArgType(cIndex).isConst() ?
1345                                  "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) +
1346                                 ");");
1347                     out.println(indent + "}");
1348                 } else if (jfunc.getArgType(idx).isBuffer()) {
1349                     if (! isPointerFunc) {
1350                         String array = numBufferArgs <= 1 ? "_array" :
1351                             "_" + cfunc.getArgName(cIndex) + "Array";
1352                         out.println(indent + "if (" + array + ") {");
1353                         out.println(indent + indent +
1354                                     "releasePointer(_env, " + array + ", " +
1355                                     cfunc.getArgName(cIndex) +
1356                                     ", " +
1357                                     (cfunc.getArgType(cIndex).isConst() ?
1358                                      "JNI_FALSE" : (emitExceptionCheck ?
1359                                      "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
1360                                     ");");
1361                         out.println(indent + "}");
1362                     }
1363                 }
1364             }
1365         }
1366 
1367         // Emit local variable declaration for strings
1368         if (stringArgs.size() > 0) {
1369             for (int i = 0; i < stringArgs.size(); i++) {
1370                 int idx = stringArgs.get(i).intValue();
1371                 int cIndex = jfunc.getArgCIndex(idx);
1372                 String cname = cfunc.getArgName(cIndex);
1373 
1374                 out.println(indent + "if (_native" + cname + ") {");
1375                 out.println(indent + "    _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");");
1376                 out.println(indent + "}");
1377             }
1378 
1379             out.println();
1380         }
1381 
1382         // Copy results back to java arrays
1383        if (nonPrimitiveArgs.size() > 0) {
1384             for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
1385                 int idx = nonPrimitiveArgs.get(i).intValue();
1386                 int cIndex = jfunc.getArgCIndex(idx);
1387                 String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase();
1388                 if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) {
1389                     remaining  = ((numArrays + numBuffers) <= 1) ? "_remaining" :
1390                                      "_" + cfunc.getArgName(cIndex) + "Remaining";
1391                     offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset";
1392                     out.println(indent +
1393                                 "if (" + jfunc.getArgName(idx) + ") {");
1394                     out.println(indent + indent +
1395                                 "for (int i = 0; i < " + remaining + "; i++) {");
1396                     out.println(indent + indent + indent +
1397                                 "jobject " + cfunc.getArgName(cIndex) +
1398                                 "_new = toEGLHandle(_env, " + baseType +
1399                                 "Class, " + baseType + "Constructor, " +
1400                                 cfunc.getArgName(cIndex) + "[i]);");
1401                     out.println(indent + indent + indent +
1402                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
1403                                 "->SetObjectArrayElement(" +
1404                                 (mUseCPlusPlus ? "" : "_env, ") +
1405                                 cfunc.getArgName(cIndex) +
1406                                 "_ref, i + " + offset + ", " +
1407                                 cfunc.getArgName(cIndex) + "_new);");
1408                     out.println(indent + indent + "}");
1409                     out.println(indent + indent +
1410                                 "delete[] " + jfunc.getArgName(idx) + ";");
1411                     out.println(indent + "}");
1412                 }
1413             }
1414         }
1415 
1416 
1417         // Throw exception if there is one
1418         if (emitExceptionCheck) {
1419             out.println(indent + "if (_exception) {");
1420             out.println(indent + indent +
1421                         "jniThrowException(_env, _exceptionType, _exceptionMessage);");
1422             out.println(indent + "}");
1423 
1424         }
1425 
1426 
1427         if (!isVoid) {
1428             if (cfunc.getType().isEGLHandle()) {
1429                 String baseType = cfunc.getType().getBaseType().toLowerCase();
1430                 out.println(indent +
1431                             "return toEGLHandle(_env, " + baseType + "Class, " +
1432                             baseType + "Constructor, _returnValue);");
1433             } else {
1434                 out.println(indent + "return (" +
1435                             getJniType(jfunc.getType()) + ")_returnValue;");
1436             }
1437         }
1438 
1439         out.println("}");
1440         out.println();
1441     }
1442 
1443 }
1444