001 /*******************************************************************************
002 * Copyright (C) 2009-2011 FuseSource Corp.
003 * Copyright (c) 2004, 2007 IBM Corporation and others.
004 *
005 * All rights reserved. This program and the accompanying materials
006 * are made available under the terms of the Eclipse Public License v1.0
007 * which accompanies this distribution, and is available at
008 * http://www.eclipse.org/legal/epl-v10.html
009 *
010 *******************************************************************************/
011 package org.fusesource.hawtjni.generator;
012
013 import java.lang.reflect.Modifier;
014 import java.util.ArrayList;
015 import java.util.List;
016
017 import org.fusesource.hawtjni.generator.model.JNIClass;
018 import org.fusesource.hawtjni.generator.model.JNIField;
019 import org.fusesource.hawtjni.generator.model.JNIMethod;
020 import org.fusesource.hawtjni.generator.model.JNIParameter;
021 import org.fusesource.hawtjni.generator.model.JNIType;
022 import org.fusesource.hawtjni.runtime.ArgFlag;
023 import org.fusesource.hawtjni.runtime.ClassFlag;
024 import org.fusesource.hawtjni.runtime.FieldFlag;
025 import org.fusesource.hawtjni.runtime.MethodFlag;
026
027 import static org.fusesource.hawtjni.runtime.MethodFlag.*;
028
029 /**
030 *
031 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
032 */
033 public class NativesGenerator extends JNIGenerator {
034
035 boolean enterExitMacro;
036
037 public NativesGenerator() {
038 enterExitMacro = true;
039 }
040
041 public void generateCopyright() {
042 outputln(fixDelimiter(getCopyright()));
043 }
044
045 public void generateIncludes() {
046 String outputName = getOutputName();
047 outputln("#include \"" + outputName + ".h\"");
048 outputln("#include \"hawtjni.h\"");
049 outputln("#include \"" + outputName + "_structs.h\"");
050 outputln("#include \"" + outputName + "_stats.h\"");
051 outputln();
052 }
053
054 public void generate(JNIClass clazz) {
055 List<JNIMethod> methods = clazz.getNativeMethods();
056 if( methods.isEmpty() ) {
057 return;
058 }
059 sortMethods(methods);
060 generateNativeMacro(clazz);
061 generate(methods);
062 }
063
064 public void generate(List<JNIMethod> methods) {
065 sortMethods(methods);
066 for (JNIMethod method : methods) {
067 if ((method.getModifiers() & Modifier.NATIVE) == 0)
068 continue;
069 generate(method);
070 if (progress != null)
071 progress.step();
072 }
073 }
074
075 boolean isStruct(ArgFlag flags[]) {
076 for (ArgFlag flag : flags) {
077 if (flag.equals(ArgFlag.BY_VALUE))
078 return true;
079 }
080 return false;
081 }
082
083 void generateCallback(JNIMethod method, String function, List<JNIParameter> params, JNIType returnType) {
084 output("static jintLong ");
085 output(function);
086 outputln(";");
087 output("static ");
088 String[] types = method.getCallbackTypes();
089 ArgFlag[][] flags = method.getCallbackFlags();
090 output(types[0]);
091 output(" ");
092 output("proc_");
093 output(function);
094 output("(");
095 boolean first = true;
096 for (int i = 1; i < types.length; i++) {
097 if (!first)
098 output(", ");
099 output(types[i]);
100 output(" ");
101 output("arg");
102 output(String.valueOf(i - 1));
103 first = false;
104 }
105 outputln(") {");
106
107 output("\t");
108 if (isStruct(flags[0])) {
109 output(types[0]);
110 output("* lprc = ");
111 } else if (!types[0].equals("void")) {
112 output("return ");
113 }
114 output("((");
115 output(types[0]);
116 if (isStruct(flags[0]))
117 output("*");
118 output(" (*)(");
119 first = true;
120 for (int i = 1; i < types.length; i++) {
121 if (!first)
122 output(", ");
123 first = false;
124 output(types[i]);
125 if (isStruct(flags[i]))
126 output("*");
127 }
128 output("))");
129 output(function);
130 output(")(");
131 first = true;
132 for (int i = 1; i < types.length; i++) {
133 if (!first)
134 output(", ");
135 first = false;
136 if (isStruct(flags[i]))
137 output("&");
138 output("arg");
139 output(String.valueOf(i - 1));
140 }
141 outputln(");");
142 if (isStruct(flags[0])) {
143 output("\t");
144 output(types[0]);
145 outputln(" rc;");
146 outputln("\tif (lprc) {");
147 outputln("\t\trc = *lprc;");
148 outputln("\t\tfree(lprc);");
149 outputln("\t} else {");
150 output("\t\tmemset(&rc, 0, sizeof(");
151 output(types[0]);
152 outputln("));");
153 outputln("\t}");
154 outputln("\treturn rc;");
155 }
156 outputln("}");
157
158 output("static jintLong ");
159 output(method.getName());
160 outputln("(jintLong func) {");
161 output("\t");
162 output(function);
163 outputln(" = func;");
164 output("\treturn (jintLong)proc_");
165 output(function);
166 outputln(";");
167 outputln("}");
168 }
169
170 private void generateConstantsInitializer(JNIMethod method) {
171 JNIClass clazz = method.getDeclaringClass();
172 ArrayList<JNIField> constants = getConstantFields(clazz);
173 if( constants.isEmpty() ) {
174 return;
175 }
176
177 if (isCPP) {
178 output("extern \"C\" ");
179 }
180 outputln("JNIEXPORT void JNICALL "+clazz.getSimpleName()+"_NATIVE("+toC(method.getName())+")(JNIEnv *env, jclass that)");
181 outputln("{");
182 for (JNIField field : constants) {
183
184 String conditional = field.getConditional();
185 if (conditional!=null) {
186 outputln("#if "+conditional);
187 }
188 JNIType type = field.getType(), type64 = field.getType64();
189 boolean allowConversion = !type.equals(type64);
190
191 String simpleName = type.getSimpleName();
192 String accessor = field.getAccessor();
193 if (accessor == null || accessor.length() == 0)
194 accessor = field.getName();
195
196 String fieldId = "(*env)->GetStaticFieldID(env, that, \""+field.getName()+"\", \""+type.getTypeSignature(allowConversion)+"\")";
197 if (isCPP) {
198 fieldId = "env->GetStaticFieldID(that, \""+field.getName()+"\", \""+type.getTypeSignature(allowConversion)+"\")";
199 }
200
201 if (type.isPrimitive()) {
202 if (isCPP) {
203 output("\tenv->SetStatic"+type.getTypeSignature1(allowConversion)+"Field(that, "+fieldId +", ");
204 } else {
205 output("\t(*env)->SetStatic"+type.getTypeSignature1(allowConversion)+"Field(env, that, "+fieldId +", ");
206 }
207 output("("+type.getTypeSignature2(allowConversion)+")");
208 if( field.isPointer() ) {
209 output("(intptr_t)");
210 }
211 output(accessor);
212 output(");");
213
214 } else if (type.isArray()) {
215 JNIType componentType = type.getComponentType(), componentType64 = type64.getComponentType();
216 if (componentType.isPrimitive()) {
217 outputln("\t{");
218 output("\t");
219 output(type.getTypeSignature2(allowConversion));
220 output(" lpObject1 = (");
221 output(type.getTypeSignature2(allowConversion));
222 if (isCPP) {
223 output(")env->GetStaticObjectField(that, ");
224 } else {
225 output(")(*env)->GetStaticObjectField(env, that, ");
226 }
227 output(field.getDeclaringClass().getSimpleName());
228 output(fieldId);
229 outputln(");");
230 if (isCPP) {
231 output("\tenv->Set");
232 } else {
233 output("\t(*env)->Set");
234 }
235 output(componentType.getTypeSignature1(!componentType.equals(componentType64)));
236 if (isCPP) {
237 output("ArrayRegion(lpObject1, 0, sizeof(");
238 } else {
239 output("ArrayRegion(env, lpObject1, 0, sizeof(");
240 }
241 output(accessor);
242 output(")");
243 if (!componentType.isType("byte")) {
244 output(" / sizeof(");
245 output(componentType.getTypeSignature2(!componentType.equals(componentType64)));
246 output(")");
247 }
248 output(", (");
249 output(type.getTypeSignature4(allowConversion, false));
250 output(")");
251 output(accessor);
252 outputln(");");
253 output("\t}");
254 } else {
255 throw new Error("not done");
256 }
257 } else {
258 outputln("\t{");
259 if (isCPP) {
260 output("\tjobject lpObject1 = env->GetStaticObjectField(that, ");
261 } else {
262 output("\tjobject lpObject1 = (*env)->GetStaticObjectField(env, that, ");
263 }
264 output(field.getDeclaringClass().getSimpleName());
265 output("Fc.");
266 output(field.getName());
267 outputln(");");
268 output("\tif (lpObject1 != NULL) set");
269 output(simpleName);
270 output("Fields(env, lpObject1, &lpStruct->");
271 output(accessor);
272 outputln(");");
273 output("\t}");
274 }
275 outputln();
276 if (conditional!=null) {
277 outputln("#endif");
278 }
279 }
280 outputln(" return;");
281 outputln("}");
282
283 }
284
285 private ArrayList<JNIField> getConstantFields(JNIClass clazz) {
286 ArrayList<JNIField> rc = new ArrayList<JNIField>();
287 List<JNIField> fields = clazz.getDeclaredFields();
288 for (JNIField field : fields) {
289 int mods = field.getModifiers();
290 if ( (mods & Modifier.STATIC) != 0 && field.getFlag(FieldFlag.CONSTANT)) {
291 rc.add(field);
292 }
293 }
294 return rc;
295 }
296
297 public void generate(JNIMethod method) {
298 if (method.getFlag(MethodFlag.METHOD_SKIP))
299 return;
300
301 JNIType returnType = method.getReturnType32(), returnType64 = method.getReturnType64();
302
303 if( method.getFlag(CONSTANT_INITIALIZER)) {
304 if( returnType.isType("void") && method.getParameters().isEmpty() ) {
305 generateConstantsInitializer(method);
306 } else {
307 output("#error Warning: invalid CONSTANT_INITIALIZER tagged method. It must be void and take no arguments: ");
308 outputln(method.toString());
309 }
310 return;
311 }
312
313 if (!(returnType.isType("void") || returnType.isPrimitive() || isSystemClass(returnType) || returnType.isType("java.lang.String"))) {
314 output("#error Warning: bad return type. :");
315 outputln(method.toString());
316 return;
317 }
318
319 String conditional = method.getConditional();
320 if (conditional!=null) {
321 outputln("#if "+conditional);
322 }
323
324 List<JNIParameter> params = method.getParameters();
325 String function = getFunctionName(method), function64 = getFunctionName(method, method.getParameterTypes64());
326 boolean sameFunction = function.equals(function64);
327 if (!sameFunction) {
328 output("#ifndef ");
329 output(JNI64);
330 outputln();
331 }
332 if (isCPP) {
333 output("extern \"C\" ");
334 generateFunctionPrototype(method, function, params, returnType, returnType64, true);
335 outputln(";");
336 }
337 if (function.startsWith("CALLBACK_")) {
338 generateCallback(method, function, params, returnType);
339 }
340 generateFunctionPrototype(method, function, params, returnType, returnType64, !sameFunction);
341 if (!function.equals(function64)) {
342 outputln();
343 outputln("#else");
344 if (isCPP) {
345 output("extern \"C\" ");
346 generateFunctionPrototype(method, function64, params, returnType, returnType64, true);
347 outputln(";");
348 }
349 generateFunctionPrototype(method, function64, params, returnType, returnType64, !sameFunction);
350 outputln();
351 outputln("#endif");
352 }
353 generateFunctionBody(method, function, function64, params, returnType, returnType64);
354 if (conditional!=null) {
355 outputln("#endif");
356 }
357 outputln();
358 }
359
360 public void setEnterExitMacro(boolean enterExitMacro) {
361 this.enterExitMacro = enterExitMacro;
362 }
363
364 void generateNativeMacro(JNIClass clazz) {
365 output("#define ");
366 output(clazz.getSimpleName());
367 output("_NATIVE(func) Java_");
368 output(toC(clazz.getName()));
369 outputln("_##func");
370 outputln();
371 }
372
373 boolean generateGetParameter(JNIMethod method, JNIParameter param, boolean critical, int indent) {
374 JNIType paramType = param.getType32(), paramType64 = param.getType64();
375 if (paramType.isPrimitive() || isSystemClass(paramType))
376 return false;
377 String iStr = String.valueOf(param.getParameter());
378 for (int j = 0; j < indent; j++)
379 output("\t");
380 output("if (arg");
381 output(iStr);
382 output(") if ((lparg");
383 output(iStr);
384 output(" = ");
385 if (paramType.isArray()) {
386 JNIType componentType = paramType.getComponentType();
387 if (componentType.isPrimitive()) {
388 if( "long".equals( componentType.getName() ) && param.isPointer() ) {
389 // This case is special as we may need to do pointer conversions..
390 // if your on a 32 bit system but are keeping track of the pointers in a 64 bit long
391 output("hawtjni_malloc_pointer_array(env, arg");
392 output(iStr);
393 output(")");
394 } else if (critical) {
395 if (isCPP) {
396 output("(");
397 output(componentType.getTypeSignature2(!paramType.equals(paramType64)));
398 output("*)");
399 output("env->GetPrimitiveArrayCritical(arg");
400 } else {
401 output("(*env)->GetPrimitiveArrayCritical(env, arg");
402 }
403 output(iStr);
404 output(", NULL)");
405 } else {
406 if (isCPP) {
407 output("env->Get");
408 } else {
409 output("(*env)->Get");
410 }
411 output(componentType.getTypeSignature1(!paramType.equals(paramType64)));
412 if (isCPP) {
413 output("ArrayElements(arg");
414 } else {
415 output("ArrayElements(env, arg");
416 }
417 output(iStr);
418 output(", NULL)");
419 }
420 } else {
421 throw new Error("not done");
422 }
423 } else if (paramType.isType("java.lang.String")) {
424 if (param.getFlag(ArgFlag.UNICODE)) {
425 if (isCPP) {
426 output("env->GetStringChars(arg");
427 } else {
428 output("(*env)->GetStringChars(env, arg");
429 }
430 output(iStr);
431 output(", NULL)");
432 } else {
433 if (isCPP) {
434 output("env->GetStringUTFChars(arg");
435 } else {
436 output("(*env)->GetStringUTFChars(env, arg");
437 }
438 output(iStr);
439 output(", NULL)");
440 }
441 } else {
442 if (param.getFlag(ArgFlag.NO_IN)) {
443 output("&_arg");
444 output(iStr);
445 } else {
446 output("get");
447 output(paramType.getSimpleName());
448 output("Fields(env, arg");
449 output(iStr);
450 output(", &_arg");
451 output(iStr);
452 output(")");
453 }
454 }
455 outputln(") == NULL) goto fail;");
456 return true;
457 }
458
459 void generateSetParameter(JNIParameter param, boolean critical) {
460 JNIType paramType = param.getType32(), paramType64 = param.getType64();
461 if (paramType.isPrimitive() || isSystemClass(paramType))
462 return;
463 String iStr = String.valueOf(param.getParameter());
464 if (paramType.isArray()) {
465 output("\tif (arg");
466 output(iStr);
467 output(" && lparg");
468 output(iStr);
469 output(") ");
470 JNIType componentType = paramType.getComponentType();
471 if (componentType.isPrimitive()) {
472 if( "long".equals( componentType.getName() ) && param.isPointer() ) {
473 // This case is special as we may need to do pointer conversions..
474 // if your on a 32 bit system but are keeping track of the pointers in a 64 bit long
475 output("hawtjni_free_pointer_array(env, arg");
476 output(iStr);
477 } else if (critical) {
478 if (isCPP) {
479 output("env->ReleasePrimitiveArrayCritical(arg");
480 } else {
481 output("(*env)->ReleasePrimitiveArrayCritical(env, arg");
482 }
483 output(iStr);
484 } else {
485 if (isCPP) {
486 output("env->Release");
487 } else {
488 output("(*env)->Release");
489 }
490 output(componentType.getTypeSignature1(!paramType.equals(paramType64)));
491 if (isCPP) {
492 output("ArrayElements(arg");
493 } else {
494 output("ArrayElements(env, arg");
495 }
496 output(iStr);
497 }
498 output(", lparg");
499 output(iStr);
500 output(", ");
501 if (param.getFlag(ArgFlag.NO_OUT)) {
502 output("JNI_ABORT");
503 } else {
504 output("0");
505 }
506 output(");");
507 } else {
508 throw new Error("not done");
509 }
510 outputln();
511 } else if (paramType.isType("java.lang.String")) {
512 output("\tif (arg");
513 output(iStr);
514 output(" && lparg");
515 output(iStr);
516 output(") ");
517 if (param.getFlag(ArgFlag.UNICODE)) {
518 if (isCPP) {
519 output("env->ReleaseStringChars(arg");
520 } else {
521 output("(*env)->ReleaseStringChars(env, arg");
522 }
523 } else {
524 if (isCPP) {
525 output("env->ReleaseStringUTFChars(arg");
526 } else {
527 output("(*env)->ReleaseStringUTFChars(env, arg");
528 }
529 }
530 output(iStr);
531 output(", lparg");
532 output(iStr);
533 outputln(");");
534 } else {
535 if (!param.getFlag(ArgFlag.NO_OUT)) {
536 output("\tif (arg");
537 output(iStr);
538 output(" && lparg");
539 output(iStr);
540 output(") ");
541 output("set");
542 output(paramType.getSimpleName());
543 output("Fields(env, arg");
544 output(iStr);
545 output(", lparg");
546 output(iStr);
547 outputln(");");
548 }
549 }
550 }
551
552 void generateEnterExitMacro(JNIMethod method, String function, String function64, boolean enter) {
553 if (!enterExitMacro)
554 return;
555 if (!function.equals(function64)) {
556 output("#ifndef ");
557 output(JNI64);
558 outputln();
559 }
560 output("\t");
561 output(method.getDeclaringClass().getSimpleName());
562 output("_NATIVE_");
563 output(enter ? "ENTER" : "EXIT");
564 output("(env, that, ");
565 output(method.getDeclaringClass().getSimpleName()+"_"+function);
566 outputln("_FUNC);");
567 if (!function.equals(function64)) {
568 outputln("#else");
569 output("\t");
570 output(method.getDeclaringClass().getSimpleName());
571 output("_NATIVE_");
572 output(enter ? "ENTER" : "EXIT");
573 output("(env, that, ");
574 output(method.getDeclaringClass().getSimpleName()+"_"+function64);
575 outputln("_FUNC);");
576 outputln("#endif");
577 }
578 }
579
580 boolean generateLocalVars(JNIMethod method, List<JNIParameter> params, JNIType returnType, JNIType returnType64) {
581 boolean needsReturn = enterExitMacro;
582 for (int i = 0; i < params.size(); i++) {
583 JNIParameter param = params.get(i);
584 JNIType paramType = param.getType32(), paramType64 = param.getType64();
585 if (paramType.isPrimitive() || isSystemClass(paramType))
586 continue;
587 output("\t");
588 if (paramType.isArray()) {
589 JNIType componentType = paramType.getComponentType();
590 if( "long".equals( componentType.getName() ) && param.isPointer() ) {
591 output("void **lparg" + i+"=NULL;");
592 } else if (componentType.isPrimitive()) {
593 output(componentType.getTypeSignature2(!paramType.equals(paramType64)));
594 output(" *lparg" + i);
595 output("=NULL;");
596 } else {
597 throw new Error("not done");
598 }
599 } else if (paramType.isType("java.lang.String")) {
600 if (param.getFlag(ArgFlag.UNICODE)) {
601 output("const jchar *lparg" + i);
602 } else {
603 output("const char *lparg" + i);
604 }
605 output("= NULL;");
606 } else {
607 if (param.getTypeClass().getFlag(ClassFlag.STRUCT) && !param.getTypeClass().getFlag(ClassFlag.TYPEDEF)) {
608 output("struct ");
609 }
610 output(paramType.getNativeName());
611 output(" _arg" + i);
612 if (param.getFlag(ArgFlag.INIT))
613 output("={0}");
614 output(", *lparg" + i);
615 output("=NULL;");
616 }
617 outputln();
618 needsReturn = true;
619 }
620 if (needsReturn) {
621 if (!returnType.isType("void")) {
622 output("\t");
623 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
624 outputln(" rc = 0;");
625 }
626 }
627 return needsReturn;
628 }
629
630 boolean generateGetters(JNIMethod method, List<JNIParameter> params) {
631 boolean genFailTag = false;
632 int criticalCount = 0;
633 for (JNIParameter param : params) {
634 if (!isCritical(param)) {
635 genFailTag |= generateGetParameter(method, param, false, 1);
636 } else {
637 criticalCount++;
638 }
639 }
640 if (criticalCount != 0) {
641 outputln("#ifdef JNI_VERSION_1_2");
642 outputln("\tif (IS_JNI_1_2) {");
643 for (JNIParameter param : params) {
644 if (isCritical(param)) {
645 genFailTag |= generateGetParameter(method, param, true, 2);
646 }
647 }
648 outputln("\t} else");
649 outputln("#endif");
650 outputln("\t{");
651 for (JNIParameter param : params) {
652 if (isCritical(param)) {
653 genFailTag |= generateGetParameter(method, param, false, 2);
654 }
655 }
656 outputln("\t}");
657 }
658 return genFailTag;
659 }
660
661 void generateSetters(JNIMethod method, List<JNIParameter> params) {
662 int criticalCount = 0;
663 for (int i = params.size() - 1; i >= 0; i--) {
664 JNIParameter param = params.get(i);
665 if (isCritical(param)) {
666 criticalCount++;
667 }
668 }
669 if (criticalCount != 0) {
670 outputln("#ifdef JNI_VERSION_1_2");
671 outputln("\tif (IS_JNI_1_2) {");
672 for (int i = params.size() - 1; i >= 0; i--) {
673 JNIParameter param = params.get(i);
674 if (isCritical(param)) {
675 output("\t");
676 generateSetParameter(param, true);
677 }
678 }
679 outputln("\t} else");
680 outputln("#endif");
681 outputln("\t{");
682 for (int i = params.size() - 1; i >= 0; i--) {
683 JNIParameter param = params.get(i);
684 if (isCritical(param)) {
685 output("\t");
686 generateSetParameter(param, false);
687 }
688 }
689 outputln("\t}");
690 }
691 for (int i = params.size() - 1; i >= 0; i--) {
692 JNIParameter param = params.get(i);
693 if (!isCritical(param)) {
694 generateSetParameter(param, false);
695 }
696 }
697 }
698
699 void generateDynamicFunctionCall(JNIMethod method, List<JNIParameter> params, JNIType returnType, JNIType returnType64, boolean needsReturn) {
700 outputln("/*");
701 generateFunctionCall(method, params, returnType, returnType64, needsReturn);
702 outputln("*/");
703 outputln("\t{");
704
705 String name = method.getName();
706 if (name.startsWith("_"))
707 name = name.substring(1);
708 output("\t\tLOAD_FUNCTION(fp, ");
709 output(name);
710 outputln(")");
711 outputln("\t\tif (fp) {");
712 output("\t\t");
713 generateFunctionCallLeftSide(method, returnType, returnType64, needsReturn);
714 output("((");
715 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
716 output(" (CALLING_CONVENTION*)(");
717 for (int i = 0; i < params.size(); i++) {
718 if (i != 0)
719 output(", ");
720 JNIParameter param = params.get(i);
721 String cast = param.getCast();
722 if( param.isPointer() ) {
723 output("(intptr_t)");
724 }
725 boolean isStruct = param.getFlag(ArgFlag.BY_VALUE);
726 if (cast.length() > 2) {
727 cast = cast.substring(1, cast.length() - 1);
728 if (isStruct) {
729 int index = cast.lastIndexOf('*');
730 if (index != -1)
731 cast = cast.substring(0, index).trim();
732 }
733 output(cast);
734 } else {
735 JNIType paramType = param.getType32(), paramType64 = param.getType64();
736 output(paramType.getTypeSignature4(!paramType.equals(paramType64), isStruct));
737 }
738 }
739 output("))");
740 output("fp");
741 output(")");
742 generateFunctionCallRightSide(method, params, 0);
743 output(";");
744 outputln();
745 outputln("\t\t}");
746 outputln("\t}");
747 }
748
749 void generateFunctionCallLeftSide(JNIMethod method, JNIType returnType, JNIType returnType64, boolean needsReturn) {
750 output("\t");
751 if (!returnType.isType("void")) {
752 if (needsReturn) {
753 output("rc = ");
754 } else {
755 output("return ");
756 }
757
758 String cast = method.getCast();
759 if (cast.length() != 0 && !cast.equals("()")) {
760 if( method.isPointer() ) {
761 output("(intptr_t)");
762 }
763 output(cast);
764 } else {
765 if( method.getFlag(CPP_NEW)) {
766 String[] parts = getNativeNameParts(method);
767 String className = parts[0];
768 output("(intptr_t)("+className+" *)");
769 } else {
770 output("(");
771 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
772 output(")");
773 }
774 }
775 }
776 if (method.getFlag(MethodFlag.ADDRESS)) {
777 output("&");
778 }
779 if (method.getFlag(MethodFlag.JNI)) {
780 output(isCPP ? "env->" : "(*env)->");
781 }
782 }
783
784 void generateFunctionCallRightSide(JNIMethod method, List<JNIParameter> params, int paramStart) {
785 if (!method.getFlag(MethodFlag.CONSTANT_GETTER)) {
786 output("(");
787 if (method.getFlag(MethodFlag.JNI)) {
788 if (!isCPP)
789 output("env, ");
790 }
791 for (int i = paramStart; i < params.size(); i++) {
792 JNIParameter param = params.get(i);
793 if (i != paramStart)
794 output(", ");
795 if (param.getFlag(ArgFlag.BY_VALUE))
796 output("*");
797 output(param.getCast());
798 if( param.isPointer() ) {
799 output("(intptr_t)");
800 }
801 if (param.getFlag(ArgFlag.CS_OBJECT))
802 output("TO_OBJECT(");
803 if (i == params.size() - 1 && param.getFlag(ArgFlag.SENTINEL)) {
804 output("NULL");
805 } else {
806 JNIType paramType = param.getType32();
807 if (!paramType.isPrimitive() && !isSystemClass(paramType))
808 output("lp");
809 output("arg" + i);
810 }
811 if (param.getFlag(ArgFlag.CS_OBJECT))
812 output(")");
813 }
814 output(")");
815 }
816 }
817
818 static String[] getNativeNameParts(JNIMethod method) {
819 String className = null;
820 String methodName = null;
821
822 JNIClass dc = method.getDeclaringClass();
823 if( dc.getFlag(ClassFlag.CPP) || dc.getFlag(ClassFlag.STRUCT) ) {
824 className = method.getDeclaringClass().getNativeName();
825 }
826
827 if( method.getAccessor().length() != 0 ) {
828 methodName = method.getAccessor();
829 int pos = methodName.lastIndexOf("::");
830 if( pos >= 0 ) {
831 className = methodName.substring(0, pos);
832 methodName = methodName.substring(pos+2);
833 }
834 } else {
835 methodName = method.getName();
836 if( className==null ) {
837 int pos = methodName.indexOf("_");
838 if( pos > 0 ) {
839 className = methodName.substring(0, pos);
840 methodName = methodName.substring(pos+1);
841 }
842 }
843 }
844 if( className==null ) {
845 throw new Error(String.format("Could not determine object type name of method '%s'", method.getDeclaringClass().getSimpleName()+"."+method.getName()));
846 }
847 return new String[]{className, methodName};
848 }
849
850 void generateFunctionCall(JNIMethod method, List<JNIParameter> params, JNIType returnType, JNIType returnType64, boolean needsReturn) {
851 String name = method.getName();
852 String copy = method.getCopy();
853 boolean makeCopy = copy.length() != 0 && isCPP && !returnType.isType("void");
854 if (makeCopy) {
855 output("\t{");
856 output("\t\t");
857 output(copy);
858 output(" temp = ");
859 } else {
860 generateFunctionCallLeftSide(method, returnType, returnType64, needsReturn);
861 }
862 int paramStart = 0;
863 if (name.startsWith("_"))
864 name = name.substring(1);
865
866 boolean objc_struct = false;
867 if (name.equals("objc_msgSend_stret") || name.equals("objc_msgSendSuper_stret"))
868 objc_struct = true;
869 if (objc_struct) {
870 outputln("if (sizeof(_arg0) > STRUCT_SIZE_LIMIT) {");
871 generate_objc_msgSend_stret(method, params, name);
872 paramStart = 1;
873 } else if (name.equalsIgnoreCase("call")) {
874 output("(");
875 JNIParameter param = params.get(0);
876 String cast = param.getCast();
877 if (cast.length() != 0 && !cast.equals("()")) {
878 output(cast);
879 if( param.isPointer() ) {
880 output("(intptr_t)");
881 }
882 } else {
883 output("(");
884 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
885 output(" (*)())");
886 }
887 output("arg0)");
888 paramStart = 1;
889 } else if (name.startsWith("VtblCall") || name.startsWith("_VtblCall")) {
890 output("((");
891 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
892 output(" (STDMETHODCALLTYPE *)(");
893 for (int i = 1; i < params.size(); i++) {
894 if (i != 1)
895 output(", ");
896 JNIParameter param = params.get(i);
897 JNIType paramType = param.getType32(), paramType64 = param.getType64();
898 output(paramType.getTypeSignature4(!paramType.equals(paramType64), false));
899 }
900 output("))(*(");
901 JNIType paramType = params.get(1).getType32(), paramType64 = params.get(1).getType64();
902 output(paramType.getTypeSignature4(!paramType.equals(paramType64), false));
903 output(" **)arg1)[arg0])");
904 paramStart = 1;
905 } else if (method.getFlag(MethodFlag.CPP_METHOD) || method.getFlag(MethodFlag.SETTER) || method.getFlag(MethodFlag.GETTER) || method.getFlag(MethodFlag.ADDER)) {
906
907 String[] parts = getNativeNameParts(method);
908 String className = parts[0];
909 String methodName = parts[1];
910
911 if (method.getFlag(MethodFlag.CS_OBJECT)) {
912 output("TO_HANDLE(");
913 }
914 output("(");
915 if( params.isEmpty() ) {
916 throw new Error(String.format("C++ bound method '%s' missing the 'this' parameter", method.getDeclaringClass().getSimpleName()+"."+method.getName()));
917 }
918 JNIParameter param = params.get(0);
919 if (param.getFlag(ArgFlag.BY_VALUE))
920 output("*");
921 String cast = param.getCast();
922 if (cast.length() != 0 && !cast.equals("()")) {
923 output(cast);
924 if( param.isPointer() ) {
925 output("(intptr_t)");
926 }
927 } else {
928 output("("+className+" *)(intptr_t)");
929 }
930 if (param.getFlag(ArgFlag.CS_OBJECT)) {
931 output("TO_OBJECT(");
932 }
933 output("arg0");
934 if (param.getFlag(ArgFlag.CS_OBJECT)) {
935 output(")");
936 }
937 output(")->");
938 output(methodName);
939 paramStart = 1;
940 } else if (method.getFlag(MethodFlag.CS_NEW)) {
941 output("TO_HANDLE(gcnew ");
942 String accessor = method.getAccessor();
943 if (accessor.length() != 0) {
944 output(accessor);
945 } else {
946 JNIClass dc = method.getDeclaringClass();
947 if( dc.getFlag(ClassFlag.CPP) || dc.getFlag(ClassFlag.STRUCT) ) {
948 output(dc.getNativeName());
949 } else {
950 int index = -1;
951 if ((index = name.indexOf('_')) != -1) {
952 output(name.substring(index + 1));
953 } else {
954 output(name);
955 }
956 }
957 }
958 } else if (method.getFlag(MethodFlag.CPP_NEW)) {
959 if (method.getFlag(MethodFlag.CS_OBJECT)) {
960 output("TO_HANDLE(");
961 }
962 output("new ");
963 String accessor = method.getAccessor();
964 if (accessor.length() != 0) {
965 output(accessor);
966 } else {
967
968 JNIClass dc = method.getDeclaringClass();
969 if( dc.getFlag(ClassFlag.CPP) ) {
970 output(method.getDeclaringClass().getNativeName());
971 } else {
972 int index = -1;
973 if ((index = name.indexOf('_')) != -1) {
974 output(name.substring(index+1));
975 } else {
976 output(name);
977 }
978 }
979
980 }
981 } else if (method.getFlag(MethodFlag.CPP_DELETE)) {
982 String[] parts = getNativeNameParts(method);
983 String className = parts[0];
984
985 output("delete ");
986 JNIParameter param = params.get(0);
987 String cast = param.getCast();
988 if (cast.length() != 0 && !cast.equals("()")) {
989 output(cast);
990 if( param.isPointer() ) {
991 output("(intptr_t)");
992 }
993 } else {
994 output("("+className+" *)(intptr_t)");
995 }
996 outputln("arg0;");
997 return;
998 } else {
999 if (method.getFlag(MethodFlag.CS_OBJECT)) {
1000 output("TO_HANDLE(");
1001 }
1002 if (method.getFlag(MethodFlag.CAST)) {
1003 output("((");
1004 String returnCast = returnType.getTypeSignature2(!returnType.equals(returnType64));
1005 if (name.equals("objc_msgSend_bool") && returnCast.equals("jboolean")) {
1006 returnCast = "BOOL";
1007 }
1008 output(returnCast);
1009 output(" (*)(");
1010 for (int i = 0; i < params.size(); i++) {
1011 if (i != 0)
1012 output(", ");
1013 JNIParameter param = params.get(i);
1014 String cast = param.getCast();
1015 if (cast.length() != 0 && !cast.equals("()") ) {
1016 if (cast.startsWith("("))
1017 cast = cast.substring(1);
1018 if (cast.endsWith(")"))
1019 cast = cast.substring(0, cast.length() - 1);
1020 output(cast);
1021 } else {
1022 JNIType paramType = param.getType32(), paramType64 = param.getType64();
1023 if (!(paramType.isPrimitive() || paramType.isArray())) {
1024 if (param.getTypeClass().getFlag(ClassFlag.STRUCT) && !param.getTypeClass().getFlag(ClassFlag.TYPEDEF)) {
1025 output("struct ");
1026 }
1027 }
1028 output(paramType.getTypeSignature4(!paramType.equals(paramType64), param.getFlag(ArgFlag.BY_VALUE)));
1029 }
1030 }
1031 output("))");
1032 }
1033 String accessor = method.getAccessor();
1034 if (accessor.length() != 0) {
1035 output(accessor);
1036 } else {
1037 output(name);
1038 }
1039 if (method.getFlag(MethodFlag.CAST)) {
1040 output(")");
1041 }
1042 }
1043 if ((method.getFlag(MethodFlag.SETTER) && params.size() == 3) || (method.getFlag(MethodFlag.GETTER) && params.size() == 2)) {
1044 output("[arg1]");
1045 paramStart++;
1046 }
1047 if (method.getFlag(MethodFlag.SETTER))
1048 output(" = ");
1049 if (method.getFlag(MethodFlag.ADDER))
1050 output(" += ");
1051 if (!method.getFlag(MethodFlag.GETTER)) {
1052 generateFunctionCallRightSide(method, params, paramStart);
1053 }
1054 if (method.getFlag(MethodFlag.CS_NEW) || method.getFlag(MethodFlag.CS_OBJECT)) {
1055 output(")");
1056 }
1057 output(";");
1058 outputln();
1059 if (makeCopy) {
1060 outputln("\t\t{");
1061 output("\t\t\t");
1062 output(copy);
1063 output("* copy = new ");
1064 output(copy);
1065 outputln("();");
1066 outputln("\t\t\t*copy = temp;");
1067 output("\t\t\trc = ");
1068 output("(");
1069 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
1070 output(")");
1071 outputln("copy;");
1072 outputln("\t\t}");
1073 outputln("\t}");
1074 }
1075 if (objc_struct) {
1076 outputln("\t} else {");
1077 generate_objc_msgSend_stret(method, params, name.substring(0, name.length() - "_stret".length()));
1078 generateFunctionCallRightSide(method, params, 1);
1079 outputln(";");
1080 outputln("\t}");
1081 }
1082 }
1083
1084 void generate_objc_msgSend_stret(JNIMethod method, List<JNIParameter> params, String func) {
1085 output("\t\t*lparg0 = (*(");
1086 JNIType paramType = params.get(0).getType32(), paramType64 = params.get(0).getType64();
1087 output(paramType.getTypeSignature4(!paramType.equals(paramType64), true));
1088 output(" (*)(");
1089 for (int i = 1; i < params.size(); i++) {
1090 if (i != 1)
1091 output(", ");
1092 JNIParameter param = params.get(i);
1093 String cast = param.getCast();
1094 if( param.isPointer() ) {
1095 output("(intptr_t)");
1096 }
1097 if (cast.length() != 0 && !cast.equals("()")) {
1098 if (cast.startsWith("("))
1099 cast = cast.substring(1);
1100 if (cast.endsWith(")"))
1101 cast = cast.substring(0, cast.length() - 1);
1102 output(cast);
1103 } else {
1104 paramType = param.getType32();
1105 paramType64 = param.getType64();
1106 if (!(paramType.isPrimitive() || paramType.isArray())) {
1107 if (param.getTypeClass().getFlag(ClassFlag.STRUCT) && !param.getTypeClass().getFlag(ClassFlag.TYPEDEF)) {
1108 output("struct ");
1109 }
1110 }
1111 output(paramType.getTypeSignature4(!paramType.equals(paramType64), param.getFlag(ArgFlag.BY_VALUE)));
1112 }
1113 }
1114 output("))");
1115 output(func);
1116 output(")");
1117 }
1118
1119 void generateReturn(JNIMethod method, JNIType returnType, boolean needsReturn) {
1120 if (needsReturn && !returnType.isType("void")) {
1121 outputln("\treturn rc;");
1122 }
1123 }
1124
1125 void generateMemmove(JNIMethod method, String function, String function64, List<JNIParameter> params) {
1126 generateEnterExitMacro(method, function, function64, true);
1127 output("\t");
1128 boolean get = params.get(0).getType32().isPrimitive();
1129 String className = params.get(get ? 1 : 0).getType32().getSimpleName();
1130 output(get ? "if (arg1) get" : "if (arg0) set");
1131 output(className);
1132 output(get ? "Fields(env, arg1, (" : "Fields(env, arg0, (");
1133 output(className);
1134 output(get ? " *)arg0)" : " *)arg1)");
1135 outputln(";");
1136 generateEnterExitMacro(method, function, function64, false);
1137 }
1138
1139 void generateFunctionBody(JNIMethod method, String function, String function64, List<JNIParameter> params, JNIType returnType, JNIType returnType64) {
1140 outputln("{");
1141
1142 /* Custom GTK memmoves. */
1143 String name = method.getName();
1144 if (name.startsWith("_"))
1145 name = name.substring(1);
1146 boolean isMemove = (name.equals("memmove") || name.equals("MoveMemory")) && params.size() == 2 && returnType.isType("void");
1147 if (isMemove) {
1148 generateMemmove(method, function, function64, params);
1149 } else {
1150 boolean needsReturn = generateLocalVars(method, params, returnType, returnType64);
1151 generateEnterExitMacro(method, function, function64, true);
1152 boolean genFailTag = generateGetters(method, params);
1153 if (method.getFlag(MethodFlag.DYNAMIC)) {
1154 generateDynamicFunctionCall(method, params, returnType, returnType64, needsReturn);
1155 } else {
1156 generateFunctionCall(method, params, returnType, returnType64, needsReturn);
1157 }
1158 if (genFailTag)
1159 outputln("fail:");
1160 generateSetters(method, params);
1161 generateEnterExitMacro(method, function, function64, false);
1162 generateReturn(method, returnType, needsReturn);
1163 }
1164
1165 outputln("}");
1166 }
1167
1168 void generateFunctionPrototype(JNIMethod method, String function, List<JNIParameter> params, JNIType returnType, JNIType returnType64, boolean singleLine) {
1169 output("JNIEXPORT ");
1170 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
1171 output(" JNICALL ");
1172 output(method.getDeclaringClass().getSimpleName());
1173 output("_NATIVE(");
1174 output(function);
1175 if (singleLine) {
1176 output(")");
1177 output("(JNIEnv *env, ");
1178 } else {
1179 outputln(")");
1180 output("\t(JNIEnv *env, ");
1181 }
1182 if ((method.getModifiers() & Modifier.STATIC) != 0) {
1183 output("jclass");
1184 } else {
1185 output("jobject");
1186 }
1187 output(" that");
1188 for (int i = 0; i < params.size(); i++) {
1189 output(", ");
1190 JNIType paramType = params.get(i).getType32(), paramType64 = params.get(i).getType64();
1191 output(paramType.getTypeSignature2(!paramType.equals(paramType64)));
1192 output(" arg" + i);
1193 }
1194 output(")");
1195 if (!singleLine)
1196 outputln();
1197 }
1198
1199 boolean isCritical(JNIParameter param) {
1200 JNIType paramType = param.getType32();
1201 return paramType.isArray() && paramType.getComponentType().isPrimitive() && param.getFlag(ArgFlag.CRITICAL);
1202 }
1203
1204 boolean isSystemClass(JNIType type) {
1205 return type.isType("java.lang.Object") || type.isType("java.lang.Class");
1206 }
1207
1208 }