use of org.robovm.compiler.clazz.Clazz in project robovm by robovm.
the class AnnotationImplPluginTest method createAnnoImpl.
private File createAnnoImpl(Class<? extends Annotation> annoClass) {
AnnotationImplPlugin plugin = new AnnotationImplPlugin();
Clazz clazz = toClazz(annoClass);
clazz.resetClazzInfo();
plugin.beforeClass(config, clazz, new ModuleBuilder());
assertFalse(clazz.getClazzInfo().getAllDependencies().isEmpty());
Dependency dep = clazz.getClazzInfo().getAllDependencies().iterator().next();
assertEquals(clazz.getInternalName() + "$Impl", dep.getClassName());
final File implFile = new File(config.getGeneratedClassDir(clazz.getPath()), clazz.getInternalName() + "$Impl.class");
assertTrue(implFile.exists());
return implFile;
}
use of org.robovm.compiler.clazz.Clazz in project robovm by robovm.
the class AnnotationImplPluginTest method testNotVisibleAnno.
@Test
public void testNotVisibleAnno() throws Exception {
AnnotationImplPlugin plugin = new AnnotationImplPlugin();
Clazz clazz = toClazz(Anno1.class);
clazz.resetClazzInfo();
plugin.beforeClass(config, clazz, new ModuleBuilder());
assertFalse(clazz.getClazzInfo().getAllDependencies().isEmpty());
}
use of org.robovm.compiler.clazz.Clazz 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;
}
use of org.robovm.compiler.clazz.Clazz in project robovm by robovm.
the class TrampolineCompiler method compile.
public void compile(ModuleBuilder mb, Clazz currentClass, Trampoline t, Set<String> dependencies, Set<Triple<String, String, String>> methodDependencies) {
this.mb = mb;
addDependencyIfNeeded(dependencies, currentClass, t);
/*
* Check if the target class exists and is accessible. Also check that
* field accesses and method calls are compatible with the target
* field/method and that the field/method is accessible to the caller.
* If any of the tests fail the weak trampoline function created by the
* ClassCompiler will be overridden with a function which throws an
* appropriate exception.
*/
Function errorFn = new FunctionBuilder(t).linkage(external).build();
if (!checkClassExists(errorFn, t) || !checkClassAccessible(errorFn, t)) {
mb.addFunction(errorFn);
return;
}
if (t instanceof New) {
SootClass target = config.getClazzes().load(t.getTarget()).getSootClass();
if (target.isAbstract() || target.isInterface()) {
call(errorFn, BC_THROW_INSTANTIATION_ERROR, errorFn.getParameterRef(0), mb.getString(t.getTarget().replace('/', '.')));
errorFn.add(new Unreachable());
mb.addFunction(errorFn);
return;
}
String fnName = Symbols.clinitWrapperSymbol(Symbols.allocatorSymbol(t.getTarget()));
alias(t, fnName);
} else if (t instanceof Instanceof) {
if (isArray(t.getTarget())) {
FunctionRef fnRef = createInstanceofArray((Instanceof) t);
alias(t, fnRef.getName());
} else {
String fnName = Symbols.instanceofSymbol(t.getTarget());
alias(t, fnName);
}
} else if (t instanceof Checkcast) {
if (isArray(t.getTarget())) {
FunctionRef fnRef = createCheckcastArray((Checkcast) t);
alias(t, fnRef.getName());
} else {
String fnName = Symbols.checkcastSymbol(t.getTarget());
alias(t, fnName);
}
} else if (t instanceof LdcClass) {
if (isArray(t.getTarget())) {
FunctionRef fnRef = createLdcArray((LdcClass) t);
alias(t, fnRef.getName());
} else {
String fnName = Symbols.ldcExternalSymbol(t.getTarget());
alias(t, fnName);
}
} else if (t instanceof Anewarray) {
FunctionRef fnRef = createAnewarray((Anewarray) t);
alias(t, fnRef.getName());
} else if (t instanceof Multianewarray) {
FunctionRef fnRef = createMultianewarray((Multianewarray) t);
alias(t, fnRef.getName());
} else if (t instanceof FieldAccessor) {
SootField field = resolveField(errorFn, (FieldAccessor) t);
if (field != null) {
dependencies.add(getInternalName(field.getDeclaringClass()));
}
if (field == null || !checkMemberAccessible(errorFn, t, field)) {
mb.addFunction(errorFn);
return;
}
Clazz caller = config.getClazzes().load(t.getCallingClass());
Clazz target = config.getClazzes().load(t.getTarget());
if (!((FieldAccessor) t).isGetter() && field.isFinal() && caller != target) {
// Only the class declaring a final field may write to it.
// (Actually only <init>/<clinit> methods may write to it but we
// don't know which method is accessing the field at this point)
throwIllegalAccessError(errorFn, ATTEMPT_TO_WRITE_TO_FINAL_FIELD, target, field.getName(), caller);
mb.addFunction(errorFn);
return;
}
if (!field.isStatic()) {
createInlinedAccessorForInstanceField((FieldAccessor) t, field);
} else {
createTrampolineAliasForField((FieldAccessor) t, field);
}
} else if (t instanceof Invokeinterface) {
SootMethod rm = resolveInterfaceMethod(errorFn, (Invokeinterface) t);
if (rm != null) {
methodDependencies.add(new ImmutableTriple<String, String, String>(getInternalName(rm.getDeclaringClass()), rm.getName(), getDescriptor(rm)));
}
if (rm == null || !checkMemberAccessible(errorFn, t, rm)) {
mb.addFunction(errorFn);
return;
}
createTrampolineAliasForMethod((Invoke) t, rm);
} else if (t instanceof Invoke) {
SootMethod method = resolveMethod(errorFn, (Invoke) t);
if (method != null) {
methodDependencies.add(new ImmutableTriple<String, String, String>(getInternalName(method.getDeclaringClass()), method.getName(), getDescriptor(method)));
}
if (method == null || !checkMemberAccessible(errorFn, t, method)) {
mb.addFunction(errorFn);
return;
}
if (t instanceof Invokespecial && method.isAbstract()) {
call(errorFn, BC_THROW_ABSTRACT_METHOD_ERROR, errorFn.getParameterRef(0), mb.getString(String.format(NO_SUCH_METHOD_ERROR, method.getDeclaringClass(), method.getName(), getDescriptor(method))));
errorFn.add(new Unreachable());
mb.addFunction(errorFn);
return;
}
createTrampolineAliasForMethod((Invoke) t, method);
}
}
use of org.robovm.compiler.clazz.Clazz in project robovm by robovm.
the class TrampolineCompiler method checkClassExists.
private boolean checkClassExists(Function f, Trampoline t) {
String targetClassName = t.getTarget();
if (isArray(targetClassName)) {
if (isPrimitiveBaseType(targetClassName)) {
return true;
}
targetClassName = getBaseType(targetClassName);
}
Clazz target = config.getClazzes().load(targetClassName);
if (target != null) {
Clazz caller = config.getClazzes().load(t.getCallingClass());
// If caller is in the bootclasspath it only sees classes in the bootclasspath
if (!caller.isInBootClasspath() || target.isInBootClasspath()) {
return true;
}
}
call(f, BC_THROW_NO_CLASS_DEF_FOUND_ERROR, f.getParameterRef(0), mb.getString(t.getTarget()));
f.add(new Unreachable());
return false;
}
Aggregations