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