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