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

Building BrainFuck in Swift

Building BrainFuck in Swift

4d6be90af74894fd132fb06dacec04d7?s=128

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