use of org.robovm.compiler.llvm.NullConstant 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.NullConstant in project robovm by robovm.
the class Linker method createCheckcast.
private Function createCheckcast(ModuleBuilder mb, Clazz clazz, TypeInfo typeInfo) {
Function fn = FunctionBuilder.checkcast(clazz);
Value info = getInfoStruct(mb, fn, clazz);
if (typeInfo.error) {
// This will trigger an exception
call(fn, BC_LDC_CLASS, fn.getParameterRef(0), info);
fn.add(new Ret(new NullConstant(Types.OBJECT_PTR)));
} else if (!clazz.getClazzInfo().isInterface()) {
Value result = call(fn, CHECKCAST_CLASS, fn.getParameterRef(0), info, fn.getParameterRef(1), new IntegerConstant((typeInfo.classTypes.length - 1) * 4 + 5 * 4), new IntegerConstant(typeInfo.id));
fn.add(new Ret(result));
} else {
Value result = call(fn, CHECKCAST_INTERFACE, fn.getParameterRef(0), info, fn.getParameterRef(1), new IntegerConstant(typeInfo.id));
fn.add(new Ret(result));
}
return fn;
}
use of org.robovm.compiler.llvm.NullConstant 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();
}
Aggregations