2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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;
23 public class JniCodeEmitter {
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>();
32 protected static String indent = " ";
33 HashSet<String> mFunctionsEmitted = new HashSet<String>();
35 public static String getJniName(JType jType) {
37 if (jType.isClass()) {
38 return "L" + jType.getBaseType() + ";";
39 } else if (jType.isArray()) {
43 String baseType = jType.getBaseType();
44 if (baseType.equals("int")) {
46 } else if (baseType.equals("float")) {
48 } else if (baseType.equals("boolean")) {
50 } else if (baseType.equals("short")) {
52 } else if (baseType.equals("long")) {
54 } else if (baseType.equals("byte")) {
56 } else if (baseType.equals("String")) {
57 jniName += "Ljava/lang/String;";
58 } else if (baseType.equals("void")) {
61 throw new RuntimeException("Uknown primitive basetype " + baseType);
67 public void emitCode(CFunc cfunc, String original,
68 PrintStream javaInterfaceStream,
69 PrintStream javaImplStream,
70 PrintStream cStream) {
75 if (cfunc.hasTypedPointerArg()) {
76 jfunc = JFunc.convert(cfunc, true);
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();
83 if (mFunctionsEmitted.contains(signature)) {
86 mFunctionsEmitted.add(signature);
90 emitNativeDeclaration(jfunc, javaImplStream);
91 emitJavaCode(jfunc, javaImplStream);
93 if (javaInterfaceStream != null) {
94 emitJavaInterfaceCode(jfunc, javaInterfaceStream);
97 emitJniCode(jfunc, cStream);
101 jfunc = JFunc.convert(cfunc, false);
103 signature = jfunc.toString();
105 if (mFunctionsEmitted.contains(signature)) {
108 mFunctionsEmitted.add(signature);
112 emitNativeDeclaration(jfunc, javaImplStream);
114 if (javaInterfaceStream != null) {
115 emitJavaInterfaceCode(jfunc, javaInterfaceStream);
118 emitJavaCode(jfunc, javaImplStream);
119 emitJniCode(jfunc, cStream);
123 public void emitNativeDeclaration(JFunc jfunc, PrintStream out) {
124 out.println(" // C function " + jfunc.getCFunc().getOriginal());
127 emitFunction(jfunc, out, true, false);
130 public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) {
131 emitFunction(jfunc, out, false, true);
134 public void emitJavaCode(JFunc jfunc, PrintStream out) {
135 emitFunction(jfunc, out, false, false);
138 boolean isPointerFunc(JFunc jfunc) {
139 String name = jfunc.getName();
140 return (name.endsWith("Pointer") || name.endsWith("PointerOES"))
141 && jfunc.getCFunc().hasPointerArg();
144 void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) {
145 boolean isVoid = jfunc.getType().isVoid();
146 boolean isPointerFunc = isPointerFunc(jfunc);
150 jfunc.getType() + " _returnValue;");
153 (isVoid ? "" : "_returnValue = ") +
155 (isPointerFunc ? "Bounds" : "" ) +
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);
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 + ")");
169 out.print(iii + indent + argName);
171 if (i == numArgs - 1) {
174 out.println(iii + indent + argName + ".remaining()");
183 out.println(iii + ");");
186 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
188 printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
189 "offset", "_remaining", iii);
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 + "}");
199 out.println(iii + "if (" + remaining + " < _needed) {");
200 if (emitExceptionCheck) {
201 out.println(iii + indent + "_exception = 1;");
203 out.println(iii + indent +
204 (mUseCPlusPlus ? "_env" : "(*_env)") +
206 (mUseCPlusPlus ? "" : "_env, ") +
210 "remaining()" : "length - " + offset) +
212 out.println(iii + indent + "goto exit;");
214 out.println(iii + "}");
217 boolean isNullAllowed(CFunc cfunc) {
218 String[] checks = mChecker.getChecks(cfunc.getName());
220 if (checks != null) {
221 while (index < checks.length) {
222 if (checks[index].equals("return")) {
224 } else if (checks[index].startsWith("check")) {
226 } else if (checks[index].equals("ifcheck")) {
228 } else if (checks[index].equals("unsupported")) {
230 } else if (checks[index].equals("requires")) {
232 } else if (checks[index].equals("nullAllowed")) {
235 System.out.println("Error: unknown keyword \"" +
236 checks[index] + "\"");
244 String getErrorReturnValue(CFunc cfunc) {
245 CType returnType = cfunc.getType();
246 boolean isVoid = returnType.isVoid();
251 String[] checks = mChecker.getChecks(cfunc.getName());
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")) {
260 } else if (checks[index].equals("ifcheck")) {
262 } else if (checks[index].equals("unsupported")) {
264 } else if (checks[index].equals("requires")) {
266 } else if (checks[index].equals("nullAllowed")) {
269 System.out.println("Error: unknown keyword \"" +
270 checks[index] + "\"");
279 boolean isUnsupportedFunc(CFunc cfunc) {
280 String[] checks = mChecker.getChecks(cfunc.getName());
282 if (checks != null) {
283 while (index < checks.length) {
284 if (checks[index].equals("unsupported")) {
286 } else if (checks[index].equals("requires")) {
288 } else if (checks[index].equals("return")) {
290 } else if (checks[index].startsWith("check")) {
292 } else if (checks[index].equals("ifcheck")) {
294 } else if (checks[index].equals("nullAllowed")) {
297 System.out.println("Error: unknown keyword \"" +
298 checks[index] + "\"");
306 String isRequiresFunc(CFunc cfunc) {
307 String[] checks = mChecker.getChecks(cfunc.getName());
309 if (checks != null) {
310 while (index < checks.length) {
311 if (checks[index].equals("unsupported")) {
313 } else if (checks[index].equals("requires")) {
314 return checks[index+1];
315 } else if (checks[index].equals("return")) {
317 } else if (checks[index].startsWith("check")) {
319 } else if (checks[index].equals("ifcheck")) {
321 } else if (checks[index].equals("nullAllowed")) {
324 System.out.println("Error: unknown keyword \"" +
325 checks[index] + "\"");
333 void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
334 boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) {
336 String[] checks = mChecker.getChecks(cfunc.getName());
338 boolean lastWasIfcheck = false;
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);
348 lastWasIfcheck = false;
349 if (cname != null && !cname.equals(checks[index + 1])) {
353 out.println(iii + "if (" + remaining + " < " +
356 if (emitExceptionCheck) {
357 out.println(iii + indent + "_exception = 1;");
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";
367 out.println(iii + indent +
368 (mUseCPlusPlus ? "_env" : "(*_env)") +
370 (mUseCPlusPlus ? "" : "_env, ") +
371 exceptionClassName + ", " +
374 "remaining()" : "length - " + offset) +
375 " < " + checks[index + 2] +
378 out.println(iii + indent + "goto exit;");
380 out.println(iii + "}");
383 } else if (checks[index].equals("ifcheck")) {
384 String[] matches = checks[index + 4].split(",");
386 if (!lastWasIfcheck) {
387 out.println(iii + "int _needed;");
394 for (int i = 0; i < matches.length; i++) {
395 out.println("#if defined(" + matches[i] + ")");
400 out.println("#endif // defined(" + matches[i] + ")");
409 lastWasIfcheck = true;
411 } else if (checks[index].equals("return")) {
414 } else if (checks[index].equals("unsupported")) {
417 } else if (checks[index].equals("requires")) {
420 } else if (checks[index].equals("nullAllowed")) {
424 System.out.println("Error: unknown keyword \"" +
425 checks[index] + "\"");
431 if (lastWasIfcheck) {
432 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
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()) {
445 } else if (jfunc.getArgType(idx).isBuffer()) {
446 if (!cfunc.getArgType(cIndex).isConst()) {
457 * Emit a function in several variants:
459 * if nativeDecl: public native <returntype> func(args);
462 * if interfaceDecl: public <returntype> func(args);
463 * if !interfaceDecl: public <returntype> func(args) { body }
465 void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) {
466 boolean isPointerFunc = isPointerFunc(jfunc);
468 if (!nativeDecl && !interfaceDecl && !isPointerFunc) {
469 // If it's not a pointer function, we've already emitted it
470 // with nativeDecl == true
474 String maybeStatic = mUseStaticMethods ? "static " : "";
478 (nativeDecl ? "private " + maybeStatic +"native " :
479 (interfaceDecl ? "" : "public ") + maybeStatic) +
480 jfunc.getType() + " " +
482 (nativeDecl ? "Bounds" : "") +
486 (nativeDecl ? "public " + maybeStatic +"native " :
487 (interfaceDecl ? "" : "public ") + maybeStatic) +
488 jfunc.getType() + " " +
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);
498 out.print(indent + indent + argType + " " + argName);
499 if (i == numArgs - 1) {
500 if (isPointerFunc && nativeDecl) {
502 out.println(indent + indent + "int remaining");
511 if (nativeDecl || interfaceDecl) {
512 out.println(indent + ");");
514 out.println(indent + ") {");
516 String iii = indent + indent;
518 // emitBoundsChecks(jfunc, out, iii);
519 emitFunctionCall(jfunc, out, iii, false);
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.
527 String fname = jfunc.getName();
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 + "}");
599 boolean isVoid = jfunc.getType().isVoid();
602 out.println(indent + indent + "return _returnValue;");
604 out.println(indent + "}");
609 public void addNativeRegistration(String s) {
610 nativeRegistrations.add(s);
613 public void emitNativeRegistration(String registrationFunctionName,
614 PrintStream cStream) {
615 cStream.println("static const char *classPathName = \"" +
620 cStream.println("static JNINativeMethod methods[] = {");
622 cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },");
624 Iterator<String> i = nativeRegistrations.iterator();
625 while (i.hasNext()) {
626 cStream.println(i.next());
629 cStream.println("};");
633 cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)");
634 cStream.println("{");
635 cStream.println(indent +
638 cStream.println(indent +
639 "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));");
641 cStream.println(indent + "return err;");
642 cStream.println("}");
645 public JniCodeEmitter() {
649 String getJniType(JType jType) {
650 if (jType.isVoid()) {
654 String baseType = jType.getBaseType();
655 if (jType.isPrimitive()) {
656 if (baseType.equals("String")) {
659 return "j" + baseType;
661 } else if (jType.isArray()) {
662 return "j" + baseType + "Array";
668 String getJniMangledName(String name) {
669 name = name.replaceAll("_", "_1");
670 name = name.replaceAll(";", "_2");
671 name = name.replaceAll("\\[", "_3");
675 public void emitJniCode(JFunc jfunc, PrintStream out) {
676 CFunc cfunc = jfunc.getCFunc();
678 // Emit comment identifying original C function
682 // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
684 out.println("/* " + cfunc.getOriginal() + " */");
686 // Emit JNI signature (name)
691 // android_glClipPlanef__I_3FI
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();
704 out.print("static ");
705 out.println(getJniType(jfunc.getType()));
708 String rsignature = getJniName(jfunc.getType());
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);
720 // Append signature to function name
721 String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_');
722 out.print("__" + sig);
723 outName += "__" + sig;
725 signature = signature.replace('.', '/');
726 rsignature = rsignature.replace('.', '/');
729 if (rsignature.length() == 0) {
735 (isPointerFunc ? "Bounds" : "") +
736 "\", \"(" + signature +")" +
741 nativeRegistrations.add(s);
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>();
748 // Emit JNI signature (arguments)
752 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) {
754 out.print(" (JNIEnv *_env, jobject _this");
755 for (int i = 0; i < numArgs; i++) {
757 JType argType = jfunc.getArgType(i);
759 if (!argType.isPrimitive()) {
760 if (argType.isArray()) {
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);
775 if (argType.isString()) {
776 stringArgs.add(new Integer(i));
779 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
782 out.print(", jint remaining");
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()) {
795 if (argType.isBuffer()) {
798 if (argType.isString()) {
805 // Emit local variable declarations for _exception and _returnValue
809 // android::gl::ogles_context_t *ctx;
812 // GLenum _returnValue;
814 CType returnType = cfunc.getType();
815 boolean isVoid = returnType.isVoid();
817 boolean isUnsupported = isUnsupportedFunc(cfunc);
820 "_env->ThrowNew(UOEClass,");
822 " \"" + cfunc.getName() + "\");");
824 String retval = getErrorReturnValue(cfunc);
825 out.println(indent + "return " + retval + ";");
832 String requiresExtension = isRequiresFunc(cfunc);
833 if (requiresExtension != null) {
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() + "\");");
841 out.println(indent + indent + " return;");
843 String retval = getErrorReturnValue(cfunc);
844 out.println(indent + indent + " return " + retval + ";");
846 out.println(indent + "}");
848 if (mUseContextPointer) {
850 "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
853 boolean initializeReturnValue = stringArgs.size() > 0;
855 boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0 || numStrings > 0) &&
856 hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs);
857 // mChecker.getChecks(cfunc.getName()) != null
859 // Emit an _exeption variable if there will be error checks
860 if (emitExceptionCheck) {
861 out.println(indent + "jint _exception = 0;");
864 // Emit a single _array or multiple _XXXArray variables
865 if (numBufferArgs == 1) {
866 out.println(indent + "jarray _array = (jarray) 0;");
868 for (int i = 0; i < numBufferArgs; i++) {
869 out.println(indent + "jarray _" + bufferArgNames.get(i) +
870 "Array = (jarray) 0;");
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;");
882 out.println(indent + returnType.getDeclaration() +
887 // Emit local variable declarations for pointer arguments
891 // GLfixed *eqn_base;
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);
902 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
903 String decl = type.getDeclaration();
904 if (jfunc.getArgType(idx).isArray()) {
907 (decl.endsWith("*") ? "" : " ") +
908 jfunc.getArgName(idx) +
909 "_base = (" + decl + ") 0;");
911 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
912 "_" + cname + "Remaining";
914 "jint " + remaining + ";");
917 (decl.endsWith("*") ? "" : " ") +
918 jfunc.getArgName(idx) +
919 " = (" + decl + ") 0;");
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);
932 out.println(indent + "const char* _native" + cname + " = 0;");
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);
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;");
951 out.println(indent + "}");
953 out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);");
959 // Emit 'GetPrimitiveArrayCritical' for arrays
960 // Emit 'GetPointer' calls for Buffer pointers
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);
967 String cname = cfunc.getArgName(cIndex);
968 offset = numArrays <= 1 ? "offset" :
970 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" :
971 "_" + cname + "Remaining";
973 if (jfunc.getArgType(idx).isArray()) {
978 if (emitExceptionCheck) {
979 out.println(indent + indent + "_exception = 1;");
981 out.println(indent + " " +
982 (mUseCPlusPlus ? "_env" : "(*_env)") +
984 (mUseCPlusPlus ? "" : "_env, ") +
988 out.println(indent + " goto exit;");
990 out.println(indent + "}");
992 out.println(indent + "if (" + offset + " < 0) {");
993 if (emitExceptionCheck) {
994 out.println(indent + indent + "_exception = 1;");
996 out.println(indent + " " +
997 (mUseCPlusPlus ? "_env" : "(*_env)") +
999 (mUseCPlusPlus ? "" : "_env, ") +
1001 "\"" + offset + " < 0\");");
1002 out.println(indent + " goto exit;");
1004 out.println(indent + "}");
1006 out.println(indent + remaining + " = " +
1007 (mUseCPlusPlus ? "_env" : "(*_env)") +
1008 "->GetArrayLength(" +
1009 (mUseCPlusPlus ? "" : "_env, ") +
1010 cname + "_ref) - " + offset + ";");
1012 emitNativeBoundsChecks(cfunc, cname, out, false,
1014 offset, remaining, " ");
1016 out.println(indent +
1019 cfunc.getArgType(cIndex).getDeclaration() +
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 +
1032 String array = numBufferArgs <= 1 ? "_array" :
1033 "_" + bufferArgNames.get(bufArgIdx++) + "Array";
1035 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc;
1037 out.println(indent + "if (" + cname + "_buf) {");
1041 if (isPointerFunc) {
1042 out.println(indent +
1045 cfunc.getArgType(cIndex).getDeclaration() +
1046 ") getDirectBufferPointer(_env, " +
1049 out.println(iii + indent + "if ( ! " + cname + " ) {");
1050 out.println(iii + iii + indent + "return;");
1051 out.println(iii + indent + "}");
1053 out.println(indent +
1056 cfunc.getArgType(cIndex).getDeclaration() +
1057 ")getPointer(_env, " +
1059 "_buf, &" + array + ", &" + remaining +
1063 emitNativeBoundsChecks(cfunc, cname, out, true,
1065 offset, remaining, nullAllowed ? " " : " ");
1068 out.println(indent + "}");
1075 out.print(indent + "_returnValue = ");
1079 String name = cfunc.getName();
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.");
1088 out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
1090 numArgs = cfunc.getNumArgs();
1092 if (mUseContextPointer) {
1093 out.println("ctx);");
1098 if (mUseContextPointer) {
1099 out.println("ctx,");
1103 for (int i = 0; i < numArgs; i++) {
1105 if (i == numArgs - 1 && isVBOPointerFunc) {
1106 typecast = "const GLvoid *";
1108 typecast = cfunc.getArgType(i).getDeclaration();
1110 out.print(indent + indent +
1114 if (cfunc.getArgType(i).isConstCharPointer()) {
1115 out.print("_native");
1117 out.print(cfunc.getArgName(i));
1119 if (i == numArgs - 1) {
1120 if (isPointerFunc) {
1122 out.println(indent + indent + "(GLsizei)remaining");
1130 out.println(indent + ");");
1135 out.println("exit:");
1140 if (nonPrimitiveArgs.size() > 0) {
1141 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
1142 int idx = nonPrimitiveArgs.get(i).intValue();
1144 int cIndex = jfunc.getArgCIndex(idx);
1145 if (jfunc.getArgType(idx).isArray()) {
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) +
1159 out.println(indent + indent + indent +
1160 (cfunc.getArgType(cIndex).isConst() ?
1162 "_exception ? JNI_ABORT: 0") +
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) +
1174 (cfunc.getArgType(cIndex).isConst() ?
1175 "JNI_FALSE" : "_exception ? JNI_FALSE :" +
1178 out.println(indent + "}");
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);
1191 out.println(indent + "if (_native" + cname + ") {");
1192 out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");");
1193 out.println(indent + "}");
1201 out.println(indent + "return _returnValue;");