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 }