| /* |
| * Copyright (C) 2006 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| import java.io.PrintStream; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| public class JniCodeEmitter { |
| |
| static final boolean mUseCPlusPlus = true; |
| protected boolean mUseContextPointer = true; |
| protected boolean mUseStaticMethods = false; |
| protected boolean mUseSimpleMethodNames = false; |
| protected boolean mUseHideCommentForAPI = false; |
| protected String mClassPathName; |
| protected ParameterChecker mChecker; |
| protected List<String> nativeRegistrations = new ArrayList<String>(); |
| boolean needsExit; |
| protected static String indent = " "; |
| HashSet<String> mFunctionsEmitted = new HashSet<String>(); |
| |
| public static String getJniName(JType jType) { |
| String jniName = ""; |
| if (jType.isEGLHandle()) { |
| return (jType.isArray() ? "[" : "" ) + "Landroid/opengl/" + jType.getBaseType() + ";"; |
| } else if (jType.isClass()) { |
| return "L" + jType.getBaseType() + ";"; |
| } else if (jType.isArray()) { |
| jniName = "["; |
| } |
| |
| String baseType = jType.getBaseType(); |
| if (baseType.equals("int")) { |
| jniName += "I"; |
| } else if (baseType.equals("float")) { |
| jniName += "F"; |
| } else if (baseType.equals("boolean")) { |
| jniName += "Z"; |
| } else if (baseType.equals("short")) { |
| jniName += "S"; |
| } else if (baseType.equals("long")) { |
| jniName += "J"; |
| } else if (baseType.equals("byte")) { |
| jniName += "B"; |
| } else if (baseType.equals("String")) { |
| jniName += "Ljava/lang/String;"; |
| } else if (baseType.equals("void")) { |
| // nothing. |
| } else { |
| throw new RuntimeException("Unknown primitive basetype " + baseType); |
| } |
| return jniName; |
| } |
| |
| public void emitCode(CFunc cfunc, String original, |
| PrintStream javaInterfaceStream, |
| PrintStream javaImplStream, |
| PrintStream cStream) { |
| JFunc jfunc; |
| String signature; |
| boolean duplicate; |
| |
| if (cfunc.hasTypedPointerArg()) { |
| jfunc = JFunc.convert(cfunc, true); |
| |
| // Don't emit duplicate functions |
| // These may appear because they are defined in multiple |
| // Java interfaces (e.g., GL11/GL11ExtensionPack) |
| signature = jfunc.toString(); |
| duplicate = false; |
| if (mFunctionsEmitted.contains(signature)) { |
| duplicate = true; |
| } else { |
| mFunctionsEmitted.add(signature); |
| } |
| |
| if (!duplicate) { |
| emitNativeDeclaration(jfunc, javaImplStream); |
| emitJavaCode(jfunc, javaImplStream); |
| } |
| if (javaInterfaceStream != null) { |
| emitJavaInterfaceCode(jfunc, javaInterfaceStream); |
| } |
| if (!duplicate) { |
| emitJniCode(jfunc, cStream); |
| } |
| // Don't create IOBuffer versions of the EGL functions |
| if (cfunc.hasEGLHandleArg()) { |
| return; |
| } |
| } |
| |
| jfunc = JFunc.convert(cfunc, false); |
| |
| signature = jfunc.toString(); |
| duplicate = false; |
| if (mFunctionsEmitted.contains(signature)) { |
| duplicate = true; |
| } else { |
| mFunctionsEmitted.add(signature); |
| } |
| |
| if (!duplicate) { |
| emitNativeDeclaration(jfunc, javaImplStream); |
| } |
| if (javaInterfaceStream != null) { |
| emitJavaInterfaceCode(jfunc, javaInterfaceStream); |
| } |
| if (!duplicate) { |
| emitJavaCode(jfunc, javaImplStream); |
| emitJniCode(jfunc, cStream); |
| } |
| } |
| |
| public void emitNativeDeclaration(JFunc jfunc, PrintStream out) { |
| if (mUseHideCommentForAPI) { |
| out.println(" /* @hide C function " + jfunc.getCFunc().getOriginal() + " */"); |
| out.println(); |
| } else { |
| out.println(" // C function " + jfunc.getCFunc().getOriginal()); |
| out.println(); |
| } |
| |
| emitFunction(jfunc, out, true, false); |
| } |
| |
| public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) { |
| emitFunction(jfunc, out, false, true); |
| } |
| |
| public void emitJavaCode(JFunc jfunc, PrintStream out) { |
| emitFunction(jfunc, out, false, false); |
| } |
| |
| boolean isPointerFunc(JFunc jfunc) { |
| String name = jfunc.getName(); |
| return (name.endsWith("Pointer") || name.endsWith("PointerOES")) |
| && jfunc.getCFunc().hasPointerArg(); |
| } |
| |
| void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) { |
| boolean isVoid = jfunc.getType().isVoid(); |
| boolean isPointerFunc = isPointerFunc(jfunc); |
| |
| if (!isVoid) { |
| out.println(iii + |
| jfunc.getType() + " _returnValue;"); |
| } |
| out.println(iii + |
| (isVoid ? "" : "_returnValue = ") + |
| jfunc.getName() + |
| (isPointerFunc ? "Bounds" : "" ) + |
| "("); |
| |
| int numArgs = jfunc.getNumArgs(); |
| for (int i = 0; i < numArgs; i++) { |
| String argName = jfunc.getArgName(i); |
| JType argType = jfunc.getArgType(i); |
| |
| if (grabArray && argType.isTypedBuffer()) { |
| String typeName = argType.getBaseType(); |
| typeName = typeName.substring(9, typeName.length() - 6); |
| out.println(iii + indent + "get" + typeName + "Array(" + argName + "),"); |
| out.print(iii + indent + "getOffset(" + argName + ")"); |
| } else { |
| out.print(iii + indent + argName); |
| } |
| if (i == numArgs - 1) { |
| if (isPointerFunc) { |
| out.println(","); |
| out.println(iii + indent + argName + ".remaining()"); |
| } else { |
| out.println(); |
| } |
| } else { |
| out.println(","); |
| } |
| } |
| |
| out.println(iii + ");"); |
| } |
| |
| void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, |
| String iii) { |
| printIfcheckPostamble(out, isBuffer, emitExceptionCheck, |
| "offset", "_remaining", iii); |
| } |
| |
| void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, |
| String offset, String remaining, String iii) { |
| out.println(iii + " default:"); |
| out.println(iii + " _needed = 1;"); |
| out.println(iii + " break;"); |
| out.println(iii + "}"); |
| |
| out.println(iii + "if (" + remaining + " < _needed) {"); |
| out.println(iii + indent + "_exception = 1;"); |
| out.println(iii + indent + |
| "_exceptionType = \"java/lang/IllegalArgumentException\";"); |
| out.println(iii + indent + |
| "_exceptionMessage = \"" + |
| (isBuffer ? "remaining()" : "length - " + offset) + |
| " < needed\";"); |
| out.println(iii + indent + "goto exit;"); |
| out.println(iii + "}"); |
| |
| needsExit = true; |
| } |
| |
| boolean isNullAllowed(CFunc cfunc) { |
| String[] checks = mChecker.getChecks(cfunc.getName()); |
| int index = 1; |
| if (checks != null) { |
| while (index < checks.length) { |
| if (checks[index].equals("nullAllowed")) { |
| return true; |
| } else { |
| index = skipOneCheck(checks, index); |
| } |
| } |
| } |
| return false; |
| } |
| |
| boolean hasCheckTest(CFunc cfunc) { |
| String[] checks = mChecker.getChecks(cfunc.getName()); |
| int index = 1; |
| if (checks != null) { |
| while (index < checks.length) { |
| if (checks[index].startsWith("check")) { |
| return true; |
| } else { |
| index = skipOneCheck(checks, index); |
| } |
| } |
| } |
| return false; |
| } |
| |
| boolean hasIfTest(CFunc cfunc) { |
| String[] checks = mChecker.getChecks(cfunc.getName()); |
| int index = 1; |
| if (checks != null) { |
| while (index < checks.length) { |
| if (checks[index].startsWith("ifcheck")) { |
| return true; |
| } else { |
| index = skipOneCheck(checks, index); |
| } |
| } |
| } |
| return false; |
| } |
| |
| int skipOneCheck(String[] checks, int index) { |
| if (checks[index].equals("return")) { |
| index += 2; |
| } else if (checks[index].startsWith("check")) { |
| index += 3; |
| } else if (checks[index].startsWith("sentinel")) { |
| index += 3; |
| } else if (checks[index].equals("ifcheck")) { |
| index += 5; |
| } else if (checks[index].equals("unsupported")) { |
| index += 1; |
| } else if (checks[index].equals("requires")) { |
| index += 2; |
| } else if (checks[index].equals("nullAllowed")) { |
| index += 1; |
| } else { |
| System.out.println("Error: unknown keyword \"" + |
| checks[index] + "\""); |
| System.exit(0); |
| } |
| |
| return index; |
| } |
| |
| String getErrorReturnValue(CFunc cfunc) { |
| CType returnType = cfunc.getType(); |
| boolean isVoid = returnType.isVoid(); |
| if (isVoid) { |
| return null; |
| } |
| |
| if (returnType.getBaseType().startsWith("EGL")) { |
| return "(" + returnType.getDeclaration() + ") 0"; |
| } |
| |
| String[] checks = mChecker.getChecks(cfunc.getName()); |
| |
| int index = 1; |
| if (checks != null) { |
| while (index < checks.length) { |
| if (checks[index].equals("return")) { |
| return checks[index + 1]; |
| } else { |
| index = skipOneCheck(checks, index); |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| boolean isUnsupportedFunc(CFunc cfunc) { |
| String[] checks = mChecker.getChecks(cfunc.getName()); |
| int index = 1; |
| if (checks != null) { |
| while (index < checks.length) { |
| if (checks[index].equals("unsupported")) { |
| return true; |
| } else { |
| index = skipOneCheck(checks, index); |
| } |
| } |
| } |
| return false; |
| } |
| |
| String isRequiresFunc(CFunc cfunc) { |
| String[] checks = mChecker.getChecks(cfunc.getName()); |
| int index = 1; |
| if (checks != null) { |
| while (index < checks.length) { |
| if (checks[index].equals("requires")) { |
| return checks[index+1]; |
| } else { |
| index = skipOneCheck(checks, index); |
| } |
| } |
| } |
| return null; |
| } |
| |
| void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out, |
| boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { |
| |
| String[] checks = mChecker.getChecks(cfunc.getName()); |
| |
| boolean lastWasIfcheck = false; |
| |
| int index = 1; |
| if (checks != null) { |
| while (index < checks.length) { |
| if (checks[index].startsWith("check")) { |
| if (lastWasIfcheck) { |
| printIfcheckPostamble(out, isBuffer, emitExceptionCheck, |
| offset, remaining, iii); |
| } |
| lastWasIfcheck = false; |
| if (cname != null && !cname.equals(checks[index + 1])) { |
| index += 3; |
| continue; |
| } |
| out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {"); |
| out.println(iii + indent + "_exception = 1;"); |
| String exceptionClassName = "java/lang/IllegalArgumentException"; |
| // If the "check" keyword was of the form |
| // "check_<class name>", use the class name in the |
| // exception to be thrown |
| int underscore = checks[index].indexOf('_'); |
| if (underscore >= 0) { |
| String abbr = checks[index].substring(underscore + 1); |
| if (abbr.equals("AIOOBE")) { |
| exceptionClassName = "java/lang/ArrayIndexOutOfBoundsException"; |
| } else { |
| throw new RuntimeException("unknown exception abbreviation: " + abbr); |
| } |
| } |
| out.println(iii + indent + |
| "_exceptionType = \""+exceptionClassName+"\";"); |
| out.println(iii + indent + |
| "_exceptionMessage = \"" + |
| (isBuffer ? "remaining()" : "length - " + |
| offset) + " < " + checks[index + 2] + |
| " < needed\";"); |
| |
| out.println(iii + indent + "goto exit;"); |
| out.println(iii + "}"); |
| |
| needsExit = true; |
| |
| index += 3; |
| } else if (checks[index].equals("ifcheck")) { |
| String[] matches = checks[index + 4].split(","); |
| |
| if (!lastWasIfcheck) { |
| out.println(iii + "int _needed;"); |
| out.println(iii + "switch (" + checks[index + 3] + ") {"); |
| } |
| |
| for (int i = 0; i < matches.length; i++) { |
| out.println("#if defined(" + matches[i] + ")"); |
| out.println(iii + " case " + matches[i] + ":"); |
| out.println("#endif // defined(" + matches[i] + ")"); |
| } |
| out.println(iii + " _needed = " + checks[index + 2] + ";"); |
| out.println(iii + " break;"); |
| |
| lastWasIfcheck = true; |
| index += 5; |
| } else { |
| index = skipOneCheck(checks, index); |
| } |
| } |
| } |
| |
| if (lastWasIfcheck) { |
| printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii); |
| } |
| } |
| |
| void emitSentinelCheck(CFunc cfunc, String cname, PrintStream out, |
| boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { |
| |
| String[] checks = mChecker.getChecks(cfunc.getName()); |
| |
| int index = 1; |
| if (checks != null) { |
| while (index < checks.length) { |
| if (checks[index].startsWith("sentinel")) { |
| if (cname != null && !cname.equals(checks[index + 1])) { |
| index += 3; |
| continue; |
| } |
| |
| out.println(iii + cname + "_sentinel = false;"); |
| out.println(iii + "for (int i = " + remaining + |
| " - 1; i >= 0; i--) {"); |
| out.println(iii + indent + "if (" + cname + |
| "[i] == " + checks[index + 2] + "){"); |
| out.println(iii + indent + indent + |
| cname + "_sentinel = true;"); |
| out.println(iii + indent + indent + "break;"); |
| out.println(iii + indent + "}"); |
| out.println(iii + "}"); |
| out.println(iii + |
| "if (" + cname + "_sentinel == false) {"); |
| out.println(iii + indent + "_exception = 1;"); |
| out.println(iii + indent + |
| "_exceptionType = \"java/lang/IllegalArgumentException\";"); |
| out.println(iii + indent + "_exceptionMessage = \"" + cname + |
| " must contain " + checks[index + 2] + "!\";"); |
| out.println(iii + indent + "goto exit;"); |
| out.println(iii + "}"); |
| |
| needsExit = true; |
| index += 3; |
| } else { |
| index = skipOneCheck(checks, index); |
| } |
| } |
| } |
| } |
| |
| void emitLocalVariablesForSentinel(CFunc cfunc, PrintStream out) { |
| |
| String[] checks = mChecker.getChecks(cfunc.getName()); |
| |
| int index = 1; |
| if (checks != null) { |
| while (index < checks.length) { |
| if (checks[index].startsWith("sentinel")) { |
| String cname = checks[index + 1]; |
| out.println(indent + "bool " + cname + "_sentinel = false;"); |
| |
| index += 3; |
| |
| } else { |
| index = skipOneCheck(checks, index); |
| } |
| } |
| } |
| } |
| |
| boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) { |
| if (nonPrimitiveArgs.size() > 0) { |
| for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { |
| int idx = nonPrimitiveArgs.get(i).intValue(); |
| int cIndex = jfunc.getArgCIndex(idx); |
| if (jfunc.getArgType(idx).isArray()) { |
| if (!cfunc.getArgType(cIndex).isConst()) { |
| return true; |
| } |
| } else if (jfunc.getArgType(idx).isBuffer()) { |
| if (!cfunc.getArgType(cIndex).isConst()) { |
| return true; |
| } |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Emit a function in several variants: |
| * |
| * if nativeDecl: public native <returntype> func(args); |
| * |
| * if !nativeDecl: |
| * if interfaceDecl: public <returntype> func(args); |
| * if !interfaceDecl: public <returntype> func(args) { body } |
| */ |
| void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) { |
| boolean isPointerFunc = isPointerFunc(jfunc); |
| |
| if (!nativeDecl && !interfaceDecl && !isPointerFunc) { |
| // If it's not a pointer function, we've already emitted it |
| // with nativeDecl == true |
| return; |
| } |
| |
| String maybeStatic = mUseStaticMethods ? "static " : ""; |
| |
| if (isPointerFunc) { |
| out.println(indent + |
| (nativeDecl ? "private " + maybeStatic +"native " : |
| (interfaceDecl ? "" : "public ") + maybeStatic) + |
| jfunc.getType() + " " + |
| jfunc.getName() + |
| (nativeDecl ? "Bounds" : "") + |
| "("); |
| } else { |
| out.println(indent + |
| (nativeDecl ? "public " + maybeStatic +"native " : |
| (interfaceDecl ? "" : "public ") + maybeStatic) + |
| jfunc.getType() + " " + |
| jfunc.getName() + |
| "("); |
| } |
| |
| int numArgs = jfunc.getNumArgs(); |
| for (int i = 0; i < numArgs; i++) { |
| String argName = jfunc.getArgName(i); |
| JType argType = jfunc.getArgType(i); |
| |
| out.print(indent + indent + argType + " " + argName); |
| if (i == numArgs - 1) { |
| if (isPointerFunc && nativeDecl) { |
| out.println(","); |
| out.println(indent + indent + "int remaining"); |
| } else { |
| out.println(); |
| } |
| } else { |
| out.println(","); |
| } |
| } |
| |
| if (nativeDecl || interfaceDecl) { |
| out.println(indent + ");"); |
| } else { |
| out.println(indent + ") {"); |
| |
| String iii = indent + indent; |
| |
| // emitBoundsChecks(jfunc, out, iii); |
| emitFunctionCall(jfunc, out, iii, false); |
| |
| // Set the pointer after we call the native code, so that if |
| // the native code throws an exception we don't modify the |
| // pointer. We assume that the native code is written so that |
| // if an exception is thrown, then the underlying glXXXPointer |
| // function will not have been called. |
| |
| String fname = jfunc.getName(); |
| if (isPointerFunc) { |
| // TODO - deal with VBO variants |
| if (fname.equals("glColorPointer")) { |
| out.println(iii + "if ((size == 4) &&"); |
| out.println(iii + " ((type == GL_FLOAT) ||"); |
| out.println(iii + " (type == GL_UNSIGNED_BYTE) ||"); |
| out.println(iii + " (type == GL_FIXED)) &&"); |
| out.println(iii + " (stride >= 0)) {"); |
| out.println(iii + indent + "_colorPointer = pointer;"); |
| out.println(iii + "}"); |
| } else if (fname.equals("glNormalPointer")) { |
| out.println(iii + "if (((type == GL_FLOAT) ||"); |
| out.println(iii + " (type == GL_BYTE) ||"); |
| out.println(iii + " (type == GL_SHORT) ||"); |
| out.println(iii + " (type == GL_FIXED)) &&"); |
| out.println(iii + " (stride >= 0)) {"); |
| out.println(iii + indent + "_normalPointer = pointer;"); |
| out.println(iii + "}"); |
| } else if (fname.equals("glTexCoordPointer")) { |
| out.println(iii + "if (((size == 2) ||"); |
| out.println(iii + " (size == 3) ||"); |
| out.println(iii + " (size == 4)) &&"); |
| out.println(iii + " ((type == GL_FLOAT) ||"); |
| out.println(iii + " (type == GL_BYTE) ||"); |
| out.println(iii + " (type == GL_SHORT) ||"); |
| out.println(iii + " (type == GL_FIXED)) &&"); |
| out.println(iii + " (stride >= 0)) {"); |
| out.println(iii + indent + "_texCoordPointer = pointer;"); |
| out.println(iii + "}"); |
| } else if (fname.equals("glVertexPointer")) { |
| out.println(iii + "if (((size == 2) ||"); |
| out.println(iii + " (size == 3) ||"); |
| out.println(iii + " (size == 4)) &&"); |
| out.println(iii + " ((type == GL_FLOAT) ||"); |
| out.println(iii + " (type == GL_BYTE) ||"); |
| out.println(iii + " (type == GL_SHORT) ||"); |
| out.println(iii + " (type == GL_FIXED)) &&"); |
| out.println(iii + " (stride >= 0)) {"); |
| out.println(iii + indent + "_vertexPointer = pointer;"); |
| out.println(iii + "}"); |
| } else if (fname.equals("glPointSizePointerOES")) { |
| out.println(iii + "if (((type == GL_FLOAT) ||"); |
| out.println(iii + " (type == GL_FIXED)) &&"); |
| out.println(iii + " (stride >= 0)) {"); |
| out.println(iii + indent + "_pointSizePointerOES = pointer;"); |
| out.println(iii + "}"); |
| } else if (fname.equals("glMatrixIndexPointerOES")) { |
| out.println(iii + "if (((size == 2) ||"); |
| out.println(iii + " (size == 3) ||"); |
| out.println(iii + " (size == 4)) &&"); |
| out.println(iii + " ((type == GL_FLOAT) ||"); |
| out.println(iii + " (type == GL_BYTE) ||"); |
| out.println(iii + " (type == GL_SHORT) ||"); |
| out.println(iii + " (type == GL_FIXED)) &&"); |
| out.println(iii + " (stride >= 0)) {"); |
| out.println(iii + indent + "_matrixIndexPointerOES = pointer;"); |
| out.println(iii + "}"); |
| } else if (fname.equals("glWeightPointer")) { |
| out.println(iii + "if (((size == 2) ||"); |
| out.println(iii + " (size == 3) ||"); |
| out.println(iii + " (size == 4)) &&"); |
| out.println(iii + " ((type == GL_FLOAT) ||"); |
| out.println(iii + " (type == GL_BYTE) ||"); |
| out.println(iii + " (type == GL_SHORT) ||"); |
| out.println(iii + " (type == GL_FIXED)) &&"); |
| out.println(iii + " (stride >= 0)) {"); |
| out.println(iii + indent + "_weightPointerOES = pointer;"); |
| out.println(iii + "}"); |
| } |
| } |
| |
| boolean isVoid = jfunc.getType().isVoid(); |
| |
| if (!isVoid) { |
| out.println(indent + indent + "return _returnValue;"); |
| } |
| out.println(indent + "}"); |
| } |
| out.println(); |
| } |
| |
| public void addNativeRegistration(String s) { |
| nativeRegistrations.add(s); |
| } |
| |
| public void emitNativeRegistration(String registrationFunctionName, |
| PrintStream cStream) { |
| cStream.println("static const char *classPathName = \"" + |
| mClassPathName + |
| "\";"); |
| cStream.println(); |
| |
| cStream.println("static JNINativeMethod methods[] = {"); |
| |
| cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },"); |
| |
| Iterator<String> i = nativeRegistrations.iterator(); |
| while (i.hasNext()) { |
| cStream.println(i.next()); |
| } |
| |
| cStream.println("};"); |
| cStream.println(); |
| |
| |
| cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)"); |
| cStream.println("{"); |
| cStream.println(indent + |
| "int err;"); |
| |
| cStream.println(indent + |
| "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));"); |
| |
| cStream.println(indent + "return err;"); |
| cStream.println("}"); |
| } |
| |
| public JniCodeEmitter() { |
| super(); |
| } |
| |
| String getJniType(JType jType) { |
| if (jType.isVoid()) { |
| return "void"; |
| } |
| |
| String baseType = jType.getBaseType(); |
| if (jType.isPrimitive()) { |
| if (baseType.equals("String")) { |
| return "jstring"; |
| } else { |
| return "j" + baseType; |
| } |
| } else if (jType.isArray()) { |
| return jType.isClass() ? "jobjectArray" : "j" + baseType + "Array"; |
| } else { |
| return "jobject"; |
| } |
| } |
| |
| String getJniMangledName(String name) { |
| name = name.replaceAll("_", "_1"); |
| name = name.replaceAll(";", "_2"); |
| name = name.replaceAll("\\[", "_3"); |
| return name; |
| } |
| |
| public void emitJniCode(JFunc jfunc, PrintStream out) { |
| CFunc cfunc = jfunc.getCFunc(); |
| |
| // Emit comment identifying original C function |
| // |
| // Example: |
| // |
| // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */ |
| // |
| out.println("/* " + cfunc.getOriginal() + " */"); |
| |
| // Emit JNI signature (name) |
| // |
| // Example: |
| // |
| // void |
| // android_glClipPlanef__I_3FI |
| // |
| |
| String outName = "android_" + jfunc.getName(); |
| boolean isPointerFunc = isPointerFunc(jfunc); |
| boolean isPointerOffsetFunc = |
| (outName.endsWith("Pointer") || outName.endsWith("PointerOES") || |
| outName.endsWith("glDrawElements") || |
| outName.endsWith("glDrawRangeElements") || |
| outName.endsWith("glTexImage2D") || |
| outName.endsWith("glTexSubImage2D") || |
| outName.endsWith("glCompressedTexImage2D") || |
| outName.endsWith("glCompressedTexSubImage2D") || |
| outName.endsWith("glTexImage3D") || |
| outName.endsWith("glTexSubImage3D") || |
| outName.endsWith("glCompressedTexImage3D") || |
| outName.endsWith("glCompressedTexSubImage3D") || |
| outName.endsWith("glReadPixels")) |
| && !jfunc.getCFunc().hasPointerArg(); |
| if (isPointerFunc) { |
| outName += "Bounds"; |
| } |
| |
| out.print("static "); |
| out.println(getJniType(jfunc.getType())); |
| out.print(outName); |
| |
| String rsignature = getJniName(jfunc.getType()); |
| |
| String signature = ""; |
| int numArgs = jfunc.getNumArgs(); |
| for (int i = 0; i < numArgs; i++) { |
| JType argType = jfunc.getArgType(i); |
| signature += getJniName(argType); |
| } |
| if (isPointerFunc) { |
| signature += "I"; |
| } |
| |
| // Append signature to function name |
| String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_'); |
| if (!mUseSimpleMethodNames) { |
| out.print("__" + sig); |
| outName += "__" + sig; |
| } |
| |
| signature = signature.replace('.', '/'); |
| rsignature = rsignature.replace('.', '/'); |
| |
| out.println(); |
| if (rsignature.length() == 0) { |
| rsignature = "V"; |
| } |
| |
| String s = "{\"" + |
| jfunc.getName() + |
| (isPointerFunc ? "Bounds" : "") + |
| "\", \"(" + signature +")" + |
| rsignature + |
| "\", (void *) " + |
| outName + |
| " },"; |
| nativeRegistrations.add(s); |
| |
| List<Integer> nonPrimitiveArgs = new ArrayList<Integer>(); |
| List<Integer> stringArgs = new ArrayList<Integer>(); |
| int numBufferArgs = 0; |
| List<String> bufferArgNames = new ArrayList<String>(); |
| |
| // Emit JNI signature (arguments) |
| // |
| // Example: |
| // |
| // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) { |
| // |
| out.print(" (JNIEnv *_env, jobject _this"); |
| for (int i = 0; i < numArgs; i++) { |
| out.print(", "); |
| JType argType = jfunc.getArgType(i); |
| String suffix = ""; |
| if (!argType.isPrimitive()) { |
| if (argType.isArray()) { |
| suffix = "_ref"; |
| } else if (argType.isBuffer()) { |
| suffix = "_buf"; |
| } |
| nonPrimitiveArgs.add(new Integer(i)); |
| if (jfunc.getArgType(i).isBuffer()) { |
| int cIndex = jfunc.getArgCIndex(i); |
| String cname = cfunc.getArgName(cIndex); |
| bufferArgNames.add(cname); |
| numBufferArgs++; |
| } |
| } |
| |
| if (argType.isString()) { |
| stringArgs.add(new Integer(i)); |
| } |
| |
| out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix); |
| } |
| if (isPointerFunc) { |
| out.print(", jint remaining"); |
| } |
| out.println(") {"); |
| |
| int numArrays = 0; |
| int numBuffers = 0; |
| int numStrings = 0; |
| for (int i = 0; i < nonPrimitiveArgs.size(); i++) { |
| int idx = nonPrimitiveArgs.get(i).intValue(); |
| JType argType = jfunc.getArgType(idx); |
| if (argType.isArray()) { |
| ++numArrays; |
| } |
| if (argType.isBuffer()) { |
| ++numBuffers; |
| } |
| if (argType.isString()) { |
| ++numStrings; |
| } |
| } |
| |
| // Emit method body |
| |
| // Emit local variable declarations for _exception and _returnValue |
| // |
| // Example: |
| // |
| // android::gl::ogles_context_t *ctx; |
| // |
| // jint _exception; |
| // GLenum _returnValue; |
| // |
| CType returnType = cfunc.getType(); |
| boolean isVoid = returnType.isVoid(); |
| |
| boolean isUnsupported = isUnsupportedFunc(cfunc); |
| if (isUnsupported) { |
| out.println(indent + |
| "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); |
| out.println(indent + |
| " \"" + cfunc.getName() + "\");"); |
| if (!isVoid) { |
| String retval = getErrorReturnValue(cfunc); |
| if (cfunc.getType().isEGLHandle()) { |
| String baseType = cfunc.getType().getBaseType().toLowerCase(); |
| out.println(indent + |
| "return toEGLHandle(_env, " + baseType + "Class, " + |
| baseType + "Constructor, " + retval + ");"); |
| } else { |
| out.println(indent + "return " + retval + ";"); |
| } |
| } |
| out.println("}"); |
| out.println(); |
| return; |
| } |
| |
| String requiresExtension = isRequiresFunc(cfunc); |
| if (requiresExtension != null) { |
| out.println(indent + |
| "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {"); |
| out.println(indent + indent + |
| "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); |
| out.println(indent + indent + |
| " \"" + cfunc.getName() + "\");"); |
| if (isVoid) { |
| out.println(indent + indent + " return;"); |
| } else { |
| String retval = getErrorReturnValue(cfunc); |
| if (cfunc.getType().isEGLHandle()) { |
| String baseType = cfunc.getType().getBaseType().toLowerCase(); |
| out.println(indent + |
| "return toEGLHandle(_env, " + baseType + "Class, " + |
| baseType + "Constructor, " + retval + ");"); |
| } else { |
| out.println(indent + "return " + retval + ";"); |
| } |
| } |
| out.println(indent + "}"); |
| } |
| if (mUseContextPointer) { |
| out.println(indent + |
| "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); |
| } |
| |
| boolean initializeReturnValue = stringArgs.size() > 0; |
| boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0) |
| && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs) |
| || (cfunc.hasPointerArg() && numArrays > 0)) |
| || hasCheckTest(cfunc) |
| || hasIfTest(cfunc)) |
| || (stringArgs.size() > 0); |
| // mChecker.getChecks(cfunc.getName()) != null |
| // Emit an _exeption variable if there will be error checks |
| if (emitExceptionCheck) { |
| out.println(indent + "jint _exception = 0;"); |
| out.println(indent + "const char * _exceptionType = NULL;"); |
| out.println(indent + "const char * _exceptionMessage = NULL;"); |
| } |
| |
| // Emit a single _array or multiple _XXXArray variables |
| if (numBufferArgs == 1) { |
| out.println(indent + "jarray _array = (jarray) 0;"); |
| out.println(indent + "jint _bufferOffset = (jint) 0;"); |
| } else { |
| for (int i = 0; i < numBufferArgs; i++) { |
| out.println(indent + "jarray _" + bufferArgNames.get(i) + |
| "Array = (jarray) 0;"); |
| out.println(indent + "jint _" + bufferArgNames.get(i) + |
| "BufferOffset = (jint) 0;"); |
| } |
| } |
| if (!isVoid) { |
| String retval = getErrorReturnValue(cfunc); |
| if (retval != null) { |
| out.println(indent + returnType.getDeclaration() + |
| " _returnValue = " + retval + ";"); |
| } else if (initializeReturnValue) { |
| out.println(indent + returnType.getDeclaration() + |
| " _returnValue = 0;"); |
| } else { |
| out.println(indent + returnType.getDeclaration() + |
| " _returnValue;"); |
| } |
| } |
| |
| // Emit local variable declarations for EGL Handles |
| // |
| // Example: |
| // |
| // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface); |
| // |
| if (nonPrimitiveArgs.size() > 0) { |
| for (int i = 0; i < nonPrimitiveArgs.size(); i++) { |
| int idx = nonPrimitiveArgs.get(i).intValue(); |
| int cIndex = jfunc.getArgCIndex(idx); |
| String cname = cfunc.getArgName(cIndex); |
| |
| if (jfunc.getArgType(idx).isBuffer() |
| || jfunc.getArgType(idx).isArray() |
| || !jfunc.getArgType(idx).isEGLHandle()) |
| continue; |
| |
| CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); |
| String decl = type.getDeclaration(); |
| out.println(indent + |
| decl + " " + cname + "_native = (" + |
| decl + ") fromEGLHandle(_env, " + |
| type.getBaseType().toLowerCase() + |
| "GetHandleID, " + jfunc.getArgName(idx) + |
| ");"); |
| } |
| } |
| |
| // Emit local variable declarations for element/sentinel checks |
| // |
| // Example: |
| // |
| // bool attrib_list_sentinel_found = false; |
| // |
| emitLocalVariablesForSentinel(cfunc, out); |
| |
| // Emit local variable declarations for pointer arguments |
| // |
| // Example: |
| // |
| // GLfixed *eqn_base; |
| // GLfixed *eqn; |
| // |
| String offset = "offset"; |
| String remaining = "_remaining"; |
| if (nonPrimitiveArgs.size() > 0) { |
| for (int i = 0; i < nonPrimitiveArgs.size(); i++) { |
| int idx = nonPrimitiveArgs.get(i).intValue(); |
| int cIndex = jfunc.getArgCIndex(idx); |
| String cname = cfunc.getArgName(cIndex); |
| |
| if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray()) |
| continue; |
| |
| CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); |
| String decl = type.getDeclaration(); |
| if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { |
| out.println(indent + |
| decl + |
| (decl.endsWith("*") ? "" : " ") + |
| jfunc.getArgName(idx) + |
| "_base = (" + decl + ") 0;"); |
| } |
| remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : |
| "_" + cname + "Remaining"; |
| out.println(indent + |
| "jint " + remaining + ";"); |
| out.println(indent + |
| decl + |
| (decl.endsWith("*") ? "" : " ") + |
| jfunc.getArgName(idx) + |
| " = (" + decl + ") 0;"); |
| } |
| |
| out.println(); |
| } |
| |
| // Emit local variable declaration for strings |
| if (stringArgs.size() > 0) { |
| for (int i = 0; i < stringArgs.size(); i++) { |
| int idx = stringArgs.get(i).intValue(); |
| int cIndex = jfunc.getArgCIndex(idx); |
| String cname = cfunc.getArgName(cIndex); |
| |
| out.println(indent + "const char* _native" + cname + " = 0;"); |
| } |
| |
| out.println(); |
| } |
| |
| // Null pointer checks and GetStringUTFChars |
| if (stringArgs.size() > 0) { |
| for (int i = 0; i < stringArgs.size(); i++) { |
| int idx = stringArgs.get(i).intValue(); |
| int cIndex = jfunc.getArgCIndex(idx); |
| String cname = cfunc.getArgName(cIndex); |
| |
| CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); |
| String decl = type.getDeclaration(); |
| needsExit = true; |
| out.println(indent + "if (!" + cname + ") {"); |
| out.println(indent + indent + |
| "_exceptionType = \"java/lang/IllegalArgumentException\";"); |
| out.println(indent + indent + |
| "_exceptionMessage = \"" + cname + " == null\";"); |
| out.println(indent + indent + "goto exit;"); |
| out.println(indent + "}"); |
| |
| out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);"); |
| } |
| |
| out.println(); |
| } |
| |
| // Emit 'GetPrimitiveArrayCritical' for non-object arrays |
| // Emit 'GetPointer' calls for Buffer pointers |
| if (nonPrimitiveArgs.size() > 0) { |
| for (int i = 0; i < nonPrimitiveArgs.size(); i++) { |
| int idx = nonPrimitiveArgs.get(i).intValue(); |
| int cIndex = jfunc.getArgCIndex(idx); |
| |
| String cname = cfunc.getArgName(cIndex); |
| offset = numArrays <= 1 ? "offset" : |
| cname + "Offset"; |
| remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : |
| "_" + cname + "Remaining"; |
| |
| if (jfunc.getArgType(idx).isArray() |
| && !jfunc.getArgType(idx).isEGLHandle()) { |
| needsExit = true; |
| out.println(indent + "if (!" + cname + "_ref) {"); |
| out.println(indent + indent + "_exception = 1;"); |
| out.println(indent + indent + |
| "_exceptionType = \"java/lang/IllegalArgumentException\";"); |
| out.println(indent + indent + |
| "_exceptionMessage = \"" + cname +" == null\";"); |
| out.println(indent + indent + "goto exit;"); |
| out.println(indent + "}"); |
| out.println(indent + "if (" + offset + " < 0) {"); |
| out.println(indent + indent + "_exception = 1;"); |
| out.println(indent + indent + |
| "_exceptionType = \"java/lang/IllegalArgumentException\";"); |
| out.println(indent + indent + |
| "_exceptionMessage = \"" + offset +" < 0\";"); |
| out.println(indent + indent + "goto exit;"); |
| out.println(indent + "}"); |
| |
| out.println(indent + remaining + " = " + |
| (mUseCPlusPlus ? "_env" : "(*_env)") + |
| "->GetArrayLength(" + |
| (mUseCPlusPlus ? "" : "_env, ") + |
| cname + "_ref) - " + offset + ";"); |
| |
| emitNativeBoundsChecks(cfunc, cname, out, false, |
| emitExceptionCheck, |
| offset, remaining, " "); |
| |
| out.println(indent + |
| cname + |
| "_base = (" + |
| cfunc.getArgType(cIndex).getDeclaration() + |
| ")"); |
| out.println(indent + " " + |
| (mUseCPlusPlus ? "_env" : "(*_env)") + |
| "->GetPrimitiveArrayCritical(" + |
| (mUseCPlusPlus ? "" : "_env, ") + |
| jfunc.getArgName(idx) + |
| "_ref, (jboolean *)0);"); |
| out.println(indent + |
| cname + " = " + cname + "_base + " + offset + ";"); |
| |
| emitSentinelCheck(cfunc, cname, out, false, |
| emitExceptionCheck, offset, |
| remaining, indent); |
| out.println(); |
| } else if (jfunc.getArgType(idx).isArray() |
| && jfunc.getArgType(idx).isEGLHandle()) { |
| needsExit = true; |
| out.println(indent + "if (!" + cname + "_ref) {"); |
| out.println(indent + indent + "_exception = 1;"); |
| out.println(indent + indent + |
| "_exceptionType = \"java/lang/IllegalArgumentException\";"); |
| out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";"); |
| out.println(indent + indent + "goto exit;"); |
| out.println(indent + "}"); |
| out.println(indent + "if (" + offset + " < 0) {"); |
| out.println(indent + indent + "_exception = 1;"); |
| out.println(indent + indent + |
| "_exceptionType = \"java/lang/IllegalArgumentException\";"); |
| out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";"); |
| out.println(indent + indent + "goto exit;"); |
| out.println(indent + "}"); |
| |
| out.println(indent + remaining + " = " + |
| (mUseCPlusPlus ? "_env" : "(*_env)") + |
| "->GetArrayLength(" + |
| (mUseCPlusPlus ? "" : "_env, ") + |
| cname + "_ref) - " + offset + ";"); |
| emitNativeBoundsChecks(cfunc, cname, out, false, |
| emitExceptionCheck, |
| offset, remaining, " "); |
| out.println(indent + |
| jfunc.getArgName(idx) + " = new " + |
| cfunc.getArgType(cIndex).getBaseType() + |
| "["+ remaining + "];"); |
| out.println(); |
| } else if (jfunc.getArgType(idx).isBuffer()) { |
| String array = numBufferArgs <= 1 ? "_array" : |
| "_" + cfunc.getArgName(cIndex) + "Array"; |
| String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : |
| "_" + cfunc.getArgName(cIndex) + "BufferOffset"; |
| |
| boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; |
| if (nullAllowed) { |
| out.println(indent + "if (" + cname + "_buf) {"); |
| out.print(indent); |
| } |
| |
| if (isPointerFunc) { |
| out.println(indent + |
| cname + |
| " = (" + |
| cfunc.getArgType(cIndex).getDeclaration() + |
| ") getDirectBufferPointer(_env, " + |
| cname + "_buf);"); |
| String iii = " "; |
| out.println(iii + indent + "if ( ! " + cname + " ) {"); |
| out.println(iii + indent + indent + "return;"); |
| out.println(iii + indent + "}"); |
| } else { |
| out.println(indent + |
| cname + |
| " = (" + |
| cfunc.getArgType(cIndex).getDeclaration() + |
| ")getPointer(_env, " + |
| cname + |
| "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset + |
| ");"); |
| } |
| |
| emitNativeBoundsChecks(cfunc, cname, out, true, |
| emitExceptionCheck, |
| offset, remaining, nullAllowed ? " " : " "); |
| |
| if (nullAllowed) { |
| out.println(indent + "}"); |
| } |
| } |
| } |
| } |
| |
| // Emit 'GetPrimitiveArrayCritical' for pointers if needed |
| if (nonPrimitiveArgs.size() > 0) { |
| for (int i = 0; i < nonPrimitiveArgs.size(); i++) { |
| int idx = nonPrimitiveArgs.get(i).intValue(); |
| int cIndex = jfunc.getArgCIndex(idx); |
| |
| if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue; |
| |
| String cname = cfunc.getArgName(cIndex); |
| String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : |
| "_" + cname + "BufferOffset"; |
| String array = numBufferArgs <= 1 ? "_array" : |
| "_" + cfunc.getArgName(cIndex) + "Array"; |
| |
| boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; |
| if (nullAllowed) { |
| out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {"); |
| } else { |
| out.println(indent + "if (" + cname +" == NULL) {"); |
| } |
| out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); |
| out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); |
| out.println(indent + "}"); |
| } |
| } |
| |
| |
| if (!isVoid) { |
| out.print(indent + "_returnValue = "); |
| } else { |
| out.print(indent); |
| } |
| String name = cfunc.getName(); |
| |
| if (mUseContextPointer) { |
| name = name.substring(2, name.length()); // Strip off 'gl' prefix |
| name = name.substring(0, 1).toLowerCase() + |
| name.substring(1, name.length()); |
| out.print("ctx->procs."); |
| } |
| |
| out.print(name + (isPointerFunc ? "Bounds" : "") + "("); |
| |
| numArgs = cfunc.getNumArgs(); |
| if (numArgs == 0) { |
| if (mUseContextPointer) { |
| out.println("ctx);"); |
| } else { |
| out.println(");"); |
| } |
| } else { |
| if (mUseContextPointer) { |
| out.println("ctx,"); |
| } else { |
| out.println(); |
| } |
| for (int i = 0; i < numArgs; i++) { |
| String typecast; |
| if (i == numArgs - 1 && isPointerOffsetFunc) { |
| typecast = "(GLvoid *)"; |
| } else { |
| typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; |
| } |
| out.print(indent + indent + |
| typecast); |
| |
| if (cfunc.getArgType(i).isConstCharPointer()) { |
| out.print("_native"); |
| } |
| |
| if (cfunc.getArgType(i).isEGLHandle() && |
| !cfunc.getArgType(i).isPointer()){ |
| out.print(cfunc.getArgName(i)+"_native"); |
| } else { |
| out.print(cfunc.getArgName(i)); |
| } |
| |
| if (i == numArgs - 1) { |
| if (isPointerFunc) { |
| out.println(","); |
| out.println(indent + indent + "(GLsizei)remaining"); |
| } else { |
| out.println(); |
| } |
| } else { |
| out.println(","); |
| } |
| } |
| out.println(indent + ");"); |
| } |
| |
| if (needsExit) { |
| out.println(); |
| out.println("exit:"); |
| needsExit = false; |
| } |
| |
| |
| if (nonPrimitiveArgs.size() > 0) { |
| for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { |
| int idx = nonPrimitiveArgs.get(i).intValue(); |
| |
| int cIndex = jfunc.getArgCIndex(idx); |
| if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { |
| |
| // If the argument is 'const', GL will not write to it. |
| // In this case, we can use the 'JNI_ABORT' flag to avoid |
| // the need to write back to the Java array |
| out.println(indent + |
| "if (" + jfunc.getArgName(idx) + "_base) {"); |
| out.println(indent + indent + |
| (mUseCPlusPlus ? "_env" : "(*_env)") + |
| "->ReleasePrimitiveArrayCritical(" + |
| (mUseCPlusPlus ? "" : "_env, ") + |
| jfunc.getArgName(idx) + "_ref, " + |
| cfunc.getArgName(cIndex) + |
| "_base,"); |
| out.println(indent + indent + indent + |
| (cfunc.getArgType(cIndex).isConst() ? |
| "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + |
| ");"); |
| out.println(indent + "}"); |
| } else if (jfunc.getArgType(idx).isBuffer()) { |
| if (! isPointerFunc) { |
| String array = numBufferArgs <= 1 ? "_array" : |
| "_" + cfunc.getArgName(cIndex) + "Array"; |
| out.println(indent + "if (" + array + ") {"); |
| out.println(indent + indent + |
| "releasePointer(_env, " + array + ", " + |
| cfunc.getArgName(cIndex) + |
| ", " + |
| (cfunc.getArgType(cIndex).isConst() ? |
| "JNI_FALSE" : (emitExceptionCheck ? |
| "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + |
| ");"); |
| out.println(indent + "}"); |
| } |
| } |
| } |
| } |
| |
| // Emit local variable declaration for strings |
| if (stringArgs.size() > 0) { |
| for (int i = 0; i < stringArgs.size(); i++) { |
| int idx = stringArgs.get(i).intValue(); |
| int cIndex = jfunc.getArgCIndex(idx); |
| String cname = cfunc.getArgName(cIndex); |
| |
| out.println(indent + "if (_native" + cname + ") {"); |
| out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");"); |
| out.println(indent + "}"); |
| } |
| |
| out.println(); |
| } |
| |
| // Copy results back to java arrays |
| if (nonPrimitiveArgs.size() > 0) { |
| for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { |
| int idx = nonPrimitiveArgs.get(i).intValue(); |
| int cIndex = jfunc.getArgCIndex(idx); |
| String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); |
| if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { |
| remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : |
| "_" + cfunc.getArgName(cIndex) + "Remaining"; |
| offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; |
| out.println(indent + |
| "if (" + jfunc.getArgName(idx) + ") {"); |
| out.println(indent + indent + |
| "for (int i = 0; i < " + remaining + "; i++) {"); |
| out.println(indent + indent + indent + |
| "jobject " + cfunc.getArgName(cIndex) + |
| "_new = toEGLHandle(_env, " + baseType + |
| "Class, " + baseType + "Constructor, " + |
| cfunc.getArgName(cIndex) + "[i]);"); |
| out.println(indent + indent + indent + |
| (mUseCPlusPlus ? "_env" : "(*_env)") + |
| "->SetObjectArrayElement(" + |
| (mUseCPlusPlus ? "" : "_env, ") + |
| cfunc.getArgName(cIndex) + |
| "_ref, i + " + offset + ", " + |
| cfunc.getArgName(cIndex) + "_new);"); |
| out.println(indent + indent + "}"); |
| out.println(indent + indent + |
| "delete[] " + jfunc.getArgName(idx) + ";"); |
| out.println(indent + "}"); |
| } |
| } |
| } |
| |
| |
| // Throw exception if there is one |
| if (emitExceptionCheck) { |
| out.println(indent + "if (_exception) {"); |
| out.println(indent + indent + |
| "jniThrowException(_env, _exceptionType, _exceptionMessage);"); |
| out.println(indent + "}"); |
| |
| } |
| |
| |
| if (!isVoid) { |
| if (cfunc.getType().isEGLHandle()) { |
| String baseType = cfunc.getType().getBaseType().toLowerCase(); |
| out.println(indent + |
| "return toEGLHandle(_env, " + baseType + "Class, " + |
| baseType + "Constructor, _returnValue);"); |
| } else { |
| out.println(indent + "return (" + |
| getJniType(jfunc.getType()) + ")_returnValue;"); |
| } |
| } |
| |
| out.println("}"); |
| out.println(); |
| } |
| |
| } |