mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Bug 1086693 - Part 5: Add a 'catchException' mode to JNI generator r=ckitching
This commit is contained in:
parent
f793c98f19
commit
4f5b795709
@ -12,12 +12,19 @@ public class AnnotationInfo {
|
||||
public final boolean isMultithreaded;
|
||||
public final boolean noThrow;
|
||||
public final boolean narrowChars;
|
||||
public final boolean catchException;
|
||||
|
||||
public AnnotationInfo(String aWrapperName, boolean aIsMultithreaded,
|
||||
boolean aNoThrow, boolean aNarrowChars) {
|
||||
boolean aNoThrow, boolean aNarrowChars, boolean aCatchException) {
|
||||
wrapperName = aWrapperName;
|
||||
isMultithreaded = aIsMultithreaded;
|
||||
noThrow = aNoThrow;
|
||||
narrowChars = aNarrowChars;
|
||||
catchException = aCatchException;
|
||||
|
||||
if (!noThrow && catchException) {
|
||||
// It doesn't make sense to have these together
|
||||
throw new IllegalArgumentException("noThrow and catchException are not allowed together");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,8 +111,10 @@ public class CodeGenerator {
|
||||
Class<?> returnType = theMethod.getReturnType();
|
||||
|
||||
// Get the C++ method signature for this method.
|
||||
String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, mCClassName, aMethodTuple.mAnnotationInfo.narrowChars);
|
||||
String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, CMethodName, mCClassName, isFieldStatic, aMethodTuple.mAnnotationInfo.narrowChars);
|
||||
String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName,
|
||||
mCClassName, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException);
|
||||
String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType,
|
||||
CMethodName, mCClassName, isFieldStatic, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException);
|
||||
|
||||
// Add the header signature to the header file.
|
||||
writeSignatureToHeader(headerSignature);
|
||||
@ -121,7 +123,8 @@ public class CodeGenerator {
|
||||
writeMethodBody(implementationSignature, theMethod, mClassToWrap,
|
||||
aMethodTuple.mAnnotationInfo.isMultithreaded,
|
||||
aMethodTuple.mAnnotationInfo.noThrow,
|
||||
aMethodTuple.mAnnotationInfo.narrowChars);
|
||||
aMethodTuple.mAnnotationInfo.narrowChars,
|
||||
aMethodTuple.mAnnotationInfo.catchException);
|
||||
}
|
||||
|
||||
private void generateGetterOrSetterBody(Field aField, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) {
|
||||
@ -196,8 +199,8 @@ public class CodeGenerator {
|
||||
boolean isFieldFinal = Utils.isMemberFinal(theField);
|
||||
|
||||
String getterName = "get" + CFieldName;
|
||||
String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars);
|
||||
String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars);
|
||||
String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false);
|
||||
String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false);
|
||||
|
||||
writeSignatureToHeader(getterHeaderSignature);
|
||||
|
||||
@ -211,8 +214,8 @@ public class CodeGenerator {
|
||||
|
||||
Class<?>[] setterArguments = new Class<?>[]{fieldType};
|
||||
|
||||
String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars);
|
||||
String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars);
|
||||
String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false);
|
||||
String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false);
|
||||
|
||||
writeSignatureToHeader(setterHeaderSignature);
|
||||
|
||||
@ -229,8 +232,10 @@ public class CodeGenerator {
|
||||
|
||||
generateMemberCommon(theCtor, mCClassName, mClassToWrap);
|
||||
|
||||
String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, mCClassName, aCtorTuple.mAnnotationInfo.narrowChars);
|
||||
String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars);
|
||||
String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName,
|
||||
mCClassName, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException);
|
||||
String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName,
|
||||
mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException);
|
||||
|
||||
// Slice off the "void " from the start of the constructor declaration.
|
||||
headerSignature = headerSignature.substring(5);
|
||||
@ -242,7 +247,8 @@ public class CodeGenerator {
|
||||
// Use the implementation signature to generate the method body...
|
||||
writeCtorBody(implementationSignature, theCtor,
|
||||
aCtorTuple.mAnnotationInfo.isMultithreaded,
|
||||
aCtorTuple.mAnnotationInfo.noThrow);
|
||||
aCtorTuple.mAnnotationInfo.noThrow,
|
||||
aCtorTuple.mAnnotationInfo.catchException);
|
||||
|
||||
if (theCtor.getParameterTypes().length == 0) {
|
||||
mHasEncounteredDefaultConstructor = true;
|
||||
@ -258,7 +264,7 @@ public class CodeGenerator {
|
||||
String name = m.getName();
|
||||
name = name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
|
||||
AnnotationInfo info = new AnnotationInfo(name, true, true, true);
|
||||
AnnotationInfo info = new AnnotationInfo(name, true, true, true, true);
|
||||
AnnotatableEntity entity = new AnnotatableEntity(m, info);
|
||||
if (m instanceof Constructor) {
|
||||
generateConstructor(entity);
|
||||
@ -408,8 +414,20 @@ public class CodeGenerator {
|
||||
return argumentContent;
|
||||
}
|
||||
|
||||
private void writeCatchException() {
|
||||
wrapperMethodBodies.append(
|
||||
" if (env->ExceptionCheck()) {\n" +
|
||||
" env->ExceptionClear();\n" +
|
||||
" if (aResult) {\n" +
|
||||
" *aResult = NS_ERROR_FAILURE;\n" +
|
||||
" }\n" +
|
||||
" } else if (aResult) {\n" +
|
||||
" *aResult = NS_OK;\n" +
|
||||
" }\n\n");
|
||||
}
|
||||
|
||||
private void writeCtorBody(String implementationSignature, Constructor<?> theCtor,
|
||||
boolean aIsThreaded, boolean aNoThrow) {
|
||||
boolean aIsThreaded, boolean aNoThrow, boolean aCatchException) {
|
||||
Class<?>[] argumentTypes = theCtor.getParameterTypes();
|
||||
|
||||
writeFunctionStartupBoilerPlate(implementationSignature, aIsThreaded);
|
||||
@ -443,9 +461,14 @@ public class CodeGenerator {
|
||||
wrapperMethodBodies.append(mMembersToIds.get(theCtor))
|
||||
// Tack on the arguments, if any..
|
||||
.append(argumentContent)
|
||||
.append("), env);\n" +
|
||||
" env->PopLocalFrame(nullptr);\n" +
|
||||
"}\n");
|
||||
.append("), env);\n");
|
||||
|
||||
// Check for exception and set aResult
|
||||
if (aCatchException) {
|
||||
writeCatchException();
|
||||
}
|
||||
|
||||
wrapperMethodBodies.append(" env->PopLocalFrame(nullptr);\n}\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -458,7 +481,8 @@ public class CodeGenerator {
|
||||
*/
|
||||
private void writeMethodBody(String methodSignature, Method aMethod,
|
||||
Class<?> aClass, boolean aIsMultithreaded,
|
||||
boolean aNoThrow, boolean aNarrowChars) {
|
||||
boolean aNoThrow, boolean aNarrowChars,
|
||||
boolean aCatchException) {
|
||||
Class<?>[] argumentTypes = aMethod.getParameterTypes();
|
||||
Class<?> returnType = aMethod.getReturnType();
|
||||
|
||||
@ -526,6 +550,11 @@ public class CodeGenerator {
|
||||
wrapperMethodBodies.append(" AndroidBridge::HandleUncaughtException(env);\n");
|
||||
}
|
||||
|
||||
// Check for exception and set aResult
|
||||
if (aCatchException) {
|
||||
writeCatchException();
|
||||
}
|
||||
|
||||
// If we're returning an object, pop the callee's stack frame extracting our ref as the return
|
||||
// value.
|
||||
if (isObjectReturningMethod) {
|
||||
|
@ -76,6 +76,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
boolean isMultithreadedStub = false;
|
||||
boolean noThrow = false;
|
||||
boolean narrowChars = false;
|
||||
boolean catchException = false;
|
||||
try {
|
||||
// Determine the explicitly-given name of the stub to generate, if any.
|
||||
final Method stubNameMethod = annotationType.getDeclaredMethod("stubName");
|
||||
@ -97,6 +98,11 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
narrowCharsMethod.setAccessible(true);
|
||||
narrowChars = (Boolean) narrowCharsMethod.invoke(annotation);
|
||||
|
||||
// Determine if we should catch exceptions
|
||||
final Method catchExceptionMethod = annotationType.getDeclaredMethod("catchException");
|
||||
catchExceptionMethod.setAccessible(true);
|
||||
catchException = (Boolean) catchExceptionMethod.invoke(annotation);
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.err.println("Unable to find expected field on WrapElementForJNI annotation. Did the signature change?");
|
||||
e.printStackTrace(System.err);
|
||||
@ -118,7 +124,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
}
|
||||
|
||||
AnnotationInfo annotationInfo = new AnnotationInfo(
|
||||
stubName, isMultithreadedStub, noThrow, narrowChars);
|
||||
stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
|
||||
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
|
||||
return;
|
||||
}
|
||||
@ -128,7 +134,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
// thanks to the "Generate everything" annotation.
|
||||
if (mIterateEveryEntry) {
|
||||
AnnotationInfo annotationInfo = new AnnotationInfo(
|
||||
candidateElement.getName(), false, false, false);
|
||||
candidateElement.getName(), false, false, false, false);
|
||||
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
|
||||
return;
|
||||
}
|
||||
|
@ -388,7 +388,8 @@ public class Utils {
|
||||
* @param aCClassName Name of the C++ class into which the method is declared.
|
||||
* @return The C++ method implementation signature for the method described.
|
||||
*/
|
||||
public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aNarrowChars) {
|
||||
public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType,
|
||||
String aCMethodName, String aCClassName, boolean aNarrowChars, boolean aCatchException) {
|
||||
StringBuilder retBuffer = new StringBuilder();
|
||||
|
||||
retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
|
||||
@ -410,6 +411,14 @@ public class Utils {
|
||||
retBuffer.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
if (aCatchException) {
|
||||
if (aArgumentTypes.length > 0) {
|
||||
retBuffer.append(", ");
|
||||
}
|
||||
retBuffer.append("nsresult* aResult");
|
||||
}
|
||||
|
||||
retBuffer.append(')');
|
||||
return retBuffer.toString();
|
||||
}
|
||||
@ -427,7 +436,8 @@ public class Utils {
|
||||
* @param aIsStaticStub true if the generated C++ method should be static, false otherwise.
|
||||
* @return The generated C++ header method signature for the method described.
|
||||
*/
|
||||
public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars) {
|
||||
public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType,
|
||||
String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars, boolean aCatchException) {
|
||||
StringBuilder retBuffer = new StringBuilder();
|
||||
|
||||
// Add the static keyword, if applicable.
|
||||
@ -457,6 +467,14 @@ public class Utils {
|
||||
retBuffer.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
if (aCatchException) {
|
||||
if (aArgumentTypes.length > 0) {
|
||||
retBuffer.append(", ");
|
||||
}
|
||||
retBuffer.append("nsresult* aResult = nullptr");
|
||||
}
|
||||
|
||||
retBuffer.append(')');
|
||||
return retBuffer.toString();
|
||||
}
|
||||
|
@ -44,5 +44,14 @@ public @interface WrapElementForJNI {
|
||||
*/
|
||||
boolean noThrow() default false;
|
||||
|
||||
/**
|
||||
* If set, uses UTF-8 strings
|
||||
*/
|
||||
boolean narrowChars() default false;
|
||||
|
||||
/**
|
||||
* If set, the generated stub will catch any exception thrown and
|
||||
* set a passed-in nsresult to NS_ERROR_FAILURE
|
||||
*/
|
||||
boolean catchException() default false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user