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