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 += "L"; 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 = 0;"); 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 isVBOPointerFunc = (outName.endsWith("Pointer") || 753 outName.endsWith("PointerOES") || 754 outName.endsWith("DrawElements") || outName.endsWith("VertexAttribPointer")) && 755 !jfunc.getCFunc().hasPointerArg(); 756 if (isPointerFunc) { 757 outName += "Bounds"; 758 } 759 760 out.print("static "); 761 out.println(getJniType(jfunc.getType())); 762 out.print(outName); 763 764 String rsignature = getJniName(jfunc.getType()); 765 766 String signature = ""; 767 int numArgs = jfunc.getNumArgs(); 768 for (int i = 0; i < numArgs; i++) { 769 JType argType = jfunc.getArgType(i); 770 signature += getJniName(argType); 771 } 772 if (isPointerFunc) { 773 signature += "I"; 774 } 775 776 // Append signature to function name 777 String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_'); 778 if (!mUseSimpleMethodNames) { 779 out.print("__" + sig); 780 outName += "__" + sig; 781 } 782 783 signature = signature.replace('.', '/'); 784 rsignature = rsignature.replace('.', '/'); 785 786 out.println(); 787 if (rsignature.length() == 0) { 788 rsignature = "V"; 789 } 790 791 String s = "{\"" + 792 jfunc.getName() + 793 (isPointerFunc ? "Bounds" : "") + 794 "\", \"(" + signature +")" + 795 rsignature + 796 "\", (void *) " + 797 outName + 798 " },"; 799 nativeRegistrations.add(s); 800 801 List<Integer> nonPrimitiveArgs = new ArrayList<Integer>(); 802 List<Integer> stringArgs = new ArrayList<Integer>(); 803 int numBufferArgs = 0; 804 List<String> bufferArgNames = new ArrayList<String>(); 805 806 // Emit JNI signature (arguments) 807 // 808 // Example: 809 // 810 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) { 811 // 812 out.print(" (JNIEnv *_env, jobject _this"); 813 for (int i = 0; i < numArgs; i++) { 814 out.print(", "); 815 JType argType = jfunc.getArgType(i); 816 String suffix = ""; 817 if (!argType.isPrimitive()) { 818 if (argType.isArray()) { 819 suffix = "_ref"; 820 } else if (argType.isBuffer()) { 821 suffix = "_buf"; 822 } 823 nonPrimitiveArgs.add(new Integer(i)); 824 if (jfunc.getArgType(i).isBuffer()) { 825 int cIndex = jfunc.getArgCIndex(i); 826 String cname = cfunc.getArgName(cIndex); 827 bufferArgNames.add(cname); 828 numBufferArgs++; 829 } 830 } 831 832 if (argType.isString()) { 833 stringArgs.add(new Integer(i)); 834 } 835 836 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix); 837 } 838 if (isPointerFunc) { 839 out.print(", jint remaining"); 840 } 841 out.println(") {"); 842 843 int numArrays = 0; 844 int numBuffers = 0; 845 int numStrings = 0; 846 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 847 int idx = nonPrimitiveArgs.get(i).intValue(); 848 JType argType = jfunc.getArgType(idx); 849 if (argType.isArray()) { 850 ++numArrays; 851 } 852 if (argType.isBuffer()) { 853 ++numBuffers; 854 } 855 if (argType.isString()) { 856 ++numStrings; 857 } 858 } 859 860 // Emit method body 861 862 // Emit local variable declarations for _exception and _returnValue 863 // 864 // Example: 865 // 866 // android::gl::ogles_context_t *ctx; 867 // 868 // jint _exception; 869 // GLenum _returnValue; 870 // 871 CType returnType = cfunc.getType(); 872 boolean isVoid = returnType.isVoid(); 873 874 boolean isUnsupported = isUnsupportedFunc(cfunc); 875 if (isUnsupported) { 876 out.println(indent + 877 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 878 out.println(indent + 879 " \"" + cfunc.getName() + "\");"); 880 if (!isVoid) { 881 String retval = getErrorReturnValue(cfunc); 882 if (cfunc.getType().isEGLHandle()) { 883 String baseType = cfunc.getType().getBaseType().toLowerCase(); 884 out.println(indent + 885 "return toEGLHandle(_env, " + baseType + "Class, " + 886 baseType + "Constructor, " + retval + ");"); 887 } else { 888 out.println(indent + "return " + retval + ";"); 889 } 890 } 891 out.println("}"); 892 out.println(); 893 return; 894 } 895 896 String requiresExtension = isRequiresFunc(cfunc); 897 if (requiresExtension != null) { 898 out.println(indent + 899 "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {"); 900 out.println(indent + indent + 901 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 902 out.println(indent + indent + 903 " \"" + cfunc.getName() + "\");"); 904 if (isVoid) { 905 out.println(indent + indent + " return;"); 906 } else { 907 String retval = getErrorReturnValue(cfunc); 908 if (cfunc.getType().isEGLHandle()) { 909 String baseType = cfunc.getType().getBaseType().toLowerCase(); 910 out.println(indent + 911 "return toEGLHandle(_env, " + baseType + "Class, " + 912 baseType + "Constructor, " + retval + ");"); 913 } else { 914 out.println(indent + "return " + retval + ";"); 915 } 916 } 917 out.println(indent + "}"); 918 } 919 if (mUseContextPointer) { 920 out.println(indent + 921 "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); 922 } 923 924 boolean initializeReturnValue = stringArgs.size() > 0; 925 boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0) 926 && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs) 927 || (cfunc.hasPointerArg() && numArrays > 0)) 928 || hasCheckTest(cfunc) 929 || hasIfTest(cfunc)) 930 || (stringArgs.size() > 0); 931 // mChecker.getChecks(cfunc.getName()) != null 932 // Emit an _exeption variable if there will be error checks 933 if (emitExceptionCheck) { 934 out.println(indent + "jint _exception = 0;"); 935 out.println(indent + "const char * _exceptionType;"); 936 out.println(indent + "const char * _exceptionMessage;"); 937 } 938 939 // Emit a single _array or multiple _XXXArray variables 940 if (numBufferArgs == 1) { 941 out.println(indent + "jarray _array = (jarray) 0;"); 942 out.println(indent + "jint _bufferOffset = (jint) 0;"); 943 } else { 944 for (int i = 0; i < numBufferArgs; i++) { 945 out.println(indent + "jarray _" + bufferArgNames.get(i) + 946 "Array = (jarray) 0;"); 947 out.println(indent + "jint _" + bufferArgNames.get(i) + 948 "BufferOffset = (jint) 0;"); 949 } 950 } 951 if (!isVoid) { 952 String retval = getErrorReturnValue(cfunc); 953 if (retval != null) { 954 out.println(indent + returnType.getDeclaration() + 955 " _returnValue = " + retval + ";"); 956 } else if (initializeReturnValue) { 957 out.println(indent + returnType.getDeclaration() + 958 " _returnValue = 0;"); 959 } else { 960 out.println(indent + returnType.getDeclaration() + 961 " _returnValue;"); 962 } 963 } 964 965 // Emit local variable declarations for EGL Handles 966 // 967 // Example: 968 // 969 // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface); 970 // 971 if (nonPrimitiveArgs.size() > 0) { 972 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 973 int idx = nonPrimitiveArgs.get(i).intValue(); 974 int cIndex = jfunc.getArgCIndex(idx); 975 String cname = cfunc.getArgName(cIndex); 976 977 if (jfunc.getArgType(idx).isBuffer() 978 || jfunc.getArgType(idx).isArray() 979 || !jfunc.getArgType(idx).isEGLHandle()) 980 continue; 981 982 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 983 String decl = type.getDeclaration(); 984 out.println(indent + 985 decl + " " + cname + "_native = (" + 986 decl + ") fromEGLHandle(_env, " + 987 type.getBaseType().toLowerCase() + 988 "GetHandleID, " + jfunc.getArgName(idx) + 989 ");"); 990 } 991 } 992 993 // Emit local variable declarations for element/sentinel checks 994 // 995 // Example: 996 // 997 // bool attrib_list_sentinel_found = false; 998 // 999 emitLocalVariablesForSentinel(cfunc, out); 1000 1001 // Emit local variable declarations for pointer arguments 1002 // 1003 // Example: 1004 // 1005 // GLfixed *eqn_base; 1006 // GLfixed *eqn; 1007 // 1008 String offset = "offset"; 1009 String remaining = "_remaining"; 1010 if (nonPrimitiveArgs.size() > 0) { 1011 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1012 int idx = nonPrimitiveArgs.get(i).intValue(); 1013 int cIndex = jfunc.getArgCIndex(idx); 1014 String cname = cfunc.getArgName(cIndex); 1015 1016 if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray()) 1017 continue; 1018 1019 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1020 String decl = type.getDeclaration(); 1021 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1022 out.println(indent + 1023 decl + 1024 (decl.endsWith("*") ? "" : " ") + 1025 jfunc.getArgName(idx) + 1026 "_base = (" + decl + ") 0;"); 1027 } 1028 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1029 "_" + cname + "Remaining"; 1030 out.println(indent + 1031 "jint " + remaining + ";"); 1032 out.println(indent + 1033 decl + 1034 (decl.endsWith("*") ? "" : " ") + 1035 jfunc.getArgName(idx) + 1036 " = (" + decl + ") 0;"); 1037 } 1038 1039 out.println(); 1040 } 1041 1042 // Emit local variable declaration for strings 1043 if (stringArgs.size() > 0) { 1044 for (int i = 0; i < stringArgs.size(); i++) { 1045 int idx = stringArgs.get(i).intValue(); 1046 int cIndex = jfunc.getArgCIndex(idx); 1047 String cname = cfunc.getArgName(cIndex); 1048 1049 out.println(indent + "const char* _native" + cname + " = 0;"); 1050 } 1051 1052 out.println(); 1053 } 1054 1055 // Null pointer checks and GetStringUTFChars 1056 if (stringArgs.size() > 0) { 1057 for (int i = 0; i < stringArgs.size(); i++) { 1058 int idx = stringArgs.get(i).intValue(); 1059 int cIndex = jfunc.getArgCIndex(idx); 1060 String cname = cfunc.getArgName(cIndex); 1061 1062 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 1063 String decl = type.getDeclaration(); 1064 needsExit = true; 1065 out.println(indent + "if (!" + cname + ") {"); 1066 out.println(indent + indent + 1067 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1068 out.println(indent + indent + 1069 "_exceptionMessage = \"" + cname + " == null\";"); 1070 out.println(indent + indent + "goto exit;"); 1071 out.println(indent + "}"); 1072 1073 out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);"); 1074 } 1075 1076 out.println(); 1077 } 1078 1079 // Emit 'GetPrimitiveArrayCritical' for non-object arrays 1080 // Emit 'GetPointer' calls for Buffer pointers 1081 if (nonPrimitiveArgs.size() > 0) { 1082 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1083 int idx = nonPrimitiveArgs.get(i).intValue(); 1084 int cIndex = jfunc.getArgCIndex(idx); 1085 1086 String cname = cfunc.getArgName(cIndex); 1087 offset = numArrays <= 1 ? "offset" : 1088 cname + "Offset"; 1089 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1090 "_" + cname + "Remaining"; 1091 1092 if (jfunc.getArgType(idx).isArray() 1093 && !jfunc.getArgType(idx).isEGLHandle()) { 1094 needsExit = true; 1095 out.println(indent + "if (!" + cname + "_ref) {"); 1096 out.println(indent + indent + "_exception = 1;"); 1097 out.println(indent + indent + 1098 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1099 out.println(indent + indent + 1100 "_exceptionMessage = \"" + cname +" == null\";"); 1101 out.println(indent + indent + "goto exit;"); 1102 out.println(indent + "}"); 1103 out.println(indent + "if (" + offset + " < 0) {"); 1104 out.println(indent + indent + "_exception = 1;"); 1105 out.println(indent + indent + 1106 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1107 out.println(indent + indent + 1108 "_exceptionMessage = \"" + offset +" < 0\";"); 1109 out.println(indent + indent + "goto exit;"); 1110 out.println(indent + "}"); 1111 1112 out.println(indent + remaining + " = " + 1113 (mUseCPlusPlus ? "_env" : "(*_env)") + 1114 "->GetArrayLength(" + 1115 (mUseCPlusPlus ? "" : "_env, ") + 1116 cname + "_ref) - " + offset + ";"); 1117 1118 emitNativeBoundsChecks(cfunc, cname, out, false, 1119 emitExceptionCheck, 1120 offset, remaining, " "); 1121 1122 out.println(indent + 1123 cname + 1124 "_base = (" + 1125 cfunc.getArgType(cIndex).getDeclaration() + 1126 ")"); 1127 out.println(indent + " " + 1128 (mUseCPlusPlus ? "_env" : "(*_env)") + 1129 "->GetPrimitiveArrayCritical(" + 1130 (mUseCPlusPlus ? "" : "_env, ") + 1131 jfunc.getArgName(idx) + 1132 "_ref, (jboolean *)0);"); 1133 out.println(indent + 1134 cname + " = " + cname + "_base + " + offset + ";"); 1135 1136 emitSentinelCheck(cfunc, cname, out, false, 1137 emitExceptionCheck, offset, 1138 remaining, indent); 1139 out.println(); 1140 } else if (jfunc.getArgType(idx).isArray() 1141 && jfunc.getArgType(idx).isEGLHandle()) { 1142 needsExit = true; 1143 out.println(indent + "if (!" + cname + "_ref) {"); 1144 out.println(indent + indent + "_exception = 1;"); 1145 out.println(indent + indent + 1146 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1147 out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";"); 1148 out.println(indent + indent + "goto exit;"); 1149 out.println(indent + "}"); 1150 out.println(indent + "if (" + offset + " < 0) {"); 1151 out.println(indent + indent + "_exception = 1;"); 1152 out.println(indent + indent + 1153 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1154 out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";"); 1155 out.println(indent + indent + "goto exit;"); 1156 out.println(indent + "}"); 1157 1158 out.println(indent + remaining + " = " + 1159 (mUseCPlusPlus ? "_env" : "(*_env)") + 1160 "->GetArrayLength(" + 1161 (mUseCPlusPlus ? "" : "_env, ") + 1162 cname + "_ref) - " + offset + ";"); 1163 emitNativeBoundsChecks(cfunc, cname, out, false, 1164 emitExceptionCheck, 1165 offset, remaining, " "); 1166 out.println(indent + 1167 jfunc.getArgName(idx) + " = new " + 1168 cfunc.getArgType(cIndex).getBaseType() + 1169 "["+ remaining + "];"); 1170 out.println(); 1171 } else if (jfunc.getArgType(idx).isBuffer()) { 1172 String array = numBufferArgs <= 1 ? "_array" : 1173 "_" + cfunc.getArgName(cIndex) + "Array"; 1174 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1175 "_" + cfunc.getArgName(cIndex) + "BufferOffset"; 1176 1177 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1178 if (nullAllowed) { 1179 out.println(indent + "if (" + cname + "_buf) {"); 1180 out.print(indent); 1181 } 1182 1183 if (isPointerFunc) { 1184 out.println(indent + 1185 cname + 1186 " = (" + 1187 cfunc.getArgType(cIndex).getDeclaration() + 1188 ") getDirectBufferPointer(_env, " + 1189 cname + "_buf);"); 1190 String iii = " "; 1191 out.println(iii + indent + "if ( ! " + cname + " ) {"); 1192 out.println(iii + indent + indent + "return;"); 1193 out.println(iii + indent + "}"); 1194 } else { 1195 out.println(indent + 1196 cname + 1197 " = (" + 1198 cfunc.getArgType(cIndex).getDeclaration() + 1199 ")getPointer(_env, " + 1200 cname + 1201 "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset + 1202 ");"); 1203 } 1204 1205 emitNativeBoundsChecks(cfunc, cname, out, true, 1206 emitExceptionCheck, 1207 offset, remaining, nullAllowed ? " " : " "); 1208 1209 if (nullAllowed) { 1210 out.println(indent + "}"); 1211 } 1212 } 1213 } 1214 } 1215 1216 // Emit 'GetPrimitiveArrayCritical' for pointers if needed 1217 if (nonPrimitiveArgs.size() > 0) { 1218 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1219 int idx = nonPrimitiveArgs.get(i).intValue(); 1220 int cIndex = jfunc.getArgCIndex(idx); 1221 1222 if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue; 1223 1224 String cname = cfunc.getArgName(cIndex); 1225 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1226 "_" + cname + "BufferOffset"; 1227 String array = numBufferArgs <= 1 ? "_array" : 1228 "_" + cfunc.getArgName(cIndex) + "Array"; 1229 1230 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1231 if (nullAllowed) { 1232 out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {"); 1233 } else { 1234 out.println(indent + "if (" + cname +" == NULL) {"); 1235 } 1236 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); 1237 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); 1238 out.println(indent + "}"); 1239 } 1240 } 1241 1242 1243 if (!isVoid) { 1244 out.print(indent + "_returnValue = "); 1245 } else { 1246 out.print(indent); 1247 } 1248 String name = cfunc.getName(); 1249 1250 if (mUseContextPointer) { 1251 name = name.substring(2, name.length()); // Strip off 'gl' prefix 1252 name = name.substring(0, 1).toLowerCase() + 1253 name.substring(1, name.length()); 1254 out.print("ctx->procs."); 1255 } 1256 1257 out.print(name + (isPointerFunc ? "Bounds" : "") + "("); 1258 1259 numArgs = cfunc.getNumArgs(); 1260 if (numArgs == 0) { 1261 if (mUseContextPointer) { 1262 out.println("ctx);"); 1263 } else { 1264 out.println(");"); 1265 } 1266 } else { 1267 if (mUseContextPointer) { 1268 out.println("ctx,"); 1269 } else { 1270 out.println(); 1271 } 1272 for (int i = 0; i < numArgs; i++) { 1273 String typecast; 1274 if (i == numArgs - 1 && isVBOPointerFunc) { 1275 typecast = "(const GLvoid *)"; 1276 } else { 1277 typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; 1278 } 1279 out.print(indent + indent + 1280 typecast); 1281 1282 if (cfunc.getArgType(i).isConstCharPointer()) { 1283 out.print("_native"); 1284 } 1285 1286 if (cfunc.getArgType(i).isEGLHandle() && 1287 !cfunc.getArgType(i).isPointer()){ 1288 out.print(cfunc.getArgName(i)+"_native"); 1289 } else { 1290 out.print(cfunc.getArgName(i)); 1291 } 1292 1293 if (i == numArgs - 1) { 1294 if (isPointerFunc) { 1295 out.println(","); 1296 out.println(indent + indent + "(GLsizei)remaining"); 1297 } else { 1298 out.println(); 1299 } 1300 } else { 1301 out.println(","); 1302 } 1303 } 1304 out.println(indent + ");"); 1305 } 1306 1307 if (needsExit) { 1308 out.println(); 1309 out.println("exit:"); 1310 needsExit = false; 1311 } 1312 1313 1314 if (nonPrimitiveArgs.size() > 0) { 1315 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1316 int idx = nonPrimitiveArgs.get(i).intValue(); 1317 1318 int cIndex = jfunc.getArgCIndex(idx); 1319 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1320 1321 // If the argument is 'const', GL will not write to it. 1322 // In this case, we can use the 'JNI_ABORT' flag to avoid 1323 // the need to write back to the Java array 1324 out.println(indent + 1325 "if (" + jfunc.getArgName(idx) + "_base) {"); 1326 out.println(indent + indent + 1327 (mUseCPlusPlus ? "_env" : "(*_env)") + 1328 "->ReleasePrimitiveArrayCritical(" + 1329 (mUseCPlusPlus ? "" : "_env, ") + 1330 jfunc.getArgName(idx) + "_ref, " + 1331 cfunc.getArgName(cIndex) + 1332 "_base,"); 1333 out.println(indent + indent + indent + 1334 (cfunc.getArgType(cIndex).isConst() ? 1335 "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + 1336 ");"); 1337 out.println(indent + "}"); 1338 } else if (jfunc.getArgType(idx).isBuffer()) { 1339 if (! isPointerFunc) { 1340 String array = numBufferArgs <= 1 ? "_array" : 1341 "_" + cfunc.getArgName(cIndex) + "Array"; 1342 out.println(indent + "if (" + array + ") {"); 1343 out.println(indent + indent + 1344 "releasePointer(_env, " + array + ", " + 1345 cfunc.getArgName(cIndex) + 1346 ", " + 1347 (cfunc.getArgType(cIndex).isConst() ? 1348 "JNI_FALSE" : (emitExceptionCheck ? 1349 "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + 1350 ");"); 1351 out.println(indent + "}"); 1352 } 1353 } 1354 } 1355 } 1356 1357 // Emit local variable declaration for strings 1358 if (stringArgs.size() > 0) { 1359 for (int i = 0; i < stringArgs.size(); i++) { 1360 int idx = stringArgs.get(i).intValue(); 1361 int cIndex = jfunc.getArgCIndex(idx); 1362 String cname = cfunc.getArgName(cIndex); 1363 1364 out.println(indent + "if (_native" + cname + ") {"); 1365 out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");"); 1366 out.println(indent + "}"); 1367 } 1368 1369 out.println(); 1370 } 1371 1372 // Copy results back to java arrays 1373 if (nonPrimitiveArgs.size() > 0) { 1374 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1375 int idx = nonPrimitiveArgs.get(i).intValue(); 1376 int cIndex = jfunc.getArgCIndex(idx); 1377 String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); 1378 if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { 1379 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1380 "_" + cfunc.getArgName(cIndex) + "Remaining"; 1381 offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; 1382 out.println(indent + 1383 "if (" + jfunc.getArgName(idx) + ") {"); 1384 out.println(indent + indent + 1385 "for (int i = 0; i < " + remaining + "; i++) {"); 1386 out.println(indent + indent + indent + 1387 "jobject " + cfunc.getArgName(cIndex) + 1388 "_new = toEGLHandle(_env, " + baseType + 1389 "Class, " + baseType + "Constructor, " + 1390 cfunc.getArgName(cIndex) + "[i]);"); 1391 out.println(indent + indent + indent + 1392 (mUseCPlusPlus ? "_env" : "(*_env)") + 1393 "->SetObjectArrayElement(" + 1394 (mUseCPlusPlus ? "" : "_env, ") + 1395 cfunc.getArgName(cIndex) + 1396 "_ref, i + " + offset + ", " + 1397 cfunc.getArgName(cIndex) + "_new);"); 1398 out.println(indent + indent + "}"); 1399 out.println(indent + indent + 1400 "delete[] " + jfunc.getArgName(idx) + ";"); 1401 out.println(indent + "}"); 1402 } 1403 } 1404 } 1405 1406 1407 // Throw exception if there is one 1408 if (emitExceptionCheck) { 1409 out.println(indent + "if (_exception) {"); 1410 out.println(indent + indent + 1411 "jniThrowException(_env, _exceptionType, _exceptionMessage);"); 1412 out.println(indent + "}"); 1413 1414 } 1415 1416 1417 if (!isVoid) { 1418 if (cfunc.getType().isEGLHandle()) { 1419 String baseType = cfunc.getType().getBaseType().toLowerCase(); 1420 out.println(indent + 1421 "return toEGLHandle(_env, " + baseType + "Class, " + 1422 baseType + "Constructor, _returnValue);"); 1423 } else { 1424 out.println(indent + "return _returnValue;"); 1425 } 1426 } 1427 1428 out.println("}"); 1429 out.println(); 1430 } 1431 1432 } 1433