JniCodeEmitter.java revision 5afdc87704f82cb6c3576695dd157b65ae6f3d33
1import java.io.PrintStream; 2import java.util.ArrayList; 3import java.util.HashSet; 4import java.util.Iterator; 5import java.util.List; 6 7public class JniCodeEmitter { 8 9 static final boolean mUseCPlusPlus = true; 10 protected boolean mUseContextPointer = true; 11 protected boolean mUseStaticMethods = false; 12 protected String mClassPathName; 13 protected ParameterChecker mChecker; 14 protected List<String> nativeRegistrations = new ArrayList<String>(); 15 boolean needsExit; 16 protected static String indent = " "; 17 HashSet<String> mFunctionsEmitted = new HashSet<String>(); 18 19 public static String getJniName(JType jType) { 20 String jniName = ""; 21 if (jType.isClass()) { 22 return "L" + jType.getBaseType() + ";"; 23 } else if (jType.isArray()) { 24 jniName = "["; 25 } 26 27 String baseType = jType.getBaseType(); 28 if (baseType.equals("int")) { 29 jniName += "I"; 30 } else if (baseType.equals("float")) { 31 jniName += "F"; 32 } else if (baseType.equals("boolean")) { 33 jniName += "Z"; 34 } else if (baseType.equals("short")) { 35 jniName += "S"; 36 } else if (baseType.equals("long")) { 37 jniName += "L"; 38 } else if (baseType.equals("byte")) { 39 jniName += "B"; 40 } 41 return jniName; 42 } 43 44 45 public void emitCode(CFunc cfunc, String original, 46 PrintStream javaInterfaceStream, 47 PrintStream javaImplStream, 48 PrintStream cStream) { 49 JFunc jfunc; 50 String signature; 51 boolean duplicate; 52 53 if (cfunc.hasTypedPointerArg()) { 54 jfunc = JFunc.convert(cfunc, true); 55 56 // Don't emit duplicate functions 57 // These may appear because they are defined in multiple 58 // Java interfaces (e.g., GL11/GL11ExtensionPack) 59 signature = jfunc.toString(); 60 duplicate = false; 61 if (mFunctionsEmitted.contains(signature)) { 62 duplicate = true; 63 } else { 64 mFunctionsEmitted.add(signature); 65 } 66 67 if (!duplicate) { 68 emitNativeDeclaration(jfunc, javaImplStream); 69 emitJavaCode(jfunc, javaImplStream); 70 } 71 if (javaInterfaceStream != null) { 72 emitJavaInterfaceCode(jfunc, javaInterfaceStream); 73 } 74 if (!duplicate) { 75 emitJniCode(jfunc, cStream); 76 } 77 } 78 79 jfunc = JFunc.convert(cfunc, false); 80 81 signature = jfunc.toString(); 82 duplicate = false; 83 if (mFunctionsEmitted.contains(signature)) { 84 duplicate = true; 85 } else { 86 mFunctionsEmitted.add(signature); 87 } 88 89 if (!duplicate) { 90 emitNativeDeclaration(jfunc, javaImplStream); 91 } 92 if (javaInterfaceStream != null) { 93 emitJavaInterfaceCode(jfunc, javaInterfaceStream); 94 } 95 if (!duplicate) { 96 emitJavaCode(jfunc, javaImplStream); 97 emitJniCode(jfunc, cStream); 98 } 99 } 100 101 public void emitNativeDeclaration(JFunc jfunc, PrintStream out) { 102 out.println(" // C function " + jfunc.getCFunc().getOriginal()); 103 out.println(); 104 105 emitFunction(jfunc, out, true, false); 106 } 107 108 public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) { 109 emitFunction(jfunc, out, false, true); 110 } 111 112 public void emitJavaCode(JFunc jfunc, PrintStream out) { 113 emitFunction(jfunc, out, false, false); 114 } 115 116 void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) { 117 boolean isVoid = jfunc.getType().isVoid(); 118 boolean isPointerFunc = jfunc.getName().endsWith("Pointer") && 119 jfunc.getCFunc().hasPointerArg(); 120 121 if (!isVoid) { 122 out.println(iii + 123 jfunc.getType() + " _returnValue;"); 124 } 125 out.println(iii + 126 (isVoid ? "" : "_returnValue = ") + 127 jfunc.getName() + 128 (isPointerFunc ? "Bounds" : "" ) + 129 "("); 130 131 int numArgs = jfunc.getNumArgs(); 132 for (int i = 0; i < numArgs; i++) { 133 String argName = jfunc.getArgName(i); 134 JType argType = jfunc.getArgType(i); 135 136 if (grabArray && argType.isTypedBuffer()) { 137 String typeName = argType.getBaseType(); 138 typeName = typeName.substring(9, typeName.length() - 6); 139 out.println(iii + indent + "get" + typeName + "Array(" + argName + "),"); 140 out.print(iii + indent + "getOffset(" + argName + ")"); 141 } else { 142 out.print(iii + indent + argName); 143 } 144 if (i == numArgs - 1) { 145 if (isPointerFunc) { 146 out.println(","); 147 out.println(iii + indent + argName + ".remaining()"); 148 } else { 149 out.println(); 150 } 151 } else { 152 out.println(","); 153 } 154 } 155 156 out.println(iii + ");"); 157 } 158 159 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, 160 String iii) { 161 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, 162 "offset", "_remaining", iii); 163 } 164 165 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, 166 String offset, String remaining, String iii) { 167 out.println(iii + " default:"); 168 out.println(iii + " _needed = 0;"); 169 out.println(iii + " break;"); 170 out.println(iii + "}"); 171 172 out.println(iii + "if (" + remaining + " < _needed) {"); 173 if (emitExceptionCheck) { 174 out.println(iii + indent + "_exception = 1;"); 175 } 176 out.println(iii + indent + 177 (mUseCPlusPlus ? "_env" : "(*_env)") + 178 "->ThrowNew(" + 179 (mUseCPlusPlus ? "" : "_env, ") + 180 "IAEClass, " + 181 "\"" + 182 (isBuffer ? 183 "remaining()" : "length - " + offset) + 184 " < needed\");"); 185 out.println(iii + indent + "goto exit;"); 186 needsExit = true; 187 out.println(iii + "}"); 188 } 189 190 boolean isNullAllowed(CFunc cfunc) { 191 String[] checks = mChecker.getChecks(cfunc.getName()); 192 int index = 1; 193 if (checks != null) { 194 while (index < checks.length) { 195 if (checks[index].equals("return")) { 196 index += 2; 197 } else if (checks[index].startsWith("check")) { 198 index += 3; 199 } else if (checks[index].equals("ifcheck")) { 200 index += 5; 201 } else if (checks[index].equals("unsupported")) { 202 index += 1; 203 } else if (checks[index].equals("nullAllowed")) { 204 return true; 205 } else { 206 System.out.println("Error: unknown keyword \"" + 207 checks[index] + "\""); 208 System.exit(0); 209 } 210 } 211 } 212 return false; 213 } 214 215 String getErrorReturnValue(CFunc cfunc) { 216 CType returnType = cfunc.getType(); 217 boolean isVoid = returnType.isVoid(); 218 if (isVoid) { 219 return null; 220 } 221 222 String[] checks = mChecker.getChecks(cfunc.getName()); 223 224 int index = 1; 225 if (checks != null) { 226 while (index < checks.length) { 227 if (checks[index].equals("return")) { 228 return checks[index + 1]; 229 } else if (checks[index].startsWith("check")) { 230 index += 3; 231 } else if (checks[index].equals("ifcheck")) { 232 index += 5; 233 } else if (checks[index].equals("unsupported")) { 234 index += 1; 235 } else if (checks[index].equals("nullAllowed")) { 236 index += 1; 237 } else { 238 System.out.println("Error: unknown keyword \"" + 239 checks[index] + "\""); 240 System.exit(0); 241 } 242 } 243 } 244 245 return null; 246 } 247 248 boolean isUnsupportedFunc(CFunc cfunc) { 249 String[] checks = mChecker.getChecks(cfunc.getName()); 250 int index = 1; 251 if (checks != null) { 252 while (index < checks.length) { 253 if (checks[index].equals("unsupported")) { 254 return true; 255 } else if (checks[index].equals("return")) { 256 index += 2; 257 } else if (checks[index].startsWith("check")) { 258 index += 3; 259 } else if (checks[index].equals("ifcheck")) { 260 index += 5; 261 } else if (checks[index].equals("nullAllowed")) { 262 index += 1; 263 } else { 264 System.out.println("Error: unknown keyword \"" + 265 checks[index] + "\""); 266 System.exit(0); 267 } 268 } 269 } 270 return false; 271 } 272 273 void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out, 274 boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { 275 276 String[] checks = mChecker.getChecks(cfunc.getName()); 277 278 boolean lastWasIfcheck = false; 279 280 int index = 1; 281 if (checks != null) { 282 while (index < checks.length) { 283 if (checks[index].startsWith("check")) { 284 if (lastWasIfcheck) { 285 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, 286 offset, remaining, iii); 287 } 288 lastWasIfcheck = false; 289 if (cname != null && !cname.equals(checks[index + 1])) { 290 index += 3; 291 continue; 292 } 293 out.println(iii + "if (" + remaining + " < " + 294 checks[index + 2] + 295 ") {"); 296 if (emitExceptionCheck) { 297 out.println(iii + indent + "_exception = 1;"); 298 } 299 String exceptionClassName = "IAEClass"; 300 // If the "check" keyword was of the form 301 // "check_<class name>", use the class name in the 302 // exception to be thrown 303 int underscore = checks[index].indexOf('_'); 304 if (underscore >= 0) { 305 exceptionClassName = checks[index].substring(underscore + 1) + "Class"; 306 } 307 out.println(iii + indent + 308 (mUseCPlusPlus ? "_env" : "(*_env)") + 309 "->ThrowNew(" + 310 (mUseCPlusPlus ? "" : "_env, ") + 311 exceptionClassName + ", " + 312 "\"" + 313 (isBuffer ? 314 "remaining()" : "length - " + offset) + 315 " < " + checks[index + 2] + 316 "\");"); 317 318 out.println(iii + indent + "goto exit;"); 319 needsExit = true; 320 out.println(iii + "}"); 321 322 index += 3; 323 } else if (checks[index].equals("ifcheck")) { 324 String[] matches = checks[index + 4].split(","); 325 326 if (!lastWasIfcheck) { 327 out.println(iii + "int _needed;"); 328 out.println(iii + 329 "switch (" + 330 checks[index + 3] + 331 ") {"); 332 } 333 334 for (int i = 0; i < matches.length; i++) { 335 out.println("#if defined(" + matches[i] + ")"); 336 out.println(iii + 337 " case " + 338 matches[i] + 339 ":"); 340 out.println("#endif // defined(" + matches[i] + ")"); 341 } 342 out.println(iii + 343 " _needed = " + 344 checks[index + 2] + 345 ";"); 346 out.println(iii + 347 " break;"); 348 349 lastWasIfcheck = true; 350 index += 5; 351 } else if (checks[index].equals("return")) { 352 // ignore 353 index += 2; 354 } else if (checks[index].equals("unsupported")) { 355 // ignore 356 index += 1; 357 } else if (checks[index].equals("nullAllowed")) { 358 // ignore 359 index += 1; 360 } else { 361 System.out.println("Error: unknown keyword \"" + 362 checks[index] + "\""); 363 System.exit(0); 364 } 365 } 366 } 367 368 if (lastWasIfcheck) { 369 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii); 370 } 371 } 372 373 boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) { 374 if (nonPrimitiveArgs.size() > 0) { 375 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 376 int idx = nonPrimitiveArgs.get(i).intValue(); 377 int cIndex = jfunc.getArgCIndex(idx); 378 if (jfunc.getArgType(idx).isArray()) { 379 if (!cfunc.getArgType(cIndex).isConst()) { 380 return true; 381 } 382 } else if (jfunc.getArgType(idx).isBuffer()) { 383 if (!cfunc.getArgType(cIndex).isConst()) { 384 return true; 385 } 386 } 387 } 388 } 389 390 return false; 391 } 392 393 /** 394 * Emit a function in several variants: 395 * 396 * if nativeDecl: public native <returntype> func(args); 397 * 398 * if !nativeDecl: 399 * if interfaceDecl: public <returntype> func(args); 400 * if !interfaceDecl: public <returntype> func(args) { body } 401 */ 402 void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) { 403 boolean isPointerFunc = 404 jfunc.getName().endsWith("Pointer") && 405 jfunc.getCFunc().hasPointerArg(); 406 407 if (!nativeDecl && !interfaceDecl && !isPointerFunc) { 408 // If it's not a pointer function, we've already emitted it 409 // with nativeDecl == true 410 return; 411 } 412 413 String maybeStatic = mUseStaticMethods ? "static " : ""; 414 415 if (isPointerFunc) { 416 out.println(indent + 417 (nativeDecl ? "private " + maybeStatic +"native " : 418 (interfaceDecl ? "" : "public ") + maybeStatic) + 419 jfunc.getType() + " " + 420 jfunc.getName() + 421 (nativeDecl ? "Bounds" : "") + 422 "("); 423 } else { 424 out.println(indent + 425 (nativeDecl ? "public " + maybeStatic +"native " : 426 (interfaceDecl ? "" : "public ") + maybeStatic) + 427 jfunc.getType() + " " + 428 jfunc.getName() + 429 "("); 430 } 431 432 int numArgs = jfunc.getNumArgs(); 433 for (int i = 0; i < numArgs; i++) { 434 String argName = jfunc.getArgName(i); 435 JType argType = jfunc.getArgType(i); 436 437 out.print(indent + indent + argType + " " + argName); 438 if (i == numArgs - 1) { 439 if (isPointerFunc && nativeDecl) { 440 out.println(","); 441 out.println(indent + indent + "int remaining"); 442 } else { 443 out.println(); 444 } 445 } else { 446 out.println(","); 447 } 448 } 449 450 if (nativeDecl || interfaceDecl) { 451 out.println(indent + ");"); 452 } else { 453 out.println(indent + ") {"); 454 455 String iii = indent + indent; 456 457 // emitBoundsChecks(jfunc, out, iii); 458 emitFunctionCall(jfunc, out, iii, false); 459 460 // Set the pointer after we call the native code, so that if 461 // the native code throws an exception we don't modify the 462 // pointer. We assume that the native code is written so that 463 // if an exception is thrown, then the underlying glXXXPointer 464 // function will not have been called. 465 466 String fname = jfunc.getName(); 467 if (isPointerFunc) { 468 // TODO - deal with VBO variants 469 if (fname.equals("glColorPointer")) { 470 out.println(iii + "if ((size == 4) &&"); 471 out.println(iii + " ((type == GL_FLOAT) ||"); 472 out.println(iii + " (type == GL_UNSIGNED_BYTE) ||"); 473 out.println(iii + " (type == GL_FIXED)) &&"); 474 out.println(iii + " (stride >= 0)) {"); 475 out.println(iii + indent + "_colorPointer = pointer;"); 476 out.println(iii + "}"); 477 } else if (fname.equals("glNormalPointer")) { 478 out.println(iii + "if (((type == GL_FLOAT) ||"); 479 out.println(iii + " (type == GL_BYTE) ||"); 480 out.println(iii + " (type == GL_SHORT) ||"); 481 out.println(iii + " (type == GL_FIXED)) &&"); 482 out.println(iii + " (stride >= 0)) {"); 483 out.println(iii + indent + "_normalPointer = pointer;"); 484 out.println(iii + "}"); 485 } else if (fname.equals("glTexCoordPointer")) { 486 out.println(iii + "if (((size == 2) ||"); 487 out.println(iii + " (size == 3) ||"); 488 out.println(iii + " (size == 4)) &&"); 489 out.println(iii + " ((type == GL_FLOAT) ||"); 490 out.println(iii + " (type == GL_BYTE) ||"); 491 out.println(iii + " (type == GL_SHORT) ||"); 492 out.println(iii + " (type == GL_FIXED)) &&"); 493 out.println(iii + " (stride >= 0)) {"); 494 out.println(iii + indent + "_texCoordPointer = pointer;"); 495 out.println(iii + "}"); 496 } else if (fname.equals("glVertexPointer")) { 497 out.println(iii + "if (((size == 2) ||"); 498 out.println(iii + " (size == 3) ||"); 499 out.println(iii + " (size == 4)) &&"); 500 out.println(iii + " ((type == GL_FLOAT) ||"); 501 out.println(iii + " (type == GL_BYTE) ||"); 502 out.println(iii + " (type == GL_SHORT) ||"); 503 out.println(iii + " (type == GL_FIXED)) &&"); 504 out.println(iii + " (stride >= 0)) {"); 505 out.println(iii + indent + "_vertexPointer = pointer;"); 506 out.println(iii + "}"); 507 } 508 } 509 510 boolean isVoid = jfunc.getType().isVoid(); 511 512 if (!isVoid) { 513 out.println(indent + indent + "return _returnValue;"); 514 } 515 out.println(indent + "}"); 516 } 517 out.println(); 518 } 519 520 public void addNativeRegistration(String s) { 521 nativeRegistrations.add(s); 522 } 523 524 public void emitNativeRegistration(String registrationFunctionName, 525 PrintStream cStream) { 526 cStream.println("static const char *classPathName = \"" + 527 mClassPathName + 528 "\";"); 529 cStream.println(); 530 531 cStream.println("static JNINativeMethod methods[] = {"); 532 533 cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },"); 534 535 Iterator<String> i = nativeRegistrations.iterator(); 536 while (i.hasNext()) { 537 cStream.println(i.next()); 538 } 539 540 cStream.println("};"); 541 cStream.println(); 542 543 544 cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)"); 545 cStream.println("{"); 546 cStream.println(indent + 547 "int err;"); 548 549 cStream.println(indent + 550 "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));"); 551 552 cStream.println(indent + "return err;"); 553 cStream.println("}"); 554 } 555 556 public JniCodeEmitter() { 557 super(); 558 } 559 560 String getJniType(JType jType) { 561 if (jType.isVoid()) { 562 return "void"; 563 } 564 565 String baseType = jType.getBaseType(); 566 if (jType.isPrimitive()) { 567 if (baseType.equals("String")) { 568 return "jstring"; 569 } else { 570 return "j" + baseType; 571 } 572 } else if (jType.isArray()) { 573 return "j" + baseType + "Array"; 574 } else { 575 return "jobject"; 576 } 577 } 578 579 String getJniMangledName(String name) { 580 name = name.replaceAll("_", "_1"); 581 name = name.replaceAll(";", "_2"); 582 name = name.replaceAll("\\[", "_3"); 583 return name; 584 } 585 586 public void emitJniCode(JFunc jfunc, PrintStream out) { 587 CFunc cfunc = jfunc.getCFunc(); 588 589 // Emit comment identifying original C function 590 // 591 // Example: 592 // 593 // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */ 594 // 595 out.println("/* " + cfunc.getOriginal() + " */"); 596 597 // Emit JNI signature (name) 598 // 599 // Example: 600 // 601 // void 602 // android_glClipPlanef__I_3FI 603 // 604 605 String outName = "android_" + jfunc.getName(); 606 boolean isPointerFunc = outName.endsWith("Pointer") && 607 jfunc.getCFunc().hasPointerArg(); 608 boolean isVBOPointerFunc = (outName.endsWith("Pointer") || 609 outName.endsWith("DrawElements")) && 610 !jfunc.getCFunc().hasPointerArg(); 611 if (isPointerFunc) { 612 outName += "Bounds"; 613 } 614 615 out.print("static "); 616 out.println(getJniType(jfunc.getType())); 617 out.print(outName); 618 619 String rsignature = getJniName(jfunc.getType()); 620 621 String signature = ""; 622 int numArgs = jfunc.getNumArgs(); 623 for (int i = 0; i < numArgs; i++) { 624 JType argType = jfunc.getArgType(i); 625 signature += getJniName(argType); 626 } 627 if (isPointerFunc) { 628 signature += "I"; 629 } 630 631 // Append signature to function name 632 String sig = getJniMangledName(signature).replace('.', '_'); 633 out.print("__" + sig); 634 outName += "__" + sig; 635 636 signature = signature.replace('.', '/'); 637 rsignature = rsignature.replace('.', '/'); 638 639 out.println(); 640 if (rsignature.length() == 0) { 641 rsignature = "V"; 642 } 643 644 String s = "{\"" + 645 jfunc.getName() + 646 (isPointerFunc ? "Bounds" : "") + 647 "\", \"(" + signature +")" + 648 rsignature + 649 "\", (void *) " + 650 outName + 651 " },"; 652 nativeRegistrations.add(s); 653 654 List<Integer> nonPrimitiveArgs = new ArrayList<Integer>(); 655 int numBufferArgs = 0; 656 List<String> bufferArgNames = new ArrayList<String>(); 657 658 // Emit JNI signature (arguments) 659 // 660 // Example: 661 // 662 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) { 663 // 664 out.print(" (JNIEnv *_env, jobject _this"); 665 for (int i = 0; i < numArgs; i++) { 666 out.print(", "); 667 JType argType = jfunc.getArgType(i); 668 String suffix; 669 if (!argType.isPrimitive()) { 670 if (argType.isArray()) { 671 suffix = "_ref"; 672 } else { 673 suffix = "_buf"; 674 } 675 nonPrimitiveArgs.add(new Integer(i)); 676 if (jfunc.getArgType(i).isBuffer()) { 677 int cIndex = jfunc.getArgCIndex(i); 678 String cname = cfunc.getArgName(cIndex); 679 bufferArgNames.add(cname); 680 numBufferArgs++; 681 } 682 } else { 683 suffix = ""; 684 } 685 686 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix); 687 } 688 if (isPointerFunc) { 689 out.print(", jint remaining"); 690 } 691 out.println(") {"); 692 693 int numArrays = 0; 694 int numBuffers = 0; 695 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 696 int idx = nonPrimitiveArgs.get(i).intValue(); 697 if (jfunc.getArgType(idx).isArray()) { 698 ++numArrays; 699 } 700 if (jfunc.getArgType(idx).isBuffer()) { 701 ++numBuffers; 702 } 703 } 704 705 // Emit method body 706 707 // Emit local variable declarations for _exception and _returnValue 708 // 709 // Example: 710 // 711 // android::gl::ogles_context_t *ctx; 712 // 713 // jint _exception; 714 // GLenum _returnValue; 715 // 716 CType returnType = cfunc.getType(); 717 boolean isVoid = returnType.isVoid(); 718 719 boolean isUnsupported = isUnsupportedFunc(cfunc); 720 if (isUnsupported) { 721 out.println(indent + 722 "_env->ThrowNew(UOEClass,"); 723 out.println(indent + 724 " \"" + cfunc.getName() + "\");"); 725 if (!isVoid) { 726 String retval = getErrorReturnValue(cfunc); 727 out.println(indent + "return " + retval + ";"); 728 } 729 out.println("}"); 730 out.println(); 731 return; 732 } 733 734 if (mUseContextPointer) { 735 out.println(indent + 736 "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); 737 } 738 739 boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) && 740 hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs); 741 // mChecker.getChecks(cfunc.getName()) != null 742 743 // Emit an _exeption variable if there will be error checks 744 if (emitExceptionCheck) { 745 out.println(indent + "jint _exception = 0;"); 746 } 747 748 // Emit a single _array or multiple _XXXArray variables 749 if (numBufferArgs == 1) { 750 out.println(indent + "jarray _array = (jarray) 0;"); 751 } else { 752 for (int i = 0; i < numBufferArgs; i++) { 753 out.println(indent + "jarray _" + bufferArgNames.get(i) + 754 "Array = (jarray) 0;"); 755 } 756 } 757 if (!isVoid) { 758 String retval = getErrorReturnValue(cfunc); 759 if (retval != null) { 760 out.println(indent + returnType.getDeclaration() + 761 " _returnValue = " + retval + ";"); 762 } else { 763 out.println(indent + returnType.getDeclaration() + 764 " _returnValue;"); 765 } 766 } 767 768 // Emit local variable declarations for pointer arguments 769 // 770 // Example: 771 // 772 // GLfixed *eqn_base; 773 // GLfixed *eqn; 774 // 775 String offset = "offset"; 776 String remaining = "_remaining"; 777 if (nonPrimitiveArgs.size() > 0) { 778 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 779 int idx = nonPrimitiveArgs.get(i).intValue(); 780 int cIndex = jfunc.getArgCIndex(idx); 781 String cname = cfunc.getArgName(cIndex); 782 783 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 784 String decl = type.getDeclaration(); 785 if (jfunc.getArgType(idx).isArray()) { 786 out.println(indent + 787 decl + 788 (decl.endsWith("*") ? "" : " ") + 789 jfunc.getArgName(idx) + 790 "_base = (" + decl + ") 0;"); 791 } 792 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" : 793 "_" + cname + "Remaining"; 794 out.println(indent + 795 "jint " + remaining + ";"); 796 out.println(indent + 797 decl + 798 (decl.endsWith("*") ? "" : " ") + 799 jfunc.getArgName(idx) + 800 " = (" + decl + ") 0;"); 801 } 802 803 out.println(); 804 } 805 806 // Emit 'GetPrimitiveArrayCritical' for arrays 807 // Emit 'GetPointer' calls for Buffer pointers 808 int bufArgIdx = 0; 809 if (nonPrimitiveArgs.size() > 0) { 810 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 811 int idx = nonPrimitiveArgs.get(i).intValue(); 812 int cIndex = jfunc.getArgCIndex(idx); 813 814 String cname = cfunc.getArgName(cIndex); 815 offset = numArrays <= 1 ? "offset" : 816 cname + "Offset"; 817 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" : 818 "_" + cname + "Remaining"; 819 820 if (jfunc.getArgType(idx).isArray()) { 821 out.println(indent + 822 "if (!" + 823 cname + 824 "_ref) {"); 825 if (emitExceptionCheck) { 826 out.println(indent + indent + "_exception = 1;"); 827 } 828 out.println(indent + " " + 829 (mUseCPlusPlus ? "_env" : "(*_env)") + 830 "->ThrowNew(" + 831 (mUseCPlusPlus ? "" : "_env, ") + 832 "IAEClass, " + 833 "\"" + cname + 834 " == null\");"); 835 out.println(indent + " goto exit;"); 836 needsExit = true; 837 out.println(indent + "}"); 838 839 out.println(indent + "if (" + offset + " < 0) {"); 840 if (emitExceptionCheck) { 841 out.println(indent + indent + "_exception = 1;"); 842 } 843 out.println(indent + " " + 844 (mUseCPlusPlus ? "_env" : "(*_env)") + 845 "->ThrowNew(" + 846 (mUseCPlusPlus ? "" : "_env, ") + 847 "IAEClass, " + 848 "\"" + offset + " < 0\");"); 849 out.println(indent + " goto exit;"); 850 needsExit = true; 851 out.println(indent + "}"); 852 853 out.println(indent + remaining + " = " + 854 (mUseCPlusPlus ? "_env" : "(*_env)") + 855 "->GetArrayLength(" + 856 (mUseCPlusPlus ? "" : "_env, ") + 857 cname + "_ref) - " + offset + ";"); 858 859 emitNativeBoundsChecks(cfunc, cname, out, false, 860 emitExceptionCheck, 861 offset, remaining, " "); 862 863 out.println(indent + 864 cname + 865 "_base = (" + 866 cfunc.getArgType(cIndex).getDeclaration() + 867 ")"); 868 out.println(indent + " " + 869 (mUseCPlusPlus ? "_env" : "(*_env)") + 870 "->GetPrimitiveArrayCritical(" + 871 (mUseCPlusPlus ? "" : "_env, ") + 872 jfunc.getArgName(idx) + 873 "_ref, (jboolean *)0);"); 874 out.println(indent + 875 cname + " = " + cname + "_base + " + offset + 876 ";"); 877 out.println(); 878 } else { 879 String array = numBufferArgs <= 1 ? "_array" : 880 "_" + bufferArgNames.get(bufArgIdx++) + "Array"; 881 882 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 883 if (nullAllowed) { 884 out.println(indent + "if (" + cname + "_buf) {"); 885 out.print(indent); 886 } 887 888 if (isPointerFunc) { 889 out.println(indent + 890 cname + 891 " = (" + 892 cfunc.getArgType(cIndex).getDeclaration() + 893 ") getDirectBufferPointer(_env, " + 894 cname + "_buf);"); 895 String iii = " "; 896 out.println(iii + indent + "if ( ! " + cname + " ) {"); 897 out.println(iii + iii + indent + "return;"); 898 out.println(iii + indent + "}"); 899 } else { 900 out.println(indent + 901 cname + 902 " = (" + 903 cfunc.getArgType(cIndex).getDeclaration() + 904 ")getPointer(_env, " + 905 cname + 906 "_buf, &" + array + ", &" + remaining + 907 ");"); 908 } 909 910 emitNativeBoundsChecks(cfunc, cname, out, true, 911 emitExceptionCheck, 912 offset, remaining, nullAllowed ? " " : " "); 913 914 if (nullAllowed) { 915 out.println(indent + "}"); 916 } 917 } 918 } 919 } 920 921 if (!isVoid) { 922 out.print(indent + "_returnValue = "); 923 } else { 924 out.print(indent); 925 } 926 String name = cfunc.getName(); 927 928 if (mUseContextPointer) { 929 name = name.substring(2, name.length()); // Strip off 'gl' prefix 930 name = name.substring(0, 1).toLowerCase() + 931 name.substring(1, name.length()); 932 out.print("ctx->procs."); 933 } 934 935 out.print(name + (isPointerFunc ? "Bounds" : "") + "("); 936 937 numArgs = cfunc.getNumArgs(); 938 if (numArgs == 0) { 939 if (mUseContextPointer) { 940 out.println("ctx);"); 941 } else { 942 out.println(");"); 943 } 944 } else { 945 if (mUseContextPointer) { 946 out.println("ctx,"); 947 } else { 948 out.println(); 949 } 950 for (int i = 0; i < numArgs; i++) { 951 String typecast; 952 if (i == numArgs - 1 && isVBOPointerFunc) { 953 typecast = "const GLvoid *"; 954 } else { 955 typecast = cfunc.getArgType(i).getDeclaration(); 956 } 957 out.print(indent + indent + 958 "(" + 959 typecast + 960 ")" + 961 cfunc.getArgName(i)); 962 963 if (i == numArgs - 1) { 964 if (isPointerFunc) { 965 out.println(","); 966 out.println(indent + indent + "(GLsizei)remaining"); 967 } else { 968 out.println(); 969 } 970 } else { 971 out.println(","); 972 } 973 } 974 out.println(indent + ");"); 975 } 976 977 if (needsExit) { 978 out.println(); 979 out.println("exit:"); 980 needsExit = false; 981 } 982 983 bufArgIdx = 0; 984 if (nonPrimitiveArgs.size() > 0) { 985 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 986 int idx = nonPrimitiveArgs.get(i).intValue(); 987 988 int cIndex = jfunc.getArgCIndex(idx); 989 if (jfunc.getArgType(idx).isArray()) { 990 991 // If the argument is 'const', GL will not write to it. 992 // In this case, we can use the 'JNI_ABORT' flag to avoid 993 // the need to write back to the Java array 994 out.println(indent + 995 "if (" + jfunc.getArgName(idx) + "_base) {"); 996 out.println(indent + indent + 997 (mUseCPlusPlus ? "_env" : "(*_env)") + 998 "->ReleasePrimitiveArrayCritical(" + 999 (mUseCPlusPlus ? "" : "_env, ") + 1000 jfunc.getArgName(idx) + "_ref, " + 1001 cfunc.getArgName(cIndex) + 1002 "_base,"); 1003 out.println(indent + indent + indent + 1004 (cfunc.getArgType(cIndex).isConst() ? 1005 "JNI_ABORT" : 1006 "_exception ? JNI_ABORT: 0") + 1007 ");"); 1008 out.println(indent + "}"); 1009 } else if (jfunc.getArgType(idx).isBuffer()) { 1010 if (! isPointerFunc) { 1011 String array = numBufferArgs <= 1 ? "_array" : 1012 "_" + bufferArgNames.get(bufArgIdx++) + "Array"; 1013 out.println(indent + "if (" + array + ") {"); 1014 out.println(indent + indent + 1015 "releasePointer(_env, " + array + ", " + 1016 cfunc.getArgName(cIndex) + 1017 ", " + 1018 (cfunc.getArgType(cIndex).isConst() ? 1019 "JNI_FALSE" : "_exception ? JNI_FALSE :" + 1020 " JNI_TRUE") + 1021 ");"); 1022 out.println(indent + "}"); 1023 } 1024 } 1025 } 1026 } 1027 1028 if (!isVoid) { 1029 out.println(indent + "return _returnValue;"); 1030 } 1031 1032 out.println("}"); 1033 out.println(); 1034 } 1035 1036} 1037