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