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