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