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