GlueGen v2.6.0-rc-20250712
GlueGen, Native Binding Generator for Java™ (public API).
CCodeUnit.java
Go to the documentation of this file.
1/**
2 * Copyright 2023 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28package com.jogamp.gluegen;
29
30import java.io.IOException;
31import java.util.List;
32
33/**
34 * C code unit (a generated C source file),
35 * covering multiple {@link FunctionEmitter} allowing to unify output, decoration and dynamic helper code injection per unit.
36 **/
37public class CCodeUnit extends CodeUnit {
38 /** base c-unit name with suffix. */
39 public final String cUnitName;
40
41 /**
42 * @param filename the class's full filename to open w/ write access
43 * @param cUnitName the base c-unit name, i.e. c-file basename with suffix
44 * @param generator informal optional object that is creating this unit, used to be mentioned in a warning message if not null.
45 * @throws IOException
46 */
47 public CCodeUnit(final String filename, final String cUnitName, final Object generator) throws IOException {
48 super(filename, generator);
49 this.cUnitName = cUnitName;
51 }
52
53 public void emitHeader(final String packageName, final String className, final List<String> customCode) {
54 emitln("#include <jni.h>");
55 emitln("#include <stdlib.h>");
56 emitln("#include <string.h>");
57 emitln("#include <assert.h>");
58 emitln("#include <stddef.h>");
59 emitln();
61 emitln();
62 emitln("static jobject JVMUtil_NewDirectByteBufferCopy(JNIEnv *env, jclass clazzBuffers, void * source_address, size_t capacity); /* forward decl. */");
63 emitln();
64
65 boolean addNewDirectByteBufferCopyUnitCode = false;
66 for (final String code : customCode) {
67 emitln(code);
68 addNewDirectByteBufferCopyUnitCode = addNewDirectByteBufferCopyUnitCode || code.contains("JVMUtil_NewDirectByteBufferCopy");
69 }
70 emitln();
71 if( addNewDirectByteBufferCopyUnitCode ) {
72 addTailCode(NewDirectByteBufferCopyUnitCode); // potentially used...
73 }
74 }
75
76 /** Emits {@link #getJNIEnvDecl()}. */
77 public void emitJNIEnvDecl() {
79 }
80
81 /** Emits {@link #getJNIOnLoadJNIEnvCode(String)}. */
82 public void emitJNIOnLoadJNIEnvCode(final String libraryBasename) {
83 emitln( getJNIOnLoadJNIEnvCode(libraryBasename) );
84 }
85
86 @Override
87 public String toString() { return "CCodeUnit[unit "+cUnitName+", file "+filename+"]"; }
88
89 public static final String NewDirectByteBufferCopyUnitCode =
90 "static const char * nameCopyNativeToDirectByteBuffer = \"copyNativeToDirectByteBuffer\";\n"+
91 "static const char * nameCopyNativeToDirectByteBufferSignature = \"(JJ)Ljava/nio/ByteBuffer;\";\n"+
92 "\n"+
93 "static jobject JVMUtil_NewDirectByteBufferCopy(JNIEnv *env, jclass clazzBuffers, void * source_address, size_t capacity) {\n"+
94 " jmethodID cstrBuffersNew = (*env)->GetStaticMethodID(env, clazzBuffers, nameCopyNativeToDirectByteBuffer, nameCopyNativeToDirectByteBufferSignature);\n"+
95 " if(NULL==cstrBuffersNew) {\n"+
96 " fprintf(stderr, \"Can't get method Buffers.%s(%s)\\n\", nameCopyNativeToDirectByteBuffer, nameCopyNativeToDirectByteBufferSignature);\n"+
97 " (*env)->FatalError(env, nameCopyNativeToDirectByteBuffer);\n"+
98 " return JNI_FALSE;\n"+
99 " }\n"+
100 " jobject jbyteBuffer = (*env)->CallStaticObjectMethod(env, clazzBuffers, cstrBuffersNew, (jlong)(intptr_t)source_address, (jlong)capacity);\n"+
101 " if( (*env)->ExceptionCheck(env) ) {\n"+
102 " (*env)->ExceptionDescribe(env);\n"+
103 " (*env)->ExceptionClear(env);\n"+
104 " (*env)->FatalError(env, \"Exception occurred\");\n"+
105 " return NULL;\n"+
106 " }\n"+
107 " return jbyteBuffer;\n"+
108 "}\n";
109
110 /**
111 * Returns native JNI declarations for `JVMUtil_GetJavaVM()`, `JVMUtil_GetJNIEnv(..)` and `JVMUtil_ReleaseJNIEnv(..)`.
112 * <p>
113 * See {@link #getJNIOnLoadJNIEnvCode(String)} for details.
114 * </p>
115 * @return the code
116 * @see #getJNIOnLoadJNIEnvCode(String)
117 */
118 public static final String getJNIEnvDecl() {
119 return "JavaVM* JVMUtil_GetJavaVM();\n"+
120 "JNIEnv* JVMUtil_GetJNIEnv(int asDaemon, int* jvmAttached);\n"+
121 "void JVMUtil_ReleaseJNIEnv(JNIEnv* env, int detachJVM);\n";
122 }
123 /**
124 * Returns native JNI code `JNI_OnLoad(..)` used for dynamic libraries,
125 * `JNI_OnLoad_{libraryBasename}(..)` used for static libraries,
126 * `JVMUtil_GetJNIEnv(..)` etc.
127 * <p>
128 * The `JNI_OnLoad*(..)` methods set a `static JavaVM* {libraryBasename}_jvmHandle`,
129 * which in turn is utilized by `JVMUtil_GetJNIEnv(..)`
130 * to attach a new thread to the `JavaVM*` generating a new `JNIEnv*`-
131 * or just to retrieve the thread's `JNIEnv*`, if already attached to the `JavaVM*`.
132 * </p>
133 * @param libraryBasename library basename to generate the `JNI_OnLoad_{libraryBasename}(..)` variant for statically linked libraries.
134 * @return the code
135 * @see #getJNIOnLoadJNIEnvDecl(String)
136 */
137 public static final String getJNIOnLoadJNIEnvCode(final String libraryBasename) {
138 final String jvmHandleName = libraryBasename+"_jvmHandle";
139 final StringBuilder sb = new StringBuilder();
140 sb.append("static JavaVM *").append(jvmHandleName).append(" = NULL;\n");
141 sb.append("\n");
142 sb.append("JavaVM* JVMUtil_GetJavaVM() {\n");
143 sb.append(" return ").append(jvmHandleName).append(";\n");
144 sb.append("}\n");
145 sb.append("JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *initVM, void *reserved) {\n");
146 sb.append(" (void)reserved;\n");
147 sb.append(" ").append(jvmHandleName).append(" = initVM;\n");
148 if( GlueGen.debug() ) {
149 sb.append(" fprintf(stderr, \"ON_LOAD_0 lib '").append(libraryBasename).append("'\\n\");\n");
150 }
151 sb.append(" return JNI_VERSION_1_8;\n");
152 sb.append("}\n");
153 sb.append("JNIEXPORT jint JNICALL JNI_OnLoad_").append(libraryBasename).append("(JavaVM *initVM, void *reserved) {\n");
154 sb.append(" (void)reserved;\n");
155 sb.append(" ").append(jvmHandleName).append(" = initVM;\n");
156 if( GlueGen.debug() ) {
157 sb.append(" fprintf(stderr, \"ON_LOAD_1 lib '").append(libraryBasename).append("'\\n\");\n");
158 }
159 sb.append(" return JNI_VERSION_1_8;\n");
160 sb.append("}\n");
161 sb.append("\n");
162 sb.append("JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {\n");
163 sb.append(" (void)vm;\n");
164 sb.append(" (void)reserved;\n");
165 sb.append(" ").append(jvmHandleName).append(" = NULL;\n");
166 if( GlueGen.debug() ) {
167 sb.append(" fprintf(stderr, \"ON_UNLOAD_0 lib '").append(libraryBasename).append("'\\n\");\n");
168 }
169 sb.append("}\n");
170 sb.append("\n");
171 sb.append("JNIEXPORT void JNICALL JNI_OnUnload_").append(libraryBasename).append("(JavaVM *vm, void *reserved) {\n");
172 sb.append(" (void)vm;\n");
173 sb.append(" (void)reserved;\n");
174 sb.append(" ").append(jvmHandleName).append(" = NULL;\n");
175 if( GlueGen.debug() ) {
176 sb.append(" fprintf(stderr, \"ON_UNLOAD_1 lib '").append(libraryBasename).append("'\\n\");\n");
177 }
178 sb.append("}\n");
179 sb.append("\n");
180 sb.append("JNIEnv* JVMUtil_GetJNIEnv(int asDaemon, int* jvmAttached) {\n");
181 sb.append(" JNIEnv* curEnv = NULL;\n");
182 sb.append(" JNIEnv* newEnv = NULL;\n");
183 sb.append(" int envRes;\n");
184 sb.append("\n");
185 sb.append(" if( NULL != jvmAttached ) {\n");
186 sb.append(" *jvmAttached = 0;\n");
187 sb.append(" }\n");
188 sb.append(" if(NULL==").append(jvmHandleName).append(") {\n");
189 sb.append(" fprintf(stderr, \"JVMUtil_GetJNIEnv(").append(libraryBasename).append("): No JavaVM handle registered.\\n\");\n");
190 sb.append(" return NULL;\n");
191 sb.append(" }\n");
192 sb.append("\n");
193 sb.append(" // retrieve this thread's JNIEnv curEnv - or detect it's detached\n");
194 sb.append(" envRes = (*").append(jvmHandleName).append(")->GetEnv(").append(jvmHandleName).append(", (void **) &curEnv, JNI_VERSION_1_8) ;\n");
195 sb.append(" if( JNI_EDETACHED == envRes ) {\n");
196 sb.append(" // detached thread - attach to JVM as daemon, w/o need to be detached!\n");
197 sb.append(" if( asDaemon ) {\n");
198 sb.append(" envRes = (*").append(jvmHandleName).append(")->AttachCurrentThreadAsDaemon(").append(jvmHandleName).append(", (void**) &newEnv, NULL);\n");
199 sb.append(" } else {\n");
200 sb.append(" envRes = (*").append(jvmHandleName).append(")->AttachCurrentThread(").append(jvmHandleName).append(", (void**) &newEnv, NULL);\n");
201 sb.append(" }\n");
202 sb.append(" if( JNI_OK != envRes ) {\n");
203 sb.append(" fprintf(stderr, \"JVMUtil_GetJNIEnv(").append(libraryBasename).append("): Can't attach thread: %d\\n\", envRes);\n");
204 sb.append(" return NULL;\n");
205 sb.append(" }\n");
206 sb.append(" curEnv = newEnv;\n");
207 sb.append(" } else if( JNI_OK != envRes ) {\n");
208 sb.append(" // oops ..\n");
209 sb.append(" fprintf(stderr, \"JVMUtil_GetJNIEnv(").append(libraryBasename).append("): Can't GetEnv: %d\\n\", envRes);\n");
210 sb.append(" return NULL;\n");
211 sb.append(" }\n");
212 sb.append(" if (curEnv==NULL) {\n");
213 sb.append(" fprintf(stderr, \"JVMUtil_GetJNIEnv(").append(libraryBasename).append("): env is NULL\\n\");\n");
214 sb.append(" return NULL;\n");
215 sb.append(" }\n");
216 sb.append(" if( NULL != jvmAttached ) {\n");
217 sb.append(" *jvmAttached = NULL != newEnv;\n");
218 sb.append(" }\n");
219 if( GlueGen.debug() ) {
220 sb.append(" fprintf(stderr, \"JVMUtil_GetJNIEnv(").append(libraryBasename).append(", asDaemon %d): jvmAttached %d -> env %p\\n.\", asDaemon, (NULL != newEnv), curEnv);\n");
221 }
222 sb.append(" return curEnv;\n");
223 sb.append("}\n");
224 sb.append("\n");
225 sb.append("void JVMUtil_ReleaseJNIEnv(JNIEnv* env, int detachJVM) {\n");
226 sb.append(" if(NULL==").append(jvmHandleName).append(") {\n");
227 sb.append(" fprintf(stderr, \"JVMUtil_ReleaseJNIEnv(").append(libraryBasename).append("): No JavaVM handle registered.\\n\");\n");
228 sb.append(" return;\n");
229 sb.append(" }\n");
230 sb.append(" if( detachJVM ) {\n");
231 sb.append(" jint res = (*").append(jvmHandleName).append(")->DetachCurrentThread(").append(jvmHandleName).append(") ;\n");
232 sb.append(" if( 0 != res ) {\n");
233 sb.append(" fprintf(stderr, \"JVMUtil_ReleaseJNIEnv(").append(libraryBasename).append(", env %p): Failed with res %d\\n.\", env, res);\n");
234 sb.append(" return;\n");
235 sb.append(" }\n");
236 if( GlueGen.debug() ) {
237 sb.append(" fprintf(stderr, \"JVMUtil_ReleaseJNIEnv(").append(libraryBasename).append(", env %p) -> res %d\\n.\", env, res);\n");
238 }
239 sb.append(" }\n");
240 sb.append("}\n");
241 sb.append("\n");
242 return sb.toString();
243 }
244}
245
C code unit (a generated C source file), covering multiple FunctionEmitter allowing to unify output,...
Definition: CCodeUnit.java:37
void emitJNIEnvDecl()
Emits getJNIEnvDecl().
Definition: CCodeUnit.java:77
final String cUnitName
base c-unit name with suffix.
Definition: CCodeUnit.java:39
static final String getJNIOnLoadJNIEnvCode(final String libraryBasename)
Returns native JNI code JNI_OnLoad(..) used for dynamic libraries, JNI_OnLoad_{libraryBasename}(....
Definition: CCodeUnit.java:137
CCodeUnit(final String filename, final String cUnitName, final Object generator)
Definition: CCodeUnit.java:47
void emitJNIOnLoadJNIEnvCode(final String libraryBasename)
Emits getJNIOnLoadJNIEnvCode(String).
Definition: CCodeUnit.java:82
void emitHeader(final String packageName, final String className, final List< String > customCode)
Definition: CCodeUnit.java:53
static final String getJNIEnvDecl()
Returns native JNI declarations for JVMUtil_GetJavaVM(), JVMUtil_GetJNIEnv(..) and JVMUtil_ReleaseJNI...
Definition: CCodeUnit.java:118
static final String NewDirectByteBufferCopyUnitCode
Definition: CCodeUnit.java:89
static void emitAutogeneratedWarning(final PrintWriter w, final Object generator, final String customLine)
General code unit (a generated C or Java source file), covering multiple FunctionEmitter allowing to ...
Definition: CodeUnit.java:42
boolean addTailCode(final String c)
Add a tail code to this unit.
Definition: CodeUnit.java:71
final PrintWriter output
Definition: CodeUnit.java:44
Glue code generator for C functions and data structures.
Definition: GlueGen.java:59