use of org.robovm.compiler.llvm.FunctionType in project robovm by robovm.
the class CallbackMethodCompiler method compileCallback.
private Function compileCallback(ModuleBuilder moduleBuilder, SootMethod method) {
Function callbackFn = null;
FunctionType nativeFnType = null;
boolean useCWrapper = requiresCWrapper(method);
if (useCWrapper) {
// The C wrapper is the function which is called by native code. It
// handles structs passed/returned by value. It calls an LLVM function
// which has the same signature but all structs passed/returned by value
// replaced by pointers (i8*).
FunctionRef callbackCWrapperRef = getCallbackCWrapperRef(method, Symbols.callbackCSymbol(method));
getCWrapperFunctions().add(createCallbackCWrapper(callbackCWrapperRef.getType(), callbackCWrapperRef.getName(), Symbols.callbackInnerCSymbol(method)));
moduleBuilder.addFunctionDeclaration(new FunctionDeclaration(callbackCWrapperRef));
Type callbackRetType = callbackCWrapperRef.getType().getReturnType() instanceof StructureType ? I8_PTR : callbackCWrapperRef.getType().getReturnType();
Type[] callbackParamTypes = new Type[callbackCWrapperRef.getType().getParameterTypes().length];
for (int i = 0; i < callbackParamTypes.length; i++) {
Type t = callbackCWrapperRef.getType().getParameterTypes()[i];
if (t instanceof StructureType) {
t = I8_PTR;
}
callbackParamTypes[i] = t;
}
moduleBuilder.addAlias(new Alias(Symbols.callbackPtrSymbol(method), Linkage._private, new ConstantBitcast(callbackCWrapperRef, I8_PTR)));
callbackFn = new FunctionBuilder(Symbols.callbackInnerCSymbol(method), new FunctionType(callbackRetType, callbackParamTypes)).build();
nativeFnType = callbackCWrapperRef.getType();
} else {
FunctionType callbackFnType = getCallbackFunctionType(method, false);
callbackFn = FunctionBuilder.callback(method, callbackFnType);
moduleBuilder.addAlias(new Alias(Symbols.callbackPtrSymbol(method), Linkage._private, new ConstantBitcast(callbackFn.ref(), I8_PTR)));
nativeFnType = callbackFnType;
}
moduleBuilder.addFunction(callbackFn);
String targetName = method.isSynchronized() ? Symbols.synchronizedWrapperSymbol(method) : Symbols.methodSymbol(method);
FunctionRef targetFn = new FunctionRef(targetName, getFunctionType(method));
// Increase the attach count for the current thread (attaches the thread
// if not attached)
Value env = call(callbackFn, BC_ATTACH_THREAD_FROM_CALLBACK);
BasicBlockRef bbSuccess = callbackFn.newBasicBlockRef(new Label("success"));
BasicBlockRef bbFailure = callbackFn.newBasicBlockRef(new Label("failure"));
pushCallbackFrame(callbackFn, env);
trycatchAllEnter(callbackFn, env, bbSuccess, bbFailure);
callbackFn.newBasicBlock(bbSuccess.getLabel());
List<MarshaledArg> marshaledArgs = new ArrayList<MarshaledArg>();
ArrayList<Value> args = new ArrayList<Value>();
args.add(env);
if (!method.isStatic()) {
MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method, MarshalSite.RECEIVER));
MarshaledArg marshaledArg = new MarshaledArg();
marshaledArg.paramIndex = MarshalSite.RECEIVER;
marshaledArgs.add(marshaledArg);
Value arg = callbackFn.getParameterRef(0);
String targetClassName = getInternalName(method.getDeclaringClass());
arg = marshalNativeToObject(callbackFn, marshalerMethod, marshaledArg, env, targetClassName, arg, MarshalerFlags.CALL_TYPE_CALLBACK);
args.add(arg);
}
for (int i = 0, argIdx = 0; i < method.getParameterCount(); i++, argIdx++) {
if (!method.isStatic() && argIdx == 0) {
argIdx++;
}
Value arg = callbackFn.getParameterRef(argIdx);
soot.Type type = method.getParameterType(i);
if (needsMarshaler(type)) {
MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method, i));
String targetClassName = getInternalName(type);
if (arg.getType() instanceof PrimitiveType) {
arg = marshalNativeToValueObject(callbackFn, marshalerMethod, env, targetClassName, arg, MarshalerFlags.CALL_TYPE_CALLBACK);
} else {
MarshaledArg marshaledArg = new MarshaledArg();
marshaledArg.paramIndex = i;
marshaledArgs.add(marshaledArg);
Type nativeType = nativeFnType.getParameterTypes()[argIdx];
if (nativeType instanceof StructureType) {
// Struct passed by value on the stack. Make a heap copy of the data and marshal that.
DataLayout dataLayout = config.getDataLayout();
Value heapCopy = call(callbackFn, BC_COPY_STRUCT, env, arg, new IntegerConstant(dataLayout.getAllocSize(nativeType)));
arg = marshalNativeToObject(callbackFn, marshalerMethod, marshaledArg, env, targetClassName, heapCopy, MarshalerFlags.CALL_TYPE_CALLBACK);
} else {
arg = marshalNativeToObject(callbackFn, marshalerMethod, marshaledArg, env, targetClassName, arg, MarshalerFlags.CALL_TYPE_CALLBACK);
}
}
} else {
arg = marshalNativeToPrimitive(callbackFn, method, i, arg);
}
args.add(arg);
}
Value result = call(callbackFn, targetFn, args);
// Call Marshaler.updateNative() for each object that was marshaled before
// the call.
updateNative(method, callbackFn, env, MarshalerFlags.CALL_TYPE_CALLBACK, marshaledArgs);
// Marshal the returned value to a native value before returning
if (needsMarshaler(method.getReturnType())) {
MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method));
Type nativeType = callbackFn.getType().getReturnType();
if (nativeType instanceof PrimitiveType) {
result = marshalValueObjectToNative(callbackFn, marshalerMethod, nativeType, env, result, MarshalerFlags.CALL_TYPE_CALLBACK);
} else {
result = marshalObjectToNative(callbackFn, marshalerMethod, null, nativeType, env, result, MarshalerFlags.CALL_TYPE_CALLBACK);
}
} else {
result = marshalPrimitiveToNative(callbackFn, method, result);
}
trycatchLeave(callbackFn, env);
popCallbackFrame(callbackFn, env);
call(callbackFn, BC_DETACH_THREAD_FROM_CALLBACK, env);
callbackFn.add(new Ret(result));
callbackFn.newBasicBlock(bbFailure.getLabel());
trycatchLeave(callbackFn, env);
popCallbackFrame(callbackFn, env);
Value ex = call(callbackFn, BC_EXCEPTION_CLEAR, env);
// Call Marshaler.updateNative() for each object that was marshaled before
// the call.
updateNative(method, callbackFn, env, MarshalerFlags.CALL_TYPE_CALLBACK, marshaledArgs);
call(callbackFn, BC_DETACH_THREAD_FROM_CALLBACK, env);
call(callbackFn, BC_THROW, env, ex);
callbackFn.add(new Unreachable());
return callbackFn;
}
use of org.robovm.compiler.llvm.FunctionType in project robovm by robovm.
the class TrampolineCompiler method createLdcArray.
private FunctionRef createLdcArray(String targetClass) {
if (isPrimitiveComponentType(targetClass)) {
throw new IllegalArgumentException();
}
String fnName = Symbols.arrayldcSymbol(targetClass);
FunctionRef fnRef = new FunctionRef(fnName, new FunctionType(OBJECT_PTR, ENV_PTR));
if (!mb.hasSymbol(fnName)) {
Function fn = new FunctionBuilder(fnRef).name(fnName).linkage(weak).build();
Global g = new Global(Symbols.arrayPtrSymbol(targetClass), weak, new NullConstant(OBJECT_PTR));
if (!mb.hasSymbol(g.getName())) {
mb.addGlobal(g);
}
FunctionRef ldcArrayClassFn = BC_LDC_ARRAY_BOOT_CLASS;
if (!isPrimitiveBaseType(targetClass)) {
Clazz baseType = config.getClazzes().load(getBaseType(targetClass));
if (!baseType.isInBootClasspath()) {
ldcArrayClassFn = BC_LDC_ARRAY_CLASS;
}
}
Value arrayClass = call(fn, ldcArrayClassFn, fn.getParameterRef(0), g.ref(), mb.getString(targetClass));
fn.add(new Ret(arrayClass));
mb.addFunction(fn);
}
return fnRef;
}
use of org.robovm.compiler.llvm.FunctionType in project robovm by robovm.
the class TypesTest method testGetFunctionTypeFromDescriptor.
@Test
public void testGetFunctionTypeFromDescriptor() {
FunctionType type = null;
type = getFunctionType("()V", true);
assertEquals(VOID, type.getReturnType());
assertEquals(1, type.getParameterTypes().length);
assertEquals(ENV_PTR, type.getParameterTypes()[0]);
type = getFunctionType("()V", false);
assertEquals(VOID, type.getReturnType());
assertEquals(2, type.getParameterTypes().length);
assertEquals(ENV_PTR, type.getParameterTypes()[0]);
assertEquals(OBJECT_PTR, type.getParameterTypes()[1]);
type = getFunctionType("(Ljava/lang/Object;)Ljava/lang/String;", true);
assertEquals(OBJECT_PTR, type.getReturnType());
assertEquals(2, type.getParameterTypes().length);
assertEquals(ENV_PTR, type.getParameterTypes()[0]);
assertEquals(OBJECT_PTR, type.getParameterTypes()[1]);
type = getFunctionType("(Ljava/lang/Object;)Ljava/lang/String;", false);
assertEquals(OBJECT_PTR, type.getReturnType());
assertEquals(3, type.getParameterTypes().length);
assertEquals(ENV_PTR, type.getParameterTypes()[0]);
assertEquals(OBJECT_PTR, type.getParameterTypes()[1]);
assertEquals(OBJECT_PTR, type.getParameterTypes()[2]);
}
use of org.robovm.compiler.llvm.FunctionType 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.FunctionType 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();
}
Aggregations