1 The Glorious New Update Mechanism
2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 When a constructor returns it makes sure that
9 R2 contains the info pointer for the constructor
10 R1,R3.. contain the components (if return in regs)
11 R1 points to the constructor object itself (if return in heap)
13 The info table for a constructor contains a pointer to the
14 constructor's update code. If a constructor returns to an
15 update frame, the update frame's code just jumps direct to the
16 constructor's update code, via the info pointer in R2.
18 This penalises slightly the return of a new constructor,
19 because we have to load R2 with the info ptr. [Fact: in runs
20 of the compiler, 20-30% of all returns are of a new constructor;
21 70-80% are existing constructors.]
25 Each dynamic-heap-allocated constructor has *two* info tables:
27 * the "NewCon" info table is put into R2 when returning a new
28 constructor, which does not yet exist in the heap; R1 is dead!
29 The "NewCon" info table has no GC entries, because it's only ever used
30 when returning in regs, never installed in a real constructor.
32 The NewCon table also needs a valid tag field (see taggery below)
34 * the "ExistingCon" info table is used for all constructors allocated
37 The update code for a constructor
38 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
39 The update code for a constructor actually performs the update
40 right away. [At present, the update is deferred until we get
41 back to the case expression.] It knows how to do the update
42 because the update code is constructor-specific.
44 Once it's done the update, it makes R1 point to the constructor object
45 in the heap (which'll either be freshly-allocated, if big, or the
46 updated thing itself), and (for non-niladic constructors) makes R2 point
47 to the "ExistingCon" info table for the constructor. (Of course the new
48 constructor will also have an ExistingCon info ptr.) For niladic
49 constructors, we do *not* use the "ExistingCon" info table. We continue
50 to overwrite updatees in-place, because this saves us an indirection
51 prior to garbage collection (and the extra niladic constructors disappear
52 during the next garbage collection anyway).
54 The update code in the ExistingCon info table simply updates with an
55 indirection, using R1. I *think* this can be one standard piece of
56 code. The only doubt here concerns GC; if updating with an
57 indirection can cause GC (possible on GRIP? or generational GC?),
58 then we need to know which regs are live. We can solve this by
59 putting a liveness mask in the info table too. [Arguably we want
60 that anyway; consider returning to the bottom of a stack object.]
61 So a liveness mask in the info table is probably a good idea.
63 Constructors which return in heap return with an ExistingCon info
64 ptr. They don't need a NewCon info table at all.
66 Notice that this means that when we return an *existing* constructor,
67 to an update frame, the update is done with an indirection, rather
68 than [as now] copying the constructor afresh. This solves the space duplication
69 problem which shows up in "clausify".
71 GC: R1 might be dead; R2 is a non-ptr. So this return convention
72 relies on using liveness masks for GC reg-liveness info, not the
73 old no-of-live-ptrs info.
78 [Current: For unvectored returns with more than one constructor, we
79 currently load TagReg, and scrutinise it in the case expression.
80 Worse, we also have to scrutinise TagReg in the update entry of the
83 In the new world, updates are handled without any nonsense. No need
84 to look at any register, becase we just jump to the constructor
87 Since we have an info ptr in R2, we can get the tag out of the info
88 table, thus getting rid of TagReg altogether. (This could conceivably
89 be a *lose* on a machine with lots of regs, because it replaces a
90 immediate small-const load by a memory fetch of the tag from the info
93 Not clear whether this is worth trying to improve. Could
95 a) #define TagReg to be a register or an offset from R2
96 b) issue a SET_TAG macro in the entry code for a constructor,
97 which usually expands to nothing
99 [NB 75-95% of all returns are vectored in runs of the compiler itself.]
101 The entry code for a constructor
102 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
103 The real reason the registers are assigned as above is to make the
104 entry code for a constructor simple. When the entry code is executed,
105 we have a new entry convention:
107 R1 points to the object
108 R2 is its info pointer
110 (Why? because we usually enter it by indirecting through its info
111 table, so it seems a shame to load the info ptr from memory twice.)
113 So all the entry code has to do is to return (perhaps vectored-ly).
114 (Maybe load TagReg, usually not --- see above.)
116 NB this entry convention applies, of course, to all thunks as
117 well as constructors -- whenever we enter an unknown object via R1 (Node).
121 Return vectors no longer need update code.
123 Unvectored returns can therefore be *direct* to the code,
124 rather than *indirect* via a 2-entry vector.
126 Penalty for this improvement: "polymorphic" return vectors,
127 notably that in an update frame, needs to accomodate either
128 a direct or a vectored return. So it has to look like:
130 UpdVec: jmp UnvectoredUpd
135 that is, the return vector is offset by some fixed amount
136 from the pointer put on the stack. Or, it could be done
142 UpdVec: ...code for UnvectoredUpd...
144 and then vectored returns would use negative offsets.
146 This grunge is necessary *only* for a fixed set of polymorphic return
147 vectors, part of the runtime system:
150 - restore cost centres
155 Case expressions generate either a direct return, or a vector,
156 but never a combination.
161 Standard update frames are still required if we don't know the type of
162 the constructor being returned. However, we often do know the type. In
163 this case, we can generate a type-specific updating return-vector to place
164 in the update frame rather than the StdUpdRetVector. This saves us one
165 level of indirection.
169 PAPs are basically handled just the same way as at present.
175 * RetVecReg dies. (Previously needed to do return after update.)
176 * Return vectors have half the number of entries.
177 * Unvectored returns go direct.
178 * Polymorphic seq/par and friends.
179 * No space duplication problem (cf clausify)
184 Tag and update code are needed only for constructor info tables.
185 It seems a shame to take up space in other info tables (ie 99% of them).
189 - use an indirection to GC code, so the vari-sized gc stuff becomes
191 - put the tag/upd code ptrs before the start of the info table. (or
192 between the info table and code when reversing info tables...)