@@ -78,10 +78,6 @@ unnecessary pinning and zone pollution; see job003525_.)
7878_`.req.setjmp `: The implementation must follow the C Standard in its
7979use of the ``setjmp() `` macro. (So that it is reliable and portable.)
8080
81- _`.req.assembly.not `: The implementation should not use assembly
82- language. (So that it can be developed in tools like Microsoft Visual
83- Studio that don't support this.)
84-
8581
8682Design
8783------
@@ -91,12 +87,12 @@ and stack must be recorded when the mutator enters the MPS, if there
9187is a possibility that the MPS might need to know the mutator context.
9288
9389_`.sol.entry-points.fragile `: The analysis of which entry points might
94- need to save the context (see `.analysis.entry-points `_ below) is fragile.
95- It might be incorrect now, or become incomplete if we refactor the
96- internals of tracing and polling. As a defence against errors of this
97- form, ``StackScan() `` asserts that the context was saved, but if the
98- client program continues from the assertion, it saves the context
99- anyway and continues.
90+ need to save the context (see `.analysis.entry-points `_ below) is
91+ fragile. It might be incorrect now, or become incomplete if we
92+ refactor the internals of tracing and polling. As a defence against
93+ errors of this form, ``StackScan() `` asserts that the context was
94+ saved, but if the client program continues from the assertion, it
95+ saves the context anyway and continues.
10096
10197_`.sol.registers `: Implementations spill the root registers onto the
10298stack so that they can be scanned there.
@@ -108,69 +104,23 @@ _`.sol.registers.root.justify`: The caller-save registers will have
108104been spilled onto the stack by the time the MPS is entered, so will be
109105scanned by the stack scan.
110106
111- _`.sol.setjmp `: The values in callee-save registers can be found by
112- invoking ``setjmp() ``. This forces any of the caller's callee-save
113- registers into either the ``jmp_buf `` or the current stack frame.
114-
115- _`.sol.setjmp.scan `: Although we might be able to decode the jump
116- buffer in a platform-dependent way, it's hard to guarantee that an
117- uncooperative compiler won't temporarily store a reference in any
118- register or stack location. We must conservatively scan the whole of
119- both.
120-
121- _`.sol.setjmp.justify `: The [C1990 ]_ standard specifies that
122- ``jmp_buf ``:
123-
124- is an array type suitable for holding the information needed to
125- restore a calling environment. The environment of a call to the
126- ``setjmp() `` macro consists of information sufficient for a call
127- to the ``longjmp() `` function to return execution to the correct
128- block and invocation of that block, were it called recursively.
129-
130- We believe that any reasonable implementation of ``setjmp() `` must
131- copy the callee-save registers either into the jump buffer or into the
132- stack frame that invokes it in order to work as described. Otherwise,
133- once the callee-save registers have been overwritten by other function
134- calls, a ``longjmp() `` would result in the callee-save registers
135- having the wrong values. A ``longjmp() `` can come from anywhere, and
136- so the function using ``setjmp() `` can't rely on callee-save registers
137- being saved by callees.
138-
139- _`.sol.stack.hot `: We could decode the frame of the function that
140- invokes ``setjmp() `` from the jump buffer in a platform-specific way,
141- but we can do something simpler (if more hacky) by calling the stub
142- function ``StackHot() `` which takes the address of its argument. So
143- long as this stub function is not inlined into the caller, then on all
144- supported platforms this yields a pointer that is pretty much at the
145- hot end of the frame.
146-
147- _`.sol.stack.hot.noinline `: The reason that ``StackHot() `` must not be
148- inlined is that after inlining, the compiler might place ``stackOut ``
149- at a colder stack address than the ``StackContextStruct ``, causing the
150- latter not to be scanned. See `mail.gdr.2018-07-11.09-48 `_.
151-
152- .. _mail.gdr.2018-07-11.09-48 : https://info.ravenbrook.com/mail/2018/07/11/09-48-49/0/
153-
154- _`.sol.stack.nest `: We can take care of scanning the jump buffer
155- itself by storing it in the same stack frame. That way a scan from the
156- hot end determined by `.sol.stack.hot `_ to the cold end will contain
157- all of the roots.
158-
159- _`.sol.stack.platform `: As of version 1.115, all supported platforms
160- are *full * and *descending * so the implementation in ``StackScan() ``
161- assumes this. New platforms must check this assumption.
162-
163- _`.sol.xc.alternative `: On macOS, we could use ``getcontext() `` from
164- libunwind (see here _), but that produces deprecation warnings and
165- introduces a dependency on that library.
107+ _`.sol.registers.root.i3 `: On IA-32, the callee-save registers are
108+ EBX, ESI, EDI and EBP [Fog ]_.
166109
167- .. _here : https://stackoverflow.com/questions/3592914/
110+ _`.sol.registers.root.i6 `: On x86-64, the callee-save registers are
111+ RBP, RBX, R12, R13, R14, and R15 [Fog ]_.
168112
113+ _`.sol.assembler `: On platforms that support inline assembler, it is
114+ straightforward to copy the callee-save registers into the
115+ ``StackContextStruct `` using assembler instructions.
169116
170- Analysis
171- --------
117+ _`.sol.setjmp `: On platforms that do not support inline assembler (in
118+ particular, Microsoft Visual C/C++) or where we do not know the
119+ callee-save registers (the generic or "ANSI" platform), the
120+ ``StackContextStruct `` contains a ``jmp_buf `` structure, and the
121+ values in callee-save registers are saved by invoking ``setjmp() ``.
172122
173- _ `.analysis.setjmp `: The [C1990 ]_ standard says:
123+ The [C1990 ]_ standard says:
174124
175125 An invocation of the ``setjmp `` macro shall appear only in one of
176126 the following contexts:
@@ -195,6 +145,39 @@ And the [C1999]_ standard adds:
195145 If the invocation appears in any other context, the behavior is
196146 undefined.
197147
148+ _`.sol.stack.hot `: We could decode the ``StackContextStruct `` in a
149+ platform-specific way, but we can do something simpler (if more hacky)
150+ by calling the stub function ``StackHot() `` which takes the address of
151+ its argument. So long as this stub function is not inlined into the
152+ caller, then on all supported platforms this yields a pointer that is
153+ pretty much at the hot end of the stack.
154+
155+ _`.sol.stack.hot.noinline `: The reason that ``StackHot() `` must not be
156+ inlined is that after inlining, the compiler might place ``stackOut ``
157+ at a colder stack address than the ``StackContextStruct ``, causing the
158+ latter not to be scanned. See `mail.gdr.2018-07-11.09-48 `_.
159+
160+ .. _mail.gdr.2018-07-11.09-48 : https://info.ravenbrook.com/mail/2018/07/11/09-48-49/0/
161+
162+ _`.sol.stack.nest `: We can take care of scanning the
163+ ``StackContextStruct `` itself by storing it in the same stack frame.
164+ That way a scan from the hot end determined by `.sol.stack.hot `_ to
165+ the cold end will contain all of the roots.
166+
167+ _`.sol.stack.platform `: As of version 1.115, all supported platforms
168+ are *full * and *descending * so the implementation in ``StackScan() ``
169+ assumes this. New platforms must check this assumption.
170+
171+ _`.sol.xc.alternative `: On macOS, we could use ``getcontext() `` from
172+ libunwind (see here _), but that produces deprecation warnings and
173+ introduces a dependency on that library.
174+
175+ .. _here : https://stackoverflow.com/questions/3592914/
176+
177+
178+ Analysis
179+ --------
180+
198181_`.analysis.entry-points `: Here's a reverse call graph (in the master
199182sources at changelevel 189652) showing which entry points might call
200183``StackScan() `` and so need to record the stack context::
0 commit comments