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