use of soot.SootClass in project robovm by robovm.
the class VTableTest method testObject.
@Test
public void testObject() {
SootClass sc = getSootClass("java.lang.Object");
VTable.Cache cache = new VTable.Cache();
VTable vtable = cache.get(sc);
assertEquals(11, vtable.size());
assertNotNull(vtable.findEntry("toString", "()Ljava/lang/String;"));
}
use of soot.SootClass in project robovm by robovm.
the class ClassCompiler method createClassInfoStruct.
private StructureConstant createClassInfoStruct() {
int flags = 0;
if (Modifier.isPublic(sootClass.getModifiers())) {
flags |= CI_PUBLIC;
}
if (Modifier.isFinal(sootClass.getModifiers())) {
flags |= CI_FINAL;
}
if (Modifier.isInterface(sootClass.getModifiers())) {
flags |= CI_INTERFACE;
}
if (Modifier.isAbstract(sootClass.getModifiers())) {
flags |= CI_ABSTRACT;
}
if ((sootClass.getModifiers() & 0x1000) > 0) {
flags |= CI_SYNTHETIC;
}
if (Modifier.isAnnotation(sootClass.getModifiers())) {
flags |= CI_ANNOTATION;
}
if (Modifier.isEnum(sootClass.getModifiers())) {
flags |= CI_ENUM;
}
if (attributesEncoder.classHasAttributes()) {
flags |= CI_ATTRIBUTES;
}
if (hasFinalizer(sootClass)) {
flags |= CI_FINALIZABLE;
}
// Create the ClassInfoHeader structure.
StructureConstantBuilder header = new StructureConstantBuilder();
// Points to the runtime Class struct
header.add(new NullConstant(I8_PTR));
header.add(new IntegerConstant(flags));
header.add(getString(getInternalName(sootClass)));
if (sootClass.declaresMethod("<clinit>", Collections.emptyList(), VoidType.v())) {
SootMethod method = sootClass.getMethod("<clinit>", Collections.emptyList(), VoidType.v());
header.add(new FunctionRef(Symbols.methodSymbol(method), getFunctionType(method)));
} else {
header.add(new NullConstant(I8_PTR));
}
mb.addGlobal(new Global(Symbols.typeInfoSymbol(getInternalName(sootClass)), Linkage.external, I8_PTR, true));
// TypeInfo* generated by Linker
header.add(new GlobalRef(Symbols.typeInfoSymbol(getInternalName(sootClass)), I8_PTR));
if (!sootClass.isInterface()) {
header.add(createVTableStruct());
} else {
header.add(createITableStruct());
}
header.add(createITablesStruct());
header.add(sizeof(classType));
header.add(sizeof(instanceType));
if (!instanceFields.isEmpty()) {
header.add(offsetof(instanceType, 1, 1));
} else {
header.add(sizeof(instanceType));
}
header.add(new IntegerConstant((short) countReferences(classFields)));
header.add(new IntegerConstant((short) countReferences(instanceFields)));
PackedStructureConstantBuilder body = new PackedStructureConstantBuilder();
body.add(new IntegerConstant((short) sootClass.getInterfaceCount()));
body.add(new IntegerConstant((short) sootClass.getFieldCount()));
body.add(new IntegerConstant((short) sootClass.getMethodCount()));
if (!sootClass.isInterface()) {
body.add(getStringOrNull(sootClass.hasSuperclass() ? getInternalName(sootClass.getSuperclass()) : null));
}
if (attributesEncoder.classHasAttributes()) {
body.add(new ConstantBitcast(attributesEncoder.getClassAttributes().ref(), I8_PTR));
}
for (SootClass s : sootClass.getInterfaces()) {
body.add(getString(getInternalName(s)));
}
for (SootField f : sootClass.getFields()) {
flags = 0;
soot.Type t = f.getType();
if (t instanceof PrimType) {
if (t.equals(BooleanType.v())) {
flags |= DESC_Z;
} else if (t.equals(ByteType.v())) {
flags |= DESC_B;
} else if (t.equals(ShortType.v())) {
flags |= DESC_S;
} else if (t.equals(CharType.v())) {
flags |= DESC_C;
} else if (t.equals(IntType.v())) {
flags |= DESC_I;
} else if (t.equals(LongType.v())) {
flags |= DESC_J;
} else if (t.equals(FloatType.v())) {
flags |= DESC_F;
} else if (t.equals(DoubleType.v())) {
flags |= DESC_D;
}
flags <<= 12;
}
if (Modifier.isPublic(f.getModifiers())) {
flags |= FI_PUBLIC;
} else if (Modifier.isPrivate(f.getModifiers())) {
flags |= FI_PRIVATE;
} else if (Modifier.isProtected(f.getModifiers())) {
flags |= FI_PROTECTED;
}
if (Modifier.isStatic(f.getModifiers())) {
flags |= FI_STATIC;
}
if (Modifier.isFinal(f.getModifiers())) {
flags |= FI_FINAL;
}
if (Modifier.isVolatile(f.getModifiers())) {
flags |= FI_VOLATILE;
}
if (Modifier.isTransient(f.getModifiers())) {
flags |= FI_TRANSIENT;
}
if ((f.getModifiers() & 0x1000) > 0) {
flags |= FI_SYNTHETIC;
}
if (Modifier.isEnum(f.getModifiers())) {
flags |= FI_ENUM;
}
if (attributesEncoder.fieldHasAttributes(f)) {
flags |= FI_ATTRIBUTES;
}
body.add(new IntegerConstant((short) flags));
body.add(getString(f.getName()));
if (!(t instanceof PrimType)) {
body.add(getString(getDescriptor(f)));
}
if (f.isStatic()) {
int index = classFields.indexOf(f);
body.add(offsetof(classType, 1, index, 1));
} else {
int index = instanceFields.indexOf(f);
body.add(offsetof(instanceType, 1, 1 + index, 1));
}
if (attributesEncoder.fieldHasAttributes(f)) {
body.add(new ConstantBitcast(attributesEncoder.getFieldAttributes(f).ref(), I8_PTR));
}
}
VTable vtable = !sootClass.isInterface() ? config.getVTableCache().get(sootClass) : null;
ITable itable = sootClass.isInterface() ? config.getITableCache().get(sootClass) : null;
;
for (SootMethod m : sootClass.getMethods()) {
soot.Type t = m.getReturnType();
flags = 0;
if (Modifier.isPublic(m.getModifiers())) {
flags |= MI_PUBLIC;
} else if (Modifier.isPrivate(m.getModifiers())) {
flags |= MI_PRIVATE;
} else if (Modifier.isProtected(m.getModifiers())) {
flags |= MI_PROTECTED;
}
if (Modifier.isStatic(m.getModifiers())) {
flags |= MI_STATIC;
}
if (Modifier.isFinal(m.getModifiers())) {
flags |= MI_FINAL;
}
if (Modifier.isSynchronized(m.getModifiers())) {
flags |= MI_SYNCHRONIZED;
}
if ((m.getModifiers() & 0x0040) > 0) {
flags |= MI_BRIDGE;
}
if ((m.getModifiers() & 0x0080) > 0) {
flags |= MI_VARARGS;
}
if (Modifier.isNative(m.getModifiers())) {
if (!isStruct(sootClass) && !hasStructMemberAnnotation(m)) {
flags |= MI_NATIVE;
}
}
if (Modifier.isAbstract(m.getModifiers())) {
flags |= MI_ABSTRACT;
}
if (Modifier.isStrictFP(m.getModifiers())) {
flags |= MI_STRICT;
}
if ((m.getModifiers() & 0x1000) > 0) {
flags |= MI_SYNTHETIC;
}
if (attributesEncoder.methodHasAttributes(m)) {
flags |= MI_ATTRIBUTES;
}
if (hasBridgeAnnotation(m) || hasGlobalValueAnnotation(m)) {
flags |= MI_BRO_BRIDGE;
}
if (hasCallbackAnnotation(m)) {
flags |= MI_BRO_CALLBACK;
}
if ((t instanceof PrimType || t == VoidType.v()) && m.getParameterCount() == 0) {
flags |= MI_COMPACT_DESC;
}
body.add(new IntegerConstant((short) flags));
Constant viTableIndex = new IntegerConstant((short) -1);
if (vtable != null) {
VTable.Entry entry = vtable.getEntry(m);
if (entry != null) {
viTableIndex = new IntegerConstant((short) entry.getIndex());
}
} else {
ITable.Entry entry = itable.getEntry(m);
if (entry != null) {
viTableIndex = new IntegerConstant((short) entry.getIndex());
}
}
body.add(viTableIndex);
body.add(getString(m.getName()));
if ((flags & MI_COMPACT_DESC) > 0) {
int desc = 0;
if (t.equals(BooleanType.v())) {
desc = DESC_Z;
} else if (t.equals(ByteType.v())) {
desc = DESC_B;
} else if (t.equals(ShortType.v())) {
desc = DESC_S;
} else if (t.equals(CharType.v())) {
desc = DESC_C;
} else if (t.equals(IntType.v())) {
desc = DESC_I;
} else if (t.equals(LongType.v())) {
desc = DESC_J;
} else if (t.equals(FloatType.v())) {
desc = DESC_F;
} else if (t.equals(DoubleType.v())) {
desc = DESC_D;
} else if (t.equals(VoidType.v())) {
desc = DESC_V;
}
body.add(new IntegerConstant((byte) desc));
} else {
body.add(getString(getDescriptor(m)));
}
if (attributesEncoder.methodHasAttributes(m)) {
body.add(new ConstantBitcast(attributesEncoder.getMethodAttributes(m).ref(), I8_PTR));
}
if (!m.isAbstract()) {
body.add(new ConstantBitcast(new FunctionRef(Symbols.methodSymbol(m), getFunctionType(m)), I8_PTR));
// Size of function. This value will be modified later by patching the .s file.
body.add(new IntegerConstant(DUMMY_METHOD_SIZE));
if (m.isSynchronized()) {
body.add(new ConstantBitcast(new FunctionRef(Symbols.synchronizedWrapperSymbol(m), getFunctionType(m)), I8_PTR));
}
if ((flags & MI_NATIVE) == 0) {
// Cannot use m.isNative() in the condition above since methods which are native in the
// Java class file may have been changed to non-native by the RoboVM compiler
// (e.g. @StructMember methods). The native code which parses the info structs will see
// the method as non-native.
// Add a weak linetable pointer which points to a -1 value which will be interpreted as 0 linenumbers in the table
Global linetableGlobal = new Global(Symbols.linetableSymbol(m), Linkage.weak, new IntegerConstant(-1));
mb.addGlobal(linetableGlobal);
body.add(linetableGlobal.ref());
}
}
if (hasBridgeAnnotation(m)) {
if (!readBooleanElem(getAnnotation(m, BRIDGE), "dynamic", false)) {
body.add(new GlobalRef(Symbols.bridgePtrSymbol(m), I8_PTR));
} else {
body.add(new NullConstant(I8_PTR));
}
} else if (hasGlobalValueAnnotation(m)) {
body.add(new GlobalRef(Symbols.globalValuePtrSymbol(m), I8_PTR));
}
if (hasCallbackAnnotation(m)) {
body.add(new AliasRef(Symbols.callbackPtrSymbol(m), I8_PTR));
}
}
// after sizeof(ClassInfoHeader) bytes.
return new StructureConstantBuilder().add(header.build()).add(body.build()).build();
}
use of soot.SootClass in project robovm by robovm.
the class BroMethodCompiler method getStructType.
private StructureType getStructType(SootClass clazz, boolean checkEmpty) {
int n = 0;
for (SootMethod method : clazz.getMethods()) {
n = Math.max(getStructMemberOffset(method) + 1, n);
}
Type[] result = new Type[n + 1];
StructureType superType = null;
if (clazz.hasSuperclass()) {
SootClass superclass = clazz.getSuperclass();
if (!superclass.getName().equals("org.robovm.rt.bro.Struct")) {
superType = getStructType(superclass, false);
}
}
result[0] = superType != null ? superType : new StructureType();
for (SootMethod method : clazz.getMethods()) {
int offset = getStructMemberOffset(method);
if (offset != -1) {
if (!method.isNative() && !method.isStatic()) {
throw new IllegalArgumentException("@StructMember annotated method " + method + " must be native and not static");
}
Type type = null;
if (method.getParameterCount() == 0) {
soot.Type sootType = method.getReturnType();
// Possibly a getter
if (hasPointerAnnotation(method) && !sootType.equals(LongType.v())) {
throw new IllegalArgumentException("@StructMember(" + offset + ") annotated getter " + method + " must be of type long when annotated with @Pointer");
}
if (hasMachineSizedFloatAnnotation(method) && !sootType.equals(DoubleType.v()) && !sootType.equals(FloatType.v())) {
throw new IllegalArgumentException("@StructMember(" + offset + ") annotated getter " + method + " must be of type float or double when annotated with @MachineSizedFloat");
}
if ((hasMachineSizedSIntAnnotation(method) || hasMachineSizedUIntAnnotation(method)) && !sootType.equals(LongType.v())) {
throw new IllegalArgumentException("@StructMember(" + offset + ") annotated getter " + method + " must be of type long when annotated with @MachineSizedSInt or @MachineSizedUInt");
}
if (sootType instanceof soot.ArrayType && !hasArrayAnnotation(method)) {
throw new IllegalArgumentException("@Array annotation expected on struct member getter " + method);
}
} else if (method.getParameterCount() == 1) {
soot.Type sootType = method.getParameterType(0);
if (hasPointerAnnotation(method, 0) && !sootType.equals(LongType.v())) {
throw new IllegalArgumentException("@StructMember(" + offset + ") annotated setter " + method + " must be of type long when annotated with @Pointer");
}
if (hasMachineSizedFloatAnnotation(method, 0) && !sootType.equals(DoubleType.v()) && !sootType.equals(FloatType.v())) {
throw new IllegalArgumentException("@StructMember(" + offset + ") annotated setter " + method + " must be of type float or double when annotated with @MachineSizedFloat");
}
if ((hasMachineSizedSIntAnnotation(method, 0) || hasMachineSizedUIntAnnotation(method)) && !sootType.equals(LongType.v())) {
throw new IllegalArgumentException("@StructMember(" + offset + ") annotated setter " + method + " must be of type long when annotated with @MachineSizedSInt or @MachineSizedUInt");
}
if (sootType instanceof soot.ArrayType && !hasArrayAnnotation(method, 0)) {
throw new IllegalArgumentException("@Array annotation expected on first parameter of struct member setter " + method);
}
soot.Type retType = method.getReturnType();
// The return type of the setter must be void or this
if (!retType.equals(VoidType.v()) && !(retType instanceof RefType && ((RefType) retType).getSootClass().equals(clazz))) {
throw new IllegalArgumentException("Setter " + method + " for " + "@StructMember(" + offset + ") " + " must either return nothing or return a " + clazz);
}
} else {
throw new IllegalArgumentException("@StructMember annotated method " + method + " has too many parameters");
}
type = getStructMemberType(method);
int index = offset + 1;
if (result[index] == null) {
result[index] = type;
} else if (type != result[index]) {
// Two members mapped to the same offset (union). Pick
// the type with the largest alignment and pad with bytes
// up to the largest size.
result[index] = mergeStructMemberTypes(config.getDataLayout(), type, result[index]);
}
}
}
for (int i = 1; i < result.length; i++) {
if (result[i] == null) {
throw new IllegalArgumentException("No @StructMember(" + i + ") defined in class " + clazz);
}
}
if (!clazz.isAbstract() && checkEmpty && n == 0 && superType == null) {
throw new IllegalArgumentException("Struct class " + clazz + " has no @StructMember annotated methods");
}
return new StructureType(result);
}
use of soot.SootClass in project robovm by robovm.
the class ObjCMemberPlugin method findOverriddenMethods.
private List<SootMethod> findOverriddenMethods(SootClass sootClass, SootMethod method) {
SootClass supercls = sootClass.getSuperclass();
while (!supercls.getType().equals(org_robovm_objc_ObjCObject.getType())) {
try {
SootMethod m = supercls.getMethod(method.getName(), method.getParameterTypes(), method.getReturnType());
if (overrides(method, m) && !hasAnnotation(m, NOT_IMPLEMENTED)) {
return Collections.singletonList(m);
}
} catch (RuntimeException e) {
// Soot throws RuntimeException if method not found
}
supercls = supercls.getSuperclass();
}
/*
* Method doesn't override any method in superclasses. Check interfaces
* as well. There may be several methods in interfaces which this method
* overrides. We have to return all of them as we cannot assume that
* first one found has the @Method or @Property annotation.
*/
List<SootMethod> candidates = new ArrayList<>();
findOverriddenMethodsOnInterfaces(sootClass, method, candidates);
return candidates;
}
use of soot.SootClass in project robovm by robovm.
the class TypeEncoder method getStructMembers.
private List<Member> getStructMembers(SootClass clazz, boolean is64bit) {
List<Member> members = new ArrayList<>();
if (clazz.hasSuperclass()) {
SootClass superclass = clazz.getSuperclass();
if (!superclass.getName().equals("org.robovm.rt.bro.Struct")) {
members.addAll(getStructMembers(clazz, is64bit));
}
}
for (SootMethod method : clazz.getMethods()) {
int offset = getStructMemberOffset(method);
if (offset != -1) {
if (!method.isNative() && !method.isStatic()) {
// thrown by the ClassCompiler later on.
continue;
}
Type type;
int idx;
if (method.getParameterCount() == 0) {
type = method.getReturnType();
idx = -1;
} else if (method.getParameterCount() == 1) {
type = method.getParameterType(0);
idx = 0;
} else {
// throw by the ClassCompiler later on.
continue;
}
Member member = new Member();
member.offset = offset;
member.type = encodeOne(method, type, idx, is64bit);
members.add(member);
}
}
return members;
}
Aggregations