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