From bbea09816015ecf3596acdcc033553127fcc0ef3 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 11 Mar 2015 15:10:15 +0100 Subject: Bug 1144 - Add 'DelegateImplementation': Requires own MethodBinding for delegates impl. / Adding ReturnsOpaque - DelegateImplementation requires own MethodBinding for delegates impl. The delegation name must be included within the FunctionSymbol's aliases _only_ for implementations, where delegation applies. This allows all subsequent type/cfg checks to hit on AliasedSymbol! Hence we need to create individual MethodBinding instances for interfaces and public/private implementations. - Adding ReturnsOpaque Configuration: ReturnsOpaque This feature is necessary to achieve 'Opaque' functionality for function's return type - instead of types in general. - Fix AliasedSymbolImpl copy-ctor, i.e. this.name = o.name ! --- .../com/jogamp/gluegen/CMethodBindingEmitter.java | 2 +- src/java/com/jogamp/gluegen/JavaConfiguration.java | 52 +++++++++++- src/java/com/jogamp/gluegen/JavaEmitter.java | 96 +++++++++++++--------- src/java/com/jogamp/gluegen/MethodBinding.java | 2 +- .../jogamp/gluegen/cgram/types/AliasedSymbol.java | 2 +- .../jogamp/gluegen/cgram/types/FunctionSymbol.java | 11 +++ .../gluegen/procaddress/ProcAddressEmitter.java | 19 ++--- .../ProcAddressJavaMethodBindingEmitter.java | 2 +- 8 files changed, 128 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java index bb95226..7c88c37 100644 --- a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java +++ b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java @@ -1083,7 +1083,7 @@ public class CMethodBindingEmitter extends FunctionEmitter { } } if( 0 == mode ) { - if( null != cfg.typeInfo(cReturnType) ) { + if( null != cfg.typeInfo(cReturnType) ) { // javaReturnType.isOpaqued() covered above via isPrimitive() // Opaque writer.println("sizeof(" + cReturnType.getCName() + ") );"); mode = 88; diff --git a/src/java/com/jogamp/gluegen/JavaConfiguration.java b/src/java/com/jogamp/gluegen/JavaConfiguration.java index 21ba8d9..019ca2d 100644 --- a/src/java/com/jogamp/gluegen/JavaConfiguration.java +++ b/src/java/com/jogamp/gluegen/JavaConfiguration.java @@ -138,6 +138,7 @@ public class JavaConfiguration { private final Map accessControl = new HashMap(); private final Map typeInfoMap = new HashMap(); private final Set returnsString = new HashSet(); + private final Map returnsOpaqueJType = new HashMap(); private final Map returnedArrayLengths = new HashMap(); /** @@ -519,7 +520,6 @@ public class JavaConfiguration { oneInSet(returnsString, symbol.getAliasedNames()); } - /** * Returns a MessageFormat string of the Java expression calculating * the number of elements in the returned array from the specified function @@ -886,7 +886,7 @@ public class JavaConfiguration { if( null == res ) { return null; } - LOG.log(INFO, "DelegatedImplementation: {0}", functionName); + LOG.log(INFO, "DelegatedImplementation: {0} -> {1}", functionName, res); return res; } @@ -924,6 +924,41 @@ public class JavaConfiguration { return res; } + /** + * Variant of {@link #getOpaqueReturnType(AliasedSymbol)}, + * where this method only considers the {@link AliasedSymbol#getName() current-name} + * of the given symbol, not the {@link #getJavaSymbolRename(String) renamed-symbol}. + */ + public JavaType getOpaqueReturnType(final String functionName) { + final JavaType res = returnsOpaqueJType.get(functionName); + if( null == res ) { + return null; + } + LOG.log(INFO, "ReturnsOpaque: {0} -> {1}", functionName, res); + return res; + } + + /** + * Returns the opaque {@link JavaType} for the given function {@link AliasedSymbol} + * or {@code null} if not opaque. + *

+ * {@code ReturnsOpaque } + *

+ */ + public JavaType getOpaqueReturnType(final AliasedSymbol symbol) { + final String name = symbol.getName(); + final Set aliases = symbol.getAliasedNames(); + JavaType res = returnsOpaqueJType.get(name); + if( null == res ) { + res = oneInMap(returnsOpaqueJType, aliases); + if( null == res ) { + return null; + } + } + LOG.log(INFO, getASTLocusTag(symbol), "ReturnsOpaque: {0} -> {1}", symbol, res); + return res; + } + /** * Variant of {@link #shouldIgnoreInInterface(AliasedSymbol)}, * where this method only considers the {@link AliasedSymbol#getName() current-name} @@ -1222,6 +1257,8 @@ public class JavaConfiguration { readOpaque(tok, filename, lineNo); } else if (cmd.equalsIgnoreCase("ReturnsString")) { readReturnsString(tok, filename, lineNo); + } else if (cmd.equalsIgnoreCase("ReturnsOpaque")) { + readReturnsOpaque(tok, filename, lineNo); } else if (cmd.equalsIgnoreCase("ReturnedArrayLength")) { readReturnedArrayLength(tok, filename, lineNo); // Warning: make sure delimiters are reset at the top of this loop @@ -1418,6 +1455,17 @@ public class JavaConfiguration { } } + protected void readReturnsOpaque(final StringTokenizer tok, final String filename, final int lineNo) { + try { + final JavaType javaType = JavaType.createForOpaqueClass(stringToPrimitiveType(tok.nextToken())); + final String funcName = tok.nextToken(); + returnsOpaqueJType.put(funcName, javaType); + } catch (final Exception e) { + throw new RuntimeException("Error parsing \"ReturnsOpaque\" command at line " + lineNo + + " in file \"" + filename + "\"", e); + } + } + protected void readReturnsString(final StringTokenizer tok, final String filename, final int lineNo) { try { final String name = tok.nextToken(); diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java index 5264531..0e2efbb 100644 --- a/src/java/com/jogamp/gluegen/JavaEmitter.java +++ b/src/java/com/jogamp/gluegen/JavaEmitter.java @@ -484,14 +484,13 @@ public class JavaEmitter implements GlueEmitter { @Override public Iterator emitFunctions(final List funcsToBind) throws Exception { // Bind all the C funcs to Java methods - final HashSet methodBindingSet = new HashSet(); final ArrayList methodBindingEmitters = new ArrayList(2*funcsToBind.size()); { int i=0; for (final FunctionSymbol cFunc : funcsToBind) { // Check to see whether this function should be ignored if ( !cfg.shouldIgnoreInImpl(cFunc) ) { - methodBindingEmitters.addAll(generateMethodBindingEmitters(methodBindingSet, cFunc)); + methodBindingEmitters.addAll(generateMethodBindingEmitters(cFunc)); LOG.log(INFO, cFunc.getASTLocusTag(), "Non-Ignored Impl[{0}]: {1}", i++, cFunc); } @@ -560,7 +559,8 @@ public class JavaEmitter implements GlueEmitter { * native code because it doesn't need any processing of the * outgoing arguments). */ - protected void generatePublicEmitters(final MethodBinding binding, final List allEmitters, final boolean signatureOnly) { + protected void generatePublicEmitters(final MethodBinding binding, final List allEmitters, + final boolean signatureOnly) { final FunctionSymbol cSymbol = binding.getCSymbol(); if ( !signatureOnly && cfg.manuallyImplement(cSymbol) ) { // We only generate signatures for manually-implemented methods; @@ -568,6 +568,20 @@ public class JavaEmitter implements GlueEmitter { return; } + final MethodAccess accessControl; + + if ( !signatureOnly && null != binding.getDelegationImplName() ) { + // private access for delegation implementation methods + accessControl = PRIVATE; + } else { + accessControl = cfg.accessControl(binding.getName()); + } + + // We should not emit anything except public APIs into interfaces + if ( signatureOnly && PUBLIC != accessControl ) { + return; + } + // It's possible we may not need a body even if signatureOnly is // set to false; for example, if the routine doesn't take any // arrays or buffers as arguments @@ -590,20 +604,6 @@ public class JavaEmitter implements GlueEmitter { final boolean emitBody = !signatureOnly && needsBody; final boolean isNativeMethod = !isUnimplemented && !needsBody && !signatureOnly; - final MethodAccess accessControl; - - if ( !signatureOnly && null != binding.getDelegationImplName() ) { - // private access for delegation implementation methods - accessControl = PRIVATE; - } else { - accessControl = cfg.accessControl(binding.getName()); - } - - // We should not emit anything except public APIs into interfaces - if ( signatureOnly && PUBLIC != accessControl ) { - return; - } - final PrintWriter writer = ((signatureOnly || cfg.allStatic()) ? javaWriter() : javaImplWriter()); final JavaMethodBindingEmitter emitter = @@ -769,18 +769,34 @@ public class JavaEmitter implements GlueEmitter { * Generate all appropriate Java bindings for the specified C function * symbols. */ - protected List generateMethodBindingEmitters(final Set methodBindingSet, final FunctionSymbol sym) throws Exception { - + protected List generateMethodBindingEmitters(final FunctionSymbol sym) throws Exception { final ArrayList allEmitters = new ArrayList(); - try { + if( cfg.emitInterface() ) { + generateMethodBindingEmittersImpl(allEmitters, sym, true); + } + if( cfg.emitImpl() ) { + generateMethodBindingEmittersImpl(allEmitters, sym, false); + } + } catch (final Exception e) { + throw new GlueGenException("Error while generating bindings for \"" + sym + "\"", sym.getASTLocusTag(), e); + } + + return allEmitters; + } + private void generateMethodBindingEmittersImpl(final ArrayList allEmitters, + final FunctionSymbol sym, + final boolean forInterface) throws Exception + { // Get Java binding for the function - final MethodBinding mb = bindFunction(sym, machDescJava, null, null); + final MethodBinding mb = bindFunction(sym, forInterface, machDescJava, null, null); // JavaTypes representing C pointers in the initial // MethodBinding have not been lowered yet to concrete types final List bindings = expandMethodBinding(mb); + final HashSet methodBindingSet = new HashSet(); + for (final MethodBinding binding : bindings) { if(!methodBindingSet.add(binding)) { @@ -841,21 +857,15 @@ public class JavaEmitter implements GlueEmitter { // Note in particular that the public entry point taking an // array is merely a special case of the indirect buffer case. - if (cfg.emitInterface()) { + if ( forInterface ) { generatePublicEmitters(binding, allEmitters, true); - } - if (cfg.emitImpl()) { + } else { generatePublicEmitters(binding, allEmitters, false); generatePrivateEmitters(binding, allEmitters); } } // end iteration over expanded bindings - } catch (final Exception e) { - throw new GlueGenException("Error while generating bindings for \"" + sym + "\"", sym.getASTLocusTag(), e); } - return allEmitters; - } - @Override public void endFunctions() throws Exception { @@ -1416,7 +1426,7 @@ public class JavaEmitter implements GlueEmitter { final Type containingCType, final JavaType containingJType, final int i, final FunctionSymbol funcSym, final String returnSizeLookupName) { // Emit method call and associated native code - final MethodBinding mb = bindFunction(funcSym, machDescJava, containingJType, containingCType); + final MethodBinding mb = bindFunction(funcSym, true /* forInterface */, machDescJava, containingJType, containingCType); mb.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis // JavaTypes representing C pointers in the initial @@ -1498,7 +1508,7 @@ public class JavaEmitter implements GlueEmitter { final int i, final FunctionSymbol funcSym, final String returnSizeLookupName, final String docArrayLenExpr, final String nativeArrayLenExpr) { // Emit method call and associated native code - final MethodBinding mb = bindFunction(funcSym, machDescJava, containingJType, containingCType); + final MethodBinding mb = bindFunction(funcSym, true /* forInterface */, machDescJava, containingJType, containingCType); mb.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis // JavaTypes representing C pointers in the initial @@ -2744,12 +2754,19 @@ public class JavaEmitter implements GlueEmitter { potentially representing C pointers rather than true Java types) and must be lowered to concrete Java types before creating emitters for them. */ - private MethodBinding bindFunction(final FunctionSymbol sym, + private MethodBinding bindFunction(FunctionSymbol sym, + final boolean forInterface, final MachineDataInfo curMachDesc, - final JavaType containingType, - final Type containingCType) { + final JavaType containingType, final Type containingCType) { - // System.out.println("bindFunction(0) "+sym.getReturnType()); + final String delegationImplName = null == containingType && null == containingCType ? + cfg.getDelegatedImplementation(sym) : null; + if( !forInterface && null != delegationImplName ) { + // We need to reflect the 'delegationImplName' for implementations + // to allow all subsequent type/cfg checks to hit on AliasedSymbol! + sym = FunctionSymbol.cloneWithDeepAliases(sym); + sym.addAliasedName(delegationImplName); + } final String name = sym.getName(); final JavaType javaReturnType; @@ -2765,7 +2782,12 @@ public class JavaEmitter implements GlueEmitter { } javaReturnType = javaType(java.lang.String.class); } else { - javaReturnType = typeToJavaType(sym.getReturnType(), curMachDesc); + final JavaType r = cfg.getOpaqueReturnType(sym); + if( null != r ) { + javaReturnType = r; + } else { + javaReturnType = typeToJavaType(sym.getReturnType(), curMachDesc); + } } // List of the indices of the arguments in this function that should be @@ -2809,8 +2831,6 @@ public class JavaEmitter implements GlueEmitter { javaArgumentTypes.add(mappedType); //System.out.println("During binding of [" + sym + "], added mapping from C type: " + cArgType + " to Java type: " + mappedType); } - final String delegationImplName = null == containingType && null == containingCType ? - cfg.getDelegatedImplementation(sym) : null; final MethodBinding mb = new MethodBinding(sym, delegationImplName, javaReturnType, javaArgumentTypes, containingType, containingCType); diff --git a/src/java/com/jogamp/gluegen/MethodBinding.java b/src/java/com/jogamp/gluegen/MethodBinding.java index 278fea0..95a10c6 100644 --- a/src/java/com/jogamp/gluegen/MethodBinding.java +++ b/src/java/com/jogamp/gluegen/MethodBinding.java @@ -203,7 +203,7 @@ public class MethodBinding { /** * Returns the {@link FunctionSymbol}'s name for the native function * which is the {@link FunctionSymbol#getOrigName() original} C API name per default, - * but may be overriden via {@link #setNativeName(String)}. + * but may be overridden via {@link #setNativeName(String)}. */ public String getNativeName() { return null != nativeName ? nativeName : sym.getOrigName(); diff --git a/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java b/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java index 73c65ef..869c658 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java +++ b/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java @@ -110,7 +110,7 @@ public interface AliasedSymbol { public AliasedSymbolImpl(final AliasedSymbolImpl o) { this.origName = o.origName; this.aliasedNames = new HashSet(o.aliasedNames); - this.name = o.origName; + this.name = o.name; } @Override public void rename(final String newName) { diff --git a/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java b/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java index 55585fc..91a0a5a 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java +++ b/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java @@ -76,6 +76,17 @@ public class FunctionSymbol extends AliasedSymbolImpl implements AliasedSemantic this.astLocus = locus; } + /** Shallow'ish copy, only aliased names are re-created. */ + public static FunctionSymbol cloneWithDeepAliases(final FunctionSymbol o) { + return new FunctionSymbol(o); + } + /** Warning: Shallow'ish copy, only aliased names are re-created. */ + private FunctionSymbol(final FunctionSymbol o) { + super(o); + this.type = o.type; + this.astLocus = o.astLocus; + } + @Override public ASTLocusTag getASTLocusTag() { return astLocus; } diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java index 423efe9..ec29b08 100644 --- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java +++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java @@ -55,7 +55,6 @@ import com.jogamp.gluegen.FunctionEmitter; import com.jogamp.gluegen.JavaConfiguration; import com.jogamp.gluegen.JavaEmitter; import com.jogamp.gluegen.JavaMethodBindingEmitter; -import com.jogamp.gluegen.MethodBinding; import com.jogamp.gluegen.cgram.types.FunctionSymbol; import com.jogamp.gluegen.cgram.types.Type; import com.jogamp.gluegen.cgram.types.TypeDictionary; @@ -115,8 +114,8 @@ public class ProcAddressEmitter extends JavaEmitter { } @Override - protected List generateMethodBindingEmitters(final Set methodBindingSet, final FunctionSymbol sym) throws Exception { - return generateMethodBindingEmittersImpl(methodBindingSet, sym); + protected List generateMethodBindingEmitters(final FunctionSymbol sym) throws Exception { + return generateMethodBindingEmittersImpl(sym); } protected boolean needsModifiedEmitters(final FunctionSymbol sym) { @@ -127,8 +126,8 @@ public class ProcAddressEmitter extends JavaEmitter { } } - private List generateMethodBindingEmittersImpl(final Set methodBindingSet, final FunctionSymbol sym) throws Exception { - final List defaultEmitters = super.generateMethodBindingEmitters(methodBindingSet, sym); + private List generateMethodBindingEmittersImpl(final FunctionSymbol sym) throws Exception { + final List defaultEmitters = super.generateMethodBindingEmitters(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 @@ -153,7 +152,7 @@ public class ProcAddressEmitter extends JavaEmitter { if ( callThroughProcAddress ) { if (getProcAddressConfig().emitProcAddressTable()) { // emit an entry in the GL proc address table for this method. - emitProcAddressTableEntryForString(getAliasedSymName(sym)); + emitProcAddressTableEntryForString(sym.getName()); } } for (final FunctionEmitter emitter : defaultEmitters) { @@ -267,14 +266,6 @@ public class ProcAddressEmitter extends JavaEmitter { emitters.add(res); } - private String getAliasedSymName(final FunctionSymbol sym) { - String symName = getConfig().getJavaSymbolRename(sym.getName()); - if (null == symName) { - symName = sym.getName(); - } - return symName; - } - protected boolean callThroughProcAddress(final FunctionSymbol sym) { final ProcAddressConfiguration cfg = getProcAddressConfig(); boolean res = false; diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java index 3faf155..5298a8d 100644 --- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java +++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java @@ -120,7 +120,7 @@ public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitte super.emitPreCallSetup(binding, writer); if (callThroughProcAddress) { - final String procAddressVariable = ProcAddressEmitter.PROCADDRESS_VAR_PREFIX + binding.getName(); + final String procAddressVariable = ProcAddressEmitter.PROCADDRESS_VAR_PREFIX + binding.getNativeName(); writer.println(" final long __addr_ = " + getProcAddressTableExpr + "." + procAddressVariable + ";"); writer.println(" if (__addr_ == 0) {"); writer.format(" throw new %s(String.format(\"Method \\\"%%s\\\" not available\", \"%s\"));%n", -- cgit v1.2.3