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