+
+\f
+/* Structure describing a value stack used during byte-code execution
+ in Fbyte_code. */
+
+struct byte_stack
+{
+ /* Program counter. This points into the byte_string below
+ and is relocated when that string is relocated. */
+ const unsigned char *pc;
+
+ /* Top and bottom of stack. The bottom points to an area of memory
+ allocated with alloca in Fbyte_code. */
+ Lisp_Object *top, *bottom;
+
+ /* The string containing the byte-code, and its current address.
+ Storing this here protects it from GC because mark_byte_stack
+ marks it. */
+ Lisp_Object byte_string;
+ const unsigned char *byte_string_start;
+
+ /* The vector of constants used during byte-code execution. Storing
+ this here protects it from GC because mark_byte_stack marks it. */
+ Lisp_Object constants;
+
+ /* Next entry in byte_stack_list. */
+ struct byte_stack *next;
+};
+
+/* A list of currently active byte-code execution value stacks.
+ Fbyte_code adds an entry to the head of this list before it starts
+ processing byte-code, and it removed the entry again when it is
+ done. Signalling an error truncates the list analoguous to
+ gcprolist. */
+
+struct byte_stack *byte_stack_list;
+
+\f
+/* Mark objects on byte_stack_list. Called during GC. */
+
+void
+mark_byte_stack ()
+{
+ struct byte_stack *stack;
+ Lisp_Object *obj;
+
+ for (stack = byte_stack_list; stack; stack = stack->next)
+ {
+ /* If STACK->top is null here, this means there's an opcode in
+ Fbyte_code that wasn't expected to GC, but did. To find out
+ which opcode this is, record the value of `stack', and walk
+ up the stack in a debugger, stopping in frames of Fbyte_code.
+ The culprit is found in the frame of Fbyte_code where the
+ address of its local variable `stack' is equal to the
+ recorded value of `stack' here. */
+ eassert (stack->top);
+
+ for (obj = stack->bottom; obj <= stack->top; ++obj)
+ mark_object (*obj);
+
+ mark_object (stack->byte_string);
+ mark_object (stack->constants);
+ }
+}
+
+
+/* Unmark objects in the stacks on byte_stack_list. Relocate program
+ counters. Called when GC has completed. */
+
+void
+unmark_byte_stack ()
+{
+ struct byte_stack *stack;
+
+ for (stack = byte_stack_list; stack; stack = stack->next)
+ {
+ if (stack->byte_string_start != SDATA (stack->byte_string))
+ {
+ int offset = stack->pc - stack->byte_string_start;
+ stack->byte_string_start = SDATA (stack->byte_string);
+ stack->pc = stack->byte_string_start + offset;
+ }
+ }
+}
+