001 /*******************************************************************************
002 * Copyright (c) 2009 Progress Software, Inc.
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 outputln("JNIEXPORT void JNICALL "+clazz.getSimpleName()+"_NATIVE("+toC(method.getName())+")(JNIEnv *env, jclass that)");
178 outputln("{");
179 for (JNIField field : constants) {
180
181 String conditional = field.getConditional();
182 if (conditional!=null) {
183 outputln("#if "+conditional);
184 }
185 JNIType type = field.getType(), type64 = field.getType64();
186 boolean allowConversion = !type.equals(type64);
187
188 String typeName = type.getSimpleName();
189 String accessor = field.getAccessor();
190 if (accessor == null || accessor.length() == 0)
191 accessor = field.getName();
192
193 String fieldId = "(*env)->GetStaticFieldID(env, that, \""+field.getName()+"\", \""+type.getTypeSignature(allowConversion)+"\")";
194 if (type.isPrimitive()) {
195 output("\t(*env)->SetStatic"+type.getTypeSignature1(allowConversion)+"Field(env, that, "+fieldId +", ");
196 output("("+type.getTypeSignature2(allowConversion)+")");
197 if( field.isPointer() ) {
198 output("(intptr_t)");
199 }
200 output(accessor);
201 output(");");
202
203 } else if (type.isArray()) {
204 JNIType componentType = type.getComponentType(), componentType64 = type64.getComponentType();
205 if (componentType.isPrimitive()) {
206 outputln("\t{");
207 output("\t");
208 output(type.getTypeSignature2(allowConversion));
209 output(" lpObject1 = (");
210 output(type.getTypeSignature2(allowConversion));
211 if (isCPP) {
212 output(")env->GetStaticObjectField(that, ");
213 } else {
214 output(")(*env)->GetStaticObjectField(env, that, ");
215 }
216 output(field.getDeclaringClass().getSimpleName());
217 output(fieldId);
218 outputln(");");
219 if (isCPP) {
220 output("\tenv->Set");
221 } else {
222 output("\t(*env)->Set");
223 }
224 output(componentType.getTypeSignature1(!componentType.equals(componentType64)));
225 if (isCPP) {
226 output("ArrayRegion(lpObject1, 0, sizeof(");
227 } else {
228 output("ArrayRegion(env, lpObject1, 0, sizeof(");
229 }
230 output(accessor);
231 output(")");
232 if (!componentType.isType("byte")) {
233 output(" / sizeof(");
234 output(componentType.getTypeSignature2(!componentType.equals(componentType64)));
235 output(")");
236 }
237 output(", (");
238 output(type.getTypeSignature4(allowConversion, false));
239 output(")");
240 output(accessor);
241 outputln(");");
242 output("\t}");
243 } else {
244 throw new Error("not done");
245 }
246 } else {
247 outputln("\t{");
248 output("\tjobject lpObject1 = (*env)->GetStaticObjectField(env, that, ");
249 output(field.getDeclaringClass().getSimpleName());
250 output("Fc.");
251 output(field.getName());
252 outputln(");");
253 output("\tif (lpObject1 != NULL) set");
254 output(typeName);
255 output("Fields(env, lpObject1, &lpStruct->");
256 output(accessor);
257 outputln(");");
258 output("\t}");
259 }
260 outputln();
261 if (conditional!=null) {
262 outputln("#endif");
263 }
264 }
265 outputln(" return;");
266 outputln("}");
267
268 }
269
270 private ArrayList<JNIField> getConstantFields(JNIClass clazz) {
271 ArrayList<JNIField> rc = new ArrayList<JNIField>();
272 List<JNIField> fields = clazz.getDeclaredFields();
273 for (JNIField field : fields) {
274 int mods = field.getModifiers();
275 if ( (mods & Modifier.STATIC) != 0 && field.getFlag(FieldFlag.CONSTANT)) {
276 rc.add(field);
277 }
278 }
279 return rc;
280 }
281
282 public void generate(JNIMethod method) {
283 if (method.getFlag(MethodFlag.METHOD_SKIP))
284 return;
285
286 JNIType returnType = method.getReturnType32(), returnType64 = method.getReturnType64();
287
288 if( method.getFlag(CONSTANT_INITIALIZER)) {
289 if( returnType.isType("void") && method.getParameters().isEmpty() ) {
290 generateConstantsInitializer(method);
291 } else {
292 output("#error Warning: invalid CONSTANT_INITIALIZER tagged method. It must be void and take no arguments: ");
293 outputln(method.toString());
294 }
295 return;
296 }
297
298 if (!(returnType.isType("void") || returnType.isPrimitive() || isSystemClass(returnType) || returnType.isType("java.lang.String"))) {
299 output("#error Warning: bad return type. :");
300 outputln(method.toString());
301 return;
302 }
303
304 String conditional = method.getConditional();
305 if (conditional!=null) {
306 outputln("#if "+conditional);
307 }
308
309 List<JNIParameter> params = method.getParameters();
310 String function = getFunctionName(method), function64 = getFunctionName(method, method.getParameterTypes64());
311 boolean sameFunction = function.equals(function64);
312 if (!sameFunction) {
313 output("#ifndef ");
314 output(JNI64);
315 outputln();
316 }
317 if (isCPP) {
318 output("extern \"C\" ");
319 generateFunctionPrototype(method, function, params, returnType, returnType64, true);
320 outputln(";");
321 }
322 if (function.startsWith("CALLBACK_")) {
323 generateCallback(method, function, params, returnType);
324 }
325 generateFunctionPrototype(method, function, params, returnType, returnType64, !sameFunction);
326 if (!function.equals(function64)) {
327 outputln();
328 outputln("#else");
329 if (isCPP) {
330 output("extern \"C\" ");
331 generateFunctionPrototype(method, function64, params, returnType, returnType64, true);
332 outputln(";");
333 }
334 generateFunctionPrototype(method, function64, params, returnType, returnType64, !sameFunction);
335 outputln();
336 outputln("#endif");
337 }
338 generateFunctionBody(method, function, function64, params, returnType, returnType64);
339 if (conditional!=null) {
340 outputln("#endif");
341 }
342 outputln();
343 }
344
345 public void setEnterExitMacro(boolean enterExitMacro) {
346 this.enterExitMacro = enterExitMacro;
347 }
348
349 void generateNativeMacro(JNIClass clazz) {
350 output("#define ");
351 output(clazz.getSimpleName());
352 output("_NATIVE(func) Java_");
353 output(toC(clazz.getName()));
354 outputln("_##func");
355 outputln();
356 }
357
358 boolean generateGetParameter(JNIMethod method, JNIParameter param, boolean critical, int indent) {
359 JNIType paramType = param.getType32(), paramType64 = param.getType64();
360 if (paramType.isPrimitive() || isSystemClass(paramType))
361 return false;
362 String iStr = String.valueOf(param.getParameter());
363 for (int j = 0; j < indent; j++)
364 output("\t");
365 output("if (arg");
366 output(iStr);
367 output(") if ((lparg");
368 output(iStr);
369 output(" = ");
370 if (paramType.isArray()) {
371 JNIType componentType = paramType.getComponentType();
372 if (componentType.isPrimitive()) {
373 if( "long".equals( componentType.getName() ) && param.isPointer() ) {
374 // This case is special as we may need to do pointer conversions..
375 // if your on a 32 bit system but are keeping track of the pointers in a 64 bit long
376 output("hawtjni_malloc_pointer_array(env, arg");
377 output(iStr);
378 output(")");
379 } else if (critical) {
380 if (isCPP) {
381 output("(");
382 output(componentType.getTypeSignature2(!paramType.equals(paramType64)));
383 output("*)");
384 output("env->GetPrimitiveArrayCritical(arg");
385 } else {
386 output("(*env)->GetPrimitiveArrayCritical(env, arg");
387 }
388 output(iStr);
389 output(", NULL)");
390 } else {
391 if (isCPP) {
392 output("env->Get");
393 } else {
394 output("(*env)->Get");
395 }
396 output(componentType.getTypeSignature1(!paramType.equals(paramType64)));
397 if (isCPP) {
398 output("ArrayElements(arg");
399 } else {
400 output("ArrayElements(env, arg");
401 }
402 output(iStr);
403 output(", NULL)");
404 }
405 } else {
406 throw new Error("not done");
407 }
408 } else if (paramType.isType("java.lang.String")) {
409 if (param.getFlag(ArgFlag.UNICODE)) {
410 if (isCPP) {
411 output("env->GetStringChars(arg");
412 } else {
413 output("(*env)->GetStringChars(env, arg");
414 }
415 output(iStr);
416 output(", NULL)");
417 } else {
418 if (isCPP) {
419 output("env->GetStringUTFChars(arg");
420 } else {
421 output("(*env)->GetStringUTFChars(env, arg");
422 }
423 output(iStr);
424 output(", NULL)");
425 }
426 } else {
427 if (param.getFlag(ArgFlag.NO_IN)) {
428 output("&_arg");
429 output(iStr);
430 } else {
431 output("get");
432 output(paramType.getSimpleName());
433 output("Fields(env, arg");
434 output(iStr);
435 output(", &_arg");
436 output(iStr);
437 output(")");
438 }
439 }
440 outputln(") == NULL) goto fail;");
441 return true;
442 }
443
444 void generateSetParameter(JNIParameter param, boolean critical) {
445 JNIType paramType = param.getType32(), paramType64 = param.getType64();
446 if (paramType.isPrimitive() || isSystemClass(paramType))
447 return;
448 String iStr = String.valueOf(param.getParameter());
449 if (paramType.isArray()) {
450 output("\tif (arg");
451 output(iStr);
452 output(" && lparg");
453 output(iStr);
454 output(") ");
455 JNIType componentType = paramType.getComponentType();
456 if (componentType.isPrimitive()) {
457 if( "long".equals( componentType.getName() ) && param.isPointer() ) {
458 // This case is special as we may need to do pointer conversions..
459 // if your on a 32 bit system but are keeping track of the pointers in a 64 bit long
460 output("hawtjni_free_pointer_array(env, arg");
461 output(iStr);
462 } else if (critical) {
463 if (isCPP) {
464 output("env->ReleasePrimitiveArrayCritical(arg");
465 } else {
466 output("(*env)->ReleasePrimitiveArrayCritical(env, arg");
467 }
468 output(iStr);
469 } else {
470 if (isCPP) {
471 output("env->Release");
472 } else {
473 output("(*env)->Release");
474 }
475 output(componentType.getTypeSignature1(!paramType.equals(paramType64)));
476 if (isCPP) {
477 output("ArrayElements(arg");
478 } else {
479 output("ArrayElements(env, arg");
480 }
481 output(iStr);
482 }
483 output(", lparg");
484 output(iStr);
485 output(", ");
486 if (param.getFlag(ArgFlag.NO_OUT)) {
487 output("JNI_ABORT");
488 } else {
489 output("0");
490 }
491 output(");");
492 } else {
493 throw new Error("not done");
494 }
495 outputln();
496 } else if (paramType.isType("java.lang.String")) {
497 output("\tif (arg");
498 output(iStr);
499 output(" && lparg");
500 output(iStr);
501 output(") ");
502 if (param.getFlag(ArgFlag.UNICODE)) {
503 if (isCPP) {
504 output("env->ReleaseStringChars(arg");
505 } else {
506 output("(*env)->ReleaseStringChars(env, arg");
507 }
508 } else {
509 if (isCPP) {
510 output("env->ReleaseStringUTFChars(arg");
511 } else {
512 output("(*env)->ReleaseStringUTFChars(env, arg");
513 }
514 }
515 output(iStr);
516 output(", lparg");
517 output(iStr);
518 outputln(");");
519 } else {
520 if (!param.getFlag(ArgFlag.NO_OUT)) {
521 output("\tif (arg");
522 output(iStr);
523 output(" && lparg");
524 output(iStr);
525 output(") ");
526 output("set");
527 output(paramType.getSimpleName());
528 output("Fields(env, arg");
529 output(iStr);
530 output(", lparg");
531 output(iStr);
532 outputln(");");
533 }
534 }
535 }
536
537 void generateEnterExitMacro(JNIMethod method, String function, String function64, boolean enter) {
538 if (!enterExitMacro)
539 return;
540 if (!function.equals(function64)) {
541 output("#ifndef ");
542 output(JNI64);
543 outputln();
544 }
545 output("\t");
546 output(method.getDeclaringClass().getSimpleName());
547 output("_NATIVE_");
548 output(enter ? "ENTER" : "EXIT");
549 output("(env, that, ");
550 output(method.getDeclaringClass().getSimpleName()+"_"+function);
551 outputln("_FUNC);");
552 if (!function.equals(function64)) {
553 outputln("#else");
554 output("\t");
555 output(method.getDeclaringClass().getSimpleName());
556 output("_NATIVE_");
557 output(enter ? "ENTER" : "EXIT");
558 output("(env, that, ");
559 output(method.getDeclaringClass().getSimpleName()+"_"+function64);
560 outputln("_FUNC);");
561 outputln("#endif");
562 }
563 }
564
565 boolean generateLocalVars(JNIMethod method, List<JNIParameter> params, JNIType returnType, JNIType returnType64) {
566 boolean needsReturn = enterExitMacro;
567 for (int i = 0; i < params.size(); i++) {
568 JNIParameter param = params.get(i);
569 JNIType paramType = param.getType32(), paramType64 = param.getType64();
570 if (paramType.isPrimitive() || isSystemClass(paramType))
571 continue;
572 output("\t");
573 if (paramType.isArray()) {
574 JNIType componentType = paramType.getComponentType();
575 if( "long".equals( componentType.getName() ) && param.isPointer() ) {
576 output("void **lparg" + i+"=NULL;");
577 } else if (componentType.isPrimitive()) {
578 output(componentType.getTypeSignature2(!paramType.equals(paramType64)));
579 output(" *lparg" + i);
580 output("=NULL;");
581 } else {
582 throw new Error("not done");
583 }
584 } else if (paramType.isType("java.lang.String")) {
585 if (param.getFlag(ArgFlag.UNICODE)) {
586 output("const jchar *lparg" + i);
587 } else {
588 output("const char *lparg" + i);
589 }
590 output("= NULL;");
591 } else {
592 if (param.getTypeClass().getFlag(ClassFlag.STRUCT) && !param.getTypeClass().getFlag(ClassFlag.TYPEDEF)) {
593 output("struct ");
594 }
595 output(paramType.getSimpleName());
596 output(" _arg" + i);
597 if (param.getFlag(ArgFlag.INIT))
598 output("={0}");
599 output(", *lparg" + i);
600 output("=NULL;");
601 }
602 outputln();
603 needsReturn = true;
604 }
605 if (needsReturn) {
606 if (!returnType.isType("void")) {
607 output("\t");
608 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
609 outputln(" rc = 0;");
610 }
611 }
612 return needsReturn;
613 }
614
615 boolean generateGetters(JNIMethod method, List<JNIParameter> params) {
616 boolean genFailTag = false;
617 int criticalCount = 0;
618 for (JNIParameter param : params) {
619 if (!isCritical(param)) {
620 genFailTag |= generateGetParameter(method, param, false, 1);
621 } else {
622 criticalCount++;
623 }
624 }
625 if (criticalCount != 0) {
626 outputln("#ifdef JNI_VERSION_1_2");
627 outputln("\tif (IS_JNI_1_2) {");
628 for (JNIParameter param : params) {
629 if (isCritical(param)) {
630 genFailTag |= generateGetParameter(method, param, true, 2);
631 }
632 }
633 outputln("\t} else");
634 outputln("#endif");
635 outputln("\t{");
636 for (JNIParameter param : params) {
637 if (isCritical(param)) {
638 genFailTag |= generateGetParameter(method, param, false, 2);
639 }
640 }
641 outputln("\t}");
642 }
643 return genFailTag;
644 }
645
646 void generateSetters(JNIMethod method, List<JNIParameter> params) {
647 int criticalCount = 0;
648 for (int i = params.size() - 1; i >= 0; i--) {
649 JNIParameter param = params.get(i);
650 if (isCritical(param)) {
651 criticalCount++;
652 }
653 }
654 if (criticalCount != 0) {
655 outputln("#ifdef JNI_VERSION_1_2");
656 outputln("\tif (IS_JNI_1_2) {");
657 for (int i = params.size() - 1; i >= 0; i--) {
658 JNIParameter param = params.get(i);
659 if (isCritical(param)) {
660 output("\t");
661 generateSetParameter(param, true);
662 }
663 }
664 outputln("\t} else");
665 outputln("#endif");
666 outputln("\t{");
667 for (int i = params.size() - 1; i >= 0; i--) {
668 JNIParameter param = params.get(i);
669 if (isCritical(param)) {
670 output("\t");
671 generateSetParameter(param, false);
672 }
673 }
674 outputln("\t}");
675 }
676 for (int i = params.size() - 1; i >= 0; i--) {
677 JNIParameter param = params.get(i);
678 if (!isCritical(param)) {
679 generateSetParameter(param, false);
680 }
681 }
682 }
683
684 void generateDynamicFunctionCall(JNIMethod method, List<JNIParameter> params, JNIType returnType, JNIType returnType64, boolean needsReturn) {
685 outputln("/*");
686 generateFunctionCall(method, params, returnType, returnType64, needsReturn);
687 outputln("*/");
688 outputln("\t{");
689
690 String name = method.getName();
691 if (name.startsWith("_"))
692 name = name.substring(1);
693 output("\t\tLOAD_FUNCTION(fp, ");
694 output(name);
695 outputln(")");
696 outputln("\t\tif (fp) {");
697 output("\t\t");
698 generateFunctionCallLeftSide(method, returnType, returnType64, needsReturn);
699 output("((");
700 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
701 output(" (CALLING_CONVENTION*)(");
702 for (int i = 0; i < params.size(); i++) {
703 if (i != 0)
704 output(", ");
705 JNIParameter param = params.get(i);
706 String cast = param.getCast();
707 if( param.isPointer() ) {
708 output("(intptr_t)");
709 }
710 boolean isStruct = param.getFlag(ArgFlag.BY_VALUE);
711 if (cast.length() > 2) {
712 cast = cast.substring(1, cast.length() - 1);
713 if (isStruct) {
714 int index = cast.lastIndexOf('*');
715 if (index != -1)
716 cast = cast.substring(0, index).trim();
717 }
718 output(cast);
719 } else {
720 JNIType paramType = param.getType32(), paramType64 = param.getType64();
721 output(paramType.getTypeSignature4(!paramType.equals(paramType64), isStruct));
722 }
723 }
724 output("))");
725 output("fp");
726 output(")");
727 generateFunctionCallRightSide(method, params, 0);
728 output(";");
729 outputln();
730 outputln("\t\t}");
731 outputln("\t}");
732 }
733
734 void generateFunctionCallLeftSide(JNIMethod method, JNIType returnType, JNIType returnType64, boolean needsReturn) {
735 output("\t");
736 if (!returnType.isType("void")) {
737 if (needsReturn) {
738 output("rc = ");
739 } else {
740 output("return ");
741 }
742
743 String cast = method.getCast();
744 if (cast != null) {
745 if( method.isPointer() ) {
746 output("(intptr_t)");
747 }
748 output(cast);
749 } else {
750 output("(");
751 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
752 output(")");
753 }
754 }
755 if (method.getFlag(MethodFlag.ADDRESS)) {
756 output("&");
757 }
758 if (method.getFlag(MethodFlag.JNI)) {
759 output(isCPP ? "env->" : "(*env)->");
760 }
761 }
762
763 void generateFunctionCallRightSide(JNIMethod method, List<JNIParameter> params, int paramStart) {
764 if (!method.getFlag(MethodFlag.CONSTANT_GETTER)) {
765 output("(");
766 if (method.getFlag(MethodFlag.JNI)) {
767 if (!isCPP)
768 output("env, ");
769 }
770 for (int i = paramStart; i < params.size(); i++) {
771 JNIParameter param = params.get(i);
772 if (i != paramStart)
773 output(", ");
774 if (param.getFlag(ArgFlag.BY_VALUE))
775 output("*");
776 output(param.getCast());
777 if( param.isPointer() ) {
778 output("(intptr_t)");
779 }
780 if (param.getFlag(ArgFlag.CS_OBJECT))
781 output("TO_OBJECT(");
782 if (i == params.size() - 1 && param.getFlag(ArgFlag.SENTINEL)) {
783 output("NULL");
784 } else {
785 JNIType paramType = param.getType32();
786 if (!paramType.isPrimitive() && !isSystemClass(paramType))
787 output("lp");
788 output("arg" + i);
789 }
790 if (param.getFlag(ArgFlag.CS_OBJECT))
791 output(")");
792 }
793 output(")");
794 }
795 }
796
797 void generateFunctionCall(JNIMethod method, List<JNIParameter> params, JNIType returnType, JNIType returnType64, boolean needsReturn) {
798 String name = method.getName();
799 String copy = method.getCopy();
800 boolean makeCopy = copy.length() != 0 && isCPP && !returnType.isType("void");
801 if (makeCopy) {
802 output("\t");
803 output(copy);
804 output(" temp = ");
805 } else {
806 generateFunctionCallLeftSide(method, returnType, returnType64, needsReturn);
807 }
808 int paramStart = 0;
809 if (name.startsWith("_"))
810 name = name.substring(1);
811
812 boolean objc_struct = false;
813 if (name.equals("objc_msgSend_stret") || name.equals("objc_msgSendSuper_stret"))
814 objc_struct = true;
815 if (objc_struct) {
816 outputln("if (sizeof(_arg0) > STRUCT_SIZE_LIMIT) {");
817 generate_objc_msgSend_stret(method, params, name);
818 paramStart = 1;
819 } else if (name.equalsIgnoreCase("call")) {
820 output("(");
821 JNIParameter param = params.get(0);
822 String cast = param.getCast();
823 if (cast.length() != 0 && !cast.equals("()")) {
824 output(cast);
825 if( param.isPointer() ) {
826 output("(intptr_t)");
827 }
828 } else {
829 output("(");
830 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
831 output(" (*)())");
832 }
833 output("arg0)");
834 paramStart = 1;
835 } else if (name.startsWith("VtblCall") || name.startsWith("_VtblCall")) {
836 output("((");
837 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
838 output(" (STDMETHODCALLTYPE *)(");
839 for (int i = 1; i < params.size(); i++) {
840 if (i != 1)
841 output(", ");
842 JNIParameter param = params.get(i);
843 JNIType paramType = param.getType32(), paramType64 = param.getType64();
844 output(paramType.getTypeSignature4(!paramType.equals(paramType64), false));
845 }
846 output("))(*(");
847 JNIType paramType = params.get(1).getType32(), paramType64 = params.get(1).getType64();
848 output(paramType.getTypeSignature4(!paramType.equals(paramType64), false));
849 output(" **)arg1)[arg0])");
850 paramStart = 1;
851 } else if (method.getFlag(MethodFlag.CPP) || method.getFlag(MethodFlag.SETTER) || method.getFlag(MethodFlag.GETTER) || method.getFlag(MethodFlag.ADDER)) {
852 if (method.getFlag(MethodFlag.CS_OBJECT)) {
853 output("TO_HANDLE(");
854 }
855 output("(");
856 JNIParameter param = params.get(0);
857 if (param.getFlag(ArgFlag.BY_VALUE))
858 output("*");
859 String cast = param.getCast();
860 if (cast.length() != 0 && !cast.equals("()")) {
861 output(cast);
862 if( param.isPointer() ) {
863 output("(intptr_t)");
864 }
865 }
866 if (param.getFlag(ArgFlag.CS_OBJECT)) {
867 output("TO_OBJECT(");
868 }
869 output("arg0");
870 if (param.getFlag(ArgFlag.CS_OBJECT)) {
871 output(")");
872 }
873 output(")->");
874 String accessor = method.getAccessor();
875 if (accessor.length() != 0) {
876 output(accessor);
877 } else {
878 int index = -1;
879 if ((index = name.indexOf('_')) != -1) {
880 output(name.substring(index + 1, name.length()));
881 } else {
882 output(name);
883 }
884 }
885 paramStart = 1;
886 } else if (method.getFlag(MethodFlag.CS_NEW)) {
887 output("TO_HANDLE(gcnew ");
888 String accessor = method.getAccessor();
889 if (accessor.length() != 0) {
890 output(accessor);
891 } else {
892 int index = -1;
893 if ((index = name.indexOf('_')) != -1) {
894 output(name.substring(index + 1));
895 } else {
896 output(name);
897 }
898 }
899 } else if (method.getFlag(MethodFlag.CPP_NEW)) {
900 if (method.getFlag(MethodFlag.CS_OBJECT)) {
901 output("TO_HANDLE(");
902 }
903 output("new ");
904 String accessor = method.getAccessor();
905 if (accessor.length() != 0) {
906 output(accessor);
907 } else {
908 int index = -1;
909 if ((index = name.indexOf('_')) != -1) {
910 output(name.substring(0, index));
911 } else {
912 output(name);
913 }
914 }
915 } else if (method.getFlag(MethodFlag.CPP_DELETE)) {
916 output("delete ");
917 JNIParameter param = params.get(0);
918 String cast = param.getCast();
919 if (cast.length() != 0 && !cast.equals("()")) {
920 output(cast);
921 if( param.isPointer() ) {
922 output("(intptr_t)");
923 }
924 } else {
925 output("(");
926 output(name.substring(0, name.indexOf("_")));
927 output(" *)");
928 }
929 outputln("arg0;");
930 return;
931 } else {
932 if (method.getFlag(MethodFlag.CS_OBJECT)) {
933 output("TO_HANDLE(");
934 }
935 if (method.getFlag(MethodFlag.CAST)) {
936 output("((");
937 String returnCast = returnType.getTypeSignature2(!returnType.equals(returnType64));
938 if (name.equals("objc_msgSend_bool") && returnCast.equals("jboolean")) {
939 returnCast = "BOOL";
940 }
941 output(returnCast);
942 output(" (*)(");
943 for (int i = 0; i < params.size(); i++) {
944 if (i != 0)
945 output(", ");
946 JNIParameter param = params.get(i);
947 String cast = param.getCast();
948 if (cast != null && cast.length() != 0) {
949 if (cast.startsWith("("))
950 cast = cast.substring(1);
951 if (cast.endsWith(")"))
952 cast = cast.substring(0, cast.length() - 1);
953 output(cast);
954 } else {
955 JNIType paramType = param.getType32(), paramType64 = param.getType64();
956 if (!(paramType.isPrimitive() || paramType.isArray())) {
957 if (param.getTypeClass().getFlag(ClassFlag.STRUCT) && !param.getTypeClass().getFlag(ClassFlag.TYPEDEF)) {
958 output("struct ");
959 }
960 }
961 output(paramType.getTypeSignature4(!paramType.equals(paramType64), param.getFlag(ArgFlag.BY_VALUE)));
962 }
963 }
964 output("))");
965 }
966 String accessor = method.getAccessor();
967 if (accessor.length() != 0) {
968 output(accessor);
969 } else {
970 output(name);
971 }
972 if (method.getFlag(MethodFlag.CAST)) {
973 output(")");
974 }
975 }
976 if ((method.getFlag(MethodFlag.SETTER) && params.size() == 3) || (method.getFlag(MethodFlag.GETTER) && params.size() == 2)) {
977 output("[arg1]");
978 paramStart++;
979 }
980 if (method.getFlag(MethodFlag.SETTER))
981 output(" = ");
982 if (method.getFlag(MethodFlag.ADDER))
983 output(" += ");
984 if (!method.getFlag(MethodFlag.GETTER)) {
985 generateFunctionCallRightSide(method, params, paramStart);
986 }
987 if (method.getFlag(MethodFlag.CS_NEW) || method.getFlag(MethodFlag.CS_OBJECT)) {
988 output(")");
989 }
990 output(";");
991 outputln();
992 if (makeCopy) {
993 outputln("\t{");
994 output("\t\t");
995 output(copy);
996 output("* copy = new ");
997 output(copy);
998 outputln("();");
999 outputln("\t\t*copy = temp;");
1000 output("\t\trc = ");
1001 output("(");
1002 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
1003 output(")");
1004 outputln("copy;");
1005 outputln("\t}");
1006 }
1007 if (objc_struct) {
1008 outputln("\t} else {");
1009 generate_objc_msgSend_stret(method, params, name.substring(0, name.length() - "_stret".length()));
1010 generateFunctionCallRightSide(method, params, 1);
1011 outputln(";");
1012 outputln("\t}");
1013 }
1014 }
1015
1016 void generate_objc_msgSend_stret(JNIMethod method, List<JNIParameter> params, String func) {
1017 output("\t\t*lparg0 = (*(");
1018 JNIType paramType = params.get(0).getType32(), paramType64 = params.get(0).getType64();
1019 output(paramType.getTypeSignature4(!paramType.equals(paramType64), true));
1020 output(" (*)(");
1021 for (int i = 1; i < params.size(); i++) {
1022 if (i != 1)
1023 output(", ");
1024 JNIParameter param = params.get(i);
1025 String cast = param.getCast();
1026 if( param.isPointer() ) {
1027 output("(intptr_t)");
1028 }
1029 if (cast != null && cast.length() != 0) {
1030 if (cast.startsWith("("))
1031 cast = cast.substring(1);
1032 if (cast.endsWith(")"))
1033 cast = cast.substring(0, cast.length() - 1);
1034 output(cast);
1035 } else {
1036 paramType = param.getType32();
1037 paramType64 = param.getType64();
1038 if (!(paramType.isPrimitive() || paramType.isArray())) {
1039 if (param.getTypeClass().getFlag(ClassFlag.STRUCT) && !param.getTypeClass().getFlag(ClassFlag.TYPEDEF)) {
1040 output("struct ");
1041 }
1042 }
1043 output(paramType.getTypeSignature4(!paramType.equals(paramType64), param.getFlag(ArgFlag.BY_VALUE)));
1044 }
1045 }
1046 output("))");
1047 output(func);
1048 output(")");
1049 }
1050
1051 void generateReturn(JNIMethod method, JNIType returnType, boolean needsReturn) {
1052 if (needsReturn && !returnType.isType("void")) {
1053 outputln("\treturn rc;");
1054 }
1055 }
1056
1057 void generateMemmove(JNIMethod method, String function, String function64, List<JNIParameter> params) {
1058 generateEnterExitMacro(method, function, function64, true);
1059 output("\t");
1060 boolean get = params.get(0).getType32().isPrimitive();
1061 String className = params.get(get ? 1 : 0).getType32().getSimpleName();
1062 output(get ? "if (arg1) get" : "if (arg0) set");
1063 output(className);
1064 output(get ? "Fields(env, arg1, (" : "Fields(env, arg0, (");
1065 output(className);
1066 output(get ? " *)arg0)" : " *)arg1)");
1067 outputln(";");
1068 generateEnterExitMacro(method, function, function64, false);
1069 }
1070
1071 void generateFunctionBody(JNIMethod method, String function, String function64, List<JNIParameter> params, JNIType returnType, JNIType returnType64) {
1072 outputln("{");
1073
1074 /* Custom GTK memmoves. */
1075 String name = method.getName();
1076 if (name.startsWith("_"))
1077 name = name.substring(1);
1078 boolean isMemove = (name.equals("memmove") || name.equals("MoveMemory")) && params.size() == 2 && returnType.isType("void");
1079 if (isMemove) {
1080 generateMemmove(method, function, function64, params);
1081 } else {
1082 boolean needsReturn = generateLocalVars(method, params, returnType, returnType64);
1083 generateEnterExitMacro(method, function, function64, true);
1084 boolean genFailTag = generateGetters(method, params);
1085 if (method.getFlag(MethodFlag.DYNAMIC)) {
1086 generateDynamicFunctionCall(method, params, returnType, returnType64, needsReturn);
1087 } else {
1088 generateFunctionCall(method, params, returnType, returnType64, needsReturn);
1089 }
1090 if (genFailTag)
1091 outputln("fail:");
1092 generateSetters(method, params);
1093 generateEnterExitMacro(method, function, function64, false);
1094 generateReturn(method, returnType, needsReturn);
1095 }
1096
1097 outputln("}");
1098 }
1099
1100 void generateFunctionPrototype(JNIMethod method, String function, List<JNIParameter> params, JNIType returnType, JNIType returnType64, boolean singleLine) {
1101 output("JNIEXPORT ");
1102 output(returnType.getTypeSignature2(!returnType.equals(returnType64)));
1103 output(" JNICALL ");
1104 output(method.getDeclaringClass().getSimpleName());
1105 output("_NATIVE(");
1106 output(function);
1107 if (singleLine) {
1108 output(")");
1109 output("(JNIEnv *env, ");
1110 } else {
1111 outputln(")");
1112 output("\t(JNIEnv *env, ");
1113 }
1114 if ((method.getModifiers() & Modifier.STATIC) != 0) {
1115 output("jclass");
1116 } else {
1117 output("jobject");
1118 }
1119 output(" that");
1120 for (int i = 0; i < params.size(); i++) {
1121 output(", ");
1122 JNIType paramType = params.get(i).getType32(), paramType64 = params.get(i).getType64();
1123 output(paramType.getTypeSignature2(!paramType.equals(paramType64)));
1124 output(" arg" + i);
1125 }
1126 output(")");
1127 if (!singleLine)
1128 outputln();
1129 }
1130
1131 boolean isCritical(JNIParameter param) {
1132 JNIType paramType = param.getType32();
1133 return paramType.isArray() && paramType.getComponentType().isPrimitive() && param.getFlag(ArgFlag.CRITICAL);
1134 }
1135
1136 boolean isSystemClass(JNIType type) {
1137 return type.isType("java.lang.Object") || type.isType("java.lang.Class");
1138 }
1139
1140 }