GlueGen v2.6.0-rc-20250712
GlueGen, Native Binding Generator for Java™ (public API).
JavaMethodBindingEmitter.java
Go to the documentation of this file.
1/**
2 * Copyright (c) 2010-2023 JogAmp Community. All rights reserved.
3 * Copyright (c) 2003 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 */
40
41package com.jogamp.gluegen;
42
43import com.jogamp.gluegen.JavaConfiguration.JavaCallbackInfo;
44import com.jogamp.gluegen.cgram.HeaderParser;
45import com.jogamp.gluegen.cgram.types.AliasedSymbol;
46import com.jogamp.gluegen.cgram.types.ArrayType;
47import com.jogamp.gluegen.cgram.types.EnumType;
48import com.jogamp.gluegen.cgram.types.FunctionSymbol;
49import com.jogamp.gluegen.cgram.types.Type;
50
51import java.io.PrintWriter;
52import java.text.MessageFormat;
53import java.util.Iterator;
54import java.util.List;
55import java.util.Set;
56
57/** Emits the Java-side component (interface and.or implementation) of the Java<->C JNI binding to its {@link CodeUnit}, see {@link FunctionEmitter}. */
59
60 public static final EmissionModifier PUBLIC = new EmissionModifier("public");
61 public static final EmissionModifier PROTECTED = new EmissionModifier("protected");
62 public static final EmissionModifier PRIVATE = new EmissionModifier("private");
63 public static final EmissionModifier ABSTRACT = new EmissionModifier("abstract");
64 public static final EmissionModifier FINAL = new EmissionModifier("final");
65 public static final EmissionModifier NATIVE = new EmissionModifier("native");
66 public static final EmissionModifier SYNCHRONIZED = new EmissionModifier("synchronized");
67
70 protected final boolean tagNativeBinding;
71 protected final boolean useNIODirectOnly;
72
73 // Exception type raised in the generated code if runtime checks fail
74 private final String runtimeExceptionType;
75 private final String unsupportedExceptionType;
76 private final boolean useNIOOnly;
77 private final boolean isNativeMethod;
78 private final boolean isUnimplemented;
79
80 private boolean emitBody;
81 private boolean eraseBufferAndArrayTypes;
82 private boolean isPrivateNativeMethod;
83 private boolean forDirectBufferImplementation;
84 private boolean forIndirectBufferAndArrayImplementation;
85
86 // Manually-specified prologue and epilogue code
87 protected List<String> prologue;
88 protected List<String> epilogue;
89
90 // A non-null value indicates that rather than returning a compound
91 // type accessor we are returning an array of such accessors; this
92 // expression is a MessageFormat string taking the names of the
93 // incoming Java arguments as parameters and computing as an int the
94 // number of elements of the returned array.
95 private String returnedArrayLengthExpression;
96 private boolean returnedArrayLengthExpressionOnlyForComments = false;
97
98 private final JavaCallbackEmitter javaCallbackEmitter;
99
100 // A suffix used to create a temporary outgoing array of Buffers to
101 // represent an array of compound type wrappers
102 private static final String COMPOUND_ARRAY_SUFFIX = "_buf_array_copy";
103
105 final CodeUnit unit,
106 final String runtimeExceptionType,
107 final String unsupportedExceptionType,
108 final boolean emitBody,
109 final boolean tagNativeBinding,
110 final boolean eraseBufferAndArrayTypes,
111 final boolean useNIOOnly,
112 final boolean useNIODirectOnly,
113 final boolean forDirectBufferImplementation,
114 final boolean forIndirectBufferAndArrayImplementation,
115 final boolean isUnimplemented,
116 final boolean isInterface,
117 final boolean isNativeMethod,
118 final boolean isPrivateNativeMethod, final JavaConfiguration configuration) {
119 super(binding, unit, isInterface, configuration);
120 this.runtimeExceptionType = runtimeExceptionType;
121 this.unsupportedExceptionType = unsupportedExceptionType;
122 this.emitBody = emitBody;
123 this.tagNativeBinding = tagNativeBinding;
124 this.eraseBufferAndArrayTypes = eraseBufferAndArrayTypes;
125 this.useNIOOnly = useNIOOnly;
126 this.useNIODirectOnly = useNIODirectOnly;
127 this.forDirectBufferImplementation = forDirectBufferImplementation;
128 this.forIndirectBufferAndArrayImplementation = forIndirectBufferAndArrayImplementation;
129 this.isUnimplemented = isUnimplemented;
130 this.isNativeMethod = isNativeMethod;
131 this.isPrivateNativeMethod = isPrivateNativeMethod;
132 if (isPrivateNativeMethod) {
134 } else {
136 }
137 final JavaCallbackInfo javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
138 if( null != javaCallback ) {
139 javaCallbackEmitter = new JavaCallbackEmitter(cfg, binding, javaCallback, appendSignature(new StringBuilder()).toString());
140 } else {
141 javaCallbackEmitter = null;
142 }
143 // !forImplementingMethodCall && !isInterface
144 }
145
147 super(arg);
148 runtimeExceptionType = arg.runtimeExceptionType;
149 unsupportedExceptionType = arg.unsupportedExceptionType;
150 emitBody = arg.emitBody;
152 eraseBufferAndArrayTypes = arg.eraseBufferAndArrayTypes;
153 useNIOOnly = arg.useNIOOnly;
155 isNativeMethod = arg.isNativeMethod;
156 isPrivateNativeMethod = arg.isPrivateNativeMethod;
157 forDirectBufferImplementation = arg.forDirectBufferImplementation;
158 forIndirectBufferAndArrayImplementation = arg.forIndirectBufferAndArrayImplementation;
159 isUnimplemented = arg.isUnimplemented;
160 prologue = arg.prologue;
161 epilogue = arg.epilogue;
162 returnedArrayLengthExpression = arg.returnedArrayLengthExpression;
163 returnedArrayLengthExpressionOnlyForComments = arg.returnedArrayLengthExpressionOnlyForComments;
164 javaCallbackEmitter = arg.javaCallbackEmitter;
165 }
166
167 public boolean isNativeMethod() { return isNativeMethod; }
168 public boolean isPrivateNativeMethod() { return isPrivateNativeMethod; }
169 public boolean isForDirectBufferImplementation() { return forDirectBufferImplementation; }
170 public boolean isForIndirectBufferAndArrayImplementation() { return forIndirectBufferAndArrayImplementation; }
171
172 @Override
173 public String getInterfaceName() {
174 return binding.getInterfaceName();
175 }
176 @Override
177 public String getImplName() {
178 return binding.getImplName();
179 }
180 @Override
181 public String getNativeName() {
182 return binding.getNativeName();
183 }
184
185 @Override
187 return binding.getCSymbol();
188 }
189
190 protected String getArgumentName(final int i) {
191 return binding.getArgumentName(i);
192 }
193
194 /** The type of exception (must subclass
195 <code>java.lang.RuntimeException</code>) raised if runtime
196 checks fail in the generated code. */
197 public String getRuntimeExceptionType() {
198 return runtimeExceptionType;
199 }
200
202 return unsupportedExceptionType;
203 }
204
205 /** If the underlying function returns an array (currently only
206 arrays of compound types are supported) as opposed to a pointer
207 to an object, this method should be called to provide a
208 MessageFormat string containing an expression that computes the
209 number of elements of the returned array. The parameters to the
210 MessageFormat expression are the names of the incoming Java
211 arguments. */
212 public void setReturnedArrayLengthExpression(final String expr) {
213 returnedArrayLengthExpression = expr;
214 returnedArrayLengthExpressionOnlyForComments = false;
215 }
216 protected void setReturnedArrayLengthExpression(final String expr, final boolean onlyForComments) {
217 returnedArrayLengthExpression = expr;
218 returnedArrayLengthExpressionOnlyForComments = onlyForComments;
219 }
221 return returnedArrayLengthExpressionOnlyForComments ? null : returnedArrayLengthExpression;
222 }
223 protected String getReturnedArrayLengthComment() {
224 return returnedArrayLengthExpression;
225 }
226
227 /** Sets the manually-generated prologue code for this emitter. */
228 public void setPrologue(final List<String> prologue) {
229 this.prologue = prologue;
230 }
231
232 /** Sets the manually-generated epilogue code for this emitter. */
233 public void setEpilogue(final List<String> epilogue) {
234 this.epilogue = epilogue;
235 }
236
237 /** Indicates whether this emitter will print only a signature, or
238 whether it will emit Java code for the body of the method as
239 well. */
240 public boolean signatureOnly() {
241 return !emitBody;
242 }
243
244 /** Accessor for subclasses. */
245 public void setEmitBody(final boolean emitBody) {
246 this.emitBody = emitBody;
247 }
248
249 /** Accessor for subclasses. */
250 public void setEraseBufferAndArrayTypes(final boolean erase) {
251 this.eraseBufferAndArrayTypes = erase;
252 }
253
254 /** Accessor for subclasses. */
255 public void setPrivateNativeMethod(final boolean v) {
256 this.isPrivateNativeMethod = v;
257 }
258
259 /** Accessor for subclasses. */
260 public void setForDirectBufferImplementation(final boolean direct) {
261 this.forDirectBufferImplementation = direct;
262 }
263
264 /** Accessor for subclasses. */
265 public void setForIndirectBufferAndArrayImplementation(final boolean indirect) {
266 this.forIndirectBufferAndArrayImplementation = indirect;
267 }
268
269 @Override
270 protected StringBuilder appendReturnType(final StringBuilder buf) {
271 return buf.append(getReturnTypeString(false));
272 }
273
274 protected String erasedTypeString(final JavaType type, final boolean skipBuffers) {
275 if (eraseBufferAndArrayTypes) {
276 if (type.isNIOBuffer()) {
277 if (!skipBuffers) {
278 // Direct buffers and arrays sent down as Object (but
279 // returned as e.g. ByteBuffer)
280 return "Object";
281 }
282 if (!type.isNIOByteBuffer()) {
283 // Return buffer requiring change of view from ByteBuffer to e.g. LongBuffer
284 return "ByteBuffer";
285 }
286 } else if (type.isPrimitiveArray()) {
287 if (!skipBuffers) {
288 // Direct buffers and arrays sent down as Object (but
289 // returned as e.g. ByteBuffer)
290 return "Object";
291 }
292 } else if (type.isNIOBufferArray()) {
293 // Arrays of direct Buffers sent down as Object[]
294 // (Note we don't yet support returning void**)
295 return "Object[]";
296 } else if (type.isCompoundTypeWrapper()) {
297 // Compound type wrappers are unwrapped to ByteBuffer
298 return "ByteBuffer";
299 } else if (type.isArrayOfCompoundTypeWrappers()) {
300 if (skipBuffers) {
301 return "ByteBuffer";
302 } else {
303 // In the case where this is called with a false skipBuffers
304 // argument we want to erase the array of compound type
305 // wrappers to ByteBuffer[]
306 return "ByteBuffer[]";
307 }
308 }
309 }
310 String name = type.getName();
311 if( null == name ) {
312 throw new IllegalArgumentException("null type name: "+type.getDebugString());
313 }
314 final int index = name.lastIndexOf('.')+1; // always >= 0
315 name = name.substring(index);
316
318 // We don't want to bake the array specification into the type name
319 return name + "[]";
320 }
321 return name;
322 }
323
324 protected String getReturnTypeString(final boolean skipArray) {
325 // The first arm of the "if" clause is used by the glue code
326 // generation for arrays of compound type wrappers
327 if (skipArray ||
328 // The following arm is used by most other kinds of return types
331 // The following arm is used specifically to get the splitting up
332 // of one returned ByteBuffer into an array of compound type
333 // wrappers to work (e.g., XGetVisualInfo)
334 (eraseBufferAndArrayTypes &&
338 }
339 return erasedTypeString(binding.getJavaReturnType(), true) + "[]";
340 }
341
342 @Override
343 protected StringBuilder appendName(final StringBuilder buf) {
344 if (isPrivateNativeMethod) {
345 buf.append(getNativeImplMethodName());
346 } else if( isInterface()) {
347 buf.append(getInterfaceName());
348 } else {
349 buf.append(getImplName());
350 }
351 return buf;
352 }
353
354 @Override
355 protected int appendArguments(final StringBuilder buf) {
356 boolean needComma = false;
357 int numEmitted = 0;
358
360 buf.append("final Class<?> _clazzBuffers");
361 ++numEmitted;
362 needComma = true;
363 }
364 if (isPrivateNativeMethod && binding.hasContainingType()) {
365 // Always emit outgoing "this" argument
366 if (needComma) {
367 buf.append(", ");
368 }
369 buf.append("ByteBuffer ");
370 buf.append(javaThisArgumentName());
371 ++numEmitted;
372 needComma = true;
373 }
374
375 for (int i = 0; i < binding.getNumArguments(); i++) {
376 final JavaType type = binding.getJavaArgumentType(i);
377 if (type.isVoid()) {
378 // Make sure this is the only param to the method; if it isn't,
379 // there's something wrong with our parsing of the headers.
380 if (binding.getNumArguments() != 1) {
381 throw new InternalError(
382 "\"void\" argument type found in " +
383 "multi-argument function \"" + binding + "\"");
384 }
385 continue;
386 }
387
388 if ( type.isJNIEnv() || type.isPascalLen() || binding.isArgumentThisPointer(i) ) {
389 // Don't need to expose these at the Java level
390 continue;
391 }
392
393 if (needComma) {
394 buf.append(", ");
395 }
396
397 buf.append(erasedTypeString(type, false));
398 buf.append(" ");
399 buf.append(getArgumentName(i));
400
401 ++numEmitted;
402 needComma = true;
403
404 // Add Buffer and array index offset arguments after each associated argument
405 if (forDirectBufferImplementation || forIndirectBufferAndArrayImplementation) {
406 if (type.isNIOBuffer()) {
407 buf.append(", int " + byteOffsetArgName(i));
408 if(!useNIODirectOnly) {
409 buf.append(", boolean " + isNIOArgName(i));
410 }
411 } else if (type.isNIOBufferArray()) {
412 buf.append(", int[] " + byteOffsetArrayArgName(i));
413 }
414 }
415
416 // Add offset argument after each primitive array
417 if (type.isPrimitiveArray()) {
418 if(useNIOOnly) {
419 throw new RuntimeException("NIO[Direct]Only "+binding+" is set, but "+getArgumentName(i)+" is a primitive array");
420 }
421 buf.append(", int " + offsetArgName(i));
422 }
423 }
425 null != javaCallbackEmitter )
426 {
427 if (needComma) {
428 buf.append(", ");
429 }
430 numEmitted += javaCallbackEmitter.appendJavaAdditionalJNIParameter(buf);
431 }
432 return numEmitted;
433 }
434
435 protected String getNativeImplMethodName() {
436 return binding.getImplName() + ( useNIODirectOnly ? "0" : "1" );
437 }
438
439 protected String byteOffsetArgName(final int i) {
441 }
442
443 protected static String byteOffsetArgName(final String s) {
444 return s + "_byte_offset";
445 }
446
447 protected String isNIOArgName(final int i) {
449 }
450
451 protected String isNIOArgName(final String s) {
452 return s + "_is_direct";
453 }
454
455 protected String byteOffsetArrayArgName(final int i) {
456 return getArgumentName(i) + "_byte_offset_array";
457 }
458
459 protected String offsetArgName(final int i) {
460 return getArgumentName(i) + "_offset";
461 }
462
463 @Override
464 protected void emitAdditionalCode() {
465 if( null != javaCallbackEmitter && !isPrivateNativeMethod ) {
466 javaCallbackEmitter.emitJavaAdditionalCode(unit, isInterface());
467 }
468 }
469
470 @Override
471 protected void emitBody() {
472 if (!emitBody) {
473 unit.emitln(";");
474 } else {
475 final MethodBinding mBinding = getBinding();
476 unit.emitln(" {");
477 unit.emitln();
478 if (isUnimplemented) {
479 unit.emitln(" throw new " + getUnsupportedExceptionType() + "(\"Unimplemented\");");
480 } else {
482 emitPreCallSetup(mBinding);
483 //emitReturnVariableSetup(binding, writer);
485 }
486 unit.emitln(" }");
487 }
488 }
489
490 protected void emitPrologueOrEpilogue(final List<String> code) {
491 if (code != null) {
492 final String[] argumentNames = argumentNameArray();
493 for (final String str : code) {
494 try {
495 final MessageFormat fmt = new MessageFormat(str);
496 unit.emitln(" " + fmt.format(argumentNames));
497 } catch (final IllegalArgumentException e) {
498 // (Poorly) handle case where prologue / epilogue contains blocks of code with braces
499 unit.emitln(" " + str);
500 }
501 }
502 }
503 }
504
505 protected void emitPreCallSetup(final MethodBinding binding) {
508 }
509
511 // Check lengths of any incoming arrays if necessary
512 for (int i = 0; i < binding.getNumArguments(); i++) {
513 final Type type = binding.getCArgumentType(i);
514 final JavaType javaType = binding.getJavaArgumentType(i);
515 if ( type.isArray() ) { // FIXME: Compound and Compound-Arrays
516 // Simply add a range check upfront
517 final ArrayType arrayType = type.asArray();
518 if (javaType.isNIOBuffer()) {
519 unit.emitln(" if ( Buffers.remainingElem("+getArgumentName(i)+") < " + arrayType.getLength() + ")");
520 } else {
521 unit.emitln(" if ( "+getArgumentName(i)+".length < " + arrayType.getLength() + ")");
522 }
523 unit.emit(" throw new " + getRuntimeExceptionType() +
524 "(\"Array \\\"" + getArgumentName(i) +
525 "\\\" length (\" + ");
526 if (javaType.isNIOBuffer()) {
527 unit.emit("Buffers.remainingElem("+getArgumentName(i)+")");
528 } else {
529 unit.emit(getArgumentName(i)+".length");
530 }
531 unit.emitln("+ \") was less than the required (" + arrayType.getLength() + ")\");");
532 }
533 if (javaType.isNIOBuffer()) {
534 if (useNIODirectOnly) {
535 unit.emitln(" if (!Buffers.isDirect(" + getArgumentName(i) + "))");
536 unit.emitln(" throw new " + getRuntimeExceptionType() + "(\"Argument \\\"" +
537 getArgumentName(i) + "\\\" is not a direct buffer\");");
538 } else {
539 unit.emitln(" final boolean " + isNIOArgName(i) + " = Buffers.isDirect(" + getArgumentName(i) + ");");
540 }
541 } else if (javaType.isNIOBufferArray()) {
542 // All buffers passed down in an array of NIO buffers must be direct
543 final String argName = getArgumentName(i);
544 final String arrayName = byteOffsetArrayArgName(i);
545 unit.emitln(" final int[] " + arrayName + " = new int[" + argName + ".length];");
546 // Check direct buffer properties of all buffers within
547 unit.emitln(" if (" + argName + " != null) {");
548 unit.emitln(" for (int _ctr = 0; _ctr < " + argName + ".length; _ctr++) {");
549 unit.emitln(" if (!Buffers.isDirect(" + argName + "[_ctr])) {");
550 unit.emitln(" throw new " + getRuntimeExceptionType() +
551 "(\"Element \" + _ctr + \" of argument \\\"" +
552 getArgumentName(i) + "\\\" was not a direct buffer\");");
553 unit.emitln(" }");
554 // get the Buffer Array offset values and save them into another array to send down to JNI
555 unit.emit (" " + arrayName + "[_ctr] = Buffers.getDirectBufferByteOffset(");
556 unit.emitln(argName + "[_ctr]);");
557 unit.emitln(" }");
558 unit.emitln(" }");
559 } else if (javaType.isPrimitiveArray()) {
560 final String argName = getArgumentName(i);
561 final String offsetArg = offsetArgName(i);
562 unit.emitln(" if(" + argName + " != null && " + argName + ".length <= " + offsetArg + ")");
563 unit.emit (" throw new " + getRuntimeExceptionType());
564 unit.emitln("(\"array offset argument \\\"" + offsetArg + "\\\" (\" + " + offsetArg +
565 " + \") equals or exceeds array length (\" + " + argName + ".length + \")\");");
566 }
567 }
568 }
569
571 // If the method binding uses outgoing arrays of compound type
572 // wrappers, we need to generate a temporary copy of this array
573 // into a ByteBuffer[] for processing by the native code
574 if (binding.signatureUsesArraysOfCompoundTypeWrappers()) {
575 for (int i = 0; i < binding.getNumArguments(); i++) {
576 final JavaType javaType = binding.getJavaArgumentType(i);
577 if (javaType.isArrayOfCompoundTypeWrappers()) {
578 final String argName = getArgumentName(i);
579 final String tempArrayName = argName + COMPOUND_ARRAY_SUFFIX;
580 unit.emitln(" final ByteBuffer[] " + tempArrayName + " = new ByteBuffer[" + argName + ".length];");
581 unit.emitln(" for (int _ctr = 0; _ctr < + " + argName + ".length; _ctr++) {");
582 unit.emitln(" " + javaType.getName() + " _tmp = " + argName + "[_ctr];");
583 unit.emitln(" " + tempArrayName + "[_ctr] = ((_tmp == null) ? null : _tmp.getBuffer());");
584 unit.emitln(" }");
585 }
586 }
587 }
588 }
589
590 protected void emitCall(final MethodBinding binding) {
592 unit.emit("(");
594 unit.emit(");");
595 }
596
597
599 final JavaType returnType = binding.getJavaReturnType();
600
601 boolean needsResultAssignment = false;
602
603 if( null != javaCallbackEmitter ) {
604 javaCallbackEmitter.emitJavaSetFuncPreCall(unit);
605 }
606 if (!returnType.isVoid()) {
607 unit.emit(" ");
608 if (returnType.isCompoundTypeWrapper() ||
609 returnType.isNIOBuffer()) {
610 unit.emitln("final ByteBuffer _res;");
611 needsResultAssignment = true;
612 } else if (returnType.isArrayOfCompoundTypeWrappers()) {
613 unit.emitln("final ByteBuffer[] _res;");
614 needsResultAssignment = true;
615 } else if (((epilogue != null) && (epilogue.size() > 0)) ||
616 binding.signatureUsesArraysOfCompoundTypeWrappers()) {
617 unit.emit("final ");
619 unit.emitln(" _res;");
620 needsResultAssignment = true;
621 }
622 }
623
624 if (needsResultAssignment) {
625 unit.emit(" _res = ");
626 } else {
627 unit.emit(" ");
628 if (!returnType.isVoid()) {
629 unit.emit("return ");
630 }
631 }
632
634 unit.emitln();
635
638 if (needsResultAssignment) {
640 }
641 }
642
644 boolean needComma = false;
645 int numArgsEmitted = 0;
646
648 unit.emit("com.jogamp.common.nio.Buffers.class");
649 needComma = true;
650 ++numArgsEmitted;
651 }
653 // Emit this pointer
655 if (needComma) {
656 unit.emit(", ");
657 }
658 unit.emit("getBuffer()");
659 needComma = true;
660 ++numArgsEmitted;
661 }
662 for (int i = 0; i < binding.getNumArguments(); i++) {
663 final JavaType type = binding.getJavaArgumentType(i);
664 if (type.isJNIEnv() || type.isPascalLen() || binding.isArgumentThisPointer(i)) {
665 // Don't need to expose these at the Java level
666 continue;
667 }
668
669 if (type.isVoid()) {
670 // Make sure this is the only param to the method; if it isn't,
671 // there's something wrong with our parsing of the headers.
672 assert(binding.getNumArguments() == 1);
673 continue;
674 }
675
676 if (needComma) {
677 unit.emit(", ");
678 }
679
680 if (type.isCompoundTypeWrapper()) {
681 unit.emit("((");
682 }
683
684 if (type.isNIOBuffer()) {
685 if(type.isNIOPointerBuffer()) {
686 if (useNIODirectOnly) {
687 unit.emit( getArgumentName(i)+ " != null ? " + getArgumentName(i) + ".getBuffer() : null");
688 } else {
689 unit.emit( isNIOArgName(i) + " ? ( " + getArgumentName(i)+ " != null ? " + getArgumentName(i) + ".getBuffer() : null )");
690 unit.emit( " : Buffers.getArray(" + getArgumentName(i) + ")" );
691 }
692 } else {
693 if (useNIODirectOnly) {
695 } else {
696 unit.emit( isNIOArgName(i) + " ? " + getArgumentName(i) + " : Buffers.getArray(" + getArgumentName(i) + ")" );
697 }
698 }
699 } else if (type.isArrayOfCompoundTypeWrappers()) {
700 unit.emit(getArgumentName(i) + COMPOUND_ARRAY_SUFFIX);
701 } else {
703 }
704
705 if (type.isCompoundTypeWrapper()) {
706 unit.emit(" == null) ? null : ");
708 unit.emit(".getBuffer())");
709 }
710
711 if (type.isNIOBuffer()) {
712 if (useNIODirectOnly) {
713 unit.emit( ", Buffers.getDirectBufferByteOffset(" + getArgumentName(i) + ")");
714 } else {
715 unit.emit( ", " + isNIOArgName(i) + " ? Buffers.getDirectBufferByteOffset(" + getArgumentName(i) + ")");
716 unit.emit( " : Buffers.getIndirectBufferByteOffset(" + getArgumentName(i) + ")");
717 }
718 } else if (type.isNIOBufferArray()) {
720 } else if (type.isPrimitiveArray()) {
721 if(type.isFloatArray()) {
722 unit.emit(", Buffers.SIZEOF_FLOAT * ");
723 } else if(type.isDoubleArray()) {
724 unit.emit(", Buffers.SIZEOF_DOUBLE * ");
725 } else if(type.isByteArray()) {
726 unit.emit(", ");
727 } else if(type.isLongArray()) {
728 unit.emit(", Buffers.SIZEOF_LONG * ");
729 } else if(type.isShortArray()) {
730 unit.emit(", Buffers.SIZEOF_SHORT * ");
731 } else if(type.isIntArray()) {
732 unit.emit(", Buffers.SIZEOF_INT * ");
733 } else {
734 throw new GlueGenException("Unsupported type for calculating array offset argument for " +
735 getArgumentName(i) +
736 " -- error occurred while processing Java glue code for " + getCSymbol().getAliasedString(),
737 getCSymbol().getASTLocusTag());
738 }
740 }
741
742 if (type.isNIOBuffer()) {
743 if (!useNIODirectOnly) {
744 unit.emit( ", " + isNIOArgName(i) );
745 }
746 } else if (type.isPrimitiveArray()) {
747 if (useNIOOnly) {
748 throw new GlueGenException("NIO[Direct]Only "+binding+" is set, but "+getArgumentName(i)+" is a primitive array",
749 getCSymbol().getASTLocusTag());
750 }
751 unit.emit( ", false");
752 }
753
754 needComma = true;
755 ++numArgsEmitted;
756 }
757 if( null != javaCallbackEmitter ) {
758 if (needComma) {
759 unit.emit(", ");
760 }
761 final StringBuilder buf = new StringBuilder();
762 numArgsEmitted += javaCallbackEmitter.appendJavaAdditionalJNIArguments(buf);
763 unit.emit(buf.toString());
764 }
765 return numArgsEmitted;
766 }
767
769 if (binding.signatureUsesArraysOfCompoundTypeWrappers()) {
770 // For each such array, we need to take the ByteBuffer[] that
771 // came back from the C method invocation and wrap the
772 // ByteBuffers back into the wrapper types
773 for (int i = 0; i < binding.getNumArguments(); i++) {
774 final JavaType javaArgType = binding.getJavaArgumentType(i);
775 if ( javaArgType.isArrayOfCompoundTypeWrappers() && !javaArgType.getElementCType().isBaseTypeConst() ) {
776 final String argName = binding.getArgumentName(i);
777 unit.emitln(" for (int _ctr = 0; _ctr < " + argName + ".length; _ctr++) {");
778 unit.emitln(" if ((" + argName + "[_ctr] == null && " + argName + COMPOUND_ARRAY_SUFFIX + "[_ctr] == null) ||");
779 unit.emitln(" (" + argName + "[_ctr] != null && " + argName + "[_ctr].getBuffer() == " + argName + COMPOUND_ARRAY_SUFFIX + "[_ctr])) {");
780 unit.emitln(" // No copy back needed");
781 unit.emitln(" } else {");
782 unit.emitln(" if (" + argName + COMPOUND_ARRAY_SUFFIX + "[_ctr] == null) {");
783 unit.emitln(" " + argName + "[_ctr] = null;");
784 unit.emitln(" } else {");
785 unit.emitln(" " + argName + "[_ctr] = " + javaArgType.getName() + ".create(" + argName + COMPOUND_ARRAY_SUFFIX + "[_ctr]);");
786 unit.emitln(" }");
787 unit.emitln(" }");
788 unit.emitln(" }");
789 }
790 }
791 }
792 }
793
795 final JavaType returnType = binding.getJavaReturnType();
796
797 if (returnType.isCompoundTypeWrapper()) {
798 // Details are handled in JavaEmitter's struct handling!
799 unit.emitln(" if (_res == null) return null;");
800 unit.emitln(" return " + returnType.getName() + ".create(Buffers.nativeOrder(_res));");
801 } else if (returnType.isNIOBuffer()) {
802 unit.emitln(" if (_res == null) return null;");
803 unit.emitln(" Buffers.nativeOrder(_res);");
804 if (!returnType.isNIOByteBuffer()) {
805 // See whether we have to expand pointers to longs
806 if (getBinding().getCReturnType().pointerDepth() >= 2) {
807 if (returnType.isNIOPointerBuffer()) {
808 unit.emitln(" return PointerBuffer.wrap(_res);");
809 } else if (returnType.isNIOLongBuffer()) {
810 unit.emitln(" return _res.asLongBuffer();");
811 } else {
812 throw new GlueGenException("While emitting glue code for " + getCSymbol().getAliasedString() +
813 ": can not legally make pointers opaque to anything but PointerBuffer or LongBuffer/long",
814 getCSymbol().getASTLocusTag());
815 }
816 } else if (getBinding().getCReturnType().pointerDepth() == 1 && returnType.isNIOLongBuffer()) {
817 unit.emitln(" return _res.asLongBuffer();");
818 } else {
819 final String returnTypeName = returnType.getName().substring("java.nio.".length());
820 unit.emitln(" return _res.as" + returnTypeName + "();");
821 }
822 } else {
823 unit.emitln(" return _res;");
824 }
825 } else if (returnType.isArrayOfCompoundTypeWrappers()) {
826 unit.emitln(" if (_res == null) return null;");
827 unit.emitln(" final " + getReturnTypeString(false) + " _retarray = new " + getReturnTypeString(true) + "[_res.length];");
828 unit.emitln(" for (int _count = 0; _count < _res.length; _count++) {");
829 unit.emitln(" _retarray[_count] = " + getReturnTypeString(true) + ".create(_res[_count]);");
830 unit.emitln(" }");
831 unit.emitln(" return _retarray;");
832 } else {
833 // Assume it's a primitive type or other type we don't have to
834 // do any conversion on
835 unit.emitln(" return _res;");
836 }
837 }
838
839 protected String[] argumentNameArray() {
840 final String[] argumentNames = new String[binding.getNumArguments()];
841 for (int i = 0; i < binding.getNumArguments(); i++) {
842 argumentNames[i] = getArgumentName(i);
844 // Add on _offset argument in comma-separated expression
845 argumentNames[i] = argumentNames[i] + ", " + offsetArgName(i);
846 }
847 }
848 return argumentNames;
849 }
850
851 public static String javaThisArgumentName() {
852 return "jthis0";
853 }
854
855 @Override
856 protected String getCommentStartString() { return "/** "; }
857
858 @Override
859 protected String getCommentEndString() {
860 final StringBuilder sb = new StringBuilder();
861 final String methodName = binding.getName();
862 final List<String> methodDocs = cfg.javadocForMethod(methodName);
863 for (final Iterator<String> iter = methodDocs.iterator(); iter.hasNext(); ) {
864 sb.append(JavaConfiguration.NEWLINE).append(getBaseIndentString()).append(iter.next());
865 }
866 if( methodDocs.size() > 0 ) {
867 sb.append(JavaConfiguration.NEWLINE).append(getBaseIndentString());
868 }
869 sb.append(" */");
870 return sb.toString();
871 }
872
873 @Override
874 protected String getBaseIndentString() { return " "; }
875
876 /**
877 * Class that emits a generic comment for JavaMethodBindingEmitters; the comment
878 * includes the C signature of the native method that is being bound by the
879 * emitter java method.
880 */
881 protected class DefaultCommentEmitter implements CommentEmitter {
882 protected void emitAliasedDocNamesComment(final AliasedSymbol sym, final PrintWriter writer) {
883 writer.print(emitAliasedDocNamesComment(sym, new StringBuilder()).toString());
884 }
885 protected StringBuilder emitAliasedDocNamesComment(final AliasedSymbol sym, final StringBuilder sb) {
886 final Set<String> aliases = cfg.getAliasedDocNames(sym);
887 if (aliases != null && aliases.size() > 0 ) {
888 int i=0;
889 sb.append("Alias for: <code>");
890 for (final String alias : aliases) {
891 if(0 < i) {
892 sb.append("</code>, <code>");
893 }
894 sb.append(alias);
895 i++;
896 }
897 sb.append("</code>");
898 }
899 return sb;
900 }
901
902 @Override
903 public void emit(final FunctionEmitter emitter, final PrintWriter writer) {
904 emitBeginning(emitter, writer);
906 final String arrayLengthExpr = getReturnedArrayLengthComment();
907 if( null != arrayLengthExpr ) {
908 writer.print(", covering an array of length <code>"+arrayLengthExpr+"</code>");
909 }
910 emitEnding(emitter, writer);
911 }
912 protected void emitBeginning(final FunctionEmitter emitter, final PrintWriter writer) {
913 writer.print("Entry point to C language function: ");
914 }
915 protected void emitBindingCSignature(final MethodBinding binding, final PrintWriter writer) {
916 final FunctionSymbol funcSym = binding.getCSymbol();
917 writer.print("<code>");
918 writer.print(funcSym.toString(tagNativeBinding));
919 writer.print("</code><br>");
920 emitAliasedDocNamesComment(funcSym, writer);
921 }
922 protected void emitEnding(final FunctionEmitter emitter, final PrintWriter writer) {
923 // If argument type is a named enum, then emit a comment detailing the
924 // acceptable values of that enum.
925 // If we're emitting a direct buffer variant only, then declare
926 // that the NIO buffer arguments must be direct.
927 final MethodBinding binding = ((JavaMethodBindingEmitter)emitter).getBinding();
928 for (int i = 0; i < binding.getNumArguments(); i++) {
929 final Type type = binding.getCArgumentType(i);
930 final JavaType javaType = binding.getJavaArgumentType(i);
931 // don't emit param comments for anonymous enums, since we can't
932 // distinguish between the values found within multiple anonymous
933 // enums in the same C translation unit.
934 if (type.isEnum() && !HeaderParser.ANONYMOUS_ENUM_NAME.equals(type.getName())) {
935 final EnumType enumType = (EnumType)type;
936 writer.println();
937 writer.print(emitter.getBaseIndentString());
938 writer.print(" ");
939 writer.print("@param ");
940 writer.print(getArgumentName(i));
941 writer.print(" valid values are: <code>");
942 for (int j = 0; j < enumType.getNumEnumerates(); ++j) {
943 if (j>0) writer.print(", ");
944 writer.print(enumType.getEnum(j).getName());
945 }
946 writer.println("</code>");
947 } else if (javaType.isNIOBuffer()) {
948 writer.println();
949 writer.print(emitter.getBaseIndentString());
950 writer.print(" ");
951 writer.print("@param ");
952 writer.print(getArgumentName(i));
953 if (useNIODirectOnly) {
954 writer.print(" a direct only {@link " + javaType.getName() + "}");
955 } else {
956 writer.print(" a direct or array-backed {@link " + javaType.getName() + "}");
957 }
958 }
959 }
960 }
961 }
962
964 @Override
965 protected void emitBeginning(final FunctionEmitter emitter, final PrintWriter writer) {
966 writer.print("Interface to C language function: <br> ");
967 }
968 }
969}
970
General code unit (a generated C or Java source file), covering multiple FunctionEmitter allowing to ...
Definition: CodeUnit.java:42
void emit(final String s)
Definition: CodeUnit.java:81
Generic function emitter to produce C (JNI) or Java code stubs to its CodeUnit, invoking a native fun...
void setCommentEmitter(final CommentEmitter cEmitter)
Set the object that will emit the comment for this function.
StringBuilder appendSignature(final StringBuilder buf)
boolean hasModifier(final EmissionModifier m)
A generic exception for Jogamp errors used throughout the binding as a substitute for RuntimeExceptio...
void emitJavaSetFuncPreCall(final CodeUnit unit)
final int appendJavaAdditionalJNIParameter(final StringBuilder buf)
void emitJavaAdditionalCode(final CodeUnit unit, final boolean isInterface)
final int appendJavaAdditionalJNIArguments(final StringBuilder buf)
JavaCallback compile time information, produced by JavaEmitter#beginFunctions(TypeDictionary,...
Parses and provides access to the contents of .cfg files for the JavaEmitter.
Set< String > getAliasedDocNames(final AliasedSymbol symbol)
Return a set of aliased-name for comment in docs.
List< String > javadocForMethod(final String methodName)
Class that emits a generic comment for JavaMethodBindingEmitters; the comment includes the C signatur...
void emitEnding(final FunctionEmitter emitter, final PrintWriter writer)
void emitBeginning(final FunctionEmitter emitter, final PrintWriter writer)
void emit(final FunctionEmitter emitter, final PrintWriter writer)
Emit the body of a comment for the specified function; do NOT emit the open (e.g.,...
void emitAliasedDocNamesComment(final AliasedSymbol sym, final PrintWriter writer)
StringBuilder emitAliasedDocNamesComment(final AliasedSymbol sym, final StringBuilder sb)
void emitBindingCSignature(final MethodBinding binding, final PrintWriter writer)
void emitBeginning(final FunctionEmitter emitter, final PrintWriter writer)
Emits the Java-side component (interface and.or implementation) of the Java<->C JNI binding to its Co...
void setEpilogue(final List< String > epilogue)
Sets the manually-generated epilogue code for this emitter.
void setForDirectBufferImplementation(final boolean direct)
Accessor for subclasses.
void setEmitBody(final boolean emitBody)
Accessor for subclasses.
void setReturnedArrayLengthExpression(final String expr)
If the underlying function returns an array (currently only arrays of compound types are supported) a...
String getRuntimeExceptionType()
The type of exception (must subclass java.lang.RuntimeException) raised if runtime checks fail in the...
void emitReturnVariableSetupAndCall(final MethodBinding binding)
int appendArguments(final StringBuilder buf)
Returns the number of arguments emitted.
void emitPostCallCleanup(final MethodBinding binding)
void emitCompoundArrayCopies(final MethodBinding binding)
JavaMethodBindingEmitter(final JavaMethodBindingEmitter arg)
StringBuilder appendReturnType(final StringBuilder buf)
String erasedTypeString(final JavaType type, final boolean skipBuffers)
void setPrologue(final List< String > prologue)
Sets the manually-generated prologue code for this emitter.
void emitCallResultReturn(final MethodBinding binding)
void emitPreCallSetup(final MethodBinding binding)
void setForIndirectBufferAndArrayImplementation(final boolean indirect)
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.
void setReturnedArrayLengthExpression(final String expr, final boolean onlyForComments)
JavaMethodBindingEmitter(final MethodBinding binding, final CodeUnit unit, final String runtimeExceptionType, final String unsupportedExceptionType, final boolean emitBody, final boolean tagNativeBinding, final boolean eraseBufferAndArrayTypes, final boolean useNIOOnly, final boolean useNIODirectOnly, final boolean forDirectBufferImplementation, final boolean forIndirectBufferAndArrayImplementation, final boolean isUnimplemented, final boolean isInterface, final boolean isNativeMethod, final boolean isPrivateNativeMethod, final JavaConfiguration configuration)
StringBuilder appendName(final StringBuilder buf)
void emitPrologueOrEpilogue(final List< String > code)
void emitArrayLengthAndNIOBufferChecks(final MethodBinding binding)
void setEraseBufferAndArrayTypes(final boolean erase)
Accessor for subclasses.
Describes a java-side representation of a type that is used to represent the same data on both the Ja...
Definition: JavaType.java:54
String getName()
Returns the Java type name corresponding to this type.
Definition: JavaType.java:339
boolean isArrayOfCompoundTypeWrappers()
Definition: JavaType.java:709
Represents the binding of a C function to a Java method.
String getArgumentName(final int i)
Returns either the argument name specified by the underlying FunctionSymbol or a fabricated argument ...
String getImplName()
Returns the FunctionSymbol's name for the implementation, which is the current aliased API name per d...
JavaType getContainingType()
Retrieves the containing type of this MethodBinding if it is for a function pointer contained in a st...
JavaType getJavaArgumentType(final int i)
String getInterfaceName()
Returns the FunctionSymbol's current aliased API name for the interface.
String getName()
Returns the FunctionSymbol's current aliased API name.
boolean hasContainingType()
Indicates whether this MethodBinding is for a function pointer contained in a struct,...
boolean isArgumentThisPointer(final int i)
Indicates whether the ith argument to this MethodBinding is actually a "this" pointer.
FunctionSymbol getCSymbol()
Returns the FunctionSymbol.
String getNativeName()
Returns the FunctionSymbol's name for the native function which is the original C API name per defaul...
static final String ANONYMOUS_ENUM_NAME
Name assigned to a anonymous EnumType (e.g., "enum { ... }").
Describes enumerated types.
Definition: EnumType.java:54
int getNumEnumerates()
Number of enumerates defined in this enum.
Definition: EnumType.java:189
Enumerator getEnum(final int i)
Fetch ith (0..getNumEnumerates() - 1) Enumerator.
Definition: EnumType.java:194
Describes a function symbol, which includes the name and type.
final boolean isArray()
Indicates whether this is an ArrayType.
Definition: Type.java:409
final boolean isBaseTypeConst()
Checks the base type of pointer-to-pointer, pointer, array or plain for const-ness.
Definition: Type.java:440
final String getName()
Returns the name of this type.
Definition: Type.java:142
final boolean isEnum()
Indicates whether this is an EnumType.
Definition: Type.java:401
ArrayType asArray()
Casts this to an ArrayType or returns null if not an ArrayType.
Definition: Type.java:388