replicant-frameworks_native/opengl/tools/glgen/src/JniCodeEmitter.java
Jack Palevich 5afdc87704 Add size checks for glBufferData and glBufferSubData
Without the size checks it's possible for calls to glBufferData
and glBufferSubData to read off the end of the Buffer object's
data, which can cause page faults.

Fix end-of-line characters for the "spec" files. (That's why
every line of these files is changed.)

Enhance our code emitter to properly handle bounds checks for
possibly-null pointers.
2009-10-21 11:02:44 -07:00

1037 lines
39 KiB
Java

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 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.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 += "L";
} else if (baseType.equals("byte")) {
jniName += "B";
}
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);
}
}
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) {
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);
}
void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) {
boolean isVoid = jfunc.getType().isVoid();
boolean isPointerFunc = jfunc.getName().endsWith("Pointer") &&
jfunc.getCFunc().hasPointerArg();
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 = 0;");
out.println(iii + " break;");
out.println(iii + "}");
out.println(iii + "if (" + remaining + " < _needed) {");
if (emitExceptionCheck) {
out.println(iii + indent + "_exception = 1;");
}
out.println(iii + indent +
(mUseCPlusPlus ? "_env" : "(*_env)") +
"->ThrowNew(" +
(mUseCPlusPlus ? "" : "_env, ") +
"IAEClass, " +
"\"" +
(isBuffer ?
"remaining()" : "length - " + offset) +
" < needed\");");
out.println(iii + indent + "goto exit;");
needsExit = true;
out.println(iii + "}");
}
boolean isNullAllowed(CFunc cfunc) {
String[] checks = mChecker.getChecks(cfunc.getName());
int index = 1;
if (checks != null) {
while (index < checks.length) {
if (checks[index].equals("return")) {
index += 2;
} else if (checks[index].startsWith("check")) {
index += 3;
} else if (checks[index].equals("ifcheck")) {
index += 5;
} else if (checks[index].equals("unsupported")) {
index += 1;
} else if (checks[index].equals("nullAllowed")) {
return true;
} else {
System.out.println("Error: unknown keyword \"" +
checks[index] + "\"");
System.exit(0);
}
}
}
return false;
}
String getErrorReturnValue(CFunc cfunc) {
CType returnType = cfunc.getType();
boolean isVoid = returnType.isVoid();
if (isVoid) {
return null;
}
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 if (checks[index].startsWith("check")) {
index += 3;
} else if (checks[index].equals("ifcheck")) {
index += 5;
} else if (checks[index].equals("unsupported")) {
index += 1;
} else if (checks[index].equals("nullAllowed")) {
index += 1;
} else {
System.out.println("Error: unknown keyword \"" +
checks[index] + "\"");
System.exit(0);
}
}
}
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 if (checks[index].equals("return")) {
index += 2;
} else if (checks[index].startsWith("check")) {
index += 3;
} else if (checks[index].equals("ifcheck")) {
index += 5;
} else if (checks[index].equals("nullAllowed")) {
index += 1;
} else {
System.out.println("Error: unknown keyword \"" +
checks[index] + "\"");
System.exit(0);
}
}
}
return false;
}
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] +
") {");
if (emitExceptionCheck) {
out.println(iii + indent + "_exception = 1;");
}
String exceptionClassName = "IAEClass";
// 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) {
exceptionClassName = checks[index].substring(underscore + 1) + "Class";
}
out.println(iii + indent +
(mUseCPlusPlus ? "_env" : "(*_env)") +
"->ThrowNew(" +
(mUseCPlusPlus ? "" : "_env, ") +
exceptionClassName + ", " +
"\"" +
(isBuffer ?
"remaining()" : "length - " + offset) +
" < " + checks[index + 2] +
"\");");
out.println(iii + indent + "goto exit;");
needsExit = true;
out.println(iii + "}");
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 if (checks[index].equals("return")) {
// ignore
index += 2;
} else if (checks[index].equals("unsupported")) {
// ignore
index += 1;
} else if (checks[index].equals("nullAllowed")) {
// ignore
index += 1;
} else {
System.out.println("Error: unknown keyword \"" +
checks[index] + "\"");
System.exit(0);
}
}
}
if (lastWasIfcheck) {
printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
}
}
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 =
jfunc.getName().endsWith("Pointer") &&
jfunc.getCFunc().hasPointerArg();
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 + "}");
}
}
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 "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 = outName.endsWith("Pointer") &&
jfunc.getCFunc().hasPointerArg();
boolean isVBOPointerFunc = (outName.endsWith("Pointer") ||
outName.endsWith("DrawElements")) &&
!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('.', '_');
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>();
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 {
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++;
}
} else {
suffix = "";
}
out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
}
if (isPointerFunc) {
out.print(", jint remaining");
}
out.println(") {");
int numArrays = 0;
int numBuffers = 0;
for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
int idx = nonPrimitiveArgs.get(i).intValue();
if (jfunc.getArgType(idx).isArray()) {
++numArrays;
}
if (jfunc.getArgType(idx).isBuffer()) {
++numBuffers;
}
}
// 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 +
"_env->ThrowNew(UOEClass,");
out.println(indent +
" \"" + cfunc.getName() + "\");");
if (!isVoid) {
String retval = getErrorReturnValue(cfunc);
out.println(indent + "return " + retval + ";");
}
out.println("}");
out.println();
return;
}
if (mUseContextPointer) {
out.println(indent +
"android::gl::ogles_context_t *ctx = getContext(_env, _this);");
}
boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) &&
hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs);
// mChecker.getChecks(cfunc.getName()) != null
// Emit an _exeption variable if there will be error checks
if (emitExceptionCheck) {
out.println(indent + "jint _exception = 0;");
}
// Emit a single _array or multiple _XXXArray variables
if (numBufferArgs == 1) {
out.println(indent + "jarray _array = (jarray) 0;");
} else {
for (int i = 0; i < numBufferArgs; i++) {
out.println(indent + "jarray _" + bufferArgNames.get(i) +
"Array = (jarray) 0;");
}
}
if (!isVoid) {
String retval = getErrorReturnValue(cfunc);
if (retval != null) {
out.println(indent + returnType.getDeclaration() +
" _returnValue = " + retval + ";");
} else {
out.println(indent + returnType.getDeclaration() +
" _returnValue;");
}
}
// 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);
CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
String decl = type.getDeclaration();
if (jfunc.getArgType(idx).isArray()) {
out.println(indent +
decl +
(decl.endsWith("*") ? "" : " ") +
jfunc.getArgName(idx) +
"_base = (" + decl + ") 0;");
}
remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
"_" + cname + "Remaining";
out.println(indent +
"jint " + remaining + ";");
out.println(indent +
decl +
(decl.endsWith("*") ? "" : " ") +
jfunc.getArgName(idx) +
" = (" + decl + ") 0;");
}
out.println();
}
// Emit 'GetPrimitiveArrayCritical' for arrays
// Emit 'GetPointer' calls for Buffer pointers
int bufArgIdx = 0;
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 <= 1 && numBuffers <= 1) ? "_remaining" :
"_" + cname + "Remaining";
if (jfunc.getArgType(idx).isArray()) {
out.println(indent +
"if (!" +
cname +
"_ref) {");
if (emitExceptionCheck) {
out.println(indent + indent + "_exception = 1;");
}
out.println(indent + " " +
(mUseCPlusPlus ? "_env" : "(*_env)") +
"->ThrowNew(" +
(mUseCPlusPlus ? "" : "_env, ") +
"IAEClass, " +
"\"" + cname +
" == null\");");
out.println(indent + " goto exit;");
needsExit = true;
out.println(indent + "}");
out.println(indent + "if (" + offset + " < 0) {");
if (emitExceptionCheck) {
out.println(indent + indent + "_exception = 1;");
}
out.println(indent + " " +
(mUseCPlusPlus ? "_env" : "(*_env)") +
"->ThrowNew(" +
(mUseCPlusPlus ? "" : "_env, ") +
"IAEClass, " +
"\"" + offset + " < 0\");");
out.println(indent + " goto exit;");
needsExit = true;
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 +
";");
out.println();
} else {
String array = numBufferArgs <= 1 ? "_array" :
"_" + bufferArgNames.get(bufArgIdx++) + "Array";
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 + iii + indent + "return;");
out.println(iii + indent + "}");
} else {
out.println(indent +
cname +
" = (" +
cfunc.getArgType(cIndex).getDeclaration() +
")getPointer(_env, " +
cname +
"_buf, &" + array + ", &" + remaining +
");");
}
emitNativeBoundsChecks(cfunc, cname, out, true,
emitExceptionCheck,
offset, remaining, nullAllowed ? " " : " ");
if (nullAllowed) {
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 && isVBOPointerFunc) {
typecast = "const GLvoid *";
} else {
typecast = cfunc.getArgType(i).getDeclaration();
}
out.print(indent + indent +
"(" +
typecast +
")" +
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;
}
bufArgIdx = 0;
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 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" :
"_" + bufferArgNames.get(bufArgIdx++) + "Array";
out.println(indent + "if (" + array + ") {");
out.println(indent + indent +
"releasePointer(_env, " + array + ", " +
cfunc.getArgName(cIndex) +
", " +
(cfunc.getArgType(cIndex).isConst() ?
"JNI_FALSE" : "_exception ? JNI_FALSE :" +
" JNI_TRUE") +
");");
out.println(indent + "}");
}
}
}
}
if (!isVoid) {
out.println(indent + "return _returnValue;");
}
out.println("}");
out.println();
}
}