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