OSDN Git Service

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