Skip to content

Commit b40c63a

Browse files
Added JIT compiler abstraction (#19)
* Added JIT compiler abstraction * Added missing access control and fixed comment nits.
1 parent ed9bcec commit b40c63a

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

Sources/LLVM/JIT.swift

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import cllvm
2+
3+
/// JITError represents the different kinds of errors the JIT compiler can
4+
/// throw.
5+
public enum JITError: Error, CustomStringConvertible {
6+
/// The JIT was unable to be initialized. A message is provided explaining
7+
/// the failure.
8+
case couldNotInitialize(String)
9+
10+
/// A human-readable description of the error.
11+
public var description: String {
12+
switch self {
13+
case .couldNotInitialize(let message):
14+
return "could not initialize JIT: \(message)"
15+
}
16+
}
17+
}
18+
19+
/// A `JIT` is a Just-In-Time compiler that will compile and execute LLVM IR
20+
/// that has been generated in a `Module`. It can execute arbitrary functions
21+
/// and return the value the function generated, allowing you to write
22+
/// interactive programs that will run as soon as they are compiled.
23+
public final class JIT {
24+
/// The underlying LLVMExecutionEngineRef backing this JIT.
25+
internal let llvm: LLVMExecutionEngineRef
26+
27+
/// Creates a Just In Time compiler that will compile the code in the
28+
/// provided `Module` to the architecture of the provided `TargetMachine`,
29+
/// and execute it.
30+
///
31+
/// - parameters:
32+
/// - module: The module containing code you wish to execute
33+
/// - machine: The target machine which you're compiling for
34+
/// - throws: JITError
35+
public init(module: Module, machine: TargetMachine) throws {
36+
var jit: LLVMExecutionEngineRef?
37+
var error: UnsafeMutablePointer<Int8>?
38+
if LLVMCreateExecutionEngineForModule(&jit, module.llvm, &error) != 0 {
39+
let str = String(cString: error!)
40+
throw JITError.couldNotInitialize(str)
41+
}
42+
guard let _jit = jit else {
43+
throw JITError.couldNotInitialize("JIT was NULL")
44+
}
45+
self.llvm = _jit
46+
}
47+
48+
49+
/// Runs the specified function with the provided arguments by compiling
50+
/// it to machine code for the target architecture used to initialize this
51+
/// JIT.
52+
///
53+
/// - parameters:
54+
/// - function: The function you wish to execute
55+
/// - args: The arguments you wish to pass to the function
56+
/// - returns: The LLVM value that the function returned
57+
public func runFunction(_ function: Function, args: [IRValue]) -> IRValue {
58+
var irArgs = args.map { $0.asLLVM() as Optional }
59+
return irArgs.withUnsafeMutableBufferPointer { buf in
60+
return LLVMRunFunction(llvm, function.asLLVM(),
61+
UInt32(buf.count), buf.baseAddress)
62+
}
63+
}
64+
65+
66+
/// Runs the specified function as if it were the `main` function in an
67+
/// executable. It takes an array of argument strings and passes them
68+
/// into the function as `argc` and `argv`.
69+
///
70+
/// - parameters:
71+
/// - function: The `main` function you wish to execute
72+
/// - args: The string arguments you wish to pass to the function
73+
/// - returns: The numerical exit code returned by the function
74+
public func runFunctionAsMain(_ function: Function, args: [String]) -> Int {
75+
// FIXME: Also add in envp.
76+
return withCArrayOfCStrings(args) { buf in
77+
return Int(LLVMRunFunctionAsMain(llvm, function.asLLVM(),
78+
UInt32(buf.count),
79+
buf.baseAddress, nil))
80+
}
81+
}
82+
}
83+
84+
85+
/// Runs the provided block with the equivalent C strings copied from the
86+
/// passed-in array. The C strings will only be alive for the duration
87+
/// of the block, and they will be freed when the block exits.
88+
///
89+
/// - parameters:
90+
/// - strings: The strings you intend to convert to C strings
91+
/// - block: A block that uses the C strings
92+
/// - returns: The result of the passed-in block.
93+
/// - throws: Will only throw if the passed-in block throws.
94+
internal func withCArrayOfCStrings<T>(_ strings: [String], _ block:
95+
(UnsafeBufferPointer<UnsafePointer<Int8>?>) throws -> T) rethrows -> T {
96+
var cStrings = [UnsafeMutablePointer<Int8>?]()
97+
for string in strings {
98+
string.withCString {
99+
cStrings.append(strdup($0))
100+
}
101+
}
102+
defer {
103+
for cStr in cStrings {
104+
free(cStr)
105+
}
106+
}
107+
return try cStrings.withUnsafeBufferPointer { buf in
108+
// We need to make this "immutable" but that doesn't change
109+
// their size or contents.
110+
let constPtr = unsafeBitCast(buf.baseAddress,
111+
to: UnsafePointer<UnsafePointer<Int8>?>.self)
112+
return try block(UnsafeBufferPointer(start: constPtr, count: buf.count))
113+
}
114+
}

0 commit comments

Comments
 (0)