summaryrefslogtreecommitdiff
path: root/build/annotationProcessors/CodeGenerator.java
diff options
context:
space:
mode:
Diffstat (limited to 'build/annotationProcessors/CodeGenerator.java')
-rw-r--r--build/annotationProcessors/CodeGenerator.java627
1 files changed, 0 insertions, 627 deletions
diff --git a/build/annotationProcessors/CodeGenerator.java b/build/annotationProcessors/CodeGenerator.java
deleted file mode 100644
index 56d257c037..0000000000
--- a/build/annotationProcessors/CodeGenerator.java
+++ /dev/null
@@ -1,627 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.annotationProcessors;
-
-import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
-import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
-import org.mozilla.gecko.annotationProcessors.utils.Utils;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.HashSet;
-
-public class CodeGenerator {
- private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
-
- // Buffers holding the strings to ultimately be written to the output files.
- private final StringBuilder cpp = new StringBuilder();
- private final StringBuilder header = new StringBuilder();
- private final StringBuilder natives = new StringBuilder();
- private final StringBuilder nativesInits = new StringBuilder();
-
- private final Class<?> cls;
- private final String clsName;
- private AnnotationInfo.CallingThread callingThread = null;
- private int numNativesInits;
-
- private final HashSet<String> takenMethodNames = new HashSet<String>();
-
- public CodeGenerator(ClassWithOptions annotatedClass) {
- this.cls = annotatedClass.wrappedClass;
- this.clsName = annotatedClass.generatedName;
-
- final String unqualifiedName = Utils.getUnqualifiedName(clsName);
- header.append(
- "class " + clsName + " : public mozilla::jni::ObjectBase<" +
- unqualifiedName + ">\n" +
- "{\n" +
- "public:\n" +
- " static const char name[];\n" +
- "\n" +
- " explicit " + unqualifiedName + "(const Context& ctx) : ObjectBase<" +
- unqualifiedName + ">(ctx) {}\n" +
- "\n");
-
- cpp.append(
- "const char " + clsName + "::name[] =\n" +
- " \"" + cls.getName().replace('.', '/') + "\";\n" +
- "\n");
-
- natives.append(
- "template<class Impl>\n" +
- "class " + clsName + "::Natives : " +
- "public mozilla::jni::NativeImpl<" + unqualifiedName + ", Impl>\n" +
- "{\n" +
- "public:\n");
- }
-
- private String getTraitsName(String uniqueName, boolean includeScope) {
- return (includeScope ? clsName + "::" : "") + uniqueName + "_t";
- }
-
- /**
- * Return the C++ type name for this class or any class within the chain
- * of declaring classes, if the target class matches the given type.
- *
- * Return null if the given type does not match any class searched.
- */
- private String getMatchingClassType(final Class<?> type) {
- Class<?> cls = this.cls;
- String clsName = this.clsName;
-
- while (cls != null) {
- if (type.equals(cls)) {
- return clsName;
- }
- cls = cls.getDeclaringClass();
- clsName = clsName.substring(0, Math.max(0, clsName.lastIndexOf("::")));
- }
- return null;
- }
-
- private String getNativeParameterType(Class<?> type, AnnotationInfo info) {
- final String clsName = getMatchingClassType(type);
- if (clsName != null) {
- return Utils.getUnqualifiedName(clsName) + "::Param";
- }
- return Utils.getNativeParameterType(type, info);
- }
-
- private String getNativeReturnType(Class<?> type, AnnotationInfo info) {
- final String clsName = getMatchingClassType(type);
- if (clsName != null) {
- return Utils.getUnqualifiedName(clsName) + "::LocalRef";
- }
- return Utils.getNativeReturnType(type, info);
- }
-
- private void generateMember(AnnotationInfo info, Member member,
- String uniqueName, Class<?> type, Class<?>[] argTypes) {
- final StringBuilder args = new StringBuilder();
- for (Class<?> argType : argTypes) {
- args.append("\n " + getNativeParameterType(argType, info) + ",");
- }
- if (args.length() > 0) {
- args.setLength(args.length() - 1);
- }
-
- header.append(
- " struct " + getTraitsName(uniqueName, /* includeScope */ false) + " {\n" +
- " typedef " + Utils.getUnqualifiedName(clsName) + " Owner;\n" +
- " typedef " + getNativeReturnType(type, info) + " ReturnType;\n" +
- " typedef " + getNativeParameterType(type, info) + " SetterType;\n" +
- " typedef mozilla::jni::Args<" + args + "> Args;\n" +
- " static constexpr char name[] = \"" +
- Utils.getMemberName(member) + "\";\n" +
- " static constexpr char signature[] =\n" +
- " \"" + Utils.getSignature(member) + "\";\n" +
- " static const bool isStatic = " + Utils.isStatic(member) + ";\n" +
- " static const mozilla::jni::ExceptionMode exceptionMode =\n" +
- " " + info.exceptionMode.nativeValue() + ";\n" +
- " static const mozilla::jni::CallingThread callingThread =\n" +
- " " + info.callingThread.nativeValue() + ";\n" +
- " static const mozilla::jni::DispatchTarget dispatchTarget =\n" +
- " " + info.dispatchTarget.nativeValue() + ";\n" +
- " };\n" +
- "\n");
-
- cpp.append(
- "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
- "::name[];\n" +
- "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
- "::signature[];\n" +
- "\n");
-
- if (this.callingThread == null) {
- this.callingThread = info.callingThread;
- } else if (this.callingThread != info.callingThread) {
- // We have a mix of calling threads, so specify "any" for the whole class.
- this.callingThread = AnnotationInfo.CallingThread.ANY;
- }
- }
-
- private String getUniqueMethodName(String basename) {
- String newName = basename;
- int index = 1;
-
- while (takenMethodNames.contains(newName)) {
- newName = basename + (++index);
- }
-
- takenMethodNames.add(newName);
- return newName;
- }
-
- /**
- * Generate a method prototype that includes return and argument types,
- * without specifiers (static, const, etc.).
- */
- private String generatePrototype(String name, Class<?>[] argTypes,
- Class<?> returnType, AnnotationInfo info,
- boolean includeScope, boolean includeArgName,
- boolean isConst) {
-
- final StringBuilder proto = new StringBuilder();
- int argIndex = 0;
-
- proto.append("auto ");
-
- if (includeScope) {
- proto.append(clsName).append("::");
- }
-
- proto.append(name).append('(');
-
- for (Class<?> argType : argTypes) {
- proto.append(getNativeParameterType(argType, info));
- if (includeArgName) {
- proto.append(" a").append(argIndex++);
- }
- proto.append(", ");
- }
-
- if (info.exceptionMode == AnnotationInfo.ExceptionMode.NSRESULT &&
- !returnType.equals(void.class)) {
- proto.append(getNativeReturnType(returnType, info)).append('*');
- if (includeArgName) {
- proto.append(" a").append(argIndex++);
- }
- proto.append(", ");
- }
-
- if (proto.substring(proto.length() - 2).equals(", ")) {
- proto.setLength(proto.length() - 2);
- }
-
- proto.append(')');
-
- if (isConst) {
- proto.append(" const");
- }
-
- if (info.exceptionMode == AnnotationInfo.ExceptionMode.NSRESULT) {
- proto.append(" -> nsresult");
- } else {
- proto.append(" -> ").append(getNativeReturnType(returnType, info));
- }
- return proto.toString();
- }
-
- /**
- * Generate a method declaration that includes the prototype with specifiers,
- * but without the method body.
- */
- private String generateDeclaration(String name, Class<?>[] argTypes,
- Class<?> returnType, AnnotationInfo info,
- boolean isStatic) {
-
- return (isStatic ? "static " : "") +
- generatePrototype(name, argTypes, returnType, info,
- /* includeScope */ false, /* includeArgName */ false,
- /* isConst */ !isStatic) + ';';
- }
-
- /**
- * Generate a method definition that includes the prototype with specifiers,
- * and with the method body.
- */
- private String generateDefinition(String accessorName, String name, Class<?>[] argTypes,
- Class<?> returnType, AnnotationInfo info, boolean isStatic) {
-
- final StringBuilder def = new StringBuilder(
- generatePrototype(name, argTypes, returnType, info,
- /* includeScope */ true, /* includeArgName */ true,
- /* isConst */ !isStatic));
- def.append("\n{\n");
-
-
- // Generate code to handle the return value, if needed.
- // We initialize rv to NS_OK instead of NS_ERROR_* because loading NS_OK (0) uses
- // fewer instructions. We are guaranteed to set rv to the correct value later.
-
- if (info.exceptionMode == AnnotationInfo.ExceptionMode.NSRESULT &&
- returnType.equals(void.class)) {
- def.append(
- " nsresult rv = NS_OK;\n" +
- " ");
-
- } else if (info.exceptionMode == AnnotationInfo.ExceptionMode.NSRESULT) {
- // Non-void return type
- final String resultArg = "a" + argTypes.length;
- def.append(
- " MOZ_ASSERT(" + resultArg + ");\n" +
- " nsresult rv = NS_OK;\n" +
- " *" + resultArg + " = ");
-
- } else {
- def.append(
- " return ");
- }
-
-
- // Generate a call, e.g., Method<Traits>::Call(a0, a1, a2);
-
- def.append(accessorName).append("(")
- .append(Utils.getUnqualifiedName(clsName) +
- (isStatic ? "::Context()" : "::mCtx"));
-
- if (info.exceptionMode == AnnotationInfo.ExceptionMode.NSRESULT) {
- def.append(", &rv");
- } else {
- def.append(", nullptr");
- }
-
- // Generate the call argument list.
- for (int argIndex = 0; argIndex < argTypes.length; argIndex++) {
- def.append(", a").append(argIndex);
- }
-
- def.append(");\n");
-
-
- if (info.exceptionMode == AnnotationInfo.ExceptionMode.NSRESULT) {
- def.append(" return rv;\n");
- }
-
- return def.append("}").toString();
- }
-
- /**
- * Append the appropriate generated code to the buffers for the method provided.
- *
- * @param annotatedMethod The Java method, plus annotation data.
- */
- public void generateMethod(AnnotatableEntity annotatedMethod) {
- // Unpack the tuple and extract some useful fields from the Method..
- final Method method = annotatedMethod.getMethod();
- final AnnotationInfo info = annotatedMethod.mAnnotationInfo;
- final String uniqueName = getUniqueMethodName(info.wrapperName);
- final Class<?>[] argTypes = method.getParameterTypes();
- final Class<?> returnType = method.getReturnType();
-
- if (method.isSynthetic()) {
- return;
- }
-
- // Sanity check
- if (info.dispatchTarget != AnnotationInfo.DispatchTarget.CURRENT) {
- throw new IllegalStateException("Invalid dispatch target \"" +
- info.dispatchTarget.name().toLowerCase() +
- "\" for non-native method " + clsName + "::" + uniqueName);
- }
-
- generateMember(info, method, uniqueName, returnType, argTypes);
-
- final boolean isStatic = Utils.isStatic(method);
-
- header.append(
- " " + generateDeclaration(info.wrapperName, argTypes,
- returnType, info, isStatic) + "\n" +
- "\n");
-
- cpp.append(
- generateDefinition(
- "mozilla::jni::Method<" +
- getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
- info.wrapperName, argTypes, returnType, info, isStatic) + "\n" +
- "\n");
- }
-
- /**
- * Append the appropriate generated code to the buffers for the native method provided.
- *
- * @param annotatedMethod The Java native method, plus annotation data.
- */
- public void generateNative(AnnotatableEntity annotatedMethod) {
- // Unpack the tuple and extract some useful fields from the Method..
- final Method method = annotatedMethod.getMethod();
- final AnnotationInfo info = annotatedMethod.mAnnotationInfo;
- final String uniqueName = getUniqueMethodName(info.wrapperName);
- final Class<?>[] argTypes = method.getParameterTypes();
- final Class<?> returnType = method.getReturnType();
-
- // Sanity check
- if (info.exceptionMode != AnnotationInfo.ExceptionMode.ABORT &&
- info.exceptionMode != AnnotationInfo.ExceptionMode.IGNORE) {
- throw new IllegalStateException("Invalid exception mode \"" +
- info.exceptionMode.name().toLowerCase() +
- "\" for native method " + clsName + "::" + uniqueName);
- }
- if (info.dispatchTarget != AnnotationInfo.DispatchTarget.CURRENT &&
- returnType != void.class) {
- throw new IllegalStateException(
- "Must return void when not dispatching to current thread for native method " +
- clsName + "::" + uniqueName);
- }
-
- generateMember(info, method, uniqueName, returnType, argTypes);
-
- final String traits = getTraitsName(uniqueName, /* includeScope */ true);
-
- if (nativesInits.length() > 0) {
- nativesInits.append(',');
- }
-
- nativesInits.append(
- "\n" +
- "\n" +
- " mozilla::jni::MakeNativeMethod<" + traits + ">(\n" +
- " mozilla::jni::NativeStub<" + traits + ", Impl>\n" +
- " ::template Wrap<&Impl::" + info.wrapperName + ">)");
- numNativesInits++;
- }
-
- private String getLiteral(Object val, AnnotationInfo info) {
- final Class<?> type = val.getClass();
-
- if (type.equals(char.class) || type.equals(Character.class)) {
- final char c = (char) val;
- if (c >= 0x20 && c < 0x7F) {
- return "'" + c + '\'';
- }
- return "u'\\u" + Integer.toHexString(0x10000 | (int) c).substring(1) + '\'';
-
- } else if (type.equals(CharSequence.class) || type.equals(String.class)) {
- final CharSequence str = (CharSequence) val;
- final StringBuilder out = new StringBuilder("u\"");
- for (int i = 0; i < str.length(); i++) {
- final char c = str.charAt(i);
- if (c >= 0x20 && c < 0x7F) {
- out.append(c);
- } else {
- out.append("\\u").append(Integer.toHexString(0x10000 | (int) c).substring(1));
- }
- }
- return out.append('"').toString();
- }
-
- return String.valueOf(val);
- }
-
- public void generateField(AnnotatableEntity annotatedField) {
- final Field field = annotatedField.getField();
- final AnnotationInfo info = annotatedField.mAnnotationInfo;
- final String uniqueName = info.wrapperName;
- final Class<?> type = field.getType();
-
- // Handles a peculiar case when dealing with enum types. We don't care about this field.
- // It just gets in the way and stops our code from compiling.
- if (field.isSynthetic() || field.getName().equals("$VALUES")) {
- return;
- }
-
- // Sanity check
- if (info.dispatchTarget != AnnotationInfo.DispatchTarget.CURRENT) {
- throw new IllegalStateException("Invalid dispatch target \"" +
- info.dispatchTarget.name().toLowerCase() +
- "\" for field " + clsName + "::" + uniqueName);
- }
-
- final boolean isStatic = Utils.isStatic(field);
- final boolean isFinal = Utils.isFinal(field);
-
- if (isStatic && isFinal && (type.isPrimitive() || type.equals(String.class))) {
- Object val = null;
- try {
- field.setAccessible(true);
- val = field.get(null);
- } catch (final IllegalAccessException e) {
- }
-
- if (val != null && type.isPrimitive()) {
- // For static final primitive fields, we can use a "static const" declaration.
- header.append(
- " static const " + Utils.getNativeReturnType(type, info) +
- ' ' + info.wrapperName + " = " + getLiteral(val, info) + ";\n" +
- "\n");
- return;
-
- } else if (val != null && type.equals(String.class)) {
- final String nativeType = "char16_t";
-
- header.append(
- " static const " + nativeType + ' ' + info.wrapperName + "[];\n" +
- "\n");
-
- cpp.append(
- "const " + nativeType + ' ' + clsName + "::" + info.wrapperName +
- "[] = " + getLiteral(val, info) + ";\n" +
- "\n");
- return;
- }
-
- // Fall back to using accessors if we encounter an exception.
- }
-
- generateMember(info, field, uniqueName, type, EMPTY_CLASS_ARRAY);
-
- final Class<?>[] getterArgs = EMPTY_CLASS_ARRAY;
-
- header.append(
- " " + generateDeclaration(info.wrapperName, getterArgs,
- type, info, isStatic) + "\n" +
- "\n");
-
- cpp.append(
- generateDefinition(
- "mozilla::jni::Field<" +
- getTraitsName(uniqueName, /* includeScope */ false) + ">::Get",
- info.wrapperName, getterArgs, type, info, isStatic) + "\n" +
- "\n");
-
- if (isFinal) {
- return;
- }
-
- final Class<?>[] setterArgs = new Class<?>[] { type };
-
- header.append(
- " " + generateDeclaration(info.wrapperName, setterArgs,
- void.class, info, isStatic) + "\n" +
- "\n");
-
- cpp.append(
- generateDefinition(
- "mozilla::jni::Field<" +
- getTraitsName(uniqueName, /* includeScope */ false) + ">::Set",
- info.wrapperName, setterArgs, void.class, info, isStatic) + "\n" +
- "\n");
- }
-
- public void generateConstructor(AnnotatableEntity annotatedConstructor) {
- // Unpack the tuple and extract some useful fields from the Method..
- final Constructor<?> method = annotatedConstructor.getConstructor();
- final AnnotationInfo info = annotatedConstructor.mAnnotationInfo;
- final String wrapperName = "New";
- final String uniqueName = getUniqueMethodName(wrapperName);
- final Class<?>[] argTypes = method.getParameterTypes();
- final Class<?> returnType = cls;
-
- if (method.isSynthetic()) {
- return;
- }
-
- // Sanity check
- if (info.dispatchTarget != AnnotationInfo.DispatchTarget.CURRENT) {
- throw new IllegalStateException("Invalid dispatch target \"" +
- info.dispatchTarget.name().toLowerCase() +
- "\" for constructor " + clsName + "::" + uniqueName);
- }
-
- generateMember(info, method, uniqueName, returnType, argTypes);
-
- header.append(
- " " + generateDeclaration(wrapperName, argTypes,
- returnType, info, /* isStatic */ true) + "\n" +
- "\n");
-
- cpp.append(
- generateDefinition(
- "mozilla::jni::Constructor<" +
- getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
- wrapperName, argTypes, returnType, info, /* isStatic */ true) + "\n" +
- "\n");
- }
-
- public void generateMembers(Member[] members) {
- for (Member m : members) {
- if (!Modifier.isPublic(m.getModifiers())) {
- continue;
- }
-
- String name = Utils.getMemberName(m);
- name = name.substring(0, 1).toUpperCase() + name.substring(1);
-
- // Default for SDK bindings.
- final AnnotationInfo info = new AnnotationInfo(name,
- AnnotationInfo.ExceptionMode.NSRESULT,
- AnnotationInfo.CallingThread.ANY,
- AnnotationInfo.DispatchTarget.CURRENT);
- final AnnotatableEntity entity = new AnnotatableEntity(m, info);
-
- if (m instanceof Constructor) {
- generateConstructor(entity);
- } else if (m instanceof Method) {
- generateMethod(entity);
- } else if (m instanceof Field) {
- generateField(entity);
- } else {
- throw new IllegalArgumentException(
- "expected member to be Constructor, Method, or Field");
- }
- }
- }
-
- public void generateClasses(final ClassWithOptions[] classes) {
- if (classes.length == 0) {
- return;
- }
-
- for (final ClassWithOptions cls : classes) {
- // Extract "Inner" from "Outer::Inner".
- header.append(
- " class " + Utils.getUnqualifiedName(cls.generatedName) + ";\n");
- }
- header.append('\n');
- }
-
- /**
- * Get the finalised bytes to go into the generated wrappers file.
- *
- * @return The bytes to be written to the wrappers file.
- */
- public String getWrapperFileContents() {
- return cpp.toString();
- }
-
- /**
- * Get the finalised bytes to go into the generated header file.
- *
- * @return The bytes to be written to the header file.
- */
- public String getHeaderFileContents() {
- if (this.callingThread == null) {
- this.callingThread = AnnotationInfo.CallingThread.ANY;
- }
-
- header.append(
- " static const mozilla::jni::CallingThread callingThread =\n" +
- " " + this.callingThread.nativeValue() + ";\n" +
- "\n");
-
- if (nativesInits.length() > 0) {
- header.append(
- " template<class Impl> class Natives;\n");
- }
- header.append(
- "};\n" +
- "\n");
- return header.toString();
- }
-
- /**
- * Get the finalised bytes to go into the generated natives header file.
- *
- * @return The bytes to be written to the header file.
- */
- public String getNativesFileContents() {
- if (nativesInits.length() == 0) {
- return "";
- }
- natives.append(
- " static const JNINativeMethod methods[" + numNativesInits + "];\n" +
- "};\n" +
- "\n" +
- "template<class Impl>\n" +
- "const JNINativeMethod " + clsName + "::Natives<Impl>::methods[] = {" + nativesInits + '\n' +
- "};\n" +
- "\n");
- return natives.toString();
- }
-}