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 String mClassPathName; 29 protected ParameterChecker mChecker; 30 protected List<String> nativeRegistrations = new ArrayList<String>(); 31 boolean needsExit; 32 protected static String indent = " "; 33 HashSet<String> mFunctionsEmitted = new HashSet<String>(); 34 35 public static String getJniName(JType jType) { 36 String jniName = ""; 37 if (jType.isClass()) { 38 return "L" + jType.getBaseType() + ";"; 39 } else if (jType.isArray()) { 40 jniName = "["; 41 } 42 43 String baseType = jType.getBaseType(); 44 if (baseType.equals("int")) { 45 jniName += "I"; 46 } else if (baseType.equals("float")) { 47 jniName += "F"; 48 } else if (baseType.equals("boolean")) { 49 jniName += "Z"; 50 } else if (baseType.equals("short")) { 51 jniName += "S"; 52 } else if (baseType.equals("long")) { 53 jniName += "L"; 54 } else if (baseType.equals("byte")) { 55 jniName += "B"; 56 } else if (baseType.equals("String")) { 57 jniName += "Ljava/lang/String;"; 58 } else if (baseType.equals("void")) { 59 // nothing. 60 } else { 61 throw new RuntimeException("Unknown primitive basetype " + baseType); 62 } 63 return jniName; 64 } 65 66 67 public void emitCode(CFunc cfunc, String original, 68 PrintStream javaInterfaceStream, 69 PrintStream javaImplStream, 70 PrintStream cStream) { 71 JFunc jfunc; 72 String signature; 73 boolean duplicate; 74 75 if (cfunc.hasTypedPointerArg()) { 76 jfunc = JFunc.convert(cfunc, true); 77 78 // Don't emit duplicate functions 79 // These may appear because they are defined in multiple 80 // Java interfaces (e.g., GL11/GL11ExtensionPack) 81 signature = jfunc.toString(); 82 duplicate = false; 83 if (mFunctionsEmitted.contains(signature)) { 84 duplicate = true; 85 } else { 86 mFunctionsEmitted.add(signature); 87 } 88 89 if (!duplicate) { 90 emitNativeDeclaration(jfunc, javaImplStream); 91 emitJavaCode(jfunc, javaImplStream); 92 } 93 if (javaInterfaceStream != null) { 94 emitJavaInterfaceCode(jfunc, javaInterfaceStream); 95 } 96 if (!duplicate) { 97 emitJniCode(jfunc, cStream); 98 } 99 } 100 101 jfunc = JFunc.convert(cfunc, false); 102 103 signature = jfunc.toString(); 104 duplicate = false; 105 if (mFunctionsEmitted.contains(signature)) { 106 duplicate = true; 107 } else { 108 mFunctionsEmitted.add(signature); 109 } 110 111 if (!duplicate) { 112 emitNativeDeclaration(jfunc, javaImplStream); 113 } 114 if (javaInterfaceStream != null) { 115 emitJavaInterfaceCode(jfunc, javaInterfaceStream); 116 } 117 if (!duplicate) { 118 emitJavaCode(jfunc, javaImplStream); 119 emitJniCode(jfunc, cStream); 120 } 121 } 122 123 public void emitNativeDeclaration(JFunc jfunc, PrintStream out) { 124 out.println(" // C function " + jfunc.getCFunc().getOriginal()); 125 out.println(); 126 127 emitFunction(jfunc, out, true, false); 128 } 129 130 public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) { 131 emitFunction(jfunc, out, false, true); 132 } 133 134 public void emitJavaCode(JFunc jfunc, PrintStream out) { 135 emitFunction(jfunc, out, false, false); 136 } 137 138 boolean isPointerFunc(JFunc jfunc) { 139 String name = jfunc.getName(); 140 return (name.endsWith("Pointer") || name.endsWith("PointerOES")) 141 && jfunc.getCFunc().hasPointerArg(); 142 } 143 144 void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) { 145 boolean isVoid = jfunc.getType().isVoid(); 146 boolean isPointerFunc = isPointerFunc(jfunc); 147 148 if (!isVoid) { 149 out.println(iii + 150 jfunc.getType() + " _returnValue;"); 151 } 152 out.println(iii + 153 (isVoid ? "" : "_returnValue = ") + 154 jfunc.getName() + 155 (isPointerFunc ? "Bounds" : "" ) + 156 "("); 157 158 int numArgs = jfunc.getNumArgs(); 159 for (int i = 0; i < numArgs; i++) { 160 String argName = jfunc.getArgName(i); 161 JType argType = jfunc.getArgType(i); 162 163 if (grabArray && argType.isTypedBuffer()) { 164 String typeName = argType.getBaseType(); 165 typeName = typeName.substring(9, typeName.length() - 6); 166 out.println(iii + indent + "get" + typeName + "Array(" + argName + "),"); 167 out.print(iii + indent + "getOffset(" + argName + ")"); 168 } else { 169 out.print(iii + indent + argName); 170 } 171 if (i == numArgs - 1) { 172 if (isPointerFunc) { 173 out.println(","); 174 out.println(iii + indent + argName + ".remaining()"); 175 } else { 176 out.println(); 177 } 178 } else { 179 out.println(","); 180 } 181 } 182 183 out.println(iii + ");"); 184 } 185 186 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, 187 String iii) { 188 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, 189 "offset", "_remaining", iii); 190 } 191 192 void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck, 193 String offset, String remaining, String iii) { 194 out.println(iii + " default:"); 195 out.println(iii + " _needed = 0;"); 196 out.println(iii + " break;"); 197 out.println(iii + "}"); 198 199 out.println(iii + "if (" + remaining + " < _needed) {"); 200 if (emitExceptionCheck) { 201 out.println(iii + indent + "_exception = 1;"); 202 } 203 out.println(iii + indent + "jniThrowException(_env, " + 204 "\"java/lang/IllegalArgumentException\", " + 205 "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < needed\");"); 206 out.println(iii + indent + "goto exit;"); 207 needsExit = true; 208 out.println(iii + "}"); 209 } 210 211 boolean isNullAllowed(CFunc cfunc) { 212 String[] checks = mChecker.getChecks(cfunc.getName()); 213 int index = 1; 214 if (checks != null) { 215 while (index < checks.length) { 216 if (checks[index].equals("return")) { 217 index += 2; 218 } else if (checks[index].startsWith("check")) { 219 index += 3; 220 } else if (checks[index].equals("ifcheck")) { 221 index += 5; 222 } else if (checks[index].equals("unsupported")) { 223 index += 1; 224 } else if (checks[index].equals("requires")) { 225 index += 2; 226 } else if (checks[index].equals("nullAllowed")) { 227 return true; 228 } else { 229 System.out.println("Error: unknown keyword \"" + 230 checks[index] + "\""); 231 System.exit(0); 232 } 233 } 234 } 235 return false; 236 } 237 238 String getErrorReturnValue(CFunc cfunc) { 239 CType returnType = cfunc.getType(); 240 boolean isVoid = returnType.isVoid(); 241 if (isVoid) { 242 return null; 243 } 244 245 String[] checks = mChecker.getChecks(cfunc.getName()); 246 247 int index = 1; 248 if (checks != null) { 249 while (index < checks.length) { 250 if (checks[index].equals("return")) { 251 return checks[index + 1]; 252 } else if (checks[index].startsWith("check")) { 253 index += 3; 254 } else if (checks[index].equals("ifcheck")) { 255 index += 5; 256 } else if (checks[index].equals("unsupported")) { 257 index += 1; 258 } else if (checks[index].equals("requires")) { 259 index += 2; 260 } else if (checks[index].equals("nullAllowed")) { 261 index += 1; 262 } else { 263 System.out.println("Error: unknown keyword \"" + 264 checks[index] + "\""); 265 System.exit(0); 266 } 267 } 268 } 269 270 return null; 271 } 272 273 boolean isUnsupportedFunc(CFunc cfunc) { 274 String[] checks = mChecker.getChecks(cfunc.getName()); 275 int index = 1; 276 if (checks != null) { 277 while (index < checks.length) { 278 if (checks[index].equals("unsupported")) { 279 return true; 280 } else if (checks[index].equals("requires")) { 281 index += 2; 282 } else if (checks[index].equals("return")) { 283 index += 2; 284 } else if (checks[index].startsWith("check")) { 285 index += 3; 286 } else if (checks[index].equals("ifcheck")) { 287 index += 5; 288 } else if (checks[index].equals("nullAllowed")) { 289 index += 1; 290 } else { 291 System.out.println("Error: unknown keyword \"" + 292 checks[index] + "\""); 293 System.exit(0); 294 } 295 } 296 } 297 return false; 298 } 299 300 String isRequiresFunc(CFunc cfunc) { 301 String[] checks = mChecker.getChecks(cfunc.getName()); 302 int index = 1; 303 if (checks != null) { 304 while (index < checks.length) { 305 if (checks[index].equals("unsupported")) { 306 index += 1; 307 } else if (checks[index].equals("requires")) { 308 return checks[index+1]; 309 } else if (checks[index].equals("return")) { 310 index += 2; 311 } else if (checks[index].startsWith("check")) { 312 index += 3; 313 } else if (checks[index].equals("ifcheck")) { 314 index += 5; 315 } else if (checks[index].equals("nullAllowed")) { 316 index += 1; 317 } else { 318 System.out.println("Error: unknown keyword \"" + 319 checks[index] + "\""); 320 System.exit(0); 321 } 322 } 323 } 324 return null; 325 } 326 327 void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out, 328 boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { 329 330 String[] checks = mChecker.getChecks(cfunc.getName()); 331 332 boolean lastWasIfcheck = false; 333 334 int index = 1; 335 if (checks != null) { 336 while (index < checks.length) { 337 if (checks[index].startsWith("check")) { 338 if (lastWasIfcheck) { 339 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, 340 offset, remaining, iii); 341 } 342 lastWasIfcheck = false; 343 if (cname != null && !cname.equals(checks[index + 1])) { 344 index += 3; 345 continue; 346 } 347 out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {"); 348 if (emitExceptionCheck) { 349 out.println(iii + indent + "_exception = 1;"); 350 } 351 String exceptionClassName = "java/lang/IllegalArgumentException"; 352 // If the "check" keyword was of the form 353 // "check_<class name>", use the class name in the 354 // exception to be thrown 355 int underscore = checks[index].indexOf('_'); 356 if (underscore >= 0) { 357 String abbr = checks[index].substring(underscore + 1); 358 if (abbr.equals("AIOOBE")) { 359 exceptionClassName = "java/lang/ArrayIndexOutOfBoundsException"; 360 } else { 361 throw new RuntimeException("unknown exception abbreviation: " + abbr); 362 } 363 } 364 out.println(iii + indent + "jniThrowException(_env, " + 365 "\"" + exceptionClassName + "\", " + 366 "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < " + checks[index + 2] + "\");"); 367 368 out.println(iii + indent + "goto exit;"); 369 needsExit = true; 370 out.println(iii + "}"); 371 372 index += 3; 373 } else if (checks[index].equals("ifcheck")) { 374 String[] matches = checks[index + 4].split(","); 375 376 if (!lastWasIfcheck) { 377 out.println(iii + "int _needed;"); 378 out.println(iii + "switch (" + checks[index + 3] + ") {"); 379 } 380 381 for (int i = 0; i < matches.length; i++) { 382 out.println("#if defined(" + matches[i] + ")"); 383 out.println(iii + " case " + matches[i] + ":"); 384 out.println("#endif // defined(" + matches[i] + ")"); 385 } 386 out.println(iii + " _needed = " + checks[index + 2] + ";"); 387 out.println(iii + " break;"); 388 389 lastWasIfcheck = true; 390 index += 5; 391 } else if (checks[index].equals("return")) { 392 // ignore 393 index += 2; 394 } else if (checks[index].equals("unsupported")) { 395 // ignore 396 index += 1; 397 } else if (checks[index].equals("requires")) { 398 // ignore 399 index += 2; 400 } else if (checks[index].equals("nullAllowed")) { 401 // ignore 402 index += 1; 403 } else { 404 System.out.println("Error: unknown keyword \"" + checks[index] + "\""); 405 System.exit(0); 406 } 407 } 408 } 409 410 if (lastWasIfcheck) { 411 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii); 412 } 413 } 414 415 boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) { 416 if (nonPrimitiveArgs.size() > 0) { 417 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 418 int idx = nonPrimitiveArgs.get(i).intValue(); 419 int cIndex = jfunc.getArgCIndex(idx); 420 if (jfunc.getArgType(idx).isArray()) { 421 if (!cfunc.getArgType(cIndex).isConst()) { 422 return true; 423 } 424 } else if (jfunc.getArgType(idx).isBuffer()) { 425 if (!cfunc.getArgType(cIndex).isConst()) { 426 return true; 427 } 428 } 429 } 430 } 431 432 return false; 433 } 434 435 /** 436 * Emit a function in several variants: 437 * 438 * if nativeDecl: public native <returntype> func(args); 439 * 440 * if !nativeDecl: 441 * if interfaceDecl: public <returntype> func(args); 442 * if !interfaceDecl: public <returntype> func(args) { body } 443 */ 444 void emitFunction(JFunc jfunc, PrintStream out, boolean nativeDecl, boolean interfaceDecl) { 445 boolean isPointerFunc = isPointerFunc(jfunc); 446 447 if (!nativeDecl && !interfaceDecl && !isPointerFunc) { 448 // If it's not a pointer function, we've already emitted it 449 // with nativeDecl == true 450 return; 451 } 452 453 String maybeStatic = mUseStaticMethods ? "static " : ""; 454 455 if (isPointerFunc) { 456 out.println(indent + 457 (nativeDecl ? "private " + maybeStatic +"native " : 458 (interfaceDecl ? "" : "public ") + maybeStatic) + 459 jfunc.getType() + " " + 460 jfunc.getName() + 461 (nativeDecl ? "Bounds" : "") + 462 "("); 463 } else { 464 out.println(indent + 465 (nativeDecl ? "public " + maybeStatic +"native " : 466 (interfaceDecl ? "" : "public ") + maybeStatic) + 467 jfunc.getType() + " " + 468 jfunc.getName() + 469 "("); 470 } 471 472 int numArgs = jfunc.getNumArgs(); 473 for (int i = 0; i < numArgs; i++) { 474 String argName = jfunc.getArgName(i); 475 JType argType = jfunc.getArgType(i); 476 477 out.print(indent + indent + argType + " " + argName); 478 if (i == numArgs - 1) { 479 if (isPointerFunc && nativeDecl) { 480 out.println(","); 481 out.println(indent + indent + "int remaining"); 482 } else { 483 out.println(); 484 } 485 } else { 486 out.println(","); 487 } 488 } 489 490 if (nativeDecl || interfaceDecl) { 491 out.println(indent + ");"); 492 } else { 493 out.println(indent + ") {"); 494 495 String iii = indent + indent; 496 497 // emitBoundsChecks(jfunc, out, iii); 498 emitFunctionCall(jfunc, out, iii, false); 499 500 // Set the pointer after we call the native code, so that if 501 // the native code throws an exception we don't modify the 502 // pointer. We assume that the native code is written so that 503 // if an exception is thrown, then the underlying glXXXPointer 504 // function will not have been called. 505 506 String fname = jfunc.getName(); 507 if (isPointerFunc) { 508 // TODO - deal with VBO variants 509 if (fname.equals("glColorPointer")) { 510 out.println(iii + "if ((size == 4) &&"); 511 out.println(iii + " ((type == GL_FLOAT) ||"); 512 out.println(iii + " (type == GL_UNSIGNED_BYTE) ||"); 513 out.println(iii + " (type == GL_FIXED)) &&"); 514 out.println(iii + " (stride >= 0)) {"); 515 out.println(iii + indent + "_colorPointer = pointer;"); 516 out.println(iii + "}"); 517 } else if (fname.equals("glNormalPointer")) { 518 out.println(iii + "if (((type == GL_FLOAT) ||"); 519 out.println(iii + " (type == GL_BYTE) ||"); 520 out.println(iii + " (type == GL_SHORT) ||"); 521 out.println(iii + " (type == GL_FIXED)) &&"); 522 out.println(iii + " (stride >= 0)) {"); 523 out.println(iii + indent + "_normalPointer = pointer;"); 524 out.println(iii + "}"); 525 } else if (fname.equals("glTexCoordPointer")) { 526 out.println(iii + "if (((size == 2) ||"); 527 out.println(iii + " (size == 3) ||"); 528 out.println(iii + " (size == 4)) &&"); 529 out.println(iii + " ((type == GL_FLOAT) ||"); 530 out.println(iii + " (type == GL_BYTE) ||"); 531 out.println(iii + " (type == GL_SHORT) ||"); 532 out.println(iii + " (type == GL_FIXED)) &&"); 533 out.println(iii + " (stride >= 0)) {"); 534 out.println(iii + indent + "_texCoordPointer = pointer;"); 535 out.println(iii + "}"); 536 } else if (fname.equals("glVertexPointer")) { 537 out.println(iii + "if (((size == 2) ||"); 538 out.println(iii + " (size == 3) ||"); 539 out.println(iii + " (size == 4)) &&"); 540 out.println(iii + " ((type == GL_FLOAT) ||"); 541 out.println(iii + " (type == GL_BYTE) ||"); 542 out.println(iii + " (type == GL_SHORT) ||"); 543 out.println(iii + " (type == GL_FIXED)) &&"); 544 out.println(iii + " (stride >= 0)) {"); 545 out.println(iii + indent + "_vertexPointer = pointer;"); 546 out.println(iii + "}"); 547 } else if (fname.equals("glPointSizePointerOES")) { 548 out.println(iii + "if (((type == GL_FLOAT) ||"); 549 out.println(iii + " (type == GL_FIXED)) &&"); 550 out.println(iii + " (stride >= 0)) {"); 551 out.println(iii + indent + "_pointSizePointerOES = pointer;"); 552 out.println(iii + "}"); 553 } else if (fname.equals("glMatrixIndexPointerOES")) { 554 out.println(iii + "if (((size == 2) ||"); 555 out.println(iii + " (size == 3) ||"); 556 out.println(iii + " (size == 4)) &&"); 557 out.println(iii + " ((type == GL_FLOAT) ||"); 558 out.println(iii + " (type == GL_BYTE) ||"); 559 out.println(iii + " (type == GL_SHORT) ||"); 560 out.println(iii + " (type == GL_FIXED)) &&"); 561 out.println(iii + " (stride >= 0)) {"); 562 out.println(iii + indent + "_matrixIndexPointerOES = pointer;"); 563 out.println(iii + "}"); 564 } else if (fname.equals("glWeightPointer")) { 565 out.println(iii + "if (((size == 2) ||"); 566 out.println(iii + " (size == 3) ||"); 567 out.println(iii + " (size == 4)) &&"); 568 out.println(iii + " ((type == GL_FLOAT) ||"); 569 out.println(iii + " (type == GL_BYTE) ||"); 570 out.println(iii + " (type == GL_SHORT) ||"); 571 out.println(iii + " (type == GL_FIXED)) &&"); 572 out.println(iii + " (stride >= 0)) {"); 573 out.println(iii + indent + "_weightPointerOES = pointer;"); 574 out.println(iii + "}"); 575 } 576 } 577 578 boolean isVoid = jfunc.getType().isVoid(); 579 580 if (!isVoid) { 581 out.println(indent + indent + "return _returnValue;"); 582 } 583 out.println(indent + "}"); 584 } 585 out.println(); 586 } 587 588 public void addNativeRegistration(String s) { 589 nativeRegistrations.add(s); 590 } 591 592 public void emitNativeRegistration(String registrationFunctionName, 593 PrintStream cStream) { 594 cStream.println("static const char *classPathName = \"" + 595 mClassPathName + 596 "\";"); 597 cStream.println(); 598 599 cStream.println("static JNINativeMethod methods[] = {"); 600 601 cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },"); 602 603 Iterator<String> i = nativeRegistrations.iterator(); 604 while (i.hasNext()) { 605 cStream.println(i.next()); 606 } 607 608 cStream.println("};"); 609 cStream.println(); 610 611 612 cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)"); 613 cStream.println("{"); 614 cStream.println(indent + 615 "int err;"); 616 617 cStream.println(indent + 618 "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));"); 619 620 cStream.println(indent + "return err;"); 621 cStream.println("}"); 622 } 623 624 public JniCodeEmitter() { 625 super(); 626 } 627 628 String getJniType(JType jType) { 629 if (jType.isVoid()) { 630 return "void"; 631 } 632 633 String baseType = jType.getBaseType(); 634 if (jType.isPrimitive()) { 635 if (baseType.equals("String")) { 636 return "jstring"; 637 } else { 638 return "j" + baseType; 639 } 640 } else if (jType.isArray()) { 641 return "j" + baseType + "Array"; 642 } else { 643 return "jobject"; 644 } 645 } 646 647 String getJniMangledName(String name) { 648 name = name.replaceAll("_", "_1"); 649 name = name.replaceAll(";", "_2"); 650 name = name.replaceAll("\\[", "_3"); 651 return name; 652 } 653 654 public void emitJniCode(JFunc jfunc, PrintStream out) { 655 CFunc cfunc = jfunc.getCFunc(); 656 657 // Emit comment identifying original C function 658 // 659 // Example: 660 // 661 // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */ 662 // 663 out.println("/* " + cfunc.getOriginal() + " */"); 664 665 // Emit JNI signature (name) 666 // 667 // Example: 668 // 669 // void 670 // android_glClipPlanef__I_3FI 671 // 672 673 String outName = "android_" + jfunc.getName(); 674 boolean isPointerFunc = isPointerFunc(jfunc); 675 boolean isVBOPointerFunc = (outName.endsWith("Pointer") || 676 outName.endsWith("PointerOES") || 677 outName.endsWith("DrawElements") || outName.endsWith("VertexAttribPointer")) && 678 !jfunc.getCFunc().hasPointerArg(); 679 if (isPointerFunc) { 680 outName += "Bounds"; 681 } 682 683 out.print("static "); 684 out.println(getJniType(jfunc.getType())); 685 out.print(outName); 686 687 String rsignature = getJniName(jfunc.getType()); 688 689 String signature = ""; 690 int numArgs = jfunc.getNumArgs(); 691 for (int i = 0; i < numArgs; i++) { 692 JType argType = jfunc.getArgType(i); 693 signature += getJniName(argType); 694 } 695 if (isPointerFunc) { 696 signature += "I"; 697 } 698 699 // Append signature to function name 700 String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_'); 701 out.print("__" + sig); 702 outName += "__" + sig; 703 704 signature = signature.replace('.', '/'); 705 rsignature = rsignature.replace('.', '/'); 706 707 out.println(); 708 if (rsignature.length() == 0) { 709 rsignature = "V"; 710 } 711 712 String s = "{\"" + 713 jfunc.getName() + 714 (isPointerFunc ? "Bounds" : "") + 715 "\", \"(" + signature +")" + 716 rsignature + 717 "\", (void *) " + 718 outName + 719 " },"; 720 nativeRegistrations.add(s); 721 722 List<Integer> nonPrimitiveArgs = new ArrayList<Integer>(); 723 List<Integer> stringArgs = new ArrayList<Integer>(); 724 int numBufferArgs = 0; 725 List<String> bufferArgNames = new ArrayList<String>(); 726 727 // Emit JNI signature (arguments) 728 // 729 // Example: 730 // 731 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) { 732 // 733 out.print(" (JNIEnv *_env, jobject _this"); 734 for (int i = 0; i < numArgs; i++) { 735 out.print(", "); 736 JType argType = jfunc.getArgType(i); 737 String suffix; 738 if (!argType.isPrimitive()) { 739 if (argType.isArray()) { 740 suffix = "_ref"; 741 } else { 742 suffix = "_buf"; 743 } 744 nonPrimitiveArgs.add(new Integer(i)); 745 if (jfunc.getArgType(i).isBuffer()) { 746 int cIndex = jfunc.getArgCIndex(i); 747 String cname = cfunc.getArgName(cIndex); 748 bufferArgNames.add(cname); 749 numBufferArgs++; 750 } 751 } else { 752 suffix = ""; 753 } 754 if (argType.isString()) { 755 stringArgs.add(new Integer(i)); 756 } 757 758 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix); 759 } 760 if (isPointerFunc) { 761 out.print(", jint remaining"); 762 } 763 out.println(") {"); 764 765 int numArrays = 0; 766 int numBuffers = 0; 767 int numStrings = 0; 768 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 769 int idx = nonPrimitiveArgs.get(i).intValue(); 770 JType argType = jfunc.getArgType(idx); 771 if (argType.isArray()) { 772 ++numArrays; 773 } 774 if (argType.isBuffer()) { 775 ++numBuffers; 776 } 777 if (argType.isString()) { 778 ++numStrings; 779 } 780 } 781 782 // Emit method body 783 784 // Emit local variable declarations for _exception and _returnValue 785 // 786 // Example: 787 // 788 // android::gl::ogles_context_t *ctx; 789 // 790 // jint _exception; 791 // GLenum _returnValue; 792 // 793 CType returnType = cfunc.getType(); 794 boolean isVoid = returnType.isVoid(); 795 796 boolean isUnsupported = isUnsupportedFunc(cfunc); 797 if (isUnsupported) { 798 out.println(indent + 799 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 800 out.println(indent + 801 " \"" + cfunc.getName() + "\");"); 802 if (!isVoid) { 803 String retval = getErrorReturnValue(cfunc); 804 out.println(indent + "return " + retval + ";"); 805 } 806 out.println("}"); 807 out.println(); 808 return; 809 } 810 811 String requiresExtension = isRequiresFunc(cfunc); 812 if (requiresExtension != null) { 813 out.println(indent + 814 "if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {"); 815 out.println(indent + indent + 816 "jniThrowException(_env, \"java/lang/UnsupportedOperationException\","); 817 out.println(indent + indent + 818 " \"" + cfunc.getName() + "\");"); 819 if (isVoid) { 820 out.println(indent + indent + " return;"); 821 } else { 822 String retval = getErrorReturnValue(cfunc); 823 out.println(indent + indent + " return " + retval + ";"); 824 } 825 out.println(indent + "}"); 826 } 827 if (mUseContextPointer) { 828 out.println(indent + 829 "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); 830 } 831 832 boolean initializeReturnValue = stringArgs.size() > 0; 833 834 boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0 || numStrings > 0) && 835 hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs); 836 // mChecker.getChecks(cfunc.getName()) != null 837 838 // Emit an _exeption variable if there will be error checks 839 if (emitExceptionCheck) { 840 out.println(indent + "jint _exception = 0;"); 841 } 842 843 // Emit a single _array or multiple _XXXArray variables 844 if (numBufferArgs == 1) { 845 out.println(indent + "jarray _array = (jarray) 0;"); 846 } else { 847 for (int i = 0; i < numBufferArgs; i++) { 848 out.println(indent + "jarray _" + bufferArgNames.get(i) + 849 "Array = (jarray) 0;"); 850 } 851 } 852 if (!isVoid) { 853 String retval = getErrorReturnValue(cfunc); 854 if (retval != null) { 855 out.println(indent + returnType.getDeclaration() + 856 " _returnValue = " + retval + ";"); 857 } else if (initializeReturnValue) { 858 out.println(indent + returnType.getDeclaration() + 859 " _returnValue = 0;"); 860 } else { 861 out.println(indent + returnType.getDeclaration() + 862 " _returnValue;"); 863 } 864 } 865 866 // Emit local variable declarations for pointer arguments 867 // 868 // Example: 869 // 870 // GLfixed *eqn_base; 871 // GLfixed *eqn; 872 // 873 String offset = "offset"; 874 String remaining = "_remaining"; 875 if (nonPrimitiveArgs.size() > 0) { 876 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 877 int idx = nonPrimitiveArgs.get(i).intValue(); 878 int cIndex = jfunc.getArgCIndex(idx); 879 String cname = cfunc.getArgName(cIndex); 880 881 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 882 String decl = type.getDeclaration(); 883 if (jfunc.getArgType(idx).isArray()) { 884 out.println(indent + 885 decl + 886 (decl.endsWith("*") ? "" : " ") + 887 jfunc.getArgName(idx) + 888 "_base = (" + decl + ") 0;"); 889 } 890 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 891 "_" + cname + "Remaining"; 892 out.println(indent + 893 "jint " + remaining + ";"); 894 out.println(indent + 895 decl + 896 (decl.endsWith("*") ? "" : " ") + 897 jfunc.getArgName(idx) + 898 " = (" + decl + ") 0;"); 899 } 900 901 out.println(); 902 } 903 904 // Emit local variable declaration for strings 905 if (stringArgs.size() > 0) { 906 for (int i = 0; i < stringArgs.size(); i++) { 907 int idx = stringArgs.get(i).intValue(); 908 int cIndex = jfunc.getArgCIndex(idx); 909 String cname = cfunc.getArgName(cIndex); 910 911 out.println(indent + "const char* _native" + cname + " = 0;"); 912 } 913 914 out.println(); 915 } 916 917 // Null pointer checks and GetStringUTFChars 918 if (stringArgs.size() > 0) { 919 for (int i = 0; i < stringArgs.size(); i++) { 920 int idx = stringArgs.get(i).intValue(); 921 int cIndex = jfunc.getArgCIndex(idx); 922 String cname = cfunc.getArgName(cIndex); 923 924 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); 925 String decl = type.getDeclaration(); 926 out.println(indent + "if (!" + cname + ") {"); 927 out.println(indent + " jniThrowException(_env, " + 928 "\"java/lang/IllegalArgumentException\", \"" + cname + " == null\");"); 929 out.println(indent + " goto exit;"); 930 needsExit = true; 931 out.println(indent + "}"); 932 933 out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);"); 934 } 935 936 out.println(); 937 } 938 939 // Emit 'GetPrimitiveArrayCritical' for arrays 940 // Emit 'GetPointer' calls for Buffer pointers 941 int bufArgIdx = 0; 942 if (nonPrimitiveArgs.size() > 0) { 943 for (int i = 0; i < nonPrimitiveArgs.size(); i++) { 944 int idx = nonPrimitiveArgs.get(i).intValue(); 945 int cIndex = jfunc.getArgCIndex(idx); 946 947 String cname = cfunc.getArgName(cIndex); 948 offset = numArrays <= 1 ? "offset" : 949 cname + "Offset"; 950 remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : 951 "_" + cname + "Remaining"; 952 953 if (jfunc.getArgType(idx).isArray()) { 954 out.println(indent + 955 "if (!" + 956 cname + 957 "_ref) {"); 958 if (emitExceptionCheck) { 959 out.println(indent + indent + "_exception = 1;"); 960 } 961 out.println(indent + " jniThrowException(_env, " + 962 "\"java/lang/IllegalArgumentException\", " + 963 "\"" + cname + " == null\");"); 964 out.println(indent + " goto exit;"); 965 needsExit = true; 966 out.println(indent + "}"); 967 968 out.println(indent + "if (" + offset + " < 0) {"); 969 if (emitExceptionCheck) { 970 out.println(indent + indent + "_exception = 1;"); 971 } 972 out.println(indent + " jniThrowException(_env, " + 973 "\"java/lang/IllegalArgumentException\", \"" + offset + " < 0\");"); 974 out.println(indent + " goto exit;"); 975 needsExit = true; 976 out.println(indent + "}"); 977 978 out.println(indent + remaining + " = " + 979 (mUseCPlusPlus ? "_env" : "(*_env)") + 980 "->GetArrayLength(" + 981 (mUseCPlusPlus ? "" : "_env, ") + 982 cname + "_ref) - " + offset + ";"); 983 984 emitNativeBoundsChecks(cfunc, cname, out, false, 985 emitExceptionCheck, 986 offset, remaining, " "); 987 988 out.println(indent + 989 cname + 990 "_base = (" + 991 cfunc.getArgType(cIndex).getDeclaration() + 992 ")"); 993 out.println(indent + " " + 994 (mUseCPlusPlus ? "_env" : "(*_env)") + 995 "->GetPrimitiveArrayCritical(" + 996 (mUseCPlusPlus ? "" : "_env, ") + 997 jfunc.getArgName(idx) + 998 "_ref, (jboolean *)0);"); 999 out.println(indent + 1000 cname + " = " + cname + "_base + " + offset + 1001 ";"); 1002 out.println(); 1003 } else { 1004 String array = numBufferArgs <= 1 ? "_array" : 1005 "_" + bufferArgNames.get(bufArgIdx++) + "Array"; 1006 1007 boolean nullAllowed = isNullAllowed(cfunc) || isPointerFunc; 1008 if (nullAllowed) { 1009 out.println(indent + "if (" + cname + "_buf) {"); 1010 out.print(indent); 1011 } 1012 1013 if (isPointerFunc) { 1014 out.println(indent + 1015 cname + 1016 " = (" + 1017 cfunc.getArgType(cIndex).getDeclaration() + 1018 ") getDirectBufferPointer(_env, " + 1019 cname + "_buf);"); 1020 String iii = " "; 1021 out.println(iii + indent + "if ( ! " + cname + " ) {"); 1022 out.println(iii + iii + indent + "return;"); 1023 out.println(iii + indent + "}"); 1024 } else { 1025 out.println(indent + 1026 cname + 1027 " = (" + 1028 cfunc.getArgType(cIndex).getDeclaration() + 1029 ")getPointer(_env, " + 1030 cname + 1031 "_buf, &" + array + ", &" + remaining + 1032 ");"); 1033 } 1034 1035 emitNativeBoundsChecks(cfunc, cname, out, true, 1036 emitExceptionCheck, 1037 offset, remaining, nullAllowed ? " " : " "); 1038 1039 if (nullAllowed) { 1040 out.println(indent + "}"); 1041 } 1042 } 1043 } 1044 } 1045 1046 if (!isVoid) { 1047 out.print(indent + "_returnValue = "); 1048 } else { 1049 out.print(indent); 1050 } 1051 String name = cfunc.getName(); 1052 1053 if (mUseContextPointer) { 1054 name = name.substring(2, name.length()); // Strip off 'gl' prefix 1055 name = name.substring(0, 1).toLowerCase() + 1056 name.substring(1, name.length()); 1057 out.print("ctx->procs."); 1058 } 1059 1060 out.print(name + (isPointerFunc ? "Bounds" : "") + "("); 1061 1062 numArgs = cfunc.getNumArgs(); 1063 if (numArgs == 0) { 1064 if (mUseContextPointer) { 1065 out.println("ctx);"); 1066 } else { 1067 out.println(");"); 1068 } 1069 } else { 1070 if (mUseContextPointer) { 1071 out.println("ctx,"); 1072 } else { 1073 out.println(); 1074 } 1075 for (int i = 0; i < numArgs; i++) { 1076 String typecast; 1077 if (i == numArgs - 1 && isVBOPointerFunc) { 1078 typecast = "const GLvoid *"; 1079 } else { 1080 typecast = cfunc.getArgType(i).getDeclaration(); 1081 } 1082 out.print(indent + indent + 1083 "(" + 1084 typecast + 1085 ")"); 1086 if (cfunc.getArgType(i).isConstCharPointer()) { 1087 out.print("_native"); 1088 } 1089 out.print(cfunc.getArgName(i)); 1090 1091 if (i == numArgs - 1) { 1092 if (isPointerFunc) { 1093 out.println(","); 1094 out.println(indent + indent + "(GLsizei)remaining"); 1095 } else { 1096 out.println(); 1097 } 1098 } else { 1099 out.println(","); 1100 } 1101 } 1102 out.println(indent + ");"); 1103 } 1104 1105 if (needsExit) { 1106 out.println(); 1107 out.println("exit:"); 1108 needsExit = false; 1109 } 1110 1111 bufArgIdx = 0; 1112 if (nonPrimitiveArgs.size() > 0) { 1113 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { 1114 int idx = nonPrimitiveArgs.get(i).intValue(); 1115 1116 int cIndex = jfunc.getArgCIndex(idx); 1117 if (jfunc.getArgType(idx).isArray()) { 1118 1119 // If the argument is 'const', GL will not write to it. 1120 // In this case, we can use the 'JNI_ABORT' flag to avoid 1121 // the need to write back to the Java array 1122 out.println(indent + 1123 "if (" + jfunc.getArgName(idx) + "_base) {"); 1124 out.println(indent + indent + 1125 (mUseCPlusPlus ? "_env" : "(*_env)") + 1126 "->ReleasePrimitiveArrayCritical(" + 1127 (mUseCPlusPlus ? "" : "_env, ") + 1128 jfunc.getArgName(idx) + "_ref, " + 1129 cfunc.getArgName(cIndex) + 1130 "_base,"); 1131 out.println(indent + indent + indent + 1132 (cfunc.getArgType(cIndex).isConst() ? 1133 "JNI_ABORT" : 1134 "_exception ? JNI_ABORT: 0") + 1135 ");"); 1136 out.println(indent + "}"); 1137 } else if (jfunc.getArgType(idx).isBuffer()) { 1138 if (! isPointerFunc) { 1139 String array = numBufferArgs <= 1 ? "_array" : 1140 "_" + bufferArgNames.get(bufArgIdx++) + "Array"; 1141 out.println(indent + "if (" + array + ") {"); 1142 out.println(indent + indent + 1143 "releasePointer(_env, " + array + ", " + 1144 cfunc.getArgName(cIndex) + 1145 ", " + 1146 (cfunc.getArgType(cIndex).isConst() ? 1147 "JNI_FALSE" : "_exception ? JNI_FALSE :" + 1148 " JNI_TRUE") + 1149 ");"); 1150 out.println(indent + "}"); 1151 } 1152 } 1153 } 1154 } 1155 1156 // Emit local variable declaration for strings 1157 if (stringArgs.size() > 0) { 1158 for (int i = 0; i < stringArgs.size(); i++) { 1159 int idx = stringArgs.get(i).intValue(); 1160 int cIndex = jfunc.getArgCIndex(idx); 1161 String cname = cfunc.getArgName(cIndex); 1162 1163 out.println(indent + "if (_native" + cname + ") {"); 1164 out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");"); 1165 out.println(indent + "}"); 1166 } 1167 1168 out.println(); 1169 } 1170 1171 1172 if (!isVoid) { 1173 out.println(indent + "return _returnValue;"); 1174 } 1175 1176 out.println("}"); 1177 out.println(); 1178 } 1179 1180 } 1181