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 + 1077 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1078 out.println(indent + indent + 1079 "_exceptionMessage = \"" + cname + " == null\";"); 1080 out.println(indent + indent + "goto exit;"); 1081 out.println(indent + "}"); 1082 1083 out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);"); 1084 } 1085 1086 out.println(); 1087 } 1088 1089 // Emit 'GetPrimitiveArrayCritical' for non-object arrays 1090 // Emit 'GetPointer' calls for Buffer pointers 1091 if (nonPrimitiveArgs.size() > 0) { 1092 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1093 int idx = nonPrimitiveArgs.get(i).intValue(); 1094 int cIndex = jfunc.getArgCIndex(idx); 1095 1096 String cname = cfunc.getArgName(cIndex); 1097 offset = numArrays <= 1 ? "offset" : 1098 cname + "Offset"; 1099 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1100 "_" + cname + "Remaining"; 1101 1102 if (jfunc.getArgType(idx).isArray() 1103 && !jfunc.getArgType(idx).isEGLHandle()) { 1104 needsExit = true; 1105 out.println(indent + "if (!" + cname + "_ref) {"); 1106 out.println(indent + indent + "_exception = 1;"); 1107 out.println(indent + indent + 1108 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1109 out.println(indent + indent + 1110 "_exceptionMessage = \"" + cname +" == null\";"); 1111 out.println(indent + indent + "goto exit;"); 1112 out.println(indent + "}"); 1113 out.println(indent + "if (" + offset + " < 0) {"); 1114 out.println(indent + indent + "_exception = 1;"); 1115 out.println(indent + indent + 1116 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1117 out.println(indent + indent + 1118 "_exceptionMessage = \"" + offset +" < 0\";"); 1119 out.println(indent + indent + "goto exit;"); 1120 out.println(indent + "}"); 1121 1122 out.println(indent + remaining + " = " + 1123 (mUseCPlusPlus ? "_env" : "(*_env)") + 1124 "->GetArrayLength(" + 1125 (mUseCPlusPlus ? "" : "_env, ") + 1126 cname + "_ref) - " + offset + ";"); 1127 1128 emitNativeBoundsChecks(cfunc, cname, out, false, 1129 emitExceptionCheck, 1130 offset, remaining, " "); 1131 1132 out.println(indent + 1133 cname + 1134 "_base = (" + 1135 cfunc.getArgType(cIndex).getDeclaration() + 1136 ")"); 1137 out.println(indent + " " + 1138 (mUseCPlusPlus ? "_env" : "(*_env)") + 1139 "->GetPrimitiveArrayCritical(" + 1140 (mUseCPlusPlus ? "" : "_env, ") + 1141 jfunc.getArgName(idx) + 1142 "_ref, (jboolean *)0);"); 1143 out.println(indent + 1144 cname + " = " + cname + "_base + " + offset + ";"); 1145 1146 emitSentinelCheck(cfunc, cname, out, false, 1147 emitExceptionCheck, offset, 1148 remaining, indent); 1149 out.println(); 1150 } else if (jfunc.getArgType(idx).isArray() 1151 && jfunc.getArgType(idx).isEGLHandle()) { 1152 needsExit = true; 1153 out.println(indent + "if (!" + cname + "_ref) {"); 1154 out.println(indent + indent + "_exception = 1;"); 1155 out.println(indent + indent + 1156 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1157 out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";"); 1158 out.println(indent + indent + "goto exit;"); 1159 out.println(indent + "}"); 1160 out.println(indent + "if (" + offset + " < 0) {"); 1161 out.println(indent + indent + "_exception = 1;"); 1162 out.println(indent + indent + 1163 "_exceptionType = \"java/lang/IllegalArgumentException\";"); 1164 out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";"); 1165 out.println(indent + indent + "goto exit;"); 1166 out.println(indent + "}"); 1167 1168 out.println(indent + remaining + " = " + 1169 (mUseCPlusPlus ? "_env" : "(*_env)") + 1170 "->GetArrayLength(" + 1171 (mUseCPlusPlus ? "" : "_env, ") + 1172 cname + "_ref) - " + offset + ";"); 1173 emitNativeBoundsChecks(cfunc, cname, out, false, 1174 emitExceptionCheck, 1175 offset, remaining, " "); 1176 out.println(indent + 1177 jfunc.getArgName(idx) + " = new " + 1178 cfunc.getArgType(cIndex).getBaseType() + 1179 "["+ remaining + "];"); 1180 out.println(); 1181 } else if (jfunc.getArgType(idx).isBuffer()) { 1182 String array = numBufferArgs <= 1 ? "_array" : 1183 "_" + cfunc.getArgName(cIndex) + "Array"; 1184 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1185 "_" + cfunc.getArgName(cIndex) + "BufferOffset"; 1186 1187 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1188 if (nullAllowed) { 1189 out.println(indent + "if (" + cname + "_buf) {"); 1190 out.print(indent); 1191 } 1192 1193 if (isPointerFunc) { 1194 out.println(indent + 1195 cname + 1196 " = (" + 1197 cfunc.getArgType(cIndex).getDeclaration() + 1198 ") getDirectBufferPointer(_env, " + 1199 cname + "_buf);"); 1200 String iii = " "; 1201 out.println(iii + indent + "if ( ! " + cname + " ) {"); 1202 out.println(iii + indent + indent + "return;"); 1203 out.println(iii + indent + "}"); 1204 } else { 1205 out.println(indent + 1206 cname + 1207 " = (" + 1208 cfunc.getArgType(cIndex).getDeclaration() + 1209 ")getPointer(_env, " + 1210 cname + 1211 "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset + 1212 ");"); 1213 } 1214 1215 emitNativeBoundsChecks(cfunc, cname, out, true, 1216 emitExceptionCheck, 1217 offset, remaining, nullAllowed ? " " : " "); 1218 1219 if (nullAllowed) { 1220 out.println(indent + "}"); 1221 } 1222 } 1223 } 1224 } 1225 1226 // Emit 'GetPrimitiveArrayCritical' for pointers if needed 1227 if (nonPrimitiveArgs.size() > 0) { 1228 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 1229 int idx = nonPrimitiveArgs.get(i).intValue(); 1230 int cIndex = jfunc.getArgCIndex(idx); 1231 1232 if(!jfunc.getArgType(idx).isBuffer() || isPointerFunc) continue; 1233 1234 String cname = cfunc.getArgName(cIndex); 1235 String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : 1236 "_" + cname + "BufferOffset"; 1237 String array = numBufferArgs <= 1 ? "_array" : 1238 "_" + cfunc.getArgName(cIndex) + "Array"; 1239 1240 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1241 if (nullAllowed) { 1242 out.println(indent + "if (" + cname + "_buf && " + cname +" == NULL) {"); 1243 } else { 1244 out.println(indent + "if (" + cname +" == NULL) {"); 1245 } 1246 out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); 1247 out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); 1248 out.println(indent + "}"); 1249 } 1250 } 1251 1252 1253 if (!isVoid) { 1254 out.print(indent + "_returnValue = "); 1255 } else { 1256 out.print(indent); 1257 } 1258 String name = cfunc.getName(); 1259 1260 if (mUseContextPointer) { 1261 name = name.substring(2, name.length()); // Strip off 'gl' prefix 1262 name = name.substring(0, 1).toLowerCase() + 1263 name.substring(1, name.length()); 1264 out.print("ctx->procs."); 1265 } 1266 1267 out.print(name + (isPointerFunc ? "Bounds" : "") + "("); 1268 1269 numArgs = cfunc.getNumArgs(); 1270 if (numArgs == 0) { 1271 if (mUseContextPointer) { 1272 out.println("ctx);"); 1273 } else { 1274 out.println(");"); 1275 } 1276 } else { 1277 if (mUseContextPointer) { 1278 out.println("ctx,"); 1279 } else { 1280 out.println(); 1281 } 1282 for (int i = 0; i < numArgs; i++) { 1283 String typecast; 1284 if (i == numArgs - 1 && isPointerOffsetFunc) { 1285 typecast = "(GLvoid *)"; 1286 } else { 1287 typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; 1288 } 1289 out.print(indent + indent + 1290 typecast); 1291 1292 if (cfunc.getArgType(i).isConstCharPointer()) { 1293 out.print("_native"); 1294 } 1295 1296 if (cfunc.getArgType(i).isEGLHandle() && 1297 !cfunc.getArgType(i).isPointer()){ 1298 out.print(cfunc.getArgName(i)+"_native"); 1299 } else { 1300 out.print(cfunc.getArgName(i)); 1301 } 1302 1303 if (i == numArgs - 1) { 1304 if (isPointerFunc) { 1305 out.println(","); 1306 out.println(indent + indent + "(GLsizei)remaining"); 1307 } else { 1308 out.println(); 1309 } 1310 } else { 1311 out.println(","); 1312 } 1313 } 1314 out.println(indent + ");"); 1315 } 1316 1317 if (needsExit) { 1318 out.println(); 1319 out.println("exit:"); 1320 needsExit = false; 1321 } 1322 1323 1324 if (nonPrimitiveArgs.size() > 0) { 1325 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1326 int idx = nonPrimitiveArgs.get(i).intValue(); 1327 1328 int cIndex = jfunc.getArgCIndex(idx); 1329 if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { 1330 1331 // If the argument is 'const', GL will not write to it. 1332 // In this case, we can use the 'JNI_ABORT' flag to avoid 1333 // the need to write back to the Java array 1334 out.println(indent + 1335 "if (" + jfunc.getArgName(idx) + "_base) {"); 1336 out.println(indent + indent + 1337 (mUseCPlusPlus ? "_env" : "(*_env)") + 1338 "->ReleasePrimitiveArrayCritical(" + 1339 (mUseCPlusPlus ? "" : "_env, ") + 1340 jfunc.getArgName(idx) + "_ref, " + 1341 cfunc.getArgName(cIndex) + 1342 "_base,"); 1343 out.println(indent + indent + indent + 1344 (cfunc.getArgType(cIndex).isConst() ? 1345 "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + 1346 ");"); 1347 out.println(indent + "}"); 1348 } else if (jfunc.getArgType(idx).isBuffer()) { 1349 if (! isPointerFunc) { 1350 String array = numBufferArgs <= 1 ? "_array" : 1351 "_" + cfunc.getArgName(cIndex) + "Array"; 1352 out.println(indent + "if (" + array + ") {"); 1353 out.println(indent + indent + 1354 "releasePointer(_env, " + array + ", " + 1355 cfunc.getArgName(cIndex) + 1356 ", " + 1357 (cfunc.getArgType(cIndex).isConst() ? 1358 "JNI_FALSE" : (emitExceptionCheck ? 1359 "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + 1360 ");"); 1361 out.println(indent + "}"); 1362 } 1363 } 1364 } 1365 } 1366 1367 // Emit local variable declaration for strings 1368 if (stringArgs.size() > 0) { 1369 for (int i = 0; i < stringArgs.size(); i++) { 1370 int idx = stringArgs.get(i).intValue(); 1371 int cIndex = jfunc.getArgCIndex(idx); 1372 String cname = cfunc.getArgName(cIndex); 1373 1374 out.println(indent + "if (_native" + cname + ") {"); 1375 out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");"); 1376 out.println(indent + "}"); 1377 } 1378 1379 out.println(); 1380 } 1381 1382 // Copy results back to java arrays 1383 if (nonPrimitiveArgs.size() > 0) { 1384 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1385 int idx = nonPrimitiveArgs.get(i).intValue(); 1386 int cIndex = jfunc.getArgCIndex(idx); 1387 String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); 1388 if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { 1389 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 1390 "_" + cfunc.getArgName(cIndex) + "Remaining"; 1391 offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; 1392 out.println(indent + 1393 "if (" + jfunc.getArgName(idx) + ") {"); 1394 out.println(indent + indent + 1395 "for (int i = 0; i < " + remaining + "; i++) {"); 1396 out.println(indent + indent + indent + 1397 "jobject " + cfunc.getArgName(cIndex) + 1398 "_new = toEGLHandle(_env, " + baseType + 1399 "Class, " + baseType + "Constructor, " + 1400 cfunc.getArgName(cIndex) + "[i]);"); 1401 out.println(indent + indent + indent + 1402 (mUseCPlusPlus ? "_env" : "(*_env)") + 1403 "->SetObjectArrayElement(" + 1404 (mUseCPlusPlus ? "" : "_env, ") + 1405 cfunc.getArgName(cIndex) + 1406 "_ref, i + " + offset + ", " + 1407 cfunc.getArgName(cIndex) + "_new);"); 1408 out.println(indent + indent + "}"); 1409 out.println(indent + indent + 1410 "delete[] " + jfunc.getArgName(idx) + ";"); 1411 out.println(indent + "}"); 1412 } 1413 } 1414 } 1415 1416 1417 // Throw exception if there is one 1418 if (emitExceptionCheck) { 1419 out.println(indent + "if (_exception) {"); 1420 out.println(indent + indent + 1421 "jniThrowException(_env, _exceptionType, _exceptionMessage);"); 1422 out.println(indent + "}"); 1423 1424 } 1425 1426 1427 if (!isVoid) { 1428 if (cfunc.getType().isEGLHandle()) { 1429 String baseType = cfunc.getType().getBaseType().toLowerCase(); 1430 out.println(indent + 1431 "return toEGLHandle(_env, " + baseType + "Class, " + 1432 baseType + "Constructor, _returnValue);"); 1433 } else { 1434 out.println(indent + "return (" + 1435 getJniType(jfunc.getType()) + ")_returnValue;"); 1436 } 1437 } 1438 1439 out.println("}"); 1440 out.println(); 1441 } 1442 1443 } 1444