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 boolean mUseSimpleMethodNames = false; 29 protected boolean mUseHideCommentForAPI = false; 30 protected String mClassPathName; 31 protected ParameterChecker mChecker; 32 protected List<String> nativeRegistrations = new ArrayList<String>(); 33 boolean needsExit; 34 protected static String indent = " "; 35 HashSet<String> mFunctionsEmitted = new HashSet<String>(); 36 37 public static String getJniName(JType jType) { 38 String jniName = ""; 39 if (jType.isEGLHandle()) { 40 return (jType.isArray() ? "[" : "" ) + "Landroid/opengl/" + jType.getBaseType() + ";"; 41 } else if (jType.isClass()) { 42 return "L" + jType.getBaseType() + ";"; 43 } else if (jType.isArray()) { 44 jniName = "["; 45 } 46 47 String baseType = jType.getBaseType(); 48 if (baseType.equals("int")) { 49 jniName += "I"; 50 } else if (baseType.equals("float")) { 51 jniName += "F"; 52 } else if (baseType.equals("boolean")) { 53 jniName += "Z"; 54 } else if (baseType.equals("short")) { 55 jniName += "S"; 56 } else if (baseType.equals("long")) { 57 jniName += "J"; 58 } else if (baseType.equals("byte")) { 59 jniName += "B"; 60 } else if (baseType.equals("String")) { 61 jniName += "Ljava/lang/String;"; 62 } else if (baseType.equals("void")) { 63 // nothing. 64 } else { 65 throw new RuntimeException("Unknown primitive basetype " + baseType); 66 } 67 return jniName; 68 } 69 70 public void emitCode(CFunc cfunc, String original, 71 PrintStream javaInterfaceStream, 72 PrintStream javaImplStream, 73 PrintStream cStream) { 74 JFunc jfunc; 75 String signature; 76 boolean duplicate; 77 78 if (cfunc.hasTypedPointerArg()) { 79 jfunc = JFunc.convert(cfunc, true); 80 81 // Don't emit duplicate functions 82 // These may appear because they are defined in multiple 83 // Java interfaces (e.g., GL11/GL11ExtensionPack) 84 signature = jfunc.toString(); 85 duplicate = false; 86 if (mFunctionsEmitted.contains(signature)) { 87 duplicate = true; 88 } else { 89 mFunctionsEmitted.add(signature); 90 } 91 92 if (!duplicate) { 93 emitNativeDeclaration(jfunc, javaImplStream); 94 emitJavaCode(jfunc, javaImplStream); 95 } 96 if (javaInterfaceStream != null) { 97 emitJavaInterfaceCode(jfunc, javaInterfaceStream); 98 } 99 if (!duplicate) { 100 emitJniCode(jfunc, cStream); 101 } 102 // Don't create IOBuffer versions of the EGL functions 103 if (cfunc.hasEGLHandleArg()) { 104 return; 105 } 106 } 107 108 jfunc = JFunc.convert(cfunc, false); 109 110 signature = jfunc.toString(); 111 duplicate = false; 112 if (mFunctionsEmitted.contains(signature)) { 113 duplicate = true; 114 } else { 115 mFunctionsEmitted.add(signature); 116 } 117 118 if (!duplicate) { 119 emitNativeDeclaration(jfunc, javaImplStream); 120 } 121 if (javaInterfaceStream != null) { 122 emitJavaInterfaceCode(jfunc, javaInterfaceStream); 123 } 124 if (!duplicate) { 125 emitJavaCode(jfunc, javaImplStream); 126 emitJniCode(jfunc, cStream); 127 } 128 } 129 130 public void emitNativeDeclaration(JFunc jfunc, PrintStream out) { 131 if (mUseHideCommentForAPI) { 132 out.println(" /* @hide C function " + jfunc.getCFunc().getOriginal() + " */"); 133 out.println(); 134 } else { 135 out.println(" // C function " + jfunc.getCFunc().getOriginal()); 136 out.println(); 137 } 138 139 emitFunction(jfunc, out, true, false); 140 } 141 142 public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) { 143 emitFunction(jfunc, out, false, true); 144 } 145 146 public void emitJavaCode(JFunc jfunc, PrintStream out) { 147 emitFunction(jfunc, out, false, false); 148 } 149 150 boolean isPointerFunc(JFunc jfunc) { 151 String name = jfunc.getName(); 152 return (name.endsWith("Pointer") || name.endsWith("PointerOES")) 153 && jfunc.getCFunc().hasPointerArg(); 154 } 155 156 void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) { 157 boolean isVoid = jfunc.getType().isVoid(); 158 boolean isPointerFunc = isPointerFunc(jfunc); 159 160 if (!isVoid) { 161 out.println(iii + 162 jfunc.getType() + " _returnValue;"); 163 } 164 out.println(iii + 165 (isVoid ? "" : "_returnValue = ") + 166 jfunc.getName() + 167 (isPointerFunc ? "Bounds" : "" ) + 168 "("); 169 170 int numArgs = jfunc.getNumArgs(); 171 for (int i = 0; i < numArgs; i++) { 172 String argName = jfunc.getArgName(i); 173 JType argType = jfunc.getArgType(i); 174 175 if (grabArray && argType.isTypedBuffer()) { 176 String typeName = argType.getBaseType(); 177 typeName = typeName.substring(9, typeName.length() - 6); 178 out.println(iii + indent + "get" + typeName + "Array(" + argName + "),"); 179 out.print(iii + indent + "getOffset(" + argName + ")"); 180 } else { 181 out.print(iii + indent + argName); 182 } 183 if (i == numArgs - 1) { 184 if (isPointerFunc) { 185 out.println(","); 186 out.println(iii + indent + argName + ".remaining()"); 187 } else { 188 out.println(); 189 } 190 } else { 191 out.println(","); 192 } 193 } 194 195 out.println(iii + ");"); 196 } 197 198 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, 199 String iii) { 200 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, 201 "offset", "_remaining", iii); 202 } 203 204 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, 205 String offset, String remaining, String iii) { 206 out.println(iii + " default:"); 207 out.println(iii + " _needed = 1;"); 208 out.println(iii + " break;"); 209 out.println(iii + "}"); 210 211 out.println(iii + "if (" + remaining + " < _needed) {"); 212 out.println(iii + indent + "_exception = 1;"); 213 out.println(iii + indent + 214 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 215 out.println(iii + indent + 216 "_exceptionMessage = \"" + 217 (isBuffer ? "remaining()" : "length - " + offset) + 218 " < needed\";"); 219 out.println(iii + indent + "goto exit;"); 220 out.println(iii + "}"); 221 222 needsExit = true; 223 } 224 225 boolean isNullAllowed(CFunc cfunc) { 226 String[] checks = mChecker.getChecks(cfunc.getName()); 227 int index = 1; 228 if (checks != null) { 229 while (index < checks.length) { 230 if (checks[index].equals("nullAllowed")) { 231 return true; 232 } else { 233 index = skipOneCheck(checks, index); 234 } 235 } 236 } 237 return false; 238 } 239 240 boolean hasCheckTest(CFunc cfunc) { 241 String[] checks = mChecker.getChecks(cfunc.getName()); 242 int index = 1; 243 if (checks != null) { 244 while (index < checks.length) { 245 if (checks[index].startsWith("check")) { 246 return true; 247 } else { 248 index = skipOneCheck(checks, index); 249 } 250 } 251 } 252 return false; 253 } 254 255 boolean hasIfTest(CFunc cfunc) { 256 String[] checks = mChecker.getChecks(cfunc.getName()); 257 int index = 1; 258 if (checks != null) { 259 while (index < checks.length) { 260 if (checks[index].startsWith("ifcheck")) { 261 return true; 262 } else { 263 index = skipOneCheck(checks, index); 264 } 265 } 266 } 267 return false; 268 } 269 270 int skipOneCheck(String[] checks, int index) { 271 if (checks[index].equals("return")) { 272 index += 2; 273 } else if (checks[index].startsWith("check")) { 274 index += 3; 275 } else if (checks[index].startsWith("sentinel")) { 276 index += 3; 277 } else if (checks[index].equals("ifcheck")) { 278 index += 5; 279 } else if (checks[index].equals("unsupported")) { 280 index += 1; 281 } else if (checks[index].equals("requires")) { 282 index += 2; 283 } else if (checks[index].equals("nullAllowed")) { 284 index += 1; 285 } else { 286 System.out.println("Error: unknown keyword \"" + 287 checks[index] + "\""); 288 System.exit(0); 289 } 290 291 return index; 292 } 293 294 String getErrorReturnValue(CFunc cfunc) { 295 CType returnType = cfunc.getType(); 296 boolean isVoid = returnType.isVoid(); 297 if (isVoid) { 298 return null; 299 } 300 301 if (returnType.getBaseType().startsWith("EGL")) { 302 return "(" + returnType.getDeclaration() + ") 0"; 303 } 304 305 String[] checks = mChecker.getChecks(cfunc.getName()); 306 307 int index = 1; 308 if (checks != null) { 309 while (index < checks.length) { 310 if (checks[index].equals("return")) { 311 return checks[index + 1]; 312 } else { 313 index = skipOneCheck(checks, index); 314 } 315 } 316 } 317 318 return null; 319 } 320 321 boolean isUnsupportedFunc(CFunc cfunc) { 322 String[] checks = mChecker.getChecks(cfunc.getName()); 323 int index = 1; 324 if (checks != null) { 325 while (index < checks.length) { 326 if (checks[index].equals("unsupported")) { 327 return true; 328 } else { 329 index = skipOneCheck(checks, index); 330 } 331 } 332 } 333 return false; 334 } 335 336 String isRequiresFunc(CFunc cfunc) { 337 String[] checks = mChecker.getChecks(cfunc.getName()); 338 int index = 1; 339 if (checks != null) { 340 while (index < checks.length) { 341 if (checks[index].equals("requires")) { 342 return checks[index+1]; 343 } else { 344 index = skipOneCheck(checks, index); 345 } 346 } 347 } 348 return null; 349 } 350 351 void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out, 352 boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { 353 354 String[] checks = mChecker.getChecks(cfunc.getName()); 355 356 boolean lastWasIfcheck = false; 357 358 int index = 1; 359 if (checks != null) { 360 while (index < checks.length) { 361 if (checks[index].startsWith("check")) { 362 if (lastWasIfcheck) { 363 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, 364 offset, remaining, iii); 365 } 366 lastWasIfcheck = false; 367 if (cname != null && !cname.equals(checks[index + 1])) { 368 index += 3; 369 continue; 370 } 371 out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {"); 372 out.println(iii + indent + "_exception = 1;"); 373 String exceptionClassName = "java/lang/IllegalArgumentException"; 374 // If the "check" keyword was of the form 375 // "check_<class name>", use the class name in the 376 // exception to be thrown 377 int underscore = checks[index].indexOf('_'); 378 if (underscore >= 0) { 379 String abbr = checks[index].substring(underscore + 1); 380 if (abbr.equals("AIOOBE")) { 381 exceptionClassName = "java/lang/ArrayIndexOutOfBoundsException"; 382 } else { 383 throw new RuntimeException("unknown exception abbreviation: " + abbr); 384 } 385 } 386 out.println(iii + indent + 387 "_exceptionType = \""+exceptionClassName+"\";"); 388 out.println(iii + indent + 389 "_exceptionMessage = \"" + 390 (isBuffer ? "remaining()" : "length - " + 391 offset) + " < " + checks[index + 2] + 392 " < needed\";"); 393 394 out.println(iii + indent + "goto exit;"); 395 out.println(iii + "}"); 396 397 needsExit = true; 398 399 index += 3; 400 } else if (checks[index].equals("ifcheck")) { 401 String[] matches = checks[index + 4].split(","); 402 403 if (!lastWasIfcheck) { 404 out.println(iii + "int _needed;"); 405 out.println(iii + "switch (" + checks[index + 3] + ") {"); 406 } 407 408 for (int i = 0; i < matches.length; i++) { 409 out.println("#if defined(" + matches[i] + ")"); 410 out.println(iii + " case " + matches[i] + ":"); 411 out.println("#endif // defined(" + matches[i] + ")"); 412 } 413 out.println(iii + " _needed = " + checks[index + 2] + ";"); 414 out.println(iii + " break;"); 415 416 lastWasIfcheck = true; 417 index += 5; 418 } else { 419 index = skipOneCheck(checks, index); 420 } 421 } 422 } 423 424 if (lastWasIfcheck) { 425 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii); 426 } 427 } 428 429 void emitSentinelCheck(CFunc cfunc, String cname, PrintStream out, 430 boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { 431 432 String[] checks = mChecker.getChecks(cfunc.getName()); 433 434 int index = 1; 435 if (checks != null) { 436 while (index < checks.length) { 437 if (checks[index].startsWith("sentinel")) { 438 if (cname != null && !cname.equals(checks[index + 1])) { 439 index += 3; 440 continue; 441 } 442 443 out.println(iii + cname + "_sentinel = false;"); 444 out.println(iii + "for (int i = " + remaining + 445 " - 1; i >= 0; i--) {"); 446 out.println(iii + indent + "if (" + cname + 447 "[i] == " + checks[index + 2] + "){"); 448 out.println(iii + indent + indent + 449 cname + "_sentinel = true;"); 450 out.println(iii + indent + indent + "break;"); 451 out.println(iii + indent + "}"); 452 out.println(iii + "}"); 453 out.println(iii + 454 "if (" + cname + "_sentinel == false) {"); 455 out.println(iii + indent + "_exception = 1;"); 456 out.println(iii + indent + 457 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 458 out.println(iii + indent + "_exceptionMessage = \"" + cname + 459 " must contain " + checks[index + 2] + "!\";"); 460 out.println(iii + indent + "goto exit;"); 461 out.println(iii + "}"); 462 463 needsExit = true; 464 index += 3; 465 } else { 466 index = skipOneCheck(checks, index); 467 } 468 } 469 } 470 } 471 472 void emitLocalVariablesForSentinel(CFunc cfunc, PrintStream out) { 473 474 String[] checks = mChecker.getChecks(cfunc.getName()); 475 476 int index = 1; 477 if (checks != null) { 478 while (index < checks.length) { 479 if (checks[index].startsWith("sentinel")) { 480 String cname = checks[index + 1]; 481 out.println(indent + "bool " + cname + "_sentinel = false;"); 482 483 index += 3; 484 485 } else { 486 index = skipOneCheck(checks, index); 487 } 488 } 489 } 490 } 491 492 boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) { 493 if (nonPrimitiveArgs.size() > 0) { 494 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 495 int idx = nonPrimitiveArgs.get(i).intValue(); 496 int cIndex = jfunc.getArgCIndex(idx); 497 if (jfunc.getArgType(idx).isArray()) { 498 if (!cfunc.getArgType(cIndex).isConst()) { 499 return true; 500 } 501 } else if (jfunc.getArgType(idx).isBuffer()) { 502 if (!cfunc.getArgType(cIndex).isConst()) { 503 return true; 504 } 505 } 506 } 507 } 508 509 return false; 510 } 511 512 /** 513 * Emit a function in several variants: 514 * 515 * if nativeDecl: public native <returntype> func(args); 516 * 517 * if !nativeDecl: 518 * if interfaceDecl: public <returntype> func(args); 519 * if !interfaceDecl: public <returntype> func(args) { body } 520 */ 521 void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) { 522 boolean isPointerFunc = isPointerFunc(jfunc); 523 524 if (!nativeDecl && !interfaceDecl && !isPointerFunc) { 525 // If it's not a pointer function, we've already emitted it 526 // with nativeDecl == true 527 return; 528 } 529 530 String maybeStatic = mUseStaticMethods ? "static " : ""; 531 532 if (isPointerFunc) { 533 out.println(indent + 534 (nativeDecl ? "private " + maybeStatic +"native " : 535 (interfaceDecl ? "" : "public ") + maybeStatic) + 536 jfunc.getType() + " " + 537 jfunc.getName() + 538 (nativeDecl ? "Bounds" : "") + 539 "("); 540 } else { 541 out.println(indent + 542 (nativeDecl ? "public " + maybeStatic +"native " : 543 (interfaceDecl ? "" : "public ") + maybeStatic) + 544 jfunc.getType() + " " + 545 jfunc.getName() + 546 "("); 547 } 548 549 int numArgs = jfunc.getNumArgs(); 550 for (int i = 0; i < numArgs; i++) { 551 String argName = jfunc.getArgName(i); 552 JType argType = jfunc.getArgType(i); 553 554 out.print(indent + indent + argType + " " + argName); 555 if (i == numArgs - 1) { 556 if (isPointerFunc && nativeDecl) { 557 out.println(","); 558 out.println(indent + indent + "int remaining"); 559 } else { 560 out.println(); 561 } 562 } else { 563 out.println(","); 564 } 565 } 566 567 if (nativeDecl || interfaceDecl) { 568 out.println(indent + ");"); 569 } else { 570 out.println(indent + ") {"); 571 572 String iii = indent + indent; 573 574 // emitBoundsChecks(jfunc, out, iii); 575 emitFunctionCall(jfunc, out, iii, false); 576 577 // Set the pointer after we call the native code, so that if 578 // the native code throws an exception we don't modify the 579 // pointer. We assume that the native code is written so that 580 // if an exception is thrown, then the underlying glXXXPointer 581 // function will not have been called. 582 583 String fname = jfunc.getName(); 584 if (isPointerFunc) { 585 // TODO - deal with VBO variants 586 if (fname.equals("glColorPointer")) { 587 out.println(iii + "if ((size == 4) &&"); 588 out.println(iii + " ((type == GL_FLOAT) ||"); 589 out.println(iii + " (type == GL_UNSIGNED_BYTE) ||"); 590 out.println(iii + " (type == GL_FIXED)) &&"); 591 out.println(iii + " (stride >= 0)) {"); 592 out.println(iii + indent + "_colorPointer = pointer;"); 593 out.println(iii + "}"); 594 } else if (fname.equals("glNormalPointer")) { 595 out.println(iii + "if (((type == GL_FLOAT) ||"); 596 out.println(iii + " (type == GL_BYTE) ||"); 597 out.println(iii + " (type == GL_SHORT) ||"); 598 out.println(iii + " (type == GL_FIXED)) &&"); 599 out.println(iii + " (stride >= 0)) {"); 600 out.println(iii + indent + "_normalPointer = pointer;"); 601 out.println(iii + "}"); 602 } else if (fname.equals("glTexCoordPointer")) { 603 out.println(iii + "if (((size == 2) ||"); 604 out.println(iii + " (size == 3) ||"); 605 out.println(iii + " (size == 4)) &&"); 606 out.println(iii + " ((type == GL_FLOAT) ||"); 607 out.println(iii + " (type == GL_BYTE) ||"); 608 out.println(iii + " (type == GL_SHORT) ||"); 609 out.println(iii + " (type == GL_FIXED)) &&"); 610 out.println(iii + " (stride >= 0)) {"); 611 out.println(iii + indent + "_texCoordPointer = pointer;"); 612 out.println(iii + "}"); 613 } else if (fname.equals("glVertexPointer")) { 614 out.println(iii + "if (((size == 2) ||"); 615 out.println(iii + " (size == 3) ||"); 616 out.println(iii + " (size == 4)) &&"); 617 out.println(iii + " ((type == GL_FLOAT) ||"); 618 out.println(iii + " (type == GL_BYTE) ||"); 619 out.println(iii + " (type == GL_SHORT) ||"); 620 out.println(iii + " (type == GL_FIXED)) &&"); 621 out.println(iii + " (stride >= 0)) {"); 622 out.println(iii + indent + "_vertexPointer = pointer;"); 623 out.println(iii + "}"); 624 } else if (fname.equals("glPointSizePointerOES")) { 625 out.println(iii + "if (((type == GL_FLOAT) ||"); 626 out.println(iii + " (type == GL_FIXED)) &&"); 627 out.println(iii + " (stride >= 0)) {"); 628 out.println(iii + indent + "_pointSizePointerOES = pointer;"); 629 out.println(iii + "}"); 630 } else if (fname.equals("glMatrixIndexPointerOES")) { 631 out.println(iii + "if (((size == 2) ||"); 632 out.println(iii + " (size == 3) ||"); 633 out.println(iii + " (size == 4)) &&"); 634 out.println(iii + " ((type == GL_FLOAT) ||"); 635 out.println(iii + " (type == GL_BYTE) ||"); 636 out.println(iii + " (type == GL_SHORT) ||"); 637 out.println(iii + " (type == GL_FIXED)) &&"); 638 out.println(iii + " (stride >= 0)) {"); 639 out.println(iii + indent + "_matrixIndexPointerOES = pointer;"); 640 out.println(iii + "}"); 641 } else if (fname.equals("glWeightPointer")) { 642 out.println(iii + "if (((size == 2) ||"); 643 out.println(iii + " (size == 3) ||"); 644 out.println(iii + " (size == 4)) &&"); 645 out.println(iii + " ((type == GL_FLOAT) ||"); 646 out.println(iii + " (type == GL_BYTE) ||"); 647 out.println(iii + " (type == GL_SHORT) ||"); 648 out.println(iii + " (type == GL_FIXED)) &&"); 649 out.println(iii + " (stride >= 0)) {"); 650 out.println(iii + indent + "_weightPointerOES = pointer;"); 651 out.println(iii + "}"); 652 } 653 } 654 655 boolean isVoid = jfunc.getType().isVoid(); 656 657 if (!isVoid) { 658 out.println(indent + indent + "return _returnValue;"); 659 } 660 out.println(indent + "}"); 661 } 662 out.println(); 663 } 664 665 public void addNativeRegistration(String s) { 666 nativeRegistrations.add(s); 667 } 668 669 public void emitNativeRegistration(String registrationFunctionName, 670 PrintStream cStream) { 671 cStream.println("static const char *classPathName = \"" + 672 mClassPathName + 673 "\";"); 674 cStream.println(); 675 676 cStream.println("static JNINativeMethod methods[] = {"); 677 678 cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },"); 679 680 Iterator<String> i = nativeRegistrations.iterator(); 681 while (i.hasNext()) { 682 cStream.println(i.next()); 683 } 684 685 cStream.println("};"); 686 cStream.println(); 687 688 689 cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)"); 690 cStream.println("{"); 691 cStream.println(indent + 692 "int err;"); 693 694 cStream.println(indent + 695 "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));"); 696 697 cStream.println(indent + "return err;"); 698 cStream.println("}"); 699 } 700 701 public JniCodeEmitter() { 702 super(); 703 } 704 705 String getJniType(JType jType) { 706 if (jType.isVoid()) { 707 return "void"; 708 } 709 710 String baseType = jType.getBaseType(); 711 if (jType.isPrimitive()) { 712 if (baseType.equals("String")) { 713 return "jstring"; 714 } else { 715 return "j" + baseType; 716 } 717 } else if (jType.isArray()) { 718 return jType.isClass() ? "jobjectArray" : "j" + baseType + "Array"; 719 } else { 720 return "jobject"; 721 } 722 } 723 724 String getJniMangledName(String name) { 725 name = name.replaceAll("_", "_1"); 726 name = name.replaceAll(";", "_2"); 727 name = name.replaceAll("\\[", "_3"); 728 return name; 729 } 730 731 public void emitJniCode(JFunc jfunc, PrintStream out) { 732 CFunc cfunc = jfunc.getCFunc(); 733 734 // Emit comment identifying original C function 735 // 736 // Example: 737 // 738 // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */ 739 // 740 out.println("/* " + cfunc.getOriginal() + " */"); 741 742 // Emit JNI signature (name) 743 // 744 // Example: 745 // 746 // void 747 // android_glClipPlanef__I_3FI 748 // 749 750 String outName = "android_" + jfunc.getName(); 751 boolean isPointerFunc = isPointerFunc(jfunc); 752 boolean isPointerOffsetFunc = 753 (outName.endsWith("Pointer") || outName.endsWith("PointerOES") || 754 outName.endsWith("glDrawElements") || 755 outName.endsWith("glDrawRangeElements") || 756 outName.endsWith("glTexImage2D") || 757 outName.endsWith("glTexSubImage2D") || 758 outName.endsWith("glCompressedTexImage2D") || 759 outName.endsWith("glCompressedTexSubImage2D") || 760 outName.endsWith("glTexImage3D") || 761 outName.endsWith("glTexSubImage3D") || 762 outName.endsWith("glCompressedTexImage3D") || 763 outName.endsWith("glCompressedTexSubImage3D") || 764 outName.endsWith("glReadPixels")) 765 && !jfunc.getCFunc().hasPointerArg(); 766 if (isPointerFunc) { 767 outName += "Bounds"; 768 } 769 770 out.print("static "); 771 out.println(getJniType(jfunc.getType())); 772 out.print(outName); 773 774 String rsignature = getJniName(jfunc.getType()); 775 776 String signature = ""; 777 int numArgs = jfunc.getNumArgs(); 778 for (int i = 0; i < numArgs; i++) { 779 JType argType = jfunc.getArgType(i); 780 signature += getJniName(argType); 781 } 782 if (isPointerFunc) { 783 signature += "I"; 784 } 785 786 // Append signature to function name 787 String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_'); 788 if (!mUseSimpleMethodNames) { 789 out.print("__" + sig); 790 outName += "__" + sig; 791 } 792 793 signature = signature.replace('.', '/'); 794 rsignature = rsignature.replace('.', '/'); 795 796 out.println(); 797 if (rsignature.length() == 0) { 798 rsignature = "V"; 799 } 800 801 String s = "{\"" + 802 jfunc.getName() + 803 (isPointerFunc ? "Bounds" : "") + 804 "\", \"(" + signature +")" + 805 rsignature + 806 "\", (void *) " + 807 outName + 808 " },"; 809 nativeRegistrations.add(s); 810 811 List<Integer> nonPrimitiveArgs = new ArrayList<Integer>(); 812 List<Integer> stringArgs = new ArrayList<Integer>(); 813 int numBufferArgs = 0; 814 List<String> bufferArgNames = new ArrayList<String>(); 815 816 // Emit JNI signature (arguments) 817 // 818 // Example: 819 // 820 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) { 821 // 822 out.print(" (JNIEnv *_env, jobject _this"); 823 for (int i = 0; i < numArgs; i++) { 824 out.print(", "); 825 JType argType = jfunc.getArgType(i); 826 String suffix = ""; 827 if (!argType.isPrimitive()) { 828 if (argType.isArray()) { 829 suffix = "_ref"; 830 } else if (argType.isBuffer()) { 831 suffix = "_buf"; 832 } 833 nonPrimitiveArgs.add(new Integer(i)); 834 if (jfunc.getArgType(i).isBuffer()) { 835 int cIndex = jfunc.getArgCIndex(i); 836 String cname = cfunc.getArgName(cIndex); 837 bufferArgNames.add(cname); 838 numBufferArgs++; 839 } 840 } 841 842 if (argType.isString()) { 843 stringArgs.add(new Integer(i)); 844 } 845 846 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix); 847 } 848 if (isPointerFunc) { 849 out.print(", jint remaining"); 850 } 851 out.println(") {"); 852 853 int numArrays = 0; 854 int numBuffers = 0; 855 int numStrings = 0; 856 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 857 int idx = nonPrimitiveArgs.get(i).intValue(); 858 JType argType = jfunc.getArgType(idx); 859 if (argType.isArray()) { 860 ++numArrays; 861 } 862 if (argType.isBuffer()) { 863 ++numBuffers; 864 } 865 if (argType.isString()) { 866 ++numStrings; 867 } 868 } 869 870 // Emit method body 871 872 // Emit local variable declarations for _exception and _returnValue 873 // 874 // Example: 875 // 876 // android::gl::ogles_context_t *ctx; 877 // 878 // jint _exception; 879 // GLenum _returnValue; 880 // 881 CType returnType = cfunc.getType(); 882 boolean isVoid = returnType.isVoid(); 883 884 boolean isUnsupported = isUnsupportedFunc(cfunc); 885 if (isUnsupported) { 886 out.println(indent + 887 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 888 out.println(indent + 889 " \"" + cfunc.getName() + "\");"); 890 if (!isVoid) { 891 String retval = getErrorReturnValue(cfunc); 892 if (cfunc.getType().isEGLHandle()) { 893 String baseType = cfunc.getType().getBaseType().toLowerCase(); 894 out.println(indent + 895 "return toEGLHandle(_env, " + baseType + "Class, " + 896 baseType + "Constructor, " + retval + ");"); 897 } else { 898 out.println(indent + "return " + retval + ";"); 899 } 900 } 901 out.println("}"); 902 out.println(); 903 return; 904 } 905 906 String requiresExtension = isRequiresFunc(cfunc); 907 if (requiresExtension != null) { 908 out.println(indent + 909 "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {"); 910 out.println(indent + indent + 911 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 912 out.println(indent + indent + 913 " \"" + cfunc.getName() + "\");"); 914 if (isVoid) { 915 out.println(indent + indent + " return;"); 916 } else { 917 String retval = getErrorReturnValue(cfunc); 918 if (cfunc.getType().isEGLHandle()) { 919 String baseType = cfunc.getType().getBaseType().toLowerCase(); 920 out.println(indent + 921 "return toEGLHandle(_env, " + baseType + "Class, " + 922 baseType + "Constructor, " + retval + ");"); 923 } else { 924 out.println(indent + "return " + retval + ";"); 925 } 926 } 927 out.println(indent + "}"); 928 } 929 if (mUseContextPointer) { 930 out.println(indent + 931 "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); 932 } 933 934 boolean initializeReturnValue = stringArgs.size() > 0; 935 boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0) 936 && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs) 937 || (cfunc.hasPointerArg() && numArrays > 0)) 938 || hasCheckTest(cfunc) 939 || hasIfTest(cfunc)) 940 || (stringArgs.size() > 0); 941 // mChecker.getChecks(cfunc.getName()) != null 942 // Emit an _exeption variable if there will be error checks 943 if (emitExceptionCheck) { 944 out.println(indent + "jint _exception = 0;"); 945 out.println(indent + "const char * _exceptionType = NULL;"); 946 out.println(indent + "const char * _exceptionMessage = NULL;"); 947 } 948 949 // Emit a single _array or multiple _XXXArray variables 950 if (numBufferArgs == 1) { 951 out.println(indent + "jarray _array = (jarray) 0;"); 952 out.println(indent + "jint _bufferOffset = (jint) 0;"); 953 } else { 954 for (int i = 0; i < numBufferArgs; i++) { 955 out.println(indent + "jarray _" + bufferArgNames.get(i) + 956 "Array = (jarray) 0;"); 957 out.println(indent + "jint _" + bufferArgNames.get(i) + 958 "BufferOffset = (jint) 0;"); 959 } 960 } 961 if (!isVoid) { 962 String retval = getErrorReturnValue(cfunc); 963 if (retval != null) { 964 out.println(indent + returnType.getDeclaration() + 965 " _returnValue = " + retval + ";"); 966 } else if (initializeReturnValue) { 967 out.println(indent + returnType.getDeclaration() + 968 " _returnValue = 0;"); 969 } else { 970 out.println(indent + returnType.getDeclaration() + 971 " _returnValue;"); 972 } 973 } 974 975 // Emit local variable declarations for EGL Handles 976 // 977 // Example: 978 // 979 // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface); 980 // 981 if (nonPrimitiveArgs.size() > 0) { 982 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 983 int idx = nonPrimitiveArgs.get(i).intValue(); 984 int cIndex = jfunc.getArgCIndex(idx); 985 String cname = cfunc.getArgName(cIndex); 986 987 if (jfunc.getArgType(idx).isBuffer() 988 || jfunc.getArgType(idx).isArray() 989 || !jfunc.getArgType(idx).isEGLHandle()) 990 continue; 991 992 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 993 String decl = type.getDeclaration(); 994 out.println(indent + 995 decl + " " + cname + "_native = (" + 996 decl + ") fromEGLHandle(_env, " + 997 type.getBaseType().toLowerCase() + 998 "GetHandleID, " + jfunc.getArgName(idx) + 999 ");"); 1000 } 1001 } 1002 1003 // Emit local variable declarations for element/sentinel checks 1004 // 1005 // Example: 1006 // 1007 // bool attrib_list_sentinel_found = false; 1008 // 1009 emitLocalVariablesForSentinel(cfunc, out); 1010 1011 // Emit local variable declarations for pointer arguments 1012 // 1013 // Example: 1014 // 1015 // GLfixed *eqn_base; 1016 // GLfixed *eqn; 1017 // 1018 String offset = "offset"; 1019 String remaining = "_remaining"; 1020 if (nonPrimitiveArgs.size() > 0) { 1021 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1022 int idx = nonPrimitiveArgs.get(i).intValue(); 1023 int cIndex = jfunc.getArgCIndex(idx); 1024 String cname = cfunc.getArgName(cIndex); 1025 1026 if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray()) 1027 continue; 1028 1029 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1030 String decl = type.getDeclaration(); 1031 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1032 out.println(indent + 1033 decl + 1034 (decl.endsWith("*") ? "" : " ") + 1035 jfunc.getArgName(idx) + 1036 "_base = (" + decl + ") 0;"); 1037 } 1038 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1039 "_" + cname + "Remaining"; 1040 out.println(indent + 1041 "jint " + remaining + ";"); 1042 out.println(indent + 1043 decl + 1044 (decl.endsWith("*") ? "" : " ") + 1045 jfunc.getArgName(idx) + 1046 " = (" + decl + ") 0;"); 1047 } 1048 1049 out.println(); 1050 } 1051 1052 // Emit local variable declaration for strings 1053 if (stringArgs.size() > 0) { 1054 for (int i = 0; i < stringArgs.size(); i++) { 1055 int idx = stringArgs.get(i).intValue(); 1056 int cIndex = jfunc.getArgCIndex(idx); 1057 String cname = cfunc.getArgName(cIndex); 1058 1059 out.println(indent + "const char* _native" + cname + " = 0;"); 1060 } 1061 1062 out.println(); 1063 } 1064 1065 // Null pointer checks and GetStringUTFChars 1066 if (stringArgs.size() > 0) { 1067 for (int i = 0; i < stringArgs.size(); i++) { 1068 int idx = stringArgs.get(i).intValue(); 1069 int cIndex = jfunc.getArgCIndex(idx); 1070 String cname = cfunc.getArgName(cIndex); 1071 1072 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1073 String decl = type.getDeclaration(); 1074 needsExit = true; 1075 out.println(indent + "if (!" + cname + ") {"); 1076 out.println(indent + indent + 1077 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1078 out.println(indent + indent + 1079 "_exceptionMessage = \"" + cname + " == null\";"); 1080 out.println(indent + indent + "goto exit;"); 1081 out.println(indent + "}"); 1082 1083 out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);"); 1084 } 1085 1086 out.println(); 1087 } 1088 1089 // Emit 'GetPrimitiveArrayCritical' for non-object arrays 1090 // Emit 'GetPointer' calls for Buffer pointers 1091 if (nonPrimitiveArgs.size() > 0) { 1092 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1093 int idx = nonPrimitiveArgs.get(i).intValue(); 1094 int cIndex = jfunc.getArgCIndex(idx); 1095 1096 String cname = cfunc.getArgName(cIndex); 1097 offset = numArrays <= 1 ? "offset" : 1098 cname + "Offset"; 1099 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1100 "_" + cname + "Remaining"; 1101 1102 if (jfunc.getArgType(idx).isArray() 1103 && !jfunc.getArgType(idx).isEGLHandle()) { 1104 needsExit = true; 1105 out.println(indent + "if (!" + cname + "_ref) {"); 1106 out.println(indent + indent + "_exception = 1;"); 1107 out.println(indent + indent + 1108 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1109 out.println(indent + indent + 1110 "_exceptionMessage = \"" + cname +" == null\";"); 1111 out.println(indent + indent + "goto exit;"); 1112 out.println(indent + "}"); 1113 out.println(indent + "if (" + offset + " < 0) {"); 1114 out.println(indent + indent + "_exception = 1;"); 1115 out.println(indent + indent + 1116 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1117 out.println(indent + indent + 1118 "_exceptionMessage = \"" + offset +" < 0\";"); 1119 out.println(indent + indent + "goto exit;"); 1120 out.println(indent + "}"); 1121 1122 out.println(indent + remaining + " = " + 1123 (mUseCPlusPlus ? "_env" : "(*_env)") + 1124 "->GetArrayLength(" + 1125 (mUseCPlusPlus ? "" : "_env, ") + 1126 cname + "_ref) - " + offset + ";"); 1127 1128 emitNativeBoundsChecks(cfunc, cname, out, false, 1129 emitExceptionCheck, 1130 offset, remaining, " "); 1131 1132 out.println(indent + 1133 cname + 1134 "_base = (" + 1135 cfunc.getArgType(cIndex).getDeclaration() + 1136 ")"); 1137 out.println(indent + " " + 1138 (mUseCPlusPlus ? "_env" : "(*_env)") + 1139 "->GetPrimitiveArrayCritical(" + 1140 (mUseCPlusPlus ? "" : "_env, ") + 1141 jfunc.getArgName(idx) + 1142 "_ref, (jboolean *)0);"); 1143 out.println(indent + 1144 cname + " = " + cname + "_base + " + offset + ";"); 1145 1146 emitSentinelCheck(cfunc, cname, out, false, 1147 emitExceptionCheck, offset, 1148 remaining, indent); 1149 out.println(); 1150 } else if (jfunc.getArgType(idx).isArray() 1151 && jfunc.getArgType(idx).isEGLHandle()) { 1152 needsExit = true; 1153 out.println(indent + "if (!" + cname + "_ref) {"); 1154 out.println(indent + indent + "_exception = 1;"); 1155 out.println(indent + indent + 1156 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1157 out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";"); 1158 out.println(indent + indent + "goto exit;"); 1159 out.println(indent + "}"); 1160 out.println(indent + "if (" + offset + " < 0) {"); 1161 out.println(indent + indent + "_exception = 1;"); 1162 out.println(indent + indent + 1163 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1164 out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";"); 1165 out.println(indent + indent + "goto exit;"); 1166 out.println(indent + "}"); 1167 1168 out.println(indent + remaining + " = " + 1169 (mUseCPlusPlus ? "_env" : "(*_env)") + 1170 "->GetArrayLength(" + 1171 (mUseCPlusPlus ? "" : "_env, ") + 1172 cname + "_ref) - " + offset + ";"); 1173 emitNativeBoundsChecks(cfunc, cname, out, false, 1174 emitExceptionCheck, 1175 offset, remaining, " "); 1176 out.println(indent + 1177 jfunc.getArgName(idx) + " = new " + 1178 cfunc.getArgType(cIndex).getBaseType() + 1179 "["+ remaining + "];"); 1180 out.println(); 1181 } else if (jfunc.getArgType(idx).isBuffer()) { 1182 String array = numBufferArgs <= 1 ? "_array" : 1183 "_" + cfunc.getArgName(cIndex) + "Array"; 1184 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1185 "_" + cfunc.getArgName(cIndex) + "BufferOffset"; 1186 1187 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1188 if (nullAllowed) { 1189 out.println(indent + "if (" + cname + "_buf) {"); 1190 out.print(indent); 1191 } 1192 1193 if (isPointerFunc) { 1194 out.println(indent + 1195 cname + 1196 " = (" + 1197 cfunc.getArgType(cIndex).getDeclaration() + 1198 ") getDirectBufferPointer(_env, " + 1199 cname + "_buf);"); 1200 String iii = " "; 1201 out.println(iii + indent + "if ( ! " + cname + " ) {"); 1202 out.println(iii + indent + indent + "return;"); 1203 out.println(iii + indent + "}"); 1204 } else { 1205 out.println(indent + 1206 cname + 1207 " = (" + 1208 cfunc.getArgType(cIndex).getDeclaration() + 1209 ")getPointer(_env, " + 1210 cname + 1211 "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset + 1212 ");"); 1213 } 1214 1215 emitNativeBoundsChecks(cfunc, cname, out, true, 1216 emitExceptionCheck, 1217 offset, remaining, nullAllowed ? " " : " "); 1218 1219 if (nullAllowed) { 1220 out.println(indent + "}"); 1221 } 1222 } 1223 } 1224 } 1225 1226 // Emit 'GetPrimitiveArrayCritical' for pointers if needed 1227 if (nonPrimitiveArgs.size() > 0) { 1228 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1229 int idx = nonPrimitiveArgs.get(i).intValue(); 1230 int cIndex = jfunc.getArgCIndex(idx); 1231 1232 if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue; 1233 1234 String cname = cfunc.getArgName(cIndex); 1235 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1236 "_" + cname + "BufferOffset"; 1237 String array = numBufferArgs <= 1 ? "_array" : 1238 "_" + cfunc.getArgName(cIndex) + "Array"; 1239 1240 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1241 if (nullAllowed) { 1242 out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {"); 1243 } else { 1244 out.println(indent + "if (" + cname +" == NULL) {"); 1245 } 1246 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); 1247 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); 1248 out.println(indent + "}"); 1249 } 1250 } 1251 1252 1253 if (!isVoid) { 1254 out.print(indent + "_returnValue = "); 1255 } else { 1256 out.print(indent); 1257 } 1258 String name = cfunc.getName(); 1259 1260 if (mUseContextPointer) { 1261 name = name.substring(2, name.length()); // Strip off 'gl' prefix 1262 name = name.substring(0, 1).toLowerCase() + 1263 name.substring(1, name.length()); 1264 out.print("ctx->procs."); 1265 } 1266 1267 out.print(name + (isPointerFunc ? "Bounds" : "") + "("); 1268 1269 numArgs = cfunc.getNumArgs(); 1270 if (numArgs == 0) { 1271 if (mUseContextPointer) { 1272 out.println("ctx);"); 1273 } else { 1274 out.println(");"); 1275 } 1276 } else { 1277 if (mUseContextPointer) { 1278 out.println("ctx,"); 1279 } else { 1280 out.println(); 1281 } 1282 for (int i = 0; i < numArgs; i++) { 1283 String typecast; 1284 if (i == numArgs - 1 && isPointerOffsetFunc) { 1285 typecast = "(GLvoid *)"; 1286 } else { 1287 typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; 1288 } 1289 out.print(indent + indent + 1290 typecast); 1291 1292 if (cfunc.getArgType(i).isConstCharPointer()) { 1293 out.print("_native"); 1294 } 1295 1296 if (cfunc.getArgType(i).isEGLHandle() && 1297 !cfunc.getArgType(i).isPointer()){ 1298 out.print(cfunc.getArgName(i)+"_native"); 1299 } else { 1300 out.print(cfunc.getArgName(i)); 1301 } 1302 1303 if (i == numArgs - 1) { 1304 if (isPointerFunc) { 1305 out.println(","); 1306 out.println(indent + indent + "(GLsizei)remaining"); 1307 } else { 1308 out.println(); 1309 } 1310 } else { 1311 out.println(","); 1312 } 1313 } 1314 out.println(indent + ");"); 1315 } 1316 1317 if (needsExit) { 1318 out.println(); 1319 out.println("exit:"); 1320 needsExit = false; 1321 } 1322 1323 1324 if (nonPrimitiveArgs.size() > 0) { 1325 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1326 int idx = nonPrimitiveArgs.get(i).intValue(); 1327 1328 int cIndex = jfunc.getArgCIndex(idx); 1329 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1330 1331 // If the argument is 'const', GL will not write to it. 1332 // In this case, we can use the 'JNI_ABORT' flag to avoid 1333 // the need to write back to the Java array 1334 out.println(indent + 1335 "if (" + jfunc.getArgName(idx) + "_base) {"); 1336 out.println(indent + indent + 1337 (mUseCPlusPlus ? "_env" : "(*_env)") + 1338 "->ReleasePrimitiveArrayCritical(" + 1339 (mUseCPlusPlus ? "" : "_env, ") + 1340 jfunc.getArgName(idx) + "_ref, " + 1341 cfunc.getArgName(cIndex) + 1342 "_base,"); 1343 out.println(indent + indent + indent + 1344 (cfunc.getArgType(cIndex).isConst() ? 1345 "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + 1346 ");"); 1347 out.println(indent + "}"); 1348 } else if (jfunc.getArgType(idx).isBuffer()) { 1349 if (! isPointerFunc) { 1350 String array = numBufferArgs <= 1 ? "_array" : 1351 "_" + cfunc.getArgName(cIndex) + "Array"; 1352 out.println(indent + "if (" + array + ") {"); 1353 out.println(indent + indent + 1354 "releasePointer(_env, " + array + ", " + 1355 cfunc.getArgName(cIndex) + 1356 ", " + 1357 (cfunc.getArgType(cIndex).isConst() ? 1358 "JNI_FALSE" : (emitExceptionCheck ? 1359 "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + 1360 ");"); 1361 out.println(indent + "}"); 1362 } 1363 } 1364 } 1365 } 1366 1367 // Emit local variable declaration for strings 1368 if (stringArgs.size() > 0) { 1369 for (int i = 0; i < stringArgs.size(); i++) { 1370 int idx = stringArgs.get(i).intValue(); 1371 int cIndex = jfunc.getArgCIndex(idx); 1372 String cname = cfunc.getArgName(cIndex); 1373 1374 out.println(indent + "if (_native" + cname + ") {"); 1375 out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");"); 1376 out.println(indent + "}"); 1377 } 1378 1379 out.println(); 1380 } 1381 1382 // Copy results back to java arrays 1383 if (nonPrimitiveArgs.size() > 0) { 1384 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1385 int idx = nonPrimitiveArgs.get(i).intValue(); 1386 int cIndex = jfunc.getArgCIndex(idx); 1387 String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); 1388 if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { 1389 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1390 "_" + cfunc.getArgName(cIndex) + "Remaining"; 1391 offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; 1392 out.println(indent + 1393 "if (" + jfunc.getArgName(idx) + ") {"); 1394 out.println(indent + indent + 1395 "for (int i = 0; i < " + remaining + "; i++) {"); 1396 out.println(indent + indent + indent + 1397 "jobject " + cfunc.getArgName(cIndex) + 1398 "_new = toEGLHandle(_env, " + baseType + 1399 "Class, " + baseType + "Constructor, " + 1400 cfunc.getArgName(cIndex) + "[i]);"); 1401 out.println(indent + indent + indent + 1402 (mUseCPlusPlus ? "_env" : "(*_env)") + 1403 "->SetObjectArrayElement(" + 1404 (mUseCPlusPlus ? "" : "_env, ") + 1405 cfunc.getArgName(cIndex) + 1406 "_ref, i + " + offset + ", " + 1407 cfunc.getArgName(cIndex) + "_new);"); 1408 out.println(indent + indent + "}"); 1409 out.println(indent + indent + 1410 "delete[] " + jfunc.getArgName(idx) + ";"); 1411 out.println(indent + "}"); 1412 } 1413 } 1414 } 1415 1416 1417 // Throw exception if there is one 1418 if (emitExceptionCheck) { 1419 out.println(indent + "if (_exception) {"); 1420 out.println(indent + indent + 1421 "jniThrowException(_env, _exceptionType, _exceptionMessage);"); 1422 out.println(indent + "}"); 1423 1424 } 1425 1426 1427 if (!isVoid) { 1428 if (cfunc.getType().isEGLHandle()) { 1429 String baseType = cfunc.getType().getBaseType().toLowerCase(); 1430 out.println(indent + 1431 "return toEGLHandle(_env, " + baseType + "Class, " + 1432 baseType + "Constructor, _returnValue);"); 1433 } else { 1434 out.println(indent + "return (" + 1435 getJniType(jfunc.getType()) + ")_returnValue;"); 1436 } 1437 } 1438 1439 out.println("}"); 1440 out.println(); 1441 } 1442 1443 } 1444