blob: 2a8bcbb8ba48d8bf71ecce0929afceced41f1678 [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001import java.io.PrintStream;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08002import java.util.ArrayList;
3import java.util.HashSet;
4import java.util.Iterator;
5import java.util.List;
6
7/**
8 * Emits a Java interface and Java & C implementation for a C function.
9 *
10 * <p> The Java interface will have Buffer and array variants for functions that
11 * have a typed pointer argument. The array variant will convert a single "<type> *data"
12 * argument to a pair of arguments "<type>[] data, int offset".
13 */
14public class JniCodeEmitter implements CodeEmitter {
15
16 // If true, use C++ style for calling through a JNIEnv *:
17 // env->Func(...)
18 // If false, use C style:
19 // (*env)->Func(env, ...)
20 static final boolean mUseCPlusPlus = true;
21
22 boolean mUseContextPointer = true;
23
24 String mClassPathName;
Jack Palevich6cbca502009-04-13 16:22:25 -070025
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080026 ParameterChecker mChecker;
27 PrintStream mJava10InterfaceStream;
28 PrintStream mJava10ExtInterfaceStream;
29 PrintStream mJava11InterfaceStream;
30 PrintStream mJava11ExtInterfaceStream;
31 PrintStream mJava11ExtPackInterfaceStream;
32 PrintStream mJavaImplStream;
33 PrintStream mCStream;
34
35 PrintStream mJavaInterfaceStream;
36
37 List<String> nativeRegistrations = new ArrayList<String>();
38
39 boolean needsExit;
40
41 static String indent = " ";
42
43 HashSet<String> mFunctionsEmitted = new HashSet<String>();
44
45 /**
46 * @param java10InterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 functions
47 * @param java10ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 extension functions
Jack Palevich6cbca502009-04-13 16:22:25 -070048 * @param java11InterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 functions
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080049 * @param java11ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension functions
50 * @param java11ExtPackInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension Pack functions
51 * @param javaImplStream the PrintStream to which to emit the Java implementation
52 * @param cStream the PrintStream to which to emit the C implementation
53 */
54 public JniCodeEmitter(String classPathName,
55 ParameterChecker checker,
56 PrintStream java10InterfaceStream,
57 PrintStream java10ExtInterfaceStream,
58 PrintStream java11InterfaceStream,
59 PrintStream java11ExtInterfaceStream,
60 PrintStream java11ExtPackInterfaceStream,
61 PrintStream javaImplStream,
62 PrintStream cStream,
63 boolean useContextPointer) {
64 mClassPathName = classPathName;
65 mChecker = checker;
66 mJava10InterfaceStream = java10InterfaceStream;
67 mJava10ExtInterfaceStream = java10ExtInterfaceStream;
68 mJava11InterfaceStream = java11InterfaceStream;
69 mJava11ExtInterfaceStream = java11ExtInterfaceStream;
70 mJava11ExtPackInterfaceStream = java11ExtPackInterfaceStream;
71 mJavaImplStream = javaImplStream;
72 mCStream = cStream;
73 mUseContextPointer = useContextPointer;
74 }
75
76 public void setVersion(int version, boolean ext, boolean pack) {
77 if (version == 0) {
78 mJavaInterfaceStream = ext ? mJava10ExtInterfaceStream :
79 mJava10InterfaceStream;
80 } else if (version == 1) {
81 mJavaInterfaceStream = ext ?
82 (pack ? mJava11ExtPackInterfaceStream :
83 mJava11ExtInterfaceStream) :
84 mJava11InterfaceStream;
85 } else {
86 throw new RuntimeException("Bad version: " + version);
87 }
88 }
89
90 public void emitCode(CFunc cfunc, String original) {
91 JFunc jfunc;
92 String signature;
93 boolean duplicate;
Jack Palevich6cbca502009-04-13 16:22:25 -070094
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080095 if (cfunc.hasTypedPointerArg()) {
96 jfunc = JFunc.convert(cfunc, true);
97
98 // Don't emit duplicate functions
99 // These may appear because they are defined in multiple
100 // Java interfaces (e.g., GL11/GL11ExtensionPack)
101 signature = jfunc.toString();
102 duplicate = false;
103 if (mFunctionsEmitted.contains(signature)) {
104 duplicate = true;
105 } else {
106 mFunctionsEmitted.add(signature);
107 }
108
109 if (!duplicate) {
110 emitNativeDeclaration(jfunc, mJavaImplStream);
111 emitJavaCode(jfunc, mJavaImplStream);
112 }
113 emitJavaInterfaceCode(jfunc, mJavaInterfaceStream);
114 if (!duplicate) {
115 emitJniCode(jfunc, mCStream);
116 }
117 }
118
119 jfunc = JFunc.convert(cfunc, false);
120
121 signature = jfunc.toString();
122 duplicate = false;
123 if (mFunctionsEmitted.contains(signature)) {
124 duplicate = true;
125 } else {
126 mFunctionsEmitted.add(signature);
127 }
128
129 if (!duplicate) {
130 emitNativeDeclaration(jfunc, mJavaImplStream);
131 }
132 emitJavaInterfaceCode(jfunc, mJavaInterfaceStream);
133 if (!duplicate) {
134 emitJavaCode(jfunc, mJavaImplStream);
135 emitJniCode(jfunc, mCStream);
136 }
137 }
138
139 public void emitNativeDeclaration(JFunc jfunc, PrintStream out) {
140 out.println(" // C function " + jfunc.getCFunc().getOriginal());
141 out.println();
142
143 emitFunction(jfunc, out, true, false);
144 }
145
146 public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) {
147 emitFunction(jfunc, out, false, true);
148 }
149
150 public void emitJavaCode(JFunc jfunc, PrintStream out) {
151 emitFunction(jfunc, out, false, false);
152 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700153
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800154 void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray ) {
155 boolean isVoid = jfunc.getType().isVoid();
156 boolean isPointerFunc = jfunc.getName().endsWith("Pointer") &&
157 jfunc.getCFunc().hasPointerArg();
158
159 if (!isVoid) {
160 out.println(iii +
161 jfunc.getType() + " _returnValue;");
162 }
163 out.println(iii +
164 (isVoid ? "" : "_returnValue = ") +
165 jfunc.getName() +
166 (isPointerFunc ? "Bounds" : "" ) +
167 "(");
Jack Palevich6cbca502009-04-13 16:22:25 -0700168
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800169 int numArgs = jfunc.getNumArgs();
170 for (int i = 0; i < numArgs; i++) {
171 String argName = jfunc.getArgName(i);
172 JType argType = jfunc.getArgType(i);
173
174 if (grabArray && argType.isTypedBuffer()) {
175 String typeName = argType.getBaseType();
176 typeName = typeName.substring(9, typeName.length() - 6);
177 out.println(iii + indent + "get" + typeName + "Array(" + argName + "),");
Jack Palevich6cbca502009-04-13 16:22:25 -0700178 out.print(iii + indent + "getOffset(" + argName + ")");
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800179 } else {
180 out.print(iii + indent + argName);
181 }
182 if (i == numArgs - 1) {
183 if (isPointerFunc) {
184 out.println(",");
185 out.println(iii + indent + argName + ".remaining()");
186 } else {
187 out.println();
188 }
189 } else {
190 out.println(",");
191 }
192 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700193
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800194 out.println(iii + ");");
195 }
196
197 void printIfcheckPostamble(PrintStream out, boolean isBuffer,
198 boolean emitExceptionCheck, String iii) {
199 printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
200 "offset", "_remaining", iii);
201 }
202
203 void printIfcheckPostamble(PrintStream out, boolean isBuffer,
204 boolean emitExceptionCheck,
205 String offset, String remaining, String iii) {
206 out.println(iii + " default:");
207 out.println(iii + " _needed = 0;");
208 out.println(iii + " break;");
209 out.println(iii + "}");
210
211 out.println(iii + "if (" + remaining + " < _needed) {");
212 if (emitExceptionCheck) {
213 out.println(iii + indent + "_exception = 1;");
214 }
215 out.println(iii + indent +
216 (mUseCPlusPlus ? "_env" : "(*_env)") +
217 "->ThrowNew(" +
218 (mUseCPlusPlus ? "" : "_env, ") +
219 "IAEClass, " +
220 "\"" +
Jack Palevich6cbca502009-04-13 16:22:25 -0700221 (isBuffer ?
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800222 "remaining()" : "length - " + offset) +
223 " < needed\");");
224 out.println(iii + indent + "goto exit;");
225 needsExit = true;
226 out.println(iii + "}");
227 }
228
229 boolean isNullAllowed(CFunc cfunc) {
230 String[] checks = mChecker.getChecks(cfunc.getName());
231 int index = 1;
232 if (checks != null) {
233 while (index < checks.length) {
234 if (checks[index].equals("return")) {
235 index += 2;
236 } else if (checks[index].startsWith("check")) {
237 index += 3;
238 } else if (checks[index].equals("ifcheck")) {
239 index += 5;
240 } else if (checks[index].equals("unsupported")) {
241 index += 1;
242 } else if (checks[index].equals("nullAllowed")) {
243 return true;
244 } else {
245 System.out.println("Error: unknown keyword \"" +
246 checks[index] + "\"");
247 System.exit(0);
248 }
249 }
250 }
251 return false;
252 }
253
254 String getErrorReturnValue(CFunc cfunc) {
255 CType returnType = cfunc.getType();
256 boolean isVoid = returnType.isVoid();
257 if (isVoid) {
258 return null;
259 }
260
261 String[] checks = mChecker.getChecks(cfunc.getName());
262
263 int index = 1;
264 if (checks != null) {
265 while (index < checks.length) {
266 if (checks[index].equals("return")) {
267 return checks[index + 1];
268 } else if (checks[index].startsWith("check")) {
269 index += 3;
270 } else if (checks[index].equals("ifcheck")) {
271 index += 5;
272 } else if (checks[index].equals("unsupported")) {
273 index += 1;
274 } else if (checks[index].equals("nullAllowed")) {
275 index += 1;
276 } else {
277 System.out.println("Error: unknown keyword \"" +
278 checks[index] + "\"");
279 System.exit(0);
280 }
281 }
282 }
283
284 return null;
285 }
286
287 boolean isUnsupportedFunc(CFunc cfunc) {
288 String[] checks = mChecker.getChecks(cfunc.getName());
289 int index = 1;
290 if (checks != null) {
291 while (index < checks.length) {
292 if (checks[index].equals("unsupported")) {
293 return true;
294 } else if (checks[index].equals("return")) {
295 index += 2;
296 } else if (checks[index].startsWith("check")) {
297 index += 3;
298 } else if (checks[index].equals("ifcheck")) {
299 index += 5;
300 } else if (checks[index].equals("nullAllowed")) {
301 index += 1;
302 } else {
303 System.out.println("Error: unknown keyword \"" +
304 checks[index] + "\"");
305 System.exit(0);
306 }
307 }
308 }
309 return false;
310 }
311
312 void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
313 boolean isBuffer, boolean emitExceptionCheck,
314 String offset, String remaining, String iii) {
315 CType returnType = cfunc.getType();
316 boolean isVoid = returnType.isVoid();
317
318 String[] checks = mChecker.getChecks(cfunc.getName());
319 String checkVar;
320 String retval = getErrorReturnValue(cfunc);
321
322 boolean lastWasIfcheck = false;
323
324 int index = 1;
325 if (checks != null) {
326 boolean remainingDeclared = false;
327 boolean nullCheckDeclared = false;
328 boolean offsetChecked = false;
329 while (index < checks.length) {
330 if (checks[index].startsWith("check")) {
331 if (lastWasIfcheck) {
332 printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
333 offset, remaining, iii);
334 }
335 lastWasIfcheck = false;
336 if (cname != null && !cname.equals(checks[index + 1])) {
337 index += 3;
338 continue;
339 }
340 out.println(iii + "if (" + remaining + " < " +
341 checks[index + 2] +
342 ") {");
343 if (emitExceptionCheck) {
344 out.println(iii + indent + "_exception = 1;");
345 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700346 String exceptionClassName = "IAEClass";
347 // If the "check" keyword was of the form
348 // "check_<class name>", use the class name in the
349 // exception to be thrown
350 int underscore = checks[index].indexOf('_');
351 if (underscore >= 0) {
352 exceptionClassName = checks[index].substring(underscore + 1) + "Class";
353 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800354 out.println(iii + indent +
355 (mUseCPlusPlus ? "_env" : "(*_env)") +
356 "->ThrowNew(" +
357 (mUseCPlusPlus ? "" : "_env, ") +
Jack Palevich6cbca502009-04-13 16:22:25 -0700358 exceptionClassName + ", " +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800359 "\"" +
Jack Palevich6cbca502009-04-13 16:22:25 -0700360 (isBuffer ?
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800361 "remaining()" : "length - " + offset) +
362 " < " + checks[index + 2] +
363 "\");");
364
365 out.println(iii + indent + "goto exit;");
366 needsExit = true;
367 out.println(iii + "}");
Jack Palevich6cbca502009-04-13 16:22:25 -0700368
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800369 index += 3;
370 } else if (checks[index].equals("ifcheck")) {
371 String[] matches = checks[index + 4].split(",");
372
373 if (!lastWasIfcheck) {
374 out.println(iii + "int _needed;");
375 out.println(iii +
376 "switch (" +
377 checks[index + 3] +
378 ") {");
379 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700380
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800381 for (int i = 0; i < matches.length; i++) {
382 out.println("#if defined(" + matches[i] + ")");
383 out.println(iii +
384 " case " +
385 matches[i] +
386 ":");
387 out.println("#endif // defined(" + matches[i] + ")");
388 }
389 out.println(iii +
390 " _needed = " +
391 checks[index + 2] +
392 ";");
393 out.println(iii +
394 " break;");
Jack Palevich6cbca502009-04-13 16:22:25 -0700395
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800396 lastWasIfcheck = true;
397 index += 5;
398 } else if (checks[index].equals("return")) {
399 // ignore
400 index += 2;
401 } else if (checks[index].equals("unsupported")) {
402 // ignore
403 index += 1;
404 } else if (checks[index].equals("nullAllowed")) {
405 // ignore
406 index += 1;
407 } else {
408 System.out.println("Error: unknown keyword \"" +
409 checks[index] + "\"");
410 System.exit(0);
411 }
412 }
413 }
414
415 if (lastWasIfcheck) {
416 printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
417 }
418 }
419
420 boolean hasNonConstArg(JFunc jfunc, CFunc cfunc,
421 List<Integer> nonPrimitiveArgs) {
422 if (nonPrimitiveArgs.size() > 0) {
423 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
424 int idx = nonPrimitiveArgs.get(i).intValue();
425 int cIndex = jfunc.getArgCIndex(idx);
426 if (jfunc.getArgType(idx).isArray()) {
427 if (!cfunc.getArgType(cIndex).isConst()) {
428 return true;
429 }
430 } else if (jfunc.getArgType(idx).isBuffer()) {
431 if (!cfunc.getArgType(cIndex).isConst()) {
432 return true;
433 }
434 }
435 }
436 }
437
438 return false;
439 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700440
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800441 /**
442 * Emit a function in several variants:
443 *
444 * if nativeDecl: public native <returntype> func(args);
445 *
446 * if !nativeDecl:
447 * if interfaceDecl: public <returntype> func(args);
448 * if !interfaceDecl: public <returntype> func(args) { body }
449 */
450 void emitFunction(JFunc jfunc,
451 PrintStream out,
452 boolean nativeDecl, boolean interfaceDecl) {
453 boolean isPointerFunc =
454 jfunc.getName().endsWith("Pointer") &&
455 jfunc.getCFunc().hasPointerArg();
456
457 if (!nativeDecl && !interfaceDecl && !isPointerFunc) {
458 // If it's not a pointer function, we've already emitted it
459 // with nativeDecl == true
460 return;
461 }
462
463 if (isPointerFunc) {
464 out.println(indent +
465 (nativeDecl ? "private native " :
466 (interfaceDecl ? "" : "public ")) +
467 jfunc.getType() + " " +
468 jfunc.getName() +
469 (nativeDecl ? "Bounds" : "") +
470 "(");
471 } else {
472 out.println(indent +
473 (nativeDecl ? "public native " :
474 (interfaceDecl ? "" : "public ")) +
475 jfunc.getType() + " " +
476 jfunc.getName() +
477 "(");
478 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700479
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800480 int numArgs = jfunc.getNumArgs();
481 for (int i = 0; i < numArgs; i++) {
482 String argName = jfunc.getArgName(i);
483 JType argType = jfunc.getArgType(i);
Jack Palevich6cbca502009-04-13 16:22:25 -0700484
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800485 out.print(indent + indent + argType + " " + argName);
486 if (i == numArgs - 1) {
487 if (isPointerFunc && nativeDecl) {
488 out.println(",");
489 out.println(indent + indent + "int remaining");
490 } else {
491 out.println();
492 }
493 } else {
494 out.println(",");
495 }
496 }
497
498 if (nativeDecl || interfaceDecl) {
499 out.println(indent + ");");
500 } else {
501 out.println(indent + ") {");
502
503 String iii = indent + indent;
504
505 String fname = jfunc.getName();
506 if (isPointerFunc) {
507 // TODO - deal with VBO variants
508 if (fname.equals("glColorPointer")) {
509 out.println(iii + "if ((size == 4) &&");
510 out.println(iii + " ((type == GL_FLOAT) ||");
511 out.println(iii + " (type == GL_UNSIGNED_BYTE) ||");
512 out.println(iii + " (type == GL_FIXED)) &&");
513 out.println(iii + " (stride >= 0)) {");
514 out.println(iii + indent + "_colorPointer = pointer;");
515 out.println(iii + "}");
516 } else if (fname.equals("glNormalPointer")) {
517 out.println(iii + "if (((type == GL_FLOAT) ||");
518 out.println(iii + " (type == GL_BYTE) ||");
519 out.println(iii + " (type == GL_SHORT) ||");
520 out.println(iii + " (type == GL_FIXED)) &&");
521 out.println(iii + " (stride >= 0)) {");
522 out.println(iii + indent + "_normalPointer = pointer;");
523 out.println(iii + "}");
524 } else if (fname.equals("glTexCoordPointer")) {
525 out.println(iii + "if (((size == 2) ||");
526 out.println(iii + " (size == 3) ||");
527 out.println(iii + " (size == 4)) &&");
528 out.println(iii + " ((type == GL_FLOAT) ||");
529 out.println(iii + " (type == GL_BYTE) ||");
530 out.println(iii + " (type == GL_SHORT) ||");
531 out.println(iii + " (type == GL_FIXED)) &&");
532 out.println(iii + " (stride >= 0)) {");
533 out.println(iii + indent + "_texCoordPointer = pointer;");
534 out.println(iii + "}");
535 } else if (fname.equals("glVertexPointer")) {
536 out.println(iii + "if (((size == 2) ||");
537 out.println(iii + " (size == 3) ||");
538 out.println(iii + " (size == 4)) &&");
539 out.println(iii + " ((type == GL_FLOAT) ||");
540 out.println(iii + " (type == GL_BYTE) ||");
541 out.println(iii + " (type == GL_SHORT) ||");
542 out.println(iii + " (type == GL_FIXED)) &&");
543 out.println(iii + " (stride >= 0)) {");
544 out.println(iii + indent + "_vertexPointer = pointer;");
545 out.println(iii + "}");
546 }
547 }
548
549 // emitBoundsChecks(jfunc, out, iii);
550 emitFunctionCall(jfunc, out, iii, false);
551
552 boolean isVoid = jfunc.getType().isVoid();
553
554 if (!isVoid) {
555 out.println(indent + indent + "return _returnValue;");
556 }
557 out.println(indent + "}");
558 }
559 out.println();
560 }
561
562 public static String getJniName(JType jType) {
563 String jniName = "";
564 if (jType.isClass()) {
565 return "L" + jType.getBaseType() + ";";
566 } else if (jType.isArray()) {
567 jniName = "[";
568 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700569
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800570 String baseType = jType.getBaseType();
571 if (baseType.equals("int")) {
572 jniName += "I";
573 } else if (baseType.equals("float")) {
574 jniName += "F";
575 } else if (baseType.equals("boolean")) {
576 jniName += "Z";
577 } else if (baseType.equals("short")) {
578 jniName += "S";
579 } else if (baseType.equals("long")) {
580 jniName += "L";
581 } else if (baseType.equals("byte")) {
582 jniName += "B";
583 }
584 return jniName;
585 }
586
587 String getJniType(JType jType) {
588 if (jType.isVoid()) {
589 return "void";
590 }
591
592 String baseType = jType.getBaseType();
593 if (jType.isPrimitive()) {
594 if (baseType.equals("String")) {
595 return "jstring";
596 } else {
597 return "j" + baseType;
598 }
599 } else if (jType.isArray()) {
600 return "j" + baseType + "Array";
601 } else {
602 return "jobject";
603 }
604 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700605
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800606 String getJniMangledName(String name) {
607 name = name.replaceAll("_", "_1");
608 name = name.replaceAll(";", "_2");
609 name = name.replaceAll("\\[", "_3");
610 return name;
611 }
612
613 public void emitJniCode(JFunc jfunc, PrintStream out) {
614 CFunc cfunc = jfunc.getCFunc();
Jack Palevich6cbca502009-04-13 16:22:25 -0700615
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800616 // Emit comment identifying original C function
617 //
618 // Example:
619 //
620 // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */
621 //
622 out.println("/* " + cfunc.getOriginal() + " */");
623
624 // Emit JNI signature (name)
625 //
626 // Example:
627 //
628 // void
629 // android_glClipPlanef__I_3FI
630 //
631
632 String outName = "android_" + jfunc.getName();
633 boolean isPointerFunc = outName.endsWith("Pointer") &&
634 jfunc.getCFunc().hasPointerArg();
635 boolean isVBOPointerFunc = (outName.endsWith("Pointer") ||
636 outName.endsWith("DrawElements")) &&
637 !jfunc.getCFunc().hasPointerArg();
638 if (isPointerFunc) {
639 outName += "Bounds";
640 }
641
642 out.print("static ");
643 out.println(getJniType(jfunc.getType()));
644 out.print(outName);
645
646 String rsignature = getJniName(jfunc.getType());
647
648 String signature = "";
649 int numArgs = jfunc.getNumArgs();
650 for (int i = 0; i < numArgs; i++) {
651 JType argType = jfunc.getArgType(i);
652 signature += getJniName(argType);
653 }
654 if (isPointerFunc) {
655 signature += "I";
656 }
657
658 // Append signature to function name
Jack Palevich6cbca502009-04-13 16:22:25 -0700659 String sig = getJniMangledName(signature).replace('.', '_');
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800660 out.print("__" + sig);
661 outName += "__" + sig;
Jack Palevich6cbca502009-04-13 16:22:25 -0700662
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800663 signature = signature.replace('.', '/');
664 rsignature = rsignature.replace('.', '/');
Jack Palevich6cbca502009-04-13 16:22:25 -0700665
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800666 out.println();
667 if (rsignature.length() == 0) {
668 rsignature = "V";
669 }
670
671 String s = "{\"" +
672 jfunc.getName() +
673 (isPointerFunc ? "Bounds" : "") +
674 "\", \"(" + signature +")" +
675 rsignature +
676 "\", (void *) " +
677 outName +
678 " },";
679 nativeRegistrations.add(s);
680
681 List<Integer> nonPrimitiveArgs = new ArrayList<Integer>();
682 int numBufferArgs = 0;
683 List<String> bufferArgNames = new ArrayList<String>();
684
685 // Emit JNI signature (arguments)
686 //
687 // Example:
688 //
689 // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) {
690 //
691 out.print(" (JNIEnv *_env, jobject _this");
692 for (int i = 0; i < numArgs; i++) {
693 out.print(", ");
694 JType argType = jfunc.getArgType(i);
695 String suffix;
696 if (!argType.isPrimitive()) {
697 if (argType.isArray()) {
698 suffix = "_ref";
699 } else {
700 suffix = "_buf";
701 }
702 nonPrimitiveArgs.add(new Integer(i));
703 if (jfunc.getArgType(i).isBuffer()) {
704 int cIndex = jfunc.getArgCIndex(i);
705 String cname = cfunc.getArgName(cIndex);
706 bufferArgNames.add(cname);
707 numBufferArgs++;
708 }
709 } else {
710 suffix = "";
711 }
712
713 out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
714 }
715 if (isPointerFunc) {
716 out.print(", jint remaining");
717 }
718 out.println(") {");
Jack Palevich6cbca502009-04-13 16:22:25 -0700719
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800720 int numArrays = 0;
721 int numBuffers = 0;
722 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
723 int idx = nonPrimitiveArgs.get(i).intValue();
724 int cIndex = jfunc.getArgCIndex(idx);
725 String cname = cfunc.getArgName(cIndex);
726 if (jfunc.getArgType(idx).isArray()) {
727 ++numArrays;
728 }
729 if (jfunc.getArgType(idx).isBuffer()) {
730 ++numBuffers;
731 }
732 }
733
734 // Emit method body
735
736 // Emit local variable declarations for _exception and _returnValue
737 //
738 // Example:
739 //
740 // android::gl::ogles_context_t *ctx;
Jack Palevich6cbca502009-04-13 16:22:25 -0700741 //
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800742 // jint _exception;
743 // GLenum _returnValue;
744 //
745 CType returnType = cfunc.getType();
746 boolean isVoid = returnType.isVoid();
747
748 boolean isUnsupported = isUnsupportedFunc(cfunc);
749 if (isUnsupported) {
750 out.println(indent +
751 "_env->ThrowNew(UOEClass,");
752 out.println(indent +
753 " \"" + cfunc.getName() + "\");");
754 if (!isVoid) {
755 String retval = getErrorReturnValue(cfunc);
756 out.println(indent + "return " + retval + ";");
757 }
758 out.println("}");
759 out.println();
760 return;
761 }
762
763 if (mUseContextPointer) {
764 out.println(indent +
765 "android::gl::ogles_context_t *ctx = getContext(_env, _this);");
766 }
767
768 boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) &&
769 hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs);
770 // mChecker.getChecks(cfunc.getName()) != null
771
772 // Emit an _exeption variable if there will be error checks
773 if (emitExceptionCheck) {
774 out.println(indent + "jint _exception = 0;");
775 }
776
777 // Emit a single _array or multiple _XXXArray variables
778 if (numBufferArgs == 1) {
779 out.println(indent + "jarray _array = (jarray) 0;");
780 } else {
781 for (int i = 0; i < numBufferArgs; i++) {
782 out.println(indent + "jarray _" + bufferArgNames.get(i) +
783 "Array = (jarray) 0;");
784 }
785 }
786 if (!isVoid) {
787 String retval = getErrorReturnValue(cfunc);
788 if (retval != null) {
789 out.println(indent + returnType.getDeclaration() +
790 " _returnValue = " + retval + ";");
791 } else {
792 out.println(indent + returnType.getDeclaration() +
793 " _returnValue;");
794 }
795 }
796
797 // Emit local variable declarations for pointer arguments
798 //
799 // Example:
800 //
801 // GLfixed *eqn_base;
802 // GLfixed *eqn;
803 //
804 String offset = "offset";
805 String remaining = "_remaining";
806 if (nonPrimitiveArgs.size() > 0) {
807 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
808 int idx = nonPrimitiveArgs.get(i).intValue();
809 int cIndex = jfunc.getArgCIndex(idx);
810 String cname = cfunc.getArgName(cIndex);
811
812 CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
813 String decl = type.getDeclaration();
814 if (jfunc.getArgType(idx).isArray()) {
815 out.println(indent +
816 decl +
817 (decl.endsWith("*") ? "" : " ") +
818 jfunc.getArgName(idx) +
819 "_base = (" + decl + ") 0;");
820 }
821 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
822 "_" + cname + "Remaining";
823 out.println(indent +
824 "jint " + remaining + ";");
825 out.println(indent +
826 decl +
827 (decl.endsWith("*") ? "" : " ") +
Jack Palevich6cbca502009-04-13 16:22:25 -0700828 jfunc.getArgName(idx) +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800829 " = (" + decl + ") 0;");
830 }
831
832 out.println();
833 }
834
835 String retval = isVoid ? "" : " _returnValue";
836
837 // Emit 'GetPrimitiveArrayCritical' for arrays
838 // Emit 'GetPointer' calls for Buffer pointers
839 int bufArgIdx = 0;
840 if (nonPrimitiveArgs.size() > 0) {
841 for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
842 int idx = nonPrimitiveArgs.get(i).intValue();
843 int cIndex = jfunc.getArgCIndex(idx);
Jack Palevich6cbca502009-04-13 16:22:25 -0700844
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800845 String cname = cfunc.getArgName(cIndex);
846 offset = numArrays <= 1 ? "offset" :
847 cname + "Offset";
848 remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" :
849 "_" + cname + "Remaining";
850
851 if (jfunc.getArgType(idx).isArray()) {
852 out.println(indent +
Jack Palevich6cbca502009-04-13 16:22:25 -0700853 "if (!" +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800854 cname +
855 "_ref) {");
856 if (emitExceptionCheck) {
857 out.println(indent + indent + "_exception = 1;");
858 }
859 out.println(indent + " " +
860 (mUseCPlusPlus ? "_env" : "(*_env)") +
861 "->ThrowNew(" +
862 (mUseCPlusPlus ? "" : "_env, ") +
863 "IAEClass, " +
864 "\"" + cname +
865 " == null\");");
866 out.println(indent + " goto exit;");
867 needsExit = true;
868 out.println(indent + "}");
869
870 out.println(indent + "if (" + offset + " < 0) {");
871 if (emitExceptionCheck) {
872 out.println(indent + indent + "_exception = 1;");
873 }
874 out.println(indent + " " +
875 (mUseCPlusPlus ? "_env" : "(*_env)") +
876 "->ThrowNew(" +
877 (mUseCPlusPlus ? "" : "_env, ") +
878 "IAEClass, " +
879 "\"" + offset + " < 0\");");
880 out.println(indent + " goto exit;");
881 needsExit = true;
882 out.println(indent + "}");
883
884 out.println(indent + remaining + " = " +
Jack Palevich6cbca502009-04-13 16:22:25 -0700885 (mUseCPlusPlus ? "_env" : "(*_env)") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800886 "->GetArrayLength(" +
887 (mUseCPlusPlus ? "" : "_env, ") +
888 cname + "_ref) - " + offset + ";");
889
890 emitNativeBoundsChecks(cfunc, cname, out, false,
891 emitExceptionCheck,
892 offset, remaining, " ");
893
894 out.println(indent +
895 cname +
896 "_base = (" +
897 cfunc.getArgType(cIndex).getDeclaration() +
898 ")");
899 out.println(indent + " " +
900 (mUseCPlusPlus ? "_env" : "(*_env)") +
901 "->GetPrimitiveArrayCritical(" +
Jack Palevich6cbca502009-04-13 16:22:25 -0700902 (mUseCPlusPlus ? "" : "_env, ") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800903 jfunc.getArgName(idx) +
904 "_ref, (jboolean *)0);");
905 out.println(indent +
906 cname + " = " + cname + "_base + " + offset +
907 ";");
908 out.println();
909 } else {
910 String array = numBufferArgs <= 1 ? "_array" :
911 "_" + bufferArgNames.get(bufArgIdx++) + "Array";
912
913 boolean nullAllowed = isNullAllowed(cfunc);
914 if (nullAllowed) {
915 out.println(indent + "if (" + cname + "_buf) {");
916 out.print(indent);
917 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700918
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800919 out.println(indent +
920 cname +
921 " = (" +
922 cfunc.getArgType(cIndex).getDeclaration() +
923 ")getPointer(_env, " +
924 cname +
925 "_buf, &" + array + ", &" + remaining + ");");
926
927 if (nullAllowed) {
928 out.println(indent + "}");
929 }
930
931 emitNativeBoundsChecks(cfunc, cname, out, true,
932 emitExceptionCheck,
933 offset, remaining, " ");
934 }
935 }
936 }
937
938 if (!isVoid) {
939 out.print(indent + "_returnValue = ");
940 } else {
941 out.print(indent);
942 }
943 String name = cfunc.getName();
944
945 if (mUseContextPointer) {
946 name = name.substring(2, name.length()); // Strip off 'gl' prefix
947 name = name.substring(0, 1).toLowerCase() +
948 name.substring(1, name.length());
949 out.print("ctx->procs.");
950 }
Jack Palevich6cbca502009-04-13 16:22:25 -0700951
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800952 out.print(name + (isPointerFunc ? "Bounds" : "") + "(");
953
Jack Palevich6cbca502009-04-13 16:22:25 -0700954 numArgs = cfunc.getNumArgs();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800955 if (numArgs == 0) {
956 if (mUseContextPointer) {
957 out.println("ctx);");
958 } else {
959 out.println(");");
960 }
961 } else {
962 if (mUseContextPointer) {
963 out.println("ctx,");
964 } else {
965 out.println();
966 }
967 for (int i = 0; i < numArgs; i++) {
968 String typecast;
969 if (i == numArgs - 1 && isVBOPointerFunc) {
970 typecast = "const GLvoid *";
971 } else {
972 typecast = cfunc.getArgType(i).getDeclaration();
973 }
974 out.print(indent + indent +
975 "(" +
976 typecast +
977 ")" +
978 cfunc.getArgName(i));
979
980 if (i == numArgs - 1) {
981 if (isPointerFunc) {
982 out.println(",");
983 out.println(indent + indent + "(GLsizei)remaining");
984 } else {
985 out.println();
986 }
987 } else {
988 out.println(",");
989 }
990 }
991 out.println(indent + ");");
992 }
993
994 if (needsExit) {
995 out.println();
996 out.println("exit:");
997 needsExit = false;
998 }
999
1000 bufArgIdx = 0;
1001 if (nonPrimitiveArgs.size() > 0) {
1002 for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) {
1003 int idx = nonPrimitiveArgs.get(i).intValue();
1004
1005 int cIndex = jfunc.getArgCIndex(idx);
1006 if (jfunc.getArgType(idx).isArray()) {
Jack Palevich6cbca502009-04-13 16:22:25 -07001007
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001008 // If the argument is 'const', GL will not write to it.
1009 // In this case, we can use the 'JNI_ABORT' flag to avoid
1010 // the need to write back to the Java array
1011 out.println(indent +
1012 "if (" + jfunc.getArgName(idx) + "_base) {");
1013 out.println(indent + indent +
1014 (mUseCPlusPlus ? "_env" : "(*_env)") +
1015 "->ReleasePrimitiveArrayCritical(" +
Jack Palevich6cbca502009-04-13 16:22:25 -07001016 (mUseCPlusPlus ? "" : "_env, ") +
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001017 jfunc.getArgName(idx) + "_ref, " +
1018 cfunc.getArgName(cIndex) +
1019 "_base,");
1020 out.println(indent + indent + indent +
1021 (cfunc.getArgType(cIndex).isConst() ?
1022 "JNI_ABORT" :
1023 "_exception ? JNI_ABORT: 0") +
1024 ");");
1025 out.println(indent + "}");
1026 } else if (jfunc.getArgType(idx).isBuffer()) {
1027 String array = numBufferArgs <= 1 ? "_array" :
1028 "_" + bufferArgNames.get(bufArgIdx++) + "Array";
1029 out.println(indent + "if (" + array + ") {");
1030 out.println(indent + indent +
1031 "releasePointer(_env, " + array + ", " +
1032 cfunc.getArgName(cIndex) +
1033 ", " +
1034 (cfunc.getArgType(cIndex).isConst() ?
1035 "JNI_FALSE" : "_exception ? JNI_FALSE : JNI_TRUE") +
1036 ");");
1037 out.println(indent + "}");
1038 }
1039 }
1040 }
1041
1042 if (!isVoid) {
1043 out.println(indent + "return _returnValue;");
1044 }
1045
1046 out.println("}");
1047 out.println();
1048 }
1049
1050 public void addNativeRegistration(String s) {
1051 nativeRegistrations.add(s);
1052 }
1053
1054 public void emitNativeRegistration() {
1055 mCStream.println("static const char *classPathName = \"" +
1056 mClassPathName +
1057 "\";");
1058 mCStream.println();
1059
1060 mCStream.println("static JNINativeMethod methods[] = {");
1061
1062 mCStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },");
1063
1064 Iterator<String> i = nativeRegistrations.iterator();
1065 while (i.hasNext()) {
1066 mCStream.println(i.next());
1067 }
1068
1069 mCStream.println("};");
1070 mCStream.println();
Jack Palevich6cbca502009-04-13 16:22:25 -07001071
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001072
1073 mCStream.println("int register_com_google_android_gles_jni_GLImpl(JNIEnv *_env)");
1074 mCStream.println("{");
1075 mCStream.println(indent +
1076 "int err;");
1077
1078 mCStream.println(indent +
1079 "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));");
1080
1081 mCStream.println(indent + "return err;");
1082 mCStream.println("}");
1083 }
1084}