Friday, December 18, 2009

Lisp Epiphany - Native Code vs Byte Code

What does "Native code" Compiler mean in Lisp terms? If we look at SBCL which is a Native Code compiler and compare it against CLISP which is a Byte Code compiler, then we can get a better idea.

Coming from a C and Scripting background, the first thought that came to my mind was that a Native Code compiler generates executables whereas a Byte Code compiler does not. Once I dug in a bit more, I realized that is not the case. To assume SBCL is a sort of GCC that reads in code and spits outs an ELF executable is completely wrong. It does nothing of the sort.

Both SBCL and CLISP can save environments as a standalone executable. So, there is no real difference from an application delivery perspective. The real difference comes when we look at how SBCL and CLISP compile functions that we define.

Common Lisp has an environment function - disassemble. If we define a simple function and pass that function to disassemble, then we can see how different SBCL and CLISP are.

Consider the following function -

 (defun square (x) (* x x)) 

Its pretty straight-forward. Just a function that squares its input. Now we call disassemble on this function.

 (disassemble #'square) 

In CLISP we see the following output

Disassembly of function SQUARE
1 required argument
0 optional arguments
No rest parameter
No keyword parameters
4 byte-code instructions:
0     (LOAD&PUSH 1)
1     (LOAD&PUSH 2)
2     (CALLSR 2 57)                       ; *
5     (SKIP&RET 2)
NIL

whereas in SBCL we see something completely different -


; disassembly for SQUARE
; 23B6C274:       8BD3             MOV EDX, EBX               ; no-arg-parsing entry point
;       76:       8BFB             MOV EDI, EBX
;       78:       E8304049FE       CALL #x220002AD            ; GENERIC-*
;       7D:       7302             JNB L0
;       7F:       8BE3             MOV ESP, EBX
;       81: L0:   8B5DFC           MOV EBX, [EBP-4]
;       84:       8BE5             MOV ESP, EBP
;       86:       F8               CLC
;       87:       5D               POP EBP
;       88:       C3               RET
;       89:       CC0A             BREAK 10                   ; error trap
;       8B:       02               BYTE #X02
;       8C:       18               BYTE #X18                  ; INVALID-ARG-COUNT-ERROR
;       8D:       4D               BYTE #X4D                  ; ECX
NIL

What we have in SBCL is real machine code whereas in CLISP we see its Virtual Machine byte code. That's the real difference. SBCL actually compiled our square function into machine code but CLISP didn't.

Both approaches have their advantages and disadvantages but I won't be putting that in this post.

No comments: