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