| | 71 | Another potential idea involves the direction flag (DF) in EFLAGS. |
| | 72 | The lisp can't use any of the string instructions, so it would be possible to |
| | 73 | use this bit for other purposes. When DF is clear, this could tell the GC that |
| | 74 | the normal register partitioning (as above) is in effect. |
| | 75 | When DF is set, this could indicate that an alternate register |
| | 76 | register partitioning would be in effect, e.g., |
| | 77 | |
| | 78 | {{{ |
| | 79 | eax imm0 |
| | 80 | ecx imm2 |
| | 81 | edx imm1 |
| | 82 | ebx arg_z |
| | 83 | esp stack pointer |
| | 84 | ebp frame pointer |
| | 85 | esi arg_y |
| | 86 | edi fn |
| | 87 | }}} |
| | 88 | |
| | 89 | We'd need to be careful save the state of the flags and clear DF before calling foreign code. |
| | 90 | |
| | 91 | (I got the idea of using a bit in EFLAGS to distinguish between two modes of register usage from http://groups.google.com/group/comp.lang.lisp/msg/d5bbe1a9461fe476.) |
| | 92 | |
| | 93 | One further idea is to arrange that no lisp object can be located at an |
| | 94 | address below 2^24^. Since no valid vector index can be as great as 2^24^ |
| | 95 | (the value of ARRAY-TOTAL-SIZE-LIMIT), this means that we could store unboxed |
| | 96 | array indicies in node registers and still have the GC reliably distinguish |
| | 97 | nodes from other values. (The main win to this would be making AREF easy. |
| | 98 | It wouldn't be necessary to fool around marking registers as immediates.) |
| | 99 | |
| 68 | | The tagging scheme can basically follow the PPC32 port. An important |
| 69 | | difference is that the three-bit tag #b101, which is for NIL on PPC32, |
| 70 | | would be used for a thing called a tagged return addresses on IA-32. |
| 71 | | (More on this later.) |
| | 102 | === TCR additions === |
| | 103 | |
| | 104 | ==== Node spill area ==== |
| | 105 | Since we have so few registers, we have a static spill area of 4 words in |
| | 106 | each lisp thread's TCR. The GC treats these as roots, and the convention |
| | 107 | is that they're caller-saved. (At the moment, the compiler knows nothing |
| | 108 | of this spill area, and it's used only from LAP functions and subprimitives.) |
| | 109 | |
| | 110 | We do have to be careful about clearing out this spill area so that the GC |
| | 111 | doesn't hang onto objects that would otherwise be garbage. PROCESS-INTERRUPT |
| | 112 | will need to save and restore these values, and we might need |
| | 113 | to say that any callback (including traps) does so as well. (There's enough |
| | 114 | complexity already in traps and callbacks that saving/restoring the spill area isn't likely |
| | 115 | to add substantial overhead.) |
| | 116 | |
| | 117 | ==== Unboxed words ==== |
| | 118 | There are also a couple of words in the TCR that are used for unboxed values. |
| | 119 | We could build a frame on the tsp, but that's rather expensive. |
| | 120 | |
| | 121 | One situation that comes to mind involves dividing an ''n''-digit bignum by a single |
| | 122 | digit: we need registers |
| | 123 | to contain the bignum dividend, the result (the bignum quotient), and an index register. The |
| | 124 | DIV instruction requires the use of EDX:EAX pair. That means we're out of registers (fn, |
| | 125 | ebp, and esp are all in use), and have to store the single digit divisor somewhere else. |
| | 126 | We'd typically keep an unboxed value in an MMX register, but we can't use an MMX register as an operand to DIV. |
| | 127 | Therefore we have to |
| | 128 | use a memory operand: the unboxed word in the TCR. |
| | 129 | |
| | 130 | ==== next-method-context ==== |
| | 131 | The CLOS implementation sometimes uses an invisible argument to pass |
| | 132 | context information for CALL-NEXT-METHOD. On other ports, this is a register |
| | 133 | that's not part of the normal calling sequence, but on IA-32, all the registers |
| | 134 | are spoken for: arg_y and arg_z contain the last two arguments, temp1 is used as |
| | 135 | nargs, and temp0 is the function about to be called. |
| | 136 | We therefore pass the next-method-context via a slot in the TCR. (No, it's not pretty.) |
| | 137 | The GC will have to |
| | 138 | treat this as a root, and we might want to arrange to clear it out somehow so |
| | 139 | that it doesn't hang onto something that's otherwise garbage. |