GlueGen v2.6.0-rc-20250712
GlueGen, Native Binding Generator for Java™ (public API).
CMethodBindingEmitter.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 static java.util.logging.Level.INFO;
44
45import java.io.PrintWriter;
46import java.text.MessageFormat;
47import java.util.List;
48
49import com.jogamp.common.os.MachineDataInfo;
50import com.jogamp.gluegen.JavaConfiguration.JavaCallbackInfo;
51import com.jogamp.gluegen.Logging.LoggerIf;
52import com.jogamp.gluegen.cgram.types.ArrayType;
53import com.jogamp.gluegen.cgram.types.FunctionSymbol;
54import com.jogamp.gluegen.cgram.types.PointerType;
55import com.jogamp.gluegen.cgram.types.Type;
56
57/** Emits the C-side component of the Java<->C JNI binding to its {@link CodeUnit}, see {@link FunctionEmitter}. */
59
61
62 protected static final String arrayResLength = "_array_res_length";
63 protected static final String arrayRes = "_array_res";
64 protected static final String arrayIdx = "_array_idx";
65
66 protected final LoggerIf LOG;
67
68 /** Name of the package in which the corresponding Java method resides.*/
69 private final String packageName;
70
71 /** Name of the class in which the corresponding Java method resides.*/
72 private final String className;
73
74 /**
75 * Whether or not the Java<->C JNI binding for this emitter's MethodBinding
76 * is overloaded.
77 */
78 private final boolean isOverloadedBinding;
79
80 /**
81 * Whether or not the Java-side of the Java<->C JNI binding for this
82 * emitter's MethodBinding is static.
83 */
84 private final boolean isJavaMethodStatic;
85
86 // Flags which change various aspects of glue code generation
87 protected boolean forImplementingMethodCall;
89
90 /**
91 * Optional List of Strings containing temporary C variables to declare.
92 */
93 private List<String> temporaryCVariableDeclarations;
94
95 /**
96 * Optional List of Strings containing assignments to temporary C variables
97 * to make after the call is completed.
98 */
99 private List<String> temporaryCVariableAssignments;
100
101 /**
102 * Capacity of the return value in the event that it is encapsulated in a
103 * java.nio.Buffer. Is ignored if binding.getJavaReturnType().isNIOBuffer()
104 * == false;
105 */
106 private MessageFormat returnValueCapacityExpression = null;
107
108 /**
109 * Length of the returned array. Is ignored if
110 * binding.getJavaReturnType().isArray() is false.
111 */
112 private MessageFormat returnValueLengthExpression = null;
113
114 protected static final String STRING_CHARS_PREFIX = "_strchars_";
115
116 // We need this in order to compute sizes of certain types
118
119 private final CMethodBindingEmitter jcbFuncCMethodEmitter;
120 private final JavaCallbackEmitter javaCallbackEmitter;
121
122 /**
123 * Constructs an emitter for the specified binding, and sets a default
124 * comment emitter that will emit the signature of the C function that is
125 * being bound.
126 */
128 final CodeUnit unit,
129 final String javaPackageName,
130 final String javaClassName,
131 final boolean isOverloadedBinding,
132 final boolean isJavaMethodStatic,
133 final boolean forImplementingMethodCall,
136 final JavaConfiguration configuration)
137 {
138 super(binding, unit, false, configuration);
139 LOG = Logging.getLogger(CMethodBindingEmitter.class.getPackage().getName(), CMethodBindingEmitter.class.getSimpleName());
140
141 assert(binding != null);
142 assert(javaClassName != null);
143 assert(javaPackageName != null);
144
145 this.packageName = javaPackageName;
146 this.className = javaClassName;
147 this.isOverloadedBinding = isOverloadedBinding;
148 this.isJavaMethodStatic = isJavaMethodStatic;
149
150 this.forImplementingMethodCall = forImplementingMethodCall;
151 this.forIndirectBufferAndArrayImplementation = forIndirectBufferAndArrayImplementation;
152 this.machDesc = machDesc;
153
154 final JavaCallbackInfo javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
155 if( null != javaCallback ) {
156 // jcbNativeBasename = CodeGenUtils.capitalizeString( javaCallback.setFuncName+javaCallback.cbSimpleClazzName.replace("_", "") );
157 jcbFuncCMethodEmitter = new CMethodBindingEmitter(javaCallback.cbFuncBinding,
158 unit, javaPackageName, javaClassName, isOverloadedBinding,
159 isJavaMethodStatic, forImplementingMethodCall,
161 javaCallbackEmitter = new JavaCallbackEmitter(cfg, binding, javaCallback, null);
162 } else {
163 jcbFuncCMethodEmitter = null;
164 javaCallbackEmitter = null;
165 }
167 }
168
169 @Override
170 public String getInterfaceName() {
171 return binding.getInterfaceName();
172 }
173 @Override
174 public String getImplName() {
175 return binding.getImplName();
176 }
177 @Override
178 public String getNativeName() {
179 return binding.getNativeName();
180 }
181
182 @Override
184 return binding.getCSymbol();
185 }
186
187 /**
188 * Get the expression for the capacity of the returned java.nio.Buffer.
189 */
190 public final MessageFormat getReturnValueCapacityExpression() {
191 return returnValueCapacityExpression;
192 }
193
194 /**
195 * If this function returns a void* encapsulated in a
196 * java.nio.Buffer (or compound type wrapper), sets the expression
197 * for the capacity of the returned Buffer.
198 *
199 * @param expression a MessageFormat which, when applied to an array
200 * of type String[] that contains each of the arguments names of the
201 * Java-side binding, returns an expression that will (when compiled
202 * by a C compiler) evaluate to an integer-valued expression. The
203 * value of this expression is the capacity of the java.nio.Buffer
204 * returned from this method.
205 *
206 * @throws IllegalArgumentException if the <code>
207 * binding.getJavaReturnType().isNIOBuffer() == false and
208 * binding.getJavaReturnType().isCompoundTypeWrapper() == false
209 * </code>
210 */
211 public final void setReturnValueCapacityExpression(final MessageFormat expression) {
212 returnValueCapacityExpression = expression;
213
216 throw new IllegalArgumentException(
217 "Cannot specify return value capacity for a method that does not " +
218 "return java.nio.Buffer or a compound type wrapper: \"" + binding + "\"");
219 }
220 }
221
222 /**
223 * Get the expression for the length of the returned array
224 */
225 public final MessageFormat getReturnValueLengthExpression() {
226 return returnValueLengthExpression;
227 }
228
229 /**
230 * If this function returns an array, sets the expression for the
231 * length of the returned array.
232 *
233 * @param expression a MessageFormat which, when applied to an array
234 * of type String[] that contains each of the arguments names of the
235 * Java-side binding, returns an expression that will (when compiled
236 * by a C compiler) evaluate to an integer-valued expression. The
237 * value of this expression is the length of the array returned from
238 * this method.
239 *
240 * @throws IllegalArgumentException if the <code>
241 * binding.getJavaReturnType().isNIOBuffer() == false
242 * </code>
243 */
244 public final void setReturnValueLengthExpression(final MessageFormat expression) {
245 returnValueLengthExpression = expression;
246
249 throw new IllegalArgumentException(
250 "Cannot specify return value length for a method that does not " +
251 "return an array: \"" + binding + "\"");
252 }
253 }
254
255 /**
256 * Returns the List of Strings containing declarations for temporary
257 * C variables to be assigned to after the underlying function call.
258 */
259 public final List<String> getTemporaryCVariableDeclarations() {
260 return temporaryCVariableDeclarations;
261 }
262
263 /**
264 * Sets up a List of Strings containing declarations for temporary C
265 * variables to be assigned to after the underlying function call. A
266 * null argument indicates that no manual declarations are to be made.
267 */
268 public final void setTemporaryCVariableDeclarations(final List<String> arg) {
269 temporaryCVariableDeclarations = arg;
270 }
271
272 /**
273 * Returns the List of Strings containing assignments for temporary
274 * C variables which are made after the underlying function call. A
275 * null argument indicates that no manual assignments are to be
276 * made.
277 */
278 public final List<String> getTemporaryCVariableAssignments() {
279 return temporaryCVariableAssignments;
280 }
281
282 /**
283 * Sets up a List of Strings containing assignments for temporary C
284 * variables which are made after the underlying function call. A
285 * null argument indicates that no manual assignments are to be made.
286 */
287 public final void setTemporaryCVariableAssignments(final List<String> arg) {
288 temporaryCVariableAssignments = arg;
289 }
290
291 /**
292 * Get the name of the class in which the corresponding Java method
293 * resides.
294 */
295 public String getJavaPackageName() { return packageName; }
296
297 /**
298 * Get the name of the package in which the corresponding Java method
299 * resides.
300 */
301 public String getJavaClassName() { return className; }
302
303 /**
304 * Is the Java<->C JNI binding for this emitter's MethodBinding one of
305 * several overloaded methods with the same name?
306 */
307 public final boolean getIsOverloadedBinding() { return isOverloadedBinding; }
308
309 /**
310 * Is the Java side of the Java<->C JNI binding for this emitter's
311 * MethodBinding a static method?.
312 */
313 public final boolean getIsJavaMethodStatic() { return isJavaMethodStatic; }
314
315 /**
316 * Is this CMethodBindingEmitter implementing the case of an
317 * indirect buffer or array being passed down to C code?
318 */
320
321 /**
322 * Used for certain internal type size computations
323 */
324 public final MachineDataInfo getMachineDataInfo() { return machDesc; }
325
326 @Override
327 protected StringBuilder appendReturnType(final StringBuilder buf) {
328 buf.append("JNIEXPORT ");
329 buf.append(binding.getJavaReturnType().jniTypeName());
330 buf.append(" JNICALL");
331 return buf;
332 }
333
334 @Override
335 protected StringBuilder appendName(final StringBuilder buf) {
336 buf.append(System.lineSeparator()); // start name on new line
338 buf.append("_");
339 if (isOverloadedBinding) {
340 buf.append(jniMangle(binding));
341 } else {
342 buf.append(JavaEmitter.jniMangle(getImplName()));
343 }
344 return buf;
345 }
346
347 protected String getImplSuffix() {
350 return "1";
351 } else {
352 return "0";
353 }
354 }
355 return "";
356 }
357
358 @Override
359 protected int appendArguments(final StringBuilder buf) {
360 buf.append("JNIEnv *env, ");
361 int numEmitted = 1; // initially just the JNIEnv
362 if (isJavaMethodStatic && !binding.hasContainingType()) {
363 buf.append("jclass");
364 } else {
365 buf.append("jobject");
366 }
367 buf.append(" _unused");
368 ++numEmitted;
369
371 buf.append(", jclass _clazzBuffers");
372 ++numEmitted;
373 }
375 // "this" argument always comes down in argument 0 as direct buffer
376 buf.append(", jobject " + JavaMethodBindingEmitter.javaThisArgumentName());
377 }
378 for (int i = 0; i < binding.getNumArguments(); i++) {
379 final JavaType javaArgType = binding.getJavaArgumentType(i);
380 // Handle case where only param is void
381 if (javaArgType.isVoid()) {
382 // Make sure this is the only param to the method; if it isn't,
383 // there's something wrong with our parsing of the headers.
384 assert(binding.getNumArguments() == 1);
385 continue;
386 }
387 if (javaArgType.isJNIEnv() || javaArgType.isPascalLen() || binding.isArgumentThisPointer(i)) {
388 continue;
389 }
390 buf.append(", ");
391 buf.append(javaArgType.jniTypeName());
392 buf.append(" ");
393 buf.append(binding.getArgumentName(i));
394 ++numEmitted;
395
396 if (javaArgType.isPrimitiveArray() ||
397 javaArgType.isNIOBuffer()) {
398 buf.append(", jint " + byteOffsetArgName(i));
400 buf.append(", jboolean " + isNIOArgName(i));
401 }
402 } else if (javaArgType.isNIOBufferArray()) {
403 buf.append(", jintArray " +
405 }
406 }
407
408 if( null != javaCallbackEmitter ) {
409 numEmitted += javaCallbackEmitter.appendCAdditionalParameter(buf);
410 }
411 return numEmitted;
412 }
413
414
415 @Override
416 protected void emitAdditionalCode() {
417 if( null != javaCallbackEmitter ) {
418 javaCallbackEmitter.emitCAdditionalCode(unit, jcbFuncCMethodEmitter);
419 }
420 }
421
422 @Override
423 protected void emitBody() {
424 unit.emitln(" {");
425// unit().emitln("printf(\" - - - - "+ getName() + getImplSuffix() +" - - - -\\n\");");
429 if( null != javaCallbackEmitter ) {
430 javaCallbackEmitter.emitCSetFuncPreCall(unit);
431 }
435 if( emitBodyMapCToJNIType(-1 /* return value */, true /* addLocalVar */) ) {
436 unit.emitln(" return _res_jni;");
437 }
438 unit.emitln("}");
439 unit.emitln();
440 }
441
443 // Emit declarations for all pointer and String conversion variables
445 emitPointerDeclaration(binding.getContainingType(),
448 null);
449 }
450
451 boolean emittedDataCopyTemps = false;
452 for (int i = 0; i < binding.getNumArguments(); i++) {
453 final JavaType type = binding.getJavaArgumentType(i);
454 if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) {
455 continue;
456 }
457
458 if (type.isArray() || type.isNIOBuffer() || type.isCompoundTypeWrapper() || type.isArrayOfCompoundTypeWrappers()) {
459 final String javaArgName = binding.getArgumentName(i);
460 final String convName = pointerConversionArgumentName(javaArgName);
461 // handle array/buffer argument types
462 final boolean needsDataCopy =
463 emitPointerDeclaration(type,
465 convName, javaArgName);
466 if (needsDataCopy && !emittedDataCopyTemps) {
467 // emit loop counter and array length variables used during data
468 // copy
469 unit.emitln(" jobject _tmpObj;");
470 unit.emitln(" int _copyIndex;");
471 unit.emitln(" jsize _tmpArrayLen;");
472
473 // Pointer to the data in the Buffer, taking the offset into account
474 if(type.isNIOBufferArray()) {
475 unit.emitln(" int * _offsetHandle = NULL;");
476 }
477
478 emittedDataCopyTemps = true;
479 }
480 } else if (type.isString()) {
481 final Type cType = binding.getCArgumentType(i);
482 if (isUTF8Type(cType)) {
483 unit.emit(" const char* ");
484 } else {
485 unit.emit(" jchar* ");
486 }
489 unit.emitln(" = NULL;");
490 }
491
492 }
493
494 // Emit declaration for return value if necessary
495 final Type cReturnType = binding.getCReturnType();
496
497 final JavaType javaReturnType = binding.getJavaReturnType();
498 if (!cReturnType.isVoid()) {
499 unit.emit(" ");
500 // Note we respect const/volatile in the function return type.
501 // However, we cannot have it 'const' for our local variable.
502 // See cast in emitBodyCallCFunction(..)!
504 unit.emitln(" _res;");
505 if (javaReturnType.isNIOByteBufferArray() ||
506 javaReturnType.isArrayOfCompoundTypeWrappers()) {
507 unit.emit(" int ");
509 unit.emitln(";");
510 unit.emit(" int ");
512 unit.emitln(";");
513 unit.emit(" jobjectArray ");
515 unit.emitln(";");
516 } else if (javaReturnType.isArray()) {
517 unit.emit(" int ");
519 unit.emitln(";");
520
521 final Class<?> componentType = javaReturnType.getJavaClass().getComponentType();
522 if (componentType.isArray()) {
523 throw new RuntimeException("Multi-dimensional arrays not supported yet");
524 }
525
526 final String javaTypeName = componentType.getName();
527 final String javaArrayTypeName = "j" + javaTypeName + "Array";
528 unit.emit(" ");
529 unit.emit(javaArrayTypeName);
530 unit.emit(" ");
532 unit.emitln(";");
533 }
534 }
535 }
536
537 /** Emits the user-defined C variable declarations from the
538 TemporaryCVariableDeclarations directive in the .cfg file. */
540 if (temporaryCVariableDeclarations != null) {
541 for (final String val : temporaryCVariableDeclarations) {
542 unit.emit(" ");
543 unit.emitln(val);
544 }
545 }
546 }
547
548 /** Checks a type to see whether it is for a UTF-8 pointer type
549 (i.e., "const char *", "const char **"). False implies that this
550 type is for a Unicode pointer type ("jchar *", "jchar **"). */
551 protected boolean isUTF8Type(Type type) {
552 final int i = 0;
553 // Try to dereference the type at most two levels
554 while (!type.isInt() && !type.isVoid() && (i < 2)) {
555 final PointerType pt = type.asPointer();
556 if (pt != null) {
557 type = pt.getTargetType();
558 } else {
559 final ArrayType arrt = type.asArray();
560 if (arrt == null) {
561 throw new IllegalArgumentException("Type " + type + " should have been a pointer or array type");
562 }
563 type = arrt.getTargetType();
564 }
565 }
566 if (type.isVoid()) {
567 // Assume UTF-8 since UTF-16 is rare
568 return true;
569 }
570 if (!type.isInt()) {
571 throw new IllegalArgumentException("Type " + type + " should have been a one- or two-dimensional integer pointer or array type");
572 }
573 if (type.getSize(machDesc) != 1 && type.getSize(machDesc) != 2) {
574 throw new IllegalArgumentException("Type " + type + " should have been a one- or two-dimensional pointer to char or short");
575 }
576 return (type.getSize(machDesc) == 1);
577 }
578
579 /**
580 * Code to init the variables that were declared in
581 * emitBodyVariableDeclarations(), PRIOR TO calling the actual C
582 * function.
583 */
585
586 // Convert all Buffers to pointers first so we don't have to
587 // call ReleasePrimitiveArrayCritical for any arrays if any
588 // incoming buffers aren't direct
590 emitPointerConversion(binding,
595 null);
596 }
597
598 // Convert all arrays to pointers, and get UTF-8 versions of jstring args
599 for (int i = 0; i < binding.getNumArguments(); i++) {
600 final JavaType javaArgType = binding.getJavaArgumentType(i);
601
602 if (javaArgType.isJNIEnv() || binding.isArgumentThisPointer(i)) {
603 continue;
604 }
605 final String javaArgName = binding.getArgumentName(i);
606
607 if (javaArgType.isCompoundTypeWrapper() ||
609 emitPointerConversion(binding, javaArgType,
610 binding.getCArgumentType(i), javaArgName,
613 } else if (javaArgType.isArray() ||
614 javaArgType.isArrayOfCompoundTypeWrappers() ||
616 final boolean needsDataCopy = javaArgTypeNeedsDataCopy(javaArgType);
617
618 unit.emitln(" if ( NULL != " + javaArgName + " ) {");
619
620 final Type cArgType = binding.getCArgumentType(i);
621 String cArgTypeName = cArgType.getCName();
622
623 final String convName = pointerConversionArgumentName(javaArgName);
624
625 if (!needsDataCopy) {
626 unit.emit(" ");
627 unit.emit(convName);
628 unit.emit(" = (");
629 if (javaArgType.isStringArray()) {
630 // java-side type is String[]
631 cArgTypeName = "jstring *";
632 }
633 unit.emit(cArgTypeName);
634 unit.emit(") ( JNI_TRUE == " + isNIOArgName(i) + " ? ");
635 unit.emit(" (*env)->GetDirectBufferAddress(env, " + javaArgName + ") : ");
636 unit.emit(" (*env)->GetPrimitiveArrayCritical(env, " + javaArgName + ", NULL) );");
637 } else {
638 // Handle the case where the array elements are of a type that needs a
639 // data copy operation to convert from the java memory model to the C
640 // memory model (e.g., int[][], String[], etc)
641 //
642 // FIXME: should factor out this whole block of code into a separate
643 // method for clarity and maintenance purposes
644 //
645 // Note that we properly handle only the case of an array of
646 // compound type wrappers in emitBodyVariablePostCallCleanup below
647 if (!cArgType.isBaseTypeConst() &&
648 !javaArgType.isArrayOfCompoundTypeWrappers()) {
649 // FIXME: if the arg type is non-const, the sematics might be that
650 // the function modifies the argument -- we don't yet support
651 // this.
652 throw new GlueGenException(
653 "Cannot copy data for ptr-to-ptr arg type \"" + cArgType.getDebugString() +
654 "\": support for non-const ptr-to-ptr types not implemented: "+binding, binding.getCSymbol().getASTLocusTag());
655 }
656
657 unit.emitln();
658 unit.emitln(" /* Copy contents of " + javaArgName + " into " + convName + "_copy */");
659
660 // get length of array being copied
661 final String arrayLenName = "_tmpArrayLen";
662 unit.emit(" ");
663 unit.emit(arrayLenName);
664 unit.emit(" = (*env)->GetArrayLength(env, ");
665 unit.emit(javaArgName);
666 unit.emitln(");");
667
668 // allocate an array to hold each element
669 final Type cArgElementType, cArgElementType2;
670 {
671 int error = 0;
672 if( cArgType.isPointer() ) {
673 cArgElementType = cArgType.asPointer().getTargetType();
674 if( cArgElementType.isPointer() ) {
675 // pointer-to-pointer
676 cArgElementType2 = cArgElementType.asPointer().getTargetType();
677 if( cArgElementType2.isPointer() ) {
678 error = 1;
679 }
680 if(cArgType.pointerDepth() != 2) {
681 error = 2;
682 }
683 } else {
684 cArgElementType2 = null;
685 if(cArgType.pointerDepth() != 1) {
686 error = 10;
687 }
688 }
689 } else if( cArgType.isArray() ) {
690 cArgElementType = cArgType.getBaseType();
691 cArgElementType2 = null;
692 } else {
693 cArgElementType = null;
694 cArgElementType2 = null;
695 error = 100;
696 }
697 if( 0 < error ) {
698 throw new GlueGenException(
699 "Could not copy data for type \"" + cArgType.getDebugString() +
700 "\"; currently only pointer- and array-types are supported. (error "+error+"): "+binding,
702 }
703 }
704 emitMalloc(
705 convName+"_copy",
706 cArgElementType.getCName(),
707 cArgType.isBaseTypeConst(),
708 arrayLenName,
709 "Could not allocate buffer for copying data in argument \\\""+javaArgName+"\\\"");
710
711 // Get the handle for the byte offset array sent down for Buffers
712 // FIXME: not 100% sure this is correct with respect to the
713 // JNI spec because it may be illegal to call
714 // GetObjectArrayElement while in a critical section. May
715 // need to do another loop and add in the offsets.
716 if (javaArgType.isNIOBufferArray()) {
717 unit.emitln
718 (" _offsetHandle = (int *) (*env)->GetPrimitiveArrayCritical(env, " +
720 ", NULL);");
721 }
722
723 // process each element in the array
724 unit.emitln(" for (_copyIndex = 0; _copyIndex < "+arrayLenName+"; ++_copyIndex) {");
725
726 // get each array element
727 unit.emitln(" /* get each element of the array argument \"" + javaArgName + "\" */");
728 unit.emit(" _tmpObj = (*env)->GetObjectArrayElement(env, ");
729 unit.emit(javaArgName);
730 unit.emitln(", _copyIndex);");
731
732 if (javaArgType.isStringArray()) {
733 if ( javaArgType.isPascalStr() ) {
734 throw new GlueGenException(
735 "Cannot handle String[] of type PascalString java " + javaArgType.getDebugString() + ", c "+ cArgType.getDebugString() +
737 }
738 unit.emit(" ");
739 emitGetStringChars("(jstring) _tmpObj",
740 convName+"_copy[_copyIndex]",
741 isUTF8Type(cArgType),
742 false, true);
743 } else if (javaArgType.isNIOBufferArray()) {
744 /* We always assume an integer "byte offset" argument follows any Buffer
745 in the method binding. */
746 emitGetDirectBufferAddress("_tmpObj",
747 cArgElementType.getCName(),
748 convName + "_copy[_copyIndex]",
749 true,
750 "_offsetHandle[_copyIndex]", true);
751 } else if (javaArgType.isArrayOfCompoundTypeWrappers()) {
752 // These come down in similar fashion to an array of NIO
753 // Buffers only we do not pass down any integer byte
754 // offset argument
755 emitGetDirectBufferAddress("_tmpObj",
756 cArgElementType.getCName(),
757 "("+convName + "_copy + _copyIndex)",
758 false /* !receivingIsPtrPtr -> linear layout -> use memcpy */,
759 null, true);
760 } else {
761 if( null == cArgElementType2 ) {
762 throw new GlueGenException("XXX: Type "+cArgType.getDebugString()+" not properly handled as ptr-to-ptr: "+binding,
764 }
765 // Question: do we always need to copy the sub-arrays, or just
766 // GetPrimitiveArrayCritical on each jobjectarray element and
767 // assign it to the appropriate elements at pointer depth 1?
768 // Probably depends on const-ness of the argument.
769 // Malloc enough space to hold a copy of each sub-array
770 unit.emit(" ");
771 emitMalloc(convName+"_copy[_copyIndex]",
772 cArgElementType2.getCName(), // assumes cArgPtrType is ptr-to-ptr-to-primitive !!
773 cArgType.isBaseTypeConst(),
774 "(*env)->GetArrayLength(env, _tmpObj)",
775 "Could not allocate buffer during copying of data in argument \\\""+javaArgName+"\\\"");
776 // FIXME: copy the data (use matched Get/ReleasePrimitiveArrayCritical() calls)
777 if (true) {
778 throw new GlueGenException("Cannot yet handle type \"" + cArgType.getDebugString() +
779 "\"; need to add support for copying ptr-to-ptr-to-primitiveType subarrays: "+binding,
781 }
782
783 }
784 unit.emitln(" }");
785
786 if (javaArgType.isNIOBufferArray()) {
787 unit.emitln
788 (" (*env)->ReleasePrimitiveArrayCritical(env, " +
790 ", _offsetHandle, JNI_ABORT);");
791 }
792
793 unit.emitln();
794 } // end of data copy
795
796 unit.emitln(" }");
797
798 } else if (javaArgType.isString()) {
799 if ( javaArgType.isPascalStr() ) {
800 unit.emitln(" size_t "+STRING_CHARS_PREFIX + javaArgName + "_len;");
801 }
802 emitGetStringChars(javaArgName,
803 STRING_CHARS_PREFIX + javaArgName,
805 javaArgType.isPascalStr(), false);
806 }
807 }
808 }
809
810
811 /**
812 * Code to clean up any variables that were declared in
813 * emitBodyVariableDeclarations(), AFTER calling the actual C function.
814 */
816
817 // Release primitive arrays and temporary UTF8 strings if necessary
818 for (int i = 0; i < binding.getNumArguments(); i++) {
819 final JavaType javaArgType = binding.getJavaArgumentType(i);
820 if (javaArgType.isJNIEnv() || binding.isArgumentThisPointer(i)) {
821 continue;
822 }
823
824 final Type cArgType = binding.getCArgumentType(i);
825 final String javaArgName = binding.getArgumentName(i);
826
827 if (javaArgType.isArray() ||
829 javaArgType.isArrayOfCompoundTypeWrappers()) {
830 final boolean needsDataCopy = javaArgTypeNeedsDataCopy(javaArgType);
831
832 final String convName = pointerConversionArgumentName(javaArgName);
833
834 if (!needsDataCopy) {
835 unit.emitln(" if ( JNI_FALSE == " + isNIOArgName(i) + " && NULL != " + javaArgName + " ) {");
836
837 // Release array
838 final String modeFlag = cArgType.isBaseTypeConst() ? "JNI_ABORT" : "0" ;
839 unit.emit(" (*env)->ReleasePrimitiveArrayCritical(env, " + javaArgName + ", " + convName + ", "+modeFlag+");");
840 } else {
841 unit.emitln(" if ( NULL != " + javaArgName + " ) {");
842
843 // clean up the case where the array elements are of a type that needed
844 // a data copy operation to convert from the java memory model to the
845 // C memory model (e.g., int[][], String[], etc)
846 //
847 // FIXME: should factor out this whole block of code into a separate
848 // method for clarity and maintenance purposes
849 if (!cArgType.isBaseTypeConst()) {
850 // FIXME: handle any cleanup from treatment of non-const args,
851 // assuming they were treated differently in
852 // emitBodyVariablePreCallSetup() (see the similar section in that
853 // method for details).
854 if (javaArgType.isArrayOfCompoundTypeWrappers()) {
855 // This is the only form of cleanup we handle right now
856 unit.emitln(" _tmpArrayLen = (*env)->GetArrayLength(env, " + javaArgName + ");");
857 unit.emitln(" for (_copyIndex = 0; _copyIndex < _tmpArrayLen; ++_copyIndex) {");
858 unit.emitln(" _tmpObj = (*env)->GetObjectArrayElement(env, " + javaArgName + ", _copyIndex);");
859 emitReturnDirectBufferAddress("_tmpObj",
860 cArgType.getBaseType().getCName(),
861 "("+convName + "_copy + _copyIndex)",
862 false /* receivingIsPtrPtr */,
863 null);
864 unit.emitln(" }");
865 } else {
866 throw new GlueGenException(
867 "Cannot clean up copied data for ptr-to-ptr arg type \"" + cArgType.getDebugString() +
868 "\": support for cleaning up most non-const ptr-to-ptr types not implemented.",
870 }
871 }
872
873 unit.emitln(" /* Clean up " + convName + "_copy */");
874
875 // Only need to perform cleanup for individual array
876 // elements if they are not direct buffers
877 if (!javaArgType.isNIOBufferArray() &&
878 !javaArgType.isArrayOfCompoundTypeWrappers()) {
879 // Re-fetch length of array that was copied
880 final String arrayLenName = "_tmpArrayLen";
881 unit.emit(" ");
882 unit.emit(arrayLenName);
883 unit.emit(" = (*env)->GetArrayLength(env, ");
884 unit.emit(javaArgName);
885 unit.emitln(");");
886
887 // free each element
888 final PointerType cArgPtrType = cArgType.asPointer();
889 if (cArgPtrType == null) {
890 throw new GlueGenException(
891 "Could not copy data for type \"" + cArgType.getDebugString() +
892 "\"; currently only pointer types supported.",
894 }
895
896 // process each element in the array
897 unit.emitln(" for (_copyIndex = 0; _copyIndex < " + arrayLenName +"; ++_copyIndex) {");
898
899 // get each array element
900 unit.emitln(" /* free each element of " +convName +"_copy */");
901 unit.emit(" _tmpObj = (*env)->GetObjectArrayElement(env, ");
902 unit.emit(javaArgName);
903 unit.emitln(", _copyIndex);");
904
905 if (javaArgType.isStringArray()) {
906 unit.emit(" (*env)->ReleaseStringUTFChars(env, ");
907 unit.emit("(jstring) _tmpObj");
908 unit.emit(", ");
909 unit.emit(convName+"_copy[_copyIndex]");
910 unit.emitln(");");
911 } else {
912 throw new GlueGenException(
913 "Cannot yet handle type \"" + cArgType.getDebugString() +
914 "\"; need to add support for cleaning up copied ptr-to-ptr-to-primitiveType subarrays",
916 }
917 unit.emitln(" }");
918 }
919
920 // free the main array
921 unit.emit(" free((void*) ");
922 unit.emit(convName+"_copy");
923 unit.emitln(");");
924 } // end of cleaning up copied data
925
926 unit.emitln(" }");
927
928 } else if (javaArgType.isString()) {
929 unit.emitln(" if ( NULL != " + javaArgName + " ) {");
930
931 if (isUTF8Type(cArgType)) {
932 unit.emit(" (*env)->ReleaseStringUTFChars(env, ");
933 unit.emit(javaArgName);
935 unit.emit(javaArgName);
936 unit.emitln(");");
937 } else {
938 unit.emitln(" free((void*) " + STRING_CHARS_PREFIX + javaArgName + ");");
939 }
940
941 unit.emitln(" }");
942 }
943 }
944 }
945
946 /** Returns the number of arguments passed so calling code knows
947 whether to print a comma */
948 protected int emitBodyPassCArguments() {
949 for (int i = 0; i < binding.getNumArguments(); i++) {
950 if (i != 0) {
951 unit.emit(", ");
952 }
953 final JavaType javaArgType = binding.getJavaArgumentType(i);
954 // Handle case where only param is void.
955 if (javaArgType.isVoid()) {
956 // Make sure this is the only param to the method; if it isn't,
957 // there's something wrong with our parsing of the headers.
958 assert(binding.getNumArguments() == 1);
959 continue;
960 }
961
962 if (javaArgType.isJNIEnv()) {
963 unit.emit("env");
964 } else if( javaArgType.isPascalLen() ) {
965 final Type cArgType = binding.getCArgumentType(i);
966 unit.emit(" ("+cArgType.getCName(true)+") "+STRING_CHARS_PREFIX + binding.getArgumentName(javaArgType.pascalStrElem.valueIdx) + "_len");
967 } else if (binding.isArgumentThisPointer(i)) {
969 } else {
970 unit.emit("(");
971 final Type cArgType = binding.getCArgumentType(i);
972 final boolean needsDataCopy = javaArgTypeNeedsDataCopy(javaArgType);
973 final boolean needsArrayOffset = !needsDataCopy && (
974 javaArgType.isArray() ||
975 javaArgType.isArrayOfCompoundTypeWrappers() ||
977 unit.emit(cArgType.getCName(true));
978 unit.emit(") ");
979
980 if (cArgType.isPointer() && javaArgType.isPrimitive()) {
981 unit.emit("(intptr_t) ");
982 }
983 if (javaArgType.isArray() || javaArgType.isNIOBuffer() ||
984 javaArgType.isCompoundTypeWrapper() || javaArgType.isArrayOfCompoundTypeWrappers()) {
985 if( needsArrayOffset ) {
986 unit.emit("(((char *) ");
987 } else if( !cArgType.isPointer() && javaArgType.isCompoundTypeWrapper() ) { // FIXME: Compound call-by-value
988 unit.emit("*");
989 }
991 if ( needsDataCopy ) {
992 unit.emit("_copy");
993 }
994 if( needsArrayOffset ) {
995 unit.emit(") + " + byteOffsetArgName(i) + ")");
996 }
997 } else {
998 if ( javaArgType.isString() ) {
1000 }
1002 if( !javaArgType.isString() && null != javaCallbackEmitter ) {
1003 javaCallbackEmitter.emitCOptArgumentSuffix(unit, i);
1004 }
1005 }
1006 }
1007 }
1008 return binding.getNumArguments();
1009 }
1010
1011 private boolean isCStructFunctionPointer = false;
1012
1013 /**
1014 * If method originates from a struct, see {@link MethodBinding#hasContainingType()},
1015 * it can either purposed to call a native static function (default)
1016 * or a struct's function pointer.
1017 */
1018 protected void setIsCStructFunctionPointer(final boolean v) {
1019 isCStructFunctionPointer = v;
1020 }
1021
1022 protected void emitBodyCallCFunction() {
1023 // Make the call to the actual C function
1024 unit.emit(" ");
1025
1026 // WARNING: this code assumes that the return type has already been
1027 // typedef-resolved.
1028 final Type cReturnType = binding.getCReturnType();
1029
1030 if (!cReturnType.isVoid()) {
1031 // Note we respect const/volatile in the function return type.
1032 // However, we cannot have it 'const' for our local variable.
1033 // See return type in emitBodyVariableDeclarations(..)!
1034 unit.emit("_res = (");
1035 unit.emit(cReturnType.getCName(false));
1036 unit.emit(") ");
1037 }
1038 if ( isCStructFunctionPointer && binding.hasContainingType() ) {
1039 // Call through function pointer
1041 }
1043 unit.emit("(");
1045 unit.emitln(");");
1046 }
1047
1048 /** Emits the user-defined C variable assignments from the
1049 TemporaryCVariableAssignments directive in the .cfg file. */
1051 if (temporaryCVariableAssignments != null) {
1052 for (final String val : temporaryCVariableAssignments) {
1053 unit.emit(" ");
1054 unit.emitln(val);
1055 }
1056 }
1057 }
1058
1059 /**
1060 * Emit code, converting a C type into a java JNI-type.
1061 * <p>
1062 * The resulting JNI value is assigned to a local JNI variable named cArgName+"_jni"
1063 * with `cArgName = binding.getArgumentName(argIdx)` or `cArgName = "_res"`.
1064 * </p>
1065 * @param argIdx -1 is return value, [0..n] is argument index
1066 * @param addLocalVar if true, emit instantiating the local JNI variable.
1067 * @return true if a non-void result has been produced, otherwise false
1068 */
1069 public boolean emitBodyMapCToJNIType(final int argIdx, final boolean addLocalVar)
1070 {
1071 // WARNING: this code assumes that the return type has already been
1072 // typedef-resolved.
1073 final boolean isReturnVal;
1074 final Type cType;
1075 final JavaType javaType;
1076 final String cArgName;
1077 if( 0 > argIdx ) {
1078 isReturnVal = true;
1079 cType = binding.getCReturnType();
1080 javaType = binding.getJavaReturnType();
1081 cArgName = "_res";
1082 } else {
1083 isReturnVal = false;
1084 cType = binding.getCArgumentType(argIdx);
1085 javaType = binding.getJavaArgumentType(argIdx);
1086 cArgName = binding.getArgumentName(argIdx);
1087 }
1088 final String javaArgName = cArgName + "_jni";
1089
1090 if ( cType.isVoid() ) {
1091 // No result to produce
1092 return false;
1093 }
1094 if (javaType.isPrimitive()) {
1095 if( addLocalVar ) {
1096 unit.emit(" "+javaType.jniTypeName()+" "+javaArgName+" = ");
1097 } else {
1098 unit.emit(" "+javaArgName+" = ");
1099 }
1100 if (cType.isPointer()) {
1101 // Pointer being converted to int or long: cast this result
1102 // (through intptr_t to avoid compiler warnings with gcc)
1103 unit.emit("(" + javaType.jniTypeName() + ") (intptr_t) ");
1104 }
1105 unit.emit(cArgName);
1106 unit.emitln(";");
1107 } else if ( !cType.isPointer() && javaType.isCompoundTypeWrapper() ) { // isReturnCompoundByValue()
1108 if( addLocalVar ) {
1109 unit.emit(" "+javaType.jniTypeName()+" "+javaArgName+" = ");
1110 } else {
1111 unit.emit(" "+javaArgName+" = ");
1112 }
1113 final String returnSizeOf;
1114 if ( isReturnVal && returnValueCapacityExpression != null ) {
1115 returnSizeOf = returnValueCapacityExpression.format(argumentNameArray());
1116 } else {
1117 returnSizeOf = "sizeof(" + cType.getCName() + ")";
1118 }
1119 unit.emitln("JVMUtil_NewDirectByteBufferCopy(env, _clazzBuffers, &"+cArgName+", "+returnSizeOf+");");
1121 } else if (javaType.isNIOBuffer() || javaType.isCompoundTypeWrapper()) {
1122 if( addLocalVar ) {
1123 unit.emitln(" "+javaType.jniTypeName()+" "+javaArgName+";");
1124 } else {
1125 unit.emitln(" "+javaArgName+";");
1126 }
1127 unit.emitln(" if(NULL == "+cArgName+") {");
1128 unit.emitln(" "+javaArgName+" = NULL;");
1129 unit.emitln(" } else {");
1130 unit.emit (" "+javaArgName+" = (*env)->NewDirectByteBuffer(env, (void *)"+cArgName+", ");
1131
1132 // See whether capacity has been specified
1133 if ( isReturnVal && returnValueCapacityExpression != null) {
1134 unit.emitln( returnValueCapacityExpression.format( argumentNameArray() ) + ");");
1135 } else {
1136 final Type cTargetType = cType.isPointer() ? cType.getTargetType() : null;
1137 int mode = 0;
1138 if ( 1 == cType.pointerDepth() && null != cTargetType ) {
1139 if( cTargetType.isCompound() ) {
1140 if( !cTargetType.isAnon() &&
1141 cTargetType.asCompound().getNumFields() > 0 )
1142 {
1143 // fully declared non-anonymous struct pointer: pass content
1144 if ( cTargetType.getSize() == null ) {
1145 throw new GlueGenException(
1146 "Error emitting code for compound type "+
1147 "for function \"" + binding + "\": " +
1148 "Structs to be emitted should have been laid out by this point " +
1149 "(type " + cTargetType.getCName() + " / " +
1150 cTargetType.getDebugString() + " was not) for "+binding.getCSymbol(),
1152 }
1153 unit.emitln("sizeof(" + cTargetType.getCName() + ") );");
1154 mode = 10;
1155 } else if( cTargetType.asCompound().getNumFields() == 0 ) {
1156 // anonymous struct pointer: pass pointer
1157 unit.emitln("sizeof(" + cType.getCName() + ") );");
1158 mode = 11;
1159 }
1160 }
1161 if( 0 == mode ) {
1162 if( cTargetType.isPrimitive() ) {
1163 // primitive pointer: pass primitive
1164 unit.emitln("sizeof(" + cTargetType.getCName() + ") );");
1165 mode = 20;
1166 } else if( cTargetType.isVoid() ) {
1167 // void pointer: pass pointer
1168 unit.emitln("sizeof(" + cType.getCName() + ") );");
1169 mode = 21;
1170 }
1171 }
1172 }
1173 if( 0 == mode ) {
1174 if( null != cfg.typeInfo(cType) ) { // javaReturnType.isOpaqued() covered above via isPrimitive()
1175 // Opaque
1176 unit.emitln("sizeof(" + cType.getCName() + ") );");
1177 mode = 88;
1178 } else {
1179 final String wmsg = "Assumed return size of equivalent C return type";
1180 unit.emitln("sizeof(" + cType.getCName() + ") ); // WARNING: "+wmsg);
1181 mode = 99;
1183 "No capacity specified for java.nio.Buffer return " +
1184 "value for function \"" + binding.getName() + "\". " + wmsg + " (sizeof(" + cType.getCName() + ")): " + binding);
1185 }
1186 }
1187 unit.emitln(" /** ");
1188 unit.emitln(" * mode: "+mode+", arg #"+argIdx);
1189 unit.emitln(" * cType: "+cType.getDebugString());
1190 unit.emitln(" * cTargetType: "+cTargetType.getDebugString());
1191 unit.emitln(" * javaType: "+javaType.getDebugString());
1192 unit.emitln(" */");
1193 }
1194 unit.emitln(" }");
1195 } else if (javaType.isString()) {
1196 final boolean pascalString = javaType.isPascalStrElem();
1197 final String lenArgName;
1198 if( pascalString ) {
1199 lenArgName = binding.getArgumentName( javaType.pascalStrElem.lengthIdx );
1200 } else {
1201 lenArgName = null;
1202 }
1203 if( addLocalVar ) {
1204 unit.emitln(" "+javaType.jniTypeName()+" "+javaArgName+";");
1205 }
1206 if( null != lenArgName ) {
1207 unit.emitln(" if (NULL == "+cArgName+" || 0 >= "+lenArgName+" ) {");
1208 } else {
1209 unit.emitln(" if (NULL == "+cArgName+") {");
1210 }
1211 unit.emitln(" "+javaArgName+" = NULL;");
1212 unit.emitln(" } else {");
1213 if( null != lenArgName ) {
1214 unit.emitln(" char* "+cArgName+"_cstr = calloc("+lenArgName+"+1, sizeof(char)); // PascalString -> Add EOS");
1215 unit.emitln(" memcpy("+cArgName+"_cstr, "+cArgName+", "+lenArgName+");");
1216 }
1217 unit.emit (" "+javaArgName+" = ");
1218 if( null != lenArgName ) {
1219 unit.emitln("(*env)->NewStringUTF(env, (const char *)"+cArgName+"_cstr);");
1220 unit.emitln(" free("+cArgName+"_cstr);");
1221 } else {
1222 unit.emitln("(*env)->NewStringUTF(env, (const char *)"+cArgName+");");
1223 }
1224 unit.emitln(" }");
1225 } else if (javaType.isArrayOfCompoundTypeWrappers() ||
1226 ( javaType.isArray() && javaType.isNIOByteBufferArray() ) )
1227 {
1228 if( addLocalVar ) {
1229 unit.emitln(" "+javaType.jniTypeName()+" "+javaArgName+";");
1230 }
1231 unit.emitln(" if (NULL == "+cArgName+") { "+javaArgName+" = NULL; } else {");
1232 if ( !isReturnVal || returnValueLengthExpression == null ) {
1233 throw new GlueGenException("Error while generating C code: No length specified for array returned from function for arg #" +
1234 argIdx + ", "+cType.getDebugString()+", for "+
1236 } // TODO: Perhaps allow usage for non-return types, i.e. configure 'returnValueLengthExpression' for all arguments.
1237 unit.emitln(" " + arrayResLength + " = " + returnValueLengthExpression.format(argumentNameArray()) + ";");
1238 unit.emitln(" " + arrayRes + " = (*env)->NewObjectArray(env, " + arrayResLength + ", (*env)->FindClass(env, \"java/nio/ByteBuffer\"), NULL);");
1239 unit.emitln(" for (" + arrayIdx + " = 0; " + arrayIdx + " < " + arrayResLength + "; " + arrayIdx + "++) {");
1240 final Type retType = binding.getCSymbol().getReturnType();
1241 final Type pointerType = retType.getArrayBaseOrPointerTargetType();
1242 unit.emitln(" (*env)->SetObjectArrayElement(env, " + arrayRes + ", " + arrayIdx +
1243 ", (*env)->NewDirectByteBuffer(env, (void *)"+cArgName+"[" + arrayIdx + "], sizeof(" + pointerType.getCName() + ")));");
1244 unit.emitln(" }");
1245 unit.emitln(" "+javaArgName+" = " + arrayRes + ";");
1246 unit.emitln(" }");
1247 } else if (javaType.isArray()) {
1248 // FIXME: must have user provide length of array in .cfg file
1249 // by providing a constant value, input parameter, or
1250 // expression which computes the array size (already present
1251 // as ReturnValueCapacity, not yet implemented / tested here)
1252 throw new GlueGenException(
1253 "Could not emit native code for arg #"+argIdx+", "+cType.getDebugString()+", for " + binding +
1254 ": array return values for non-char types not implemented yet.",
1256
1257 // FIXME: This is approximately what will be required here
1258 //
1259 //unit().emit(" ");
1260 //unit().emit(arrayRes);
1261 //unit().emit(" = (*env)->New");
1262 //unit().emit(capitalizedComponentType);
1263 //unit().emit("Array(env, ");
1264 //unit().emit(arrayResLength);
1265 //unit().emitln(");");
1266 //unit().emit(" (*env)->Set");
1267 //unit().emit(capitalizedComponentType);
1268 //unit().emit("ArrayRegion(env, ");
1269 //unit().emit(arrayRes);
1270 //unit().emit(", 0, ");
1271 //unit().emit(arrayResLength);
1272 //unit().emitln(", "+cArgName+");");
1273 //unit().emit(" return ");
1274 //unit().emit(arrayRes);
1275 //unit().emitln(";");
1276 } else {
1277 throw new GlueGenException("Unhandled return type: arg #"+argIdx+", C "+cType.getDebugString()+", java "+javaType.getDebugString()+" for "+binding,
1279 }
1280 return true;
1281 }
1282
1283 protected static String cThisArgumentName() {
1284 return "this0";
1285 }
1286
1287 protected String jniMangle(final MethodBinding binding) {
1288 final StringBuilder buf = new StringBuilder();
1289 buf.append(JavaEmitter.jniMangle(getImplName()));
1290 buf.append(getImplSuffix());
1291 if( null == javaCallbackEmitter ) {
1292 buf.append("__");
1294 if( null != javaCallbackEmitter ) {
1295 javaCallbackEmitter.appendCAdditionalJNIDescriptor(buf);
1296 }
1297 }
1298 return buf.toString();
1299 }
1300
1301 /**
1302 * Return the mangled JNI argument names of given binding.
1303 * @param binding
1304 * @param forIndirectBufferAndArrayImplementation If true, this CMethodBindingEmitter implements the case of an indirect buffer or array being passed down to C code, otherwise false.
1305 * @param buf
1306 * @return
1307 */
1308 public static StringBuilder appendJNIMangledArgs(final MethodBinding binding, final boolean forIndirectBufferAndArrayImplementation, final StringBuilder buf) {
1310 JavaType.appendJNIDescriptor(buf, Class.class, true);
1311 }
1312 if (binding.hasContainingType()) {
1313 // "this" argument always comes down in argument 0 as direct buffer
1314 JavaType.appendJNIDescriptor(buf, java.nio.ByteBuffer.class, true);
1315 }
1316 for (int i = 0; i < binding.getNumArguments(); i++) {
1318 continue;
1319 }
1320 final JavaType type = binding.getJavaArgumentType(i);
1321 if (type.isVoid()) {
1322 // We should only see "void" as the first argument of a 1-argument function
1323 // FIXME: should normalize this in the parser
1324 if ((i != 0) || (binding.getNumArguments() > 1)) {
1325 throw new GlueGenException("Saw illegal \"void\" argument while emitting arg "+i+" of "+binding,
1327 }
1328 } else if ( type.isPascalLen() ) {
1329 // drop
1330 } else {
1331 Class<?> c = type.getJavaClass();
1332 if (c != null) {
1333 JavaType.appendJNIDescriptor(buf, c, false);
1334 // If Buffer offset arguments were added, we need to mangle the JNI for the
1335 // extra arguments
1336 if (type.isNIOBuffer()) {
1337 JavaType.appendJNIDescriptor(buf, Integer.TYPE, false);
1339 JavaType.appendJNIDescriptor(buf, Boolean.TYPE, false);
1340 }
1341 } else if (type.isNIOBufferArray()) {
1342 final int[] intArrayType = new int[0];
1343 c = intArrayType.getClass();
1344 JavaType.appendJNIDescriptor(buf, c , true);
1345 }
1346 if (type.isPrimitiveArray()) {
1347 JavaType.appendJNIDescriptor(buf, Integer.TYPE, false);
1348 }
1349 } else if (type.isNamedClass()) {
1350 buf.append(type.getJNIMethodDesciptor());
1351 } else if (type.isCompoundTypeWrapper()) {
1352 // Mangle wrappers for C structs as ByteBuffer
1353 JavaType.appendJNIDescriptor(buf, java.nio.ByteBuffer.class, true);
1354 } else if (type.isArrayOfCompoundTypeWrappers()) {
1355 // Mangle arrays of C structs as ByteBuffer[]
1356 final java.nio.ByteBuffer[] tmp = new java.nio.ByteBuffer[0];
1357 JavaType.appendJNIDescriptor(buf, tmp.getClass(), true);
1358 } else if (type.isJNIEnv()) {
1359 // These are not exposed at the Java level
1360 } else {
1361 // FIXME: add support for char* -> String conversion
1362 throw new GlueGenException("Unknown kind of JavaType: arg "+i+", name="+type.getName()+" of "+binding,
1364 }
1365 }
1366 }
1367 return buf;
1368 }
1369
1370 private void emitOutOfMemoryCheck(final String varName, final String errorMessage) {
1371 unit.emitln(" if ( NULL == " + varName + " ) {");
1372 unit.emitln(" (*env)->ThrowNew(env, (*env)->FindClass(env, \"java/lang/OutOfMemoryError\"),");
1373 unit.emit(" \"" + errorMessage);
1374 unit.emit(" in native dispatcher for \\\"");
1376 unit.emitln("\\\"\");");
1377 unit.emit(" return");
1378 if (!binding.getJavaReturnType().isVoid()) {
1379 unit.emit(" 0");
1380 }
1381 unit.emitln(";");
1382 unit.emitln(" }");
1383 }
1384
1385 private void emitMalloc(final String targetVarName,
1386 final String elementTypeString,
1387 final boolean elementTypeIsConst,
1388 final String numElementsExpression,
1389 final String mallocFailureErrorString) {
1390 unit.emit(" ");
1391 unit.emit(targetVarName);
1392 unit.emit(" = (");
1393 if(elementTypeIsConst) {
1394 unit.emit("const ");
1395 }
1396 unit.emit(elementTypeString);
1397 unit.emit(" *) malloc(");
1398 unit.emit(numElementsExpression);
1399 unit.emit(" * sizeof(");
1400 unit.emit(elementTypeString);
1401 unit.emitln("));");
1402 // Catch memory allocation failure
1403 emitOutOfMemoryCheck( targetVarName, mallocFailureErrorString);
1404 }
1405
1406 private void emitCalloc(final String targetVarName,
1407 final String elementTypeString,
1408 final String numElementsExpression,
1409 final String mallocFailureErrorString) {
1410 unit.emit(" ");
1411 unit.emit(targetVarName);
1412 unit.emit(" = (");
1413 unit.emit(elementTypeString);
1414 unit.emit(" *) calloc(");
1415 unit.emit(numElementsExpression);
1416 unit.emit(", sizeof(");
1417 unit.emit(elementTypeString);
1418 unit.emitln("));");
1419 // Catch memory allocation failure
1420 emitOutOfMemoryCheck( targetVarName, mallocFailureErrorString);
1421 }
1422
1423 private void emitGetStringChars(final String sourceVarName,
1424 final String receivingVarName,
1425 final boolean isUTF8,
1426 final boolean addLengthVar,
1427 final boolean emitElseClause) {
1428 unit.emitln(" if ( NULL != " + sourceVarName + " ) {");
1429
1430 if( addLengthVar ) {
1431 unit.emit(" "+receivingVarName+"_len = (size_t) ");
1432 }
1433 if (isUTF8) {
1434 if( addLengthVar ) {
1435 unit.emit(" (*env)->GetStringUTFLength(env, ");
1436 unit.emit(sourceVarName);
1437 unit.emitln(");");
1438 }
1439 unit.emit(" ");
1440 unit.emit(receivingVarName);
1441 unit.emit(" = (*env)->GetStringUTFChars(env, ");
1442 unit.emit(sourceVarName);
1443 unit.emitln(", (jboolean*)NULL);");
1444 // Catch memory allocation failure in the event that the VM didn't pin
1445 // the String and failed to allocate a copy
1446 emitOutOfMemoryCheck( receivingVarName, "Failed to get UTF-8 chars for argument \\\""+sourceVarName+"\\\"");
1447 } else {
1448 // The UTF-16 case is basically Windows specific. Unix platforms
1449 // tend to use only the UTF-8 encoding. On Windows the problem
1450 // is that wide character strings are expected to be null
1451 // terminated, but the JNI GetStringChars doesn't return a
1452 // null-terminated Unicode string. For this reason we explicitly
1453 // calloc our buffer, including the null terminator, and use
1454 // GetStringRegion to fetch the string's characters.
1455 if( addLengthVar ) {
1456 unit.emit(" (*env)->GetStringLength(env, ");
1457 unit.emit(sourceVarName);
1458 unit.emitln(");");
1459 emitCalloc(receivingVarName,
1460 "jchar",
1461 receivingVarName+"_len + 1",
1462 "Could not allocate temporary buffer for copying string argument \\\""+sourceVarName+"\\\"");
1463 } else {
1464 emitCalloc(receivingVarName,
1465 "jchar",
1466 "(*env)->GetStringLength(env, " + sourceVarName + ") + 1",
1467 "Could not allocate temporary buffer for copying string argument \\\""+sourceVarName+"\\\"");
1468 }
1469 unit.emitln(" (*env)->GetStringRegion(env, " + sourceVarName + ", 0, (*env)->GetStringLength(env, " + sourceVarName + "), " + receivingVarName + ");");
1470 }
1471 if( addLengthVar ) {
1472 unit.emitln(" } else {");
1473 unit.emitln(" "+receivingVarName+"_len = 0;");
1474 }
1475 unit.emit(" }");
1476 if (emitElseClause) {
1477 unit.emit(" else {");
1478 unit.emit(" ");
1479 unit.emit(receivingVarName);
1480 unit.emitln(" = NULL;");
1481 unit.emitln(" }");
1482 } else {
1483 unit.emitln();
1484 }
1485 }
1486
1487 private void emitGetDirectBufferAddress(final String sourceVarName,
1488 final String receivingVarTypeString,
1489 final String receivingVarName,
1490 final boolean receivingIsPtrPtr,
1491 final String byteOffsetVarName, final boolean emitElseClause) {
1492 unit.emitln(" if ( NULL != " + sourceVarName + " ) {");
1493 unit.emit(" ");
1494 unit.emit(" ");
1495 if( receivingIsPtrPtr ) {
1496 unit.emit(receivingVarName+" = ("+receivingVarTypeString+") (((char*) (*env)->GetDirectBufferAddress(env, "+sourceVarName+"))");
1497 unit.emitln(" + " + ((byteOffsetVarName != null) ? byteOffsetVarName : "0") + ");");
1498 } else {
1499 // linear layout -> use memcpy
1500 unit.emitln("memcpy((void *)"+receivingVarName+", (*env)->GetDirectBufferAddress(env, "+sourceVarName+"), sizeof("+receivingVarTypeString+"));");
1501 }
1502
1503 if (emitElseClause) {
1504 unit.emitln(" } else {");
1505 unit.emit(" ");
1506 unit.emit(" ");
1507 if( receivingIsPtrPtr ) {
1508 unit.emit(receivingVarName);
1509 unit.emitln(" = NULL;");
1510 } else {
1511 unit.emitln("memset((void *)"+receivingVarName+", 0, sizeof("+receivingVarTypeString+"));");
1512 }
1513 }
1514 unit.emitln(" }");
1515 unit.emitln();
1516 }
1517
1518 private void emitReturnDirectBufferAddress(final String sourceVarName,
1519 final String receivingVarTypeString,
1520 final String receivingVarName,
1521 final boolean receivingIsPtrPtr,
1522 final String byteOffsetVarName) {
1523 unit.emit(" ");
1524 unit.emit(" ");
1525 if( receivingIsPtrPtr ) {
1526 unit.emit("(((char*) (*env)->GetDirectBufferAddress(env, "+sourceVarName+"))");
1527 unit.emitln(" + " + ((byteOffsetVarName != null) ? byteOffsetVarName : "0") + ") = "+receivingVarName+";");
1528 throw new RuntimeException("incomplete implementation"); // FIXME doesn't work, currently unused
1529 } else {
1530 // linear layout -> use memcpy
1531 unit.emitln("memcpy((*env)->GetDirectBufferAddress(env, "+sourceVarName+"), "+receivingVarName+", sizeof("+receivingVarTypeString+"));");
1532 }
1533 unit.emitln();
1534 }
1535
1536 // Note: if the data in the Type needs to be converted from the Java memory
1537 // model to the C memory model prior to calling any C-side functions, then
1538 // an extra variable named XXX_copy (where XXX is the value of the
1539 // cVariableName argument) will be emitted and TRUE will be returned.
1540 private boolean emitPointerDeclaration(final JavaType javaType,
1541 final Type cType,
1542 final String cVariableName,
1543 final String javaArgumentName) {
1544 String ptrTypeString = null;
1545 boolean needsDataCopy = false;
1546
1547 // Emit declaration for the pointer variable.
1548 //
1549 // Note that we don't need to obey const/volatile for outgoing arguments
1550 //
1551 if (javaType.isNIOBuffer()) {
1552 // primitive NIO object
1553 ptrTypeString = cType.getCName();
1554 } else if (javaType.isArray() || javaType.isArrayOfCompoundTypeWrappers()) {
1555 needsDataCopy = javaArgTypeNeedsDataCopy(javaType);
1556 if (javaType.isPrimitiveArray() ||
1557 javaType.isNIOBufferArray() ||
1558 javaType.isArrayOfCompoundTypeWrappers()) {
1559 ptrTypeString = cType.getCName();
1560 } else if (!javaType.isStringArray()) {
1561 final Class<?> elementType = javaType.getJavaClass().getComponentType();
1562 if (elementType.isArray()) {
1563 final Class<?> subElementType = elementType.getComponentType();
1564 if (subElementType.isPrimitive()) {
1565 // type is pointer to pointer to primitive
1566 ptrTypeString = cType.getCName();
1567 } else {
1568 // type is pointer to pointer of some type we don't support (maybe
1569 // it's an array of pointers to structs?)
1570 throw new GlueGenException("Unsupported pointer type: \"" + cType.getDebugString() + "\"", cType.getASTLocusTag());
1571 }
1572 } else {
1573 // type is pointer to pointer of some type we don't support (maybe
1574 // it's an array of pointers to structs?)
1575 throw new GlueGenException("Unsupported pointer type: \"" + cType.getDebugString() + "\"", cType.getASTLocusTag());
1576 }
1577 }
1578 } else {
1579 ptrTypeString = cType.getCName();
1580 }
1581
1582 unit.emit(" ");
1583 if (!needsDataCopy) {
1584 // declare the pointer variable
1585 unit.emit(ptrTypeString);
1586 if( !cType.isPointer() && javaType.isCompoundTypeWrapper() ) { // FIXME: Compound call-by-value
1587 unit.emit(" * ");
1588 } else {
1589 unit.emit(" ");
1590 }
1591 unit.emit(cVariableName);
1592 unit.emitln(" = NULL;");
1593 } else {
1594 // Declare a variable to hold a copy of the argument data in which the
1595 // incoming data has been properly laid out in memory to match the C
1596 // memory model
1597 if (javaType.isStringArray()) {
1598 String cElementTypeName = "char *";
1599 final PointerType cPtrType = cType.asPointer();
1600 if (cPtrType != null) {
1601 cElementTypeName = cPtrType.getTargetType().asPointer().getCName();
1602 }
1603 if (cType.isBaseTypeConst()) {
1604 unit.emit("const ");
1605 }
1606 unit.emit(cElementTypeName+" *");
1607 } else {
1608 if (cType.isBaseTypeConst()) {
1609 unit.emit("const ");
1610 }
1611 unit.emit(ptrTypeString);
1612 }
1613 unit.emit(" ");
1614 unit.emit(cVariableName);
1615 unit.emit("_copy = NULL; /* copy of data in ");
1616 unit.emit(javaArgumentName);
1617 unit.emitln(", laid out according to C memory model */");
1618 }
1619
1620 return needsDataCopy;
1621 }
1622
1623 private void emitPointerConversion(final MethodBinding binding,
1624 final JavaType type,
1625 final Type cType,
1626 final String incomingArgumentName,
1627 final String cVariableName,
1628 String byteOffsetVarName) {
1629 // Compound type wrappers do not get byte offsets added on
1630 if (type.isCompoundTypeWrapper()) {
1631 byteOffsetVarName = null;
1632 }
1633
1634 final String cVariableType;
1635 if( !cType.isPointer() && type.isCompoundTypeWrapper() ) { // FIXME: Compound call-by-value
1636 cVariableType = cType.getCName()+" *";
1637 } else {
1638 cVariableType = cType.getCName();
1639 }
1640 emitGetDirectBufferAddress(incomingArgumentName,
1641 cVariableType,
1642 cVariableName,
1643 true,
1644 byteOffsetVarName, false);
1645 }
1646
1647 protected String byteOffsetArgName(final int i) {
1649 }
1650
1651 protected String isNIOArgName(final int i) {
1653 }
1654
1655 protected String isNIOArgName(final String s) {
1656 return s + "_is_nio";
1657 }
1658
1659 protected String byteOffsetArrayArgName(final int i) {
1660 return binding.getArgumentName(i) + "_byte_offset_array";
1661 }
1662
1663 protected String[] argumentNameArray() {
1664 final String[] argumentNames = new String[binding.getNumArguments()];
1665 for (int i = 0; i < binding.getNumArguments(); i++) {
1666 argumentNames[i] = binding.getArgumentName(i);
1668 // Add on _offset argument in comma-separated expression
1669 argumentNames[i] = argumentNames[i] + ", " + byteOffsetArgName(i);
1670 }
1671 }
1672 return argumentNames;
1673 }
1674
1675 protected String pointerConversionArgumentName(final String argName) {
1676 return "_" + argName + "_ptr";
1677 }
1678
1679 /**
1680 * Class that emits a generic comment for CMethodBindingEmitters; the comment
1681 * includes the C signature of the native method that is being bound by the
1682 * emitter java method.
1683 */
1684 protected static class DefaultCommentEmitter implements CommentEmitter {
1685 @Override
1686 public void emit(final FunctionEmitter emitter, final PrintWriter writer) {
1687 emitBeginning((CMethodBindingEmitter)emitter, writer);
1688 emitEnding((CMethodBindingEmitter)emitter, writer);
1689 }
1690 protected void emitBeginning(final CMethodBindingEmitter emitter, final PrintWriter writer) {
1691 writer.println(" Java->C glue code:");
1692 writer.print(" * Java package: ");
1693 writer.print(emitter.getJavaPackageName());
1694 writer.print(".");
1695 writer.println(emitter.getJavaClassName());
1696 writer.print(" * Java method: ");
1697 final MethodBinding binding = emitter.getBinding();
1698 writer.println(binding);
1699 writer.println(" * C function: " + binding.getCSymbol());
1700 }
1701 protected void emitEnding(final CMethodBindingEmitter emitter, final PrintWriter writer) {
1702 }
1703 }
1704
1705 protected boolean javaArgTypeNeedsDataCopy(final JavaType javaArgType) {
1706 if (javaArgType.isArray()) {
1707 return (javaArgType.isNIOBufferArray() ||
1708 javaArgType.isStringArray() ||
1709 javaArgType.getJavaClass().getComponentType().isArray());
1710 }
1711 if (javaArgType.isArrayOfCompoundTypeWrappers()) {
1712 return true;
1713 }
1714 return false;
1715 }
1716}
Machine data description for alignment and size onle, see com.jogamp.gluegen.
C code unit (a generated C source file), covering multiple FunctionEmitter allowing to unify output,...
Definition: CCodeUnit.java:37
static final String NewDirectByteBufferCopyUnitCode
Definition: CCodeUnit.java:89
Class that emits a generic comment for CMethodBindingEmitters; the comment includes the C signature o...
void emitEnding(final CMethodBindingEmitter 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 emitBeginning(final CMethodBindingEmitter emitter, final PrintWriter writer)
Emits the C-side component of the Java<->C JNI binding to its CodeUnit, see FunctionEmitter.
final void setTemporaryCVariableDeclarations(final List< String > arg)
Sets up a List of Strings containing declarations for temporary C variables to be assigned to after t...
int appendArguments(final StringBuilder buf)
Returns the number of arguments emitted.
void emitBodyUserVariableDeclarations()
Emits the user-defined C variable declarations from the TemporaryCVariableDeclarations directive in t...
final MachineDataInfo getMachineDataInfo()
Used for certain internal type size computations.
CMethodBindingEmitter(final MethodBinding binding, final CodeUnit unit, final String javaPackageName, final String javaClassName, final boolean isOverloadedBinding, final boolean isJavaMethodStatic, final boolean forImplementingMethodCall, final boolean forIndirectBufferAndArrayImplementation, final MachineDataInfo machDesc, final JavaConfiguration configuration)
Constructs an emitter for the specified binding, and sets a default comment emitter that will emit th...
void emitBodyVariablePostCallCleanup()
Code to clean up any variables that were declared in emitBodyVariableDeclarations(),...
int emitBodyPassCArguments()
Returns the number of arguments passed so calling code knows whether to print a comma.
final MessageFormat getReturnValueLengthExpression()
Get the expression for the length of the returned array.
StringBuilder appendName(final StringBuilder buf)
String jniMangle(final MethodBinding binding)
static final CommentEmitter defaultCommentEmitter
boolean javaArgTypeNeedsDataCopy(final JavaType javaArgType)
final List< String > getTemporaryCVariableDeclarations()
Returns the List of Strings containing declarations for temporary C variables to be assigned to after...
void emitBodyUserVariableAssignments()
Emits the user-defined C variable assignments from the TemporaryCVariableAssignments directive in the...
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),...
boolean isUTF8Type(Type type)
Checks a type to see whether it is for a UTF-8 pointer type (i.e., "const char *",...
final boolean forIndirectBufferAndArrayImplementation()
Is this CMethodBindingEmitter implementing the case of an indirect buffer or array being passed down ...
final boolean getIsOverloadedBinding()
Is the Java<->C JNI binding for this emitter's MethodBinding one of several overloaded methods with t...
void emitBodyVariablePreCallSetup()
Code to init the variables that were declared in emitBodyVariableDeclarations(), PRIOR TO calling the...
static StringBuilder appendJNIMangledArgs(final MethodBinding binding, final boolean forIndirectBufferAndArrayImplementation, final StringBuilder buf)
Return the mangled JNI argument names of given binding.
final void setReturnValueLengthExpression(final MessageFormat expression)
If this function returns an array, sets the expression for the length of the returned array.
String getJavaClassName()
Get the name of the package in which the corresponding Java method resides.
final boolean getIsJavaMethodStatic()
Is the Java side of the Java<->C JNI binding for this emitter's MethodBinding a static method?...
void setIsCStructFunctionPointer(final boolean v)
If method originates from a struct, see MethodBinding#hasContainingType(), it can either purposed to ...
String getJavaPackageName()
Get the name of the class in which the corresponding Java method resides.
final List< String > getTemporaryCVariableAssignments()
Returns the List of Strings containing assignments for temporary C variables which are made after the...
StringBuilder appendReturnType(final StringBuilder buf)
boolean emitBodyMapCToJNIType(final int argIdx, final boolean addLocalVar)
Emit code, converting a C type into a java JNI-type.
String pointerConversionArgumentName(final String argName)
final void setTemporaryCVariableAssignments(final List< String > arg)
Sets up a List of Strings containing assignments for temporary C variables which are made after the u...
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
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.
A generic exception for Jogamp errors used throughout the binding as a substitute for RuntimeExceptio...
void emitCAdditionalCode(final CodeUnit unit, final CMethodBindingEmitter jcbFuncCMethodEmitter)
Emit addition C code, i.e.
void appendCAdditionalJNIDescriptor(final StringBuilder buf)
void emitCOptArgumentSuffix(final CodeUnit unit, final int argIdx)
int appendCAdditionalParameter(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.
TypeInfo typeInfo(Type type)
If this type should be considered opaque, returns the TypeInfo describing the replacement type.
static String getJNIMethodNamePrefix(final String javaPackageName, final String javaClassName)
Returns the JNI method prefix consisting our of mangled package- and class-name.
static String jniMangle(final String name)
Mangle a class, package or function name for JNI usage, i.e.
Emits the Java-side component (interface and.or implementation) of the Java<->C JNI binding to its Co...
Describes a java-side representation of a type that is used to represent the same data on both the Ja...
Definition: JavaType.java:54
static StringBuilder appendJNIDescriptor(final StringBuilder res, final Class<?> c, final boolean useTrueType)
Appends the native (JNI) method-name descriptor corresponding to the given Class<?...
Definition: JavaType.java:471
String getName()
Returns the Java type name corresponding to this type.
Definition: JavaType.java:339
String getJNIMethodDesciptor()
Returns the native (JNI) method-name descriptor corresponding to this type, i.e.
Definition: JavaType.java:396
final PascalStringElem pascalStrElem
Definition: JavaType.java:124
String jniTypeName()
Returns the String corresponding to the JNI type for this type, or NULL if it can't be represented (i...
Definition: JavaType.java:528
boolean isArrayOfCompoundTypeWrappers()
Definition: JavaType.java:709
Class<?> getJavaClass()
Returns the Java Class corresponding to this type.
Definition: JavaType.java:332
static LoggerIf getLogger()
Returns the root package logger.
Definition: Logging.java:355
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 ...
Type getContainingCType()
Retrieves the containing C type of this MethodBinding if it is for a function pointer contained in a ...
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...
final Type getTargetType()
Helper method to returns the target type of this type, in case another type is being referenced,...
Definition: ArrayType.java:115
int getNumFields()
Returns the number of fields in this type.
Describes a function symbol, which includes the name and type.
ASTLocusTag getASTLocusTag()
Returns this instance's ASTLocusTag, if available, otherwise returns null.
Type getReturnType()
Returns the return type of this function.
final Type getTargetType()
Helper method to returns the target type of this type, in case another type is being referenced,...
final String getCName()
Returns the name of this type.
Definition: Type.java:132
final boolean isArray()
Indicates whether this is an ArrayType.
Definition: Type.java:409
final boolean isInt()
Indicates whether this is an IntType.
Definition: Type.java:399
final boolean isVoid()
Indicates whether this is a VoidType.
Definition: Type.java:415
final boolean isBaseTypeConst()
Checks the base type of pointer-to-pointer, pointer, array or plain for const-ness.
Definition: Type.java:440
final ASTLocusTag getASTLocusTag()
Returns this instance's ASTLocusTag, if available, otherwise returns null.
Definition: Type.java:125
Type getArrayBaseOrPointerTargetType()
Return getBaseType() if isArray() or returns getTargetType() otherwise.
Definition: Type.java:612
Type getBaseType()
Helper method to returns the bottom-most element type of this type, i.e.
Definition: Type.java:588
PointerType asPointer()
Casts this to a PointerType or returns null if not a PointerType.
Definition: Type.java:386
int pointerDepth()
Helper method for determining how many pointer indirections this type represents (i....
Definition: Type.java:564
Type getTargetType()
Helper method to returns the target type of this type, in case another type is being referenced,...
Definition: Type.java:605
boolean isPrimitive()
Indicates whether this type is a primitive type.
Definition: Type.java:426
final SizeThunk getSize()
SizeThunk which computes size of this type in bytes.
Definition: Type.java:360
ArrayType asArray()
Casts this to an ArrayType or returns null if not an ArrayType.
Definition: Type.java:388
final boolean isPointer()
Indicates whether this is a PointerType.
Definition: Type.java:407
CompoundType asCompound()
Casts this to a CompoundType or returns null if not a CompoundType.
Definition: Type.java:390
final boolean isCompound()
Indicates whether this is a CompoundType.
Definition: Type.java:411
An interface for Logger.
Definition: Logging.java:59
void warning(final String msg)
See Logger#warning(String).