JniCodeEmitter.java revision 5afdc87704f82cb6c3576695dd157b65ae6f3d33
1import java.io.PrintStream;
2import java.util.ArrayList;
3import java.util.HashSet;
4import java.util.Iterator;
5import java.util.List;
6
7public class JniCodeEmitter {
8
9    static final boolean mUseCPlusPlus = true;
10    protected boolean mUseContextPointer = true;
11    protected boolean mUseStaticMethods = false;
12    protected String mClassPathName;
13    protected ParameterChecker mChecker;
14    protected List<String> nativeRegistrations = new ArrayList<String>();
15    boolean needsExit;
16    protected static String indent = "    ";
17    HashSet<String> mFunctionsEmitted = new HashSet<String>();
18
19    public static String getJniName(JType jType) {
20        String jniName = "";
21        if (jType.isClass()) {
22            return "L" + jType.getBaseType() + ";";
23        } else if (jType.isArray()) {
24            jniName = "[";
25        }
26
27        String baseType = jType.getBaseType();
28        if (baseType.equals("int")) {
29            jniName += "I";
30        } else if (baseType.equals("float")) {
31            jniName += "F";
32        } else if (baseType.equals("boolean")) {
33            jniName += "Z";
34        } else if (baseType.equals("short")) {
35            jniName += "S";
36        } else if (baseType.equals("long")) {
37            jniName += "L";
38        } else if (baseType.equals("byte")) {
39            jniName += "B";
40        }
41        return jniName;
42    }
43
44
45    public void emitCode(CFunc cfunc, String original,
46            PrintStream javaInterfaceStream,
47            PrintStream javaImplStream,
48            PrintStream cStream) {
49        JFunc jfunc;
50        String signature;
51        boolean duplicate;
52
53        if (cfunc.hasTypedPointerArg()) {
54            jfunc = JFunc.convert(cfunc, true);
55
56            // Don't emit duplicate functions
57            // These may appear because they are defined in multiple
58            // Java interfaces (e.g., GL11/GL11ExtensionPack)
59            signature = jfunc.toString();
60            duplicate = false;
61            if (mFunctionsEmitted.contains(signature)) {
62                duplicate = true;
63            } else {
64                mFunctionsEmitted.add(signature);
65            }
66
67            if (!duplicate) {
68                emitNativeDeclaration(jfunc, javaImplStream);
69                emitJavaCode(jfunc, javaImplStream);
70            }
71            if (javaInterfaceStream != null) {
72                emitJavaInterfaceCode(jfunc, javaInterfaceStream);
73            }
74            if (!duplicate) {
75                emitJniCode(jfunc, cStream);
76            }
77        }
78
79        jfunc = JFunc.convert(cfunc, false);
80
81        signature = jfunc.toString();
82        duplicate = false;
83        if (mFunctionsEmitted.contains(signature)) {
84            duplicate = true;
85        } else {
86            mFunctionsEmitted.add(signature);
87        }
88
89        if (!duplicate) {
90            emitNativeDeclaration(jfunc, javaImplStream);
91        }
92        if (javaInterfaceStream != null) {
93            emitJavaInterfaceCode(jfunc, javaInterfaceStream);
94        }
95        if (!duplicate) {
96            emitJavaCode(jfunc, javaImplStream);
97            emitJniCode(jfunc, cStream);
98        }
99    }
100
101    public void emitNativeDeclaration(JFunc jfunc, PrintStream out) {
102        out.println("    // C function " + jfunc.getCFunc().getOriginal());
103        out.println();
104
105        emitFunction(jfunc, out, true, false);
106    }
107
108    public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) {
109        emitFunction(jfunc, out, false, true);
110    }
111
112    public void emitJavaCode(JFunc jfunc, PrintStream out) {
113        emitFunction(jfunc, out, false, false);
114    }
115
116    void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) {
117        boolean isVoid = jfunc.getType().isVoid();
118        boolean isPointerFunc = jfunc.getName().endsWith("Pointer") &&
119            jfunc.getCFunc().hasPointerArg();
120
121        if (!isVoid) {
122            out.println(iii +
123                        jfunc.getType() + " _returnValue;");
124        }
125        out.println(iii +
126                    (isVoid ? "" : "_returnValue = ") +
127                    jfunc.getName() +
128                    (isPointerFunc ? "Bounds" : "" ) +
129                    "(");
130
131        int numArgs = jfunc.getNumArgs();
132        for (int i = 0; i < numArgs; i++) {
133            String argName = jfunc.getArgName(i);
134            JType argType = jfunc.getArgType(i);
135
136            if (grabArray && argType.isTypedBuffer()) {
137                String typeName = argType.getBaseType();
138                typeName = typeName.substring(9, typeName.length() - 6);
139                out.println(iii + indent + "get" + typeName + "Array(" + argName + "),");
140                out.print(iii + indent + "getOffset(" + argName + ")");
141            } else {
142                out.print(iii + indent + argName);
143            }
144            if (i == numArgs - 1) {
145                if (isPointerFunc) {
146                    out.println(",");
147                    out.println(iii + indent + argName + ".remaining()");
148                } else {
149                    out.println();
150                }
151            } else {
152                out.println(",");
153            }
154        }
155
156        out.println(iii + ");");
157    }
158
159    void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
160            String iii) {
161                printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
162                                      "offset", "_remaining", iii);
163            }
164
165    void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
166            String offset, String remaining, String iii) {
167                out.println(iii + "    default:");
168                out.println(iii + "        _needed = 0;");
169                out.println(iii + "        break;");
170                out.println(iii + "}");
171
172                out.println(iii + "if (" + remaining + " < _needed) {");
173                if (emitExceptionCheck) {
174                    out.println(iii + indent + "_exception = 1;");
175                }
176                out.println(iii + indent +
177                            (mUseCPlusPlus ? "_env" : "(*_env)") +
178                            "->ThrowNew(" +
179                            (mUseCPlusPlus ? "" : "_env, ") +
180                            "IAEClass, " +
181                            "\"" +
182                            (isBuffer ?
183                             "remaining()" : "length - " + offset) +
184                            " < needed\");");
185                out.println(iii + indent + "goto exit;");
186                needsExit = true;
187                out.println(iii + "}");
188            }
189
190    boolean isNullAllowed(CFunc cfunc) {
191        String[] checks = mChecker.getChecks(cfunc.getName());
192        int index = 1;
193        if (checks != null) {
194            while (index < checks.length) {
195                if (checks[index].equals("return")) {
196                    index += 2;
197                } else if (checks[index].startsWith("check")) {
198                    index += 3;
199                } else if (checks[index].equals("ifcheck")) {
200                    index += 5;
201                } else if (checks[index].equals("unsupported")) {
202                    index += 1;
203                } else if (checks[index].equals("nullAllowed")) {
204                    return true;
205                } else {
206                    System.out.println("Error: unknown keyword \"" +
207                                       checks[index] + "\"");
208                    System.exit(0);
209                }
210            }
211        }
212        return false;
213    }
214
215    String getErrorReturnValue(CFunc cfunc) {
216        CType returnType = cfunc.getType();
217        boolean isVoid = returnType.isVoid();
218        if (isVoid) {
219            return null;
220        }
221
222        String[] checks = mChecker.getChecks(cfunc.getName());
223
224        int index = 1;
225        if (checks != null) {
226            while (index < checks.length) {
227                if (checks[index].equals("return")) {
228                    return checks[index + 1];
229                } else if (checks[index].startsWith("check")) {
230                    index += 3;
231                } else if (checks[index].equals("ifcheck")) {
232                    index += 5;
233                } else if (checks[index].equals("unsupported")) {
234                    index += 1;
235                } else if (checks[index].equals("nullAllowed")) {
236                    index += 1;
237                } else {
238                    System.out.println("Error: unknown keyword \"" +
239                                       checks[index] + "\"");
240                    System.exit(0);
241                }
242            }
243        }
244
245        return null;
246    }
247
248    boolean isUnsupportedFunc(CFunc cfunc) {
249        String[] checks = mChecker.getChecks(cfunc.getName());
250        int index = 1;
251        if (checks != null) {
252            while (index < checks.length) {
253                if (checks[index].equals("unsupported")) {
254                    return true;
255                } else if (checks[index].equals("return")) {
256                    index += 2;
257                } else if (checks[index].startsWith("check")) {
258                    index += 3;
259                } else if (checks[index].equals("ifcheck")) {
260                    index += 5;
261                } else if (checks[index].equals("nullAllowed")) {
262                    index += 1;
263                } else {
264                    System.out.println("Error: unknown keyword \"" +
265                                       checks[index] + "\"");
266                    System.exit(0);
267                }
268            }
269        }
270        return false;
271    }
272
273    void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
274            boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) {
275
276                String[] checks = mChecker.getChecks(cfunc.getName());
277
278                boolean lastWasIfcheck = false;
279
280                int index = 1;
281                if (checks != null) {
282                    while (index < checks.length) {
283                        if (checks[index].startsWith("check")) {
284                            if (lastWasIfcheck) {
285                                printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
286                                                      offset, remaining, iii);
287                            }
288                            lastWasIfcheck = false;
289                            if (cname != null && !cname.equals(checks[index + 1])) {
290                                index += 3;
291                                continue;
292                            }
293                            out.println(iii + "if (" + remaining + " < " +
294                                        checks[index + 2] +
295                                        ") {");
296                            if (emitExceptionCheck) {
297                                out.println(iii + indent + "_exception = 1;");
298                            }
299                    String exceptionClassName = "IAEClass";
300                    // If the "check" keyword was of the form
301                    // "check_<class name>", use the class name in the
302                    // exception to be thrown
303                    int underscore = checks[index].indexOf('_');
304                    if (underscore >= 0) {
305                    exceptionClassName = checks[index].substring(underscore + 1) + "Class";
306                    }
307                            out.println(iii + indent +
308                                        (mUseCPlusPlus ? "_env" : "(*_env)") +
309                                        "->ThrowNew(" +
310                                        (mUseCPlusPlus ? "" : "_env, ") +
311                        exceptionClassName + ", " +
312                                        "\"" +
313                                        (isBuffer ?
314                                         "remaining()" : "length - " + offset) +
315                                        " < " + checks[index + 2] +
316                                        "\");");
317
318                            out.println(iii + indent + "goto exit;");
319                            needsExit = true;
320                            out.println(iii + "}");
321
322                            index += 3;
323                        } else if (checks[index].equals("ifcheck")) {
324                            String[] matches = checks[index + 4].split(",");
325
326                            if (!lastWasIfcheck) {
327                                out.println(iii + "int _needed;");
328                                out.println(iii +
329                                            "switch (" +
330                                            checks[index + 3] +
331                                            ") {");
332                            }
333
334                            for (int i = 0; i < matches.length; i++) {
335                                out.println("#if defined(" + matches[i] + ")");
336                                out.println(iii +
337                                            "    case " +
338                                            matches[i] +
339                                            ":");
340                                out.println("#endif // defined(" + matches[i] + ")");
341                            }
342                            out.println(iii +
343                                        "        _needed = " +
344                                        checks[index + 2] +
345                                        ";");
346                            out.println(iii +
347                                        "        break;");
348
349                            lastWasIfcheck = true;
350                            index += 5;
351                        } else if (checks[index].equals("return")) {
352                            // ignore
353                            index += 2;
354                        } else if (checks[index].equals("unsupported")) {
355                            // ignore
356                            index += 1;
357                        } else if (checks[index].equals("nullAllowed")) {
358                            // ignore
359                            index += 1;
360                        } else {
361                            System.out.println("Error: unknown keyword \"" +
362                                               checks[index] + "\"");
363                            System.exit(0);
364                        }
365                    }
366                }
367
368                if (lastWasIfcheck) {
369                    printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
370                }
371            }
372
373    boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) {
374        if (nonPrimitiveArgs.size() > 0) {
375            for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
376                int idx = nonPrimitiveArgs.get(i).intValue();
377                int cIndex = jfunc.getArgCIndex(idx);
378                if (jfunc.getArgType(idx).isArray()) {
379                    if (!cfunc.getArgType(cIndex).isConst()) {
380                        return true;
381                    }
382                } else if (jfunc.getArgType(idx).isBuffer()) {
383                    if (!cfunc.getArgType(cIndex).isConst()) {
384                        return true;
385                    }
386                }
387            }
388        }
389
390        return false;
391    }
392
393    /**
394     * Emit a function in several variants:
395     *
396     * if nativeDecl: public native <returntype> func(args);
397     *
398     * if !nativeDecl:
399     *   if interfaceDecl:  public <returntype> func(args);
400     *   if !interfaceDecl: public <returntype> func(args) { body }
401     */
402    void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) {
403        boolean isPointerFunc =
404            jfunc.getName().endsWith("Pointer") &&
405            jfunc.getCFunc().hasPointerArg();
406
407        if (!nativeDecl && !interfaceDecl && !isPointerFunc) {
408            // If it's not a pointer function, we've already emitted it
409            // with nativeDecl == true
410            return;
411        }
412
413        String maybeStatic = mUseStaticMethods ? "static " : "";
414
415        if (isPointerFunc) {
416            out.println(indent +
417                        (nativeDecl ? "private " + maybeStatic +"native " :
418                         (interfaceDecl ? "" : "public ") + maybeStatic) +
419                        jfunc.getType() + " " +
420                        jfunc.getName() +
421                        (nativeDecl ? "Bounds" : "") +
422                        "(");
423        } else {
424            out.println(indent +
425                        (nativeDecl ? "public " + maybeStatic +"native " :
426                         (interfaceDecl ? "" : "public ") + maybeStatic) +
427                        jfunc.getType() + " " +
428                        jfunc.getName() +
429                        "(");
430        }
431
432        int numArgs = jfunc.getNumArgs();
433        for (int i = 0; i < numArgs; i++) {
434            String argName = jfunc.getArgName(i);
435            JType argType = jfunc.getArgType(i);
436
437            out.print(indent + indent + argType + " " + argName);
438            if (i == numArgs - 1) {
439                if (isPointerFunc && nativeDecl) {
440                    out.println(",");
441                    out.println(indent + indent + "int remaining");
442                } else {
443                    out.println();
444                }
445            } else {
446                out.println(",");
447            }
448        }
449
450        if (nativeDecl || interfaceDecl) {
451            out.println(indent + ");");
452        } else {
453            out.println(indent + ") {");
454
455            String iii = indent + indent;
456
457            // emitBoundsChecks(jfunc, out, iii);
458            emitFunctionCall(jfunc, out, iii, false);
459
460            // Set the pointer after we call the native code, so that if
461            // the native code throws an exception we don't modify the
462            // pointer. We assume that the native code is written so that
463            // if an exception is thrown, then the underlying glXXXPointer
464            // function will not have been called.
465
466            String fname = jfunc.getName();
467            if (isPointerFunc) {
468                // TODO - deal with VBO variants
469                if (fname.equals("glColorPointer")) {
470                    out.println(iii + "if ((size == 4) &&");
471                    out.println(iii + "    ((type == GL_FLOAT) ||");
472                    out.println(iii + "     (type == GL_UNSIGNED_BYTE) ||");
473                    out.println(iii + "     (type == GL_FIXED)) &&");
474                    out.println(iii + "    (stride >= 0)) {");
475                    out.println(iii + indent + "_colorPointer = pointer;");
476                    out.println(iii + "}");
477                } else if (fname.equals("glNormalPointer")) {
478                    out.println(iii + "if (((type == GL_FLOAT) ||");
479                    out.println(iii + "     (type == GL_BYTE) ||");
480                    out.println(iii + "     (type == GL_SHORT) ||");
481                    out.println(iii + "     (type == GL_FIXED)) &&");
482                    out.println(iii + "    (stride >= 0)) {");
483                    out.println(iii + indent + "_normalPointer = pointer;");
484                    out.println(iii + "}");
485                } else if (fname.equals("glTexCoordPointer")) {
486                    out.println(iii + "if (((size == 2) ||");
487                    out.println(iii + "     (size == 3) ||");
488                    out.println(iii + "     (size == 4)) &&");
489                    out.println(iii + "    ((type == GL_FLOAT) ||");
490                    out.println(iii + "     (type == GL_BYTE) ||");
491                    out.println(iii + "     (type == GL_SHORT) ||");
492                    out.println(iii + "     (type == GL_FIXED)) &&");
493                    out.println(iii + "    (stride >= 0)) {");
494                    out.println(iii + indent + "_texCoordPointer = pointer;");
495                    out.println(iii + "}");
496                } else if (fname.equals("glVertexPointer")) {
497                    out.println(iii + "if (((size == 2) ||");
498                    out.println(iii + "     (size == 3) ||");
499                    out.println(iii + "     (size == 4)) &&");
500                    out.println(iii + "    ((type == GL_FLOAT) ||");
501                    out.println(iii + "     (type == GL_BYTE) ||");
502                    out.println(iii + "     (type == GL_SHORT) ||");
503                    out.println(iii + "     (type == GL_FIXED)) &&");
504                    out.println(iii + "    (stride >= 0)) {");
505                    out.println(iii + indent + "_vertexPointer = pointer;");
506                    out.println(iii + "}");
507                }
508            }
509
510            boolean isVoid = jfunc.getType().isVoid();
511
512            if (!isVoid) {
513                out.println(indent + indent + "return _returnValue;");
514            }
515            out.println(indent + "}");
516        }
517        out.println();
518    }
519
520    public void addNativeRegistration(String s) {
521        nativeRegistrations.add(s);
522    }
523
524    public void emitNativeRegistration(String registrationFunctionName,
525            PrintStream cStream) {
526        cStream.println("static const char *classPathName = \"" +
527                        mClassPathName +
528                        "\";");
529        cStream.println();
530
531        cStream.println("static JNINativeMethod methods[] = {");
532
533        cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },");
534
535        Iterator<String> i = nativeRegistrations.iterator();
536        while (i.hasNext()) {
537            cStream.println(i.next());
538        }
539
540        cStream.println("};");
541        cStream.println();
542
543
544        cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)");
545        cStream.println("{");
546        cStream.println(indent +
547                        "int err;");
548
549        cStream.println(indent +
550                        "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));");
551
552        cStream.println(indent + "return err;");
553        cStream.println("}");
554    }
555
556    public JniCodeEmitter() {
557        super();
558    }
559
560    String getJniType(JType jType) {
561        if (jType.isVoid()) {
562            return "void";
563        }
564
565        String baseType = jType.getBaseType();
566        if (jType.isPrimitive()) {
567            if (baseType.equals("String")) {
568                return "jstring";
569            } else {
570                return "j" + baseType;
571            }
572        } else if (jType.isArray()) {
573            return "j" + baseType + "Array";
574        } else {
575            return "jobject";
576        }
577    }
578
579    String getJniMangledName(String name) {
580        name = name.replaceAll("_", "_1");
581        name = name.replaceAll(";", "_2");
582        name = name.replaceAll("\\[", "_3");
583        return name;
584    }
585
586    public void emitJniCode(JFunc jfunc, PrintStream out) {
587        CFunc cfunc = jfunc.getCFunc();
588
589        // Emit comment identifying original C function
590        //
591        // Example:
592        //
593        // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
594        //
595        out.println("/* " + cfunc.getOriginal() + " */");
596
597        // Emit JNI signature (name)
598        //
599        // Example:
600        //
601        // void
602        // android_glClipPlanef__I_3FI
603        //
604
605        String outName = "android_" + jfunc.getName();
606        boolean isPointerFunc = outName.endsWith("Pointer") &&
607            jfunc.getCFunc().hasPointerArg();
608        boolean isVBOPointerFunc = (outName.endsWith("Pointer") ||
609            outName.endsWith("DrawElements")) &&
610            !jfunc.getCFunc().hasPointerArg();
611        if (isPointerFunc) {
612            outName += "Bounds";
613        }
614
615        out.print("static ");
616        out.println(getJniType(jfunc.getType()));
617        out.print(outName);
618
619        String rsignature = getJniName(jfunc.getType());
620
621        String signature = "";
622        int numArgs = jfunc.getNumArgs();
623        for (int i = 0; i < numArgs; i++) {
624            JType argType = jfunc.getArgType(i);
625            signature += getJniName(argType);
626        }
627        if (isPointerFunc) {
628            signature += "I";
629        }
630
631        // Append signature to function name
632        String sig = getJniMangledName(signature).replace('.', '_');
633        out.print("__" + sig);
634        outName += "__" + sig;
635
636        signature = signature.replace('.', '/');
637        rsignature = rsignature.replace('.', '/');
638
639        out.println();
640        if (rsignature.length() == 0) {
641            rsignature = "V";
642        }
643
644        String s = "{\"" +
645            jfunc.getName() +
646            (isPointerFunc ? "Bounds" : "") +
647            "\", \"(" + signature +")" +
648            rsignature +
649            "\", (void *) " +
650            outName +
651            " },";
652        nativeRegistrations.add(s);
653
654        List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
655        int numBufferArgs = 0;
656        List<String> bufferArgNames = new ArrayList<String>();
657
658        // Emit JNI signature (arguments)
659        //
660        // Example:
661        //
662        // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) {
663        //
664        out.print("  (JNIEnv *_env, jobject _this");
665        for (int i = 0; i < numArgs; i++) {
666            out.print(", ");
667            JType argType = jfunc.getArgType(i);
668            String suffix;
669            if (!argType.isPrimitive()) {
670                if (argType.isArray()) {
671                    suffix = "_ref";
672                } else {
673                    suffix = "_buf";
674                }
675                nonPrimitiveArgs.add(new Integer(i));
676                if (jfunc.getArgType(i).isBuffer()) {
677                    int cIndex = jfunc.getArgCIndex(i);
678                    String cname = cfunc.getArgName(cIndex);
679                    bufferArgNames.add(cname);
680                    numBufferArgs++;
681                }
682            } else {
683                suffix = "";
684            }
685
686            out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
687        }
688        if (isPointerFunc) {
689            out.print(", jint remaining");
690        }
691        out.println(") {");
692
693        int numArrays = 0;
694        int numBuffers = 0;
695        for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
696            int idx = nonPrimitiveArgs.get(i).intValue();
697            if (jfunc.getArgType(idx).isArray()) {
698                ++numArrays;
699            }
700            if (jfunc.getArgType(idx).isBuffer()) {
701                ++numBuffers;
702            }
703        }
704
705        // Emit method body
706
707        // Emit local variable declarations for _exception and _returnValue
708        //
709        // Example:
710        //
711        // android::gl::ogles_context_t *ctx;
712        //
713        // jint _exception;
714        // GLenum _returnValue;
715        //
716        CType returnType = cfunc.getType();
717        boolean isVoid = returnType.isVoid();
718
719        boolean isUnsupported = isUnsupportedFunc(cfunc);
720        if (isUnsupported) {
721            out.println(indent +
722                        "_env->ThrowNew(UOEClass,");
723            out.println(indent +
724                        "    \"" + cfunc.getName() + "\");");
725            if (!isVoid) {
726                String retval = getErrorReturnValue(cfunc);
727                out.println(indent + "return " + retval + ";");
728            }
729            out.println("}");
730            out.println();
731            return;
732        }
733
734        if (mUseContextPointer) {
735            out.println(indent +
736                "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
737        }
738
739        boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) &&
740            hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs);
741        // mChecker.getChecks(cfunc.getName()) != null
742
743        // Emit an _exeption variable if there will be error checks
744        if (emitExceptionCheck) {
745            out.println(indent + "jint _exception = 0;");
746        }
747
748        // Emit a single _array or multiple _XXXArray variables
749        if (numBufferArgs == 1) {
750                out.println(indent + "jarray _array = (jarray) 0;");
751        } else {
752            for (int i = 0; i < numBufferArgs; i++) {
753                out.println(indent + "jarray _" + bufferArgNames.get(i) +
754                            "Array = (jarray) 0;");
755            }
756        }
757        if (!isVoid) {
758            String retval = getErrorReturnValue(cfunc);
759            if (retval != null) {
760                out.println(indent + returnType.getDeclaration() +
761                            " _returnValue = " + retval + ";");
762            } else {
763                out.println(indent + returnType.getDeclaration() +
764                            " _returnValue;");
765            }
766        }
767
768        // Emit local variable declarations for pointer arguments
769        //
770        // Example:
771        //
772        // GLfixed *eqn_base;
773        // GLfixed *eqn;
774        //
775        String offset = "offset";
776        String remaining = "_remaining";
777        if (nonPrimitiveArgs.size() > 0) {
778            for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
779                int idx = nonPrimitiveArgs.get(i).intValue();
780                int cIndex = jfunc.getArgCIndex(idx);
781                String cname = cfunc.getArgName(cIndex);
782
783                CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
784                String decl = type.getDeclaration();
785                if (jfunc.getArgType(idx).isArray()) {
786                    out.println(indent +
787                                decl +
788                                (decl.endsWith("*") ? "" : " ") +
789                                jfunc.getArgName(idx) +
790                                "_base = (" + decl + ") 0;");
791                }
792                remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
793                    "_" + cname + "Remaining";
794                out.println(indent +
795                            "jint " + remaining + ";");
796                out.println(indent +
797                            decl +
798                            (decl.endsWith("*") ? "" : " ") +
799                            jfunc.getArgName(idx) +
800                            " = (" + decl + ") 0;");
801            }
802
803            out.println();
804        }
805
806        // Emit 'GetPrimitiveArrayCritical' for arrays
807        // Emit 'GetPointer' calls for Buffer pointers
808        int bufArgIdx = 0;
809        if (nonPrimitiveArgs.size() > 0) {
810            for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
811                int idx = nonPrimitiveArgs.get(i).intValue();
812                int cIndex = jfunc.getArgCIndex(idx);
813
814                String cname = cfunc.getArgName(cIndex);
815                offset = numArrays <= 1 ? "offset" :
816                    cname + "Offset";
817                remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
818                    "_" + cname + "Remaining";
819
820                if (jfunc.getArgType(idx).isArray()) {
821                    out.println(indent +
822                                "if (!" +
823                                cname +
824                                "_ref) {");
825                    if (emitExceptionCheck) {
826                        out.println(indent + indent + "_exception = 1;");
827                    }
828                    out.println(indent + "    " +
829                                (mUseCPlusPlus ? "_env" : "(*_env)") +
830                                "->ThrowNew(" +
831                                (mUseCPlusPlus ? "" : "_env, ") +
832                                "IAEClass, " +
833                                "\"" + cname +
834                                " == null\");");
835                    out.println(indent + "    goto exit;");
836                    needsExit = true;
837                    out.println(indent + "}");
838
839                    out.println(indent + "if (" + offset + " < 0) {");
840                    if (emitExceptionCheck) {
841                        out.println(indent + indent + "_exception = 1;");
842                    }
843                    out.println(indent + "    " +
844                                (mUseCPlusPlus ? "_env" : "(*_env)") +
845                                "->ThrowNew(" +
846                                (mUseCPlusPlus ? "" : "_env, ") +
847                                "IAEClass, " +
848                                "\"" + offset + " < 0\");");
849                    out.println(indent + "    goto exit;");
850                    needsExit = true;
851                    out.println(indent + "}");
852
853                    out.println(indent + remaining + " = " +
854                                    (mUseCPlusPlus ? "_env" : "(*_env)") +
855                                    "->GetArrayLength(" +
856                                    (mUseCPlusPlus ? "" : "_env, ") +
857                                    cname + "_ref) - " + offset + ";");
858
859                    emitNativeBoundsChecks(cfunc, cname, out, false,
860                                           emitExceptionCheck,
861                                           offset, remaining, "    ");
862
863                    out.println(indent +
864                                cname +
865                                "_base = (" +
866                                cfunc.getArgType(cIndex).getDeclaration() +
867                                ")");
868                    out.println(indent + "    " +
869                                (mUseCPlusPlus ? "_env" : "(*_env)") +
870                                "->GetPrimitiveArrayCritical(" +
871                                (mUseCPlusPlus ? "" : "_env, ") +
872                                jfunc.getArgName(idx) +
873                                "_ref, (jboolean *)0);");
874                    out.println(indent +
875                                cname + " = " + cname + "_base + " + offset +
876                                ";");
877                    out.println();
878                } else {
879                    String array = numBufferArgs <= 1 ? "_array" :
880                        "_" + bufferArgNames.get(bufArgIdx++) + "Array";
881
882                    boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc;
883                    if (nullAllowed) {
884                        out.println(indent + "if (" + cname + "_buf) {");
885                        out.print(indent);
886                    }
887
888                    if (isPointerFunc) {
889                        out.println(indent +
890                                cname +
891                                " = (" +
892                                cfunc.getArgType(cIndex).getDeclaration() +
893                                ") getDirectBufferPointer(_env, " +
894                                cname + "_buf);");
895                        String iii = "    ";
896                        out.println(iii + indent + "if ( ! " + cname + " ) {");
897                        out.println(iii + iii + indent + "return;");
898                        out.println(iii + indent + "}");
899                    } else {
900                        out.println(indent +
901                                    cname +
902                                    " = (" +
903                                    cfunc.getArgType(cIndex).getDeclaration() +
904                                    ")getPointer(_env, " +
905                                    cname +
906                                    "_buf, &" + array + ", &" + remaining +
907                                    ");");
908                    }
909
910                    emitNativeBoundsChecks(cfunc, cname, out, true,
911                                           emitExceptionCheck,
912                                           offset, remaining, nullAllowed ? "        " : "    ");
913
914                    if (nullAllowed) {
915                        out.println(indent + "}");
916                    }
917                }
918            }
919        }
920
921        if (!isVoid) {
922            out.print(indent + "_returnValue = ");
923        } else {
924            out.print(indent);
925        }
926        String name = cfunc.getName();
927
928        if (mUseContextPointer) {
929            name = name.substring(2, name.length()); // Strip off 'gl' prefix
930            name = name.substring(0, 1).toLowerCase() +
931                name.substring(1, name.length());
932            out.print("ctx->procs.");
933        }
934
935        out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
936
937        numArgs = cfunc.getNumArgs();
938        if (numArgs == 0) {
939            if (mUseContextPointer) {
940                out.println("ctx);");
941            } else {
942                out.println(");");
943            }
944        } else {
945            if (mUseContextPointer) {
946                out.println("ctx,");
947            } else {
948                out.println();
949            }
950            for (int i = 0; i < numArgs; i++) {
951                String typecast;
952                if (i == numArgs - 1 && isVBOPointerFunc) {
953                    typecast = "const GLvoid *";
954                } else {
955                    typecast = cfunc.getArgType(i).getDeclaration();
956                }
957                out.print(indent + indent +
958                          "(" +
959                          typecast +
960                          ")" +
961                          cfunc.getArgName(i));
962
963                if (i == numArgs - 1) {
964                    if (isPointerFunc) {
965                        out.println(",");
966                        out.println(indent + indent + "(GLsizei)remaining");
967                    } else {
968                        out.println();
969                    }
970                } else {
971                    out.println(",");
972                }
973            }
974            out.println(indent + ");");
975        }
976
977        if (needsExit) {
978            out.println();
979            out.println("exit:");
980            needsExit = false;
981        }
982
983        bufArgIdx = 0;
984        if (nonPrimitiveArgs.size() > 0) {
985            for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
986                int idx = nonPrimitiveArgs.get(i).intValue();
987
988                int cIndex = jfunc.getArgCIndex(idx);
989                if (jfunc.getArgType(idx).isArray()) {
990
991                    // If the argument is 'const', GL will not write to it.
992                    // In this case, we can use the 'JNI_ABORT' flag to avoid
993                    // the need to write back to the Java array
994                    out.println(indent +
995                                "if (" + jfunc.getArgName(idx) + "_base) {");
996                    out.println(indent + indent +
997                                (mUseCPlusPlus ? "_env" : "(*_env)") +
998                                "->ReleasePrimitiveArrayCritical(" +
999                                (mUseCPlusPlus ? "" : "_env, ") +
1000                                jfunc.getArgName(idx) + "_ref, " +
1001                                cfunc.getArgName(cIndex) +
1002                                "_base,");
1003                    out.println(indent + indent + indent +
1004                                (cfunc.getArgType(cIndex).isConst() ?
1005                                 "JNI_ABORT" :
1006                                 "_exception ? JNI_ABORT: 0") +
1007                                ");");
1008                    out.println(indent + "}");
1009                } else if (jfunc.getArgType(idx).isBuffer()) {
1010                    if (! isPointerFunc) {
1011                        String array = numBufferArgs <= 1 ? "_array" :
1012                            "_" + bufferArgNames.get(bufArgIdx++) + "Array";
1013                        out.println(indent + "if (" + array + ") {");
1014                        out.println(indent + indent +
1015                                    "releasePointer(_env, " + array + ", " +
1016                                    cfunc.getArgName(cIndex) +
1017                                    ", " +
1018                                    (cfunc.getArgType(cIndex).isConst() ?
1019                                     "JNI_FALSE" : "_exception ? JNI_FALSE :" +
1020                                             " JNI_TRUE") +
1021                                    ");");
1022                        out.println(indent + "}");
1023                    }
1024                }
1025            }
1026        }
1027
1028        if (!isVoid) {
1029            out.println(indent + "return _returnValue;");
1030        }
1031
1032        out.println("}");
1033        out.println();
1034    }
1035
1036}
1037