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