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 *******************************************************************************/ 011package org.fusesource.hawtjni.generator; 012 013import java.lang.reflect.Modifier; 014import java.util.ArrayList; 015import java.util.List; 016 017import org.fusesource.hawtjni.generator.model.JNIClass; 018import org.fusesource.hawtjni.generator.model.JNIField; 019import org.fusesource.hawtjni.generator.model.JNIMethod; 020import org.fusesource.hawtjni.generator.model.JNIParameter; 021import org.fusesource.hawtjni.generator.model.JNIType; 022import org.fusesource.hawtjni.runtime.ArgFlag; 023import org.fusesource.hawtjni.runtime.ClassFlag; 024import org.fusesource.hawtjni.runtime.FieldFlag; 025import org.fusesource.hawtjni.runtime.MethodFlag; 026 027import static org.fusesource.hawtjni.runtime.MethodFlag.*; 028 029/** 030 * 031 * @author <a href="http://hiramchirino.com">Hiram Chirino</a> 032 */ 033public 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("org.fusesource.hawtjni.runtime.JNIEnv")) { 600 // no need to generate a local for this one.. 601 } else if (paramType.isType("java.lang.String")) { 602 if (param.getFlag(ArgFlag.UNICODE)) { 603 output("const jchar *lparg" + i); 604 } else { 605 output("const char *lparg" + i); 606 } 607 output("= NULL;"); 608 } else { 609 if (param.getTypeClass().getFlag(ClassFlag.STRUCT) && !param.getTypeClass().getFlag(ClassFlag.TYPEDEF)) { 610 output("struct "); 611 } 612 output(paramType.getNativeName()); 613 output(" _arg" + i); 614 if (param.getFlag(ArgFlag.INIT)) 615 output("={0}"); 616 output(", *lparg" + i); 617 output("=NULL;"); 618 } 619 outputln(); 620 needsReturn = true; 621 } 622 if (needsReturn) { 623 if (!returnType.isType("void")) { 624 output("\t"); 625 output(returnType.getTypeSignature2(!returnType.equals(returnType64))); 626 outputln(" rc = 0;"); 627 } 628 } 629 return needsReturn; 630 } 631 632 boolean generateGetters(JNIMethod method, List<JNIParameter> params) { 633 boolean genFailTag = false; 634 int criticalCount = 0; 635 for (JNIParameter param : params) { 636 if( !"org.fusesource.hawtjni.runtime.JNIEnv".equals(param.getTypeClass().getName()) ) { 637 if (!isCritical(param)) { 638 genFailTag |= generateGetParameter(method, param, false, 1); 639 } else { 640 criticalCount++; 641 } 642 } 643 } 644 if (criticalCount != 0) { 645 outputln("#ifdef JNI_VERSION_1_2"); 646 outputln("\tif (IS_JNI_1_2) {"); 647 for (JNIParameter param : params) { 648 if( !"org.fusesource.hawtjni.runtime.JNIEnv".equals(param.getTypeClass().getName()) ) { 649 if (isCritical(param)) { 650 genFailTag |= generateGetParameter(method, param, true, 2); 651 } 652 } 653 } 654 outputln("\t} else"); 655 outputln("#endif"); 656 outputln("\t{"); 657 for (JNIParameter param : params) { 658 if( !"org.fusesource.hawtjni.runtime.JNIEnv".equals(param.getTypeClass().getName()) ) { 659 if (isCritical(param)) { 660 genFailTag |= generateGetParameter(method, param, false, 2); 661 } 662 } 663 } 664 outputln("\t}"); 665 } 666 return genFailTag; 667 } 668 669 void generateSetters(JNIMethod method, List<JNIParameter> params) { 670 int criticalCount = 0; 671 for (int i = params.size() - 1; i >= 0; i--) { 672 JNIParameter param = params.get(i); 673 if( !"org.fusesource.hawtjni.runtime.JNIEnv".equals(param.getTypeClass().getName()) ) { 674 if (isCritical(param)) { 675 criticalCount++; 676 } 677 } 678 } 679 if (criticalCount != 0) { 680 outputln("#ifdef JNI_VERSION_1_2"); 681 outputln("\tif (IS_JNI_1_2) {"); 682 for (int i = params.size() - 1; i >= 0; i--) { 683 JNIParameter param = params.get(i); 684 if( !"org.fusesource.hawtjni.runtime.JNIEnv".equals(param.getTypeClass().getName()) ) { 685 if (isCritical(param)) { 686 output("\t"); 687 generateSetParameter(param, true); 688 } 689 } 690 } 691 outputln("\t} else"); 692 outputln("#endif"); 693 outputln("\t{"); 694 for (int i = params.size() - 1; i >= 0; i--) { 695 JNIParameter param = params.get(i); 696 if( !"org.fusesource.hawtjni.runtime.JNIEnv".equals(param.getTypeClass().getName()) ) { 697 if (isCritical(param)) { 698 output("\t"); 699 generateSetParameter(param, false); 700 } 701 } 702 } 703 outputln("\t}"); 704 } 705 for (int i = params.size() - 1; i >= 0; i--) { 706 JNIParameter param = params.get(i); 707 if( !"org.fusesource.hawtjni.runtime.JNIEnv".equals(param.getTypeClass().getName()) ) { 708 if (!isCritical(param)) { 709 generateSetParameter(param, false); 710 } 711 } 712 } 713 } 714 715 void generateDynamicFunctionCall(JNIMethod method, List<JNIParameter> params, JNIType returnType, JNIType returnType64, boolean needsReturn) { 716 outputln("/*"); 717 generateFunctionCall(method, params, returnType, returnType64, needsReturn); 718 outputln("*/"); 719 outputln("\t{"); 720 721 String name = method.getName(); 722 if (name.startsWith("_")) 723 name = name.substring(1); 724 output("\t\tLOAD_FUNCTION(fp, "); 725 output(name); 726 outputln(")"); 727 outputln("\t\tif (fp) {"); 728 output("\t\t"); 729 generateFunctionCallLeftSide(method, returnType, returnType64, needsReturn); 730 output("(("); 731 output(returnType.getTypeSignature2(!returnType.equals(returnType64))); 732 output(" (CALLING_CONVENTION*)("); 733 for (int i = 0; i < params.size(); i++) { 734 if (i != 0) 735 output(", "); 736 JNIParameter param = params.get(i); 737 String cast = param.getCast(); 738 if( param.isPointer() ) { 739 output("(intptr_t)"); 740 } 741 boolean isStruct = param.getFlag(ArgFlag.BY_VALUE); 742 if (cast.length() > 2) { 743 cast = cast.substring(1, cast.length() - 1); 744 if (isStruct) { 745 int index = cast.lastIndexOf('*'); 746 if (index != -1) 747 cast = cast.substring(0, index).trim(); 748 } 749 output(cast); 750 } else { 751 JNIType paramType = param.getType32(), paramType64 = param.getType64(); 752 output(paramType.getTypeSignature4(!paramType.equals(paramType64), isStruct)); 753 } 754 } 755 output("))"); 756 output("fp"); 757 output(")"); 758 generateFunctionCallRightSide(method, params, 0); 759 output(";"); 760 outputln(); 761 outputln("\t\t}"); 762 outputln("\t}"); 763 } 764 765 void generateFunctionCallLeftSide(JNIMethod method, JNIType returnType, JNIType returnType64, boolean needsReturn) { 766 output("\t"); 767 if (!returnType.isType("void")) { 768 if (needsReturn) { 769 output("rc = "); 770 } else { 771 output("return "); 772 } 773 774 String cast = method.getCast(); 775 if (cast.length() != 0 && !cast.equals("()")) { 776 if( method.isPointer() ) { 777 output("(intptr_t)"); 778 } 779 output(cast); 780 } else { 781 if( method.getFlag(CPP_NEW)) { 782 String[] parts = getNativeNameParts(method); 783 String className = parts[0]; 784 output("(intptr_t)("+className+" *)"); 785 } else { 786 output("("); 787 output(returnType.getTypeSignature2(!returnType.equals(returnType64))); 788 output(")"); 789 } 790 } 791 } 792 if (method.getFlag(MethodFlag.ADDRESS)) { 793 output("&"); 794 } 795 if (method.getFlag(MethodFlag.JNI)) { 796 output(isCPP ? "env->" : "(*env)->"); 797 } 798 } 799 800 void generateFunctionCallRightSide(JNIMethod method, List<JNIParameter> params, int paramStart) { 801 if (!method.getFlag(MethodFlag.CONSTANT_GETTER)) { 802 output("("); 803 if (method.getFlag(MethodFlag.JNI)) { 804 if (!isCPP) 805 output("env, "); 806 } 807 for (int i = paramStart; i < params.size(); i++) { 808 JNIParameter param = params.get(i); 809 if (i != paramStart) 810 output(", "); 811 if (param.getFlag(ArgFlag.BY_VALUE)) 812 output("*"); 813 output(param.getCast()); 814 if( param.isPointer() ) { 815 output("(intptr_t)"); 816 } 817 if (param.getFlag(ArgFlag.CS_OBJECT)) 818 output("TO_OBJECT("); 819 if (i == params.size() - 1 && param.getFlag(ArgFlag.SENTINEL)) { 820 output("NULL"); 821 } else { 822 if( "org.fusesource.hawtjni.runtime.JNIEnv".equals(param.getTypeClass().getName()) ) { 823 output("env"); 824 } else { 825 JNIType paramType = param.getType32(); 826 if (!paramType.isPrimitive() && !isSystemClass(paramType)) 827 output("lp"); 828 output("arg" + i); 829 } 830 } 831 if (param.getFlag(ArgFlag.CS_OBJECT)) 832 output(")"); 833 } 834 output(")"); 835 } 836 } 837 838 static String[] getNativeNameParts(JNIMethod method) { 839 String className = null; 840 String methodName = null; 841 842 JNIClass dc = method.getDeclaringClass(); 843 if( dc.getFlag(ClassFlag.CPP) || dc.getFlag(ClassFlag.STRUCT) ) { 844 className = method.getDeclaringClass().getNativeName(); 845 } 846 847 if( method.getAccessor().length() != 0 ) { 848 methodName = method.getAccessor(); 849 int pos = methodName.lastIndexOf("::"); 850 if( pos >= 0 ) { 851 className = methodName.substring(0, pos); 852 methodName = methodName.substring(pos+2); 853 } 854 } else { 855 methodName = method.getName(); 856 if( className==null ) { 857 int pos = methodName.indexOf("_"); 858 if( pos > 0 ) { 859 className = methodName.substring(0, pos); 860 methodName = methodName.substring(pos+1); 861 } 862 } 863 } 864 if( className==null ) { 865 throw new Error(String.format("Could not determine object type name of method '%s'", method.getDeclaringClass().getSimpleName()+"."+method.getName())); 866 } 867 return new String[]{className, methodName}; 868 } 869 870 void generateFunctionCall(JNIMethod method, List<JNIParameter> params, JNIType returnType, JNIType returnType64, boolean needsReturn) { 871 String name = method.getName(); 872 String copy = method.getCopy(); 873 boolean makeCopy = copy.length() != 0 && isCPP && !returnType.isType("void"); 874 if (makeCopy) { 875 output("\t{"); 876 output("\t\t"); 877 output(copy); 878 output(" temp = "); 879 } else { 880 generateFunctionCallLeftSide(method, returnType, returnType64, needsReturn); 881 } 882 int paramStart = 0; 883 if (name.startsWith("_")) 884 name = name.substring(1); 885 886 boolean objc_struct = false; 887 if (name.equals("objc_msgSend_stret") || name.equals("objc_msgSendSuper_stret")) 888 objc_struct = true; 889 if (objc_struct) { 890 outputln("if (sizeof(_arg0) > STRUCT_SIZE_LIMIT) {"); 891 generate_objc_msgSend_stret(method, params, name); 892 paramStart = 1; 893 } else if (name.equalsIgnoreCase("call")) { 894 output("("); 895 JNIParameter param = params.get(0); 896 String cast = param.getCast(); 897 if (cast.length() != 0 && !cast.equals("()")) { 898 output(cast); 899 if( param.isPointer() ) { 900 output("(intptr_t)"); 901 } 902 } else { 903 output("("); 904 output(returnType.getTypeSignature2(!returnType.equals(returnType64))); 905 output(" (*)())"); 906 } 907 output("arg0)"); 908 paramStart = 1; 909 } else if (name.startsWith("VtblCall") || name.startsWith("_VtblCall")) { 910 output("(("); 911 output(returnType.getTypeSignature2(!returnType.equals(returnType64))); 912 output(" (STDMETHODCALLTYPE *)("); 913 for (int i = 1; i < params.size(); i++) { 914 if (i != 1) 915 output(", "); 916 JNIParameter param = params.get(i); 917 JNIType paramType = param.getType32(), paramType64 = param.getType64(); 918 output(paramType.getTypeSignature4(!paramType.equals(paramType64), false)); 919 } 920 output("))(*("); 921 JNIType paramType = params.get(1).getType32(), paramType64 = params.get(1).getType64(); 922 output(paramType.getTypeSignature4(!paramType.equals(paramType64), false)); 923 output(" **)arg1)[arg0])"); 924 paramStart = 1; 925 } else if (method.getFlag(MethodFlag.CPP_METHOD) || method.getFlag(MethodFlag.SETTER) || method.getFlag(MethodFlag.GETTER) || method.getFlag(MethodFlag.ADDER)) { 926 927 String[] parts = getNativeNameParts(method); 928 String className = parts[0]; 929 String methodName = parts[1]; 930 931 if (method.getFlag(MethodFlag.CS_OBJECT)) { 932 output("TO_HANDLE("); 933 } 934 output("("); 935 if( params.isEmpty() ) { 936 throw new Error(String.format("C++ bound method '%s' missing the 'this' parameter", method.getDeclaringClass().getSimpleName()+"."+method.getName())); 937 } 938 JNIParameter param = params.get(0); 939 if (param.getFlag(ArgFlag.BY_VALUE)) 940 output("*"); 941 String cast = param.getCast(); 942 if (cast.length() != 0 && !cast.equals("()")) { 943 output(cast); 944 if( param.isPointer() ) { 945 output("(intptr_t)"); 946 } 947 } else { 948 output("("+className+" *)(intptr_t)"); 949 } 950 if (param.getFlag(ArgFlag.CS_OBJECT)) { 951 output("TO_OBJECT("); 952 } 953 output("arg0"); 954 if (param.getFlag(ArgFlag.CS_OBJECT)) { 955 output(")"); 956 } 957 output(")->"); 958 output(methodName); 959 paramStart = 1; 960 } else if (method.getFlag(MethodFlag.CS_NEW)) { 961 output("TO_HANDLE(gcnew "); 962 String accessor = method.getAccessor(); 963 if (accessor.length() != 0) { 964 output(accessor); 965 } else { 966 JNIClass dc = method.getDeclaringClass(); 967 if( dc.getFlag(ClassFlag.CPP) || dc.getFlag(ClassFlag.STRUCT) ) { 968 output(dc.getNativeName()); 969 } else { 970 int index = -1; 971 if ((index = name.indexOf('_')) != -1) { 972 output(name.substring(index + 1)); 973 } else { 974 output(name); 975 } 976 } 977 } 978 } else if (method.getFlag(MethodFlag.CPP_NEW)) { 979 if (method.getFlag(MethodFlag.CS_OBJECT)) { 980 output("TO_HANDLE("); 981 } 982 output("new "); 983 String accessor = method.getAccessor(); 984 if (accessor.length() != 0) { 985 output(accessor); 986 } else { 987 988 JNIClass dc = method.getDeclaringClass(); 989 if( dc.getFlag(ClassFlag.CPP) ) { 990 output(method.getDeclaringClass().getNativeName()); 991 } else { 992 int index = -1; 993 if ((index = name.indexOf('_')) != -1) { 994 output(name.substring(index+1)); 995 } else { 996 output(name); 997 } 998 } 999 1000 } 1001 } else if (method.getFlag(MethodFlag.CPP_DELETE)) { 1002 String[] parts = getNativeNameParts(method); 1003 String className = parts[0]; 1004 1005 output("delete "); 1006 JNIParameter param = params.get(0); 1007 String cast = param.getCast(); 1008 if (cast.length() != 0 && !cast.equals("()")) { 1009 output(cast); 1010 if( param.isPointer() ) { 1011 output("(intptr_t)"); 1012 } 1013 } else { 1014 output("("+className+" *)(intptr_t)"); 1015 } 1016 outputln("arg0;"); 1017 return; 1018 } else { 1019 if (method.getFlag(MethodFlag.CS_OBJECT)) { 1020 output("TO_HANDLE("); 1021 } 1022 if (method.getFlag(MethodFlag.CAST)) { 1023 output("(("); 1024 String returnCast = returnType.getTypeSignature2(!returnType.equals(returnType64)); 1025 if (name.equals("objc_msgSend_bool") && returnCast.equals("jboolean")) { 1026 returnCast = "BOOL"; 1027 } 1028 output(returnCast); 1029 output(" (*)("); 1030 for (int i = 0; i < params.size(); i++) { 1031 if (i != 0) 1032 output(", "); 1033 JNIParameter param = params.get(i); 1034 String cast = param.getCast(); 1035 if (cast.length() != 0 && !cast.equals("()") ) { 1036 if (cast.startsWith("(")) 1037 cast = cast.substring(1); 1038 if (cast.endsWith(")")) 1039 cast = cast.substring(0, cast.length() - 1); 1040 output(cast); 1041 } else { 1042 JNIType paramType = param.getType32(), paramType64 = param.getType64(); 1043 if (!(paramType.isPrimitive() || paramType.isArray())) { 1044 if (param.getTypeClass().getFlag(ClassFlag.STRUCT) && !param.getTypeClass().getFlag(ClassFlag.TYPEDEF)) { 1045 output("struct "); 1046 } 1047 } 1048 output(paramType.getTypeSignature4(!paramType.equals(paramType64), param.getFlag(ArgFlag.BY_VALUE))); 1049 } 1050 } 1051 output("))"); 1052 } 1053 String accessor = method.getAccessor(); 1054 if (accessor.length() != 0) { 1055 output(accessor); 1056 } else { 1057 output(name); 1058 } 1059 if (method.getFlag(MethodFlag.CAST)) { 1060 output(")"); 1061 } 1062 } 1063 if ((method.getFlag(MethodFlag.SETTER) && params.size() == 3) || (method.getFlag(MethodFlag.GETTER) && params.size() == 2)) { 1064 output("[arg1]"); 1065 paramStart++; 1066 } 1067 if (method.getFlag(MethodFlag.SETTER)) 1068 output(" = "); 1069 if (method.getFlag(MethodFlag.ADDER)) 1070 output(" += "); 1071 if (!method.getFlag(MethodFlag.GETTER)) { 1072 generateFunctionCallRightSide(method, params, paramStart); 1073 } 1074 if (method.getFlag(MethodFlag.CS_NEW) || method.getFlag(MethodFlag.CS_OBJECT)) { 1075 output(")"); 1076 } 1077 output(";"); 1078 outputln(); 1079 if (makeCopy) { 1080 outputln("\t\t{"); 1081 output("\t\t\t"); 1082 output(copy); 1083 output("* copy = new "); 1084 output(copy); 1085 outputln("();"); 1086 outputln("\t\t\t*copy = temp;"); 1087 output("\t\t\trc = "); 1088 output("("); 1089 output(returnType.getTypeSignature2(!returnType.equals(returnType64))); 1090 output(")"); 1091 outputln("copy;"); 1092 outputln("\t\t}"); 1093 outputln("\t}"); 1094 } 1095 if (objc_struct) { 1096 outputln("\t} else {"); 1097 generate_objc_msgSend_stret(method, params, name.substring(0, name.length() - "_stret".length())); 1098 generateFunctionCallRightSide(method, params, 1); 1099 outputln(";"); 1100 outputln("\t}"); 1101 } 1102 } 1103 1104 void generate_objc_msgSend_stret(JNIMethod method, List<JNIParameter> params, String func) { 1105 output("\t\t*lparg0 = (*("); 1106 JNIType paramType = params.get(0).getType32(), paramType64 = params.get(0).getType64(); 1107 output(paramType.getTypeSignature4(!paramType.equals(paramType64), true)); 1108 output(" (*)("); 1109 for (int i = 1; i < params.size(); i++) { 1110 if (i != 1) 1111 output(", "); 1112 JNIParameter param = params.get(i); 1113 String cast = param.getCast(); 1114 if( param.isPointer() ) { 1115 output("(intptr_t)"); 1116 } 1117 if (cast.length() != 0 && !cast.equals("()")) { 1118 if (cast.startsWith("(")) 1119 cast = cast.substring(1); 1120 if (cast.endsWith(")")) 1121 cast = cast.substring(0, cast.length() - 1); 1122 output(cast); 1123 } else { 1124 paramType = param.getType32(); 1125 paramType64 = param.getType64(); 1126 if (!(paramType.isPrimitive() || paramType.isArray())) { 1127 if (param.getTypeClass().getFlag(ClassFlag.STRUCT) && !param.getTypeClass().getFlag(ClassFlag.TYPEDEF)) { 1128 output("struct "); 1129 } 1130 } 1131 output(paramType.getTypeSignature4(!paramType.equals(paramType64), param.getFlag(ArgFlag.BY_VALUE))); 1132 } 1133 } 1134 output("))"); 1135 output(func); 1136 output(")"); 1137 } 1138 1139 void generateReturn(JNIMethod method, JNIType returnType, boolean needsReturn) { 1140 if (needsReturn && !returnType.isType("void")) { 1141 outputln("\treturn rc;"); 1142 } 1143 } 1144 1145 void generateMemmove(JNIMethod method, String function, String function64, List<JNIParameter> params) { 1146 generateEnterExitMacro(method, function, function64, true); 1147 output("\t"); 1148 boolean get = params.get(0).getType32().isPrimitive(); 1149 String className = params.get(get ? 1 : 0).getType32().getSimpleName(); 1150 output(get ? "if (arg1) get" : "if (arg0) set"); 1151 output(className); 1152 output(get ? "Fields(env, arg1, (" : "Fields(env, arg0, ("); 1153 output(className); 1154 output(get ? " *)arg0)" : " *)arg1)"); 1155 outputln(";"); 1156 generateEnterExitMacro(method, function, function64, false); 1157 } 1158 1159 void generateFunctionBody(JNIMethod method, String function, String function64, List<JNIParameter> params, JNIType returnType, JNIType returnType64) { 1160 outputln("{"); 1161 1162 /* Custom GTK memmoves. */ 1163 String name = method.getName(); 1164 if (name.startsWith("_")) 1165 name = name.substring(1); 1166 boolean isMemove = (name.equals("memmove") || name.equals("MoveMemory")) && params.size() == 2 && returnType.isType("void"); 1167 if (isMemove) { 1168 generateMemmove(method, function, function64, params); 1169 } else { 1170 boolean needsReturn = generateLocalVars(method, params, returnType, returnType64); 1171 generateEnterExitMacro(method, function, function64, true); 1172 boolean genFailTag = generateGetters(method, params); 1173 if (method.getFlag(MethodFlag.DYNAMIC)) { 1174 generateDynamicFunctionCall(method, params, returnType, returnType64, needsReturn); 1175 } else { 1176 generateFunctionCall(method, params, returnType, returnType64, needsReturn); 1177 } 1178 if (genFailTag) 1179 outputln("fail:"); 1180 generateSetters(method, params); 1181 generateEnterExitMacro(method, function, function64, false); 1182 generateReturn(method, returnType, needsReturn); 1183 } 1184 1185 outputln("}"); 1186 } 1187 1188 void generateFunctionPrototype(JNIMethod method, String function, List<JNIParameter> params, JNIType returnType, JNIType returnType64, boolean singleLine) { 1189 output("JNIEXPORT "); 1190 output(returnType.getTypeSignature2(!returnType.equals(returnType64))); 1191 output(" JNICALL "); 1192 output(method.getDeclaringClass().getSimpleName()); 1193 output("_NATIVE("); 1194 output(function); 1195 if (singleLine) { 1196 output(")"); 1197 output("(JNIEnv *env, "); 1198 } else { 1199 outputln(")"); 1200 output("\t(JNIEnv *env, "); 1201 } 1202 if ((method.getModifiers() & Modifier.STATIC) != 0) { 1203 output("jclass"); 1204 } else { 1205 output("jobject"); 1206 } 1207 output(" that"); 1208 for (int i = 0; i < params.size(); i++) { 1209 output(", "); 1210 JNIType paramType = params.get(i).getType32(), paramType64 = params.get(i).getType64(); 1211 output(paramType.getTypeSignature2(!paramType.equals(paramType64))); 1212 output(" arg" + i); 1213 } 1214 output(")"); 1215 if (!singleLine) 1216 outputln(); 1217 } 1218 1219 boolean isCritical(JNIParameter param) { 1220 JNIType paramType = param.getType32(); 1221 return paramType.isArray() && paramType.getComponentType().isPrimitive() && param.getFlag(ArgFlag.CRITICAL); 1222 } 1223 1224 boolean isSystemClass(JNIType type) { 1225 return type.isType("java.lang.Object") || type.isType("java.lang.Class"); 1226 } 1227 1228}