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, String cname) { 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 checks[index + 1].equals(cname)) { 232 return true; 233 } else { 234 index = skipOneCheck(checks, index); 235 } 236 } 237 } 238 return false; 239 } 240 241 boolean hasCheckTest(CFunc cfunc) { 242 String[] checks = mChecker.getChecks(cfunc.getName()); 243 int index = 1; 244 if (checks != null) { 245 while (index < checks.length) { 246 if (checks[index].startsWith("check")) { 247 return true; 248 } else { 249 index = skipOneCheck(checks, index); 250 } 251 } 252 } 253 return false; 254 } 255 256 boolean hasCheckTest(CFunc cfunc, String cname) { 257 String[] checks = mChecker.getChecks(cfunc.getName()); 258 int index = 1; 259 if (checks != null) { 260 while (index < checks.length) { 261 if (checks[index].startsWith("check") && 262 cname != null && cname.equals(checks[index + 1])) { 263 return true; 264 } else { 265 index = skipOneCheck(checks, index); 266 } 267 } 268 } 269 return false; 270 } 271 272 boolean hasIfTest(CFunc cfunc) { 273 String[] checks = mChecker.getChecks(cfunc.getName()); 274 int index = 1; 275 if (checks != null) { 276 while (index < checks.length) { 277 if (checks[index].startsWith("ifcheck")) { 278 return true; 279 } else { 280 index = skipOneCheck(checks, index); 281 } 282 } 283 } 284 return false; 285 } 286 287 int skipOneCheck(String[] checks, int index) { 288 if (checks[index].equals("return")) { 289 index += 2; 290 } else if (checks[index].startsWith("check")) { 291 index += 3; 292 } else if (checks[index].startsWith("sentinel")) { 293 index += 3; 294 } else if (checks[index].equals("ifcheck")) { 295 index += 5; 296 } else if (checks[index].equals("unsupported")) { 297 index += 1; 298 } else if (checks[index].equals("requires")) { 299 index += 2; 300 } else if (checks[index].equals("nullAllowed")) { 301 index += 2; 302 } else { 303 System.out.println("Error: unknown keyword \"" + 304 checks[index] + "\""); 305 System.exit(0); 306 } 307 308 return index; 309 } 310 311 String getErrorReturnValue(CFunc cfunc) { 312 CType returnType = cfunc.getType(); 313 boolean isVoid = returnType.isVoid(); 314 if (isVoid) { 315 return null; 316 } 317 318 if (returnType.getBaseType().startsWith("EGL")) { 319 return "(" + returnType.getDeclaration() + ") 0"; 320 } 321 322 String[] checks = mChecker.getChecks(cfunc.getName()); 323 324 int index = 1; 325 if (checks != null) { 326 while (index < checks.length) { 327 if (checks[index].equals("return")) { 328 return checks[index + 1]; 329 } else { 330 index = skipOneCheck(checks, index); 331 } 332 } 333 } 334 335 return null; 336 } 337 338 boolean isUnsupportedFunc(CFunc cfunc) { 339 String[] checks = mChecker.getChecks(cfunc.getName()); 340 int index = 1; 341 if (checks != null) { 342 while (index < checks.length) { 343 if (checks[index].equals("unsupported")) { 344 return true; 345 } else { 346 index = skipOneCheck(checks, index); 347 } 348 } 349 } 350 return false; 351 } 352 353 String isRequiresFunc(CFunc cfunc) { 354 String[] checks = mChecker.getChecks(cfunc.getName()); 355 int index = 1; 356 if (checks != null) { 357 while (index < checks.length) { 358 if (checks[index].equals("requires")) { 359 return checks[index+1]; 360 } else { 361 index = skipOneCheck(checks, index); 362 } 363 } 364 } 365 return null; 366 } 367 368 void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out, 369 boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { 370 371 String[] checks = mChecker.getChecks(cfunc.getName()); 372 373 boolean lastWasIfcheck = false; 374 375 int index = 1; 376 if (checks != null) { 377 while (index < checks.length) { 378 if (checks[index].startsWith("check")) { 379 if (lastWasIfcheck) { 380 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, 381 offset, remaining, iii); 382 } 383 lastWasIfcheck = false; 384 if (cname != null && !cname.equals(checks[index + 1])) { 385 index += 3; 386 continue; 387 } 388 out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {"); 389 out.println(iii + indent + "_exception = 1;"); 390 String exceptionClassName = "java/lang/IllegalArgumentException"; 391 // If the "check" keyword was of the form 392 // "check_<class name>", use the class name in the 393 // exception to be thrown 394 int underscore = checks[index].indexOf('_'); 395 if (underscore >= 0) { 396 String abbr = checks[index].substring(underscore + 1); 397 if (abbr.equals("AIOOBE")) { 398 exceptionClassName = "java/lang/ArrayIndexOutOfBoundsException"; 399 } else { 400 throw new RuntimeException("unknown exception abbreviation: " + abbr); 401 } 402 } 403 out.println(iii + indent + 404 "_exceptionType = \""+exceptionClassName+"\";"); 405 out.println(iii + indent + 406 "_exceptionMessage = \"" + 407 (isBuffer ? "remaining()" : "length - " + 408 offset) + " < " + checks[index + 2] + 409 " < needed\";"); 410 411 out.println(iii + indent + "goto exit;"); 412 out.println(iii + "}"); 413 414 needsExit = true; 415 416 index += 3; 417 } else if (checks[index].equals("ifcheck")) { 418 String[] matches = checks[index + 4].split(","); 419 420 if (!lastWasIfcheck) { 421 out.println(iii + "int _needed;"); 422 out.println(iii + "switch (" + checks[index + 3] + ") {"); 423 } 424 425 for (int i = 0; i < matches.length; i++) { 426 out.println("#if defined(" + matches[i] + ")"); 427 out.println(iii + " case " + matches[i] + ":"); 428 out.println("#endif // defined(" + matches[i] + ")"); 429 } 430 out.println(iii + " _needed = " + checks[index + 2] + ";"); 431 out.println(iii + " break;"); 432 433 lastWasIfcheck = true; 434 index += 5; 435 } else { 436 index = skipOneCheck(checks, index); 437 } 438 } 439 } 440 441 if (lastWasIfcheck) { 442 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii); 443 } 444 } 445 446 void emitSentinelCheck(CFunc cfunc, String cname, PrintStream out, 447 boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { 448 449 String[] checks = mChecker.getChecks(cfunc.getName()); 450 451 int index = 1; 452 if (checks != null) { 453 while (index < checks.length) { 454 if (checks[index].startsWith("sentinel")) { 455 if (cname != null && !cname.equals(checks[index + 1])) { 456 index += 3; 457 continue; 458 } 459 460 out.println(iii + cname + "_sentinel = false;"); 461 out.println(iii + "for (int i = " + remaining + 462 " - 1; i >= 0; i--) {"); 463 out.println(iii + indent + "if (" + cname + 464 "[i] == " + checks[index + 2] + "){"); 465 out.println(iii + indent + indent + 466 cname + "_sentinel = true;"); 467 out.println(iii + indent + indent + "break;"); 468 out.println(iii + indent + "}"); 469 out.println(iii + "}"); 470 out.println(iii + 471 "if (" + cname + "_sentinel == false) {"); 472 out.println(iii + indent + "_exception = 1;"); 473 out.println(iii + indent + 474 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 475 out.println(iii + indent + "_exceptionMessage = \"" + cname + 476 " must contain " + checks[index + 2] + "!\";"); 477 out.println(iii + indent + "goto exit;"); 478 out.println(iii + "}"); 479 480 needsExit = true; 481 index += 3; 482 } else { 483 index = skipOneCheck(checks, index); 484 } 485 } 486 } 487 } 488 489 void emitStringCheck(CFunc cfunc, String cname, PrintStream out, String iii) { 490 491 String[] checks = mChecker.getChecks(cfunc.getName()); 492 493 int index = 1; 494 if (checks != null) { 495 while (index < checks.length) { 496 if (checks[index].startsWith("check")) { 497 if (cname != null && !cname.equals(checks[index + 1])) { 498 index += 3; 499 continue; 500 } 501 out.println(iii + "_stringlen = _env->GetStringUTFLength(" + cname + ");"); 502 out.println(iii + "if (" + checks[index + 2] + " > _stringlen) {"); 503 out.println(iii + indent + "_exception = 1;"); 504 out.println(iii + indent + 505 "_exceptionType = \"java/lang/ArrayIndexOutOfBoundsException\";"); 506 out.println(iii + indent + 507 "_exceptionMessage = \"length of " + cname + " is shorter than " + 508 checks[index + 2] + " argument\";"); 509 out.println(iii + indent + "goto exit;"); 510 out.println(iii + "}"); 511 index += 3; 512 needsExit = true; 513 } else { 514 index = skipOneCheck(checks, index); 515 } 516 } 517 } 518 } 519 520 void emitLocalVariablesForSentinel(CFunc cfunc, PrintStream out) { 521 522 String[] checks = mChecker.getChecks(cfunc.getName()); 523 524 int index = 1; 525 if (checks != null) { 526 while (index < checks.length) { 527 if (checks[index].startsWith("sentinel")) { 528 String cname = checks[index + 1]; 529 out.println(indent + "bool " + cname + "_sentinel = false;"); 530 531 index += 3; 532 533 } else { 534 index = skipOneCheck(checks, index); 535 } 536 } 537 } 538 } 539 540 boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) { 541 if (nonPrimitiveArgs.size() > 0) { 542 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 543 int idx = nonPrimitiveArgs.get(i).intValue(); 544 int cIndex = jfunc.getArgCIndex(idx); 545 if (jfunc.getArgType(idx).isArray()) { 546 if (!cfunc.getArgType(cIndex).isConst()) { 547 return true; 548 } 549 } else if (jfunc.getArgType(idx).isBuffer()) { 550 if (!cfunc.getArgType(cIndex).isConst()) { 551 return true; 552 } 553 } 554 } 555 } 556 557 return false; 558 } 559 560 /** 561 * Emit a function in several variants: 562 * 563 * if nativeDecl: public native <returntype> func(args); 564 * 565 * if !nativeDecl: 566 * if interfaceDecl: public <returntype> func(args); 567 * if !interfaceDecl: public <returntype> func(args) { body } 568 */ 569 void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) { 570 boolean isPointerFunc = isPointerFunc(jfunc); 571 572 if (!nativeDecl && !interfaceDecl && !isPointerFunc) { 573 // If it's not a pointer function, we've already emitted it 574 // with nativeDecl == true 575 return; 576 } 577 578 String maybeStatic = mUseStaticMethods ? "static " : ""; 579 580 if (isPointerFunc) { 581 out.println(indent + 582 (nativeDecl ? "private " + maybeStatic +"native " : 583 (interfaceDecl ? "" : "public ") + maybeStatic) + 584 jfunc.getType() + " " + 585 jfunc.getName() + 586 (nativeDecl ? "Bounds" : "") + 587 "("); 588 } else { 589 out.println(indent + 590 (nativeDecl ? "public " + maybeStatic +"native " : 591 (interfaceDecl ? "" : "public ") + maybeStatic) + 592 jfunc.getType() + " " + 593 jfunc.getName() + 594 "("); 595 } 596 597 int numArgs = jfunc.getNumArgs(); 598 for (int i = 0; i < numArgs; i++) { 599 String argName = jfunc.getArgName(i); 600 JType argType = jfunc.getArgType(i); 601 602 out.print(indent + indent + argType + " " + argName); 603 if (i == numArgs - 1) { 604 if (isPointerFunc && nativeDecl) { 605 out.println(","); 606 out.println(indent + indent + "int remaining"); 607 } else { 608 out.println(); 609 } 610 } else { 611 out.println(","); 612 } 613 } 614 615 if (nativeDecl || interfaceDecl) { 616 out.println(indent + ");"); 617 } else { 618 out.println(indent + ") {"); 619 620 String iii = indent + indent; 621 622 // emitBoundsChecks(jfunc, out, iii); 623 emitFunctionCall(jfunc, out, iii, false); 624 625 // Set the pointer after we call the native code, so that if 626 // the native code throws an exception we don't modify the 627 // pointer. We assume that the native code is written so that 628 // if an exception is thrown, then the underlying glXXXPointer 629 // function will not have been called. 630 631 String fname = jfunc.getName(); 632 if (isPointerFunc) { 633 // TODO - deal with VBO variants 634 if (fname.equals("glColorPointer")) { 635 out.println(iii + "if ((size == 4) &&"); 636 out.println(iii + " ((type == GL_FLOAT) ||"); 637 out.println(iii + " (type == GL_UNSIGNED_BYTE) ||"); 638 out.println(iii + " (type == GL_FIXED)) &&"); 639 out.println(iii + " (stride >= 0)) {"); 640 out.println(iii + indent + "_colorPointer = pointer;"); 641 out.println(iii + "}"); 642 } else if (fname.equals("glNormalPointer")) { 643 out.println(iii + "if (((type == GL_FLOAT) ||"); 644 out.println(iii + " (type == GL_BYTE) ||"); 645 out.println(iii + " (type == GL_SHORT) ||"); 646 out.println(iii + " (type == GL_FIXED)) &&"); 647 out.println(iii + " (stride >= 0)) {"); 648 out.println(iii + indent + "_normalPointer = pointer;"); 649 out.println(iii + "}"); 650 } else if (fname.equals("glTexCoordPointer")) { 651 out.println(iii + "if (((size == 2) ||"); 652 out.println(iii + " (size == 3) ||"); 653 out.println(iii + " (size == 4)) &&"); 654 out.println(iii + " ((type == GL_FLOAT) ||"); 655 out.println(iii + " (type == GL_BYTE) ||"); 656 out.println(iii + " (type == GL_SHORT) ||"); 657 out.println(iii + " (type == GL_FIXED)) &&"); 658 out.println(iii + " (stride >= 0)) {"); 659 out.println(iii + indent + "_texCoordPointer = pointer;"); 660 out.println(iii + "}"); 661 } else if (fname.equals("glVertexPointer")) { 662 out.println(iii + "if (((size == 2) ||"); 663 out.println(iii + " (size == 3) ||"); 664 out.println(iii + " (size == 4)) &&"); 665 out.println(iii + " ((type == GL_FLOAT) ||"); 666 out.println(iii + " (type == GL_BYTE) ||"); 667 out.println(iii + " (type == GL_SHORT) ||"); 668 out.println(iii + " (type == GL_FIXED)) &&"); 669 out.println(iii + " (stride >= 0)) {"); 670 out.println(iii + indent + "_vertexPointer = pointer;"); 671 out.println(iii + "}"); 672 } else if (fname.equals("glPointSizePointerOES")) { 673 out.println(iii + "if (((type == GL_FLOAT) ||"); 674 out.println(iii + " (type == GL_FIXED)) &&"); 675 out.println(iii + " (stride >= 0)) {"); 676 out.println(iii + indent + "_pointSizePointerOES = pointer;"); 677 out.println(iii + "}"); 678 } else if (fname.equals("glMatrixIndexPointerOES")) { 679 out.println(iii + "if (((size == 2) ||"); 680 out.println(iii + " (size == 3) ||"); 681 out.println(iii + " (size == 4)) &&"); 682 out.println(iii + " ((type == GL_FLOAT) ||"); 683 out.println(iii + " (type == GL_BYTE) ||"); 684 out.println(iii + " (type == GL_SHORT) ||"); 685 out.println(iii + " (type == GL_FIXED)) &&"); 686 out.println(iii + " (stride >= 0)) {"); 687 out.println(iii + indent + "_matrixIndexPointerOES = pointer;"); 688 out.println(iii + "}"); 689 } else if (fname.equals("glWeightPointer")) { 690 out.println(iii + "if (((size == 2) ||"); 691 out.println(iii + " (size == 3) ||"); 692 out.println(iii + " (size == 4)) &&"); 693 out.println(iii + " ((type == GL_FLOAT) ||"); 694 out.println(iii + " (type == GL_BYTE) ||"); 695 out.println(iii + " (type == GL_SHORT) ||"); 696 out.println(iii + " (type == GL_FIXED)) &&"); 697 out.println(iii + " (stride >= 0)) {"); 698 out.println(iii + indent + "_weightPointerOES = pointer;"); 699 out.println(iii + "}"); 700 } 701 } 702 703 boolean isVoid = jfunc.getType().isVoid(); 704 705 if (!isVoid) { 706 out.println(indent + indent + "return _returnValue;"); 707 } 708 out.println(indent + "}"); 709 } 710 out.println(); 711 } 712 713 public void addNativeRegistration(String s) { 714 nativeRegistrations.add(s); 715 } 716 717 public void emitNativeRegistration(String registrationFunctionName, 718 PrintStream cStream) { 719 cStream.println("static const char *classPathName = \"" + 720 mClassPathName + 721 "\";"); 722 cStream.println(); 723 724 cStream.println("static const JNINativeMethod methods[] = {"); 725 726 cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },"); 727 728 Iterator<String> i = nativeRegistrations.iterator(); 729 while (i.hasNext()) { 730 cStream.println(i.next()); 731 } 732 733 cStream.println("};"); 734 cStream.println(); 735 736 737 cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)"); 738 cStream.println("{"); 739 cStream.println(indent + 740 "int err;"); 741 742 cStream.println(indent + 743 "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));"); 744 745 cStream.println(indent + "return err;"); 746 cStream.println("}"); 747 } 748 749 public JniCodeEmitter() { 750 super(); 751 } 752 753 String getJniType(JType jType) { 754 if (jType.isVoid()) { 755 return "void"; 756 } 757 758 String baseType = jType.getBaseType(); 759 if (jType.isPrimitive()) { 760 if (baseType.equals("String")) { 761 return "jstring"; 762 } else { 763 return "j" + baseType; 764 } 765 } else if (jType.isArray()) { 766 return jType.isClass() ? "jobjectArray" : "j" + baseType + "Array"; 767 } else { 768 return "jobject"; 769 } 770 } 771 772 String getJniMangledName(String name) { 773 name = name.replaceAll("_", "_1"); 774 name = name.replaceAll(";", "_2"); 775 name = name.replaceAll("\\[", "_3"); 776 return name; 777 } 778 779 public void emitJniCode(JFunc jfunc, PrintStream out) { 780 CFunc cfunc = jfunc.getCFunc(); 781 782 // Emit comment identifying original C function 783 // 784 // Example: 785 // 786 // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */ 787 // 788 out.println("/* " + cfunc.getOriginal() + " */"); 789 790 // Emit JNI signature (name) 791 // 792 // Example: 793 // 794 // void 795 // android_glClipPlanef__I_3FI 796 // 797 798 String outName = "android_" + jfunc.getName(); 799 boolean isPointerFunc = isPointerFunc(jfunc); 800 boolean isPointerOffsetFunc = 801 (outName.endsWith("Pointer") || outName.endsWith("PointerOES") || 802 outName.endsWith("glDrawElements") || 803 outName.endsWith("glDrawRangeElements") || 804 outName.endsWith("glTexImage2D") || 805 outName.endsWith("glTexSubImage2D") || 806 outName.endsWith("glCompressedTexImage2D") || 807 outName.endsWith("glCompressedTexSubImage2D") || 808 outName.endsWith("glTexImage3D") || 809 outName.endsWith("glTexSubImage3D") || 810 outName.endsWith("glCompressedTexImage3D") || 811 outName.endsWith("glCompressedTexSubImage3D") || 812 outName.endsWith("glReadPixels")) 813 && !jfunc.getCFunc().hasPointerArg(); 814 if (isPointerFunc) { 815 outName += "Bounds"; 816 } 817 818 out.print("static "); 819 out.println(getJniType(jfunc.getType())); 820 out.print(outName); 821 822 String rsignature = getJniName(jfunc.getType()); 823 824 String signature = ""; 825 int numArgs = jfunc.getNumArgs(); 826 for (int i = 0; i < numArgs; i++) { 827 JType argType = jfunc.getArgType(i); 828 signature += getJniName(argType); 829 } 830 if (isPointerFunc) { 831 signature += "I"; 832 } 833 834 // Append signature to function name 835 String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_'); 836 if (!mUseSimpleMethodNames) { 837 out.print("__" + sig); 838 outName += "__" + sig; 839 } 840 841 signature = signature.replace('.', '/'); 842 rsignature = rsignature.replace('.', '/'); 843 844 out.println(); 845 if (rsignature.length() == 0) { 846 rsignature = "V"; 847 } 848 849 String s = "{\"" + 850 jfunc.getName() + 851 (isPointerFunc ? "Bounds" : "") + 852 "\", \"(" + signature +")" + 853 rsignature + 854 "\", (void *) " + 855 outName + 856 " },"; 857 nativeRegistrations.add(s); 858 859 List<Integer> nonPrimitiveArgs = new ArrayList<Integer>(); 860 List<Integer> stringArgs = new ArrayList<Integer>(); 861 int numBufferArgs = 0; 862 List<String> bufferArgNames = new ArrayList<String>(); 863 List<JType> bufferArgTypes = new ArrayList<JType>(); 864 865 // Emit JNI signature (arguments) 866 // 867 // Example: 868 // 869 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) { 870 // 871 out.print(" (JNIEnv *_env, jobject _this"); 872 for (int i = 0; i < numArgs; i++) { 873 out.print(", "); 874 JType argType = jfunc.getArgType(i); 875 String suffix = ""; 876 if (!argType.isPrimitive()) { 877 if (argType.isArray()) { 878 suffix = "_ref"; 879 } else if (argType.isBuffer()) { 880 suffix = "_buf"; 881 } 882 nonPrimitiveArgs.add(new Integer(i)); 883 if (jfunc.getArgType(i).isBuffer()) { 884 int cIndex = jfunc.getArgCIndex(i); 885 String cname = cfunc.getArgName(cIndex); 886 bufferArgNames.add(cname); 887 bufferArgTypes.add(jfunc.getArgType(i)); 888 numBufferArgs++; 889 } 890 } 891 892 if (argType.isString()) { 893 stringArgs.add(new Integer(i)); 894 } 895 896 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix); 897 } 898 if (isPointerFunc) { 899 out.print(", jint remaining"); 900 } 901 out.println(") {"); 902 903 int numArrays = 0; 904 int numBuffers = 0; 905 int numStrings = 0; 906 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 907 int idx = nonPrimitiveArgs.get(i).intValue(); 908 JType argType = jfunc.getArgType(idx); 909 if (argType.isArray()) { 910 ++numArrays; 911 } 912 if (argType.isBuffer()) { 913 ++numBuffers; 914 } 915 if (argType.isString()) { 916 ++numStrings; 917 } 918 } 919 920 // Emit method body 921 922 // Emit local variable declarations for _exception and _returnValue 923 // 924 // Example: 925 // 926 // android::gl::ogles_context_t *ctx; 927 // 928 // jint _exception; 929 // GLenum _returnValue; 930 // 931 CType returnType = cfunc.getType(); 932 boolean isVoid = returnType.isVoid(); 933 934 boolean isUnsupported = isUnsupportedFunc(cfunc); 935 if (isUnsupported) { 936 out.println(indent + 937 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 938 out.println(indent + 939 " \"" + cfunc.getName() + "\");"); 940 if (!isVoid) { 941 String retval = getErrorReturnValue(cfunc); 942 if (cfunc.getType().isEGLHandle()) { 943 String baseType = cfunc.getType().getBaseType().toLowerCase(); 944 out.println(indent + 945 "return toEGLHandle(_env, " + baseType + "Class, " + 946 baseType + "Constructor, " + retval + ");"); 947 } else { 948 out.println(indent + "return " + retval + ";"); 949 } 950 } 951 out.println("}"); 952 out.println(); 953 return; 954 } 955 956 String requiresExtension = isRequiresFunc(cfunc); 957 if (requiresExtension != null) { 958 out.println(indent + 959 "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {"); 960 out.println(indent + indent + 961 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 962 out.println(indent + indent + 963 " \"" + cfunc.getName() + "\");"); 964 if (isVoid) { 965 out.println(indent + indent + " return;"); 966 } else { 967 String retval = getErrorReturnValue(cfunc); 968 if (cfunc.getType().isEGLHandle()) { 969 String baseType = cfunc.getType().getBaseType().toLowerCase(); 970 out.println(indent + 971 "return toEGLHandle(_env, " + baseType + "Class, " + 972 baseType + "Constructor, " + retval + ");"); 973 } else { 974 out.println(indent + "return " + retval + ";"); 975 } 976 } 977 out.println(indent + "}"); 978 } 979 if (mUseContextPointer) { 980 out.println(indent + 981 "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); 982 } 983 984 boolean initializeReturnValue = stringArgs.size() > 0; 985 boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0) 986 && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs) 987 || (cfunc.hasPointerArg() && numArrays > 0)) 988 || hasCheckTest(cfunc) 989 || hasIfTest(cfunc)) 990 || (stringArgs.size() > 0); 991 // mChecker.getChecks(cfunc.getName()) != null 992 // Emit an _exeption variable if there will be error checks 993 if (emitExceptionCheck) { 994 out.println(indent + "jint _exception = 0;"); 995 out.println(indent + "const char * _exceptionType = NULL;"); 996 out.println(indent + "const char * _exceptionMessage = NULL;"); 997 } 998 999 // Emit a single _array or multiple _XXXArray variables 1000 if (numBufferArgs == 1) { 1001 JType bufferType = bufferArgTypes.get(0); 1002 if (bufferType.isTypedBuffer()) { 1003 String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer()); 1004 out.println(indent + typedArrayType + " _array = (" + typedArrayType + ") 0;"); 1005 } else { 1006 out.println(indent + "jarray _array = (jarray) 0;"); 1007 } 1008 out.println(indent + "jint _bufferOffset = (jint) 0;"); 1009 } else { 1010 for (int i = 0; i < numBufferArgs; i++) { 1011 JType bufferType = bufferArgTypes.get(0); 1012 if (bufferType.isTypedBuffer()) { 1013 String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer()); 1014 out.println(indent + typedArrayType + " _" + bufferArgNames.get(i) + 1015 "Array = (" + typedArrayType + ") 0;"); 1016 } else { 1017 out.println(indent + "jarray _" + bufferArgNames.get(i) + 1018 "Array = (jarray) 0;"); 1019 } 1020 out.println(indent + "jint _" + bufferArgNames.get(i) + 1021 "BufferOffset = (jint) 0;"); 1022 } 1023 } 1024 if (!isVoid) { 1025 String retval = getErrorReturnValue(cfunc); 1026 if (retval != null) { 1027 out.println(indent + returnType.getDeclaration() + 1028 " _returnValue = " + retval + ";"); 1029 } else if (initializeReturnValue) { 1030 out.println(indent + returnType.getDeclaration() + 1031 " _returnValue = 0;"); 1032 } else { 1033 out.println(indent + returnType.getDeclaration() + 1034 " _returnValue;"); 1035 } 1036 } 1037 1038 // Emit local variable declarations for EGL Handles 1039 // 1040 // Example: 1041 // 1042 // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface); 1043 // 1044 if (nonPrimitiveArgs.size() > 0) { 1045 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1046 int idx = nonPrimitiveArgs.get(i).intValue(); 1047 int cIndex = jfunc.getArgCIndex(idx); 1048 String cname = cfunc.getArgName(cIndex); 1049 1050 if (jfunc.getArgType(idx).isBuffer() 1051 || jfunc.getArgType(idx).isArray() 1052 || !jfunc.getArgType(idx).isEGLHandle()) 1053 continue; 1054 1055 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1056 String decl = type.getDeclaration(); 1057 out.println(indent + 1058 decl + " " + cname + "_native = (" + 1059 decl + ") fromEGLHandle(_env, " + 1060 type.getBaseType().toLowerCase() + 1061 "GetHandleID, " + jfunc.getArgName(idx) + 1062 ");"); 1063 } 1064 } 1065 1066 // Emit local variable declarations for element/sentinel checks 1067 // 1068 // Example: 1069 // 1070 // bool attrib_list_sentinel_found = false; 1071 // 1072 emitLocalVariablesForSentinel(cfunc, out); 1073 1074 // Emit local variable declarations for pointer arguments 1075 // 1076 // Example: 1077 // 1078 // GLfixed *eqn_base; 1079 // GLfixed *eqn; 1080 // 1081 String offset = "offset"; 1082 String remaining = "_remaining"; 1083 if (nonPrimitiveArgs.size() > 0) { 1084 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1085 int idx = nonPrimitiveArgs.get(i).intValue(); 1086 int cIndex = jfunc.getArgCIndex(idx); 1087 String cname = cfunc.getArgName(cIndex); 1088 1089 if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray()) 1090 continue; 1091 1092 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1093 String decl = type.getDeclaration(); 1094 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1095 out.println(indent + 1096 decl + 1097 (decl.endsWith("*") ? "" : " ") + 1098 jfunc.getArgName(idx) + 1099 "_base = (" + decl + ") 0;"); 1100 } 1101 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1102 "_" + cname + "Remaining"; 1103 out.println(indent + 1104 "jint " + remaining + ";"); 1105 out.println(indent + 1106 decl + 1107 (decl.endsWith("*") ? "" : " ") + 1108 jfunc.getArgName(idx) + 1109 " = (" + decl + ") 0;"); 1110 } 1111 1112 out.println(); 1113 } 1114 1115 // Emit local variable declaration for strings 1116 if (stringArgs.size() > 0) { 1117 boolean requiresStringLengthCheck = false; 1118 for (int i = 0; i < stringArgs.size(); i++) { 1119 int idx = stringArgs.get(i).intValue(); 1120 int cIndex = jfunc.getArgCIndex(idx); 1121 String cname = cfunc.getArgName(cIndex); 1122 1123 out.println(indent + "const char* _native" + cname + " = 0;"); 1124 if (hasCheckTest(cfunc, cname)) { 1125 requiresStringLengthCheck = true; 1126 } 1127 } 1128 1129 if (requiresStringLengthCheck) { 1130 out.println(indent + "jsize _stringlen = 0;"); 1131 } 1132 1133 out.println(); 1134 } 1135 1136 // Null pointer checks and GetStringUTFChars 1137 if (stringArgs.size() > 0) { 1138 for (int i = 0; i < stringArgs.size(); i++) { 1139 int idx = stringArgs.get(i).intValue(); 1140 int cIndex = jfunc.getArgCIndex(idx); 1141 String cname = cfunc.getArgName(cIndex); 1142 1143 boolean nullAllowed = isNullAllowed(cfunc, cname); 1144 String nullAllowedIndent = nullAllowed ? indent : ""; 1145 1146 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1147 String decl = type.getDeclaration(); 1148 1149 if (nullAllowed) { 1150 out.println(indent + "if (" + cname + ") {"); 1151 } else { 1152 needsExit = true; 1153 out.println(indent + "if (!" + cname + ") {"); 1154 out.println(indent + indent + "_exception = 1;"); 1155 out.println(indent + indent + 1156 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1157 out.println(indent + indent + 1158 "_exceptionMessage = \"" + cname + " == null\";"); 1159 out.println(indent + indent + "goto exit;"); 1160 out.println(indent + "}"); 1161 } 1162 1163 out.println(nullAllowedIndent + indent + "_native" + cname + 1164 " = _env->GetStringUTFChars(" + cname + ", 0);"); 1165 1166 emitStringCheck(cfunc, cname, out, nullAllowedIndent + indent); 1167 1168 if (nullAllowed) { 1169 out.println(indent + "}"); 1170 } 1171 } 1172 1173 out.println(); 1174 } 1175 1176 // Emit 'GetPrimitiveArrayCritical' for non-object arrays 1177 // Emit 'GetPointer' calls for Buffer pointers 1178 if (nonPrimitiveArgs.size() > 0) { 1179 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1180 int idx = nonPrimitiveArgs.get(i).intValue(); 1181 int cIndex = jfunc.getArgCIndex(idx); 1182 1183 String cname = cfunc.getArgName(cIndex); 1184 offset = numArrays <= 1 ? "offset" : 1185 cname + "Offset"; 1186 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1187 "_" + cname + "Remaining"; 1188 1189 boolean nullAllowed = isNullAllowed(cfunc, cname); 1190 String nullAllowedIndent = nullAllowed ? indent : ""; 1191 1192 if (jfunc.getArgType(idx).isArray() 1193 && !jfunc.getArgType(idx).isEGLHandle()) { 1194 needsExit = true; 1195 1196 if (nullAllowed) { 1197 out.println(indent + "if (" + cname + "_ref) {"); 1198 } 1199 else 1200 { 1201 out.println(indent + "if (!" + cname + "_ref) {"); 1202 out.println(indent + indent + "_exception = 1;"); 1203 out.println(indent + indent + 1204 "_exceptionType = " + 1205 "\"java/lang/IllegalArgumentException\";"); 1206 out.println(indent + indent + 1207 "_exceptionMessage = \"" + cname + 1208 " == null\";"); 1209 out.println(indent + indent + "goto exit;"); 1210 out.println(indent + "}"); 1211 } 1212 1213 out.println(nullAllowedIndent + indent + "if (" + offset + 1214 " < 0) {"); 1215 out.println(nullAllowedIndent + indent + indent + 1216 "_exception = 1;"); 1217 out.println(nullAllowedIndent + indent + indent + 1218 "_exceptionType = " + 1219 "\"java/lang/IllegalArgumentException\";"); 1220 out.println(nullAllowedIndent + indent + indent + 1221 "_exceptionMessage = \"" + offset +" < 0\";"); 1222 out.println(nullAllowedIndent + indent + indent + 1223 "goto exit;"); 1224 out.println(nullAllowedIndent + indent + "}"); 1225 1226 out.println(nullAllowedIndent + indent + remaining + " = " + 1227 (mUseCPlusPlus ? "_env" : "(*_env)") + 1228 "->GetArrayLength(" + 1229 (mUseCPlusPlus ? "" : "_env, ") + 1230 cname + "_ref) - " + offset + ";"); 1231 1232 emitNativeBoundsChecks(cfunc, cname, out, false, 1233 emitExceptionCheck, offset, remaining, 1234 nullAllowedIndent + indent); 1235 1236 out.println(nullAllowedIndent + indent + 1237 cname + 1238 "_base = (" + 1239 cfunc.getArgType(cIndex).getDeclaration() + 1240 ")"); 1241 String arrayGetter = jfunc.getArgType(idx).getArrayGetterForPrimitiveArray(); 1242 out.println(nullAllowedIndent + indent + " " + 1243 (mUseCPlusPlus ? "_env" : "(*_env)") + 1244 "->" + arrayGetter + "(" + 1245 (mUseCPlusPlus ? "" : "_env, ") + 1246 jfunc.getArgName(idx) + 1247 "_ref, (jboolean *)0);"); 1248 out.println(nullAllowedIndent + indent + 1249 cname + " = " + cname + "_base + " + offset + ";"); 1250 1251 emitSentinelCheck(cfunc, cname, out, false, 1252 emitExceptionCheck, offset, remaining, 1253 nullAllowedIndent + indent); 1254 1255 if (nullAllowed) { 1256 out.println(indent + "}"); 1257 } 1258 1259 out.println(); 1260 } else if (jfunc.getArgType(idx).isArray() 1261 && jfunc.getArgType(idx).isEGLHandle()) { 1262 needsExit = true; 1263 1264 if (nullAllowed) { 1265 out.println(indent + "if (" + cname + "_ref) {"); 1266 } 1267 else 1268 { 1269 out.println(indent + "if (!" + cname + "_ref) {"); 1270 out.println(indent + indent + "_exception = 1;"); 1271 out.println(indent + indent + "_exceptionType = " + 1272 "\"java/lang/IllegalArgumentException\";"); 1273 out.println(indent + indent + "_exceptionMessage = \"" + 1274 cname +" == null\";"); 1275 out.println(indent + indent + "goto exit;"); 1276 out.println(indent + "}"); 1277 } 1278 1279 out.println(nullAllowedIndent + indent + "if (" + offset + 1280 " < 0) {"); 1281 out.println(nullAllowedIndent + indent + indent + 1282 "_exception = 1;"); 1283 out.println(nullAllowedIndent + indent + indent + 1284 "_exceptionType = " + 1285 "\"java/lang/IllegalArgumentException\";"); 1286 out.println(nullAllowedIndent + indent + indent + 1287 "_exceptionMessage = \"" + offset +" < 0\";"); 1288 out.println(nullAllowedIndent + indent + indent + 1289 "goto exit;"); 1290 out.println(nullAllowedIndent + indent + "}"); 1291 1292 out.println(nullAllowedIndent + indent + remaining + " = " + 1293 (mUseCPlusPlus ? "_env" : "(*_env)") + 1294 "->GetArrayLength(" + 1295 (mUseCPlusPlus ? "" : "_env, ") + 1296 cname + "_ref) - " + offset + ";"); 1297 emitNativeBoundsChecks(cfunc, cname, out, false, 1298 emitExceptionCheck, offset, remaining, 1299 nullAllowedIndent + indent); 1300 out.println(nullAllowedIndent + indent + 1301 jfunc.getArgName(idx) + " = new " + 1302 cfunc.getArgType(cIndex).getBaseType() + 1303 "["+ remaining + "];"); 1304 1305 if (nullAllowed) { 1306 out.println(indent + "}"); 1307 } 1308 1309 out.println(); 1310 } else if (jfunc.getArgType(idx).isBuffer()) { 1311 String array = numBufferArgs <= 1 ? "_array" : 1312 "_" + cfunc.getArgName(cIndex) + "Array"; 1313 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1314 "_" + cfunc.getArgName(cIndex) + "BufferOffset"; 1315 1316 nullAllowed = nullAllowed || isPointerFunc; 1317 if (nullAllowed) { 1318 out.println(indent + "if (" + cname + "_buf) {"); 1319 out.print(indent); 1320 } 1321 1322 if (isPointerFunc) { 1323 out.println(indent + 1324 cname + 1325 " = (" + 1326 cfunc.getArgType(cIndex).getDeclaration() + 1327 ") getDirectBufferPointer(_env, " + 1328 cname + "_buf);"); 1329 String iii = " "; 1330 out.println(iii + indent + "if ( ! " + cname + " ) {"); 1331 out.println(iii + indent + indent + "return;"); 1332 out.println(iii + indent + "}"); 1333 } else { 1334 out.println(indent + 1335 cname + 1336 " = (" + 1337 cfunc.getArgType(cIndex).getDeclaration() + 1338 ")getPointer(_env, " + 1339 cname + 1340 "_buf, (jarray*)&" + array + ", &" + remaining + ", &" + bufferOffset + 1341 ");"); 1342 } 1343 1344 emitNativeBoundsChecks(cfunc, cname, out, true, 1345 emitExceptionCheck, 1346 offset, remaining, nullAllowed ? " " : " "); 1347 1348 if (nullAllowed) { 1349 out.println(indent + "}"); 1350 } 1351 } 1352 } 1353 } 1354 1355 // Emit 'GetPrimitiveArrayCritical' for pointers if needed 1356 if (nonPrimitiveArgs.size() > 0) { 1357 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1358 int idx = nonPrimitiveArgs.get(i).intValue(); 1359 int cIndex = jfunc.getArgCIndex(idx); 1360 1361 if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue; 1362 1363 String cname = cfunc.getArgName(cIndex); 1364 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1365 "_" + cname + "BufferOffset"; 1366 String array = numBufferArgs <= 1 ? "_array" : 1367 "_" + cfunc.getArgName(cIndex) + "Array"; 1368 1369 boolean nullAllowed = isNullAllowed(cfunc, cname) || 1370 isPointerFunc; 1371 if (nullAllowed) { 1372 out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {"); 1373 } else { 1374 out.println(indent + "if (" + cname +" == NULL) {"); 1375 } 1376 JType argType = jfunc.getArgType(idx); 1377 if (argType.isTypedBuffer()) { 1378 String arrayGetter = argType.getArrayTypeForTypedBuffer().getArrayGetterForPrimitiveArray(); 1379 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->" + arrayGetter + "(" + array + ", (jboolean *) 0);"); 1380 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); 1381 out.println(indent + "}"); 1382 } else { 1383 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); 1384 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); 1385 out.println(indent + "}"); 1386 } 1387 } 1388 } 1389 1390 1391 if (!isVoid) { 1392 out.print(indent + "_returnValue = "); 1393 } else { 1394 out.print(indent); 1395 } 1396 String name = cfunc.getName(); 1397 1398 if (mUseContextPointer) { 1399 name = name.substring(2, name.length()); // Strip off 'gl' prefix 1400 name = name.substring(0, 1).toLowerCase() + 1401 name.substring(1, name.length()); 1402 out.print("ctx->procs."); 1403 } 1404 1405 out.print(name + (isPointerFunc ? "Bounds" : "") + "("); 1406 1407 numArgs = cfunc.getNumArgs(); 1408 if (numArgs == 0) { 1409 if (mUseContextPointer) { 1410 out.println("ctx);"); 1411 } else { 1412 out.println(");"); 1413 } 1414 } else { 1415 if (mUseContextPointer) { 1416 out.println("ctx,"); 1417 } else { 1418 out.println(); 1419 } 1420 for (int i = 0; i < numArgs; i++) { 1421 String typecast; 1422 if (i == numArgs - 1 && isPointerOffsetFunc) { 1423 typecast = "reinterpret_cast<GLvoid *>"; 1424 } else { 1425 typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; 1426 } 1427 out.print(indent + indent + 1428 typecast); 1429 1430 if (cfunc.getArgType(i).isConstCharPointer()) { 1431 out.print("_native"); 1432 } 1433 1434 if (cfunc.getArgType(i).isEGLHandle() && 1435 !cfunc.getArgType(i).isPointer()){ 1436 out.print(cfunc.getArgName(i)+"_native"); 1437 } else if (i == numArgs - 1 && isPointerOffsetFunc){ 1438 out.print("("+cfunc.getArgName(i)+")"); 1439 } else { 1440 out.print(cfunc.getArgName(i)); 1441 } 1442 1443 if (i == numArgs - 1) { 1444 if (isPointerFunc) { 1445 out.println(","); 1446 out.println(indent + indent + "(GLsizei)remaining"); 1447 } else { 1448 out.println(); 1449 } 1450 } else { 1451 out.println(","); 1452 } 1453 } 1454 out.println(indent + ");"); 1455 } 1456 1457 if (needsExit) { 1458 out.println(); 1459 out.println("exit:"); 1460 needsExit = false; 1461 } 1462 1463 1464 if (nonPrimitiveArgs.size() > 0) { 1465 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1466 int idx = nonPrimitiveArgs.get(i).intValue(); 1467 1468 int cIndex = jfunc.getArgCIndex(idx); 1469 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1470 1471 // If the argument is 'const', GL will not write to it. 1472 // In this case, we can use the 'JNI_ABORT' flag to avoid 1473 // the need to write back to the Java array 1474 out.println(indent + 1475 "if (" + jfunc.getArgName(idx) + "_base) {"); 1476 String arrayReleaser = jfunc.getArgType(idx).getArrayReleaserForPrimitiveArray(); 1477 out.println(indent + indent + 1478 (mUseCPlusPlus ? "_env" : "(*_env)") + 1479 "->" + arrayReleaser + "(" + 1480 (mUseCPlusPlus ? "" : "_env, ") + 1481 jfunc.getArgName(idx) + "_ref, " + 1482 "(j" + jfunc.getArgType(idx).getBaseType() + "*)" + cfunc.getArgName(cIndex) + 1483 "_base,"); 1484 out.println(indent + indent + indent + 1485 (cfunc.getArgType(cIndex).isConst() ? 1486 "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + 1487 ");"); 1488 out.println(indent + "}"); 1489 } else if (jfunc.getArgType(idx).isBuffer()) { 1490 if (! isPointerFunc) { 1491 JType argType = jfunc.getArgType(idx); 1492 String array = numBufferArgs <= 1 ? "_array" : 1493 "_" + cfunc.getArgName(cIndex) + "Array"; 1494 out.println(indent + "if (" + array + ") {"); 1495 if (argType.isTypedBuffer()) { 1496 String arrayReleaser = 1497 argType.getArrayTypeForTypedBuffer().getArrayReleaserForPrimitiveArray(); 1498 out.println(indent + indent + 1499 "_env->" + arrayReleaser + "(" + array + ", " + 1500 "(j" + argType.getArrayTypeForTypedBuffer().getBaseType() + "*)" + 1501 cfunc.getArgName(cIndex) + 1502 ", " + 1503 (cfunc.getArgType(cIndex).isConst() ? 1504 "JNI_ABORT" : (emitExceptionCheck ? 1505 "_exception ? JNI_ABORT : 0" : "0")) + 1506 ");"); 1507 } else { 1508 out.println(indent + indent + 1509 "releasePointer(_env, " + array + ", " + 1510 cfunc.getArgName(cIndex) + 1511 ", " + 1512 (cfunc.getArgType(cIndex).isConst() ? 1513 "JNI_FALSE" : (emitExceptionCheck ? 1514 "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + 1515 ");"); 1516 } 1517 out.println(indent + "}"); 1518 } 1519 } 1520 } 1521 } 1522 1523 // Emit local variable declaration for strings 1524 if (stringArgs.size() > 0) { 1525 for (int i = 0; i < stringArgs.size(); i++) { 1526 int idx = stringArgs.get(i).intValue(); 1527 int cIndex = jfunc.getArgCIndex(idx); 1528 String cname = cfunc.getArgName(cIndex); 1529 1530 out.println(indent + "if (_native" + cname + ") {"); 1531 out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");"); 1532 out.println(indent + "}"); 1533 } 1534 1535 out.println(); 1536 } 1537 1538 // Copy results back to java arrays 1539 if (nonPrimitiveArgs.size() > 0) { 1540 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1541 int idx = nonPrimitiveArgs.get(i).intValue(); 1542 int cIndex = jfunc.getArgCIndex(idx); 1543 String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); 1544 if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { 1545 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1546 "_" + cfunc.getArgName(cIndex) + "Remaining"; 1547 offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; 1548 out.println(indent + 1549 "if (" + jfunc.getArgName(idx) + ") {"); 1550 out.println(indent + indent + 1551 "for (int i = 0; i < " + remaining + "; i++) {"); 1552 out.println(indent + indent + indent + 1553 "jobject " + cfunc.getArgName(cIndex) + 1554 "_new = toEGLHandle(_env, " + baseType + 1555 "Class, " + baseType + "Constructor, " + 1556 cfunc.getArgName(cIndex) + "[i]);"); 1557 out.println(indent + indent + indent + 1558 (mUseCPlusPlus ? "_env" : "(*_env)") + 1559 "->SetObjectArrayElement(" + 1560 (mUseCPlusPlus ? "" : "_env, ") + 1561 cfunc.getArgName(cIndex) + 1562 "_ref, i + " + offset + ", " + 1563 cfunc.getArgName(cIndex) + "_new);"); 1564 out.println(indent + indent + "}"); 1565 out.println(indent + indent + 1566 "delete[] " + jfunc.getArgName(idx) + ";"); 1567 out.println(indent + "}"); 1568 } 1569 } 1570 } 1571 1572 1573 // Throw exception if there is one 1574 if (emitExceptionCheck) { 1575 out.println(indent + "if (_exception) {"); 1576 out.println(indent + indent + 1577 "jniThrowException(_env, _exceptionType, _exceptionMessage);"); 1578 out.println(indent + "}"); 1579 1580 } 1581 1582 1583 if (!isVoid) { 1584 if (cfunc.getType().isEGLHandle()) { 1585 String baseType = cfunc.getType().getBaseType().toLowerCase(); 1586 out.println(indent + 1587 "return toEGLHandle(_env, " + baseType + "Class, " + 1588 baseType + "Constructor, _returnValue);"); 1589 } else { 1590 out.println(indent + "return (" + 1591 getJniType(jfunc.getType()) + ")_returnValue;"); 1592 } 1593 } 1594 1595 out.println("}"); 1596 out.println(); 1597 } 1598 1599 } 1600