Changes between Version 6 and Version 7 of InternalsMiscellany


Ignore:
Timestamp:
May 11, 2009, 8:12:38 AM (10 years ago)
Author:
lpolzer
Comment:

Moved the larger part of this page to separate pages in the internals section.

Legend:

Unmodified
Added
Removed
Modified
  • InternalsMiscellany

    v6 v7  
    1 [[TOC]]
    2 = Assorted internals tidbits =
    3 
    4 == Compiler backend ==
    5 {{{
    6 VINSN   Virtual instruction (probably akin to SBCL's VOPs)
    7   LAP   Lisp Assembly Parser; compiles SEXPs into opcodes
    8 }}}
    9 
    10 === VINSN macros ===
    11 {{{
    12 <-    copy register
    13 @     label
    14 @=    label (aligned)
    15 ->    jump to label
    16 ^     branch
    17 ?     register (unwired)
    18 $     register (wired)
    19 }}}
    20 
    21 (from compiler/X86/x862.lisp)
    22 
    23 === Operand syntax ===
    24 {{{
    25 (% x)    register
    26 ($ x)    immediate
    27 (@ x)    memory operand; x ~ ([seg] [disp] [base] [index] [scale])
    28 x        labelref
    29 (:rcontext x)   memory operand, using segment register or gpr; see @ for syntax of x.
    30 (:self fn)      self-reference
    31 }}}
    32 
    33 (from compiler/X86/x86-lap.lisp)
     1This page contains snippets of internals information that are work in progress.
    342
    353== Kernel ==
    364  * x86: the FS register contains a pointer to the current TCR.
    375  * x86: the TCR is defined in lisp-kernel/x86-constants32.h (struct tcr)
    38 
    39 === Memory allocation ===
    40 Explanation by gb:
    41 
    42   Memory allocation is per-thread; a thread conses within a private "chunk" of memory by decrementing a per-thread pointer that starts at the high end of its current chunk and comparing that pointer to the low end of the chunk; if the pointer's above the limit, we use the memory, otherwise we need a new chunk:
    43 
    44 {{{
    45    [21]    (subl ($ 7) (@ (% fs) 132))  ; subtract the size of a cons - the tag of a
    46 cons
    47                                         ; from the per-thread pointer
    48    [30]    (movl (@ (% fs) 132) (% temp0)) ; load the per-thread pointer into a temp
    49 reg
    50    [38]    (cmpl (@ (% fs) 136) (% temp0)) ; compare to limit
    51    [46]    (ja L50)                        ; continue if above limit
    52    [48]    (uuo-alloc)                     ; trap, get a new chunk
    53 L50
    54    [50]    (andb ($ 248) (@ (% fs) 132))   ; clear tag bits in thread-local storage
    55    [59]    (movl (% arg_y) (@ 3 (% temp0))) ; store car
    56    [62]    (movl (% arg_z) (@ -1 (% temp0))) ; store cdr
    57    [65]    (movl (% temp0) (% arg_z))      ; return cons cell
    58 }}}
    59 
    60 == Exception handling ==
    61 The manual has some information on this. Here's some more.
    62 
    63 === UUOs (by gb) ===
    64 
    65 ==== Origin ====
    66 On the DEC PDP-10, the acronym UUO stood for "Unimplemented User Operation"; UUOs were used to invoke system services and/or to invoke what we'd think of as exception handlers. [...] As it's used in CCL, the term just means "an illegal instruction that'll ultimately cause a lisp-aware handler function to be called."
    67 
    68 ==== Implementation details ====
    69 Executing an "int $n" (#xcd n) instruction transfers control to an
    70 entry insome (incredibly complex and baroque) table of handlers
    71 maintained by the chip.  The OS might use a few entries in this table
    72 to implement system calls (though modern x86 CPUs often have faster
    73 ways of doing system calls), and some entries are reserved for hardware-
    74 related interrupts.
    75 
    76 Trying to execute an "int $n" instruction that doesn't have a defined
    77 entry in this table causes a General Protection Fault, and this
    78 eventually causes (on Unix) a signal to be raised.  Exactly what
    79 signal depends on the OS; there's a macro called SIGNUM_FOR_INTN_TRAP
    80 defined conditionally in ccl/lisp-kernel/x86-exceptions.h that defines
    81 this.  As you can see, it's generally overloaded on SIGBUS or SIGSEGV,
    82 which usually indicates an addressing exception (yes, SIGILL would
    83 make more sense, but since it involves a GP fault an undefined "int
    84 $n" winds up taking the same path as a memory protection fault) and
    85 we need to look at other arguments to the signal handler (as defined
    86 by the IS_MAYBE_INT_TRAP macro: if IS_MAYBE_INT_TRAP is true, we believe
    87 that we can look at the the byte that the PC in the signal context is
    88 pointing to to see if it's #xcd; if not, the SIGSEGV or SIGBUS might
    89 have been caused by trying to execute code at an unmapped address.)
    90 
    91 We also use "ud2a" instructions (followed by a byte or more of data)
    92 for similar purposes, but "int $n" is generally shorter; illegal
    93 instructions that use the ud2a opcode (which generally -does- raise
    94 SIGILL when executed) are sometimes called "xuuos" (eXtended UUOs).
    95 
    96 Once in a while (when doing a port to a new OS), we've found that the
    97 OS uses an interrupt that we've previously considered free for our
    98 use, and have had to do things differently (reassign UUOs or avoid
    99 emitting conflicting ones.)  I suppose that that could happen if we
    100 ported to some other OS (NetBSD ?), but it's unlikely that x8632 OSes
    101 will invoke new functionality via "int $n" (since other means of doing
    102 system calls are generally faster/better.)  See the comment in x86-asm.lisp:
    103 
    104 ;;; DON'T use #xcd8x: doing so will make Mach angry and confused.