use of org.robovm.compiler.llvm.Bitcast in project robovm by robovm.
the class ClassCompiler method createLookupFunction.
private void createLookupFunction(SootMethod m) {
Function function = FunctionBuilder.lookup(m, true);
mb.addFunction(function);
Variable reserved0 = function.newVariable(I8_PTR_PTR);
function.add(new Getelementptr(reserved0, function.getParameterRef(0), 0, 4));
Variable reserved1 = function.newVariable(I8_PTR_PTR);
function.add(new Getelementptr(reserved1, function.getParameterRef(0), 0, 5));
function.add(new Store(getString(m.getName()), reserved0.ref()));
function.add(new Store(getString(getDescriptor(m)), reserved1.ref()));
if (!sootClass.isInterface()) {
int vtableIndex = 0;
try {
VTable vtable = config.getVTableCache().get(sootClass);
vtableIndex = vtable.getEntry(m).getIndex();
} catch (IllegalArgumentException e) {
// VTable throws this if any of the superclasses of the class is actually an interface.
// Shouldn't happen frequently but the DRLVM test suite has some tests for this.
// Use 0 as vtableIndex since this lookup function will never be called anyway.
}
Value classPtr = call(function, OBJECT_CLASS, function.getParameterRef(1));
Value vtablePtr = call(function, CLASS_VITABLE, classPtr);
Variable funcPtrPtr = function.newVariable(I8_PTR_PTR);
function.add(new Getelementptr(funcPtrPtr, vtablePtr, 0, 1, vtableIndex));
Variable funcPtr = function.newVariable(I8_PTR);
function.add(new Load(funcPtr, funcPtrPtr.ref()));
Variable f = function.newVariable(function.getType());
function.add(new Bitcast(f, funcPtr.ref(), f.getType()));
Value result = tailcall(function, f.ref(), function.getParameterRefs());
function.add(new Ret(result));
} else {
ITable itable = config.getITableCache().get(sootClass);
ITable.Entry entry = itable.getEntry(m);
List<Value> args = new ArrayList<Value>();
args.add(function.getParameterRef(0));
args.add(getInfoStruct(function, sootClass));
args.add(function.getParameterRef(1));
args.add(new IntegerConstant(entry.getIndex()));
Value fptr = call(function, BC_LOOKUP_INTERFACE_METHOD_IMPL, args);
Variable f = function.newVariable(function.getType());
function.add(new Bitcast(f, fptr, f.getType()));
Value result = tailcall(function, f.ref(), function.getParameterRefs());
function.add(new Ret(result));
}
}
use of org.robovm.compiler.llvm.Bitcast in project robovm by robovm.
the class NativeMethodCompiler method createNative.
private FunctionRef createNative(ModuleBuilder mb, SootMethod method) {
String targetInternalName = getInternalName(method.getDeclaringClass());
String methodName = method.getName();
String methodDesc = getDescriptor(method);
FunctionType nativeFunctionType = Types.getNativeFunctionType(methodDesc, method.isStatic());
String shortName = mangleNativeMethod(targetInternalName, methodName);
String longName = mangleNativeMethod(targetInternalName, methodName, methodDesc);
/*
* To support statically linked native method implementation we create
* weak stub functions with the same names as the expected JNI functions
* (long and short names). These will be discarded by the linker if
* proper functions are available at link time.
*
* The weak stub with the short JNI name just calls the weak stub with
* the long name.
*
* The weak stub with the long name calls _bcResolveNative() which will
* try to resolve the native method against dynamically loaded JNI libs.
* If _bcResolveNative() finds a matching symbol in a dynamic lib or an
* implementation has previously been registered using JNI
* RegisterNatives() that will be stored in the native method pointer
* passed to it and returned. The stub will call the implementation
* returned by _bcResolveNative(). If no implementation can be found
* _bcResolveNative() throws an UnsatisfiedLinkError and doesn't return
* to the stub.
*
* The limitation of this approach is that RegisterNatives() only works
* for dynamically linked native methods and can only be used prior to
* the first call of such a method. Native methods can never be rewired
* or unregistered.
*/
/*
* The function with the long JNI name. This is the one that calls
* _bcResolveNative() and then calls the implementation.
*/
Function fn = new FunctionBuilder(longName, nativeFunctionType).linkage(weak).build();
Global g = new Global(Symbols.nativeMethodPtrSymbol(targetInternalName, methodName, methodDesc), new NullConstant(I8_PTR));
mb.addGlobal(g);
FunctionRef ldcFn = FunctionBuilder.ldcInternal(targetInternalName).ref();
Value theClass = call(fn, ldcFn, fn.getParameterRef(0));
Value implI8Ptr = call(fn, BC_RESOLVE_NATIVE, fn.getParameterRef(0), theClass, mb.getString(methodName), mb.getString(methodDesc), mb.getString(shortName), mb.getString(longName), g.ref());
Variable nullTest = fn.newVariable(I1);
fn.add(new Icmp(nullTest, Condition.ne, implI8Ptr, new NullConstant(I8_PTR)));
Label trueLabel = new Label();
Label falseLabel = new Label();
fn.add(new Br(nullTest.ref(), fn.newBasicBlockRef(trueLabel), fn.newBasicBlockRef(falseLabel)));
fn.newBasicBlock(falseLabel);
if (fn.getType().getReturnType() instanceof IntegerType) {
fn.add(new Ret(new IntegerConstant(0, (IntegerType) fn.getType().getReturnType())));
} else if (fn.getType().getReturnType() instanceof FloatingPointType) {
fn.add(new Ret(new FloatingPointConstant(0.0, (FloatingPointType) fn.getType().getReturnType())));
} else if (fn.getType().getReturnType() instanceof PointerType) {
fn.add(new Ret(new NullConstant((PointerType) fn.getType().getReturnType())));
} else {
fn.add(new Ret());
}
fn.newBasicBlock(trueLabel);
Variable impl = fn.newVariable(nativeFunctionType);
fn.add(new Bitcast(impl, implI8Ptr, impl.getType()));
Value result = call(fn, impl.ref(), fn.getParameterRefs());
fn.add(new Ret(result));
mb.addFunction(fn);
FunctionRef targetFn = fn.ref();
if (!isLongNativeFunctionNameRequired(method)) {
/*
* Generate a function with the short JNI name. This just calls the
* function with the long name.
*/
Function fnShort = new FunctionBuilder(shortName, nativeFunctionType).linkage(weak).build();
Value resultInner = call(fnShort, fn.ref(), fnShort.getParameterRefs());
fnShort.add(new Ret(resultInner));
mb.addFunction(fnShort);
targetFn = fnShort.ref();
}
return targetFn;
}
use of org.robovm.compiler.llvm.Bitcast in project robovm by robovm.
the class StructMemberMethodCompiler method structMember.
private Function structMember(ModuleBuilder moduleBuilder, SootMethod method) {
Function function = createMethodFunction(method);
moduleBuilder.addFunction(function);
// Get the value of the handle field in the Struct base class and cast it to a <structType>*
Variable handleI64 = function.newVariable(I64);
function.add(new Load(handleI64, getFieldPtr(function, function.getParameterRef(1), offsetof(new StructureType(DATA_OBJECT, new StructureType(I64)), 1, 0), I64)));
Variable handlePtr = function.newVariable(new PointerType(structType));
function.add(new Inttoptr(handlePtr, handleI64.ref(), handlePtr.getType()));
// Add 1 since the first type in structType is the superclass type or {}.
int offset = getStructMemberOffset(method) + 1;
Type memberType = getStructMemberType(method);
Variable memberPtr = function.newVariable(new PointerType(memberType));
if (memberType != structType.getTypeAt(offset)) {
// Several @StructMembers of different types have this offset (union)
Variable tmp = function.newVariable(new PointerType(structType.getTypeAt(offset)));
function.add(new Getelementptr(tmp, handlePtr.ref(), 0, offset));
function.add(new Bitcast(memberPtr, tmp.ref(), memberPtr.getType()));
} else {
function.add(new Getelementptr(memberPtr, handlePtr.ref(), 0, offset));
}
VariableRef env = function.getParameterRef(0);
if (method.getParameterCount() == 0) {
// Getter
Value result = loadValueForGetter(method, function, memberType, memberPtr.ref(), function.getParameterRef(0), true, MarshalerFlags.CALL_TYPE_STRUCT_MEMBER);
function.add(new Ret(result));
} else {
// Setter
// 'env' is parameter 0, 'this' is at 1, the value we're interested in is at index 2
Value value = function.getParameterRef(2);
storeValueForSetter(method, function, memberType, memberPtr.ref(), env, value, MarshalerFlags.CALL_TYPE_STRUCT_MEMBER);
if (method.getReturnType().equals(VoidType.v())) {
function.add(new Ret());
} else {
function.add(new Ret(function.getParameterRef(1)));
}
}
return function;
}
use of org.robovm.compiler.llvm.Bitcast in project robovm by robovm.
the class BroMethodCompiler method loadValueForGetter.
protected Value loadValueForGetter(SootMethod method, Function fn, Type memberType, Value memberPtr, Value env, boolean dereference, long flags) {
soot.Type type = method.getReturnType();
Value result = null;
if (memberType instanceof StructureType) {
// The member is a child struct contained in the current struct
result = memberPtr;
} else if (memberType instanceof ArrayType) {
// The member is an array contained in the current struct
result = memberPtr;
} else if (dereference) {
Variable tmp = fn.newVariable(memberType);
fn.add(new Load(tmp, memberPtr));
result = tmp.ref();
} else {
// Do not dereference the pointer but use it as is. This is needed for
// global values such as _dispatch_main_q which is a struct and not a
// pointer which we should load. We want the address of the struct.
Variable tmp = fn.newVariable(memberType);
fn.add(new Bitcast(tmp, memberPtr, tmp.getType()));
result = tmp.ref();
}
if (needsMarshaler(type)) {
MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method));
String targetClassName = getInternalName(type);
if (memberType instanceof PrimitiveType) {
// Value type wrapping a primitive value (e.g. Enum, Integer and Bits)
result = marshalNativeToValueObject(fn, marshalerMethod, env, targetClassName, result, flags);
} else {
if (memberType instanceof ArrayType) {
// Array
result = marshalNativeToArray(fn, marshalerMethod, env, targetClassName, result, flags, getArrayDimensions(method));
} else {
result = marshalNativeToObject(fn, marshalerMethod, null, env, targetClassName, result, flags);
}
}
} else {
result = marshalNativeToPrimitive(fn, method, result);
}
return result;
}
Aggregations