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.HashMap; 016import java.util.List; 017 018import org.fusesource.hawtjni.generator.model.JNIClass; 019import org.fusesource.hawtjni.generator.model.JNIField; 020import org.fusesource.hawtjni.generator.model.JNIFieldAccessor; 021import org.fusesource.hawtjni.generator.model.JNIType; 022import org.fusesource.hawtjni.runtime.ClassFlag; 023 024/** 025 * 026 * @author <a href="http://hiramchirino.com">Hiram Chirino</a> 027 */ 028public class StructsGenerator extends JNIGenerator { 029 030 boolean header; 031 032 static final boolean GLOBAL_REF = false; 033 034 private HashMap<JNIClass, ArrayList<JNIField>> structFields = new HashMap<JNIClass, ArrayList<JNIField>>(); 035 036 public StructsGenerator(boolean header) { 037 this.header = header; 038 } 039 040 public void generateCopyright() { 041 outputln(fixDelimiter(getCopyright())); 042 } 043 044 public void generateIncludes() { 045 if (header) { 046 outputln("#include \""+getOutputName()+".h\""); 047 } else { 048 outputln("#include \""+getOutputName()+".h\""); 049 outputln("#include \"hawtjni.h\""); 050 outputln("#include \""+getOutputName()+"_structs.h\""); 051 } 052 outputln(); 053 } 054 055 public void generate(JNIClass clazz) { 056 ArrayList<JNIField> fields = getStructFields(clazz); 057 if (fields.isEmpty()) 058 return; 059 if (header) { 060 generateHeaderFile(clazz); 061 } else { 062 generateSourceFile(clazz); 063 } 064 } 065 066 private ArrayList<JNIField> getStructFields(JNIClass clazz) { 067 if (!structFields.containsKey(clazz)) { 068 ArrayList<JNIField> rc = new ArrayList<JNIField>(); 069 List<JNIField> fields = clazz.getDeclaredFields(); 070 for (JNIField field : fields) { 071 int mods = field.getModifiers(); 072 if ((mods & Modifier.STATIC) == 0 && (mods & Modifier.TRANSIENT) == 0) { 073 rc.add(field); 074 } 075 } 076 077 structFields.put(clazz, rc); 078 } 079 return structFields.get(clazz); 080 } 081 082 void generateHeaderFile(JNIClass clazz) { 083 generateSourceStart(clazz); 084 generatePrototypes(clazz); 085 generateBlankMacros(clazz); 086 generateSourceEnd(clazz); 087 outputln(); 088 } 089 090 void generateSourceFile(JNIClass clazz) { 091 generateSourceStart(clazz); 092 generateFIDsStructure(clazz); 093 outputln(); 094 generateGlobalVar(clazz); 095 outputln(); 096 generateFunctions(clazz); 097 generateSourceEnd(clazz); 098 outputln(); 099 } 100 101 void generateSourceStart(JNIClass clazz) { 102 String conditional = clazz.getConditional(); 103 if (conditional!=null) { 104 outputln("#if "+conditional); 105 } 106 } 107 108 void generateSourceEnd(JNIClass clazz) { 109 if (clazz.getConditional()!=null) { 110 outputln("#endif"); 111 } 112 } 113 114 void generateGlobalVar(JNIClass clazz) { 115 String simpleName = clazz.getSimpleName(); 116 output(simpleName); 117 output("_FID_CACHE "); 118 output(simpleName); 119 outputln("Fc;"); 120 } 121 122 void generateBlankMacros(JNIClass clazz) { 123 124 if (clazz.getConditional()==null) { 125 return; 126 } 127 128 String simpleName = clazz.getSimpleName(); 129 outputln("#else"); 130 output("#define cache"); 131 output(simpleName); 132 outputln("Fields(a,b)"); 133 output("#define get"); 134 output(simpleName); 135 outputln("Fields(a,b,c) NULL"); 136 output("#define set"); 137 output(simpleName); 138 outputln("Fields(a,b,c)"); 139 } 140 141 void generatePrototypes(JNIClass clazz) { 142 String clazzName = clazz.getNativeName(); 143 String simpleName = clazz.getSimpleName(); 144 output("void cache"); 145 output(simpleName); 146 outputln("Fields(JNIEnv *env, jobject lpObject);"); 147 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) { 148 output("struct "); 149 } 150 output(clazzName); 151 output(" *get"); 152 output(simpleName); 153 output("Fields(JNIEnv *env, jobject lpObject, "); 154 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) { 155 output("struct "); 156 } 157 output(clazzName); 158 outputln(" *lpStruct);"); 159 output("void set"); 160 output(simpleName); 161 output("Fields(JNIEnv *env, jobject lpObject, "); 162 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) { 163 output("struct "); 164 } 165 output(clazzName); 166 outputln(" *lpStruct);"); 167 } 168 169 void generateFIDsStructure(JNIClass clazz) { 170 String simpleName = clazz.getSimpleName(); 171 output("typedef struct "); 172 output(simpleName); 173 outputln("_FID_CACHE {"); 174 outputln("\tint cached;"); 175 outputln("\tjclass clazz;"); 176 List<JNIField> fields = clazz.getDeclaredFields(); 177 boolean first = true; 178 for (JNIField field : fields) { 179 if (ignoreField(field)) 180 continue; 181 if (first) 182 output("\tjfieldID "); 183 else 184 output(", "); 185 output(field.getName()); 186 first = false; 187 } 188 outputln(";"); 189 output("} "); 190 output(simpleName); 191 outputln("_FID_CACHE;"); 192 } 193 194 void generateCacheFunction(JNIClass clazz) { 195 String simpleName = clazz.getSimpleName(); 196 String clazzName = clazz.getNativeName(); 197 output("void cache"); 198 output(simpleName); 199 outputln("Fields(JNIEnv *env, jobject lpObject)"); 200 outputln("{"); 201 output("\tif ("); 202 output(simpleName); 203 outputln("Fc.cached) return;"); 204 JNIClass superclazz = clazz.getSuperclass(); 205 if (!superclazz.getName().equals("java.lang.Object") && hasNonIgnoredFields(superclazz)) { 206 String superName = superclazz.getSimpleName(); 207 output("\tcache"); 208 output(superName); 209 outputln("Fields(env, lpObject);"); 210 } 211 output("\t"); 212 output(simpleName); 213 if (isCPP) { 214 if (GLOBAL_REF) { 215 output("Fc.clazz = (jclass)env->NewGlobalRef(env->GetObjectClass(lpObject));"); 216 } else { 217 output("Fc.clazz = env->GetObjectClass(lpObject);"); 218 } 219 } else { 220 if (GLOBAL_REF) { 221 output("Fc.clazz = (*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, lpObject));"); 222 } else { 223 output("Fc.clazz = (*env)->GetObjectClass(env, lpObject);"); 224 } 225 } 226 outputln(); 227 List<JNIField> fields = clazz.getDeclaredFields(); 228 for (JNIField field : fields) { 229 if (ignoreField(field)) 230 continue; 231 output("\t"); 232 output(simpleName); 233 output("Fc."); 234 output(field.getName()); 235 if (isCPP) { 236 output(" = env->GetFieldID("); 237 } else { 238 output(" = (*env)->GetFieldID(env, "); 239 } 240 output(simpleName); 241 output("Fc.clazz, \""); 242 output(field.getName()); 243 JNIType type = field.getType(), type64 = field.getType64(); 244 output("\", "); 245 if (type.equals(type64)) 246 output("\""); 247 output(type.getTypeSignature(!type.equals(type64))); 248 if (type.equals(type64)) 249 output("\""); 250 outputln(");"); 251 } 252 // Makes sure compiler/cpu does not reorder the following write before the previous updates are done. 253 outputln("\thawtjni_w_barrier();"); 254 output("\t"); 255 output(simpleName); 256 outputln("Fc.cached = 1;"); 257 outputln("}"); 258 } 259 260 void generateGetFields(JNIClass clazz) { 261 JNIClass superclazz = clazz.getSuperclass(); 262 String clazzName = clazz.getNativeName(); 263 String superName = superclazz.getNativeName(); 264 String methodname; 265 if (!superclazz.getName().equals("java.lang.Object") && hasNonIgnoredFields(superclazz)) { 266 /* 267 * Windows exception - cannot call get/set function of super class 268 * in this case 269 */ 270 if (!(clazzName.equals(superName + "A") || clazzName.equals(superName + "W"))) { 271 output("\tget"); 272 output(superName); 273 output("Fields(env, lpObject, ("); 274 output(superName); 275 outputln(" *)lpStruct);"); 276 } else { 277 generateGetFields(superclazz); 278 } 279 } 280 List<JNIField> fields = clazz.getDeclaredFields(); 281 for (JNIField field : fields) { 282 if (ignoreField(field)) 283 continue; 284 String conditional = field.getConditional(); 285 if (conditional!=null) { 286 outputln("#if "+conditional); 287 } 288 JNIType type = field.getType(), type64 = field.getType64(); 289 String simpleName = type.getSimpleName(); 290 JNIFieldAccessor accessor = field.getAccessor(); 291 output("\t"); 292 if (type.isPrimitive()) { 293 if (!accessor.isNonMemberSetter()) 294 output("lpStruct->"); 295 if (accessor.isMethodSetter()) { 296 String setterStart = accessor.setter().split("\\(")[0]; 297 output(setterStart + "("); 298 if (accessor.isNonMemberSetter()) 299 output("lpStruct, "); 300 } else { 301 output(accessor.setter()); 302 output(" = "); 303 } 304 output(field.getCast()); 305 if (field.isPointer()) { 306 output("(intptr_t)"); 307 } 308 if (isCPP) { 309 output("env->Get"); 310 } else { 311 output("(*env)->Get"); 312 } 313 output(type.getTypeSignature1(!type.equals(type64))); 314 if (isCPP) { 315 output("Field(lpObject, "); 316 } else { 317 output("Field(env, lpObject, "); 318 } 319 output(field.getDeclaringClass().getSimpleName()); 320 output("Fc."); 321 output(field.getName()); 322 if (accessor.isMethodSetter()) 323 output(")"); 324 output(");"); 325 } else if (type.isArray()) { 326 JNIType componentType = type.getComponentType(), componentType64 = type64.getComponentType(); 327 if (componentType.isPrimitive()) { 328 outputln("{"); 329 output("\t"); 330 output(type.getTypeSignature2(!type.equals(type64))); 331 output(" lpObject1 = ("); 332 output(type.getTypeSignature2(!type.equals(type64))); 333 if (isCPP) { 334 output(")env->GetObjectField(lpObject, "); 335 } else { 336 output(")(*env)->GetObjectField(env, lpObject, "); 337 } 338 output(field.getDeclaringClass().getSimpleName()); 339 output("Fc."); 340 output(field.getName()); 341 outputln(");"); 342 if (isCPP) { 343 output("\tenv->Get"); 344 } else { 345 output("\t(*env)->Get"); 346 } 347 output(componentType.getTypeSignature1(!componentType.equals(componentType64))); 348 if (isCPP) { 349 output("ArrayRegion(lpObject1, 0, sizeof("); 350 } else { 351 output("ArrayRegion(env, lpObject1, 0, sizeof("); 352 } 353 if (!accessor.isNonMemberGetter()) 354 output("lpStruct->"); 355 output(accessor.getter()); 356 output(")"); 357 if (!componentType.isType("byte")) { 358 output(" / sizeof("); 359 output(componentType.getTypeSignature2(!componentType.equals(componentType64))); 360 output(")"); 361 } 362 output(", ("); 363 output(type.getTypeSignature4(!type.equals(type64), false)); 364 output(")"); 365 if (!accessor.isNonMemberGetter()) 366 output("lpStruct->"); 367 output(accessor.getter()); 368 outputln(");"); 369 output("\t}"); 370 } else { 371 throw new Error("not done"); 372 } 373 } else { 374 outputln("\t{"); 375 if (isCPP) { 376 output("\tjobject lpObject1 = env->GetObjectField(lpObject, "); 377 } else { 378 output("\tjobject lpObject1 = (*env)->GetObjectField(env, lpObject, "); 379 } 380 output(field.getDeclaringClass().getSimpleName()); 381 output("Fc."); 382 output(field.getName()); 383 outputln(");"); 384 output("\tif (lpObject1 != NULL) get"); 385 output(simpleName); 386 output("Fields(env, lpObject1, &lpStruct->"); 387 output(accessor.getter()); 388 outputln(");"); 389 output("\t}"); 390 } 391 outputln(); 392 if (conditional!=null) { 393 outputln("#endif"); 394 } 395 } 396 } 397 398 void generateGetFunction(JNIClass clazz) { 399 String clazzName = clazz.getNativeName(); 400 String simpleName = clazz.getSimpleName(); 401 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) { 402 output("struct "); 403 } 404 output(clazzName); 405 output(" *get"); 406 output(simpleName); 407 output("Fields(JNIEnv *env, jobject lpObject, "); 408 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) { 409 output("struct "); 410 } 411 output(clazzName); 412 outputln(" *lpStruct)"); 413 outputln("{"); 414 output("\tif (!"); 415 output(simpleName); 416 output("Fc.cached) cache"); 417 output(simpleName); 418 outputln("Fields(env, lpObject);"); 419 if( clazz.getFlag(ClassFlag.ZERO_OUT) ) { 420 outputln("memset(lpStruct, 0, sizeof(struct "+clazzName+"));"); 421 } 422 generateGetFields(clazz); 423 outputln("\treturn lpStruct;"); 424 outputln("}"); 425 } 426 427 void generateSetFields(JNIClass clazz) { 428 JNIClass superclazz = clazz.getSuperclass(); 429 String clazzName = clazz.getNativeName(); 430 String superName = superclazz.getNativeName(); 431 if (!superclazz.getName().equals("java.lang.Object") && hasNonIgnoredFields(superclazz)) { 432 /* 433 * Windows exception - cannot call get/set function of super class 434 * in this case 435 */ 436 if (!(clazzName.equals(superName + "A") || clazzName.equals(superName + "W"))) { 437 output("\tset"); 438 output(superName); 439 output("Fields(env, lpObject, ("); 440 output(superName); 441 outputln(" *)lpStruct);"); 442 } else { 443 generateSetFields(superclazz); 444 } 445 } 446 List<JNIField> fields = clazz.getDeclaredFields(); 447 for (JNIField field : fields) { 448 if (ignoreField(field)) 449 continue; 450 String conditional = field.getConditional(); 451 if (conditional!=null) { 452 outputln("#if "+conditional); 453 } 454 JNIType type = field.getType(), type64 = field.getType64(); 455 boolean allowConversion = !type.equals(type64); 456 457 String simpleName = type.getSimpleName(); 458 JNIFieldAccessor accessor = field.getAccessor(); 459 if (type.isPrimitive()) { 460 if (isCPP) { 461 output("\tenv->Set"); 462 } else { 463 output("\t(*env)->Set"); 464 } 465 output(type.getTypeSignature1(allowConversion)); 466 if (isCPP) { 467 output("Field(lpObject, "); 468 } else { 469 output("Field(env, lpObject, "); 470 } 471 output(field.getDeclaringClass().getSimpleName()); 472 output("Fc."); 473 output(field.getName()); 474 output(", "); 475 output("("+type.getTypeSignature2(allowConversion)+")"); 476 if( field.isPointer() ) { 477 output("(intptr_t)"); 478 } 479 if (!accessor.isNonMemberGetter()) 480 output("lpStruct->"); 481 if (accessor.isMethodGetter()) { 482 String getterStart = accessor.getter().split("\\(")[0]; 483 output(getterStart + "("); 484 if (accessor.isNonMemberGetter()) 485 output("lpStruct"); 486 output(")"); 487 } else { 488 output(accessor.getter()); 489 } 490 output(");"); 491 } else if (type.isArray()) { 492 JNIType componentType = type.getComponentType(), componentType64 = type64.getComponentType(); 493 if (componentType.isPrimitive()) { 494 outputln("\t{"); 495 output("\t"); 496 output(type.getTypeSignature2(allowConversion)); 497 output(" lpObject1 = ("); 498 output(type.getTypeSignature2(allowConversion)); 499 if (isCPP) { 500 output(")env->GetObjectField(lpObject, "); 501 } else { 502 output(")(*env)->GetObjectField(env, lpObject, "); 503 } 504 output(field.getDeclaringClass().getSimpleName()); 505 output("Fc."); 506 output(field.getName()); 507 outputln(");"); 508 if (isCPP) { 509 output("\tenv->Set"); 510 } else { 511 output("\t(*env)->Set"); 512 } 513 output(componentType.getTypeSignature1(!componentType.equals(componentType64))); 514 if (isCPP) { 515 output("ArrayRegion(lpObject1, 0, sizeof("); 516 } else { 517 output("ArrayRegion(env, lpObject1, 0, sizeof("); 518 } 519 if (!accessor.isNonMemberGetter()) 520 output("lpStruct->"); 521 if (accessor.isMethodGetter()) { 522 String getterStart = accessor.getter().split("\\(")[0]; 523 output(getterStart + "("); 524 if (accessor.isNonMemberGetter()) 525 output("lpStruct"); 526 output(")"); 527 } else { 528 output(accessor.getter()); 529 } 530 output(")"); 531 if (!componentType.isType("byte")) { 532 output(" / sizeof("); 533 output(componentType.getTypeSignature2(!componentType.equals(componentType64))); 534 output(")"); 535 } 536 output(", ("); 537 output(type.getTypeSignature4(allowConversion, false)); 538 output(")"); 539 if (!accessor.isNonMemberGetter()) 540 output("lpStruct->"); 541 output(accessor.getter()); 542 outputln(");"); 543 output("\t}"); 544 } else { 545 throw new Error("not done"); 546 } 547 } else { 548 outputln("\t{"); 549 if (isCPP) { 550 output("\tjobject lpObject1 = env->GetObjectField(lpObject, "); 551 } else { 552 output("\tjobject lpObject1 = (*env)->GetObjectField(env, lpObject, "); 553 } 554 output(field.getDeclaringClass().getSimpleName()); 555 output("Fc."); 556 output(field.getName()); 557 outputln(");"); 558 output("\tif (lpObject1 != NULL) set"); 559 output(simpleName); 560 output("Fields(env, lpObject1, &lpStruct->"); 561 output(accessor.getter()); 562 outputln(");"); 563 output("\t}"); 564 } 565 outputln(); 566 if (conditional!=null) { 567 outputln("#endif"); 568 } 569 } 570 } 571 572 void generateSetFunction(JNIClass clazz) { 573 String clazzName = clazz.getNativeName(); 574 String simpleName = clazz.getSimpleName(); 575 output("void set"); 576 output(simpleName); 577 output("Fields(JNIEnv *env, jobject lpObject, "); 578 if (clazz.getFlag(ClassFlag.STRUCT) && !clazz.getFlag(ClassFlag.TYPEDEF)) { 579 output("struct "); 580 } 581 output(clazzName); 582 outputln(" *lpStruct)"); 583 outputln("{"); 584 output("\tif (!"); 585 output(simpleName); 586 output("Fc.cached) cache"); 587 output(simpleName); 588 outputln("Fields(env, lpObject);"); 589 generateSetFields(clazz); 590 outputln("}"); 591 } 592 593 void generateFunctions(JNIClass clazz) { 594 generateCacheFunction(clazz); 595 outputln(); 596 generateGetFunction(clazz); 597 outputln(); 598 generateSetFunction(clazz); 599 } 600 601 boolean ignoreField(JNIField field) { 602 int mods = field.getModifiers(); 603 return field.ignore() || ((mods & Modifier.FINAL) != 0) || ((mods & Modifier.STATIC) != 0); 604 } 605 606 boolean hasNonIgnoredFields(JNIClass clazz) { 607 for (JNIField field : getStructFields(clazz)) 608 if (!ignoreField(field)) return true; 609 return false; 610 } 611 612}