Skip to content

Commit

Permalink
Bug 1086693 - Part 5: Add a 'catchException' mode to JNI generator r=…
Browse files Browse the repository at this point in the history
…ckitching
  • Loading branch information
snorp committed Nov 13, 2014
1 parent f793c98 commit 4f5b795
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 21 deletions.
9 changes: 8 additions & 1 deletion build/annotationProcessors/AnnotationInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}
}
61 changes: 45 additions & 16 deletions build/annotationProcessors/CodeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,10 @@ public void generateMethod(AnnotatableEntity aMethodTuple) {
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);
Expand All @@ -121,7 +123,8 @@ public void generateMethod(AnnotatableEntity aMethodTuple) {
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) {
Expand Down Expand Up @@ -196,8 +199,8 @@ public void generateField(AnnotatableEntity aFieldTuple) {
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);

Expand All @@ -211,8 +214,8 @@ public void generateField(AnnotatableEntity aFieldTuple) {

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);

Expand All @@ -229,8 +232,10 @@ public void generateConstructor(AnnotatableEntity aCtorTuple) {

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);
Expand All @@ -242,7 +247,8 @@ public void generateConstructor(AnnotatableEntity aCtorTuple) {
// 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;
Expand All @@ -258,7 +264,7 @@ public void generateMembers(Member[] members) {
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);
Expand Down Expand Up @@ -408,8 +414,20 @@ private StringBuilder getArgumentMarshalling(Class<?>[] argumentTypes) {
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);
Expand Down Expand Up @@ -443,9 +461,14 @@ private void writeCtorBody(String implementationSignature, Constructor<?> theCto
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");
}

/**
Expand All @@ -458,7 +481,8 @@ private void writeCtorBody(String implementationSignature, Constructor<?> theCto
*/
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();

Expand Down Expand Up @@ -526,6 +550,11 @@ private void writeMethodBody(String methodSignature, Method aMethod,
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) {
Expand Down
10 changes: 8 additions & 2 deletions build/annotationProcessors/utils/GeneratableElementIterator.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ private void findNextValue() {
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");
Expand All @@ -97,6 +98,11 @@ private void findNextValue() {
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);
Expand All @@ -118,7 +124,7 @@ private void findNextValue() {
}

AnnotationInfo annotationInfo = new AnnotationInfo(
stubName, isMultithreadedStub, noThrow, narrowChars);
stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
return;
}
Expand All @@ -128,7 +134,7 @@ private void findNextValue() {
// 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;
}
Expand Down
22 changes: 20 additions & 2 deletions build/annotationProcessors/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,8 @@ private static void writeTypeSignature(StringBuilder sb, Class<?> c) {
* @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));
Expand All @@ -410,6 +411,14 @@ public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes
retBuffer.append(", ");
}
}

if (aCatchException) {
if (aArgumentTypes.length > 0) {
retBuffer.append(", ");
}
retBuffer.append("nsresult* aResult");
}

retBuffer.append(')');
return retBuffer.toString();
}
Expand All @@ -427,7 +436,8 @@ public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes
* @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.
Expand Down Expand Up @@ -457,6 +467,14 @@ public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annota
retBuffer.append(", ");
}
}

if (aCatchException) {
if (aArgumentTypes.length > 0) {
retBuffer.append(", ");
}
retBuffer.append("nsresult* aResult = nullptr");
}

retBuffer.append(')');
return retBuffer.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,14 @@
*/
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;
}

0 comments on commit 4f5b795

Please sign in to comment.