/******************************************************************************* * Copyright (c) 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-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 className = getClassName(getMainClass()).toLowerCase(); outputln("#include \"swt.h\""); output("#include \""); output(className); outputln("_structs.h\""); output("#include \""); output(className); 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("}"); } } 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(); } } 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())) { 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 generateNativeMacro(Class clazz) { output("#define "); output(getClassName(clazz)); output("_NATIVE(func) Java_"); output(toC(clazz.getName())); outputln("_##func"); outputln(); } void generateGetParameter(int i, Class paramType, ParameterData paramData, boolean critical) { if (paramType.isPrimitive()) return; String iStr = String.valueOf(i); output("\tif (arg"); output(iStr); output(") 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); output(";"); } else { output("get"); output(getClassName(paramType)); output("Fields(env, arg"); output(iStr); output(", &_arg"); output(iStr); output(");"); } } outputln(); } void generateSetParameter(int i, Class paramType, ParameterData paramData, boolean critical) { if (paramType.isPrimitive()) return; String iStr = String.valueOf(i); if (paramType.isArray()) { output("\tif (arg"); 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(") "); 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(") "); 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()) 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;"); } } return needsReturn; } void generateGetters(Method method, Class[] paramTypes) { 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)) { generateGetParameter(i, paramType, paramData, false); } 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)) { output("\t"); generateGetParameter(i, paramType, paramData, true); } } 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)) { output("\t"); generateGetParameter(i, paramType, paramData, false); } } outputln("\t}"); } } 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{"); 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 = GetModuleHandle("); output(method.getName()); output("_LIB))) hm = LoadLibrary("); output(method.getName()); outputln("_LIB);"); output("\t\t\tif (hm) fp = GetProcAddress(hm, \""); output(method.getName()); 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 { 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(method.getName()); outputln("_LIB, RTLD_LAZY);"); output("\t\t\tif (handle) fptr = (FPTR)dlsym(handle, \""); output(method.getName()); 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("&"); } } void generateFunctionCallRightSide(Method method, MethodData methodData, Class[] paramTypes, int paramStart) { if (!methodData.getFlag("const")) { output("("); 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()) 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; if (method.getName().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 (method.getName().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("))(*(int **)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; String name = method.getName(); 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; String name = method.getName(); 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); } outputln("arg0;"); return; } else { String accessor = methodData.getAccessor(); if (accessor.length() != 0) { output(accessor); } else { output(method.getName()); } } 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. */ boolean isGTKmemove = method.getName().equals("memmove") && paramTypes.length == 2 && returnType == Void.TYPE; if (isGTKmemove) { generateGTKmemmove(method, function, paramTypes); } else { boolean needsReturn = generateLocalVars(method, paramTypes, returnType); generateEnterMacro(method, function); generateGetters(method, paramTypes); if (methodData.getFlag("dynamic")) { generateDynamicFunctionCall(method, methodData, paramTypes, returnType, needsReturn); } else { generateFunctionCall(method, methodData, paramTypes, returnType, needsReturn); } 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"); } 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 "); 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); } } }