Recently, I implemented last year's ICFP problem. Part of it is writing a VM that consists of memory slots, some registers and input and input ports. It takes a list of instructions, works them off one after the other, reading from input or memory, calculating something and the changing registers or writing to memory or output.
My implementation worked, but I wanted to make it faster, and thought compiling the instructions into a function using a macro could help. Indeed, my vm got 5 times faster, using arrays and an imperative style (generated by the compiler). But the macro I wrote is butt-ugly, so I thought I might get some advice on this list... To keep it simple I'll use an even simpler VM that only has memory and a simple instruction set. Example of an instruction: [+ 2 3] That means: read memory at address 2, read memory at address 3 and write the sum of both values back to address 2. This is how I use the compiler macro, feeding in 3 instructions: user=> (def compiled (compile-instructions '([+ 2 3] [- 0 1] [+ 1 0]))) #'user/compiled user=> (fn? compiled) true Now let's allocate an int array for the memory, using a size of 4 slots: user=> (def memory (into-array Integer/TYPE (range 4))) #'user/memory user=> (seq memory) (0 1 2 3) And now let's run the instructions on that memory: user=> (compiled memory) 0 user=> (seq memory) (-1 0 5 3) And finally, here comes the code for the macro - but be warned, I'm lacking formal macro education, which is why I'd appreciate any good comment: (defmacro compile-instructions [instructions] (let [memory (gensym "memory-")] (apply list 'fn [memory] (map (fn [[op m1 m2]] (list aset memory m1 (list op (list aget memory m1) (list aget memory m2)))) (eval instructions))))) I'm not using the backtick as it seemed simpler for what I was trying to do. I don't know if eval is evil and there's a better alternative? I'm actually not so sure whether it is good to roll out all instructions for performance. It might makes things actually slower, as the JIT can compile less, apart from the fact that a Java method is limited to 64k in size, so the number of instructions I can compile is limited: user=> (def compiled (compile-instructions (take 1150 (cycle '([+ 2 3] [- 0 1] [+ 1 0]))))) java.lang.ClassFormatError: Invalid method Code length 65581 in class file user$compiled__97 (NO_SOURCE_FILE:25) It blows up at just above 1k instructions. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en