use of org.robovm.compiler.llvm.FunctionRef in project robovm by robovm.
the class MethodCompiler method immediate.
private Value immediate(Unit unit, Immediate v) {
// v is either a soot.Local or a soot.jimple.Constant
if (v instanceof soot.Local) {
Local local = (Local) v;
Type type = getLocalType(v.getType());
VariableRef var = new VariableRef(local.getName(), new PointerType(type));
Variable tmp = function.newVariable(type);
function.add(new Load(tmp, var, !sootMethod.getActiveBody().getTraps().isEmpty())).attach(unit);
return new VariableRef(tmp);
} else if (v instanceof soot.jimple.IntConstant) {
return new IntegerConstant(((soot.jimple.IntConstant) v).value);
} else if (v instanceof soot.jimple.LongConstant) {
return new IntegerConstant(((soot.jimple.LongConstant) v).value);
} else if (v instanceof soot.jimple.FloatConstant) {
return new FloatingPointConstant(((soot.jimple.FloatConstant) v).value);
} else if (v instanceof soot.jimple.DoubleConstant) {
return new FloatingPointConstant(((soot.jimple.DoubleConstant) v).value);
} else if (v instanceof soot.jimple.NullConstant) {
return new NullConstant(OBJECT_PTR);
} else if (v instanceof soot.jimple.StringConstant) {
String s = ((soot.jimple.StringConstant) v).value;
return call(unit, ldcString(s), env);
} else if (v instanceof soot.jimple.ClassConstant) {
// ClassConstant is either the internal name of a class or the descriptor of an array
String targetClassName = ((soot.jimple.ClassConstant) v).getValue();
if (isArray(targetClassName) && isPrimitiveComponentType(targetClassName)) {
String primitiveDesc = targetClassName.substring(1);
Variable result = function.newVariable(OBJECT_PTR);
function.add(new Load(result, new ConstantBitcast(new GlobalRef("array_" + primitiveDesc, CLASS_PTR), new PointerType(OBJECT_PTR)))).attach(unit);
return result.ref();
} else {
FunctionRef fn = null;
if (targetClassName.equals(this.className)) {
fn = FunctionBuilder.ldcInternal(sootMethod.getDeclaringClass()).ref();
} else {
Trampoline trampoline = new LdcClass(className, ((soot.jimple.ClassConstant) v).getValue());
trampolines.add(trampoline);
fn = trampoline.getFunctionRef();
}
return call(unit, fn, env);
}
}
throw new IllegalArgumentException("Unknown Immediate type: " + v.getClass());
}
use of org.robovm.compiler.llvm.FunctionRef in project robovm by robovm.
the class Linker method createLookup.
private Function createLookup(ModuleBuilder mb, ClazzInfo ci, MethodInfo mi) {
Function function = FunctionBuilder.lookup(ci, mi, false);
String targetFnName = mi.isSynchronized() ? Symbols.synchronizedWrapperSymbol(ci.getInternalName(), mi.getName(), mi.getDesc()) : Symbols.methodSymbol(ci.getInternalName(), mi.getName(), mi.getDesc());
FunctionRef fn = new FunctionRef(targetFnName, function.getType());
if (!mb.hasSymbol(fn.getName())) {
mb.addFunctionDeclaration(new FunctionDeclaration(fn));
}
Value result = tailcall(function, fn, function.getParameterRefs());
function.add(new Ret(result));
return function;
}
use of org.robovm.compiler.llvm.FunctionRef in project robovm by robovm.
the class Linker method link.
public void link(Set<Clazz> classes) throws IOException {
for (CompilerPlugin plugin : config.getCompilerPlugins()) {
plugin.beforeLinker(config, this, classes);
}
Arch arch = config.getArch();
OS os = config.getOs();
Set<Clazz> linkClasses = new TreeSet<Clazz>(classes);
config.getLogger().info("Linking %d classes (%s %s %s)", linkClasses.size(), os, arch, config.isDebug() ? "debug" : "release");
ModuleBuilder mb = new ModuleBuilder();
mb.addInclude(getClass().getClassLoader().getResource(String.format("header-%s-%s.ll", os.getFamily(), arch)));
mb.addInclude(getClass().getClassLoader().getResource("header.ll"));
mb.addGlobal(new Global("_bcRuntimeData", runtimeDataToBytes()));
ArrayConstantBuilder staticLibs = new ArrayConstantBuilder(I8_PTR);
for (Config.Lib lib : config.getLibs()) {
String p = lib.getValue();
if (p.endsWith(".a")) {
p = new File(p).getName();
String libName = p.substring(0, p.length() - 2);
if (libName.startsWith("lib")) {
libName = libName.substring(3);
}
staticLibs.add(mb.getString(libName));
}
}
staticLibs.add(new NullConstant(Type.I8_PTR));
mb.addGlobal(new Global("_bcStaticLibs", new ConstantGetelementptr(mb.newGlobal(staticLibs.build()).ref(), 0, 0)));
HashTableGenerator<String, Constant> bcpHashGen = new HashTableGenerator<String, Constant>(new ModifiedUtf8HashFunction());
HashTableGenerator<String, Constant> cpHashGen = new HashTableGenerator<String, Constant>(new ModifiedUtf8HashFunction());
int classCount = 0;
Map<ClazzInfo, TypeInfo> typeInfos = new HashMap<ClazzInfo, TypeInfo>();
for (Clazz clazz : linkClasses) {
TypeInfo typeInfo = new TypeInfo();
typeInfo.clazz = clazz;
typeInfo.id = classCount++;
typeInfos.put(clazz.getClazzInfo(), typeInfo);
StructureConstant infoErrorStruct = createClassInfoErrorStruct(mb, clazz.getClazzInfo());
Global info = null;
if (infoErrorStruct == null) {
info = new Global(Symbols.infoStructSymbol(clazz.getInternalName()), external, I8_PTR, false);
} else {
typeInfo.error = true;
info = new Global(Symbols.infoStructSymbol(clazz.getInternalName()), infoErrorStruct);
}
mb.addGlobal(info);
if (clazz.isInBootClasspath()) {
bcpHashGen.put(clazz.getInternalName(), new ConstantBitcast(info.ref(), I8_PTR));
} else {
cpHashGen.put(clazz.getInternalName(), new ConstantBitcast(info.ref(), I8_PTR));
}
}
mb.addGlobal(new Global("_bcBootClassesHash", new ConstantGetelementptr(mb.newGlobal(bcpHashGen.generate(), true).ref(), 0, 0)));
mb.addGlobal(new Global("_bcClassesHash", new ConstantGetelementptr(mb.newGlobal(cpHashGen.generate(), true).ref(), 0, 0)));
ArrayConstantBuilder bootClasspathValues = new ArrayConstantBuilder(I8_PTR);
ArrayConstantBuilder classpathValues = new ArrayConstantBuilder(I8_PTR);
List<Path> allPaths = new ArrayList<Path>();
allPaths.addAll(config.getClazzes().getPaths());
allPaths.addAll(config.getResourcesPaths());
for (Path path : allPaths) {
String entryName = null;
if (config.isSkipInstall() && config.getTarget().canLaunchInPlace()) {
entryName = path.getFile().getAbsolutePath();
} else {
entryName = config.getTarget().getInstallRelativeArchivePath(path);
}
if (path.isInBootClasspath()) {
bootClasspathValues.add(mb.getString(entryName));
} else {
classpathValues.add(mb.getString(entryName));
}
}
bootClasspathValues.add(new NullConstant(Type.I8_PTR));
classpathValues.add(new NullConstant(Type.I8_PTR));
mb.addGlobal(new Global("_bcBootclasspath", new ConstantGetelementptr(mb.newGlobal(bootClasspathValues.build()).ref(), 0, 0)));
mb.addGlobal(new Global("_bcClasspath", new ConstantGetelementptr(mb.newGlobal(classpathValues.build()).ref(), 0, 0)));
if (config.getMainClass() != null) {
mb.addGlobal(new Global("_bcMainClass", mb.getString(config.getMainClass())));
}
ModuleBuilder[] mbs = new ModuleBuilder[config.getThreads() + 1];
FunctionRef[] stubRefs = new FunctionRef[mbs.length];
ArrayConstantBuilder stubRefsArray = new ArrayConstantBuilder(I8_PTR);
mbs[0] = mb;
for (int i = 1; i < mbs.length; i++) {
mbs[i] = new ModuleBuilder();
mbs[i].addInclude(getClass().getClassLoader().getResource(String.format("header-%s-%s.ll", os.getFamily(), arch)));
mbs[i].addInclude(getClass().getClassLoader().getResource("header.ll"));
Function fn = new FunctionBuilder("_stripped_method" + i, new FunctionType(VOID, ENV_PTR)).linkage(external).build();
call(fn, BC_THROW_NO_SUCH_METHOD_ERROR, fn.getParameterRef(0), mbs[i].getString("Method has been stripped out of the executable"));
fn.add(new Unreachable());
mbs[i].addFunction(fn);
mb.addFunctionDeclaration(new FunctionDeclaration(fn.ref()));
stubRefs[i] = fn.ref();
stubRefsArray.add(new ConstantBitcast(fn.ref(), I8_PTR));
}
stubRefsArray.add(new NullConstant(I8_PTR));
mb.addGlobal(new Global("_bcStrippedMethodStubs", stubRefsArray.build()));
Random rnd = new Random();
buildTypeInfos(typeInfos);
Set<String> checkcasts = new HashSet<>();
Set<String> instanceofs = new HashSet<>();
Set<String> invokes = new HashSet<>();
for (Clazz clazz : linkClasses) {
ClazzInfo ci = clazz.getClazzInfo();
checkcasts.addAll(ci.getCheckcasts());
instanceofs.addAll(ci.getInstanceofs());
invokes.addAll(ci.getInvokes());
}
Set<String> reachableMethods = new HashSet<>();
for (Triple<String, String, String> node : config.getDependencyGraph().findReachableMethods()) {
reachableMethods.add(node.getLeft() + "." + node.getMiddle() + node.getRight());
}
int totalMethodCount = 0;
int reachableMethodCount = 0;
for (Clazz clazz : linkClasses) {
int mbIdx = rnd.nextInt(mbs.length - 1) + 1;
ClazzInfo ci = clazz.getClazzInfo();
// symbols errors.
for (MethodInfo mi : ci.getMethods()) {
if (!mi.isAbstract()) {
totalMethodCount++;
if (!reachableMethods.contains(clazz.getInternalName() + "." + mi.getName() + mi.getDesc())) {
createStrippedMethodStub(stubRefs[mbIdx], mbs[mbIdx], clazz, mi);
} else {
reachableMethodCount++;
}
}
}
TypeInfo typeInfo = typeInfos.get(ci);
if (typeInfo.error) {
// Add an empty TypeInfo
mb.addGlobal(new Global(Symbols.typeInfoSymbol(clazz.getInternalName()), new StructureConstantBuilder().add(new IntegerConstant(typeInfo.id)).add(new IntegerConstant(0)).add(new IntegerConstant(-1)).add(new IntegerConstant(0)).add(new IntegerConstant(0)).build()));
} else {
int[] classIds = new int[typeInfo.classTypes.length];
for (int i = 0; i < typeInfo.classTypes.length; i++) {
classIds[i] = typeInfo.classTypes[i].id;
}
int[] interfaceIds = new int[typeInfo.interfaceTypes.length];
for (int i = 0; i < typeInfo.interfaceTypes.length; i++) {
interfaceIds[i] = typeInfo.interfaceTypes[i].id;
}
mb.addGlobal(new Global(Symbols.typeInfoSymbol(clazz.getInternalName()), new StructureConstantBuilder().add(new IntegerConstant(typeInfo.id)).add(new IntegerConstant((typeInfo.classTypes.length - 1) * 4 + 5 * 4)).add(new IntegerConstant(-1)).add(new IntegerConstant(typeInfo.classTypes.length)).add(new IntegerConstant(typeInfo.interfaceTypes.length)).add(new ArrayConstantBuilder(I32).add(classIds).build()).add(new ArrayConstantBuilder(I32).add(interfaceIds).build()).build()));
if (!config.isDebug() && !ci.isInterface() && !ci.isFinal() && typeInfo.children.isEmpty()) {
// which doesn't do any lookup.
for (MethodInfo mi : ci.getMethods()) {
String name = mi.getName();
if (!name.equals("<clinit>") && !name.equals("<init>") && !mi.isPrivate() && !mi.isStatic() && !mi.isFinal() && !mi.isAbstract()) {
if (invokes.contains(clazz.getInternalName() + "." + name + mi.getDesc())) {
if (reachableMethods.contains(clazz.getInternalName() + "." + name + mi.getDesc())) {
mbs[mbIdx].addFunction(createLookup(mbs[mbIdx], ci, mi));
}
}
}
}
}
}
if (checkcasts.contains(clazz.getInternalName())) {
mbs[mbIdx].addFunction(createCheckcast(mbs[mbIdx], clazz, typeInfo));
}
if (instanceofs.contains(clazz.getInternalName())) {
mbs[mbIdx].addFunction(createInstanceof(mbs[mbIdx], clazz, typeInfo));
}
}
config.getLogger().info("%d methods out of %d included in the executable", reachableMethodCount, totalMethodCount);
List<File> objectFiles = new ArrayList<File>();
generateMachineCode(config, mbs, objectFiles);
for (Clazz clazz : linkClasses) {
objectFiles.add(config.getOFile(clazz));
}
/*
* Assemble the lines files for all linked classes into the module.
*/
for (Clazz clazz : linkClasses) {
File f = config.getLinesOFile(clazz);
if (f.exists() && f.length() > 0) {
objectFiles.add(f);
}
}
config.getTarget().build(objectFiles);
}
use of org.robovm.compiler.llvm.FunctionRef in project robovm by robovm.
the class BroMethodCompiler method ldcClass.
protected Value ldcClass(Function fn, String name, Value env) {
if (isArray(name) && isPrimitiveBaseType(name)) {
String primitiveDesc = name.substring(name.length() - 1);
Variable result = fn.newVariable(OBJECT_PTR);
fn.add(new Load(result, new ConstantBitcast(new GlobalRef("array_" + primitiveDesc, CLASS_PTR), new PointerType(OBJECT_PTR))));
return result.ref();
} else {
FunctionRef ldcClassFn = null;
if (name.equals(this.className)) {
ldcClassFn = FunctionBuilder.ldcInternal(this.className).ref();
} else {
Trampoline trampoline = new LdcClass(this.className, name);
trampolines.add(trampoline);
ldcClassFn = trampoline.getFunctionRef();
}
return call(fn, ldcClassFn, env);
}
}
use of org.robovm.compiler.llvm.FunctionRef 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;
}
Aggregations