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         }
    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 = 1;");
    208         out.println(iii + "        break;");
    209         out.println(iii + "}");
    210 
    211         out.println(iii + "if (" + remaining + " < _needed) {");
    212         out.println(iii + indent + "_exception = 1;");
    213         out.println(iii + indent +
    214                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
    215         out.println(iii + indent +
    216                 "_exceptionMessage = \"" +
    217                 (isBuffer ? "remaining()" : "length - " + offset) +
    218                 " < needed\";");
    219         out.println(iii + indent + "goto exit;");
    220         out.println(iii + "}");
    221 
    222         needsExit = true;
    223     }
    224 
    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 isPointerOffsetFunc =
    753             (outName.endsWith("Pointer") || outName.endsWith("PointerOES") ||
    754              outName.endsWith("glDrawElements") ||
    755              outName.endsWith("glDrawRangeElements") ||
    756              outName.endsWith("glTexImage2D") ||
    757              outName.endsWith("glTexSubImage2D") ||
    758              outName.endsWith("glCompressedTexImage2D") ||
    759              outName.endsWith("glCompressedTexSubImage2D") ||
    760              outName.endsWith("glTexImage3D") ||
    761              outName.endsWith("glTexSubImage3D") ||
    762              outName.endsWith("glCompressedTexImage3D") ||
    763              outName.endsWith("glCompressedTexSubImage3D") ||
    764              outName.endsWith("glReadPixels"))
    765             && !jfunc.getCFunc().hasPointerArg();
    766         if (isPointerFunc) {
    767             outName += "Bounds";
    768         }
    769 
    770         out.print("static ");
    771         out.println(getJniType(jfunc.getType()));
    772         out.print(outName);
    773 
    774         String rsignature = getJniName(jfunc.getType());
    775 
    776         String signature = "";
    777         int numArgs = jfunc.getNumArgs();
    778         for (int i = 0; i < numArgs; i++) {
    779             JType argType = jfunc.getArgType(i);
    780             signature += getJniName(argType);
    781         }
    782         if (isPointerFunc) {
    783             signature += "I";
    784         }
    785 
    786         // Append signature to function name
    787         String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_');
    788         if (!mUseSimpleMethodNames) {
    789             out.print("__" + sig);
    790             outName += "__" + sig;
    791         }
    792 
    793         signature = signature.replace('.', '/');
    794         rsignature = rsignature.replace('.', '/');
    795 
    796         out.println();
    797         if (rsignature.length() == 0) {
    798             rsignature = "V";
    799         }
    800 
    801         String s = "{\"" +
    802             jfunc.getName() +
    803             (isPointerFunc ? "Bounds" : "") +
    804             "\", \"(" + signature +")" +
    805             rsignature +
    806             "\", (void *) " +
    807             outName +
    808             " },";
    809         nativeRegistrations.add(s);
    810 
    811         List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
    812         List<Integer> stringArgs = new ArrayList<Integer>();
    813         int numBufferArgs = 0;
    814         List<String> bufferArgNames = new ArrayList<String>();
    815 
    816         // Emit JNI signature (arguments)
    817         //
    818         // Example:
    819         //
    820         // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) {
    821         //
    822         out.print("  (JNIEnv *_env, jobject _this");
    823         for (int i = 0; i < numArgs; i++) {
    824             out.print(", ");
    825             JType argType = jfunc.getArgType(i);
    826             String suffix = "";
    827             if (!argType.isPrimitive()) {
    828                 if (argType.isArray()) {
    829                     suffix = "_ref";
    830                 } else if (argType.isBuffer()) {
    831                     suffix = "_buf";
    832                 }
    833                 nonPrimitiveArgs.add(new Integer(i));
    834                 if (jfunc.getArgType(i).isBuffer()) {
    835                     int cIndex = jfunc.getArgCIndex(i);
    836                     String cname = cfunc.getArgName(cIndex);
    837                     bufferArgNames.add(cname);
    838                     numBufferArgs++;
    839                 }
    840             }
    841 
    842             if (argType.isString()) {
    843                 stringArgs.add(new Integer(i));
    844             }
    845 
    846             out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
    847         }
    848         if (isPointerFunc) {
    849             out.print(", jint remaining");
    850         }
    851         out.println(") {");
    852 
    853         int numArrays = 0;
    854         int numBuffers = 0;
    855         int numStrings = 0;
    856         for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
    857             int idx = nonPrimitiveArgs.get(i).intValue();
    858             JType argType = jfunc.getArgType(idx);
    859             if (argType.isArray()) {
    860                 ++numArrays;
    861             }
    862             if (argType.isBuffer()) {
    863                 ++numBuffers;
    864             }
    865             if (argType.isString()) {
    866                 ++numStrings;
    867             }
    868         }
    869 
    870         // Emit method body
    871 
    872         // Emit local variable declarations for _exception and _returnValue
    873         //
    874         // Example:
    875         //
    876         // android::gl::ogles_context_t *ctx;
    877         //
    878         // jint _exception;
    879         // GLenum _returnValue;
    880         //
    881         CType returnType = cfunc.getType();
    882         boolean isVoid = returnType.isVoid();
    883 
    884         boolean isUnsupported = isUnsupportedFunc(cfunc);
    885         if (isUnsupported) {
    886             out.println(indent +
    887                         "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
    888             out.println(indent +
    889                         "    \"" + cfunc.getName() + "\");");
    890             if (!isVoid) {
    891                 String retval = getErrorReturnValue(cfunc);
    892                 if (cfunc.getType().isEGLHandle()) {
    893                     String baseType = cfunc.getType().getBaseType().toLowerCase();
    894                     out.println(indent +
    895                                 "return toEGLHandle(_env, " + baseType + "Class, " +
    896                                 baseType + "Constructor, " + retval + ");");
    897                 } else {
    898                     out.println(indent + "return " + retval + ";");
    899                 }
    900             }
    901             out.println("}");
    902             out.println();
    903             return;
    904         }
    905 
    906         String requiresExtension = isRequiresFunc(cfunc);
    907         if (requiresExtension != null) {
    908             out.println(indent +
    909                         "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {");
    910             out.println(indent + indent +
    911                         "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
    912             out.println(indent + indent +
    913                         "    \"" + cfunc.getName() + "\");");
    914             if (isVoid) {
    915                 out.println(indent + indent + "    return;");
    916             } else {
    917                 String retval = getErrorReturnValue(cfunc);
    918                 if (cfunc.getType().isEGLHandle()) {
    919                     String baseType = cfunc.getType().getBaseType().toLowerCase();
    920                     out.println(indent +
    921                                 "return toEGLHandle(_env, " + baseType + "Class, " +
    922                                 baseType + "Constructor, " + retval + ");");
    923                 } else {
    924                     out.println(indent + "return " + retval + ";");
    925                 }
    926             }
    927             out.println(indent + "}");
    928         }
    929         if (mUseContextPointer) {
    930             out.println(indent +
    931                 "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
    932         }
    933 
    934         boolean initializeReturnValue = stringArgs.size() > 0;
    935         boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0)
    936                                              && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs)
    937                                                  || (cfunc.hasPointerArg() && numArrays > 0))
    938                                          || hasCheckTest(cfunc)
    939                                          || hasIfTest(cfunc))
    940                                          || (stringArgs.size() > 0);
    941         // mChecker.getChecks(cfunc.getName()) != null
    942         // Emit an _exeption variable if there will be error checks
    943         if (emitExceptionCheck) {
    944             out.println(indent + "jint _exception = 0;");
    945             out.println(indent + "const char * _exceptionType = NULL;");
    946             out.println(indent + "const char * _exceptionMessage = NULL;");
    947         }
    948 
    949         // Emit a single _array or multiple _XXXArray variables
    950         if (numBufferArgs == 1) {
    951                 out.println(indent + "jarray _array = (jarray) 0;");
    952                 out.println(indent + "jint _bufferOffset = (jint) 0;");
    953         } else {
    954             for (int i = 0; i < numBufferArgs; i++) {
    955                 out.println(indent + "jarray _" + bufferArgNames.get(i) +
    956                             "Array = (jarray) 0;");
    957                 out.println(indent + "jint _" + bufferArgNames.get(i) +
    958                             "BufferOffset = (jint) 0;");
    959             }
    960         }
    961         if (!isVoid) {
    962             String retval = getErrorReturnValue(cfunc);
    963             if (retval != null) {
    964                 out.println(indent + returnType.getDeclaration() +
    965                             " _returnValue = " + retval + ";");
    966             } else if (initializeReturnValue) {
    967                 out.println(indent + returnType.getDeclaration() +
    968                             " _returnValue = 0;");
    969             } else {
    970                 out.println(indent + returnType.getDeclaration() +
    971                             " _returnValue;");
    972             }
    973         }
    974 
    975         // Emit local variable declarations for EGL Handles
    976         //
    977         // Example:
    978         //
    979         // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface);
    980         //
    981         if (nonPrimitiveArgs.size() > 0) {
    982             for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
    983                 int idx = nonPrimitiveArgs.get(i).intValue();
    984                 int cIndex = jfunc.getArgCIndex(idx);
    985                 String cname = cfunc.getArgName(cIndex);
    986 
    987                 if (jfunc.getArgType(idx).isBuffer()
    988                    || jfunc.getArgType(idx).isArray()
    989                    || !jfunc.getArgType(idx).isEGLHandle())
    990                     continue;
    991 
    992                 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
    993                 String decl = type.getDeclaration();
    994                 out.println(indent +
    995                             decl + " " + cname + "_native = (" +
    996                             decl + ") fromEGLHandle(_env, " +
    997                             type.getBaseType().toLowerCase() +
    998                             "GetHandleID, " + jfunc.getArgName(idx) +
    999                             ");");
   1000             }
   1001         }
   1002 
   1003         // Emit local variable declarations for element/sentinel checks
   1004         //
   1005         // Example:
   1006         //
   1007         // bool attrib_list_sentinel_found = false;
   1008         //
   1009         emitLocalVariablesForSentinel(cfunc, out);
   1010 
   1011         // Emit local variable declarations for pointer arguments
   1012         //
   1013         // Example:
   1014         //
   1015         // GLfixed *eqn_base;
   1016         // GLfixed *eqn;
   1017         //
   1018         String offset = "offset";
   1019         String remaining = "_remaining";
   1020         if (nonPrimitiveArgs.size() > 0) {
   1021             for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
   1022                 int idx = nonPrimitiveArgs.get(i).intValue();
   1023                 int cIndex = jfunc.getArgCIndex(idx);
   1024                 String cname = cfunc.getArgName(cIndex);
   1025 
   1026                 if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray())
   1027                     continue;
   1028 
   1029                 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
   1030                 String decl = type.getDeclaration();
   1031                 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) {
   1032                     out.println(indent +
   1033                                 decl +
   1034                                 (decl.endsWith("*") ? "" : " ") +
   1035                                 jfunc.getArgName(idx) +
   1036                                 "_base = (" + decl + ") 0;");
   1037                 }
   1038                 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
   1039                     "_" + cname + "Remaining";
   1040                 out.println(indent +
   1041                             "jint " + remaining + ";");
   1042                 out.println(indent +
   1043                                 decl +
   1044                                 (decl.endsWith("*") ? "" : " ") +
   1045                                 jfunc.getArgName(idx) +
   1046                                 " = (" + decl + ") 0;");
   1047             }
   1048 
   1049             out.println();
   1050         }
   1051 
   1052         // Emit local variable declaration for strings
   1053         if (stringArgs.size() > 0) {
   1054             for (int i = 0; i < stringArgs.size(); i++) {
   1055                 int idx = stringArgs.get(i).intValue();
   1056                 int cIndex = jfunc.getArgCIndex(idx);
   1057                 String cname = cfunc.getArgName(cIndex);
   1058 
   1059                 out.println(indent + "const char* _native" + cname + " = 0;");
   1060             }
   1061 
   1062             out.println();
   1063         }
   1064 
   1065         // Null pointer checks and GetStringUTFChars
   1066         if (stringArgs.size() > 0) {
   1067             for (int i = 0; i < stringArgs.size(); i++) {
   1068                 int idx = stringArgs.get(i).intValue();
   1069                 int cIndex = jfunc.getArgCIndex(idx);
   1070                 String cname = cfunc.getArgName(cIndex);
   1071 
   1072                 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
   1073                 String decl = type.getDeclaration();
   1074                 needsExit = true;
   1075                 out.println(indent + "if (!" + cname + ") {");
   1076                 out.println(indent + indent +
   1077                             "_exceptionType = \"java/lang/IllegalArgumentException\";");
   1078                 out.println(indent + indent +
   1079                             "_exceptionMessage = \"" + cname + " == null\";");
   1080                 out.println(indent + indent + "goto exit;");
   1081                 out.println(indent + "}");
   1082 
   1083                 out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);");
   1084             }
   1085 
   1086             out.println();
   1087         }
   1088 
   1089         // Emit 'GetPrimitiveArrayCritical' for non-object arrays
   1090         // Emit 'GetPointer' calls for Buffer pointers
   1091         if (nonPrimitiveArgs.size() > 0) {
   1092             for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
   1093                 int idx = nonPrimitiveArgs.get(i).intValue();
   1094                 int cIndex = jfunc.getArgCIndex(idx);
   1095 
   1096                 String cname = cfunc.getArgName(cIndex);
   1097                 offset = numArrays <= 1 ? "offset" :
   1098                     cname + "Offset";
   1099                 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
   1100                     "_" + cname + "Remaining";
   1101 
   1102                 if (jfunc.getArgType(idx).isArray()
   1103                        && !jfunc.getArgType(idx).isEGLHandle()) {
   1104                     needsExit = true;
   1105                     out.println(indent + "if (!" + cname + "_ref) {");
   1106                     out.println(indent + indent + "_exception = 1;");
   1107                     out.println(indent + indent +
   1108                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
   1109                     out.println(indent + indent +
   1110                                 "_exceptionMessage = \"" + cname +" == null\";");
   1111                     out.println(indent + indent + "goto exit;");
   1112                     out.println(indent + "}");
   1113                     out.println(indent + "if (" + offset + " < 0) {");
   1114                     out.println(indent + indent + "_exception = 1;");
   1115                     out.println(indent + indent +
   1116                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
   1117                     out.println(indent + indent +
   1118                                 "_exceptionMessage = \"" + offset +" < 0\";");
   1119                     out.println(indent + indent + "goto exit;");
   1120                     out.println(indent + "}");
   1121 
   1122                     out.println(indent + remaining + " = " +
   1123                                     (mUseCPlusPlus ? "_env" : "(*_env)") +
   1124                                     "->GetArrayLength(" +
   1125                                     (mUseCPlusPlus ? "" : "_env, ") +
   1126                                     cname + "_ref) - " + offset + ";");
   1127 
   1128                     emitNativeBoundsChecks(cfunc, cname, out, false,
   1129                                            emitExceptionCheck,
   1130                                            offset, remaining, "    ");
   1131 
   1132                     out.println(indent +
   1133                                 cname +
   1134                                 "_base = (" +
   1135                                 cfunc.getArgType(cIndex).getDeclaration() +
   1136                                 ")");
   1137                     out.println(indent + "    " +
   1138                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
   1139                                 "->GetPrimitiveArrayCritical(" +
   1140                                 (mUseCPlusPlus ? "" : "_env, ") +
   1141                                 jfunc.getArgName(idx) +
   1142                                 "_ref, (jboolean *)0);");
   1143                     out.println(indent +
   1144                                 cname + " = " + cname + "_base + " + offset + ";");
   1145 
   1146                     emitSentinelCheck(cfunc, cname, out, false,
   1147                                       emitExceptionCheck, offset,
   1148                                       remaining, indent);
   1149                     out.println();
   1150                 } else if (jfunc.getArgType(idx).isArray()
   1151                               && jfunc.getArgType(idx).isEGLHandle()) {
   1152                     needsExit = true;
   1153                     out.println(indent + "if (!" + cname + "_ref) {");
   1154                     out.println(indent + indent + "_exception = 1;");
   1155                     out.println(indent + indent +
   1156                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
   1157                     out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";");
   1158                     out.println(indent + indent + "goto exit;");
   1159                     out.println(indent + "}");
   1160                     out.println(indent + "if (" + offset + " < 0) {");
   1161                     out.println(indent + indent + "_exception = 1;");
   1162                     out.println(indent + indent +
   1163                                 "_exceptionType = \"java/lang/IllegalArgumentException\";");
   1164                     out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";");
   1165                     out.println(indent + indent + "goto exit;");
   1166                     out.println(indent + "}");
   1167 
   1168                     out.println(indent + remaining + " = " +
   1169                                     (mUseCPlusPlus ? "_env" : "(*_env)") +
   1170                                     "->GetArrayLength(" +
   1171                                     (mUseCPlusPlus ? "" : "_env, ") +
   1172                                     cname + "_ref) - " + offset + ";");
   1173                     emitNativeBoundsChecks(cfunc, cname, out, false,
   1174                                            emitExceptionCheck,
   1175                                            offset, remaining, "    ");
   1176                     out.println(indent +
   1177                                 jfunc.getArgName(idx) + " = new " +
   1178                                 cfunc.getArgType(cIndex).getBaseType() +
   1179                                "["+ remaining + "];");
   1180                     out.println();
   1181                 } else if (jfunc.getArgType(idx).isBuffer()) {
   1182                     String array = numBufferArgs <= 1 ? "_array" :
   1183                         "_" + cfunc.getArgName(cIndex) + "Array";
   1184                     String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
   1185                         "_" + cfunc.getArgName(cIndex) + "BufferOffset";
   1186 
   1187                     boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc;
   1188                     if (nullAllowed) {
   1189                         out.println(indent + "if (" + cname + "_buf) {");
   1190                         out.print(indent);
   1191                     }
   1192 
   1193                     if (isPointerFunc) {
   1194                         out.println(indent +
   1195                                 cname +
   1196                                 " = (" +
   1197                                 cfunc.getArgType(cIndex).getDeclaration() +
   1198                                 ") getDirectBufferPointer(_env, " +
   1199                                 cname + "_buf);");
   1200                         String iii = "    ";
   1201                         out.println(iii + indent + "if ( ! " + cname + " ) {");
   1202                         out.println(iii + indent + indent + "return;");
   1203                         out.println(iii + indent + "}");
   1204                     } else {
   1205                         out.println(indent +
   1206                                     cname +
   1207                                     " = (" +
   1208                                     cfunc.getArgType(cIndex).getDeclaration() +
   1209                                     ")getPointer(_env, " +
   1210                                     cname +
   1211                                     "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset +
   1212                                     ");");
   1213                     }
   1214 
   1215                     emitNativeBoundsChecks(cfunc, cname, out, true,
   1216                                            emitExceptionCheck,
   1217                                            offset, remaining, nullAllowed ? "        " : "    ");
   1218 
   1219                     if (nullAllowed) {
   1220                         out.println(indent + "}");
   1221                     }
   1222                 }
   1223             }
   1224         }
   1225 
   1226         // Emit 'GetPrimitiveArrayCritical' for pointers if needed
   1227         if (nonPrimitiveArgs.size() > 0) {
   1228             for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
   1229                 int idx = nonPrimitiveArgs.get(i).intValue();
   1230                 int cIndex = jfunc.getArgCIndex(idx);
   1231 
   1232                 if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue;
   1233 
   1234                 String cname = cfunc.getArgName(cIndex);
   1235                 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
   1236                             "_" + cname + "BufferOffset";
   1237                 String array = numBufferArgs <= 1 ? "_array" :
   1238                             "_" + cfunc.getArgName(cIndex) + "Array";
   1239 
   1240                 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc;
   1241                 if (nullAllowed) {
   1242                     out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {");
   1243                 } else {
   1244                     out.println(indent + "if (" + cname +" == NULL) {");
   1245                 }
   1246                 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);");
   1247                 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");");
   1248                 out.println(indent + "}");
   1249              }
   1250         }
   1251 
   1252 
   1253         if (!isVoid) {
   1254             out.print(indent + "_returnValue = ");
   1255         } else {
   1256             out.print(indent);
   1257         }
   1258         String name = cfunc.getName();
   1259 
   1260         if (mUseContextPointer) {
   1261             name = name.substring(2, name.length()); // Strip off 'gl' prefix
   1262             name = name.substring(0, 1).toLowerCase() +
   1263                 name.substring(1, name.length());
   1264             out.print("ctx->procs.");
   1265         }
   1266 
   1267         out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
   1268 
   1269         numArgs = cfunc.getNumArgs();
   1270         if (numArgs == 0) {
   1271             if (mUseContextPointer) {
   1272                 out.println("ctx);");
   1273             } else {
   1274                 out.println(");");
   1275             }
   1276         } else {
   1277             if (mUseContextPointer) {
   1278                 out.println("ctx,");
   1279             } else {
   1280                 out.println();
   1281             }
   1282             for (int i = 0; i < numArgs; i++) {
   1283                 String typecast;
   1284                 if (i == numArgs - 1 && isPointerOffsetFunc) {
   1285                     typecast = "(GLvoid *)";
   1286                 } else {
   1287                     typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")";
   1288                 }
   1289                 out.print(indent + indent +
   1290                           typecast);
   1291 
   1292                 if (cfunc.getArgType(i).isConstCharPointer()) {
   1293                     out.print("_native");
   1294                 }
   1295 
   1296                 if (cfunc.getArgType(i).isEGLHandle() &&
   1297                     !cfunc.getArgType(i).isPointer()){
   1298                     out.print(cfunc.getArgName(i)+"_native");
   1299                 } else {
   1300                     out.print(cfunc.getArgName(i));
   1301                 }
   1302 
   1303                 if (i == numArgs - 1) {
   1304                     if (isPointerFunc) {
   1305                         out.println(",");
   1306                         out.println(indent + indent + "(GLsizei)remaining");
   1307                     } else {
   1308                         out.println();
   1309                     }
   1310                 } else {
   1311                     out.println(",");
   1312                 }
   1313             }
   1314             out.println(indent + ");");
   1315         }
   1316 
   1317         if (needsExit) {
   1318             out.println();
   1319             out.println("exit:");
   1320             needsExit = false;
   1321         }
   1322 
   1323 
   1324         if (nonPrimitiveArgs.size() > 0) {
   1325             for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
   1326                 int idx = nonPrimitiveArgs.get(i).intValue();
   1327 
   1328                 int cIndex = jfunc.getArgCIndex(idx);
   1329                 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) {
   1330 
   1331                     // If the argument is 'const', GL will not write to it.
   1332                     // In this case, we can use the 'JNI_ABORT' flag to avoid
   1333                     // the need to write back to the Java array
   1334                     out.println(indent +
   1335                                 "if (" + jfunc.getArgName(idx) + "_base) {");
   1336                     out.println(indent + indent +
   1337                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
   1338                                 "->ReleasePrimitiveArrayCritical(" +
   1339                                 (mUseCPlusPlus ? "" : "_env, ") +
   1340                                 jfunc.getArgName(idx) + "_ref, " +
   1341                                 cfunc.getArgName(cIndex) +
   1342                                 "_base,");
   1343                     out.println(indent + indent + indent +
   1344                                 (cfunc.getArgType(cIndex).isConst() ?
   1345                                  "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) +
   1346                                 ");");
   1347                     out.println(indent + "}");
   1348                 } else if (jfunc.getArgType(idx).isBuffer()) {
   1349                     if (! isPointerFunc) {
   1350                         String array = numBufferArgs <= 1 ? "_array" :
   1351                             "_" + cfunc.getArgName(cIndex) + "Array";
   1352                         out.println(indent + "if (" + array + ") {");
   1353                         out.println(indent + indent +
   1354                                     "releasePointer(_env, " + array + ", " +
   1355                                     cfunc.getArgName(cIndex) +
   1356                                     ", " +
   1357                                     (cfunc.getArgType(cIndex).isConst() ?
   1358                                      "JNI_FALSE" : (emitExceptionCheck ?
   1359                                      "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
   1360                                     ");");
   1361                         out.println(indent + "}");
   1362                     }
   1363                 }
   1364             }
   1365         }
   1366 
   1367         // Emit local variable declaration for strings
   1368         if (stringArgs.size() > 0) {
   1369             for (int i = 0; i < stringArgs.size(); i++) {
   1370                 int idx = stringArgs.get(i).intValue();
   1371                 int cIndex = jfunc.getArgCIndex(idx);
   1372                 String cname = cfunc.getArgName(cIndex);
   1373 
   1374                 out.println(indent + "if (_native" + cname + ") {");
   1375                 out.println(indent + "    _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");");
   1376                 out.println(indent + "}");
   1377             }
   1378 
   1379             out.println();
   1380         }
   1381 
   1382         // Copy results back to java arrays
   1383        if (nonPrimitiveArgs.size() > 0) {
   1384             for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
   1385                 int idx = nonPrimitiveArgs.get(i).intValue();
   1386                 int cIndex = jfunc.getArgCIndex(idx);
   1387                 String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase();
   1388                 if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) {
   1389                     remaining  = ((numArrays + numBuffers) <= 1) ? "_remaining" :
   1390                                      "_" + cfunc.getArgName(cIndex) + "Remaining";
   1391                     offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset";
   1392                     out.println(indent +
   1393                                 "if (" + jfunc.getArgName(idx) + ") {");
   1394                     out.println(indent + indent +
   1395                                 "for (int i = 0; i < " + remaining + "; i++) {");
   1396                     out.println(indent + indent + indent +
   1397                                 "jobject " + cfunc.getArgName(cIndex) +
   1398                                 "_new = toEGLHandle(_env, " + baseType +
   1399                                 "Class, " + baseType + "Constructor, " +
   1400                                 cfunc.getArgName(cIndex) + "[i]);");
   1401                     out.println(indent + indent + indent +
   1402                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
   1403                                 "->SetObjectArrayElement(" +
   1404                                 (mUseCPlusPlus ? "" : "_env, ") +
   1405                                 cfunc.getArgName(cIndex) +
   1406                                 "_ref, i + " + offset + ", " +
   1407                                 cfunc.getArgName(cIndex) + "_new);");
   1408                     out.println(indent + indent + "}");
   1409                     out.println(indent + indent +
   1410                                 "delete[] " + jfunc.getArgName(idx) + ";");
   1411                     out.println(indent + "}");
   1412                 }
   1413             }
   1414         }
   1415 
   1416 
   1417         // Throw exception if there is one
   1418         if (emitExceptionCheck) {
   1419             out.println(indent + "if (_exception) {");
   1420             out.println(indent + indent +
   1421                         "jniThrowException(_env, _exceptionType, _exceptionMessage);");
   1422             out.println(indent + "}");
   1423 
   1424         }
   1425 
   1426 
   1427         if (!isVoid) {
   1428             if (cfunc.getType().isEGLHandle()) {
   1429                 String baseType = cfunc.getType().getBaseType().toLowerCase();
   1430                 out.println(indent +
   1431                             "return toEGLHandle(_env, " + baseType + "Class, " +
   1432                             baseType + "Constructor, _returnValue);");
   1433             } else {
   1434                 out.println(indent + "return (" +
   1435                             getJniType(jfunc.getType()) + ")_returnValue;");
   1436             }
   1437         }
   1438 
   1439         out.println("}");
   1440         out.println();
   1441     }
   1442 
   1443 }
   1444