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