diff --git a/Sources/LLVM/JIT.swift b/Sources/LLVM/JIT.swift index 6257344f..3e130fd3 100644 --- a/Sources/LLVM/JIT.swift +++ b/Sources/LLVM/JIT.swift @@ -7,9 +7,15 @@ public enum JITError: Error, CustomStringConvertible { /// the failure. case couldNotInitialize(String) + /// The JIT was unable to remove the provided module. A message is provided + /// explaining the failure + case couldNotRemoveModule(Module, String) + /// A human-readable description of the error. public var description: String { switch self { + case .couldNotRemoveModule(let module, let message): + return "could not remove module '\(module.name)': \(message)" case .couldNotInitialize(let message): return "could not initialize JIT: \(message)" } @@ -61,6 +67,42 @@ public final class JIT { } } + /// Retrieves a pointer to the function compiled by this JIT. + /// - parameter name: The name of the function you wish to look up. + /// - returns: A pointer to the result of compiling the specified function. + /// - note: You will have to `unsafeBitCast` this pointer to + /// the appropriate `@convention(c)` function type to be + /// able to run it from Swift. + /// + /// ``` + /// typealias FnPtr = @convention(c) () -> Double + /// let fnAddr = jit.addressOfFunction(name: "test") + /// let fn = unsafeBitCast(fnAddr, to: FnPtr.self) + /// ``` + public func addressOfFunction(name: String) -> OpaquePointer? { + let addr = LLVMGetFunctionAddress(llvm, name) + guard addr != 0 else { return nil } + return OpaquePointer(bitPattern: UInt(addr)) + } + + /// Adds the provided module, and all top-level declarations into this JIT. + /// - parameter module: The module you wish to add. + public func addModule(_ module: Module) { + LLVMAddModule(llvm, module.llvm) + } + + /// Removes the provided module, and all top-level declarations, from this + /// JIT. + public func removeModule(_ module: Module) throws { + var outMod: LLVMModuleRef? = module.llvm + var outError: UnsafeMutablePointer? + LLVMRemoveModule(llvm, module.llvm, &outMod, &outError) + if let err = outError { + defer { LLVMDisposeMessage(err) } + throw JITError.couldNotRemoveModule(module, String(cString: err)) + } + } + /// Runs the specified function as if it were the `main` function in an /// executable. It takes an array of argument strings and passes them /// into the function as `argc` and `argv`. diff --git a/Sources/LLVM/Module.swift b/Sources/LLVM/Module.swift index 6faf926e..dbf93d98 100644 --- a/Sources/LLVM/Module.swift +++ b/Sources/LLVM/Module.swift @@ -72,6 +72,17 @@ public final class Module: CustomStringConvertible { return TargetData(llvm: LLVMGetModuleDataLayout(llvm)) } + /// The identifier of this module. + public var name: String { + get { + guard let id = LLVMGetModuleIdentifier(llvm, nil) else { return "" } + return String(cString: id) + } + set { + LLVMSetModuleIdentifier(llvm, newValue, newValue.utf8.count) + } + } + /// Print a representation of a module to a file at the given path. /// /// If the provided path is not suitable for writing, this function will throw