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 || (numBufferArgs > 0) 989 || hasCheckTest(cfunc) 990 || hasIfTest(cfunc)) 991 || (stringArgs.size() > 0); 992 // mChecker.getChecks(cfunc.getName()) != null 993 // Emit an _exeption variable if there will be error checks 994 if (emitExceptionCheck) { 995 out.println(indent + "jint _exception = 0;"); 996 out.println(indent + "const char * _exceptionType = NULL;"); 997 out.println(indent + "const char * _exceptionMessage = NULL;"); 998 } 999 1000 // Emit a single _array or multiple _XXXArray variables 1001 if (numBufferArgs == 1) { 1002 JType bufferType = bufferArgTypes.get(0); 1003 if (bufferType.isTypedBuffer()) { 1004 String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer()); 1005 out.println(indent + typedArrayType + " _array = (" + typedArrayType + ") 0;"); 1006 } else { 1007 out.println(indent + "jarray _array = (jarray) 0;"); 1008 } 1009 out.println(indent + "jint _bufferOffset = (jint) 0;"); 1010 } else { 1011 for (int i = 0; i < numBufferArgs; i++) { 1012 JType bufferType = bufferArgTypes.get(0); 1013 if (bufferType.isTypedBuffer()) { 1014 String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer()); 1015 out.println(indent + typedArrayType + " _" + bufferArgNames.get(i) + 1016 "Array = (" + typedArrayType + ") 0;"); 1017 } else { 1018 out.println(indent + "jarray _" + bufferArgNames.get(i) + 1019 "Array = (jarray) 0;"); 1020 } 1021 out.println(indent + "jint _" + bufferArgNames.get(i) + 1022 "BufferOffset = (jint) 0;"); 1023 } 1024 } 1025 if (!isVoid) { 1026 String retval = getErrorReturnValue(cfunc); 1027 if (retval != null) { 1028 out.println(indent + returnType.getDeclaration() + 1029 " _returnValue = " + retval + ";"); 1030 } else if (initializeReturnValue) { 1031 out.println(indent + returnType.getDeclaration() + 1032 " _returnValue = 0;"); 1033 } else { 1034 out.println(indent + returnType.getDeclaration() + 1035 " _returnValue;"); 1036 } 1037 } 1038 1039 // Emit local variable declarations for EGL Handles 1040 // 1041 // Example: 1042 // 1043 // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface); 1044 // 1045 if (nonPrimitiveArgs.size() > 0) { 1046 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1047 int idx = nonPrimitiveArgs.get(i).intValue(); 1048 int cIndex = jfunc.getArgCIndex(idx); 1049 String cname = cfunc.getArgName(cIndex); 1050 1051 if (jfunc.getArgType(idx).isBuffer() 1052 || jfunc.getArgType(idx).isArray() 1053 || !jfunc.getArgType(idx).isEGLHandle()) 1054 continue; 1055 1056 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1057 String decl = type.getDeclaration(); 1058 out.println(indent + 1059 decl + " " + cname + "_native = (" + 1060 decl + ") fromEGLHandle(_env, " + 1061 type.getBaseType().toLowerCase() + 1062 "GetHandleID, " + jfunc.getArgName(idx) + 1063 ");"); 1064 } 1065 } 1066 1067 // Emit local variable declarations for element/sentinel checks 1068 // 1069 // Example: 1070 // 1071 // bool attrib_list_sentinel_found = false; 1072 // 1073 emitLocalVariablesForSentinel(cfunc, out); 1074 1075 // Emit local variable declarations for pointer arguments 1076 // 1077 // Example: 1078 // 1079 // GLfixed *eqn_base; 1080 // GLfixed *eqn; 1081 // 1082 String offset = "offset"; 1083 String remaining = "_remaining"; 1084 if (nonPrimitiveArgs.size() > 0) { 1085 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1086 int idx = nonPrimitiveArgs.get(i).intValue(); 1087 int cIndex = jfunc.getArgCIndex(idx); 1088 String cname = cfunc.getArgName(cIndex); 1089 1090 if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray()) 1091 continue; 1092 1093 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1094 String decl = type.getDeclaration(); 1095 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1096 out.println(indent + 1097 decl + 1098 (decl.endsWith("*") ? "" : " ") + 1099 jfunc.getArgName(idx) + 1100 "_base = (" + decl + ") 0;"); 1101 } 1102 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1103 "_" + cname + "Remaining"; 1104 out.println(indent + 1105 "jint " + remaining + ";"); 1106 out.println(indent + 1107 decl + 1108 (decl.endsWith("*") ? "" : " ") + 1109 jfunc.getArgName(idx) + 1110 " = (" + decl + ") 0;"); 1111 } 1112 1113 out.println(); 1114 } 1115 1116 // Emit local variable declaration for strings 1117 if (stringArgs.size() > 0) { 1118 boolean requiresStringLengthCheck = false; 1119 for (int i = 0; i < stringArgs.size(); i++) { 1120 int idx = stringArgs.get(i).intValue(); 1121 int cIndex = jfunc.getArgCIndex(idx); 1122 String cname = cfunc.getArgName(cIndex); 1123 1124 out.println(indent + "const char* _native" + cname + " = 0;"); 1125 if (hasCheckTest(cfunc, cname)) { 1126 requiresStringLengthCheck = true; 1127 } 1128 } 1129 1130 if (requiresStringLengthCheck) { 1131 out.println(indent + "jsize _stringlen = 0;"); 1132 } 1133 1134 out.println(); 1135 } 1136 1137 // Null pointer checks and GetStringUTFChars 1138 if (stringArgs.size() > 0) { 1139 for (int i = 0; i < stringArgs.size(); i++) { 1140 int idx = stringArgs.get(i).intValue(); 1141 int cIndex = jfunc.getArgCIndex(idx); 1142 String cname = cfunc.getArgName(cIndex); 1143 1144 boolean nullAllowed = isNullAllowed(cfunc, cname); 1145 String nullAllowedIndent = nullAllowed ? indent : ""; 1146 1147 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1148 String decl = type.getDeclaration(); 1149 1150 if (nullAllowed) { 1151 out.println(indent + "if (" + cname + ") {"); 1152 } else { 1153 needsExit = true; 1154 out.println(indent + "if (!" + cname + ") {"); 1155 out.println(indent + indent + "_exception = 1;"); 1156 out.println(indent + indent + 1157 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1158 out.println(indent + indent + 1159 "_exceptionMessage = \"" + cname + " == null\";"); 1160 out.println(indent + indent + "goto exit;"); 1161 out.println(indent + "}"); 1162 } 1163 1164 out.println(nullAllowedIndent + indent + "_native" + cname + 1165 " = _env->GetStringUTFChars(" + cname + ", 0);"); 1166 1167 emitStringCheck(cfunc, cname, out, nullAllowedIndent + indent); 1168 1169 if (nullAllowed) { 1170 out.println(indent + "}"); 1171 } 1172 } 1173 1174 out.println(); 1175 } 1176 1177 // Emit 'GetPrimitiveArrayCritical' for non-object arrays 1178 // Emit 'GetPointer' calls for Buffer pointers 1179 if (nonPrimitiveArgs.size() > 0) { 1180 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1181 int idx = nonPrimitiveArgs.get(i).intValue(); 1182 int cIndex = jfunc.getArgCIndex(idx); 1183 1184 String cname = cfunc.getArgName(cIndex); 1185 offset = numArrays <= 1 ? "offset" : 1186 cname + "Offset"; 1187 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1188 "_" + cname + "Remaining"; 1189 1190 boolean nullAllowed = isNullAllowed(cfunc, cname); 1191 String nullAllowedIndent = nullAllowed ? indent : ""; 1192 1193 if (jfunc.getArgType(idx).isArray() 1194 && !jfunc.getArgType(idx).isEGLHandle()) { 1195 needsExit = true; 1196 1197 if (nullAllowed) { 1198 out.println(indent + "if (" + cname + "_ref) {"); 1199 } 1200 else 1201 { 1202 out.println(indent + "if (!" + cname + "_ref) {"); 1203 out.println(indent + indent + "_exception = 1;"); 1204 out.println(indent + indent + 1205 "_exceptionType = " + 1206 "\"java/lang/IllegalArgumentException\";"); 1207 out.println(indent + indent + 1208 "_exceptionMessage = \"" + cname + 1209 " == null\";"); 1210 out.println(indent + indent + "goto exit;"); 1211 out.println(indent + "}"); 1212 } 1213 1214 out.println(nullAllowedIndent + indent + "if (" + offset + 1215 " < 0) {"); 1216 out.println(nullAllowedIndent + indent + indent + 1217 "_exception = 1;"); 1218 out.println(nullAllowedIndent + indent + indent + 1219 "_exceptionType = " + 1220 "\"java/lang/IllegalArgumentException\";"); 1221 out.println(nullAllowedIndent + indent + indent + 1222 "_exceptionMessage = \"" + offset +" < 0\";"); 1223 out.println(nullAllowedIndent + indent + indent + 1224 "goto exit;"); 1225 out.println(nullAllowedIndent + indent + "}"); 1226 1227 out.println(nullAllowedIndent + indent + remaining + " = " + 1228 (mUseCPlusPlus ? "_env" : "(*_env)") + 1229 "->GetArrayLength(" + 1230 (mUseCPlusPlus ? "" : "_env, ") + 1231 cname + "_ref) - " + offset + ";"); 1232 1233 emitNativeBoundsChecks(cfunc, cname, out, false, 1234 emitExceptionCheck, offset, remaining, 1235 nullAllowedIndent + indent); 1236 1237 out.println(nullAllowedIndent + indent + 1238 cname + 1239 "_base = (" + 1240 cfunc.getArgType(cIndex).getDeclaration() + 1241 ")"); 1242 String arrayGetter = jfunc.getArgType(idx).getArrayGetterForPrimitiveArray(); 1243 out.println(nullAllowedIndent + indent + " " + 1244 (mUseCPlusPlus ? "_env" : "(*_env)") + 1245 "->" + arrayGetter + "(" + 1246 (mUseCPlusPlus ? "" : "_env, ") + 1247 jfunc.getArgName(idx) + 1248 "_ref, (jboolean *)0);"); 1249 out.println(nullAllowedIndent + indent + 1250 cname + " = " + cname + "_base + " + offset + ";"); 1251 1252 emitSentinelCheck(cfunc, cname, out, false, 1253 emitExceptionCheck, offset, remaining, 1254 nullAllowedIndent + indent); 1255 1256 if (nullAllowed) { 1257 out.println(indent + "}"); 1258 } 1259 1260 out.println(); 1261 } else if (jfunc.getArgType(idx).isArray() 1262 && jfunc.getArgType(idx).isEGLHandle()) { 1263 needsExit = true; 1264 1265 if (nullAllowed) { 1266 out.println(indent + "if (" + cname + "_ref) {"); 1267 } 1268 else 1269 { 1270 out.println(indent + "if (!" + cname + "_ref) {"); 1271 out.println(indent + indent + "_exception = 1;"); 1272 out.println(indent + indent + "_exceptionType = " + 1273 "\"java/lang/IllegalArgumentException\";"); 1274 out.println(indent + indent + "_exceptionMessage = \"" + 1275 cname +" == null\";"); 1276 out.println(indent + indent + "goto exit;"); 1277 out.println(indent + "}"); 1278 } 1279 1280 out.println(nullAllowedIndent + indent + "if (" + offset + 1281 " < 0) {"); 1282 out.println(nullAllowedIndent + indent + indent + 1283 "_exception = 1;"); 1284 out.println(nullAllowedIndent + indent + indent + 1285 "_exceptionType = " + 1286 "\"java/lang/IllegalArgumentException\";"); 1287 out.println(nullAllowedIndent + indent + indent + 1288 "_exceptionMessage = \"" + offset +" < 0\";"); 1289 out.println(nullAllowedIndent + indent + indent + 1290 "goto exit;"); 1291 out.println(nullAllowedIndent + indent + "}"); 1292 1293 out.println(nullAllowedIndent + indent + remaining + " = " + 1294 (mUseCPlusPlus ? "_env" : "(*_env)") + 1295 "->GetArrayLength(" + 1296 (mUseCPlusPlus ? "" : "_env, ") + 1297 cname + "_ref) - " + offset + ";"); 1298 emitNativeBoundsChecks(cfunc, cname, out, false, 1299 emitExceptionCheck, offset, remaining, 1300 nullAllowedIndent + indent); 1301 out.println(nullAllowedIndent + indent + 1302 jfunc.getArgName(idx) + " = new " + 1303 cfunc.getArgType(cIndex).getBaseType() + 1304 "["+ remaining + "];"); 1305 1306 if (nullAllowed) { 1307 out.println(indent + "}"); 1308 } 1309 1310 out.println(); 1311 } else if (jfunc.getArgType(idx).isBuffer()) { 1312 needsExit = needsExit || (!nullAllowed && !isPointerFunc); 1313 1314 String array = numBufferArgs <= 1 ? "_array" : 1315 "_" + cfunc.getArgName(cIndex) + "Array"; 1316 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1317 "_" + cfunc.getArgName(cIndex) + "BufferOffset"; 1318 1319 nullAllowed = nullAllowed || isPointerFunc; 1320 if (nullAllowed) { 1321 out.println(indent + "if (" + cname + "_buf) {"); 1322 out.print(indent); 1323 } 1324 else 1325 { 1326 out.println(indent + "if (!" + cname + "_buf) {"); 1327 out.println(indent + indent + "_exception = 1;"); 1328 out.println(indent + indent + "_exceptionType = " + 1329 "\"java/lang/IllegalArgumentException\";"); 1330 out.println(indent + indent + "_exceptionMessage = \"" + 1331 cname +" == null\";"); 1332 out.println(indent + indent + "goto exit;"); 1333 out.println(indent + "}"); 1334 } 1335 1336 if (isPointerFunc) { 1337 out.println(indent + 1338 cname + 1339 " = (" + 1340 cfunc.getArgType(cIndex).getDeclaration() + 1341 ") getDirectBufferPointer(_env, " + 1342 cname + "_buf);"); 1343 String iii = " "; 1344 out.println(iii + indent + "if ( ! " + cname + " ) {"); 1345 out.println(iii + indent + indent + "return;"); 1346 out.println(iii + indent + "}"); 1347 } else { 1348 out.println(indent + 1349 cname + 1350 " = (" + 1351 cfunc.getArgType(cIndex).getDeclaration() + 1352 ")getPointer(_env, " + 1353 cname + 1354 "_buf, (jarray*)&" + array + ", &" + remaining + ", &" + bufferOffset + 1355 ");"); 1356 } 1357 1358 emitNativeBoundsChecks(cfunc, cname, out, true, 1359 emitExceptionCheck, 1360 offset, remaining, nullAllowed ? " " : " "); 1361 1362 if (nullAllowed) { 1363 out.println(indent + "}"); 1364 } 1365 } 1366 } 1367 } 1368 1369 // Emit 'GetPrimitiveArrayCritical' for pointers if needed 1370 if (nonPrimitiveArgs.size() > 0) { 1371 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1372 int idx = nonPrimitiveArgs.get(i).intValue(); 1373 int cIndex = jfunc.getArgCIndex(idx); 1374 1375 if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue; 1376 1377 String cname = cfunc.getArgName(cIndex); 1378 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1379 "_" + cname + "BufferOffset"; 1380 String array = numBufferArgs <= 1 ? "_array" : 1381 "_" + cfunc.getArgName(cIndex) + "Array"; 1382 1383 boolean nullAllowed = isNullAllowed(cfunc, cname) || 1384 isPointerFunc; 1385 if (nullAllowed) { 1386 out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {"); 1387 } else { 1388 out.println(indent + "if (" + cname +" == NULL) {"); 1389 } 1390 JType argType = jfunc.getArgType(idx); 1391 if (argType.isTypedBuffer()) { 1392 String arrayGetter = argType.getArrayTypeForTypedBuffer().getArrayGetterForPrimitiveArray(); 1393 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->" + arrayGetter + "(" + array + ", (jboolean *) 0);"); 1394 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); 1395 out.println(indent + "}"); 1396 } else { 1397 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); 1398 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); 1399 out.println(indent + "}"); 1400 } 1401 } 1402 } 1403 1404 1405 if (!isVoid) { 1406 out.print(indent + "_returnValue = "); 1407 } else { 1408 out.print(indent); 1409 } 1410 String name = cfunc.getName(); 1411 1412 if (mUseContextPointer) { 1413 name = name.substring(2, name.length()); // Strip off 'gl' prefix 1414 name = name.substring(0, 1).toLowerCase() + 1415 name.substring(1, name.length()); 1416 out.print("ctx->procs."); 1417 } 1418 1419 out.print(name + (isPointerFunc ? "Bounds" : "") + "("); 1420 1421 numArgs = cfunc.getNumArgs(); 1422 if (numArgs == 0) { 1423 if (mUseContextPointer) { 1424 out.println("ctx);"); 1425 } else { 1426 out.println(");"); 1427 } 1428 } else { 1429 if (mUseContextPointer) { 1430 out.println("ctx,"); 1431 } else { 1432 out.println(); 1433 } 1434 for (int i = 0; i < numArgs; i++) { 1435 String typecast; 1436 if (i == numArgs - 1 && isPointerOffsetFunc) { 1437 typecast = "reinterpret_cast<GLvoid *>"; 1438 } else { 1439 typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; 1440 } 1441 out.print(indent + indent + 1442 typecast); 1443 1444 if (cfunc.getArgType(i).isConstCharPointer()) { 1445 out.print("_native"); 1446 } 1447 1448 if (cfunc.getArgType(i).isEGLHandle() && 1449 !cfunc.getArgType(i).isPointer()){ 1450 out.print(cfunc.getArgName(i)+"_native"); 1451 } else if (i == numArgs - 1 && isPointerOffsetFunc){ 1452 out.print("("+cfunc.getArgName(i)+")"); 1453 } else { 1454 out.print(cfunc.getArgName(i)); 1455 } 1456 1457 if (i == numArgs - 1) { 1458 if (isPointerFunc) { 1459 out.println(","); 1460 out.println(indent + indent + "(GLsizei)remaining"); 1461 } else { 1462 out.println(); 1463 } 1464 } else { 1465 out.println(","); 1466 } 1467 } 1468 out.println(indent + ");"); 1469 } 1470 1471 if (needsExit) { 1472 out.println(); 1473 out.println("exit:"); 1474 needsExit = false; 1475 } 1476 1477 1478 if (nonPrimitiveArgs.size() > 0) { 1479 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1480 int idx = nonPrimitiveArgs.get(i).intValue(); 1481 1482 int cIndex = jfunc.getArgCIndex(idx); 1483 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1484 1485 // If the argument is 'const', GL will not write to it. 1486 // In this case, we can use the 'JNI_ABORT' flag to avoid 1487 // the need to write back to the Java array 1488 out.println(indent + 1489 "if (" + jfunc.getArgName(idx) + "_base) {"); 1490 String arrayReleaser = jfunc.getArgType(idx).getArrayReleaserForPrimitiveArray(); 1491 out.println(indent + indent + 1492 (mUseCPlusPlus ? "_env" : "(*_env)") + 1493 "->" + arrayReleaser + "(" + 1494 (mUseCPlusPlus ? "" : "_env, ") + 1495 jfunc.getArgName(idx) + "_ref, " + 1496 "(j" + jfunc.getArgType(idx).getBaseType() + "*)" + cfunc.getArgName(cIndex) + 1497 "_base,"); 1498 out.println(indent + indent + indent + 1499 (cfunc.getArgType(cIndex).isConst() ? 1500 "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + 1501 ");"); 1502 out.println(indent + "}"); 1503 } else if (jfunc.getArgType(idx).isBuffer()) { 1504 if (! isPointerFunc) { 1505 JType argType = jfunc.getArgType(idx); 1506 String array = numBufferArgs <= 1 ? "_array" : 1507 "_" + cfunc.getArgName(cIndex) + "Array"; 1508 out.println(indent + "if (" + array + ") {"); 1509 if (argType.isTypedBuffer()) { 1510 String arrayReleaser = 1511 argType.getArrayTypeForTypedBuffer().getArrayReleaserForPrimitiveArray(); 1512 out.println(indent + indent + 1513 "_env->" + arrayReleaser + "(" + array + ", " + 1514 "(j" + argType.getArrayTypeForTypedBuffer().getBaseType() + "*)" + 1515 cfunc.getArgName(cIndex) + 1516 ", " + 1517 (cfunc.getArgType(cIndex).isConst() ? 1518 "JNI_ABORT" : (emitExceptionCheck ? 1519 "_exception ? JNI_ABORT : 0" : "0")) + 1520 ");"); 1521 } else { 1522 out.println(indent + indent + 1523 "releasePointer(_env, " + array + ", " + 1524 cfunc.getArgName(cIndex) + 1525 ", " + 1526 (cfunc.getArgType(cIndex).isConst() ? 1527 "JNI_FALSE" : (emitExceptionCheck ? 1528 "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + 1529 ");"); 1530 } 1531 out.println(indent + "}"); 1532 } 1533 } 1534 } 1535 } 1536 1537 // Emit local variable declaration for strings 1538 if (stringArgs.size() > 0) { 1539 for (int i = 0; i < stringArgs.size(); i++) { 1540 int idx = stringArgs.get(i).intValue(); 1541 int cIndex = jfunc.getArgCIndex(idx); 1542 String cname = cfunc.getArgName(cIndex); 1543 1544 out.println(indent + "if (_native" + cname + ") {"); 1545 out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");"); 1546 out.println(indent + "}"); 1547 } 1548 1549 out.println(); 1550 } 1551 1552 // Copy results back to java arrays 1553 if (nonPrimitiveArgs.size() > 0) { 1554 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1555 int idx = nonPrimitiveArgs.get(i).intValue(); 1556 int cIndex = jfunc.getArgCIndex(idx); 1557 String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); 1558 if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { 1559 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1560 "_" + cfunc.getArgName(cIndex) + "Remaining"; 1561 offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; 1562 out.println(indent + 1563 "if (" + jfunc.getArgName(idx) + ") {"); 1564 out.println(indent + indent + 1565 "for (int i = 0; i < " + remaining + "; i++) {"); 1566 out.println(indent + indent + indent + 1567 "jobject " + cfunc.getArgName(cIndex) + 1568 "_new = toEGLHandle(_env, " + baseType + 1569 "Class, " + baseType + "Constructor, " + 1570 cfunc.getArgName(cIndex) + "[i]);"); 1571 out.println(indent + indent + indent + 1572 (mUseCPlusPlus ? "_env" : "(*_env)") + 1573 "->SetObjectArrayElement(" + 1574 (mUseCPlusPlus ? "" : "_env, ") + 1575 cfunc.getArgName(cIndex) + 1576 "_ref, i + " + offset + ", " + 1577 cfunc.getArgName(cIndex) + "_new);"); 1578 out.println(indent + indent + "}"); 1579 out.println(indent + indent + 1580 "delete[] " + jfunc.getArgName(idx) + ";"); 1581 out.println(indent + "}"); 1582 } 1583 } 1584 } 1585 1586 1587 // Throw exception if there is one 1588 if (emitExceptionCheck) { 1589 out.println(indent + "if (_exception) {"); 1590 out.println(indent + indent + 1591 "jniThrowException(_env, _exceptionType, _exceptionMessage);"); 1592 out.println(indent + "}"); 1593 1594 } 1595 1596 1597 if (!isVoid) { 1598 if (cfunc.getType().isEGLHandle()) { 1599 String baseType = cfunc.getType().getBaseType().toLowerCase(); 1600 out.println(indent + 1601 "return toEGLHandle(_env, " + baseType + "Class, " + 1602 baseType + "Constructor, _returnValue);"); 1603 } else { 1604 out.println(indent + "return (" + 1605 getJniType(jfunc.getType()) + ")_returnValue;"); 1606 } 1607 } 1608 1609 out.println("}"); 1610 out.println(); 1611 } 1612 1613 } 1614