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