| 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. |