Skip to content

JIT with mulle clang

mulle-kybernetik-tv edited this page Sep 25, 2018 · 12 revisions

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.

Depending on the JIT setup you may have to call __load_mulle_objc yourself, to get classes, categories, strings, selectors etc. added to the runtime, if you can get at the static function symbol somehow.

Configure llvm for mulle-objc

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);
}

Compiling without mulle-objc-runtime.h

The lldb debugger does some funky JIT stuff, as the mulle-objc-runtime.h header is not readily available. To support such scenarios, your code must define 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 =
{
  12, // 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
};
Clone this wiki locally