1 import java.io.PrintStream; 2 import java.util.ArrayList; 3 import java.util.HashSet; 4 import java.util.Iterator; 5 import java.util.List; 6 7 public 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 getJniName(JType jType)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 emitCode(CFunc cfunc, String original, PrintStream javaInterfaceStream, PrintStream javaImplStream, PrintStream cStream)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 emitNativeDeclaration(JFunc jfunc, PrintStream out)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 emitJavaInterfaceCode(JFunc jfunc, PrintStream out)108 public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) { 109 emitFunction(jfunc, out, false, true); 110 } 111 emitJavaCode(JFunc jfunc, PrintStream out)112 public void emitJavaCode(JFunc jfunc, PrintStream out) { 113 emitFunction(jfunc, out, false, false); 114 } 115 emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray)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 printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String iii)159 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, 160 String iii) { 161 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, 162 "offset", "_remaining", iii); 163 } 164 printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii)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 isNullAllowed(CFunc cfunc)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 getErrorReturnValue(CFunc cfunc)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 isUnsupportedFunc(CFunc cfunc)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 emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out, boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii)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 hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs)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 */ emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl)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 addNativeRegistration(String s)520 public void addNativeRegistration(String s) { 521 nativeRegistrations.add(s); 522 } 523 emitNativeRegistration(String registrationFunctionName, PrintStream cStream)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 JniCodeEmitter()556 public JniCodeEmitter() { 557 super(); 558 } 559 getJniType(JType jType)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 getJniMangledName(String name)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 emitJniCode(JFunc jfunc, PrintStream out)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