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