diff options
Diffstat (limited to 'src/java/com/jogamp/gluegen/procaddress')
4 files changed, 1045 insertions, 0 deletions
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java new file mode 100755 index 0000000..fedb1e6 --- /dev/null +++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.jogamp.gluegen.procaddress; + +import com.jogamp.gluegen.CMethodBindingEmitter; +import com.jogamp.gluegen.MethodBinding; +import com.jogamp.gluegen.JavaType; +import java.io.*; +import com.jogamp.gluegen.*; +import com.jogamp.gluegen.cgram.types.*; + +public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter { + + private boolean callThroughProcAddress; + private boolean needsLocalTypedef; + + private String localTypedefCallingConvention; + + private static final String procAddressJavaTypeName = JavaType.createForClass(Long.TYPE).jniTypeName(); + private ProcAddressEmitter emitter; + + public ProcAddressCMethodBindingEmitter(CMethodBindingEmitter methodToWrap, final boolean callThroughProcAddress, + boolean needsLocalTypedef, String localTypedefCallingConvention, ProcAddressEmitter emitter) { + + super( + new MethodBinding(methodToWrap.getBinding()) { + @Override + public String getName() { + if (callThroughProcAddress) { + return ProcAddressEmitter.WRAP_PREFIX + super.getName(); + } else { + return super.getName(); + } + } + }, + methodToWrap.getDefaultOutput(), + methodToWrap.getJavaPackageName(), + methodToWrap.getJavaClassName(), + methodToWrap.getIsOverloadedBinding(), + methodToWrap.getIsJavaMethodStatic(), + true, + methodToWrap.forIndirectBufferAndArrayImplementation(), + methodToWrap.getMachineDescription() + ); + + if (methodToWrap.getReturnValueCapacityExpression() != null) { + setReturnValueCapacityExpression(methodToWrap.getReturnValueCapacityExpression()); + } + if (methodToWrap.getReturnValueLengthExpression() != null) { + setReturnValueLengthExpression(methodToWrap.getReturnValueLengthExpression()); + } + setTemporaryCVariableDeclarations(methodToWrap.getTemporaryCVariableDeclarations()); + setTemporaryCVariableAssignments(methodToWrap.getTemporaryCVariableAssignments()); + + setCommentEmitter(defaultCommentEmitter); + + this.callThroughProcAddress = callThroughProcAddress; + this.needsLocalTypedef = needsLocalTypedef; + this.localTypedefCallingConvention = localTypedefCallingConvention; + this.emitter = emitter; + } + + @Override + protected int emitArguments(PrintWriter writer) { + int numEmitted = super.emitArguments(writer); + if (callThroughProcAddress) { + if (numEmitted > 0) { + writer.print(", "); + } + writer.print(procAddressJavaTypeName); + writer.print(" procAddress"); + ++numEmitted; + } + + return numEmitted; + } + + @Override + protected void emitBodyVariableDeclarations(PrintWriter writer) { + if (callThroughProcAddress) { + // create variable for the function pointer with the right type, and set + // it to the value of the passed-in proc address + FunctionSymbol cSym = getBinding().getCSymbol(); + String funcPointerTypedefName = + emitter.getFunctionPointerTypedefName(cSym); + + if (needsLocalTypedef) { + // We (probably) didn't get a typedef for this function + // pointer type in the header file; the user requested that we + // forcibly generate one. Here we force the emission of one. + PointerType funcPtrType = new PointerType(null, cSym.getType(), 0); + // Just for safety, emit this name slightly differently than + // the mangling would otherwise produce + funcPointerTypedefName = "_local_" + funcPointerTypedefName; + + writer.print(" typedef "); + writer.print(funcPtrType.toString(funcPointerTypedefName, localTypedefCallingConvention)); + writer.println(";"); + } + + writer.print(" "); + writer.print(funcPointerTypedefName); + writer.print(" ptr_"); + writer.print(cSym.getName()); + writer.println(";"); + } + + super.emitBodyVariableDeclarations(writer); + } + + @Override + protected void emitBodyVariablePreCallSetup(PrintWriter writer) { + super.emitBodyVariablePreCallSetup(writer); + + if (callThroughProcAddress) { + // set the function pointer to the value of the passed-in procAddress + FunctionSymbol cSym = getBinding().getCSymbol(); + String funcPointerTypedefName = emitter.getFunctionPointerTypedefName(cSym); + if (needsLocalTypedef) { + funcPointerTypedefName = "_local_" + funcPointerTypedefName; + } + + String ptrVarName = "ptr_" + cSym.getName(); + + writer.print(" "); + writer.print(ptrVarName); + writer.print(" = ("); + writer.print(funcPointerTypedefName); + writer.println(") (intptr_t) procAddress;"); + + writer.println(" assert(" + ptrVarName + " != NULL);"); + } + } + + @Override + protected void emitBodyCallCFunction(PrintWriter writer) { + if (!callThroughProcAddress) { + super.emitBodyCallCFunction(writer); + } else { + // Make the call to the actual C function + writer.print(" "); + + // WARNING: this code assumes that the return type has already been + // typedef-resolved. + Type cReturnType = binding.getCReturnType(); + + if (!cReturnType.isVoid()) { + writer.print("_res = "); + } + MethodBinding mBinding = getBinding(); + if (mBinding.hasContainingType()) { + // FIXME: this can and should be handled and unified with the + // associated code in the CMethodBindingEmitter + throw new IllegalStateException("Cannot call through function pointer because binding has containing type: " + mBinding); + } + + // call throught the run-time function pointer + writer.print("(* ptr_"); + writer.print(mBinding.getCSymbol().getName()); + writer.print(") "); + writer.print("("); + emitBodyPassCArguments(writer); + writer.println(");"); + } + } + + @Override + protected String jniMangle(MethodBinding binding) { + StringBuffer buf = new StringBuffer(super.jniMangle(binding)); + if (callThroughProcAddress) { + jniMangle(Long.TYPE, buf, false); // to account for the additional _addr_ parameter + } + return buf.toString(); + } +} diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java new file mode 100755 index 0000000..51e3166 --- /dev/null +++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ +package com.jogamp.gluegen.procaddress; + +import com.jogamp.gluegen.JavaConfiguration; +import java.io.*; +import java.text.*; +import java.util.*; + +import com.jogamp.gluegen.*; + +public class ProcAddressConfiguration extends JavaConfiguration { + + private boolean emitProcAddressTable = false; + private boolean forceProcAddressGen4All = false; + + private String tableClassPackage; + private String tableClassName = "ProcAddressTable"; + private String getProcAddressTableExpr; + private String localProcAddressCallingConvention4All = null; + + private ConvNode procAddressNameConverter; + private final Set<String> skipProcAddressGen = new HashSet<String>(); + private final List<String> forceProcAddressGen = new ArrayList<String>(); + private final Set<String> forceProcAddressGenSet = new HashSet<String>(); + + // This is needed only on Windows. Ideally we would modify the + // HeaderParser and PCPP to automatically pick up the calling + // convention from the headers + private Map<String, String> localProcAddressCallingConventionMap = new HashMap<String, String>(); + + @Override + protected void dispatch(String cmd, StringTokenizer tok, File file, String filename, int lineNo) throws IOException { + if (cmd.equalsIgnoreCase("EmitProcAddressTable")) { + emitProcAddressTable = readBoolean("EmitProcAddressTable", tok, filename, lineNo).booleanValue(); + } else if (cmd.equalsIgnoreCase("ProcAddressTablePackage")) { + tableClassPackage = readString("ProcAddressTablePackage", tok, filename, lineNo); + } else if (cmd.equalsIgnoreCase("ProcAddressTableClassName")) { + tableClassName = readString("ProcAddressTableClassName", tok, filename, lineNo); + } else if (cmd.equalsIgnoreCase("SkipProcAddressGen")) { + String sym = readString("SkipProcAddressGen", tok, filename, lineNo); + skipProcAddressGen.add(sym); + } else if (cmd.equalsIgnoreCase("ForceProcAddressGen")) { + String funcName = readString("ForceProcAddressGen", tok, filename, lineNo); + if (funcName.equals("__ALL__")) { + forceProcAddressGen4All = true; + } else { + addForceProcAddressGen(funcName); + } + } else if (cmd.equalsIgnoreCase("GetProcAddressTableExpr")) { + getProcAddressTableExpr = readGetProcAddressTableExpr(tok, filename, lineNo); + } else if (cmd.equalsIgnoreCase("ProcAddressNameExpr")) { + readProcAddressNameExpr(tok, filename, lineNo); + } else if (cmd.equalsIgnoreCase("LocalProcAddressCallingConvention")) { + readLocalProcAddressCallingConvention(tok, filename, lineNo); + } else { + super.dispatch(cmd, tok, file, filename, lineNo); + } + } + + protected String readGetProcAddressTableExpr(StringTokenizer tok, String filename, int lineNo) { + try { + String restOfLine = tok.nextToken("\n\r\f"); + return restOfLine.trim(); + } catch (NoSuchElementException e) { + throw new RuntimeException("Error parsing \"GetProcAddressTableExpr\" command at line " + lineNo + + " in file \"" + filename + "\"", e); + } + } + + protected void setProcAddressNameExpr(String expr) { + // Parse this into something allowing us to map from a function + // name to the typedef'ed function pointer name + List<String> tokens = new ArrayList<String>(); + StringTokenizer tok1 = new StringTokenizer(expr); + while (tok1.hasMoreTokens()) { + String sstr = tok1.nextToken(); + StringTokenizer tok2 = new StringTokenizer(sstr, "$()", true); + while (tok2.hasMoreTokens()) { + tokens.add(tok2.nextToken()); + } + } + + // Now that the string is flattened out, convert it to nodes + procAddressNameConverter = makeConverter(tokens.iterator()); + if (procAddressNameConverter == null) { + throw new NoSuchElementException("Error creating converter from string"); + } + } + + protected void readProcAddressNameExpr(StringTokenizer tok, String filename, int lineNo) { + try { + String restOfLine = tok.nextToken("\n\r\f"); + restOfLine = restOfLine.trim(); + setProcAddressNameExpr(restOfLine); + } catch (NoSuchElementException e) { + throw new RuntimeException("Error parsing \"ProcAddressNameExpr\" command at line " + lineNo + + " in file \"" + filename + "\"", e); + } + } + + protected void readLocalProcAddressCallingConvention(StringTokenizer tok, String filename, int lineNo) throws IOException { + try { + String functionName = tok.nextToken(); + String callingConvention = tok.nextToken(); + if (functionName.equals("__ALL__")) { + localProcAddressCallingConvention4All = callingConvention; + } else { + localProcAddressCallingConventionMap.put(functionName, callingConvention); + } + } catch (NoSuchElementException e) { + throw new RuntimeException("Error parsing \"LocalProcAddressCallingConvention\" command at line " + lineNo + + " in file \"" + filename + "\"", e); + } + } + + private static ConvNode makeConverter(Iterator<String> iter) { + List<ConvNode> result = new ArrayList<ConvNode>(); + + while (iter.hasNext()) { + String str = iter.next(); + if (str.equals("$")) { + String command = iter.next(); + String openParen = iter.next(); + if (!openParen.equals("(")) { + throw new NoSuchElementException("Expected \"(\""); + } + boolean uppercase = false; + if (command.equalsIgnoreCase("UPPERCASE")) { + uppercase = true; + } else if (!command.equalsIgnoreCase("LOWERCASE")) { + throw new NoSuchElementException("Unknown ProcAddressNameExpr command \"" + command + "\""); + } + result.add(new CaseNode(uppercase, makeConverter(iter))); + } else if (str.equals(")")) { + // Fall through and return + } else if (str.indexOf('{') >= 0) { + result.add(new FormatNode(str)); + } else { + result.add(new ConstStringNode(str)); + } + } + if (result.isEmpty()) { + return null; + } else if (result.size() == 1) { + return result.get(0); + } else { + return new ConcatNode(result); + } + } + + /** Helper class for converting a function name to the typedef'ed + function pointer name */ + static abstract class ConvNode { + abstract String convert(String funcName); + } + + static class FormatNode extends ConvNode { + + private MessageFormat msgFmt; + + FormatNode(String fmt) { + msgFmt = new MessageFormat(fmt); + } + + String convert(String funcName) { + StringBuffer buf = new StringBuffer(); + msgFmt.format(new Object[]{funcName}, buf, null); + return buf.toString(); + } + } + + static class ConstStringNode extends ConvNode { + + private String str; + + ConstStringNode(String str) { + this.str = str; + } + + String convert(String funcName) { + return str; + } + } + + static class ConcatNode extends ConvNode { + + private List<ConvNode> children; + + ConcatNode(List<ConvNode> children) { + this.children = children; + } + + String convert(String funcName) { + StringBuilder res = new StringBuilder(); + for (ConvNode node : children) { + res.append(node.convert(funcName)); + } + return res.toString(); + } + } + + static class CaseNode extends ConvNode { + + private boolean upperCase; + private ConvNode child; + + CaseNode(boolean upperCase, ConvNode child) { + this.upperCase = upperCase; + this.child = child; + } + + public String convert(String funcName) { + if (upperCase) { + return child.convert(funcName).toUpperCase(); + } else { + return child.convert(funcName).toLowerCase(); + } + } + } + + public boolean emitProcAddressTable() { + return emitProcAddressTable; + } + + public String tableClassPackage() { + return tableClassPackage; + } + + public String tableClassName() { + return tableClassName; + } + + public boolean skipProcAddressGen(String name) { + return skipProcAddressGen.contains(name); + } + + public boolean isForceProcAddressGen4All() { + return forceProcAddressGen4All; + } + + public List<String> getForceProcAddressGen() { + return forceProcAddressGen; + } + + public String getProcAddressTableExpr() { + if (getProcAddressTableExpr == null) { + throw new RuntimeException("GetProcAddressTableExpr was not defined in .cfg file"); + } + return getProcAddressTableExpr; + } + + public String convertToFunctionPointerName(String funcName) { + if (procAddressNameConverter == null) { + throw new RuntimeException("ProcAddressNameExpr was not defined in .cfg file"); + } + return procAddressNameConverter.convert(funcName); + } + + public boolean forceProcAddressGen(String funcName) { + return forceProcAddressGen4All || forceProcAddressGenSet.contains(funcName); + } + + public void addForceProcAddressGen(String funcName) { + forceProcAddressGen.add(funcName); + forceProcAddressGenSet.add(funcName); + } + + public void addLocalProcAddressCallingConvention(String funcName, String callingConvention) { + localProcAddressCallingConventionMap.put(funcName, callingConvention); + } + + public String getLocalProcAddressCallingConvention(String funcName) { + if (isLocalProcAddressCallingConvention4All()) { + return getLocalProcAddressCallingConvention4All(); + } + return localProcAddressCallingConventionMap.get(funcName); + } + + public boolean isLocalProcAddressCallingConvention4All() { + return localProcAddressCallingConvention4All != null; + } + + public String getLocalProcAddressCallingConvention4All() { + return localProcAddressCallingConvention4All; + } +} diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java new file mode 100755 index 0000000..c07dab7 --- /dev/null +++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ +package com.jogamp.gluegen.procaddress; + +import com.jogamp.gluegen.CMethodBindingEmitter; +import com.jogamp.gluegen.JavaConfiguration; +import com.jogamp.gluegen.MethodBinding; +import com.jogamp.gluegen.FunctionEmitter; +import com.jogamp.gluegen.CodeGenUtils; +import com.jogamp.gluegen.JavaMethodBindingEmitter; +import com.jogamp.gluegen.JavaEmitter; +import java.io.*; +import java.text.MessageFormat; +import java.util.*; +import com.jogamp.gluegen.*; +import com.jogamp.gluegen.cgram.types.*; +import com.jogamp.gluegen.runtime.*; + +/** + * A subclass of JavaEmitter that modifies the normal emission of C + * and Java code to allow dynamic lookups of the C entry points + * associated with the Java methods. + */ +public class ProcAddressEmitter extends JavaEmitter { + + public static final String PROCADDRESS_VAR_PREFIX = ProcAddressTable.PROCADDRESS_VAR_PREFIX; + protected static final String WRAP_PREFIX = "dispatch_"; + private TypeDictionary typedefDictionary; + protected PrintWriter tableWriter; + protected Set<String> emittedTableEntries; + protected String tableClassPackage; + protected String tableClassName; + + @Override + public void beginFunctions(TypeDictionary typedefDictionary, TypeDictionary structDictionary, Map<Type, Type> canonMap) throws Exception { + this.typedefDictionary = typedefDictionary; + + if (getProcAddressConfig().emitProcAddressTable()) { + beginProcAddressTable(); + } + super.beginFunctions(typedefDictionary, structDictionary, canonMap); + } + + @Override + public void endFunctions() throws Exception { + if (getProcAddressConfig().emitProcAddressTable()) { + endProcAddressTable(); + } + super.endFunctions(); + } + + @Override + public void beginStructs(TypeDictionary typedefDictionary, TypeDictionary structDictionary, Map<Type, Type> canonMap) throws Exception { + super.beginStructs(typedefDictionary, structDictionary, canonMap); + } + + public String runtimeExceptionType() { + return getConfig().runtimeExceptionType(); + } + + public String unsupportedExceptionType() { + return getConfig().unsupportedExceptionType(); + } + + @Override + protected JavaConfiguration createConfig() { + return new ProcAddressConfiguration(); + } + + @Override + protected List<? extends FunctionEmitter> generateMethodBindingEmitters(Set<MethodBinding> methodBindingSet, FunctionSymbol sym) throws Exception { + return generateMethodBindingEmittersImpl(methodBindingSet, sym); + } + + protected boolean needsModifiedEmitters(FunctionSymbol sym) { + if (!needsProcAddressWrapper(sym) + || getConfig().isUnimplemented(getAliasedSymName(sym))) { + return false; + } + + return true; + } + + private List<? extends FunctionEmitter> generateMethodBindingEmittersImpl(Set<MethodBinding> methodBindingSet, FunctionSymbol sym) throws Exception { + List<? extends FunctionEmitter> defaultEmitters = super.generateMethodBindingEmitters(methodBindingSet, sym); + + // if the superclass didn't generate any bindings for the symbol, let's + // honor that (for example, the superclass might have caught an Ignore + // direction that matched the symbol's name). + if (defaultEmitters.isEmpty()) { + return defaultEmitters; + } + + // Don't do anything special if this symbol doesn't require + // modifications + if (!needsModifiedEmitters(sym)) { + return defaultEmitters; + } + + ArrayList<FunctionEmitter> modifiedEmitters = new ArrayList<FunctionEmitter>(defaultEmitters.size()); + + if (needsProcAddressWrapper(sym)) { + if (getProcAddressConfig().emitProcAddressTable()) { + // emit an entry in the GL proc address table for this method. + emitProcAddressTableEntryForString(getAliasedSymName(sym)); + } + } + for (FunctionEmitter emitter : defaultEmitters) { + if (emitter instanceof JavaMethodBindingEmitter) { + generateModifiedEmitters((JavaMethodBindingEmitter)emitter, modifiedEmitters); + } else if (emitter instanceof CMethodBindingEmitter) { + generateModifiedEmitters((CMethodBindingEmitter) emitter, modifiedEmitters); + } else { + throw new RuntimeException("Unexpected emitter type: " + emitter.getClass().getName()); + } + } + + return modifiedEmitters; + } + + /** + * Returns the name of the typedef for a pointer to the function + * represented by the argument as defined by the ProcAddressNameExpr + * in the .cfg file. For example, in the OpenGL headers, if the + * argument is the function "glFuncName", the value returned will be + * "PFNGLFUNCNAMEPROC". This returns a valid string regardless of + * whether or not the typedef is actually defined. + */ + protected String getFunctionPointerTypedefName(FunctionSymbol sym) { + return getProcAddressConfig().convertToFunctionPointerName(sym.getName()); + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + protected void generateModifiedEmitters(JavaMethodBindingEmitter baseJavaEmitter, List<FunctionEmitter> emitters) { + if (getConfig().manuallyImplement(baseJavaEmitter.getName())) { + // User will provide Java-side implementation of this routine; + // pass through any emitters which will produce signatures for + // it unmodified + emitters.add(baseJavaEmitter); + return; + } + + // See whether we need a proc address entry for this one + boolean callThroughProcAddress = needsProcAddressWrapper(baseJavaEmitter.getBinding().getCSymbol()); + + ProcAddressJavaMethodBindingEmitter emitter = + new ProcAddressJavaMethodBindingEmitter(baseJavaEmitter, + callThroughProcAddress, + getProcAddressConfig().getProcAddressTableExpr(), + baseJavaEmitter.isForImplementingMethodCall(), + this); + emitters.add(emitter); + + // If this emitter doesn't have a body (i.e., is a direct native + // call with no intervening argument processing), we need to force + // it to emit a body, and produce another one to act as the entry + // point + // FIXME: the negative test against the PRIVATE modifier is a + // nasty hack to prevent the ProcAddressJavaMethodBindingEmitter + // from incorrectly introducing method bodies to the private + // native implementing methods; want this to work at least for + // public and package-private methods + if (baseJavaEmitter.signatureOnly() + && !baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.PRIVATE) + && baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.NATIVE) + && callThroughProcAddress) { + emitter.setEmitBody(true); + emitter.removeModifier(JavaMethodBindingEmitter.NATIVE); + emitter = new ProcAddressJavaMethodBindingEmitter(baseJavaEmitter, + callThroughProcAddress, + getProcAddressConfig().getProcAddressTableExpr(), + true, + this); + emitter.setForImplementingMethodCall(true); + emitters.add(emitter); + } + } + + protected void generateModifiedEmitters(CMethodBindingEmitter baseCEmitter, List<FunctionEmitter> emitters) { + + FunctionSymbol cSymbol = baseCEmitter.getBinding().getCSymbol(); + + // See whether we need a proc address entry for this one + boolean callThroughProcAddress = needsProcAddressWrapper(cSymbol); + boolean forceProcAddress = getProcAddressConfig().forceProcAddressGen(cSymbol.getName()); + + String forcedCallingConvention = null; + if (forceProcAddress) { + forcedCallingConvention = getProcAddressConfig().getLocalProcAddressCallingConvention(cSymbol.getName()); + } + // Note that we don't care much about the naming of the C argument + // variables so to keep things simple we ignore the buffer object + // property for the binding + + // The C-side JNI binding for this particular function will have an + // extra final argument, which is the address (the OpenGL procedure + // address) of the function it needs to call + ProcAddressCMethodBindingEmitter res = new ProcAddressCMethodBindingEmitter( + baseCEmitter, callThroughProcAddress, forceProcAddress, forcedCallingConvention, this); + + MessageFormat exp = baseCEmitter.getReturnValueCapacityExpression(); + if (exp != null) { + res.setReturnValueCapacityExpression(exp); + } + emitters.add(res); + } + + private String getAliasedSymName(FunctionSymbol sym) { + String symName = getConfig().getJavaSymbolRename(sym.getName()); + if (null == symName) { + symName = sym.getName(); + } + return symName; + } + + protected boolean needsProcAddressWrapper(FunctionSymbol sym) { + String symName = getAliasedSymName(sym); + + ProcAddressConfiguration config = getProcAddressConfig(); + + // We should only generate code to call through a function pointer + // if the symbol has an associated function pointer typedef. + String funcPointerTypedefName = getFunctionPointerTypedefName(sym); + boolean shouldWrap = typedefDictionary.containsKey(funcPointerTypedefName); + //System.err.println(funcPointerTypedefName + " defined: " + shouldWrap); + + if (config.skipProcAddressGen(symName)) { + shouldWrap = false; + } + + if (config.forceProcAddressGen(symName)) { + shouldWrap = true; + } + + if (shouldWrap) { + // Hoist argument names from function pointer if not supplied in prototype + Type funcPointerType = typedefDictionary.get(funcPointerTypedefName); + if (funcPointerType != null) { + FunctionType typedef = funcPointerType.asPointer().getTargetType().asFunction(); + FunctionType fun = sym.getType(); + int numarg = typedef.getNumArguments(); + for (int i = 0; i < numarg; i++) { + if (fun.getArgumentName(i) == null) { + fun.setArgumentName(i, typedef.getArgumentName(i)); + } + } + } + } + + return shouldWrap; + } + + protected void beginProcAddressTable() throws Exception { + tableClassPackage = getProcAddressConfig().tableClassPackage(); + tableClassName = getProcAddressConfig().tableClassName(); + + // Table defaults to going into the impl directory unless otherwise overridden + String implPackageName = tableClassPackage; + if (implPackageName == null) { + implPackageName = getImplPackageName(); + } + String jImplRoot = getJavaOutputDir() + File.separator + CodeGenUtils.packageAsPath(implPackageName); + + tableWriter = openFile(jImplRoot + File.separator + tableClassName + ".java"); + emittedTableEntries = new HashSet<String>(); + + CodeGenUtils.emitAutogeneratedWarning(tableWriter, this); + + tableWriter.println("package " + implPackageName + ";"); + tableWriter.println(); + for (String imporT : getConfig().imports()) { + tableWriter.println("import " + imporT + ";"); + } + tableWriter.println("import " + ProcAddressTable.class.getName() + ";"); + tableWriter.println(); + + tableWriter.println("/**"); + tableWriter.println(" * This table is a cache of pointers to the dynamically-linkable C library."); + tableWriter.println(" * @see " + ProcAddressTable.class.getSimpleName()); + tableWriter.println(" */"); + tableWriter.println("public class " + tableClassName + " extends "+ ProcAddressTable.class.getSimpleName() + " {"); + tableWriter.println(); + + for (String string : getProcAddressConfig().getForceProcAddressGen()) { + emitProcAddressTableEntryForString(string); + } + + tableWriter.println(); + tableWriter.println(" public "+tableClassName+"(){ super(); }"); + tableWriter.println(); + tableWriter.println(" public "+tableClassName+"("+FunctionAddressResolver.class.getName()+" resolver){ super(resolver); }"); + tableWriter.println(); + + } + + protected void endProcAddressTable() throws Exception { + tableWriter.println("} // end of class " + tableClassName); + tableWriter.flush(); + tableWriter.close(); + } + + protected void emitProcAddressTableEntryForString(String str) { + // Deal gracefully with forced proc address generation in the face + // of having the function pointer typedef in the header file too + if (emittedTableEntries.contains(str)) { + return; + } + emittedTableEntries.add(str); + tableWriter.print(" public long "); + tableWriter.print(PROCADDRESS_VAR_PREFIX); + tableWriter.print(str); + tableWriter.println(";"); + } + + protected ProcAddressConfiguration getProcAddressConfig() { + return (ProcAddressConfiguration) getConfig(); + } +} diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java new file mode 100755 index 0000000..443c1d8 --- /dev/null +++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ +package com.jogamp.gluegen.procaddress; + +import com.jogamp.gluegen.MethodBinding; +import com.jogamp.gluegen.FunctionEmitter; +import com.jogamp.gluegen.JavaMethodBindingEmitter; +import java.io.*; +import com.jogamp.gluegen.*; + +/** A specialization of JavaMethodBindingEmitter with knowledge of how +to call through a function pointer. */ +public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitter { + + protected boolean callThroughProcAddress; + protected boolean changeNameAndArguments; + + protected String getProcAddressTableExpr; + protected ProcAddressEmitter emitter; + + public ProcAddressJavaMethodBindingEmitter(JavaMethodBindingEmitter methodToWrap, boolean callThroughProcAddress, + String getProcAddressTableExpr, boolean changeNameAndArguments, ProcAddressEmitter emitter) { + + super(methodToWrap); + + this.callThroughProcAddress = callThroughProcAddress; + this.getProcAddressTableExpr = getProcAddressTableExpr; + this.changeNameAndArguments = changeNameAndArguments; + this.emitter = emitter; + + if (callThroughProcAddress) { + setCommentEmitter(new WrappedMethodCommentEmitter()); + } + + if (methodToWrap.getBinding().hasContainingType()) { + throw new IllegalArgumentException( + "Cannot create proc. address wrapper; method has containing type: \"" + + methodToWrap.getBinding() + "\""); + } + } + + public ProcAddressJavaMethodBindingEmitter(ProcAddressJavaMethodBindingEmitter methodToWrap) { + this(methodToWrap, methodToWrap.callThroughProcAddress, methodToWrap.getProcAddressTableExpr, + methodToWrap.changeNameAndArguments, methodToWrap.emitter); + } + + @Override + public String getName() { + String res = super.getName(); + if (changeNameAndArguments) { + return ProcAddressEmitter.WRAP_PREFIX + res; + } + return res; + } + + @Override + protected int emitArguments(PrintWriter writer) { + int numEmitted = super.emitArguments(writer); + if (callThroughProcAddress) { + if (changeNameAndArguments) { + if (numEmitted > 0) { + writer.print(", "); + } + + writer.print("long procAddress"); + ++numEmitted; + } + } + + return numEmitted; + } + + @Override + protected String getImplMethodName() { + String name = super.getImplMethodName(); + if (callThroughProcAddress) { + return ProcAddressEmitter.WRAP_PREFIX + name; + } + return name; + } + + @Override + protected void emitPreCallSetup(MethodBinding binding, PrintWriter writer) { + super.emitPreCallSetup(binding, writer); + + if (callThroughProcAddress) { + String procAddressVariable = ProcAddressEmitter.PROCADDRESS_VAR_PREFIX + binding.getName(); + writer.println(" final long __addr_ = " + getProcAddressTableExpr + "." + procAddressVariable + ";"); + writer.println(" if (__addr_ == 0) {"); + writer.println(" throw new " + emitter.unsupportedExceptionType() + "(\"Method \\\"" + binding.getName() + "\\\" not available\");"); + writer.println(" }"); + } + } + + @Override + protected int emitCallArguments(MethodBinding binding, PrintWriter writer) { + int numEmitted = super.emitCallArguments(binding, writer); + if (callThroughProcAddress) { + if (numEmitted > 0) { + writer.print(", "); + } + writer.print("__addr_"); + ++numEmitted; + } + + return numEmitted; + } + + /** This class emits the comment for the wrapper method */ + public class WrappedMethodCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter { + + @Override + protected void emitBeginning(FunctionEmitter methodEmitter, PrintWriter writer) { + writer.print("Entry point (through function pointer) to C language function: <br> "); + } + } +} |