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