blob: 0e589e68f5b84b6c9bcb1d7a0357fad08b1aecf3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.tools.internal;
import java.lang.reflect.*;
import java.util.HashSet;
import java.util.Iterator;
public class NativesGenerator extends JNIGenerator {
boolean enterExitMacro;
public NativesGenerator() {
enterExitMacro = true;
}
public void generateCopyright() {
generateMetaData("swt_copyright");
}
public void generateIncludes() {
String outputName = getOutputName();
outputln("#include \"swt.h\"");
output("#include \"");
output(outputName);
outputln("_structs.h\"");
output("#include \"");
output(outputName);
outputln("_stats.h\"");
outputln();
}
public void generate(Class clazz, String methodName) {
Method[] methods = clazz.getDeclaredMethods();
int count = 0;
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().startsWith(methodName)) count++;
}
Method[] result = new Method[count];
count = 0;
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().startsWith(methodName)) result[count++] = methods[i];
}
generate(result);
}
public void generate(Class clazz) {
Method[] methods = clazz.getDeclaredMethods();
int i = 0;
for (; i < methods.length; i++) {
Method method = methods[i];
if ((method.getModifiers() & Modifier.NATIVE) != 0) break;
}
if (i == methods.length) return;
sort(methods);
if (isCPP) {
outputln("extern \"C\" {");
outputln();
}
generateNativeMacro(clazz);
generateExcludes(methods);
generate(methods);
if (isCPP) {
outputln("}");
}
}
public void generate(Method[] methods) {
sort(methods);
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if ((method.getModifiers() & Modifier.NATIVE) == 0) continue;
generate(method);
if (progress != null) progress.step();
}
}
public void generate(Method method) {
MethodData methodData = getMetaData().getMetaData(method);
if (methodData.getFlag("no_gen")) return;
Class returnType = method.getReturnType();
Class[] paramTypes = method.getParameterTypes();
String function = getFunctionName(method);
if (!(returnType == Void.TYPE || returnType.isPrimitive() || isSystemClass(returnType) || returnType == String.class)) {
output("Warning: bad return type. :");
outputln(method.toString());
return;
}
generateSourceStart(function);
generateFunctionPrototype(method, function, paramTypes, returnType);
generateFunctionBody(method, methodData, function, paramTypes, returnType);
generateSourceEnd(function);
outputln();
}
public void setEnterExitMacro(boolean enterExitMacro) {
this.enterExitMacro = enterExitMacro;
}
void generateExcludes(Method[] methods) {
HashSet excludes = new HashSet();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if ((method.getModifiers() & Modifier.NATIVE) == 0) continue;
MethodData methodData = getMetaData().getMetaData(method);
String exclude = methodData.getExclude();
if (exclude.length() != 0) {
excludes.add(exclude);
}
}
for (Iterator iter = excludes.iterator(); iter.hasNext();) {
String exclude = (String)iter.next();
outputln(exclude);
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if ((method.getModifiers() & Modifier.NATIVE) == 0) continue;
MethodData methodData = getMetaData().getMetaData(method);
String methodExclude = methodData.getExclude();
if (exclude.equals(methodExclude)) {
output("#define NO_");
outputln(getFunctionName(method));
}
}
outputln("#endif");
outputln();
}
}
void generateNativeMacro(Class clazz) {
output("#define ");
output(getClassName(clazz));
output("_NATIVE(func) Java_");
output(toC(clazz.getName()));
outputln("_##func");
outputln();
}
boolean generateGetParameter(Method method, int i, Class paramType, ParameterData paramData, boolean critical, int indent) {
if (paramType.isPrimitive() || isSystemClass(paramType)) return false;
String iStr = String.valueOf(i);
for (int j = 0; j < indent; j++) output("\t");
output("if (arg");
output(iStr);
output(") if ((lparg");
output(iStr);
output(" = ");
if (paramType.isArray()) {
Class componentType = paramType.getComponentType();
if (componentType.isPrimitive()) {
if (critical) {
if (isCPP) {
output("env->GetPrimitiveArrayCritical(arg");
} else {
output("(*env)->GetPrimitiveArrayCritical(env, arg");
}
output(iStr);
output(", NULL)");
} else {
if (isCPP) {
output("env->Get");
} else {
output("(*env)->Get");
}
output(getTypeSignature1(componentType));
if (isCPP) {
output("ArrayElements(arg");
} else {
output("ArrayElements(env, arg");
}
output(iStr);
output(", NULL)");
}
} else {
throw new Error("not done");
}
} else if (paramType == String.class) {
if (paramData.getFlag("unicode")) {
if (isCPP) {
output("env->GetStringChars(arg");
} else {
output("(*env)->GetStringChars(env, arg");
}
output(iStr);
output(", NULL)");
} else {
if (isCPP) {
output("env->GetStringUTFChars(arg");
} else {
output("(*env)->GetStringUTFChars(env, arg");
}
output(iStr);
output(", NULL)");
}
} else {
if (paramData.getFlag("no_in")) {
output("&_arg");
output(iStr);
} else {
output("get");
output(getClassName(paramType));
output("Fields(env, arg");
output(iStr);
output(", &_arg");
output(iStr);
output(")");
}
}
outputln(") == NULL) goto fail;");
return true;
}
void generateSetParameter(int i, Class paramType, ParameterData paramData, boolean critical) {
if (paramType.isPrimitive() || isSystemClass(paramType)) return;
String iStr = String.valueOf(i);
if (paramType.isArray()) {
output("\tif (arg");
output(iStr);
output(" && lparg");
output(iStr);
output(") ");
Class componentType = paramType.getComponentType();
if (componentType.isPrimitive()) {
if (critical) {
if (isCPP) {
output("env->ReleasePrimitiveArrayCritical(arg");
} else {
output("(*env)->ReleasePrimitiveArrayCritical(env, arg");
}
output(iStr);
} else {
if (isCPP) {
output("env->Release");
} else {
output("(*env)->Release");
}
output(getTypeSignature1(componentType));
if (isCPP) {
output("ArrayElements(arg");
} else {
output("ArrayElements(env, arg");
}
output(iStr);
}
output(", lparg");
output(iStr);
output(", ");
if (paramData.getFlag("no_out")) {
output("JNI_ABORT");
} else {
output("0");
}
output(");");
} else {
throw new Error("not done");
}
outputln();
} else if (paramType == String.class) {
output("\tif (arg");
output(iStr);
output(" && lparg");
output(iStr);
output(") ");
if (paramData.getFlag("unicode")) {
if (isCPP) {
output("env->ReleaseStringChars(arg");
} else {
output("(*env)->ReleaseStringChars(env, arg");
}
} else {
if (isCPP) {
output("env->ReleaseStringUTFChars(arg");
} else {
output("(*env)->ReleaseStringUTFChars(env, arg");
}
}
output(iStr);
output(", lparg");
output(iStr);
outputln(");");
} else {
if (!paramData.getFlag("no_out")) {
output("\tif (arg");
output(iStr);
output(" && lparg");
output(iStr);
output(") ");
output("set");
output(getClassName(paramType));
output("Fields(env, arg");
output(iStr);
output(", lparg");
output(iStr);
outputln(");");
}
}
}
void generateExitMacro(Method method, String function) {
if (!enterExitMacro) return;
output("\t");
output(getClassName(method.getDeclaringClass()));
output("_NATIVE_EXIT(env, that, ");
output(function);
outputln("_FUNC);");
}
void generateEnterMacro(Method method, String function) {
if (!enterExitMacro) return;
output("\t");
output(getClassName(method.getDeclaringClass()));
output("_NATIVE_ENTER(env, that, ");
output(function);
outputln("_FUNC);");
}
boolean generateLocalVars(Method method, Class[] paramTypes, Class returnType) {
boolean needsReturn = enterExitMacro;
for (int i = 0; i < paramTypes.length; i++) {
Class paramType = paramTypes[i];
if (paramType.isPrimitive() || isSystemClass(paramType)) continue;
ParameterData paramData = getMetaData().getMetaData(method, i);
output("\t");
if (paramType.isArray()) {
Class componentType = paramType.getComponentType();
if (componentType.isPrimitive()) {
output(getTypeSignature2(componentType));
output(" *lparg" + i);
output("=NULL;");
} else {
throw new Error("not done");
}
} else if (paramType == String.class) {
if (paramData.getFlag("unicode")) {
output("const jchar *lparg" + i);
} else {
output("const char *lparg" + i);
}
output("= NULL;");
} else {
output(getClassName(paramType));
output(" _arg" + i);
if (paramData.getFlag("init")) output("={0}");
output(", *lparg" + i);
output("=NULL;");
}
outputln();
needsReturn = true;
}
if (needsReturn) {
if (returnType != Void.TYPE) {
output("\t");
output(getTypeSignature2(returnType));
outputln(" rc = 0;");
}
}
return needsReturn;
}
boolean generateGetters(Method method, Class[] paramTypes) {
boolean genFailTag = false;
int criticalCount = 0;
for (int i = 0; i < paramTypes.length; i++) {
Class paramType = paramTypes[i];
ParameterData paramData = getMetaData().getMetaData(method, i);
if (!isCritical(paramType, paramData)) {
genFailTag |= generateGetParameter(method, i, paramType, paramData, false, 1);
} else {
criticalCount++;
}
}
if (criticalCount != 0) {
outputln("#ifdef JNI_VERSION_1_2");
outputln("\tif (IS_JNI_1_2) {");
for (int i = 0; i < paramTypes.length; i++) {
Class paramType = paramTypes[i];
ParameterData paramData = getMetaData().getMetaData(method, i);
if (isCritical(paramType, paramData)) {
genFailTag |= generateGetParameter(method, i, paramType, paramData, true, 2);
}
}
outputln("\t} else");
outputln("#endif");
outputln("\t{");
for (int i = 0; i < paramTypes.length; i++) {
Class paramType = paramTypes[i];
ParameterData paramData = getMetaData().getMetaData(method, i);
if (isCritical(paramType, paramData)) {
genFailTag |= generateGetParameter(method, i, paramType, paramData, false, 2);
}
}
outputln("\t}");
}
return genFailTag;
}
void generateSetters(Method method, Class[] paramTypes) {
int criticalCount = 0;
for (int i = paramTypes.length - 1; i >= 0; i--) {
Class paramType = paramTypes[i];
ParameterData paramData = getMetaData().getMetaData(method, i);
if (isCritical(paramType, paramData)) {
criticalCount++;
}
}
if (criticalCount != 0) {
outputln("#ifdef JNI_VERSION_1_2");
outputln("\tif (IS_JNI_1_2) {");
for (int i = paramTypes.length - 1; i >= 0; i--) {
Class paramType = paramTypes[i];
ParameterData paramData = getMetaData().getMetaData(method, i);
if (isCritical(paramType, paramData)) {
output("\t");
generateSetParameter(i, paramType, paramData, true);
}
}
outputln("\t} else");
outputln("#endif");
outputln("\t{");
for (int i = paramTypes.length - 1; i >= 0; i--) {
Class paramType = paramTypes[i];
ParameterData paramData = getMetaData().getMetaData(method, i);
if (isCritical(paramType, paramData)) {
output("\t");
generateSetParameter(i, paramType, paramData, false);
}
}
outputln("\t}");
}
for (int i = paramTypes.length - 1; i >= 0; i--) {
Class paramType = paramTypes[i];
ParameterData paramData = getMetaData().getMetaData(method, i);
if (!isCritical(paramType, paramData)) {
generateSetParameter(i, paramType, paramData, false);
}
}
}
void generateDynamicFunctionCall(Method method, MethodData methodData, Class[] paramTypes, Class returnType, boolean needsReturn) {
outputln("/*");
generateFunctionCall(method, methodData, paramTypes, returnType, needsReturn);
outputln("*/");
outputln("\t{");
String name = method.getName();
if (name.startsWith("_")) name = name.substring(1);
if (getPlatform().equals("win32")) {
outputln("\t\tstatic int initialized = 0;");
outputln("\t\tstatic HMODULE hm = NULL;");
outputln("\t\tstatic FARPROC fp = NULL;");
if (returnType != Void.TYPE) {
if (needsReturn) {
outputln("\t\trc = 0;");
}
}
outputln("\t\tif (!initialized) {");
output("\t\t\tif (!hm) hm = LoadLibrary(");
output(name);
outputln("_LIB);");
output("\t\t\tif (hm) fp = GetProcAddress(hm, \"");
output(name);
outputln("\");");
outputln("\t\t\tinitialized = 1;");
outputln("\t\t}");
outputln("\t\tif (fp) {");
output("\t\t");
generateFunctionCallLeftSide(method, methodData, returnType, needsReturn);
output("fp");
generateFunctionCallRightSide(method, methodData, paramTypes, 0);
outputln();
outputln("\t\t}");
} else if (getPlatform().equals("carbon")) {
outputln("\t\tstatic int initialized = 0;");
outputln("\t\tstatic CFBundleRef bundle = NULL;");
output("\t\ttypedef ");
output(getTypeSignature2(returnType));
output(" (*FPTR)(");
for (int i = 0; i < paramTypes.length; i++) {
if (i != 0) output(", ");
Class paramType = paramTypes[i];
ParameterData paramData = getMetaData().getMetaData(method, i);
String cast = paramData.getCast();
if (cast.length() > 2) {
output(cast.substring(1, cast.length() - 1));
} else {
output(getTypeSignature4(paramType));
}
}
outputln(");");
outputln("\t\tstatic FPTR fptr;");
if (returnType != Void.TYPE) {
if (needsReturn) {
outputln("\t\trc = 0;");
}
}
outputln("\t\tif (!initialized) {");
output("\t\t\tif (!bundle) bundle = CFBundleGetBundleWithIdentifier(CFSTR(");
output(name);
outputln("_LIB));");
output("\t\t\tif (bundle) fptr = (FPTR)CFBundleGetFunctionPointerForName(bundle, CFSTR(\"");
output(name);
outputln("\"));");
outputln("\t\t\tinitialized = 1;");
outputln("\t\t}");
outputln("\t\tif (fptr) {");
output("\t\t");
generateFunctionCallLeftSide(method, methodData, returnType, needsReturn);
output("(*fptr)");
generateFunctionCallRightSide(method, methodData, paramTypes, 0);
outputln();
outputln("\t\t}");
} else {
outputln("\t\tstatic int initialized = 0;");
outputln("\t\tstatic void *handle = NULL;");
output("\t\ttypedef ");
output(getTypeSignature2(returnType));
output(" (*FPTR)(");
for (int i = 0; i < paramTypes.length; i++) {
if (i != 0) output(", ");
Class paramType = paramTypes[i];
ParameterData paramData = getMetaData().getMetaData(method, i);
String cast = paramData.getCast();
if (cast.length() > 2) {
output(cast.substring(1, cast.length() - 1));
} else {
output(getTypeSignature4(paramType));
}
}
outputln(");");
outputln("\t\tstatic FPTR fptr;");
if (returnType != Void.TYPE) {
if (needsReturn) {
outputln("\t\trc = 0;");
}
}
outputln("\t\tif (!initialized) {");
output("\t\t\tif (!handle) handle = dlopen(");
output(name);
outputln("_LIB, RTLD_LAZY);");
output("\t\t\tif (handle) fptr = (FPTR)dlsym(handle, \"");
output(name);
outputln("\");");
outputln("\t\t\tinitialized = 1;");
outputln("\t\t}");
outputln("\t\tif (fptr) {");
output("\t\t");
generateFunctionCallLeftSide(method, methodData, returnType, needsReturn);
output("(*fptr)");
generateFunctionCallRightSide(method, methodData, paramTypes, 0);
outputln();
outputln("\t\t}");
}
outputln("\t}");
}
void generateFunctionCallLeftSide(Method method, MethodData methodData, Class returnType, boolean needsReturn) {
output("\t");
if (returnType != Void.TYPE) {
if (needsReturn) {
output("rc = ");
} else {
output("return ");
}
output("(");
output(getTypeSignature2(returnType));
output(")");
}
if (methodData.getFlag("address")) {
output("&");
}
if (methodData.getFlag("jni")) {
output(isCPP ? "env->" : "(*env)->");
}
}
void generateFunctionCallRightSide(Method method, MethodData methodData, Class[] paramTypes, int paramStart) {
if (!methodData.getFlag("const")) {
output("(");
if (methodData.getFlag("jni")) {
if (!isCPP) output("env, ");
}
for (int i = paramStart; i < paramTypes.length; i++) {
Class paramType = paramTypes[i];
ParameterData paramData = getMetaData().getMetaData(method, i);
if (i != paramStart) output(", ");
if (paramData.getFlag("struct")) output("*");
output(paramData.getCast());
if (!paramType.isPrimitive() && !isSystemClass(paramType)) output("lp");
output("arg" + i);
}
output(")");
}
output(";");
}
void generateFunctionCall(Method method, MethodData methodData, Class[] paramTypes, Class returnType, boolean needsReturn) {
String copy = (String)methodData.getParam("copy");
boolean makeCopy = copy.length() != 0 && isCPP && returnType != Void.TYPE;
if (makeCopy) {
output("\t");
output(copy);
output(" temp = ");
} else {
generateFunctionCallLeftSide(method, methodData, returnType, needsReturn);
}
int paramStart = 0;
String name = method.getName();
if (name.startsWith("_")) name = name.substring(1);
if (name.equalsIgnoreCase("call")) {
output("(");
ParameterData paramData = getMetaData().getMetaData(method, 0);
String cast = paramData.getCast();
if (cast.length() != 0 && !cast.equals("()")) {
output(cast);
} else {
output("(");
output(getTypeSignature2(returnType));
output(" (*)())");
}
output("arg0)");
paramStart = 1;
} else if (name.startsWith("VtblCall")) {
output("((");
output(getTypeSignature2(returnType));
output(" (STDMETHODCALLTYPE *)(");
for (int i = 1; i < paramTypes.length; i++) {
if (i != 1) output(", ");
Class paramType = paramTypes[i];
output(getTypeSignature4(paramType));
}
output("))(*(");
output(getTypeSignature4(paramTypes[1]));
output(" **)arg1)[arg0])");
paramStart = 1;
} else if (methodData.getFlag("cpp")) {
output("(");
ParameterData paramData = getMetaData().getMetaData(method, 0);
if (paramData.getFlag("struct")) output("*");
String cast = paramData.getCast();
if (cast.length() != 0 && !cast.equals("()")) {
output(cast);
}
output("arg0)->");
String accessor = methodData.getAccessor();
if (accessor.length() != 0) {
output(accessor);
} else {
int index = -1;
if ((index = name.indexOf('_')) != -1) {
output(name.substring(index + 1, name.length()));
} else {
output(name);
}
}
paramStart = 1;
} else if (methodData.getFlag("new")) {
output("new ");
String accessor = methodData.getAccessor();
if (accessor.length() != 0) {
output(accessor);
} else {
int index = -1;
if ((index = name.indexOf('_')) != -1) {
output(name.substring(0, index));
} else {
output(name);
}
}
} else if (methodData.getFlag("delete")) {
output("delete ");
ParameterData paramData = getMetaData().getMetaData(method, 0);
String cast = paramData.getCast();
if (cast.length() != 0 && !cast.equals("()")) {
output(cast);
} else {
output("(");
output(name.substring(0, name.indexOf("_")));
output(" *)");
}
outputln("arg0;");
return;
} else {
String accessor = methodData.getAccessor();
if (accessor.length() != 0) {
output(accessor);
} else {
output(name);
}
}
generateFunctionCallRightSide(method, methodData, paramTypes, paramStart);
outputln();
if (makeCopy) {
outputln("\t{");
output("\t\t");
output(copy);
output("* copy = new ");
output(copy);
outputln("();");
outputln("\t\t*copy = temp;");
output("\t\trc = ");
output("(");
output(getTypeSignature2(returnType));
output(")");
outputln("copy;");
outputln("\t}");
}
}
void generateReturn(Method method, Class returnType, boolean needsReturn) {
if (needsReturn && returnType != Void.TYPE) {
outputln("\treturn rc;");
}
}
void generateGTKmemmove(Method method, String function, Class[] paramTypes) {
generateEnterMacro(method, function);
output("\t");
boolean get = paramTypes[0].isPrimitive();
String className = getClassName(paramTypes[get ? 1 : 0]);
output(get ? "if (arg1) get" : "if (arg0) set");
output(className);
output(get ? "Fields(env, arg1, (" : "Fields(env, arg0, (");
output(className);
output(get ? " *)arg0)" : " *)arg1)");
outputln(";");
generateExitMacro(method, function);
}
void generateFunctionBody(Method method, MethodData methodData, String function, Class[] paramTypes, Class returnType) {
outputln("{");
/* Custom GTK memmoves. */
String name = method.getName();
if (name.startsWith("_")) name = name.substring(1);
boolean isGTKmemove = name.equals("memmove") && paramTypes.length == 2 && returnType == Void.TYPE;
if (isGTKmemove) {
generateGTKmemmove(method, function, paramTypes);
} else {
boolean needsReturn = generateLocalVars(method, paramTypes, returnType);
generateEnterMacro(method, function);
boolean genFailTag = generateGetters(method, paramTypes);
if (methodData.getFlag("dynamic")) {
generateDynamicFunctionCall(method, methodData, paramTypes, returnType, needsReturn);
} else {
generateFunctionCall(method, methodData, paramTypes, returnType, needsReturn);
}
if (genFailTag) outputln("fail:");
generateSetters(method, paramTypes);
generateExitMacro(method, function);
generateReturn(method, returnType, needsReturn);
}
outputln("}");
}
void generateFunctionPrototype(Method method, String function, Class[] paramTypes, Class returnType) {
output("JNIEXPORT ");
output(getTypeSignature2(returnType));
output(" JNICALL ");
output(getClassName(method.getDeclaringClass()));
output("_NATIVE(");
output(function);
outputln(")");
output("\t(JNIEnv *env, ");
if ((method.getModifiers() & Modifier.STATIC) != 0) {
output("jclass");
} else {
output("jobject");
}
output(" that");
for (int i = 0; i < paramTypes.length; i++) {
Class paramType = paramTypes[i];
output(", ");
output(getTypeSignature2(paramType));
output(" arg" + i);
}
outputln(")");
}
void generateSourceStart(String function) {
output("#ifndef NO_");
outputln(function);
}
void generateSourceEnd(String function) {
outputln("#endif");
}
boolean isCritical(Class paramType, ParameterData paramData) {
return paramType.isArray() && paramType.getComponentType().isPrimitive() && paramData.getFlag("critical");
}
boolean isSystemClass(Class type) {
return type == Object.class || type == Class.class;
}
public static void main(String[] args) {
// args = new String[]{"org.eclipse.swt.internal.win32.OS"};
if (args.length < 1) {
System.out.println("Usage: java NativesGenerator <className1> <className2>");
return;
}
try {
NativesGenerator gen = new NativesGenerator();
for (int i = 0; i < args.length; i++) {
String clazzName = args[i];
Class clazz = Class.forName(clazzName);
gen.generate(clazz);
// gen.generate(clazz, "CommandBar_Destroy");
}
} catch (Exception e) {
System.out.println("Problem");
e.printStackTrace(System.out);
}
}
}