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 += "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 out.println(indent + "jint _bufferOffset = (jint) 0;"); 943 } else { 944 for (int i = 0; i < numBufferArgs; i++) { 945 out.println(indent + "jarray _" + bufferArgNames.get(i) + 946 "Array = (jarray) 0;"); 947 out.println(indent + "jint _" + bufferArgNames.get(i) + 948 "BufferOffset = (jint) 0;"); 949 } 950 } 951 if (!isVoid) { 952 String retval = getErrorReturnValue(cfunc); 953 if (retval != null) { 954 out.println(indent + returnType.getDeclaration() + 955 " _returnValue = " + retval + ";"); 956 } else if (initializeReturnValue) { 957 out.println(indent + returnType.getDeclaration() + 958 " _returnValue = 0;"); 959 } else { 960 out.println(indent + returnType.getDeclaration() + 961 " _returnValue;"); 962 } 963 } 964 965 // Emit local variable declarations for EGL Handles 966 // 967 // Example: 968 // 969 // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface); 970 // 971 if (nonPrimitiveArgs.size() > 0) { 972 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 973 int idx = nonPrimitiveArgs.get(i).intValue(); 974 int cIndex = jfunc.getArgCIndex(idx); 975 String cname = cfunc.getArgName(cIndex); 976 977 if (jfunc.getArgType(idx).isBuffer() 978 || jfunc.getArgType(idx).isArray() 979 || !jfunc.getArgType(idx).isEGLHandle()) 980 continue; 981 982 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 983 String decl = type.getDeclaration(); 984 out.println(indent + 985 decl + " " + cname + "_native = (" + 986 decl + ") fromEGLHandle(_env, " + 987 type.getBaseType().toLowerCase() + 988 "GetHandleID, " + jfunc.getArgName(idx) + 989 ");"); 990 } 991 } 992 993 // Emit local variable declarations for element/sentinel checks 994 // 995 // Example: 996 // 997 // bool attrib_list_sentinel_found = false; 998 // 999 emitLocalVariablesForSentinel(cfunc, out); 1000 1001 // Emit local variable declarations for pointer arguments 1002 // 1003 // Example: 1004 // 1005 // GLfixed *eqn_base; 1006 // GLfixed *eqn; 1007 // 1008 String offset = "offset"; 1009 String remaining = "_remaining"; 1010 if (nonPrimitiveArgs.size() > 0) { 1011 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1012 int idx = nonPrimitiveArgs.get(i).intValue(); 1013 int cIndex = jfunc.getArgCIndex(idx); 1014 String cname = cfunc.getArgName(cIndex); 1015 1016 if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray()) 1017 continue; 1018 1019 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1020 String decl = type.getDeclaration(); 1021 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1022 out.println(indent + 1023 decl + 1024 (decl.endsWith("*") ? "" : " ") + 1025 jfunc.getArgName(idx) + 1026 "_base = (" + decl + ") 0;"); 1027 } 1028 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1029 "_" + cname + "Remaining"; 1030 out.println(indent + 1031 "jint " + remaining + ";"); 1032 out.println(indent + 1033 decl + 1034 (decl.endsWith("*") ? "" : " ") + 1035 jfunc.getArgName(idx) + 1036 " = (" + decl + ") 0;"); 1037 } 1038 1039 out.println(); 1040 } 1041 1042 // Emit local variable declaration for strings 1043 if (stringArgs.size() > 0) { 1044 for (int i = 0; i < stringArgs.size(); i++) { 1045 int idx = stringArgs.get(i).intValue(); 1046 int cIndex = jfunc.getArgCIndex(idx); 1047 String cname = cfunc.getArgName(cIndex); 1048 1049 out.println(indent + "const char* _native" + cname + " = 0;"); 1050 } 1051 1052 out.println(); 1053 } 1054 1055 // Null pointer checks and GetStringUTFChars 1056 if (stringArgs.size() > 0) { 1057 for (int i = 0; i < stringArgs.size(); i++) { 1058 int idx = stringArgs.get(i).intValue(); 1059 int cIndex = jfunc.getArgCIndex(idx); 1060 String cname = cfunc.getArgName(cIndex); 1061 1062 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1063 String decl = type.getDeclaration(); 1064 needsExit = true; 1065 out.println(indent + "if (!" + cname + ") {"); 1066 out.println(indent + indent + 1067 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1068 out.println(indent + indent + 1069 "_exceptionMessage = \"" + cname + " == null\";"); 1070 out.println(indent + indent + "goto exit;"); 1071 out.println(indent + "}"); 1072 1073 out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);"); 1074 } 1075 1076 out.println(); 1077 } 1078 1079 // Emit 'GetPrimitiveArrayCritical' for non-object arrays 1080 // Emit 'GetPointer' calls for Buffer pointers 1081 if (nonPrimitiveArgs.size() > 0) { 1082 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1083 int idx = nonPrimitiveArgs.get(i).intValue(); 1084 int cIndex = jfunc.getArgCIndex(idx); 1085 1086 String cname = cfunc.getArgName(cIndex); 1087 offset = numArrays <= 1 ? "offset" : 1088 cname + "Offset"; 1089 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1090 "_" + cname + "Remaining"; 1091 1092 if (jfunc.getArgType(idx).isArray() 1093 && !jfunc.getArgType(idx).isEGLHandle()) { 1094 needsExit = true; 1095 out.println(indent + "if (!" + cname + "_ref) {"); 1096 out.println(indent + indent + "_exception = 1;"); 1097 out.println(indent + indent + 1098 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1099 out.println(indent + indent + 1100 "_exceptionMessage = \"" + cname +" == null\";"); 1101 out.println(indent + indent + "goto exit;"); 1102 out.println(indent + "}"); 1103 out.println(indent + "if (" + offset + " < 0) {"); 1104 out.println(indent + indent + "_exception = 1;"); 1105 out.println(indent + indent + 1106 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1107 out.println(indent + indent + 1108 "_exceptionMessage = \"" + offset +" < 0\";"); 1109 out.println(indent + indent + "goto exit;"); 1110 out.println(indent + "}"); 1111 1112 out.println(indent + remaining + " = " + 1113 (mUseCPlusPlus ? "_env" : "(*_env)") + 1114 "->GetArrayLength(" + 1115 (mUseCPlusPlus ? "" : "_env, ") + 1116 cname + "_ref) - " + offset + ";"); 1117 1118 emitNativeBoundsChecks(cfunc, cname, out, false, 1119 emitExceptionCheck, 1120 offset, remaining, " "); 1121 1122 out.println(indent + 1123 cname + 1124 "_base = (" + 1125 cfunc.getArgType(cIndex).getDeclaration() + 1126 ")"); 1127 out.println(indent + " " + 1128 (mUseCPlusPlus ? "_env" : "(*_env)") + 1129 "->GetPrimitiveArrayCritical(" + 1130 (mUseCPlusPlus ? "" : "_env, ") + 1131 jfunc.getArgName(idx) + 1132 "_ref, (jboolean *)0);"); 1133 out.println(indent + 1134 cname + " = " + cname + "_base + " + offset + ";"); 1135 1136 emitSentinelCheck(cfunc, cname, out, false, 1137 emitExceptionCheck, offset, 1138 remaining, indent); 1139 out.println(); 1140 } else if (jfunc.getArgType(idx).isArray() 1141 && jfunc.getArgType(idx).isEGLHandle()) { 1142 needsExit = true; 1143 out.println(indent + "if (!" + cname + "_ref) {"); 1144 out.println(indent + indent + "_exception = 1;"); 1145 out.println(indent + indent + 1146 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1147 out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";"); 1148 out.println(indent + indent + "goto exit;"); 1149 out.println(indent + "}"); 1150 out.println(indent + "if (" + offset + " < 0) {"); 1151 out.println(indent + indent + "_exception = 1;"); 1152 out.println(indent + indent + 1153 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1154 out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";"); 1155 out.println(indent + indent + "goto exit;"); 1156 out.println(indent + "}"); 1157 1158 out.println(indent + remaining + " = " + 1159 (mUseCPlusPlus ? "_env" : "(*_env)") + 1160 "->GetArrayLength(" + 1161 (mUseCPlusPlus ? "" : "_env, ") + 1162 cname + "_ref) - " + offset + ";"); 1163 emitNativeBoundsChecks(cfunc, cname, out, false, 1164 emitExceptionCheck, 1165 offset, remaining, " "); 1166 out.println(indent + 1167 jfunc.getArgName(idx) + " = new " + 1168 cfunc.getArgType(cIndex).getBaseType() + 1169 "["+ remaining + "];"); 1170 out.println(); 1171 } else if (jfunc.getArgType(idx).isBuffer()) { 1172 String array = numBufferArgs <= 1 ? "_array" : 1173 "_" + cfunc.getArgName(cIndex) + "Array"; 1174 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1175 "_" + cfunc.getArgName(cIndex) + "BufferOffset"; 1176 1177 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1178 if (nullAllowed) { 1179 out.println(indent + "if (" + cname + "_buf) {"); 1180 out.print(indent); 1181 } 1182 1183 if (isPointerFunc) { 1184 out.println(indent + 1185 cname + 1186 " = (" + 1187 cfunc.getArgType(cIndex).getDeclaration() + 1188 ") getDirectBufferPointer(_env, " + 1189 cname + "_buf);"); 1190 String iii = " "; 1191 out.println(iii + indent + "if ( ! " + cname + " ) {"); 1192 out.println(iii + indent + indent + "return;"); 1193 out.println(iii + indent + "}"); 1194 } else { 1195 out.println(indent + 1196 cname + 1197 " = (" + 1198 cfunc.getArgType(cIndex).getDeclaration() + 1199 ")getPointer(_env, " + 1200 cname + 1201 "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset + 1202 ");"); 1203 } 1204 1205 emitNativeBoundsChecks(cfunc, cname, out, true, 1206 emitExceptionCheck, 1207 offset, remaining, nullAllowed ? " " : " "); 1208 1209 if (nullAllowed) { 1210 out.println(indent + "}"); 1211 } 1212 } 1213 } 1214 } 1215 1216 // Emit 'GetPrimitiveArrayCritical' for pointers if needed 1217 if (nonPrimitiveArgs.size() > 0) { 1218 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1219 int idx = nonPrimitiveArgs.get(i).intValue(); 1220 int cIndex = jfunc.getArgCIndex(idx); 1221 1222 if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue; 1223 1224 String cname = cfunc.getArgName(cIndex); 1225 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1226 "_" + cname + "BufferOffset"; 1227 String array = numBufferArgs <= 1 ? "_array" : 1228 "_" + cfunc.getArgName(cIndex) + "Array"; 1229 1230 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1231 if (nullAllowed) { 1232 out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {"); 1233 } else { 1234 out.println(indent + "if (" + cname +" == NULL) {"); 1235 } 1236 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); 1237 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); 1238 out.println(indent + "}"); 1239 } 1240 } 1241 1242 1243 if (!isVoid) { 1244 out.print(indent + "_returnValue = "); 1245 } else { 1246 out.print(indent); 1247 } 1248 String name = cfunc.getName(); 1249 1250 if (mUseContextPointer) { 1251 name = name.substring(2, name.length()); // Strip off 'gl' prefix 1252 name = name.substring(0, 1).toLowerCase() + 1253 name.substring(1, name.length()); 1254 out.print("ctx->procs."); 1255 } 1256 1257 out.print(name + (isPointerFunc ? "Bounds" : "") + "("); 1258 1259 numArgs = cfunc.getNumArgs(); 1260 if (numArgs == 0) { 1261 if (mUseContextPointer) { 1262 out.println("ctx);"); 1263 } else { 1264 out.println(");"); 1265 } 1266 } else { 1267 if (mUseContextPointer) { 1268 out.println("ctx,"); 1269 } else { 1270 out.println(); 1271 } 1272 for (int i = 0; i < numArgs; i++) { 1273 String typecast; 1274 if (i == numArgs - 1 && isVBOPointerFunc) { 1275 typecast = "(const GLvoid *)"; 1276 } else { 1277 typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; 1278 } 1279 out.print(indent + indent + 1280 typecast); 1281 1282 if (cfunc.getArgType(i).isConstCharPointer()) { 1283 out.print("_native"); 1284 } 1285 1286 if (cfunc.getArgType(i).isEGLHandle() && 1287 !cfunc.getArgType(i).isPointer()){ 1288 out.print(cfunc.getArgName(i)+"_native"); 1289 } else { 1290 out.print(cfunc.getArgName(i)); 1291 } 1292 1293 if (i == numArgs - 1) { 1294 if (isPointerFunc) { 1295 out.println(","); 1296 out.println(indent + indent + "(GLsizei)remaining"); 1297 } else { 1298 out.println(); 1299 } 1300 } else { 1301 out.println(","); 1302 } 1303 } 1304 out.println(indent + ");"); 1305 } 1306 1307 if (needsExit) { 1308 out.println(); 1309 out.println("exit:"); 1310 needsExit = false; 1311 } 1312 1313 1314 if (nonPrimitiveArgs.size() > 0) { 1315 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1316 int idx = nonPrimitiveArgs.get(i).intValue(); 1317 1318 int cIndex = jfunc.getArgCIndex(idx); 1319 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1320 1321 // If the argument is 'const', GL will not write to it. 1322 // In this case, we can use the 'JNI_ABORT' flag to avoid 1323 // the need to write back to the Java array 1324 out.println(indent + 1325 "if (" + jfunc.getArgName(idx) + "_base) {"); 1326 out.println(indent + indent + 1327 (mUseCPlusPlus ? "_env" : "(*_env)") + 1328 "->ReleasePrimitiveArrayCritical(" + 1329 (mUseCPlusPlus ? "" : "_env, ") + 1330 jfunc.getArgName(idx) + "_ref, " + 1331 cfunc.getArgName(cIndex) + 1332 "_base,"); 1333 out.println(indent + indent + indent + 1334 (cfunc.getArgType(cIndex).isConst() ? 1335 "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + 1336 ");"); 1337 out.println(indent + "}"); 1338 } else if (jfunc.getArgType(idx).isBuffer()) { 1339 if (! isPointerFunc) { 1340 String array = numBufferArgs <= 1 ? "_array" : 1341 "_" + cfunc.getArgName(cIndex) + "Array"; 1342 out.println(indent + "if (" + array + ") {"); 1343 out.println(indent + indent + 1344 "releasePointer(_env, " + array + ", " + 1345 cfunc.getArgName(cIndex) + 1346 ", " + 1347 (cfunc.getArgType(cIndex).isConst() ? 1348 "JNI_FALSE" : (emitExceptionCheck ? 1349 "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + 1350 ");"); 1351 out.println(indent + "}"); 1352 } 1353 } 1354 } 1355 } 1356 1357 // Emit local variable declaration for strings 1358 if (stringArgs.size() > 0) { 1359 for (int i = 0; i < stringArgs.size(); i++) { 1360 int idx = stringArgs.get(i).intValue(); 1361 int cIndex = jfunc.getArgCIndex(idx); 1362 String cname = cfunc.getArgName(cIndex); 1363 1364 out.println(indent + "if (_native" + cname + ") {"); 1365 out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");"); 1366 out.println(indent + "}"); 1367 } 1368 1369 out.println(); 1370 } 1371 1372 // Copy results back to java arrays 1373 if (nonPrimitiveArgs.size() > 0) { 1374 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1375 int idx = nonPrimitiveArgs.get(i).intValue(); 1376 int cIndex = jfunc.getArgCIndex(idx); 1377 String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); 1378 if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { 1379 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1380 "_" + cfunc.getArgName(cIndex) + "Remaining"; 1381 offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; 1382 out.println(indent + 1383 "if (" + jfunc.getArgName(idx) + ") {"); 1384 out.println(indent + indent + 1385 "for (int i = 0; i < " + remaining + "; i++) {"); 1386 out.println(indent + indent + indent + 1387 "jobject " + cfunc.getArgName(cIndex) + 1388 "_new = toEGLHandle(_env, " + baseType + 1389 "Class, " + baseType + "Constructor, " + 1390 cfunc.getArgName(cIndex) + "[i]);"); 1391 out.println(indent + indent + indent + 1392 (mUseCPlusPlus ? "_env" : "(*_env)") + 1393 "->SetObjectArrayElement(" + 1394 (mUseCPlusPlus ? "" : "_env, ") + 1395 cfunc.getArgName(cIndex) + 1396 "_ref, i + " + offset + ", " + 1397 cfunc.getArgName(cIndex) + "_new);"); 1398 out.println(indent + indent + "}"); 1399 out.println(indent + indent + 1400 "delete[] " + jfunc.getArgName(idx) + ";"); 1401 out.println(indent + "}"); 1402 } 1403 } 1404 } 1405 1406 1407 // Throw exception if there is one 1408 if (emitExceptionCheck) { 1409 out.println(indent + "if (_exception) {"); 1410 out.println(indent + indent + 1411 "jniThrowException(_env, _exceptionType, _exceptionMessage);"); 1412 out.println(indent + "}"); 1413 1414 } 1415 1416 1417 if (!isVoid) { 1418 if (cfunc.getType().isEGLHandle()) { 1419 String baseType = cfunc.getType().getBaseType().toLowerCase(); 1420 out.println(indent + 1421 "return toEGLHandle(_env, " + baseType + "Class, " + 1422 baseType + "Constructor, _returnValue);"); 1423 } else { 1424 out.println(indent + "return _returnValue;"); 1425 } 1426 } 1427 1428 out.println("}"); 1429 out.println(); 1430 } 1431 1432 } 1433