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