JniCodeEmitter.java revision 66a42db8cbfba902f72f0ace5ac448ef4bfd3951
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 17import java.io.PrintStream; 18import java.util.ArrayList; 19import java.util.HashSet; 20import java.util.Iterator; 21import java.util.List; 22 23public 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 += "L"; 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 = 0;"); 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 isVBOPointerFunc = (outName.endsWith("Pointer") || 753 outName.endsWith("PointerOES") || 754 outName.endsWith("DrawElements") || outName.endsWith("VertexAttribPointer")) && 755 !jfunc.getCFunc().hasPointerArg(); 756 if (isPointerFunc) { 757 outName += "Bounds"; 758 } 759 760 out.print("static "); 761 out.println(getJniType(jfunc.getType())); 762 out.print(outName); 763 764 String rsignature = getJniName(jfunc.getType()); 765 766 String signature = ""; 767 int numArgs = jfunc.getNumArgs(); 768 for (int i = 0; i < numArgs; i++) { 769 JType argType = jfunc.getArgType(i); 770 signature += getJniName(argType); 771 } 772 if (isPointerFunc) { 773 signature += "I"; 774 } 775 776 // Append signature to function name 777 String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_'); 778 if (!mUseSimpleMethodNames) { 779 out.print("__" + sig); 780 outName += "__" + sig; 781 } 782 783 signature = signature.replace('.', '/'); 784 rsignature = rsignature.replace('.', '/'); 785 786 out.println(); 787 if (rsignature.length() == 0) { 788 rsignature = "V"; 789 } 790 791 String s = "{\"" + 792 jfunc.getName() + 793 (isPointerFunc ? "Bounds" : "") + 794 "\", \"(" + signature +")" + 795 rsignature + 796 "\", (void *) " + 797 outName + 798 " },"; 799 nativeRegistrations.add(s); 800 801 List<Integer> nonPrimitiveArgs = new ArrayList<Integer>(); 802 List<Integer> stringArgs = new ArrayList<Integer>(); 803 int numBufferArgs = 0; 804 List<String> bufferArgNames = new ArrayList<String>(); 805 806 // Emit JNI signature (arguments) 807 // 808 // Example: 809 // 810 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) { 811 // 812 out.print(" (JNIEnv *_env, jobject _this"); 813 for (int i = 0; i < numArgs; i++) { 814 out.print(", "); 815 JType argType = jfunc.getArgType(i); 816 String suffix = ""; 817 if (!argType.isPrimitive()) { 818 if (argType.isArray()) { 819 suffix = "_ref"; 820 } else if (argType.isBuffer()) { 821 suffix = "_buf"; 822 } 823 nonPrimitiveArgs.add(new Integer(i)); 824 if (jfunc.getArgType(i).isBuffer()) { 825 int cIndex = jfunc.getArgCIndex(i); 826 String cname = cfunc.getArgName(cIndex); 827 bufferArgNames.add(cname); 828 numBufferArgs++; 829 } 830 } 831 832 if (argType.isString()) { 833 stringArgs.add(new Integer(i)); 834 } 835 836 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix); 837 } 838 if (isPointerFunc) { 839 out.print(", jint remaining"); 840 } 841 out.println(") {"); 842 843 int numArrays = 0; 844 int numBuffers = 0; 845 int numStrings = 0; 846 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 847 int idx = nonPrimitiveArgs.get(i).intValue(); 848 JType argType = jfunc.getArgType(idx); 849 if (argType.isArray()) { 850 ++numArrays; 851 } 852 if (argType.isBuffer()) { 853 ++numBuffers; 854 } 855 if (argType.isString()) { 856 ++numStrings; 857 } 858 } 859 860 // Emit method body 861 862 // Emit local variable declarations for _exception and _returnValue 863 // 864 // Example: 865 // 866 // android::gl::ogles_context_t *ctx; 867 // 868 // jint _exception; 869 // GLenum _returnValue; 870 // 871 CType returnType = cfunc.getType(); 872 boolean isVoid = returnType.isVoid(); 873 874 boolean isUnsupported = isUnsupportedFunc(cfunc); 875 if (isUnsupported) { 876 out.println(indent + 877 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 878 out.println(indent + 879 " \"" + cfunc.getName() + "\");"); 880 if (!isVoid) { 881 String retval = getErrorReturnValue(cfunc); 882 if (cfunc.getType().isEGLHandle()) { 883 String baseType = cfunc.getType().getBaseType().toLowerCase(); 884 out.println(indent + 885 "return toEGLHandle(_env, " + baseType + "Class, " + 886 baseType + "Constructor, " + retval + ");"); 887 } else { 888 out.println(indent + "return " + retval + ";"); 889 } 890 } 891 out.println("}"); 892 out.println(); 893 return; 894 } 895 896 String requiresExtension = isRequiresFunc(cfunc); 897 if (requiresExtension != null) { 898 out.println(indent + 899 "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {"); 900 out.println(indent + indent + 901 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 902 out.println(indent + indent + 903 " \"" + cfunc.getName() + "\");"); 904 if (isVoid) { 905 out.println(indent + indent + " return;"); 906 } else { 907 String retval = getErrorReturnValue(cfunc); 908 if (cfunc.getType().isEGLHandle()) { 909 String baseType = cfunc.getType().getBaseType().toLowerCase(); 910 out.println(indent + 911 "return toEGLHandle(_env, " + baseType + "Class, " + 912 baseType + "Constructor, " + retval + ");"); 913 } else { 914 out.println(indent + "return " + retval + ";"); 915 } 916 } 917 out.println(indent + "}"); 918 } 919 if (mUseContextPointer) { 920 out.println(indent + 921 "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); 922 } 923 924 boolean initializeReturnValue = stringArgs.size() > 0; 925 boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0) 926 && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs) 927 || (cfunc.hasPointerArg() && numArrays > 0)) 928 || hasCheckTest(cfunc) 929 || hasIfTest(cfunc)) 930 || (stringArgs.size() > 0); 931 // mChecker.getChecks(cfunc.getName()) != null 932 // Emit an _exeption variable if there will be error checks 933 if (emitExceptionCheck) { 934 out.println(indent + "jint _exception = 0;"); 935 out.println(indent + "const char * _exceptionType;"); 936 out.println(indent + "const char * _exceptionMessage;"); 937 } 938 939 // Emit a single _array or multiple _XXXArray variables 940 if (numBufferArgs == 1) { 941 out.println(indent + "jarray _array = (jarray) 0;"); 942 } else { 943 for (int i = 0; i < numBufferArgs; i++) { 944 out.println(indent + "jarray _" + bufferArgNames.get(i) + 945 "Array = (jarray) 0;"); 946 } 947 } 948 if (!isVoid) { 949 String retval = getErrorReturnValue(cfunc); 950 if (retval != null) { 951 out.println(indent + returnType.getDeclaration() + 952 " _returnValue = " + retval + ";"); 953 } else if (initializeReturnValue) { 954 out.println(indent + returnType.getDeclaration() + 955 " _returnValue = 0;"); 956 } else { 957 out.println(indent + returnType.getDeclaration() + 958 " _returnValue;"); 959 } 960 } 961 962 // Emit local variable declarations for EGL Handles 963 // 964 // Example: 965 // 966 // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface); 967 // 968 if (nonPrimitiveArgs.size() > 0) { 969 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 970 int idx = nonPrimitiveArgs.get(i).intValue(); 971 int cIndex = jfunc.getArgCIndex(idx); 972 String cname = cfunc.getArgName(cIndex); 973 974 if (jfunc.getArgType(idx).isBuffer() 975 || jfunc.getArgType(idx).isArray() 976 || !jfunc.getArgType(idx).isEGLHandle()) 977 continue; 978 979 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 980 String decl = type.getDeclaration(); 981 out.println(indent + 982 decl + " " + cname + "_native = (" + 983 decl + ") fromEGLHandle(_env, " + 984 type.getBaseType().toLowerCase() + 985 "GetHandleID, " + jfunc.getArgName(idx) + 986 ");"); 987 } 988 } 989 990 // Emit local variable declarations for element/sentinel checks 991 // 992 // Example: 993 // 994 // bool attrib_list_sentinel_found = false; 995 // 996 emitLocalVariablesForSentinel(cfunc, out); 997 998 // Emit local variable declarations for pointer arguments 999 // 1000 // Example: 1001 // 1002 // GLfixed *eqn_base; 1003 // GLfixed *eqn; 1004 // 1005 String offset = "offset"; 1006 String remaining = "_remaining"; 1007 if (nonPrimitiveArgs.size() > 0) { 1008 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1009 int idx = nonPrimitiveArgs.get(i).intValue(); 1010 int cIndex = jfunc.getArgCIndex(idx); 1011 String cname = cfunc.getArgName(cIndex); 1012 1013 if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray()) 1014 continue; 1015 1016 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1017 String decl = type.getDeclaration(); 1018 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1019 out.println(indent + 1020 decl + 1021 (decl.endsWith("*") ? "" : " ") + 1022 jfunc.getArgName(idx) + 1023 "_base = (" + decl + ") 0;"); 1024 } 1025 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1026 "_" + cname + "Remaining"; 1027 out.println(indent + 1028 "jint " + remaining + ";"); 1029 out.println(indent + 1030 decl + 1031 (decl.endsWith("*") ? "" : " ") + 1032 jfunc.getArgName(idx) + 1033 " = (" + decl + ") 0;"); 1034 } 1035 1036 out.println(); 1037 } 1038 1039 // Emit local variable declaration for strings 1040 if (stringArgs.size() > 0) { 1041 for (int i = 0; i < stringArgs.size(); i++) { 1042 int idx = stringArgs.get(i).intValue(); 1043 int cIndex = jfunc.getArgCIndex(idx); 1044 String cname = cfunc.getArgName(cIndex); 1045 1046 out.println(indent + "const char* _native" + cname + " = 0;"); 1047 } 1048 1049 out.println(); 1050 } 1051 1052 // Null pointer checks and GetStringUTFChars 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 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1060 String decl = type.getDeclaration(); 1061 needsExit = true; 1062 out.println(indent + "if (!" + cname + ") {"); 1063 out.println(indent + indent + 1064 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1065 out.println(indent + indent + 1066 "_exceptionMessage = \"" + cname + " == null\";"); 1067 out.println(indent + indent + "goto exit;"); 1068 out.println(indent + "}"); 1069 1070 out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);"); 1071 } 1072 1073 out.println(); 1074 } 1075 1076 // Emit 'GetPrimitiveArrayCritical' for non-object arrays 1077 // Emit 'GetPointer' calls for Buffer pointers 1078 int bufArgIdx = 0; 1079 if (nonPrimitiveArgs.size() > 0) { 1080 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1081 int idx = nonPrimitiveArgs.get(i).intValue(); 1082 int cIndex = jfunc.getArgCIndex(idx); 1083 1084 String cname = cfunc.getArgName(cIndex); 1085 offset = numArrays <= 1 ? "offset" : 1086 cname + "Offset"; 1087 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1088 "_" + cname + "Remaining"; 1089 1090 if (jfunc.getArgType(idx).isArray() 1091 && !jfunc.getArgType(idx).isEGLHandle()) { 1092 needsExit = true; 1093 out.println(indent + "if (!" + cname + "_ref) {"); 1094 out.println(indent + indent + "_exception = 1;"); 1095 out.println(indent + indent + 1096 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1097 out.println(indent + indent + 1098 "_exceptionMessage = \"" + cname +" == null\";"); 1099 out.println(indent + indent + "goto exit;"); 1100 out.println(indent + "}"); 1101 out.println(indent + "if (" + offset + " < 0) {"); 1102 out.println(indent + indent + "_exception = 1;"); 1103 out.println(indent + indent + 1104 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1105 out.println(indent + indent + 1106 "_exceptionMessage = \"" + offset +" < 0\";"); 1107 out.println(indent + indent + "goto exit;"); 1108 out.println(indent + "}"); 1109 1110 out.println(indent + remaining + " = " + 1111 (mUseCPlusPlus ? "_env" : "(*_env)") + 1112 "->GetArrayLength(" + 1113 (mUseCPlusPlus ? "" : "_env, ") + 1114 cname + "_ref) - " + offset + ";"); 1115 1116 emitNativeBoundsChecks(cfunc, cname, out, false, 1117 emitExceptionCheck, 1118 offset, remaining, " "); 1119 1120 out.println(indent + 1121 cname + 1122 "_base = (" + 1123 cfunc.getArgType(cIndex).getDeclaration() + 1124 ")"); 1125 out.println(indent + " " + 1126 (mUseCPlusPlus ? "_env" : "(*_env)") + 1127 "->GetPrimitiveArrayCritical(" + 1128 (mUseCPlusPlus ? "" : "_env, ") + 1129 jfunc.getArgName(idx) + 1130 "_ref, (jboolean *)0);"); 1131 out.println(indent + 1132 cname + " = " + cname + "_base + " + offset + ";"); 1133 1134 emitSentinelCheck(cfunc, cname, out, false, 1135 emitExceptionCheck, offset, 1136 remaining, indent); 1137 out.println(); 1138 } else if (jfunc.getArgType(idx).isArray() 1139 && jfunc.getArgType(idx).isEGLHandle()) { 1140 needsExit = true; 1141 out.println(indent + "if (!" + cname + "_ref) {"); 1142 out.println(indent + indent + "_exception = 1;"); 1143 out.println(indent + indent + 1144 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1145 out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";"); 1146 out.println(indent + indent + "goto exit;"); 1147 out.println(indent + "}"); 1148 out.println(indent + "if (" + offset + " < 0) {"); 1149 out.println(indent + indent + "_exception = 1;"); 1150 out.println(indent + indent + 1151 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1152 out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";"); 1153 out.println(indent + indent + "goto exit;"); 1154 out.println(indent + "}"); 1155 1156 out.println(indent + remaining + " = " + 1157 (mUseCPlusPlus ? "_env" : "(*_env)") + 1158 "->GetArrayLength(" + 1159 (mUseCPlusPlus ? "" : "_env, ") + 1160 cname + "_ref) - " + offset + ";"); 1161 emitNativeBoundsChecks(cfunc, cname, out, false, 1162 emitExceptionCheck, 1163 offset, remaining, " "); 1164 out.println(indent + 1165 jfunc.getArgName(idx) + " = new " + 1166 cfunc.getArgType(cIndex).getBaseType() + 1167 "["+ remaining + "];"); 1168 out.println(); 1169 } else if (jfunc.getArgType(idx).isBuffer()) { 1170 String array = numBufferArgs <= 1 ? "_array" : 1171 "_" + bufferArgNames.get(bufArgIdx++) + "Array"; 1172 1173 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1174 if (nullAllowed) { 1175 out.println(indent + "if (" + cname + "_buf) {"); 1176 out.print(indent); 1177 } 1178 1179 if (isPointerFunc) { 1180 out.println(indent + 1181 cname + 1182 " = (" + 1183 cfunc.getArgType(cIndex).getDeclaration() + 1184 ") getDirectBufferPointer(_env, " + 1185 cname + "_buf);"); 1186 String iii = " "; 1187 out.println(iii + indent + "if ( ! " + cname + " ) {"); 1188 out.println(iii + indent + indent + "return;"); 1189 out.println(iii + indent + "}"); 1190 } else { 1191 out.println(indent + 1192 cname + 1193 " = (" + 1194 cfunc.getArgType(cIndex).getDeclaration() + 1195 ")getPointer(_env, " + 1196 cname + 1197 "_buf, &" + array + ", &" + remaining + 1198 ");"); 1199 } 1200 1201 emitNativeBoundsChecks(cfunc, cname, out, true, 1202 emitExceptionCheck, 1203 offset, remaining, nullAllowed ? " " : " "); 1204 1205 if (nullAllowed) { 1206 out.println(indent + "}"); 1207 } 1208 } 1209 } 1210 } 1211 1212 if (!isVoid) { 1213 out.print(indent + "_returnValue = "); 1214 } else { 1215 out.print(indent); 1216 } 1217 String name = cfunc.getName(); 1218 1219 if (mUseContextPointer) { 1220 name = name.substring(2, name.length()); // Strip off 'gl' prefix 1221 name = name.substring(0, 1).toLowerCase() + 1222 name.substring(1, name.length()); 1223 out.print("ctx->procs."); 1224 } 1225 1226 out.print(name + (isPointerFunc ? "Bounds" : "") + "("); 1227 1228 numArgs = cfunc.getNumArgs(); 1229 if (numArgs == 0) { 1230 if (mUseContextPointer) { 1231 out.println("ctx);"); 1232 } else { 1233 out.println(");"); 1234 } 1235 } else { 1236 if (mUseContextPointer) { 1237 out.println("ctx,"); 1238 } else { 1239 out.println(); 1240 } 1241 for (int i = 0; i < numArgs; i++) { 1242 String typecast; 1243 if (i == numArgs - 1 && isVBOPointerFunc) { 1244 typecast = "(const GLvoid *)"; 1245 } else { 1246 typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; 1247 } 1248 out.print(indent + indent + 1249 typecast); 1250 1251 if (cfunc.getArgType(i).isConstCharPointer()) { 1252 out.print("_native"); 1253 } 1254 1255 if (cfunc.getArgType(i).isEGLHandle() && 1256 !cfunc.getArgType(i).isPointer()){ 1257 out.print(cfunc.getArgName(i)+"_native"); 1258 } else { 1259 out.print(cfunc.getArgName(i)); 1260 } 1261 1262 if (i == numArgs - 1) { 1263 if (isPointerFunc) { 1264 out.println(","); 1265 out.println(indent + indent + "(GLsizei)remaining"); 1266 } else { 1267 out.println(); 1268 } 1269 } else { 1270 out.println(","); 1271 } 1272 } 1273 out.println(indent + ");"); 1274 } 1275 1276 if (needsExit) { 1277 out.println(); 1278 out.println("exit:"); 1279 needsExit = false; 1280 } 1281 1282 bufArgIdx = 0; 1283 if (nonPrimitiveArgs.size() > 0) { 1284 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1285 int idx = nonPrimitiveArgs.get(i).intValue(); 1286 1287 int cIndex = jfunc.getArgCIndex(idx); 1288 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1289 1290 // If the argument is 'const', GL will not write to it. 1291 // In this case, we can use the 'JNI_ABORT' flag to avoid 1292 // the need to write back to the Java array 1293 out.println(indent + 1294 "if (" + jfunc.getArgName(idx) + "_base) {"); 1295 out.println(indent + indent + 1296 (mUseCPlusPlus ? "_env" : "(*_env)") + 1297 "->ReleasePrimitiveArrayCritical(" + 1298 (mUseCPlusPlus ? "" : "_env, ") + 1299 jfunc.getArgName(idx) + "_ref, " + 1300 cfunc.getArgName(cIndex) + 1301 "_base,"); 1302 out.println(indent + indent + indent + 1303 (cfunc.getArgType(cIndex).isConst() ? 1304 "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + 1305 ");"); 1306 out.println(indent + "}"); 1307 } else if (jfunc.getArgType(idx).isBuffer()) { 1308 if (! isPointerFunc) { 1309 String array = numBufferArgs <= 1 ? "_array" : 1310 "_" + bufferArgNames.get(bufArgIdx++) + "Array"; 1311 out.println(indent + "if (" + array + ") {"); 1312 out.println(indent + indent + 1313 "releasePointer(_env, " + array + ", " + 1314 cfunc.getArgName(cIndex) + 1315 ", " + 1316 (cfunc.getArgType(cIndex).isConst() ? 1317 "JNI_FALSE" : (emitExceptionCheck ? 1318 "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + 1319 ");"); 1320 out.println(indent + "}"); 1321 } 1322 } 1323 } 1324 } 1325 1326 // Emit local variable declaration for strings 1327 if (stringArgs.size() > 0) { 1328 for (int i = 0; i < stringArgs.size(); i++) { 1329 int idx = stringArgs.get(i).intValue(); 1330 int cIndex = jfunc.getArgCIndex(idx); 1331 String cname = cfunc.getArgName(cIndex); 1332 1333 out.println(indent + "if (_native" + cname + ") {"); 1334 out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");"); 1335 out.println(indent + "}"); 1336 } 1337 1338 out.println(); 1339 } 1340 1341 // Copy results back to java arrays 1342 if (nonPrimitiveArgs.size() > 0) { 1343 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1344 int idx = nonPrimitiveArgs.get(i).intValue(); 1345 int cIndex = jfunc.getArgCIndex(idx); 1346 String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); 1347 if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { 1348 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1349 "_" + cfunc.getArgName(cIndex) + "Remaining"; 1350 offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; 1351 out.println(indent + 1352 "if (" + jfunc.getArgName(idx) + ") {"); 1353 out.println(indent + indent + 1354 "for (int i = 0; i < " + remaining + "; i++) {"); 1355 out.println(indent + indent + indent + 1356 "jobject " + cfunc.getArgName(cIndex) + 1357 "_new = toEGLHandle(_env, " + baseType + 1358 "Class, " + baseType + "Constructor, " + 1359 cfunc.getArgName(cIndex) + "[i]);"); 1360 out.println(indent + indent + indent + 1361 (mUseCPlusPlus ? "_env" : "(*_env)") + 1362 "->SetObjectArrayElement(" + 1363 (mUseCPlusPlus ? "" : "_env, ") + 1364 cfunc.getArgName(cIndex) + 1365 "_ref, i + " + offset + ", " + 1366 cfunc.getArgName(cIndex) + "_new);"); 1367 out.println(indent + indent + "}"); 1368 out.println(indent + indent + 1369 "delete[] " + jfunc.getArgName(idx) + ";"); 1370 out.println(indent + "}"); 1371 } 1372 } 1373 } 1374 1375 1376 // Throw exception if there is one 1377 if (emitExceptionCheck) { 1378 out.println(indent + "if (_exception) {"); 1379 out.println(indent + indent + 1380 "jniThrowException(_env, _exceptionType, _exceptionMessage);"); 1381 out.println(indent + "}"); 1382 1383 } 1384 1385 1386 if (!isVoid) { 1387 if (cfunc.getType().isEGLHandle()) { 1388 String baseType = cfunc.getType().getBaseType().toLowerCase(); 1389 out.println(indent + 1390 "return toEGLHandle(_env, " + baseType + "Class, " + 1391 baseType + "Constructor, _returnValue);"); 1392 } else { 1393 out.println(indent + "return _returnValue;"); 1394 } 1395 } 1396 1397 out.println("}"); 1398 out.println(); 1399 } 1400 1401} 1402