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 }