use of org.robovm.compiler.util.generic.Type in project robovm by robovm.
the class ObjCBlockPlugin method resolveTargetMethodSignature.
protected static Type[] resolveTargetMethodSignature(SootMethod blockMethod, SootMethod targetMethod, Type blockParamType) {
if (targetMethod.getTag("SignatureTag") == null) {
// Not a generic method.
Type[] result = new Type[targetMethod.getParameterCount() + 1];
result[0] = new SootTypeType(targetMethod.getReturnType());
for (int i = 1; i < result.length; i++) {
result[i] = new SootTypeType(targetMethod.getParameterType(i - 1));
}
return result;
}
SootClassType base = new SootClassType(targetMethod.getDeclaringClass());
TypeVariable<?>[] typeParameters = base.getTypeParameters();
SootClassType offspring = null;
Type[] actualArgs = null;
if (blockParamType instanceof SootClassType) {
offspring = (SootClassType) blockParamType;
actualArgs = new Type[0];
} else if (blockParamType instanceof ParameterizedType) {
offspring = (SootClassType) ((ParameterizedType) blockParamType).getRawType();
actualArgs = ((ParameterizedType) blockParamType).getActualTypeArguments();
}
Type[] resolvedArgs = resolveActualTypeArgs(offspring, base, actualArgs);
Type[] result = new Type[targetMethod.getParameterCount() + 1];
SootMethodType targetMethodType = new SootMethodType(targetMethod);
result[0] = resolveMethodType(blockMethod, -1, targetMethodType.getGenericReturnType(), resolvedArgs, typeParameters);
Type[] genericParameterTypes = targetMethodType.getGenericParameterTypes();
for (int i = 1; i < result.length; i++) {
result[i] = resolveMethodType(blockMethod, i - 1, genericParameterTypes[i - 1], resolvedArgs, typeParameters);
}
return result;
}
use of org.robovm.compiler.util.generic.Type in project robovm by robovm.
the class ObjCBlockPlugin method resolveMethodType.
/**
*
*/
private static Type resolveMethodType(SootMethod blockMethod, int paramIndex, Type t, Type[] resolvedArgs, TypeVariable<?>[] typeParameters) {
if (t instanceof SootClassType) {
return t;
}
if (t instanceof SootTypeType) {
return t;
}
if (t instanceof TypeVariable) {
int idx = indexOf(((TypeVariable<?>) t).getName(), typeParameters);
if (idx != -1) {
Type u = resolvedArgs[idx];
if (u instanceof TypeVariable) {
if (((TypeVariable<?>) t).getName().equals(((TypeVariable<?>) u).getName())) {
return resolveMethodType(blockMethod, paramIndex, ((TypeVariable<?>) t).getBounds()[0], resolvedArgs, typeParameters);
}
}
return resolveMethodType(blockMethod, paramIndex, resolvedArgs[idx], resolvedArgs, typeParameters);
}
throw new CompilerException("Unresolved type variable " + t + " in " + (paramIndex == -1 ? "return type" : "parameter " + (paramIndex + 1)) + " of @Block method " + blockMethod);
}
if (t instanceof WildcardType) {
Type[] upperBounds = ((WildcardType) t).getUpperBounds();
return resolveMethodType(blockMethod, paramIndex, upperBounds[0], resolvedArgs, typeParameters);
}
if (t instanceof ParameterizedType) {
ImplForType pType = (ImplForType) t;
ListOfTypes types = new ListOfTypes(pType.getActualTypeArguments().length);
for (Type arg : pType.getActualTypeArguments()) {
types.add(resolveMethodType(blockMethod, paramIndex, arg, resolvedArgs, typeParameters));
}
return new ImplForType((ImplForType) pType.getOwnerType(), pType.getRawType().getSootClass().getName(), types);
}
if (t instanceof GenericArrayType) {
Type componentType = resolveMethodType(blockMethod, paramIndex, ((GenericArrayType) t).getGenericComponentType(), resolvedArgs, typeParameters);
return new ImplForArray(componentType);
}
throw new CompilerException("Unresolved type " + t + " in " + (paramIndex == -1 ? "return type" : "parameter " + (paramIndex + 1)) + " of @Block method " + blockMethod);
}
use of org.robovm.compiler.util.generic.Type in project robovm by robovm.
the class ObjCBlockPlugin method transformMethod.
private void transformMethod(Config config, Clazz clazz, SootMethod blockMethod, int[] blockParamIndexes, Map<String, Integer> blockTypeIds) throws IOException {
SootMethodType blockMethodType = new SootMethodType(blockMethod);
if (blockParamIndexes != null) {
Type[] genericParameterTypes = blockMethodType.getGenericParameterTypes();
for (int i = 0; i < blockParamIndexes.length; i++) {
int idx = blockParamIndexes[i];
if (idx == -1) {
break;
}
SootMethod targetMethod = getBlockTargetMethod(blockMethod, idx);
Type[] actualGenericTypes = resolveTargetMethodSignature(blockMethod, targetMethod, genericParameterTypes[idx]);
soot.Type[] actualRawTypes = toRawTypes(actualGenericTypes);
soot.Type[] unboxedTypes = unboxTypes(actualRawTypes);
String[][] targetMethodAnnotations = parseTargetMethodAnnotations(targetMethod, readStringElem(getParameterAnnotation(blockMethod, idx, BLOCK), "value", ""));
// Create the marshaler class associated with this block type
String marshaler = createBlockMarshaler(config, clazz, targetMethod, actualGenericTypes, actualRawTypes, unboxedTypes, blockTypeIds, targetMethodAnnotations);
addMarshalerAnnotation(blockMethod, idx, marshaler);
}
}
if (hasAnnotation(blockMethod, BLOCK)) {
SootMethod targetMethod = getBlockTargetMethod(blockMethod);
Type[] actualGenericTypes = resolveTargetMethodSignature(blockMethod, targetMethod, blockMethodType.getGenericReturnType());
soot.Type[] actualRawTypes = toRawTypes(actualGenericTypes);
soot.Type[] unboxedTypes = unboxTypes(actualRawTypes);
String[][] targetMethodAnnotations = parseTargetMethodAnnotations(targetMethod, readStringElem(getAnnotation(blockMethod, BLOCK), "value", ""));
String marshaler = createBlockMarshaler(config, clazz, targetMethod, actualGenericTypes, actualRawTypes, unboxedTypes, blockTypeIds, targetMethodAnnotations);
addMarshalerAnnotation(blockMethod, marshaler);
}
}
use of org.robovm.compiler.util.generic.Type in project robovm by robovm.
the class ObjCBlockPlugin method generateTargetMethod.
private void generateTargetMethod(String owner, SootMethod targetMethod, Type[] actualGenericTypes, soot.Type[] actualRawTypes, soot.Type[] unboxedTypes, Set<String> usedBoxMethods, Set<String> usedUnboxMethods, ClassWriter cw) {
String name = targetMethod.getName();
String signature = getGenericSignature(Arrays.asList(actualGenericTypes).subList(1, actualGenericTypes.length), actualGenericTypes[0]);
String desc = getDescriptor(targetMethod);
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, name, desc, signature, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, owner, "objCBlock", "L" + getInternalName(org_robovm_objc_ObjCBlock) + ";");
mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(org_robovm_objc_ObjCBlock), "invoke", "()J");
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, owner, "objCBlock", "L" + getInternalName(org_robovm_objc_ObjCBlock) + ";");
for (int i = 1, var = 1; i < actualRawTypes.length; i++, var++) {
soot.Type from = actualRawTypes[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 = unboxedTypes[i];
if (from != to) {
mv.visitTypeInsn(CHECKCAST, getInternalName(from));
// Unbox the value on the top of the stack.
String unboxDesc = getDescriptor(Collections.singletonList(from), to);
usedUnboxMethods.add(unboxDesc);
mv.visitMethodInsn(INVOKESTATIC, owner, "unbox", unboxDesc);
}
}
// Now the function pointer, block and all arguments are on the stack
// (unboxed if needed). Call the invoke() bridge method.
List<soot.Type> paramTypes = new ArrayList<>();
paramTypes.add(LongType.v());
paramTypes.add(org_robovm_objc_ObjCBlock.getType());
paramTypes.addAll(Arrays.asList(unboxedTypes).subList(1, unboxedTypes.length));
mv.visitMethodInsn(INVOKESTATIC, owner, "invoke", getDescriptor(paramTypes, unboxedTypes[0]));
if (unboxedTypes[0] != actualRawTypes[0]) {
// Box the value on the top of the stack.
String boxDesc = getDescriptor(Collections.singletonList(unboxedTypes[0]), actualRawTypes[0]);
usedBoxMethods.add(boxDesc);
mv.visitMethodInsn(INVOKESTATIC, owner, "box", boxDesc);
}
if (actualRawTypes[0] == VoidType.v()) {
mv.visitInsn(RETURN);
} else if (actualRawTypes[0] == LongType.v()) {
mv.visitInsn(LRETURN);
} else if (actualRawTypes[0] == FloatType.v()) {
mv.visitInsn(FRETURN);
} else if (actualRawTypes[0] == DoubleType.v()) {
mv.visitInsn(DRETURN);
} else if (actualRawTypes[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 createBlockMarshaler.
private String createBlockMarshaler(Config config, Clazz clazz, final SootMethod targetMethod, Type[] actualGenericTypes, soot.Type[] actualRawTypes, soot.Type[] unboxedTypes, Map<String, Integer> blockTypeIds, String[][] targetMethodAnnotations) throws IOException {
if (targetMethod.getDeclaringClass().getName().equals("java.lang.Runnable") && targetMethod.getName().equals("run")) {
return RUNNABLE_AS_OBJC_BLOCK_MARSHALER;
}
String targetMethodKey = getTargetMethodKey(targetMethod, actualRawTypes, targetMethodAnnotations);
Integer id = blockTypeIds.get(targetMethodKey);
if (id != null) {
// Already generated
return getBlockMarshalerName(clazz, id);
}
id = blockTypeIds.size();
blockTypeIds.put(targetMethodKey, id);
final String blockMarshalerName = getBlockMarshalerName(clazz, id);
final String targetInterfaceName = Types.getInternalName(targetMethod.getDeclaringClass());
// We use RunnableAsObjCBlockMarshaler as template
Clazz templateMarshaler = config.getClazzes().load(RUNNABLE_AS_OBJC_BLOCK_MARSHALER);
final Set<String> usedBoxMethods = new HashSet<>();
final Set<String> usedUnboxMethods = new HashSet<>();
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
generateTargetMethod(blockMarshalerName, targetMethod, actualGenericTypes, actualRawTypes, unboxedTypes, usedBoxMethods, usedUnboxMethods, cw);
generateBridgeMethod(actualGenericTypes, unboxedTypes, targetMethodAnnotations, cw);
generateCallbackMethod(blockMarshalerName, targetMethod, actualGenericTypes, actualRawTypes, unboxedTypes, usedBoxMethods, usedUnboxMethods, targetMethodAnnotations, cw);
ClassReader classReader = new ClassReader(templateMarshaler.getBytes());
classReader.accept(new ClassVisitor(ASM4, cw) {
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
super.visit(version, access, blockMarshalerName, signature, superName, new String[] { targetInterfaceName });
}
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
// Ignore
}
@Override
public void visitSource(String source, String debug) {
// Ignore
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
switch(name) {
case "run":
case "invoke":
case "invoked":
// Skip all these
return null;
case "box":
if (!usedBoxMethods.contains(desc)) {
return null;
}
break;
case "unbox":
if (!usedUnboxMethods.contains(desc)) {
return null;
}
break;
}
desc = desc.replace("java/lang/Runnable", targetInterfaceName);
signature = null;
// RunnableAsObjCBlockMarshaler to the blockMarshalerName
return new MethodVisitor(ASM4, super.visitMethod(access, name, desc, signature, exceptions)) {
@Override
public void visitLdcInsn(Object cst) {
if (cst instanceof org.objectweb.asm.Type) {
if (((org.objectweb.asm.Type) cst).getSort() == org.objectweb.asm.Type.OBJECT) {
String internalName = ((org.objectweb.asm.Type) cst).getInternalName();
if (RUNNABLE_AS_OBJC_BLOCK_MARSHALER.equals(internalName)) {
cst = org.objectweb.asm.Type.getObjectType(blockMarshalerName);
}
}
}
super.visitLdcInsn(cst);
}
@Override
public void visitTypeInsn(int opcode, String type) {
if (RUNNABLE_AS_OBJC_BLOCK_MARSHALER.equals(type)) {
type = blockMarshalerName;
} else if ("java/lang/Runnable".equals(type)) {
type = targetInterfaceName;
}
super.visitTypeInsn(opcode, type);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (RUNNABLE_AS_OBJC_BLOCK_MARSHALER.equals(owner)) {
owner = blockMarshalerName;
}
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
if (RUNNABLE_AS_OBJC_BLOCK_MARSHALER.equals(owner)) {
owner = blockMarshalerName;
}
super.visitMethodInsn(opcode, owner, name, desc);
}
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
// Ignored
}
@Override
public void visitLineNumber(int line, Label start) {
// Ignored
}
};
}
}, 0);
cw.visitInnerClass(blockMarshalerName, clazz.getInternalName(), blockMarshalerName.substring(clazz.getInternalName().length() + 1), ACC_PUBLIC + ACC_STATIC);
cw.visitEnd();
File f = clazz.getPath().getGeneratedClassFile(blockMarshalerName);
FileUtils.writeByteArrayToFile(f, cw.toByteArray());
// The marshaler class is created after the class is compiled.
// This prevents the triggering of a recompile of the class.
f.setLastModified(clazz.lastModified());
return blockMarshalerName;
}
Aggregations