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 List<JType> bufferArgTypes = new ArrayList<JType>(); 816 817 // Emit JNI signature (arguments) 818 // 819 // Example: 820 // 821 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) { 822 // 823 out.print(" (JNIEnv *_env, jobject _this"); 824 for (int i = 0; i < numArgs; i++) { 825 out.print(", "); 826 JType argType = jfunc.getArgType(i); 827 String suffix = ""; 828 if (!argType.isPrimitive()) { 829 if (argType.isArray()) { 830 suffix = "_ref"; 831 } else if (argType.isBuffer()) { 832 suffix = "_buf"; 833 } 834 nonPrimitiveArgs.add(new Integer(i)); 835 if (jfunc.getArgType(i).isBuffer()) { 836 int cIndex = jfunc.getArgCIndex(i); 837 String cname = cfunc.getArgName(cIndex); 838 bufferArgNames.add(cname); 839 bufferArgTypes.add(jfunc.getArgType(i)); 840 numBufferArgs++; 841 } 842 } 843 844 if (argType.isString()) { 845 stringArgs.add(new Integer(i)); 846 } 847 848 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix); 849 } 850 if (isPointerFunc) { 851 out.print(", jint remaining"); 852 } 853 out.println(") {"); 854 855 int numArrays = 0; 856 int numBuffers = 0; 857 int numStrings = 0; 858 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 859 int idx = nonPrimitiveArgs.get(i).intValue(); 860 JType argType = jfunc.getArgType(idx); 861 if (argType.isArray()) { 862 ++numArrays; 863 } 864 if (argType.isBuffer()) { 865 ++numBuffers; 866 } 867 if (argType.isString()) { 868 ++numStrings; 869 } 870 } 871 872 // Emit method body 873 874 // Emit local variable declarations for _exception and _returnValue 875 // 876 // Example: 877 // 878 // android::gl::ogles_context_t *ctx; 879 // 880 // jint _exception; 881 // GLenum _returnValue; 882 // 883 CType returnType = cfunc.getType(); 884 boolean isVoid = returnType.isVoid(); 885 886 boolean isUnsupported = isUnsupportedFunc(cfunc); 887 if (isUnsupported) { 888 out.println(indent + 889 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 890 out.println(indent + 891 " \"" + cfunc.getName() + "\");"); 892 if (!isVoid) { 893 String retval = getErrorReturnValue(cfunc); 894 if (cfunc.getType().isEGLHandle()) { 895 String baseType = cfunc.getType().getBaseType().toLowerCase(); 896 out.println(indent + 897 "return toEGLHandle(_env, " + baseType + "Class, " + 898 baseType + "Constructor, " + retval + ");"); 899 } else { 900 out.println(indent + "return " + retval + ";"); 901 } 902 } 903 out.println("}"); 904 out.println(); 905 return; 906 } 907 908 String requiresExtension = isRequiresFunc(cfunc); 909 if (requiresExtension != null) { 910 out.println(indent + 911 "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {"); 912 out.println(indent + indent + 913 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 914 out.println(indent + indent + 915 " \"" + cfunc.getName() + "\");"); 916 if (isVoid) { 917 out.println(indent + indent + " return;"); 918 } else { 919 String retval = getErrorReturnValue(cfunc); 920 if (cfunc.getType().isEGLHandle()) { 921 String baseType = cfunc.getType().getBaseType().toLowerCase(); 922 out.println(indent + 923 "return toEGLHandle(_env, " + baseType + "Class, " + 924 baseType + "Constructor, " + retval + ");"); 925 } else { 926 out.println(indent + "return " + retval + ";"); 927 } 928 } 929 out.println(indent + "}"); 930 } 931 if (mUseContextPointer) { 932 out.println(indent + 933 "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); 934 } 935 936 boolean initializeReturnValue = stringArgs.size() > 0; 937 boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0) 938 && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs) 939 || (cfunc.hasPointerArg() && numArrays > 0)) 940 || hasCheckTest(cfunc) 941 || hasIfTest(cfunc)) 942 || (stringArgs.size() > 0); 943 // mChecker.getChecks(cfunc.getName()) != null 944 // Emit an _exeption variable if there will be error checks 945 if (emitExceptionCheck) { 946 out.println(indent + "jint _exception = 0;"); 947 out.println(indent + "const char * _exceptionType = NULL;"); 948 out.println(indent + "const char * _exceptionMessage = NULL;"); 949 } 950 951 // Emit a single _array or multiple _XXXArray variables 952 if (numBufferArgs == 1) { 953 JType bufferType = bufferArgTypes.get(0); 954 if (bufferType.isTypedBuffer()) { 955 String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer()); 956 out.println(indent + typedArrayType + " _array = (" + typedArrayType + ") 0;"); 957 } else { 958 out.println(indent + "jarray _array = (jarray) 0;"); 959 } 960 out.println(indent + "jint _bufferOffset = (jint) 0;"); 961 } else { 962 for (int i = 0; i < numBufferArgs; i++) { 963 JType bufferType = bufferArgTypes.get(0); 964 if (bufferType.isTypedBuffer()) { 965 String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer()); 966 out.println(indent + typedArrayType + " _" + bufferArgNames.get(i) + 967 "Array = (" + typedArrayType + ") 0;"); 968 } else { 969 out.println(indent + "jarray _" + bufferArgNames.get(i) + 970 "Array = (jarray) 0;"); 971 } 972 out.println(indent + "jint _" + bufferArgNames.get(i) + 973 "BufferOffset = (jint) 0;"); 974 } 975 } 976 if (!isVoid) { 977 String retval = getErrorReturnValue(cfunc); 978 if (retval != null) { 979 out.println(indent + returnType.getDeclaration() + 980 " _returnValue = " + retval + ";"); 981 } else if (initializeReturnValue) { 982 out.println(indent + returnType.getDeclaration() + 983 " _returnValue = 0;"); 984 } else { 985 out.println(indent + returnType.getDeclaration() + 986 " _returnValue;"); 987 } 988 } 989 990 // Emit local variable declarations for EGL Handles 991 // 992 // Example: 993 // 994 // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface); 995 // 996 if (nonPrimitiveArgs.size() > 0) { 997 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 998 int idx = nonPrimitiveArgs.get(i).intValue(); 999 int cIndex = jfunc.getArgCIndex(idx); 1000 String cname = cfunc.getArgName(cIndex); 1001 1002 if (jfunc.getArgType(idx).isBuffer() 1003 || jfunc.getArgType(idx).isArray() 1004 || !jfunc.getArgType(idx).isEGLHandle()) 1005 continue; 1006 1007 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1008 String decl = type.getDeclaration(); 1009 out.println(indent + 1010 decl + " " + cname + "_native = (" + 1011 decl + ") fromEGLHandle(_env, " + 1012 type.getBaseType().toLowerCase() + 1013 "GetHandleID, " + jfunc.getArgName(idx) + 1014 ");"); 1015 } 1016 } 1017 1018 // Emit local variable declarations for element/sentinel checks 1019 // 1020 // Example: 1021 // 1022 // bool attrib_list_sentinel_found = false; 1023 // 1024 emitLocalVariablesForSentinel(cfunc, out); 1025 1026 // Emit local variable declarations for pointer arguments 1027 // 1028 // Example: 1029 // 1030 // GLfixed *eqn_base; 1031 // GLfixed *eqn; 1032 // 1033 String offset = "offset"; 1034 String remaining = "_remaining"; 1035 if (nonPrimitiveArgs.size() > 0) { 1036 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1037 int idx = nonPrimitiveArgs.get(i).intValue(); 1038 int cIndex = jfunc.getArgCIndex(idx); 1039 String cname = cfunc.getArgName(cIndex); 1040 1041 if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray()) 1042 continue; 1043 1044 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1045 String decl = type.getDeclaration(); 1046 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1047 out.println(indent + 1048 decl + 1049 (decl.endsWith("*") ? "" : " ") + 1050 jfunc.getArgName(idx) + 1051 "_base = (" + decl + ") 0;"); 1052 } 1053 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1054 "_" + cname + "Remaining"; 1055 out.println(indent + 1056 "jint " + remaining + ";"); 1057 out.println(indent + 1058 decl + 1059 (decl.endsWith("*") ? "" : " ") + 1060 jfunc.getArgName(idx) + 1061 " = (" + decl + ") 0;"); 1062 } 1063 1064 out.println(); 1065 } 1066 1067 // Emit local variable declaration for strings 1068 if (stringArgs.size() > 0) { 1069 for (int i = 0; i < stringArgs.size(); i++) { 1070 int idx = stringArgs.get(i).intValue(); 1071 int cIndex = jfunc.getArgCIndex(idx); 1072 String cname = cfunc.getArgName(cIndex); 1073 1074 out.println(indent + "const char* _native" + cname + " = 0;"); 1075 } 1076 1077 out.println(); 1078 } 1079 1080 // Null pointer checks and GetStringUTFChars 1081 if (stringArgs.size() > 0) { 1082 for (int i = 0; i < stringArgs.size(); i++) { 1083 int idx = stringArgs.get(i).intValue(); 1084 int cIndex = jfunc.getArgCIndex(idx); 1085 String cname = cfunc.getArgName(cIndex); 1086 1087 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1088 String decl = type.getDeclaration(); 1089 needsExit = true; 1090 out.println(indent + "if (!" + cname + ") {"); 1091 out.println(indent + indent + "_exception = 1;"); 1092 out.println(indent + indent + 1093 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1094 out.println(indent + indent + 1095 "_exceptionMessage = \"" + cname + " == null\";"); 1096 out.println(indent + indent + "goto exit;"); 1097 out.println(indent + "}"); 1098 1099 out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);"); 1100 } 1101 1102 out.println(); 1103 } 1104 1105 // Emit 'GetPrimitiveArrayCritical' for non-object arrays 1106 // Emit 'GetPointer' calls for Buffer pointers 1107 if (nonPrimitiveArgs.size() > 0) { 1108 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1109 int idx = nonPrimitiveArgs.get(i).intValue(); 1110 int cIndex = jfunc.getArgCIndex(idx); 1111 1112 String cname = cfunc.getArgName(cIndex); 1113 offset = numArrays <= 1 ? "offset" : 1114 cname + "Offset"; 1115 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1116 "_" + cname + "Remaining"; 1117 1118 if (jfunc.getArgType(idx).isArray() 1119 && !jfunc.getArgType(idx).isEGLHandle()) { 1120 needsExit = true; 1121 out.println(indent + "if (!" + cname + "_ref) {"); 1122 out.println(indent + indent + "_exception = 1;"); 1123 out.println(indent + indent + 1124 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1125 out.println(indent + indent + 1126 "_exceptionMessage = \"" + cname +" == null\";"); 1127 out.println(indent + indent + "goto exit;"); 1128 out.println(indent + "}"); 1129 out.println(indent + "if (" + offset + " < 0) {"); 1130 out.println(indent + indent + "_exception = 1;"); 1131 out.println(indent + indent + 1132 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1133 out.println(indent + indent + 1134 "_exceptionMessage = \"" + offset +" < 0\";"); 1135 out.println(indent + indent + "goto exit;"); 1136 out.println(indent + "}"); 1137 1138 out.println(indent + remaining + " = " + 1139 (mUseCPlusPlus ? "_env" : "(*_env)") + 1140 "->GetArrayLength(" + 1141 (mUseCPlusPlus ? "" : "_env, ") + 1142 cname + "_ref) - " + offset + ";"); 1143 1144 emitNativeBoundsChecks(cfunc, cname, out, false, 1145 emitExceptionCheck, 1146 offset, remaining, " "); 1147 1148 out.println(indent + 1149 cname + 1150 "_base = (" + 1151 cfunc.getArgType(cIndex).getDeclaration() + 1152 ")"); 1153 String arrayGetter = jfunc.getArgType(idx).getArrayGetterForPrimitiveArray(); 1154 out.println(indent + " " + 1155 (mUseCPlusPlus ? "_env" : "(*_env)") + 1156 "->" + arrayGetter + "(" + 1157 (mUseCPlusPlus ? "" : "_env, ") + 1158 jfunc.getArgName(idx) + 1159 "_ref, (jboolean *)0);"); 1160 out.println(indent + 1161 cname + " = " + cname + "_base + " + offset + ";"); 1162 1163 emitSentinelCheck(cfunc, cname, out, false, 1164 emitExceptionCheck, offset, 1165 remaining, indent); 1166 out.println(); 1167 } else if (jfunc.getArgType(idx).isArray() 1168 && jfunc.getArgType(idx).isEGLHandle()) { 1169 needsExit = true; 1170 out.println(indent + "if (!" + cname + "_ref) {"); 1171 out.println(indent + indent + "_exception = 1;"); 1172 out.println(indent + indent + 1173 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1174 out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";"); 1175 out.println(indent + indent + "goto exit;"); 1176 out.println(indent + "}"); 1177 out.println(indent + "if (" + offset + " < 0) {"); 1178 out.println(indent + indent + "_exception = 1;"); 1179 out.println(indent + indent + 1180 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1181 out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";"); 1182 out.println(indent + indent + "goto exit;"); 1183 out.println(indent + "}"); 1184 1185 out.println(indent + remaining + " = " + 1186 (mUseCPlusPlus ? "_env" : "(*_env)") + 1187 "->GetArrayLength(" + 1188 (mUseCPlusPlus ? "" : "_env, ") + 1189 cname + "_ref) - " + offset + ";"); 1190 emitNativeBoundsChecks(cfunc, cname, out, false, 1191 emitExceptionCheck, 1192 offset, remaining, " "); 1193 out.println(indent + 1194 jfunc.getArgName(idx) + " = new " + 1195 cfunc.getArgType(cIndex).getBaseType() + 1196 "["+ remaining + "];"); 1197 out.println(); 1198 } else if (jfunc.getArgType(idx).isBuffer()) { 1199 String array = numBufferArgs <= 1 ? "_array" : 1200 "_" + cfunc.getArgName(cIndex) + "Array"; 1201 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1202 "_" + cfunc.getArgName(cIndex) + "BufferOffset"; 1203 1204 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1205 if (nullAllowed) { 1206 out.println(indent + "if (" + cname + "_buf) {"); 1207 out.print(indent); 1208 } 1209 1210 if (isPointerFunc) { 1211 out.println(indent + 1212 cname + 1213 " = (" + 1214 cfunc.getArgType(cIndex).getDeclaration() + 1215 ") getDirectBufferPointer(_env, " + 1216 cname + "_buf);"); 1217 String iii = " "; 1218 out.println(iii + indent + "if ( ! " + cname + " ) {"); 1219 out.println(iii + indent + indent + "return;"); 1220 out.println(iii + indent + "}"); 1221 } else { 1222 out.println(indent + 1223 cname + 1224 " = (" + 1225 cfunc.getArgType(cIndex).getDeclaration() + 1226 ")getPointer(_env, " + 1227 cname + 1228 "_buf, (jarray*)&" + array + ", &" + remaining + ", &" + bufferOffset + 1229 ");"); 1230 } 1231 1232 emitNativeBoundsChecks(cfunc, cname, out, true, 1233 emitExceptionCheck, 1234 offset, remaining, nullAllowed ? " " : " "); 1235 1236 if (nullAllowed) { 1237 out.println(indent + "}"); 1238 } 1239 } 1240 } 1241 } 1242 1243 // Emit 'GetPrimitiveArrayCritical' for pointers if needed 1244 if (nonPrimitiveArgs.size() > 0) { 1245 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1246 int idx = nonPrimitiveArgs.get(i).intValue(); 1247 int cIndex = jfunc.getArgCIndex(idx); 1248 1249 if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue; 1250 1251 String cname = cfunc.getArgName(cIndex); 1252 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1253 "_" + cname + "BufferOffset"; 1254 String array = numBufferArgs <= 1 ? "_array" : 1255 "_" + cfunc.getArgName(cIndex) + "Array"; 1256 1257 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1258 if (nullAllowed) { 1259 out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {"); 1260 } else { 1261 out.println(indent + "if (" + cname +" == NULL) {"); 1262 } 1263 JType argType = jfunc.getArgType(idx); 1264 if (argType.isTypedBuffer()) { 1265 String arrayGetter = argType.getArrayTypeForTypedBuffer().getArrayGetterForPrimitiveArray(); 1266 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->" + arrayGetter + "(" + array + ", (jboolean *) 0);"); 1267 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); 1268 out.println(indent + "}"); 1269 } else { 1270 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); 1271 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); 1272 out.println(indent + "}"); 1273 } 1274 } 1275 } 1276 1277 1278 if (!isVoid) { 1279 out.print(indent + "_returnValue = "); 1280 } else { 1281 out.print(indent); 1282 } 1283 String name = cfunc.getName(); 1284 1285 if (mUseContextPointer) { 1286 name = name.substring(2, name.length()); // Strip off 'gl' prefix 1287 name = name.substring(0, 1).toLowerCase() + 1288 name.substring(1, name.length()); 1289 out.print("ctx->procs."); 1290 } 1291 1292 out.print(name + (isPointerFunc ? "Bounds" : "") + "("); 1293 1294 numArgs = cfunc.getNumArgs(); 1295 if (numArgs == 0) { 1296 if (mUseContextPointer) { 1297 out.println("ctx);"); 1298 } else { 1299 out.println(");"); 1300 } 1301 } else { 1302 if (mUseContextPointer) { 1303 out.println("ctx,"); 1304 } else { 1305 out.println(); 1306 } 1307 for (int i = 0; i < numArgs; i++) { 1308 String typecast; 1309 if (i == numArgs - 1 && isPointerOffsetFunc) { 1310 typecast = "reinterpret_cast<GLvoid *>"; 1311 } else { 1312 typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; 1313 } 1314 out.print(indent + indent + 1315 typecast); 1316 1317 if (cfunc.getArgType(i).isConstCharPointer()) { 1318 out.print("_native"); 1319 } 1320 1321 if (cfunc.getArgType(i).isEGLHandle() && 1322 !cfunc.getArgType(i).isPointer()){ 1323 out.print(cfunc.getArgName(i)+"_native"); 1324 } else if (i == numArgs - 1 && isPointerOffsetFunc){ 1325 out.print("("+cfunc.getArgName(i)+")"); 1326 } else { 1327 out.print(cfunc.getArgName(i)); 1328 } 1329 1330 if (i == numArgs - 1) { 1331 if (isPointerFunc) { 1332 out.println(","); 1333 out.println(indent + indent + "(GLsizei)remaining"); 1334 } else { 1335 out.println(); 1336 } 1337 } else { 1338 out.println(","); 1339 } 1340 } 1341 out.println(indent + ");"); 1342 } 1343 1344 if (needsExit) { 1345 out.println(); 1346 out.println("exit:"); 1347 needsExit = false; 1348 } 1349 1350 1351 if (nonPrimitiveArgs.size() > 0) { 1352 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1353 int idx = nonPrimitiveArgs.get(i).intValue(); 1354 1355 int cIndex = jfunc.getArgCIndex(idx); 1356 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1357 1358 // If the argument is 'const', GL will not write to it. 1359 // In this case, we can use the 'JNI_ABORT' flag to avoid 1360 // the need to write back to the Java array 1361 out.println(indent + 1362 "if (" + jfunc.getArgName(idx) + "_base) {"); 1363 String arrayReleaser = jfunc.getArgType(idx).getArrayReleaserForPrimitiveArray(); 1364 out.println(indent + indent + 1365 (mUseCPlusPlus ? "_env" : "(*_env)") + 1366 "->" + arrayReleaser + "(" + 1367 (mUseCPlusPlus ? "" : "_env, ") + 1368 jfunc.getArgName(idx) + "_ref, " + 1369 "(j" + jfunc.getArgType(idx).getBaseType() + "*)" + cfunc.getArgName(cIndex) + 1370 "_base,"); 1371 out.println(indent + indent + indent + 1372 (cfunc.getArgType(cIndex).isConst() ? 1373 "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + 1374 ");"); 1375 out.println(indent + "}"); 1376 } else if (jfunc.getArgType(idx).isBuffer()) { 1377 if (! isPointerFunc) { 1378 JType argType = jfunc.getArgType(idx); 1379 String array = numBufferArgs <= 1 ? "_array" : 1380 "_" + cfunc.getArgName(cIndex) + "Array"; 1381 out.println(indent + "if (" + array + ") {"); 1382 if (argType.isTypedBuffer()) { 1383 String arrayReleaser = 1384 argType.getArrayTypeForTypedBuffer().getArrayReleaserForPrimitiveArray(); 1385 out.println(indent + indent + 1386 "_env->" + arrayReleaser + "(" + array + ", " + 1387 "(j" + argType.getArrayTypeForTypedBuffer().getBaseType() + "*)" + 1388 cfunc.getArgName(cIndex) + 1389 ", " + 1390 (cfunc.getArgType(cIndex).isConst() ? 1391 "JNI_ABORT" : (emitExceptionCheck ? 1392 "_exception ? JNI_ABORT : 0" : "0")) + 1393 ");"); 1394 } else { 1395 out.println(indent + indent + 1396 "releasePointer(_env, " + array + ", " + 1397 cfunc.getArgName(cIndex) + 1398 ", " + 1399 (cfunc.getArgType(cIndex).isConst() ? 1400 "JNI_FALSE" : (emitExceptionCheck ? 1401 "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + 1402 ");"); 1403 } 1404 out.println(indent + "}"); 1405 } 1406 } 1407 } 1408 } 1409 1410 // Emit local variable declaration for strings 1411 if (stringArgs.size() > 0) { 1412 for (int i = 0; i < stringArgs.size(); i++) { 1413 int idx = stringArgs.get(i).intValue(); 1414 int cIndex = jfunc.getArgCIndex(idx); 1415 String cname = cfunc.getArgName(cIndex); 1416 1417 out.println(indent + "if (_native" + cname + ") {"); 1418 out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");"); 1419 out.println(indent + "}"); 1420 } 1421 1422 out.println(); 1423 } 1424 1425 // Copy results back to java arrays 1426 if (nonPrimitiveArgs.size() > 0) { 1427 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1428 int idx = nonPrimitiveArgs.get(i).intValue(); 1429 int cIndex = jfunc.getArgCIndex(idx); 1430 String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); 1431 if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { 1432 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1433 "_" + cfunc.getArgName(cIndex) + "Remaining"; 1434 offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; 1435 out.println(indent + 1436 "if (" + jfunc.getArgName(idx) + ") {"); 1437 out.println(indent + indent + 1438 "for (int i = 0; i < " + remaining + "; i++) {"); 1439 out.println(indent + indent + indent + 1440 "jobject " + cfunc.getArgName(cIndex) + 1441 "_new = toEGLHandle(_env, " + baseType + 1442 "Class, " + baseType + "Constructor, " + 1443 cfunc.getArgName(cIndex) + "[i]);"); 1444 out.println(indent + indent + indent + 1445 (mUseCPlusPlus ? "_env" : "(*_env)") + 1446 "->SetObjectArrayElement(" + 1447 (mUseCPlusPlus ? "" : "_env, ") + 1448 cfunc.getArgName(cIndex) + 1449 "_ref, i + " + offset + ", " + 1450 cfunc.getArgName(cIndex) + "_new);"); 1451 out.println(indent + indent + "}"); 1452 out.println(indent + indent + 1453 "delete[] " + jfunc.getArgName(idx) + ";"); 1454 out.println(indent + "}"); 1455 } 1456 } 1457 } 1458 1459 1460 // Throw exception if there is one 1461 if (emitExceptionCheck) { 1462 out.println(indent + "if (_exception) {"); 1463 out.println(indent + indent + 1464 "jniThrowException(_env, _exceptionType, _exceptionMessage);"); 1465 out.println(indent + "}"); 1466 1467 } 1468 1469 1470 if (!isVoid) { 1471 if (cfunc.getType().isEGLHandle()) { 1472 String baseType = cfunc.getType().getBaseType().toLowerCase(); 1473 out.println(indent + 1474 "return toEGLHandle(_env, " + baseType + "Class, " + 1475 baseType + "Constructor, _returnValue);"); 1476 } else { 1477 out.println(indent + "return (" + 1478 getJniType(jfunc.getType()) + ")_returnValue;"); 1479 } 1480 } 1481 1482 out.println("}"); 1483 out.println(); 1484 } 1485 1486 } 1487