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