-
Notifications
You must be signed in to change notification settings - Fork 8
JIT with mulle clang
JIT with mulle-clang is possible with mulle-clang-7 and up
JIT compilation should be easy, if you have the proper mulle-objc-runtime.h
header accessible. Your JIT code should import it, which it usually does by virtue of including Foundation.h
, MulleObjC.h
or some such header.
The resulting compiled object will contain a function __load_mulle_objc
that is an __attribute__(( constructor))
function, meaning that it should execute as soon as loaded.
It is important that your JIT setup calls the "static constructor" __load_mulle_objc
, to get classes, categories, strings, selectors etc. added to the runtime.
There are multiple JIT options available in llvm. Make sure the JIT is able to execute static constructor functions. This is how to do it fairly lowlevel:
static int Execute(std::unique_ptr<llvm::Module> Mod, char *const *envp)
{
llvm::Module &M = *Mod;
std::string Error;
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
std::unique_ptr<llvm::ExecutionEngine> EE(
createExecutionEngine(std::move(Mod), &Error));
if (!EE) {
llvm::errs() << "unable to make execution engine: " << Error << "\n";
return 255;
}
EE->finalizeObject();
EE->runStaticConstructorsDestructors( false); # the IMPORTANT part
llvm::Function *EntryFn = M.getFunction("main");
if( EntryFn)
{
// pass in something to main
std::vector<std::string> Args;
Args.push_back(M.getModuleIdentifier());
return EE->runFunctionAsMain(EntryFn, Args, envp);
}
return( 0);
}
Adapt the version numbers to your actual runtime. See the <mulle-objc-runtime/mulle-objc-version.h>
header for current values:
#define MULLE_OBJC_RUNTIME_VERSION_MAJOR 0
#define MULLE_OBJC_RUNTIME_VERSION_MINOR 14
#define MULLE_OBJC_RUNTIME_VERSION_PATCH 0
#define MULLE_OBJC_RUNTIME_LOAD_VERSION 13
extern int printf( const char *, ...);
@interface Foo
@end
@implementation Foo
+ (void) print
{
printf( "VfL Bochum 1848\n");
}
@end
// this function is optional for demo purposes
// it is not required to add the classes to the
// runtime
int main( void)
{
[Foo print];
return( 1848);
}
Copy/paste the contents of <mulle-objc-runtime/mulle-objc-jit.inc>
in front of your source code.
The lldb debugger needs to do some funky JIT stuff. With the mulle-objc-runtime.h
not readily available, it will add a top level variable __mulle_objc_objccompilerinfo
like so:
static const struct mulle_clang_objccompilerinfo
{
unsigned int load_version;
unsigned int runtime_version;
} __mulle_objc_objccompilerinfo =
{
13, // load version must match!
// check with: mulle-clang --version
0 // 0 to not emit __load_mulle_objc
// otherwise provide the current runtime version
// as: ((0 << 20) | (13 << 8) | 1) for 0.13.1
};