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