Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building BrainFuck in Swift

Building BrainFuck in Swift

Samuel E. Giddins

August 14, 2015
Tweet

More Decks by Samuel E. Giddins

Other Decks in Technology

Transcript

  1. | Character | Meaning | |:----------|:-----------------------------------------------------------------------------------| | > | Move

    data pointer one cell to the right | | < | Move data pointer one cell to the left | | + | Increment the value at the data pointer | | - | Decrement the value at the data pointer | | . | Print out the value at the data pointer (as ASCII) | | , | Accept a byte of input, and store it as the value at the data pointer | | [ | Jump to the matching `]` unless the value at the data pointer is `0` | | ] | Jump backwards to the matching `[` unless the value at the data pointer is not `0` |
  2. !

  3. Virtual Machine class VM { init?(program: String) func run() var

    data: UnsafeMutablePointer<UInt8> var dataPointer: Int = 0 }
  4. VM.Command » IncrData » DecrData » Incr » Decr »

    Output » Input » LoopStart » LoopEnd
  5. The Naïve Approach public func run() { while instructionPointer !=

    program.endIndex { if let command = Command(rawValue: String(program[instructionPointer])) { command.execute(self) } instructionPointer++ } }
  6. The Naïve Approach Suuuuuuuuuuuuuuuper slow. » LoopStart & LoopEnd have

    arbitrary (linear) complexity. » Extra layers of indirection.
  7. var index = 0 var pairs = [Int]() for command

    in commands { switch command { case .LoopStart(_): pairs.append(index) case .LoopEnd(let endBox): if pairs.count == 0 { fatalError("invalid program") } let start = pairs.removeLast() switch commands[start] { case .LoopStart(let startBox): startBox.val = index endBox.val = start default: fatalError("invalid program") } default: () } index++ } if pairs.count != 0 { fatalError("invalid program") }
  8. » We know that each [ is balanced with a

    ] » Maintain a stack of jump targets [ » Push every time we see a [ » Pop every time we see a ] » Match up the jump target indices » Yes / No validation
  9. Next Steps » Roll up adjacent commands » No need

    to just increment / decrement » No need to just move one cell at a time » No need to run Swift code
  10. (All) Interpreters are Slow » Interpretation takes time » Function

    call for each command » Continuous penalty while program runs » Host language overhead » Refcounting is a pain
  11. JIT » malloc » mprotect » address[i] = instr »

    0xB3 0xF000 0xBA4 » mprotect » func run() { typealias Trampoline = @convention(c) Int -> Int let fp = executableSpace let f = unsafeBitCast(fp, Trampoline.self) print(f(data)) }