diff options
21 files changed, 1147 insertions, 652 deletions
diff --git a/make/cglext.cfg b/make/cglext.cfg index 74e7ac841..0d1ae1dcc 100755 --- a/make/cglext.cfg +++ b/make/cglext.cfg @@ -12,7 +12,7 @@ Include gl-common-macosx.cfg EmitProcAddressTable true ProcAddressTableClassName CGLExtProcAddressTable -ContextVariableName _context +GetProcAddressTableExpr _context.getCGLExtProcAddressTable() # Ignore everything that doesn't start with cgl or CGL IgnoreNot ^(cgl|CGL).+ diff --git a/make/gl-macosx.cfg b/make/gl-macosx.cfg index 156f66b77..106b90471 100644 --- a/make/gl-macosx.cfg +++ b/make/gl-macosx.cfg @@ -8,7 +8,7 @@ Include gl-common-macosx.cfg EmitProcAddressTable true ProcAddressTableClassName GLProcAddressTable -ContextVariableName _context +GetProcAddressTableExpr _context.getGLProcAddressTable() CustomCCode #include <inttypes.h> CustomCCode #include <stdlib.h> diff --git a/make/gl-win32.cfg b/make/gl-win32.cfg index 950d67320..978b624c1 100644 --- a/make/gl-win32.cfg +++ b/make/gl-win32.cfg @@ -8,7 +8,7 @@ Include gl-common-win32.cfg EmitProcAddressTable true ProcAddressTableClassName GLProcAddressTable -ContextVariableName _context +GetProcAddressTableExpr _context.getGLProcAddressTable() CustomCCode #define WIN32_LEAN_AND_MEAN CustomCCode #include <windows.h> diff --git a/make/gl-x11.cfg b/make/gl-x11.cfg index fd793c5b9..f67e301cc 100644 --- a/make/gl-x11.cfg +++ b/make/gl-x11.cfg @@ -8,7 +8,7 @@ Include gl-common-x11.cfg EmitProcAddressTable true ProcAddressTableClassName GLProcAddressTable -ContextVariableName _context +GetProcAddressTableExpr _context.getGLProcAddressTable() CustomCCode #include <inttypes.h> CustomCCode #include <stdlib.h> diff --git a/make/glu-CustomJavaCode.java b/make/glu-CustomJavaCode.java index e5fac91e6..56a3fc0c4 100644 --- a/make/glu-CustomJavaCode.java +++ b/make/glu-CustomJavaCode.java @@ -1436,7 +1436,7 @@ private static GLUProcAddressTable gluProcAddressTable; private static GLUProcAddressTable getGLUProcAddressTable() { if (gluProcAddressTable == null) { GLUProcAddressTable tmp = new GLUProcAddressTable(); - GLDrawableFactoryImpl.getFactoryImpl().resetProcAddressTable(tmp); + ProcAddressHelper.resetProcAddressTable(tmp, GLDrawableFactoryImpl.getFactoryImpl()); gluProcAddressTable = tmp; } return gluProcAddressTable; diff --git a/make/glxext.cfg b/make/glxext.cfg index b3186a254..88e6ba63d 100755 --- a/make/glxext.cfg +++ b/make/glxext.cfg @@ -9,7 +9,7 @@ Include gl-common-x11.cfg EmitProcAddressTable true ProcAddressTableClassName GLXExtProcAddressTable -ContextVariableName _context +GetProcAddressTableExpr _context.getGLXExtProcAddressTable() # Ignore everything that doesn't start with glX or GLX IgnoreNot ^(glX|GLX).+ diff --git a/make/wglext.cfg b/make/wglext.cfg index bc27252a5..5c7537481 100644 --- a/make/wglext.cfg +++ b/make/wglext.cfg @@ -9,7 +9,7 @@ Include gl-common-win32.cfg EmitProcAddressTable true ProcAddressTableClassName WGLExtProcAddressTable -ContextVariableName _context +GetProcAddressTableExpr _context.getWGLExtProcAddressTable() # Ignore everything that doesn't start with wgl or WGL Ignore ^[^wW].+ diff --git a/src/classes/com/sun/gluegen/JavaConfiguration.java b/src/classes/com/sun/gluegen/JavaConfiguration.java index a48582a3f..152d9cf80 100644 --- a/src/classes/com/sun/gluegen/JavaConfiguration.java +++ b/src/classes/com/sun/gluegen/JavaConfiguration.java @@ -180,10 +180,10 @@ public class JavaConfiguration { } if (className == null && (emissionStyle() != JavaEmitter.IMPL_ONLY)) { - throw new RuntimeException("Output class name was not specified in configuration file"); + throw new RuntimeException("Output class name was not specified in configuration file \"" + filename + "\""); } if (packageName == null && (emissionStyle() != JavaEmitter.IMPL_ONLY)) { - throw new RuntimeException("Output package name was not specified in configuration file"); + throw new RuntimeException("Output package name was not specified in configuration file \"" + filename + "\""); } if (allStatic()) { @@ -735,7 +735,7 @@ public class JavaConfiguration { } else if (style.equalsIgnoreCase("PRIVATE")) { acc = JavaEmitter.ACC_PRIVATE; } else if (style.equalsIgnoreCase("PACKAGE_PRIVATE")) { - acc = JavaEmitter.ACC_PRIVATE; + acc = JavaEmitter.ACC_PACKAGE_PRIVATE; } else { throw new RuntimeException("Error parsing \"AccessControl\" command at line " + lineNo + " in file \"" + filename + "\""); diff --git a/src/classes/com/sun/gluegen/JavaEmitter.java b/src/classes/com/sun/gluegen/JavaEmitter.java index 85ba363a1..c280e1de7 100644 --- a/src/classes/com/sun/gluegen/JavaEmitter.java +++ b/src/classes/com/sun/gluegen/JavaEmitter.java @@ -339,6 +339,12 @@ public class JavaEmitter implements GlueEmitter { return; } + int accessControl = cfg.accessControl(binding.getName()); + // We should not emit anything except public APIs into interfaces + if (signatureOnly && (accessControl != ACC_PUBLIC)) { + 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 @@ -363,7 +369,7 @@ public class JavaEmitter implements GlueEmitter { false, false, isUnimplemented); - switch (cfg.accessControl(binding.getName())) { + switch (accessControl) { case ACC_PUBLIC: emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); break; case ACC_PROTECTED: emitter.addModifier(JavaMethodBindingEmitter.PROTECTED); break; case ACC_PRIVATE: emitter.addModifier(JavaMethodBindingEmitter.PRIVATE); break; diff --git a/src/classes/com/sun/gluegen/JavaMethodBindingEmitter.java b/src/classes/com/sun/gluegen/JavaMethodBindingEmitter.java index 64d349ca9..031a994e0 100644 --- a/src/classes/com/sun/gluegen/JavaMethodBindingEmitter.java +++ b/src/classes/com/sun/gluegen/JavaMethodBindingEmitter.java @@ -349,7 +349,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter emitPreCallSetup(binding, writer); //emitReturnVariableSetup(binding, writer); emitReturnVariableSetupAndCall(binding, writer, machDesc); - emitPrologueOrEpilogue(epilogue, writer); } writer.println(" }"); } @@ -449,6 +448,10 @@ public class JavaMethodBindingEmitter extends FunctionEmitter } else if (returnType.isArrayOfCompoundTypeWrappers()) { writer.println("ByteBuffer[] _res;"); needsResultAssignment = true; + } else if ((epilogue != null) && (epilogue.size() > 0)) { + emitReturnType(writer); + writer.println(" _res;"); + needsResultAssignment = true; } } @@ -502,6 +505,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter } else { writer.println(); } + emitPrologueOrEpilogue(epilogue, writer); if (needsResultAssignment) { emitCallResultReturn(binding, writer, machDesc); } @@ -638,6 +642,10 @@ public class JavaMethodBindingEmitter extends FunctionEmitter writer.println(" _retarray[_count] = " + getReturnTypeString(true) + ".create(_res[_count]);"); writer.println(" }"); writer.println(" return _retarray;"); + } else { + // Assume it's a primitive type or other type we don't have to + // do any conversion on + writer.println(" return _res;"); } } diff --git a/src/classes/com/sun/gluegen/opengl/GLConfiguration.java b/src/classes/com/sun/gluegen/opengl/GLConfiguration.java new file mode 100755 index 000000000..a44f3fe9f --- /dev/null +++ b/src/classes/com/sun/gluegen/opengl/GLConfiguration.java @@ -0,0 +1,198 @@ +/* + * 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.sun.gluegen.opengl; + +import java.io.*; +import java.util.*; + +import com.sun.gluegen.*; +import com.sun.gluegen.procaddress.*; + +public class GLConfiguration extends ProcAddressConfiguration { + // The following data members support ignoring an entire extension at a time + private List/*<String>*/ glHeaders = new ArrayList(); + private Set/*<String>*/ ignoredExtensions = new HashSet(); + private BuildStaticGLInfo glInfo; + // Maps function names to the kind of buffer object it deals with + private Map/*<String,GLEmitter.BufferObjectKind>*/ bufferObjectKinds = new HashMap(); + private GLEmitter emitter; + + public GLConfiguration(GLEmitter emitter) { + super(); + this.emitter = emitter; + try { + setProcAddressNameExpr("PFN $UPPERCASE({0}) PROC"); + } catch (NoSuchElementException e) { + throw new RuntimeException("Error configuring ProcAddressNameExpr", e); + } + } + + protected void dispatch(String cmd, StringTokenizer tok, File file, String filename, int lineNo) throws IOException { + if (cmd.equalsIgnoreCase("IgnoreExtension")) + { + String sym = readString("IgnoreExtension", tok, filename, lineNo); + ignoredExtensions.add(sym); + } + else if (cmd.equalsIgnoreCase("GLHeader")) + { + String sym = readString("GLHeader", tok, filename, lineNo); + glHeaders.add(sym); + } + else if (cmd.equalsIgnoreCase("BufferObjectKind")) + { + readBufferObjectKind(tok, filename, lineNo); + } + else + { + super.dispatch(cmd,tok,file,filename,lineNo); + } + } + + protected void readBufferObjectKind(StringTokenizer tok, String filename, int lineNo) { + try { + String kindString = tok.nextToken(); + GLEmitter.BufferObjectKind kind = null; + String target = tok.nextToken(); + if (kindString.equalsIgnoreCase("UnpackPixel")) { + kind = GLEmitter.BufferObjectKind.UNPACK_PIXEL; + } else if (kindString.equalsIgnoreCase("PackPixel")) { + kind = GLEmitter.BufferObjectKind.PACK_PIXEL; + } else if (kindString.equalsIgnoreCase("Array")) { + kind = GLEmitter.BufferObjectKind.ARRAY; + } else if (kindString.equalsIgnoreCase("Element")) { + kind = GLEmitter.BufferObjectKind.ELEMENT; + } else { + throw new RuntimeException("Error parsing \"BufferObjectKind\" command at line " + lineNo + + " in file \"" + filename + "\": illegal BufferObjectKind \"" + + kindString + "\", expected one of UnpackPixel, PackPixel, Array, or Element"); + } + + bufferObjectKinds.put(target, kind); + } catch (NoSuchElementException e) { + throw new RuntimeException("Error parsing \"BufferObjectKind\" command at line " + lineNo + + " in file \"" + filename + "\"", e); + } + } + + /** Overrides javaPrologueForMethod in superclass and + automatically generates prologue code for functions associated + with buffer objects. */ + public List/*<String>*/ javaPrologueForMethod(MethodBinding binding, + boolean forImplementingMethodCall, + boolean eraseBufferAndArrayTypes) { + List/*<String>*/ res = super.javaPrologueForMethod(binding, + forImplementingMethodCall, + eraseBufferAndArrayTypes); + GLEmitter.BufferObjectKind kind = getBufferObjectKind(binding.getName()); + if (kind != null) { + // Need to generate appropriate prologue based on both buffer + // object kind and whether this variant of the MethodBinding + // is the one accepting a "long" as argument + if (res == null) { + res = new ArrayList(); + } + + String prologue = "check"; + + if (kind == GLEmitter.BufferObjectKind.UNPACK_PIXEL) { + prologue = prologue + "UnpackPBO"; + } else if (kind == GLEmitter.BufferObjectKind.PACK_PIXEL) { + prologue = prologue + "PackPBO"; + } else if (kind == GLEmitter.BufferObjectKind.ARRAY) { + prologue = prologue + "ArrayVBO"; + } else if (kind == GLEmitter.BufferObjectKind.ELEMENT) { + prologue = prologue + "ElementVBO"; + } else { + throw new RuntimeException("Unknown BufferObjectKind " + kind); + } + + if (emitter.isBufferObjectMethodBinding(binding)) { + prologue = prologue + "Enabled"; + } else { + prologue = prologue + "Disabled"; + } + + prologue = prologue + "();"; + + res.add(0, prologue); + } + + return res; + } + + public boolean shouldIgnore(String symbol) { + // Check ignored extensions based on our knowledge of the static GL info + if (glInfo != null) { + String extension = glInfo.getExtension(symbol); + if (extension != null && + ignoredExtensions.contains(extension)) { + return true; + } + } + + return super.shouldIgnore(symbol); + } + + /** Returns the kind of buffer object this function deals with, or + null if none. */ + public GLEmitter.BufferObjectKind getBufferObjectKind(String name) { + return (GLEmitter.BufferObjectKind) bufferObjectKinds.get(name); + } + + public boolean isBufferObjectFunction(String name) { + return (getBufferObjectKind(name) != null); + } + + /** Parses any GL headers specified in the configuration file for + the purpose of being able to ignore an extension at a time. */ + public void parseGLHeaders(GlueEmitterControls controls) throws IOException { + if (!glHeaders.isEmpty()) { + glInfo = new BuildStaticGLInfo(); + for (Iterator iter = glHeaders.iterator(); iter.hasNext(); ) { + String file = (String) iter.next(); + String fullPath = controls.findHeaderFile(file); + if (fullPath == null) { + throw new IOException("Unable to locate header file \"" + file + "\""); + } + glInfo.parse(fullPath); + } + } + } +} diff --git a/src/classes/com/sun/gluegen/opengl/GLEmitter.java b/src/classes/com/sun/gluegen/opengl/GLEmitter.java index 4ba1df87b..8e7484a73 100644 --- a/src/classes/com/sun/gluegen/opengl/GLEmitter.java +++ b/src/classes/com/sun/gluegen/opengl/GLEmitter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * 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 @@ -44,22 +44,15 @@ import java.text.MessageFormat; import java.util.*; import com.sun.gluegen.*; import com.sun.gluegen.cgram.types.*; +import com.sun.gluegen.procaddress.*; import com.sun.gluegen.runtime.*; /** - * A subclass of JavaEmitter that modifies the normal emission of C and Java - * code in order to allow a high-performance, cross-platform binding of Java - * to OpenGL. + * A subclass of ProcAddressEmitter with special OpenGL-specific + * configuration abilities. */ -public class GLEmitter extends JavaEmitter +public class GLEmitter extends ProcAddressEmitter { - public static final String PROCADDRESS_VAR_PREFIX = ProcAddressHelper.PROCADDRESS_VAR_PREFIX; - protected static final String WRAP_PREFIX = "dispatch_"; - private TypeDictionary typedefDictionary; - private PrintWriter tableWriter; - private String tableClassPackage; - private String tableClassName; - private int numProcAddressEntries; // Keeps track of which MethodBindings were created for handling // Buffer Object variants. Used as a Set rather than a Map. private Map/*<MethodBinding>*/ bufferObjectMethodBindings = new IdentityHashMap(); @@ -79,36 +72,8 @@ public class GLEmitter extends JavaEmitter super.beginEmission(controls); } - public void beginFunctions(TypeDictionary typedefDictionary, - TypeDictionary structDictionary, - Map canonMap) throws Exception - { - this.typedefDictionary = typedefDictionary; - - if (getGLConfig().emitProcAddressTable()) - { - beginGLProcAddressTable(); - } - super.beginFunctions(typedefDictionary, structDictionary, canonMap); - } - - public void endFunctions() throws Exception - { - if (getGLConfig().emitProcAddressTable()) - { - endGLProcAddressTable(); - } - super.endFunctions(); - } - - public void beginStructs(TypeDictionary typedefDictionary, - TypeDictionary structDictionary, - Map canonMap) throws Exception { - super.beginStructs(typedefDictionary, structDictionary, canonMap); - } - protected JavaConfiguration createConfig() { - return new GLConfiguration(); + return new GLConfiguration(this); } /** In order to implement Buffer Object variants of certain @@ -166,76 +131,17 @@ public class GLEmitter extends JavaEmitter return newBindings; } - protected List generateMethodBindingEmitters(FunctionSymbol sym) throws Exception - { - return generateMethodBindingEmittersImpl(sym); - } - - private List generateMethodBindingEmittersImpl(FunctionSymbol sym) throws Exception - { - 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 - // direction that matched the symbol's name). - if (defaultEmitters.isEmpty()) - { - return defaultEmitters; - } - - // Don't do anything special if this symbol doesn't require - // OpenGL-related modifications + protected boolean needsModifiedEmitters(FunctionSymbol sym) { if ((!needsProcAddressWrapper(sym) && !needsBufferObjectVariant(sym)) || - getConfig().isUnimplemented(sym.getName())) - { - return defaultEmitters; + getConfig().isUnimplemented(sym.getName())) { + return false; } - ArrayList modifiedEmitters = new ArrayList(defaultEmitters.size()); - - if (needsProcAddressWrapper(sym)) { - if (getGLConfig().emitProcAddressTable()) { - // emit an entry in the GL proc address table for this method. - emitGLProcAddressTableEntryForSymbol(sym); - } - } - - for (Iterator iter = defaultEmitters.iterator(); iter.hasNext(); ) - { - FunctionEmitter emitter = (FunctionEmitter) iter.next(); - 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; + return true; } - /** - * Returns the name of the typedef for a pointer to the GL function - * represented by the argument. For example, 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. - */ - static String getGLFunctionPointerTypedefName(FunctionSymbol sym) - { - String symName = sym.getName(); - StringBuffer buf = new StringBuffer(symName.length() + 8); - buf.append("PFN"); - buf.append(symName.toUpperCase()); - buf.append("PROC"); - return buf.toString(); + public boolean isBufferObjectMethodBinding(MethodBinding binding) { + return bufferObjectMethodBindings.containsKey(binding); } //---------------------------------------------------------------------- @@ -243,405 +149,31 @@ public class GLEmitter extends JavaEmitter // protected void generateModifiedEmitters(JavaMethodBindingEmitter baseJavaEmitter, List emitters) { - if (getGLConfig().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()); + List superEmitters = new ArrayList(); + super.generateModifiedEmitters(baseJavaEmitter, superEmitters); + // See whether this is one of the Buffer Object variants boolean bufferObjectVariant = bufferObjectMethodBindings.containsKey(baseJavaEmitter.getBinding()); - GLJavaMethodBindingEmitter emitter = - new GLJavaMethodBindingEmitter(baseJavaEmitter, - callThroughProcAddress, - getGLConfig().getProcAddressTableExpr(), - baseJavaEmitter.isForImplementingMethodCall(), - bufferObjectVariant); - emitters.add(emitter); - - // If this emitter doesn't have a body (i.e., is a public native - // call), we need to force it to emit a body, and produce another - // one to act as the entry point - if (baseJavaEmitter.signatureOnly() && - baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.PUBLIC) && - baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.NATIVE) && - callThroughProcAddress) { - emitter.setEmitBody(true); - emitter.removeModifier(JavaMethodBindingEmitter.NATIVE); - emitter = new GLJavaMethodBindingEmitter(baseJavaEmitter, - callThroughProcAddress, - getGLConfig().getProcAddressTableExpr(), - true, - bufferObjectVariant); - emitter.setForImplementingMethodCall(true); - emitters.add(emitter); - } - } - - protected void generateModifiedEmitters(CMethodBindingEmitter baseCEmitter, List emitters) - { - // See whether we need a proc address entry for this one - boolean callThroughProcAddress = needsProcAddressWrapper(baseCEmitter.getBinding().getCSymbol()); - // 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 - GLCMethodBindingEmitter res = new GLCMethodBindingEmitter(baseCEmitter, callThroughProcAddress); - MessageFormat exp = baseCEmitter.getReturnValueCapacityExpression(); - if (exp != null) { - res.setReturnValueCapacityExpression(exp); - } - emitters.add(res); - } - - protected boolean needsProcAddressWrapper(FunctionSymbol sym) - { - String symName = sym.getName(); - - GLConfiguration config = getGLConfig(); - - // We should only wrap the GL symbol if its function pointer typedef has - // been defined (most likely in glext.h). - String funcPointerTypedefName = getGLFunctionPointerTypedefName(sym); - boolean shouldWrap = typedefDictionary.containsKey(funcPointerTypedefName); - //System.err.println(funcPointerTypedefName + " defined: " + shouldWrap); - - if (config.skipProcAddressGen(symName)) { - shouldWrap = false; - } - - if (!shouldWrap) - { - //System.err.println("WARNING (GL): *not* run-time linking: " + sym + - // "(" + funcPointerTypedefName + " undefined)"); - } - else - { - FunctionType typedef = typedefDictionary.get(funcPointerTypedefName).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)); + if (bufferObjectVariant) { + for (Iterator iter = superEmitters.iterator(); iter.hasNext(); ) { + JavaMethodBindingEmitter emitter = (JavaMethodBindingEmitter) iter.next(); + if (emitter instanceof ProcAddressJavaMethodBindingEmitter) { + emitters.add(new GLJavaMethodBindingEmitter((ProcAddressJavaMethodBindingEmitter) emitter, bufferObjectVariant)); + } else { + emitters.add(emitter); + } } + } else { + emitters.addAll(superEmitters); } - - return shouldWrap; } protected boolean needsBufferObjectVariant(FunctionSymbol sym) { return getGLConfig().isBufferObjectFunction(sym.getName()); } - private void beginGLProcAddressTable() throws Exception - { - tableClassPackage = getGLConfig().tableClassPackage(); - tableClassName = getGLConfig().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"); - - CodeGenUtils.emitAutogeneratedWarning(tableWriter, this); - - tableWriter.println("package " + implPackageName + ";"); - tableWriter.println(); - for (Iterator iter = getConfig().imports().iterator(); iter.hasNext(); ) { - tableWriter.println("import " + ((String) iter.next()) + ";"); - } - tableWriter.println(); - tableWriter.println("/**"); - tableWriter.println(" * This table is a cache of the native pointers to OpenGL extension"); - tableWriter.println(" * functions, to be used for run-time linking of these extensions. "); - tableWriter.println(" * These pointers are obtained by the OpenGL context via a "); - tableWriter.println(" * platform-specific function (e.g., wglGetProcAddress() on Win32,"); - tableWriter.println(" * glXGetProcAddress() on X11, etc). If the member variable "); - tableWriter.println(" * " + PROCADDRESS_VAR_PREFIX + "glFuncName is non-zero then function"); - tableWriter.println(" * \"glFuncName\" can be called through the associated GLContext; "); - tableWriter.println(" * if it is 0, then the extension is not available and cannot be called."); - tableWriter.println(" */"); - tableWriter.println("public class " + tableClassName); - tableWriter.println("{"); - numProcAddressEntries = 0; - - for (Iterator iter = getGLConfig().getForceProcAddressGen().iterator(); iter.hasNext(); ) { - emitGLProcAddressTableEntryForString((String) iter.next()); - } - } - - private void endGLProcAddressTable() throws Exception - { - PrintWriter w = tableWriter; - - w.println(); - w.println(" /**"); - w.println(" * This is a convenience method to get (by name) the native function "); - w.println(" * pointer for a given extension function. It lets you avoid "); - w.println(" * having to manually compute the " + PROCADDRESS_VAR_PREFIX + "<glFunctionName>"); - w.println(" * member variable name and look it up via reflection; it also"); - w.println(" * will throw an exception if you try to get the address of an"); - w.println(" * unknown GL extension, or one that is statically linked "); - w.println(" * and therefore does not have a valid GL procedure address. "); - w.println(" */"); - w.println(" public long getAddressFor(String glFunctionName) {"); - w.println(" String addressFieldName = com.sun.gluegen.opengl.GLEmitter.PROCADDRESS_VAR_PREFIX + glFunctionName;"); - w.println(" try { "); - w.println(" java.lang.reflect.Field addressField = this.getClass().getField(addressFieldName);"); - w.println(" return addressField.getLong(this);"); - w.println(" } catch (Exception e) {"); - w.println(" // The user is calling a bogus function or one which is not runtime"); - w.println(" // linked (extensions and core post-OpenGL 1.1 functions are runtime linked)"); - w.println(" if (!FunctionAvailabilityCache.isPartOfGLCore(\"1.1\", glFunctionName)) "); - w.println(" {"); - w.println(" throw new RuntimeException(" ); - w.println(" \"WARNING: Address query failed for \\\"\" + glFunctionName +"); - w.println(" \"\\\"; either it's not runtime linked or it is not a known \" +"); - w.println(" \"OpenGL function\", e);"); - w.println(" }"); - w.println(" } "); - w.println(" assert(false); // should never get this far"); - w.println(" return 0;"); - w.println(" }"); - - w.println("} // end of class " + tableClassName); - w.flush(); - w.close(); - } - - protected void emitGLProcAddressTableEntryForSymbol(FunctionSymbol cFunc) - { - emitGLProcAddressTableEntryForString(cFunc.getName()); - } - - protected void emitGLProcAddressTableEntryForString(String str) - { - tableWriter.print(" public long "); - tableWriter.print(PROCADDRESS_VAR_PREFIX); - tableWriter.print(str); - tableWriter.println(";"); - ++numProcAddressEntries; - } - protected GLConfiguration getGLConfig() { return (GLConfiguration) getConfig(); } - - protected class GLConfiguration extends JavaConfiguration - { - private boolean emitProcAddressTable = false; - private String tableClassPackage; - private String tableClassName = "ProcAddressTable"; - private Set/*<String>*/ skipProcAddressGen = new HashSet(); - private List/*<String>*/ forceProcAddressGen = new ArrayList(); - private String contextVariableName = "context"; - private String getProcAddressTableExpr; - // The following data members support ignoring an entire extension at a time - private List/*<String>*/ glHeaders = new ArrayList(); - private Set/*<String>*/ ignoredExtensions = new HashSet(); - private BuildStaticGLInfo glInfo; - // Maps function names to the kind of buffer object it deals with - private Map/*<String,BufferObjectKind>*/ bufferObjectKinds = new HashMap(); - - 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 sym = readString("ForceProcAddressGen", tok, filename, lineNo); - forceProcAddressGen.add(sym); - } - else if (cmd.equalsIgnoreCase("ContextVariableName")) - { - contextVariableName = readString("ContextVariableName", tok, filename, lineNo); - } - else if (cmd.equalsIgnoreCase("GetProcAddressTableExpr")) - { - getProcAddressTableExpr = readGetProcAddressTableExpr(tok, filename, lineNo); - } - else if (cmd.equalsIgnoreCase("IgnoreExtension")) - { - String sym = readString("IgnoreExtension", tok, filename, lineNo); - ignoredExtensions.add(sym); - } - else if (cmd.equalsIgnoreCase("GLHeader")) - { - String sym = readString("GLHeader", tok, filename, lineNo); - glHeaders.add(sym); - } - else if (cmd.equalsIgnoreCase("BufferObjectKind")) - { - readBufferObjectKind(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 readBufferObjectKind(StringTokenizer tok, String filename, int lineNo) { - try { - String kindString = tok.nextToken(); - BufferObjectKind kind = null; - String target = tok.nextToken(); - if (kindString.equalsIgnoreCase("UnpackPixel")) { - kind = BufferObjectKind.UNPACK_PIXEL; - } else if (kindString.equalsIgnoreCase("PackPixel")) { - kind = BufferObjectKind.PACK_PIXEL; - } else if (kindString.equalsIgnoreCase("Array")) { - kind = BufferObjectKind.ARRAY; - } else if (kindString.equalsIgnoreCase("Element")) { - kind = BufferObjectKind.ELEMENT; - } else { - throw new RuntimeException("Error parsing \"BufferObjectKind\" command at line " + lineNo + - " in file \"" + filename + "\": illegal BufferObjectKind \"" + - kindString + "\", expected one of UnpackPixel, PackPixel, Array, or Element"); - } - - bufferObjectKinds.put(target, kind); - } catch (NoSuchElementException e) { - throw new RuntimeException("Error parsing \"BufferObjectKind\" command at line " + lineNo + - " in file \"" + filename + "\"", e); - } - } - - 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 List getForceProcAddressGen() { return forceProcAddressGen; } - public String contextVariableName() { return contextVariableName; } - public String getProcAddressTableExpr() { - if (getProcAddressTableExpr == null) { - getProcAddressTableExpr = contextVariableName + ".get" + tableClassName + "()"; - } - return getProcAddressTableExpr; - } - - public boolean shouldIgnore(String symbol) { - // Check ignored extensions based on our knowledge of the static GL info - if (glInfo != null) { - String extension = glInfo.getExtension(symbol); - if (extension != null && - ignoredExtensions.contains(extension)) { - return true; - } - } - - return super.shouldIgnore(symbol); - } - - /** Overrides javaPrologueForMethod in superclass and - automatically generates prologue code for functions associated - with buffer objects. */ - public List/*<String>*/ javaPrologueForMethod(MethodBinding binding, - boolean forImplementingMethodCall, - boolean eraseBufferAndArrayTypes) { - List/*<String>*/ res = super.javaPrologueForMethod(binding, - forImplementingMethodCall, - eraseBufferAndArrayTypes); - BufferObjectKind kind = getBufferObjectKind(binding.getName()); - if (kind != null) { - // Need to generate appropriate prologue based on both buffer - // object kind and whether this variant of the MethodBinding - // is the one accepting a "long" as argument - if (res == null) { - res = new ArrayList(); - } - - String prologue = "check"; - - if (kind == BufferObjectKind.UNPACK_PIXEL) { - prologue = prologue + "UnpackPBO"; - } else if (kind == BufferObjectKind.PACK_PIXEL) { - prologue = prologue + "PackPBO"; - } else if (kind == BufferObjectKind.ARRAY) { - prologue = prologue + "ArrayVBO"; - } else if (kind == BufferObjectKind.ELEMENT) { - prologue = prologue + "ElementVBO"; - } else { - throw new RuntimeException("Unknown BufferObjectKind " + kind); - } - - if (bufferObjectMethodBindings.containsKey(binding)) { - prologue = prologue + "Enabled"; - } else { - prologue = prologue + "Disabled"; - } - - prologue = prologue + "();"; - - res.add(0, prologue); - } - - return res; - } - - /** Returns the kind of buffer object this function deals with, or - null if none. */ - public BufferObjectKind getBufferObjectKind(String name) { - return (BufferObjectKind) bufferObjectKinds.get(name); - } - - public boolean isBufferObjectFunction(String name) { - return (getBufferObjectKind(name) != null); - } - - /** Parses any GL headers specified in the configuration file for - the purpose of being able to ignore an extension at a time. */ - public void parseGLHeaders(GlueEmitterControls controls) throws IOException { - if (!glHeaders.isEmpty()) { - glInfo = new BuildStaticGLInfo(); - for (Iterator iter = glHeaders.iterator(); iter.hasNext(); ) { - String file = (String) iter.next(); - String fullPath = controls.findHeaderFile(file); - if (fullPath == null) { - throw new IOException("Unable to locate header file \"" + file + "\""); - } - glInfo.parse(fullPath); - } - } - } - } // end class GLConfiguration } diff --git a/src/classes/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java b/src/classes/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java index 1e72cd633..ce7f3110e 100755 --- a/src/classes/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java +++ b/src/classes/com/sun/gluegen/opengl/GLJavaMethodBindingEmitter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * 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 @@ -43,44 +43,33 @@ import java.io.*; import java.util.*; import com.sun.gluegen.*; import com.sun.gluegen.cgram.types.*; +import com.sun.gluegen.procaddress.*; -public class GLJavaMethodBindingEmitter extends JavaMethodBindingEmitter { - private final CommentEmitter commentEmitterForWrappedMethod = - new WrappedMethodCommentEmitter(); +/** A specialization of the proc address emitter which knows how to + change argument names to take into account Vertex Buffer Object / + Pixel Buffer Object variants. */ - private boolean callThroughProcAddress; - private boolean changeNameAndArguments; - private String getProcAddressTableExpr; +public class GLJavaMethodBindingEmitter extends ProcAddressJavaMethodBindingEmitter { private boolean bufferObjectVariant; public GLJavaMethodBindingEmitter(JavaMethodBindingEmitter methodToWrap, boolean callThroughProcAddress, String getProcAddressTableExpr, boolean changeNameAndArguments, - boolean bufferObjectVariant) { - super(methodToWrap); - this.callThroughProcAddress = callThroughProcAddress; - this.getProcAddressTableExpr = getProcAddressTableExpr; - this.changeNameAndArguments = changeNameAndArguments; + boolean bufferObjectVariant, + GLEmitter emitter) { + super(methodToWrap, + callThroughProcAddress, + getProcAddressTableExpr, + changeNameAndArguments, + emitter); this.bufferObjectVariant = bufferObjectVariant; - if (callThroughProcAddress) { - setCommentEmitter(new WrappedMethodCommentEmitter()); - } - - if (methodToWrap.getBinding().hasContainingType()) - { - throw new IllegalArgumentException( - "Cannot create OpenGL proc. address wrapper; method has containing type: \"" + - methodToWrap.getBinding() + "\""); - } } - public String getName() { - String res = super.getName(); - if (changeNameAndArguments) { - return GLEmitter.WRAP_PREFIX + res; - } - return res; + public GLJavaMethodBindingEmitter(ProcAddressJavaMethodBindingEmitter methodToWrap, + boolean bufferObjectVariant) { + super(methodToWrap); + this.bufferObjectVariant = bufferObjectVariant; } protected String getArgumentName(int i) { @@ -103,61 +92,4 @@ public class GLJavaMethodBindingEmitter extends JavaMethodBindingEmitter { return name; } - - protected int emitArguments(PrintWriter writer) { - int numEmitted = super.emitArguments(writer); - if (callThroughProcAddress) { - if (changeNameAndArguments) { - if (numEmitted > 0) { - writer.print(", "); - } - - writer.print("long glProcAddress"); - ++numEmitted; - } - } - - return numEmitted; - } - - protected String getImplMethodName(boolean direct) { - String name = super.getImplMethodName(direct); - if (callThroughProcAddress) { - return GLEmitter.WRAP_PREFIX + name; - } - return name; - } - - protected void emitPreCallSetup(MethodBinding binding, PrintWriter writer) { - super.emitPreCallSetup(binding, writer); - - if (callThroughProcAddress) { - String procAddressVariable = - GLEmitter.PROCADDRESS_VAR_PREFIX + binding.getName(); - writer.println(" final long __addr_ = " + getProcAddressTableExpr + "." + procAddressVariable + ";"); - writer.println(" if (__addr_ == 0) {"); - writer.println(" throw new GLException(\"Method \\\"" + binding.getName() + "\\\" not available\");"); - writer.println(" }"); - } - } - - protected int emitCallArguments(MethodBinding binding, PrintWriter writer, boolean indirect) { - int numEmitted = super.emitCallArguments(binding, writer, indirect); - if (callThroughProcAddress) { - if (numEmitted > 0) { - writer.print(", "); - } - writer.print("__addr_"); - ++numEmitted; - } - - return numEmitted; - } - - /** This class emits the comment for the wrapper method */ - private class WrappedMethodCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter { - protected void emitBeginning(FunctionEmitter methodEmitter, PrintWriter writer) { - writer.print("Encapsulates function pointer for OpenGL function <br>: "); - } - } -} // end class GLJavaMethodBindingEmitter +} diff --git a/src/classes/com/sun/gluegen/opengl/GLCMethodBindingEmitter.java b/src/classes/com/sun/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java index 43053410e..cc363178d 100755 --- a/src/classes/com/sun/gluegen/opengl/GLCMethodBindingEmitter.java +++ b/src/classes/com/sun/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * 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 @@ -37,29 +37,27 @@ * and developed by Kenneth Bradley Russell and Christopher John Kline. */ -package com.sun.gluegen.opengl; +package com.sun.gluegen.procaddress; import java.io.*; import java.util.*; import com.sun.gluegen.*; import com.sun.gluegen.cgram.types.*; -public class GLCMethodBindingEmitter extends CMethodBindingEmitter { - private static final CommentEmitter defaultCommentEmitter = - new CGLPAWrapperCommentEmitter(); - +public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter { private boolean callThroughProcAddress; - private String glFuncPtrTypedefValue; private static String procAddressJavaTypeName = JavaType.createForClass(Long.TYPE).jniTypeName(); + private ProcAddressEmitter emitter; - public GLCMethodBindingEmitter(CMethodBindingEmitter methodToWrap, - final boolean callThroughProcAddress) { + public ProcAddressCMethodBindingEmitter(CMethodBindingEmitter methodToWrap, + final boolean callThroughProcAddress, + ProcAddressEmitter emitter) { super( new MethodBinding(methodToWrap.getBinding()) { public String getName() { if (callThroughProcAddress) { - return GLEmitter.WRAP_PREFIX + super.getName(); + return ProcAddressEmitter.WRAP_PREFIX + super.getName(); } else { return super.getName(); } @@ -67,7 +65,7 @@ public class GLCMethodBindingEmitter extends CMethodBindingEmitter { public String getRenamedMethodName() { if (callThroughProcAddress) { - return GLEmitter.WRAP_PREFIX + super.getRenamedMethodName(); + return ProcAddressEmitter.WRAP_PREFIX + super.getRenamedMethodName(); } else { return super.getRenamedMethodName(); } @@ -94,6 +92,7 @@ public class GLCMethodBindingEmitter extends CMethodBindingEmitter { setCommentEmitter(defaultCommentEmitter); this.callThroughProcAddress = callThroughProcAddress; + this.emitter = emitter; } protected int emitArguments(PrintWriter writer) { @@ -103,9 +102,8 @@ public class GLCMethodBindingEmitter extends CMethodBindingEmitter { { writer.print(", "); } - //writer.print("long glProcAddress"); writer.print(procAddressJavaTypeName); - writer.print(" glProcAddress"); + writer.print(" procAddress"); ++numEmitted; } @@ -118,7 +116,7 @@ public class GLCMethodBindingEmitter extends CMethodBindingEmitter { // it to the value of the passed-in glProcAddress FunctionSymbol cSym = getBinding().getCSymbol(); String funcPointerTypedefName = - GLEmitter.getGLFunctionPointerTypedefName(cSym); + emitter.getFunctionPointerTypedefName(cSym); writer.print(" "); writer.print(funcPointerTypedefName); @@ -138,8 +136,7 @@ public class GLCMethodBindingEmitter extends CMethodBindingEmitter { if (!emittingPrimitiveArrayCritical) { // set the function pointer to the value of the passed-in glProcAddress FunctionSymbol cSym = getBinding().getCSymbol(); - String funcPointerTypedefName = - GLEmitter.getGLFunctionPointerTypedefName(cSym); + String funcPointerTypedefName = emitter.getFunctionPointerTypedefName(cSym); String ptrVarName = "ptr_" + cSym.getName(); @@ -147,7 +144,7 @@ public class GLCMethodBindingEmitter extends CMethodBindingEmitter { writer.print(ptrVarName); writer.print(" = ("); writer.print(funcPointerTypedefName); - writer.println(") (intptr_t) glProcAddress;"); + writer.println(") (intptr_t) procAddress;"); writer.println(" assert(" + ptrVarName + " != NULL);"); } @@ -170,9 +167,9 @@ public class GLCMethodBindingEmitter extends CMethodBindingEmitter { } MethodBinding binding = getBinding(); if (binding.hasContainingType()) { - // Cannot call GL func through function pointer - throw new IllegalStateException( - "Cannot call GL func through function pointer: " + binding); + // 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: " + binding); } // call throught the run-time function pointer @@ -191,12 +188,5 @@ public class GLCMethodBindingEmitter extends CMethodBindingEmitter { jniMangle(Long.TYPE, buf, false); // to account for the additional _addr_ parameter } return buf.toString(); - } - - /** This class emits the comment for the wrapper method */ - private static class CGLPAWrapperCommentEmitter extends CMethodBindingEmitter.DefaultCommentEmitter { - protected void emitBeginning(FunctionEmitter methodEmitter, PrintWriter writer) { - writer.print(" -- FIXME: IMPLEMENT COMMENT FOR CGLPAWrapperCommentEmitter -- "); - } } -} // end class GLCMethodBindingEmitter +} diff --git a/src/classes/com/sun/gluegen/procaddress/ProcAddressConfiguration.java b/src/classes/com/sun/gluegen/procaddress/ProcAddressConfiguration.java new file mode 100755 index 000000000..54dd2cbf8 --- /dev/null +++ b/src/classes/com/sun/gluegen/procaddress/ProcAddressConfiguration.java @@ -0,0 +1,256 @@ +/* + * 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.sun.gluegen.procaddress; + +import java.io.*; +import java.text.*; +import java.util.*; + +import com.sun.gluegen.*; + +public class ProcAddressConfiguration extends JavaConfiguration +{ + private boolean emitProcAddressTable = false; + private String tableClassPackage; + private String tableClassName = "ProcAddressTable"; + private Set/*<String>*/ skipProcAddressGen = new HashSet(); + private List/*<String>*/ forceProcAddressGen = new ArrayList(); + private String getProcAddressTableExpr; + private ConvNode procAddressNameConverter; + + 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 sym = readString("ForceProcAddressGen", tok, filename, lineNo); + forceProcAddressGen.add(sym); + } + else if (cmd.equalsIgnoreCase("GetProcAddressTableExpr")) + { + getProcAddressTableExpr = readGetProcAddressTableExpr(tok, filename, lineNo); + } + else if (cmd.equalsIgnoreCase("ProcAddressNameExpr")) + { + readProcAddressNameExpr(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); + } + } + + private static ConvNode makeConverter(Iterator/*<String>*/ iter) { + List/*<ConvNode>*/ result = new ArrayList/*<ConvNode>*/(); + while (iter.hasNext()) { + String str = (String) iter.next(); + if (str.equals("$")) { + String command = (String) iter.next(); + String openParen = (String) 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.size() == 0) { + return null; + } else if (result.size() == 1) { + return (ConvNode) 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) { + StringBuffer res = new StringBuffer(); + for (Iterator iter = children.iterator(); iter.hasNext(); ) { + ConvNode node = (ConvNode) iter.next(); + 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 List 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); + } +} diff --git a/src/classes/com/sun/gluegen/procaddress/ProcAddressEmitter.java b/src/classes/com/sun/gluegen/procaddress/ProcAddressEmitter.java new file mode 100755 index 000000000..75fb59c2f --- /dev/null +++ b/src/classes/com/sun/gluegen/procaddress/ProcAddressEmitter.java @@ -0,0 +1,370 @@ +/* + * 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.sun.gluegen.procaddress; + +import java.io.*; +import java.text.MessageFormat; +import java.util.*; +import com.sun.gluegen.*; +import com.sun.gluegen.cgram.types.*; +import com.sun.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 = ProcAddressHelper.PROCADDRESS_VAR_PREFIX; + protected static final String WRAP_PREFIX = "dispatch_"; + private TypeDictionary typedefDictionary; + private PrintWriter tableWriter; + private String tableClassPackage; + private String tableClassName; + + public void beginFunctions(TypeDictionary typedefDictionary, + TypeDictionary structDictionary, + Map canonMap) throws Exception + { + this.typedefDictionary = typedefDictionary; + + if (getProcAddressConfig().emitProcAddressTable()) + { + beginProcAddressTable(); + } + super.beginFunctions(typedefDictionary, structDictionary, canonMap); + } + + public void endFunctions() throws Exception + { + if (getProcAddressConfig().emitProcAddressTable()) + { + endProcAddressTable(); + } + super.endFunctions(); + } + + public void beginStructs(TypeDictionary typedefDictionary, + TypeDictionary structDictionary, + Map canonMap) throws Exception { + super.beginStructs(typedefDictionary, structDictionary, canonMap); + } + + public String runtimeExceptionType() { + return getConfig().runtimeExceptionType(); + } + + protected JavaConfiguration createConfig() { + return new ProcAddressConfiguration(); + } + + protected List generateMethodBindingEmitters(FunctionSymbol sym) throws Exception + { + return generateMethodBindingEmittersImpl(sym); + } + + protected boolean needsModifiedEmitters(FunctionSymbol sym) { + if (!needsProcAddressWrapper(sym) || + getConfig().isUnimplemented(sym.getName())) { + return false; + } + + return true; + } + + private List generateMethodBindingEmittersImpl(FunctionSymbol sym) throws Exception + { + 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 + // 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 modifiedEmitters = new ArrayList(defaultEmitters.size()); + + if (needsProcAddressWrapper(sym)) { + if (getProcAddressConfig().emitProcAddressTable()) { + // emit an entry in the GL proc address table for this method. + emitProcAddressTableEntryForSymbol(sym); + } + } + + for (Iterator iter = defaultEmitters.iterator(); iter.hasNext(); ) + { + FunctionEmitter emitter = (FunctionEmitter) iter.next(); + 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 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 public native + // call), we need to force it to emit a body, and produce another + // one to act as the entry point + if (baseJavaEmitter.signatureOnly() && + baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.PUBLIC) && + 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 emitters) + { + // See whether we need a proc address entry for this one + boolean callThroughProcAddress = needsProcAddressWrapper(baseCEmitter.getBinding().getCSymbol()); + // 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, this); + MessageFormat exp = baseCEmitter.getReturnValueCapacityExpression(); + if (exp != null) { + res.setReturnValueCapacityExpression(exp); + } + emitters.add(res); + } + + protected boolean needsProcAddressWrapper(FunctionSymbol sym) + { + String symName = sym.getName(); + + 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 (shouldWrap) + { + // Hoist argument names from function pointer if not supplied in prototype + FunctionType typedef = typedefDictionary.get(funcPointerTypedefName).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; + } + + private 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"); + + CodeGenUtils.emitAutogeneratedWarning(tableWriter, this); + + tableWriter.println("package " + implPackageName + ";"); + tableWriter.println(); + for (Iterator iter = getConfig().imports().iterator(); iter.hasNext(); ) { + tableWriter.println("import " + ((String) iter.next()) + ";"); + } + tableWriter.println(); + + tableWriter.println("/**"); + tableWriter.println(" * This table is a cache of pointers to the dynamically-linkable C"); + tableWriter.println(" * functions this autogenerated Java binding has exposed. Some"); + tableWriter.println(" * libraries such as OpenGL, OpenAL and others define function pointer"); + tableWriter.println(" * signatures rather than statically linkable entry points for the"); + tableWriter.println(" * purposes of being able to query at run-time whether a particular"); + tableWriter.println(" * extension is available. This table acts as a cache of these"); + tableWriter.println(" * function pointers. Each function pointer is typically looked up at"); + tableWriter.println(" * run-time by a platform-dependent mechanism such as dlsym(),"); + tableWriter.println(" * wgl/glXGetProcAddress(), or alGetProcAddress(). The associated"); + tableWriter.println(" * autogenerated Java and C code accesses the fields in this table to"); + tableWriter.println(" * call the various functions. If the field containing the function"); + tableWriter.println(" * pointer is 0, the function is considered to be unavailable and can"); + tableWriter.println(" * not be called."); + tableWriter.println(" */"); + tableWriter.println("public class " + tableClassName); + tableWriter.println("{"); + + for (Iterator iter = getProcAddressConfig().getForceProcAddressGen().iterator(); iter.hasNext(); ) { + emitProcAddressTableEntryForString((String) iter.next()); + } + } + + private void endProcAddressTable() throws Exception + { + PrintWriter w = tableWriter; + + w.println(" /**"); + w.println(" * This is a convenience method to get (by name) the native function"); + w.println(" * pointer for a given function. It lets you avoid having to"); + w.println(" * manually compute the "" + PROCADDRESS_VAR_PREFIX + " + "); + w.println(" * <functionName>" member variable name and look it up via"); + w.println(" * reflection; it also will throw an exception if you try to get the"); + w.println(" * address of an unknown function, or one that is statically linked"); + w.println(" * and therefore does not have a function pointer in this table."); + w.println(" *"); + w.println(" * @throws RuntimeException if the function pointer was not found in"); + w.println(" * this table, either because the function was unknown or because"); + w.println(" * it was statically linked."); + w.println(" */"); + w.println(" public long getAddressFor(String functionName) {"); + w.println(" String addressFieldName = com.sun.gluegen.runtime.ProcAddressHelper.PROCADDRESS_VAR_PREFIX + functionName;"); + w.println(" try { "); + w.println(" java.lang.reflect.Field addressField = getClass().getField(addressFieldName);"); + w.println(" return addressField.getLong(this);"); + w.println(" } catch (Exception e) {"); + w.println(" // The user is calling a bogus function or one which is not"); + w.println(" // runtime linked"); + w.println(" throw new RuntimeException("); + w.println(" \"WARNING: Address query failed for \\\"\" + functionName +"); + w.println(" \"\\\"; it's either statically linked or is not a known \" +"); + w.println(" \"function\", e);"); + w.println(" } "); + w.println(" }"); + + w.println("} // end of class " + tableClassName); + w.flush(); + w.close(); + } + + protected void emitProcAddressTableEntryForSymbol(FunctionSymbol cFunc) + { + emitProcAddressTableEntryForString(cFunc.getName()); + } + + protected void emitProcAddressTableEntryForString(String 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/classes/com/sun/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java b/src/classes/com/sun/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java new file mode 100755 index 000000000..a020ad715 --- /dev/null +++ b/src/classes/com/sun/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.sun.gluegen.procaddress; + +import java.io.*; +import java.util.*; +import com.sun.gluegen.*; +import com.sun.gluegen.cgram.types.*; + +/** A specialization of JavaMethodBindingEmitter with knowledge of how + to call through a function pointer. */ + +public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitter { + private final CommentEmitter commentEmitterForWrappedMethod = + new WrappedMethodCommentEmitter(); + + private boolean callThroughProcAddress; + private String getProcAddressTableExpr; + private boolean changeNameAndArguments; + private 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); + } + + public String getName() { + String res = super.getName(); + if (changeNameAndArguments) { + return ProcAddressEmitter.WRAP_PREFIX + res; + } + return res; + } + + 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; + } + + protected String getImplMethodName(boolean direct) { + String name = super.getImplMethodName(direct); + if (callThroughProcAddress) { + return ProcAddressEmitter.WRAP_PREFIX + name; + } + return name; + } + + 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.runtimeExceptionType() + "(\"Method \\\"" + binding.getName() + "\\\" not available\");"); + writer.println(" }"); + } + } + + protected int emitCallArguments(MethodBinding binding, PrintWriter writer, boolean indirect) { + int numEmitted = super.emitCallArguments(binding, writer, indirect); + if (callThroughProcAddress) { + if (numEmitted > 0) { + writer.print(", "); + } + writer.print("__addr_"); + ++numEmitted; + } + + return numEmitted; + } + + /** This class emits the comment for the wrapper method */ + private class WrappedMethodCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter { + protected void emitBeginning(FunctionEmitter methodEmitter, PrintWriter writer) { + writer.print("Entry point (through function pointer) to C language function <br>: "); + } + } +} diff --git a/src/classes/com/sun/gluegen/runtime/DynamicLookupHelper.java b/src/classes/com/sun/gluegen/runtime/DynamicLookupHelper.java new file mode 100755 index 000000000..07417f9c3 --- /dev/null +++ b/src/classes/com/sun/gluegen/runtime/DynamicLookupHelper.java @@ -0,0 +1,50 @@ +/* + * 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.sun.gluegen.runtime; + +/** Interface callers may use to use the ProcAddressHelper's {@link + ProcAddressHelper#resetProcAddressTable resetProcAddressTable} + helper method to install function pointers into a + ProcAddressTable. This must typically be written with native + code. */ + +public interface DynamicLookupHelper { + public long dynamicLookupFunction(String funcName); +} diff --git a/src/classes/com/sun/gluegen/runtime/ProcAddressHelper.java b/src/classes/com/sun/gluegen/runtime/ProcAddressHelper.java index 4d40fd487..4cf0b76d3 100644 --- a/src/classes/com/sun/gluegen/runtime/ProcAddressHelper.java +++ b/src/classes/com/sun/gluegen/runtime/ProcAddressHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * 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 @@ -39,8 +39,36 @@ package com.sun.gluegen.runtime; -/** Contains constants used in glue code generation. */ +/** Helper class containing constants and methods to assist with the + manipulation of auto-generated ProcAddressTables. */ public class ProcAddressHelper { public static final String PROCADDRESS_VAR_PREFIX = "_addressof_"; + + public static void resetProcAddressTable(Object table, + DynamicLookupHelper lookup) throws RuntimeException { + Class tableClass = table.getClass(); + java.lang.reflect.Field[] fields = tableClass.getDeclaredFields(); + + for (int i = 0; i < fields.length; ++i) { + String addressFieldName = fields[i].getName(); + if (!addressFieldName.startsWith(ProcAddressHelper.PROCADDRESS_VAR_PREFIX)) { + // not a proc address variable + continue; + } + int startOfMethodName = ProcAddressHelper.PROCADDRESS_VAR_PREFIX.length(); + String funcName = addressFieldName.substring(startOfMethodName); + try { + java.lang.reflect.Field addressField = tableClass.getDeclaredField(addressFieldName); + assert(addressField.getType() == Long.TYPE); + long newProcAddress = lookup.dynamicLookupFunction(funcName); + // set the current value of the proc address variable in the table object + addressField.setLong(table, newProcAddress); + } catch (Exception e) { + throw new RuntimeException("Can not get proc address for method \"" + + funcName + "\": Couldn't set value of field \"" + addressFieldName + + "\" in class " + tableClass.getName(), e); + } + } + } } diff --git a/src/classes/com/sun/opengl/impl/GLContextImpl.java b/src/classes/com/sun/opengl/impl/GLContextImpl.java index f2dfa216b..0b3933588 100644 --- a/src/classes/com/sun/opengl/impl/GLContextImpl.java +++ b/src/classes/com/sun/opengl/impl/GLContextImpl.java @@ -188,7 +188,7 @@ public abstract class GLContextImpl extends GLContext { /** Helper routine which resets a ProcAddressTable generated by the GLEmitter by looking up anew all of its function pointers. */ protected void resetProcAddressTable(Object table) { - GLDrawableFactoryImpl.getFactoryImpl().resetProcAddressTable(table); + ProcAddressHelper.resetProcAddressTable(table, GLDrawableFactoryImpl.getFactoryImpl()); } /** Indicates whether the underlying OpenGL context has been diff --git a/src/classes/com/sun/opengl/impl/GLDrawableFactoryImpl.java b/src/classes/com/sun/opengl/impl/GLDrawableFactoryImpl.java index 37dea5c15..d47003e45 100644 --- a/src/classes/com/sun/opengl/impl/GLDrawableFactoryImpl.java +++ b/src/classes/com/sun/opengl/impl/GLDrawableFactoryImpl.java @@ -42,7 +42,7 @@ package com.sun.opengl.impl; import java.awt.Component; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; -import com.sun.gluegen.runtime.*; // for PROCADDRESS_VAR_PREFIX +import com.sun.gluegen.runtime.*; import javax.media.opengl.*; /** Extends GLDrawableFactory with a few methods for handling @@ -50,41 +50,13 @@ import javax.media.opengl.*; Independent Bitmaps on Windows, pixmaps on X11). Direct access to these GLDrawables is not supplied directly to end users, though they may be instantiated by the GLJPanel implementation. */ -public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { +public abstract class GLDrawableFactoryImpl extends GLDrawableFactory implements DynamicLookupHelper { /** Creates a (typically software-accelerated) offscreen GLDrawable used to implement the fallback rendering path of the GLJPanel. */ public abstract GLDrawableImpl createOffscreenDrawable(GLCapabilities capabilities, GLCapabilitiesChooser chooser); - /** Helper routine which resets a ProcAddressTable generated by the - GLEmitter by looking up anew all of its function pointers. */ - public void resetProcAddressTable(Object table) { - Class tableClass = table.getClass(); - java.lang.reflect.Field[] fields = tableClass.getDeclaredFields(); - - for (int i = 0; i < fields.length; ++i) { - String addressFieldName = fields[i].getName(); - if (!addressFieldName.startsWith(ProcAddressHelper.PROCADDRESS_VAR_PREFIX)) { - // not a proc address variable - continue; - } - int startOfMethodName = ProcAddressHelper.PROCADDRESS_VAR_PREFIX.length(); - String glFuncName = addressFieldName.substring(startOfMethodName); - try { - java.lang.reflect.Field addressField = tableClass.getDeclaredField(addressFieldName); - assert(addressField.getType() == Long.TYPE); - long newProcAddress = dynamicLookupFunction(glFuncName); - // set the current value of the proc address variable in the table object - addressField.setLong(table, newProcAddress); - } catch (Exception e) { - throw new GLException("Cannot get GL proc address for method \"" + - glFuncName + "\": Couldn't set value of field \"" + addressFieldName + - "\" in class " + tableClass.getName(), e); - } - } - } - /** Dynamically looks up the given function. */ public abstract long dynamicLookupFunction(String glFuncName); |