use of org.robovm.compiler.llvm.Type 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 org.robovm.compiler.llvm.Type in project robovm by robovm.
the class BroMethodCompiler method getBridgeOrCallbackFunctionType.
private FunctionType getBridgeOrCallbackFunctionType(String anno, SootMethod method, boolean dynamic, boolean considerVariadic) {
Type returnType = getReturnType(anno, method);
boolean varargs = considerVariadic && hasVariadicAnnotation(method);
int variadicIndex = varargs ? getVariadicParameterIndex(method) : Integer.MAX_VALUE;
List<Type> paramTypes = new ArrayList<>();
for (int i = dynamic ? 1 : 0; i < method.getParameterCount(); i++) {
if (i == variadicIndex) {
break;
}
paramTypes.add(getParameterType(anno, method, i));
}
if (!method.isStatic()) {
int idx = hasStructRetAnnotation(method, 0) ? 1 : 0;
soot.Type sootType = method.getDeclaringClass().getType();
if (isStruct(sootType)) {
paramTypes.add(idx, new PointerType(getStructType(sootType)));
} else if (isNativeObject(sootType)) {
// NativeObjects are always passed by reference.
paramTypes.add(idx, I8_PTR);
} else {
throw new IllegalArgumentException("Receiver of non static " + anno + " method " + method + " must either be a Struct or a NativeObject");
}
}
return new FunctionType(returnType, varargs, paramTypes.toArray(new Type[paramTypes.size()]));
}
use of org.robovm.compiler.llvm.Type in project robovm by robovm.
the class Functions method callWithArguments.
public static Value callWithArguments(Function currentFunction, Value fn, Argument... args) {
Variable result = null;
Type returnType = ((FunctionType) fn.getType()).getReturnType();
if (returnType != VOID) {
result = currentFunction.newVariable(returnType);
}
currentFunction.add(new Call(result, fn, args));
return result == null ? null : result.ref();
}
use of org.robovm.compiler.llvm.Type in project robovm by robovm.
the class Functions method invoke.
public static Value invoke(Function currentFunction, Value fn, BasicBlockRef success, BasicBlockRef failure, Value... args) {
Variable result = null;
Type returnType = ((FunctionType) fn.getType()).getReturnType();
if (returnType != VOID) {
result = currentFunction.newVariable(returnType);
}
currentFunction.add(new Invoke(result, fn, success, failure, args));
return result == null ? null : result.ref();
}
use of org.robovm.compiler.llvm.Type in project robovm by robovm.
the class GlobalValueMethodCompiler method doCompile.
protected Function doCompile(ModuleBuilder moduleBuilder, SootMethod method) {
AnnotationTag globalValueAnnotation = getAnnotation(method, GLOBAL_VALUE);
validateGlobalValueMethod(method, globalValueAnnotation);
boolean optional = readBooleanElem(globalValueAnnotation, "optional", false);
boolean dereference = readBooleanElem(globalValueAnnotation, "dereference", true);
Function fn = createMethodFunction(method);
moduleBuilder.addFunction(fn);
Type valueType = getStructMemberType(method);
// Load the address of the resolved @GlobalValue method
Variable valuePtr = fn.newVariable(new PointerType(valueType));
Global valuePtrPtr = new Global(Symbols.globalValuePtrSymbol(method), _private, new NullConstant(I8_PTR));
moduleBuilder.addGlobal(valuePtrPtr);
fn.add(new Load(valuePtr, new ConstantBitcast(valuePtrPtr.ref(), new PointerType(valuePtr.getType()))));
Label nullLabel = new Label();
Label notNullLabel = new Label();
Variable nullCheck = fn.newVariable(I1);
fn.add(new Icmp(nullCheck, Condition.eq, valuePtr.ref(), new NullConstant(valuePtr.getType())));
fn.add(new Br(nullCheck.ref(), fn.newBasicBlockRef(nullLabel), fn.newBasicBlockRef(notNullLabel)));
fn.newBasicBlock(nullLabel);
VariableRef env = fn.getParameterRef(0);
call(fn, BC_THROW_UNSATISIFED_LINK_ERROR, env, moduleBuilder.getString(String.format((optional ? "Optional " : "") + "@GlobalValue method %s.%s%s not bound", className, method.getName(), getDescriptor(method))));
fn.add(new Unreachable());
fn.newBasicBlock(notNullLabel);
if (method.getParameterCount() == 0) {
// Getter
Value result = loadValueForGetter(method, fn, valueType, valuePtr.ref(), env, dereference, MarshalerFlags.CALL_TYPE_GLOBAL_VALUE);
fn.add(new Ret(result));
} else {
// Setter
// 'env' is parameter 0, the value we're interested in is at index 1
Value value = fn.getParameterRef(1);
storeValueForSetter(method, fn, valueType, valuePtr.ref(), env, value, MarshalerFlags.CALL_TYPE_GLOBAL_VALUE);
fn.add(new Ret());
}
return fn;
}
Aggregations