GlueGen v2.6.0-rc-20250712
GlueGen, Native Binding Generator for Java™ (public API).
ProcAddressEmitter.java
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010-2023 JogAmp Community. All rights reserved.
3 * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * - Redistribution of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * - Redistribution in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of Sun Microsystems, Inc. or the names of
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * This software is provided "AS IS," without a warranty of any kind. ALL
21 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
22 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
23 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
24 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
25 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
26 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
27 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
28 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
29 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
30 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
31 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32 *
33 * You acknowledge that this software is not designed or intended for use
34 * in the design, construction, operation or maintenance of any nuclear
35 * facility.
36 *
37 * Sun gratefully acknowledges that this software was originally authored
38 * and developed by Kenneth Bradley Russell and Christopher John Kline.
39 */
40package com.jogamp.gluegen.procaddress;
41
42import java.io.File;
43import java.text.MessageFormat;
44import java.util.ArrayList;
45import java.util.HashSet;
46import java.util.List;
47import java.util.Map;
48import java.util.Set;
49import java.util.logging.Level;
50
51import com.jogamp.gluegen.CMethodBindingEmitter;
52import com.jogamp.gluegen.CodeGenUtils;
53import com.jogamp.gluegen.FunctionEmitter;
54import com.jogamp.gluegen.JavaCodeUnit;
55import com.jogamp.gluegen.JavaConfiguration;
56import com.jogamp.gluegen.JavaEmitter;
57import com.jogamp.gluegen.JavaMethodBindingEmitter;
58import com.jogamp.gluegen.cgram.types.FunctionSymbol;
59import com.jogamp.gluegen.cgram.types.Type;
60import com.jogamp.gluegen.cgram.types.TypeDictionary;
61import com.jogamp.gluegen.runtime.FunctionAddressResolver;
62import com.jogamp.gluegen.runtime.ProcAddressTable;
63
64/**
65 * A subclass of JavaEmitter that modifies the normal emission of C
66 * and Java code to allow dynamic lookups of the C entry points
67 * associated with the Java methods.
68 */
69public class ProcAddressEmitter extends JavaEmitter {
70
71 /** Must be synchronized w/ ProcAddressTable.PROCADDRESS_VAR_PREFIX !!! */
72 public static final String PROCADDRESS_VAR_PREFIX = "_addressof_";
73 protected static final String WRAP_PREFIX = "dispatch_";
74 private TypeDictionary typedefDictionary;
76 protected Set<String> emittedTableEntries;
77 protected String tableClassPackage;
78 protected String tableClassName;
79
80 @Override
81 public void beginFunctions(final TypeDictionary typedefDictionary, final TypeDictionary structDictionary,
82 final Map<Type, Type> canonMap, final List<FunctionSymbol> cFunctions) throws Exception {
83 this.typedefDictionary = typedefDictionary;
84
85 if (getProcAddressConfig().emitProcAddressTable()) {
87 }
88 super.beginFunctions(typedefDictionary, structDictionary, canonMap, cFunctions);
89 }
90
91 @Override
92 public void endFunctions() throws Exception {
93 if (getProcAddressConfig().emitProcAddressTable()) {
95 }
96 super.endFunctions();
97 }
98
99 @Override
100 public void beginStructs(final TypeDictionary typedefDictionary, final TypeDictionary structDictionary, final Map<Type, Type> canonMap) throws Exception {
101 super.beginStructs(typedefDictionary, structDictionary, canonMap);
102 }
103
104 public String runtimeExceptionType() {
105 return getConfig().runtimeExceptionType();
106 }
107
108 public String unsupportedExceptionType() {
109 return getConfig().unsupportedExceptionType();
110 }
111
112 @Override
114 return new ProcAddressConfiguration();
115 }
116
117 @Override
118 protected List<? extends FunctionEmitter> generateMethodBindingEmitters(final FunctionSymbol sym) throws Exception {
119 return generateMethodBindingEmittersImpl(sym);
120 }
121
122 protected boolean needsModifiedEmitters(final FunctionSymbol sym) {
123 if ( !callThroughProcAddress(sym) || getConfig().isUnimplemented(sym) ) {
124 return false;
125 } else {
126 return true;
127 }
128 }
129
130 private List<? extends FunctionEmitter> generateMethodBindingEmittersImpl(final FunctionSymbol sym) throws Exception {
131 final List<? extends FunctionEmitter> defaultEmitters = super.generateMethodBindingEmitters(sym);
132
133 // if the superclass didn't generate any bindings for the symbol, let's
134 // honor that (for example, the superclass might have caught an Ignore
135 // direction that matched the symbol's name).
136 if (defaultEmitters.isEmpty()) {
137 LOG.log(Level.INFO, sym.getASTLocusTag(), "genModProcAddrEmitter: SKIP, empty binding set: {0}", sym);
138 return defaultEmitters;
139 }
140
142 final boolean isUnimplemented = getConfig().isUnimplemented(sym);
143
144 // Don't do anything special if this symbol doesn't require modifications
145 if( !callThroughProcAddress || isUnimplemented ) {
146 LOG.log(Level.INFO, sym.getASTLocusTag(), "genModProcAddrEmitter: SKIP, not needed: callThrough {0}, isUnimplemented {1}: {2}",
147 callThroughProcAddress, isUnimplemented, sym);
148 return defaultEmitters;
149 }
150
151 final ArrayList<FunctionEmitter> modifiedEmitters = new ArrayList<FunctionEmitter>(defaultEmitters.size());
152
154 if (getProcAddressConfig().emitProcAddressTable()) {
155 // emit an entry in the GL proc address table for this method.
157 }
158 }
159 for (final FunctionEmitter emitter : defaultEmitters) {
160 if (emitter instanceof JavaMethodBindingEmitter) {
161 generateModifiedEmitters((JavaMethodBindingEmitter)emitter, modifiedEmitters);
162 } else if (emitter instanceof CMethodBindingEmitter) {
163 generateModifiedEmitters((CMethodBindingEmitter) emitter, modifiedEmitters);
164 } else {
165 throw new RuntimeException("Unexpected emitter type: " + emitter.getClass().getName());
166 }
167 }
168
169 return modifiedEmitters;
170 }
171
172 /**
173 * Returns the name of the typedef for a pointer to the function
174 * represented by the argument as defined by the ProcAddressNameExpr
175 * in the .cfg file. For example, in the OpenGL headers, if the
176 * argument is the function "glFuncName", the value returned will be
177 * "PFNGLFUNCNAMEPROC". This returns a valid string regardless of
178 * whether or not the typedef is actually defined.
179 */
180 protected String getFunctionPointerTypedefName(final FunctionSymbol sym) {
182 }
183
184 //----------------------------------------------------------------------
185 // Internals only below this point
186 //
187
188 /** If 'native', enforce 'private native' modifiers. */
189 protected void fixSecurityModifiers(final JavaMethodBindingEmitter javaEmitter) {
192 {
198 }
199 }
200
201 protected void generateModifiedEmitters(final JavaMethodBindingEmitter baseJavaEmitter, final List<FunctionEmitter> emitters) {
202 // See whether we need a proc address entry for this one
203 final boolean callThroughProcAddress = callThroughProcAddress(baseJavaEmitter.getBinding().getCSymbol());
204
205 // If this emitter doesn't have a body (i.e., is a direct native
206 // call with no intervening argument processing), we need to force
207 // it to emit a body, and produce another one to act as the entry point
208 final boolean needsJavaWrapper = baseJavaEmitter.signatureOnly() &&
209 baseJavaEmitter.isNativeMethod() &&
210 !baseJavaEmitter.isPrivateNativeMethod() &&
212
213
214 {
217 getProcAddressConfig().getProcAddressTableExpr(),
218 baseJavaEmitter.isPrivateNativeMethod(),
219 this);
220 if( needsJavaWrapper ) {
221 emitter.setEmitBody(true);
223 } else if ( callThroughProcAddress ) {
224 fixSecurityModifiers(emitter);
225 }
226 emitters.add(emitter);
227 }
228
229 if( needsJavaWrapper ) {
232 getProcAddressConfig().getProcAddressTableExpr(),
233 true,
234 this);
235 emitter.setPrivateNativeMethod(true);
236 fixSecurityModifiers(emitter);
237 emitters.add(emitter);
238 }
239 }
240
241 protected void generateModifiedEmitters(final CMethodBindingEmitter baseCEmitter, final List<FunctionEmitter> emitters) {
242
243 final FunctionSymbol cSymbol = baseCEmitter.getBinding().getCSymbol();
244
245 // See whether we need a proc address entry for this one
246 final boolean hasProcAddrTypedef = hasFunctionPointerTypedef(cSymbol);
247 final boolean callThroughProcAddress = hasProcAddrTypedef || callThroughProcAddress(cSymbol);
248 final String localProcCallingConvention = getProcAddressConfig().getLocalProcAddressCallingConvention(cSymbol);
249
250 LOG.log(Level.INFO, cSymbol.getASTLocusTag(), "genModProcAddrEmitter: callThrough {0}, hasTypedef {1}, localCallConv {2}: {3}",
251 callThroughProcAddress, hasProcAddrTypedef, localProcCallingConvention, cSymbol);
252
253 // Note that we don't care much about the naming of the C argument
254 // variables so to keep things simple we ignore the buffer object
255 // property for the binding
256
257 // The C-side JNI binding for this particular function will have an
258 // extra final argument, which is the address (the OpenGL procedure
259 // address) of the function it needs to call
261 baseCEmitter, callThroughProcAddress, hasProcAddrTypedef, localProcCallingConvention, this);
262
263 final MessageFormat exp = baseCEmitter.getReturnValueCapacityExpression();
264 if (exp != null) {
266 }
267 emitters.add(res);
268 }
269
270 protected boolean callThroughProcAddress(final FunctionSymbol sym) {
272 boolean res = false;
273 int mode = 0;
274 if (cfg.forceProcAddressGen(sym)) {
275 res = true;
276 mode = 1;
277 } else {
278 if (cfg.skipProcAddressGen(sym)) {
279 res = false;
280 mode = 2;
281 } else {
282 res = hasFunctionPointerTypedef(sym);
283 mode = 3;
284 }
285 }
286 LOG.log(Level.INFO, sym.getASTLocusTag(), "callThroughProcAddress: {0} [m {1}]: {2}", res, mode, sym);
287 return res;
288 }
289 protected boolean hasFunctionPointerTypedef(final FunctionSymbol sym) {
290 final String funcPointerTypedefName = getFunctionPointerTypedefName(sym);
291 final boolean res = typedefDictionary.containsKey(funcPointerTypedefName);
292 LOG.log(Level.INFO, sym.getASTLocusTag(), "hasFunctionPointerTypedef: {0}: {1}", res, sym);
293 return res;
294 }
295
296 protected void beginProcAddressTable() throws Exception {
298 tableClassPackage = cfg.tableClassPackage();
299 tableClassName = cfg.tableClassName();
300
301 // Table defaults to going into the impl directory unless otherwise overridden
302 String implPackageName = tableClassPackage;
303 if (implPackageName == null) {
304 implPackageName = getImplPackageName();
305 }
306 final String tableClassFQN = implPackageName + "." + tableClassName;
307 final String[] accessModifiers = getClassAccessModifiers(tableClassFQN);
308
309 final String jImplRoot = getJavaOutputDir() + File.separator + CodeGenUtils.packageAsPath(implPackageName);
310
311 final String javaFileName = jImplRoot + File.separator + tableClassName + ".java";
312 tableJavaUnit = openJavaUnit(javaFileName, implPackageName, tableClassName);
313
314 emittedTableEntries = new HashSet<String>();
315
316 tableJavaUnit.emitln("package " + implPackageName + ";");
318 for (final String imporT : getConfig().imports()) {
319 tableJavaUnit.emitln("import " + imporT + ";");
320 }
321 tableJavaUnit.emitln("import " + ProcAddressTable.class.getName() + ";");
322 tableJavaUnit.emitln("import com.jogamp.common.util.SecurityUtil;");
324
325 tableJavaUnit.emitln("/**");
326 tableJavaUnit.emitln(" * This table is a cache of pointers to the dynamically-linkable C library.");
327 tableJavaUnit.emitln(" * @see " + ProcAddressTable.class.getSimpleName());
328 tableJavaUnit.emitln(" */");
329 for (int i = 0; accessModifiers != null && i < accessModifiers.length; ++i) {
330 tableJavaUnit.emit(accessModifiers[i]);
331 tableJavaUnit.emit(" ");
332 }
333 tableJavaUnit.emitln("final class " + tableClassName + " extends "+ ProcAddressTable.class.getSimpleName() + " {");
335
336 for (final String string : getProcAddressConfig().getForceProcAddressGen()) {
338 }
339
341 tableJavaUnit.emitln(" public "+tableClassName+"(){ super(); }");
343 tableJavaUnit.emitln(" public "+tableClassName+"("+FunctionAddressResolver.class.getName()+" resolver){ super(resolver); }");
345
346 }
347
348 protected void endProcAddressTable() throws Exception {
349 tableJavaUnit.emitln("} // end of class " + tableClassName);
351 tableJavaUnit = null;
352 }
353
354 protected void emitProcAddressTableEntryForString(final String str) {
355 // Deal gracefully with forced proc address generation in the face
356 // of having the function pointer typedef in the header file too
357 if (emittedTableEntries.contains(str)) {
358 return;
359 }
360 emittedTableEntries.add(str);
361 tableJavaUnit.emit(" /* pp */ long ");
363 tableJavaUnit.emit(str);
365 }
366
369 }
370}
Emits the C-side component of the Java<->C JNI binding to its CodeUnit, see FunctionEmitter.
final MessageFormat getReturnValueCapacityExpression()
Get the expression for the capacity of the returned java.nio.Buffer.
final void setReturnValueCapacityExpression(final MessageFormat expression)
If this function returns a void* encapsulated in a java.nio.Buffer (or compound type wrapper),...
static String packageAsPath(final String packageName)
Given a java package name (e.g., "java.lang"), return the package as a directory path (i....
void emit(final String s)
Definition: CodeUnit.java:81
boolean removeModifier(final EmissionModifier m)
boolean hasModifier(final EmissionModifier m)
void addModifier(final EmissionModifier m)
Java code unit (a generated Java source file), covering multiple FunctionEmitter allowing to unify ou...
Parses and provides access to the contents of .cfg files for the JavaEmitter.
boolean isUnimplemented(final AliasedSymbol symbol)
Returns true if this function should be given a body which throws a run-time exception with an "unimp...
String getJavaOutputDir()
Returns the value that was specified by the configuration directive "JavaOutputDir",...
JavaCodeUnit openJavaUnit(final String filename, final String packageName, final String simpleClassName)
String getImplPackageName()
Returns the value that was specified by the configuration directive "ImplPackage",...
JavaConfiguration getConfig()
String[] getClassAccessModifiers(final String classFQName)
Emits the Java-side component (interface and.or implementation) of the Java<->C JNI binding to its Co...
void setEmitBody(final boolean emitBody)
Accessor for subclasses.
boolean signatureOnly()
Indicates whether this emitter will print only a signature, or whether it will emit Java code for the...
void setPrivateNativeMethod(final boolean v)
Accessor for subclasses.
FunctionSymbol getCSymbol()
Returns the FunctionSymbol.
String getOrigName()
Return the original-name as set at creation.
Describes a function symbol, which includes the name and type.
ASTLocusTag getASTLocusTag()
Returns this instance's ASTLocusTag, if available, otherwise returns null.
Utility class for recording names of typedefs and structs.
String getLocalProcAddressCallingConvention(final FunctionSymbol symbol)
A subclass of JavaEmitter that modifies the normal emission of C and Java code to allow dynamic looku...
List<? extends FunctionEmitter > generateMethodBindingEmitters(final FunctionSymbol sym)
Generate all appropriate Java bindings for the specified C function symbols.
String getFunctionPointerTypedefName(final FunctionSymbol sym)
Returns the name of the typedef for a pointer to the function represented by the argument as defined ...
void beginStructs(final TypeDictionary typedefDictionary, final TypeDictionary structDictionary, final Map< Type, Type > canonMap)
void beginFunctions(final TypeDictionary typedefDictionary, final TypeDictionary structDictionary, final Map< Type, Type > canonMap, final List< FunctionSymbol > cFunctions)
boolean hasFunctionPointerTypedef(final FunctionSymbol sym)
void generateModifiedEmitters(final CMethodBindingEmitter baseCEmitter, final List< FunctionEmitter > emitters)
static final String PROCADDRESS_VAR_PREFIX
Must be synchronized w/ ProcAddressTable.PROCADDRESS_VAR_PREFIX !!!
boolean callThroughProcAddress(final FunctionSymbol sym)
JavaConfiguration createConfig()
Create the object that will read and store configuration information for this JavaEmitter.
void fixSecurityModifiers(final JavaMethodBindingEmitter javaEmitter)
If 'native', enforce 'private native' modifiers.
boolean needsModifiedEmitters(final FunctionSymbol sym)
void generateModifiedEmitters(final JavaMethodBindingEmitter baseJavaEmitter, final List< FunctionEmitter > emitters)
A specialization of JavaMethodBindingEmitter with knowledge of how to call through a function pointer...
Superclass for all generated ProcAddressTables.
void log(final Level level, final String msg)
See Logger#log(Level, String).