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

Building BrainFuck in Swift

Building BrainFuck in Swift

Avatar for Samuel E. Giddins

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