• 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 + "_exception = 1;");
1077                 out.println(indent + indent +
1078                             "_exceptionType = \"java/lang/IllegalArgumentException\";");
1079                 out.println(indent + indent +
1080                             "_exceptionMessage = \"" + cname + " == null\";");
1081                 out.println(indent + indent + "goto exit;");
1082                 out.println(indent + "}");
1083 
1084                 out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);");
1085             }
1086 
1087             out.println();
1088         }
1089 
1090         // Emit 'GetPrimitiveArrayCritical' for non-object arrays
1091         // Emit 'GetPointer' calls for Buffer pointers
1092         if (nonPrimitiveArgs.size() > 0) {
1093             for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
1094                 int idx = nonPrimitiveArgs.get(i).intValue();
1095                 int cIndex = jfunc.getArgCIndex(idx);
1096 
1097                 String cname = cfunc.getArgName(cIndex);
1098                 offset = numArrays <= 1 ? "offset" :
1099                     cname + "Offset";
1100                 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
1101                     "_" + cname + "Remaining";
1102 
1103                 if (jfunc.getArgType(idx).isArray()
1104                        && !jfunc.getArgType(idx).isEGLHandle()) {
1105                     needsExit = true;
1106                     out.println(indent + "if (!" + cname + "_ref) {");
1107                     out.println(indent + indent + "_exception = 1;");
1108                     out.println(indent + indent +
1109                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
1110                     out.println(indent + indent +
1111                                 "_exceptionMessage = \"" + cname +" == null\";");
1112                     out.println(indent + indent + "goto exit;");
1113                     out.println(indent + "}");
1114                     out.println(indent + "if (" + offset + " < 0) {");
1115                     out.println(indent + indent + "_exception = 1;");
1116                     out.println(indent + indent +
1117                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
1118                     out.println(indent + indent +
1119                                 "_exceptionMessage = \"" + offset +" < 0\";");
1120                     out.println(indent + indent + "goto exit;");
1121                     out.println(indent + "}");
1122 
1123                     out.println(indent + remaining + " = " +
1124                                     (mUseCPlusPlus ? "_env" : "(*_env)") +
1125                                     "->GetArrayLength(" +
1126                                     (mUseCPlusPlus ? "" : "_env, ") +
1127                                     cname + "_ref) - " + offset + ";");
1128 
1129                     emitNativeBoundsChecks(cfunc, cname, out, false,
1130                                            emitExceptionCheck,
1131                                            offset, remaining, "    ");
1132 
1133                     out.println(indent +
1134                                 cname +
1135                                 "_base = (" +
1136                                 cfunc.getArgType(cIndex).getDeclaration() +
1137                                 ")");
1138                     out.println(indent + "    " +
1139                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
1140                                 "->GetPrimitiveArrayCritical(" +
1141                                 (mUseCPlusPlus ? "" : "_env, ") +
1142                                 jfunc.getArgName(idx) +
1143                                 "_ref, (jboolean *)0);");
1144                     out.println(indent +
1145                                 cname + " = " + cname + "_base + " + offset + ";");
1146 
1147                     emitSentinelCheck(cfunc, cname, out, false,
1148                                       emitExceptionCheck, offset,
1149                                       remaining, indent);
1150                     out.println();
1151                 } else if (jfunc.getArgType(idx).isArray()
1152                               && jfunc.getArgType(idx).isEGLHandle()) {
1153                     needsExit = true;
1154                     out.println(indent + "if (!" + cname + "_ref) {");
1155                     out.println(indent + indent + "_exception = 1;");
1156                     out.println(indent + indent +
1157                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
1158                     out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";");
1159                     out.println(indent + indent + "goto exit;");
1160                     out.println(indent + "}");
1161                     out.println(indent + "if (" + offset + " < 0) {");
1162                     out.println(indent + indent + "_exception = 1;");
1163                     out.println(indent + indent +
1164                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
1165                     out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";");
1166                     out.println(indent + indent + "goto exit;");
1167                     out.println(indent + "}");
1168 
1169                     out.println(indent + remaining + " = " +
1170                                     (mUseCPlusPlus ? "_env" : "(*_env)") +
1171                                     "->GetArrayLength(" +
1172                                     (mUseCPlusPlus ? "" : "_env, ") +
1173                                     cname + "_ref) - " + offset + ";");
1174                     emitNativeBoundsChecks(cfunc, cname, out, false,
1175                                            emitExceptionCheck,
1176                                            offset, remaining, "    ");
1177                     out.println(indent +
1178                                 jfunc.getArgName(idx) + " = new " +
1179                                 cfunc.getArgType(cIndex).getBaseType() +
1180                                "["+ remaining + "];");
1181                     out.println();
1182                 } else if (jfunc.getArgType(idx).isBuffer()) {
1183                     String array = numBufferArgs <= 1 ? "_array" :
1184                         "_" + cfunc.getArgName(cIndex) + "Array";
1185                     String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
1186                         "_" + cfunc.getArgName(cIndex) + "BufferOffset";
1187 
1188                     boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc;
1189                     if (nullAllowed) {
1190                         out.println(indent + "if (" + cname + "_buf) {");
1191                         out.print(indent);
1192                     }
1193 
1194                     if (isPointerFunc) {
1195                         out.println(indent +
1196                                 cname +
1197                                 " = (" +
1198                                 cfunc.getArgType(cIndex).getDeclaration() +
1199                                 ") getDirectBufferPointer(_env, " +
1200                                 cname + "_buf);");
1201                         String iii = "    ";
1202                         out.println(iii + indent + "if ( ! " + cname + " ) {");
1203                         out.println(iii + indent + indent + "return;");
1204                         out.println(iii + indent + "}");
1205                     } else {
1206                         out.println(indent +
1207                                     cname +
1208                                     " = (" +
1209                                     cfunc.getArgType(cIndex).getDeclaration() +
1210                                     ")getPointer(_env, " +
1211                                     cname +
1212                                     "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset +
1213                                     ");");
1214                     }
1215 
1216                     emitNativeBoundsChecks(cfunc, cname, out, true,
1217                                            emitExceptionCheck,
1218                                            offset, remaining, nullAllowed ? "        " : "    ");
1219 
1220                     if (nullAllowed) {
1221                         out.println(indent + "}");
1222                     }
1223                 }
1224             }
1225         }
1226 
1227         // Emit 'GetPrimitiveArrayCritical' for pointers if needed
1228         if (nonPrimitiveArgs.size() > 0) {
1229             for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
1230                 int idx = nonPrimitiveArgs.get(i).intValue();
1231                 int cIndex = jfunc.getArgCIndex(idx);
1232 
1233                 if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue;
1234 
1235                 String cname = cfunc.getArgName(cIndex);
1236                 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
1237                             "_" + cname + "BufferOffset";
1238                 String array = numBufferArgs <= 1 ? "_array" :
1239                             "_" + cfunc.getArgName(cIndex) + "Array";
1240 
1241                 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc;
1242                 if (nullAllowed) {
1243                     out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {");
1244                 } else {
1245                     out.println(indent + "if (" + cname +" == NULL) {");
1246                 }
1247                 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);");
1248                 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");");
1249                 out.println(indent + "}");
1250              }
1251         }
1252 
1253 
1254         if (!isVoid) {
1255             out.print(indent + "_returnValue = ");
1256         } else {
1257             out.print(indent);
1258         }
1259         String name = cfunc.getName();
1260 
1261         if (mUseContextPointer) {
1262             name = name.substring(2, name.length()); // Strip off 'gl' prefix
1263             name = name.substring(0, 1).toLowerCase() +
1264                 name.substring(1, name.length());
1265             out.print("ctx->procs.");
1266         }
1267 
1268         out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
1269 
1270         numArgs = cfunc.getNumArgs();
1271         if (numArgs == 0) {
1272             if (mUseContextPointer) {
1273                 out.println("ctx);");
1274             } else {
1275                 out.println(");");
1276             }
1277         } else {
1278             if (mUseContextPointer) {
1279                 out.println("ctx,");
1280             } else {
1281                 out.println();
1282             }
1283             for (int i = 0; i < numArgs; i++) {
1284                 String typecast;
1285                 if (i == numArgs - 1 && isPointerOffsetFunc) {
1286                     typecast = "reinterpret_cast<GLvoid *>";
1287                 } else {
1288                     typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")";
1289                 }
1290                 out.print(indent + indent +
1291                           typecast);
1292 
1293                 if (cfunc.getArgType(i).isConstCharPointer()) {
1294                     out.print("_native");
1295                 }
1296 
1297                 if (cfunc.getArgType(i).isEGLHandle() &&
1298                     !cfunc.getArgType(i).isPointer()){
1299                     out.print(cfunc.getArgName(i)+"_native");
1300                 } else if (i == numArgs - 1 && isPointerOffsetFunc){
1301                     out.print("("+cfunc.getArgName(i)+")");
1302                 } else {
1303                     out.print(cfunc.getArgName(i));
1304                 }
1305 
1306                 if (i == numArgs - 1) {
1307                     if (isPointerFunc) {
1308                         out.println(",");
1309                         out.println(indent + indent + "(GLsizei)remaining");
1310                     } else {
1311                         out.println();
1312                     }
1313                 } else {
1314                     out.println(",");
1315                 }
1316             }
1317             out.println(indent + ");");
1318         }
1319 
1320         if (needsExit) {
1321             out.println();
1322             out.println("exit:");
1323             needsExit = false;
1324         }
1325 
1326 
1327         if (nonPrimitiveArgs.size() > 0) {
1328             for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
1329                 int idx = nonPrimitiveArgs.get(i).intValue();
1330 
1331                 int cIndex = jfunc.getArgCIndex(idx);
1332                 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) {
1333 
1334                     // If the argument is 'const', GL will not write to it.
1335                     // In this case, we can use the 'JNI_ABORT' flag to avoid
1336                     // the need to write back to the Java array
1337                     out.println(indent +
1338                                 "if (" + jfunc.getArgName(idx) + "_base) {");
1339                     out.println(indent + indent +
1340                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
1341                                 "->ReleasePrimitiveArrayCritical(" +
1342                                 (mUseCPlusPlus ? "" : "_env, ") +
1343                                 jfunc.getArgName(idx) + "_ref, " +
1344                                 cfunc.getArgName(cIndex) +
1345                                 "_base,");
1346                     out.println(indent + indent + indent +
1347                                 (cfunc.getArgType(cIndex).isConst() ?
1348                                  "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) +
1349                                 ");");
1350                     out.println(indent + "}");
1351                 } else if (jfunc.getArgType(idx).isBuffer()) {
1352                     if (! isPointerFunc) {
1353                         String array = numBufferArgs <= 1 ? "_array" :
1354                             "_" + cfunc.getArgName(cIndex) + "Array";
1355                         out.println(indent + "if (" + array + ") {");
1356                         out.println(indent + indent +
1357                                     "releasePointer(_env, " + array + ", " +
1358                                     cfunc.getArgName(cIndex) +
1359                                     ", " +
1360                                     (cfunc.getArgType(cIndex).isConst() ?
1361                                      "JNI_FALSE" : (emitExceptionCheck ?
1362                                      "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
1363                                     ");");
1364                         out.println(indent + "}");
1365                     }
1366                 }
1367             }
1368         }
1369 
1370         // Emit local variable declaration for strings
1371         if (stringArgs.size() > 0) {
1372             for (int i = 0; i < stringArgs.size(); i++) {
1373                 int idx = stringArgs.get(i).intValue();
1374                 int cIndex = jfunc.getArgCIndex(idx);
1375                 String cname = cfunc.getArgName(cIndex);
1376 
1377                 out.println(indent + "if (_native" + cname + ") {");
1378                 out.println(indent + "    _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");");
1379                 out.println(indent + "}");
1380             }
1381 
1382             out.println();
1383         }
1384 
1385         // Copy results back to java arrays
1386        if (nonPrimitiveArgs.size() > 0) {
1387             for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
1388                 int idx = nonPrimitiveArgs.get(i).intValue();
1389                 int cIndex = jfunc.getArgCIndex(idx);
1390                 String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase();
1391                 if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) {
1392                     remaining  = ((numArrays + numBuffers) <= 1) ? "_remaining" :
1393                                      "_" + cfunc.getArgName(cIndex) + "Remaining";
1394                     offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset";
1395                     out.println(indent +
1396                                 "if (" + jfunc.getArgName(idx) + ") {");
1397                     out.println(indent + indent +
1398                                 "for (int i = 0; i < " + remaining + "; i++) {");
1399                     out.println(indent + indent + indent +
1400                                 "jobject " + cfunc.getArgName(cIndex) +
1401                                 "_new = toEGLHandle(_env, " + baseType +
1402                                 "Class, " + baseType + "Constructor, " +
1403                                 cfunc.getArgName(cIndex) + "[i]);");
1404                     out.println(indent + indent + indent +
1405                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
1406                                 "->SetObjectArrayElement(" +
1407                                 (mUseCPlusPlus ? "" : "_env, ") +
1408                                 cfunc.getArgName(cIndex) +
1409                                 "_ref, i + " + offset + ", " +
1410                                 cfunc.getArgName(cIndex) + "_new);");
1411                     out.println(indent + indent + "}");
1412                     out.println(indent + indent +
1413                                 "delete[] " + jfunc.getArgName(idx) + ";");
1414                     out.println(indent + "}");
1415                 }
1416             }
1417         }
1418 
1419 
1420         // Throw exception if there is one
1421         if (emitExceptionCheck) {
1422             out.println(indent + "if (_exception) {");
1423             out.println(indent + indent +
1424                         "jniThrowException(_env, _exceptionType, _exceptionMessage);");
1425             out.println(indent + "}");
1426 
1427         }
1428 
1429 
1430         if (!isVoid) {
1431             if (cfunc.getType().isEGLHandle()) {
1432                 String baseType = cfunc.getType().getBaseType().toLowerCase();
1433                 out.println(indent +
1434                             "return toEGLHandle(_env, " + baseType + "Class, " +
1435                             baseType + "Constructor, _returnValue);");
1436             } else {
1437                 out.println(indent + "return (" +
1438                             getJniType(jfunc.getType()) + ")_returnValue;");
1439             }
1440         }
1441 
1442         out.println("}");
1443         out.println();
1444     }
1445 
1446 }
1447