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. Building BrainFuck in Swift Samuel Giddins

  2. Samuel Giddins Cocoa @ Realm CocoaPods, Bundler, Jazzy, etc.

  3. BrainFuck

  4. Turing Complete

  5. ++++++++ [>++++ [>++>+++>+++>+<<<<-] >+>+>->>+[<]<- ] >>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.

  6. Hello World! ++++++++ [>++++ [>++>+++>+++>+<<<<-] >+>+>->>+[<]<- ] >>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.

  7. The 8 Operations

  8. | 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` |
  9. !

  10. Interpreter

  11. Virtual Machine » Encapsulates state » Internally driven » Single-use

  12. Virtual Machine class VM { init?(program: String) func run() }

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

    data: UnsafeMutablePointer<UInt8> var dataPointer: Int = 0 }
  14. class VM { init?(program: String) func run() var data: UnsafeMutablePointer<UInt8>

    var dataPointer: Int = 0 let commands: [Command] }
  15. VM.Command » IncrData » DecrData » Incr » Decr »

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

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

    arbitrary (linear) complexity. » Extra layers of indirection.
  18. None
  19. So how do we make our interpreter that fast?

  20. Threading!

  21. Threading! (no, not that kind of threading)

  22. Threading! » Precompute all of our jumps » Validate program

    before running
  23. 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") }
  24. » 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
  25. 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
  26. No need to run Swift code

  27. (All) Interpreters are Slow » Interpretation takes time » Function

    call for each command » Continuous penalty while program runs » Host language overhead » Refcounting is a pain
  28. So let's not write an interpreter. Let's used compiled code.

    Let's compile it Just-In-Time.
  29. 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)) }
  30. None
  31. Swift Gotchas » ARC » Strings » UnsafeMutablePointer » MutableBox

    » Trapping arithmatic » Bounds checking
  32. Open Source https://github.com/segiddins/BF

  33. Demo

  34. ----[---->+<]>++.[--->+<]>+++.[--->+<]>-.-[---->+<]>++.----[->++++<]>+.++++ .++[->+++<]>.[--->+<]>----.+.-----------.++++++.-.+++++.[->+++++<]>.>++++++ ++++..>-[--->+<]>--.++++++++++++++.++++++++++++.++++++++.++[->+++<]>.++++++ +.[++>---<]>--.+++[->++<]>+.-[-->+++<]>.-----..+++++.+++++.+++++.+[---->+<] >+++.++++++++.++[-->+++<]>+.-[----->+<]>.++++[->+++<]>.++.++.-----..+++++.+ ++++.+++++.-[--->+<]>+++.>++++++++++..>-[--->+<]>-.[---->+++++<]>-.-------. +++++++++++++.---.++++++++.+[---->+<]>+++.---[->++++<]>-.----.[--->+<]>---- -.+[----->+<]>.++++++++.+[->+++<]>+.+++++.--[--->+<]>--.---[->++++<]>.----- .[--->+<]>-----.>-[--->+<]>---.+[----->+++<]>.----.+++++++++++.+.[->+++++<] >-.-[--->++<]>--.+++++++.++++.+.-----------.+++++.-------.-[--->+<]>-.-.--[

    ->++<]>.---------.>++++++++++..
  35. None