use of org.robovm.compiler.util.generic.Type in project robovm by robovm.
the class ObjCBlockPlugin method generateBridgeMethod.
private void generateBridgeMethod(Type[] actualGenericTypes, soot.Type[] unboxedTypes, String[][] targetMethodAnnotations, ClassWriter cw) {
List<Type> genericParamTypes = new ArrayList<>();
genericParamTypes.add(new SootTypeType(LongType.v()));
genericParamTypes.add(new SootTypeType(org_robovm_objc_ObjCBlock.getType()));
for (int i = 1; i < unboxedTypes.length; i++) {
Type t = unboxedTypes[i] instanceof PrimType ? new SootTypeType(unboxedTypes[i]) : actualGenericTypes[i];
genericParamTypes.add(t);
}
Type genericReturnType = unboxedTypes[0] instanceof PrimType ? new SootTypeType(unboxedTypes[0]) : actualGenericTypes[0];
List<soot.Type> rawParamTypes = new ArrayList<>();
rawParamTypes.add(LongType.v());
rawParamTypes.add(org_robovm_objc_ObjCBlock.getType());
rawParamTypes.addAll(Arrays.asList(unboxedTypes).subList(1, unboxedTypes.length));
String name = "invoke";
String signature = getGenericSignature(genericParamTypes, genericReturnType);
String desc = getDescriptor(rawParamTypes, unboxedTypes[0]);
MethodVisitor mv = cw.visitMethod(ACC_PRIVATE | ACC_STATIC | ACC_NATIVE, name, desc, signature, null);
AnnotationVisitor av = mv.visitAnnotation(BRIDGE, true);
av.visit("dynamic", true);
av.visitEnd();
for (String s : targetMethodAnnotations[0]) {
mv.visitAnnotation(s, true).visitEnd();
}
for (int i = 1; i < targetMethodAnnotations.length; i++) {
for (String s : targetMethodAnnotations[i]) {
// We add 2 parameters first so annotations for the first
// parameter must be added at index 2.
mv.visitParameterAnnotation(i + 1, s, true).visitEnd();
}
}
mv.visitParameterAnnotation(0, POINTER, true).visitEnd();
mv.visitEnd();
}
use of org.robovm.compiler.util.generic.Type in project robovm by robovm.
the class ObjCBlockPlugin method resolveActualTypeArgs.
/**
* Resolves the actual generic type arguments for a base class, as viewed from a subclass or implementation.
*
* @param offspring class or interface subclassing or extending the base type
* @param base base class
* @param actualArgs the actual type arguments passed to the offspring class
* @return actual generic type arguments, must match the type parameters of the offspring class. If omitted, the
* type parameters will be used instead.
*
* This code was copied from
* http://stackoverflow.com/questions/17297308/how-do-i-resolve-the-actual-type-for-a-generic-return-type-using-reflection
* and changed slightly.
*/
protected static Type[] resolveActualTypeArgs(SootClassType offspring, SootClassType base, Type... actualArgs) {
TypeVariable<?>[] typeParameters = offspring.getTypeParameters();
// If actual types are omitted, the type parameters will be used instead.
if (actualArgs.length == 0) {
actualArgs = typeParameters;
}
// map type parameters into the actual types
Map<String, Type> typeVariables = new HashMap<>();
for (int i = 0; i < actualArgs.length; i++) {
TypeVariable<?> typeVariable = (TypeVariable<?>) typeParameters[i];
Type t = actualArgs[i];
if (t instanceof WildcardType) {
// If actual arg is ? it will have an upper bound of java.lang.Object but the
// TypeVariable could specify a more specific type.
Type upper = ((WildcardType) t).getUpperBounds()[0];
if (upper instanceof SootClassType) {
if ("java.lang.Object".equals(((SootClassType) upper).getSootClass().getName())) {
actualArgs[i] = typeVariable.getBounds()[0];
}
}
}
typeVariables.put(typeVariable.getName(), actualArgs[i]);
}
// Find direct ancestors (superclass, interfaces)
List<Type> ancestors = new LinkedList<Type>();
if (offspring.getGenericSuperclass() != null) {
ancestors.add(offspring.getGenericSuperclass());
}
for (Type t : offspring.getGenericInterfaces()) {
ancestors.add(t);
}
// Recurse into ancestors (superclass, interfaces)
for (Type type : ancestors) {
if (type instanceof SootClassType) {
// ancestor is non-parameterized. Recurse only if it matches the base class.
SootClassType ancestorClass = (SootClassType) type;
if (base.isAssignableFrom(ancestorClass)) {
Type[] result = resolveActualTypeArgs(ancestorClass, base);
if (result != null) {
return result;
}
}
}
if (type instanceof ParameterizedType) {
// ancestor is parameterized. Recurse only if the raw type matches the base class.
ParameterizedType parameterizedType = (ParameterizedType) type;
Type rawType = parameterizedType.getRawType();
if (rawType instanceof SootClassType) {
SootClassType rawTypeClass = (SootClassType) rawType;
if (base.isAssignableFrom(rawTypeClass)) {
parameterizedType = resolveParameterizedType(parameterizedType, typeVariables);
Type[] result = resolveActualTypeArgs(rawTypeClass, base, parameterizedType.getActualTypeArguments());
if (result != null) {
return result;
}
}
}
}
}
// we have a result if we reached the base class.
return offspring.equals(base) ? actualArgs : null;
}
use of org.robovm.compiler.util.generic.Type in project robovm by robovm.
the class ObjCBlockPlugin method generateCallbackMethod.
private void generateCallbackMethod(String owner, SootMethod targetMethod, Type[] actualGenericTypes, soot.Type[] actualRawTypes, soot.Type[] unboxedTypes, Set<String> usedBoxMethods, Set<String> usedUnboxMethods, String[][] targetMethodAnnotations, ClassWriter cw) {
String targetInterfaceName = Types.getInternalName(targetMethod.getDeclaringClass());
List<Type> genericParamTypes = new ArrayList<>();
genericParamTypes.add(new SootTypeType(org_robovm_objc_ObjCBlock.getType()));
for (int i = 1; i < unboxedTypes.length; i++) {
Type t = unboxedTypes[i] instanceof PrimType ? new SootTypeType(unboxedTypes[i]) : actualGenericTypes[i];
genericParamTypes.add(t);
}
Type genericReturnType = unboxedTypes[0] instanceof PrimType ? new SootTypeType(unboxedTypes[0]) : actualGenericTypes[0];
List<soot.Type> rawParamTypes = new ArrayList<>();
rawParamTypes.add(org_robovm_objc_ObjCBlock.getType());
rawParamTypes.addAll(Arrays.asList(unboxedTypes).subList(1, unboxedTypes.length));
String name = "invoked";
String signature = getGenericSignature(genericParamTypes, genericReturnType);
String desc = getDescriptor(rawParamTypes, unboxedTypes[0]);
MethodVisitor mv = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, name, desc, signature, null);
mv.visitAnnotation(CALLBACK, true).visitEnd();
for (String s : targetMethodAnnotations[0]) {
mv.visitAnnotation(s, true).visitEnd();
}
for (int i = 1; i < targetMethodAnnotations.length; i++) {
for (String s : targetMethodAnnotations[i]) {
// We add 1 parameter first so annotations for the first
// parameter should be added at index 1.
mv.visitParameterAnnotation(i, s, true).visitEnd();
}
}
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, "org/robovm/objc/ObjCBlock", "object", "()Ljava/lang/Object;");
mv.visitTypeInsn(CHECKCAST, targetInterfaceName);
for (int i = 1, var = 1; i < actualRawTypes.length; i++, var++) {
soot.Type from = unboxedTypes[i];
if (from == LongType.v()) {
mv.visitVarInsn(LLOAD, var);
// longs need 2 slots
var++;
} else if (from == FloatType.v()) {
mv.visitVarInsn(FLOAD, var);
} else if (from == DoubleType.v()) {
mv.visitVarInsn(DLOAD, var);
// doubles need 2 slots
var++;
} else if (from instanceof PrimType) {
// boolean, byte, short, char and int are loaded using ILOAD
mv.visitVarInsn(ILOAD, var);
} else {
// Reference
mv.visitVarInsn(ALOAD, var);
}
soot.Type to = actualRawTypes[i];
if (from != to) {
// Box the value on the top of the stack.
String boxDesc = getDescriptor(Collections.singletonList(from), to);
usedBoxMethods.add(boxDesc);
mv.visitMethodInsn(INVOKESTATIC, owner, "box", boxDesc);
}
}
// Now the receiver and all arguments are on the stack (boxed if needed).
// Call the target method.
mv.visitMethodInsn(INVOKEINTERFACE, targetInterfaceName, targetMethod.getName(), getDescriptor(targetMethod));
if (unboxedTypes[0] != actualRawTypes[0]) {
mv.visitTypeInsn(CHECKCAST, getInternalName(actualRawTypes[0]));
// Unbox the value on the top of the stack.
String unboxDesc = getDescriptor(Collections.singletonList(actualRawTypes[0]), unboxedTypes[0]);
usedUnboxMethods.add(unboxDesc);
mv.visitMethodInsn(INVOKESTATIC, owner, "unbox", unboxDesc);
}
if (unboxedTypes[0] == VoidType.v()) {
mv.visitInsn(RETURN);
} else if (unboxedTypes[0] == LongType.v()) {
mv.visitInsn(LRETURN);
} else if (unboxedTypes[0] == FloatType.v()) {
mv.visitInsn(FRETURN);
} else if (unboxedTypes[0] == DoubleType.v()) {
mv.visitInsn(DRETURN);
} else if (unboxedTypes[0] instanceof PrimType) {
mv.visitInsn(IRETURN);
} else {
mv.visitInsn(ARETURN);
}
mv.visitMaxs(0, 0);
mv.visitEnd();
}
use of org.robovm.compiler.util.generic.Type in project robovm by robovm.
the class ObjCBlockPlugin method resolveParameterizedType.
/**
* Loops through all type arguments and replaces type variables with the
* actually known types.
*/
private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Map<String, Type> typeVariables) {
List<Type> resolvedTypes = new LinkedList<Type>();
for (Type t : parameterizedType.getActualTypeArguments()) {
if (t instanceof TypeVariable<?>) {
Type resolvedType = typeVariables.get(((TypeVariable<?>) t).getName());
if (resolvedType instanceof ParameterizedType) {
resolvedType = resolveParameterizedType((ParameterizedType) resolvedType, typeVariables);
}
resolvedTypes.add(resolvedType != null ? resolvedType : t);
} else if (t instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) t;
resolvedTypes.add(resolveParameterizedType(pType, typeVariables));
} else {
resolvedTypes.add(t);
}
}
ListOfTypes types = new ListOfTypes(resolvedTypes.toArray(new Type[resolvedTypes.size()]));
return new ImplForType(null, parameterizedType.getRawType().toString(), types);
}
use of org.robovm.compiler.util.generic.Type in project robovm by robovm.
the class ObjCBlockPlugin method getGenericSignature.
private String getGenericSignature(List<Type> genericParamTypes, Type genericReturnType) {
StringBuilder sb = new StringBuilder();
sb.append("(");
for (Type t : genericParamTypes) {
sb.append(t.toGenericSignature());
}
sb.append(")");
sb.append(genericReturnType.toGenericSignature());
String s = sb.toString();
if (s.contains("<")) {
return s;
}
// Not a generic signature.
return null;
}
Aggregations