specpdl_ptr->let.kind = SPECPDL_LET;
specpdl_ptr->let.symbol = symbol;
specpdl_ptr->let.old_value = SYMBOL_VAL (sym);
- ++specpdl_ptr;
+ specpdl_ptr->let.saved_value = Qnil;
- if (!sym->constant)
- SET_SYMBOL_VAL (sym, value);
- else
- set_internal (symbol, value, Qnil, 1);
+ grow_specpdl ();
+ do_specbind (sym, specpdl_ptr - 1, value);
break;
case SYMBOL_LOCALIZED:
if (SYMBOL_BLV (sym)->frame_local)
if (NILP (Flocal_variable_p (symbol, Qnil)))
{
specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT;
- ++specpdl_ptr;
+ grow_specpdl ();
- Fset_default (symbol, value);
+ do_specbind (sym, specpdl_ptr - 1, value);
return;
}
}
else
specpdl_ptr->let.kind = SPECPDL_LET;
- specpdl_ptr++;
+ grow_specpdl ();
- set_internal (symbol, value, Qnil, 1);
+ do_specbind (sym, specpdl_ptr - 1, value);
break;
}
default: emacs_abort ();
specpdl_ptr->unwind.kind = SPECPDL_UNWIND;
specpdl_ptr->unwind.func = function;
specpdl_ptr->unwind.arg = arg;
- specpdl_ptr++;
+ grow_specpdl ();
}
+void
+rebind_for_thread_switch (void)
+{
+ union specbinding *bind;
+
+ for (bind = specpdl; bind != specpdl_ptr; ++bind)
+ {
+ if (bind->kind >= SPECPDL_LET)
+ {
+ Lisp_Object value = specpdl_saved_value (bind);
+
+ bind->let.saved_value = Qnil;
+ do_specbind (XSYMBOL (binding_symbol (bind)), bind, value);
+ }
+ }
+}
+
+static void
+do_one_unbind (union specbinding *this_binding, int unwinding)
+{
+ eassert (unwinding || this_binding->kind >= SPECPDL_LET);
+ switch (this_binding->kind)
+ {
+ case SPECPDL_UNWIND:
+ specpdl_func (this_binding) (specpdl_arg (this_binding));
+ break;
+ case SPECPDL_LET:
+ /* If variable has a trivial value (no forwarding), we can
+ just set it. No need to check for constant symbols here,
+ since that was already done by specbind. */
+ if (XSYMBOL (specpdl_symbol (this_binding))->redirect
+ == SYMBOL_PLAINVAL)
+ SET_SYMBOL_VAL (XSYMBOL (specpdl_symbol (this_binding)),
+ specpdl_old_value (this_binding));
+ else
+ /* NOTE: we only ever come here if make_local_foo was used for
+ the first time on this var within this let. */
+ Fset_default (specpdl_symbol (this_binding),
+ specpdl_old_value (this_binding));
+ break;
+ case SPECPDL_BACKTRACE:
+ break;
+ case SPECPDL_LET_LOCAL:
+ case SPECPDL_LET_DEFAULT:
+ { /* If the symbol is a list, it is really (SYMBOL WHERE
+ . CURRENT-BUFFER) where WHERE is either nil, a buffer, or a
+ frame. If WHERE is a buffer or frame, this indicates we
+ bound a variable that had a buffer-local or frame-local
+ binding. WHERE nil means that the variable had the default
+ value when it was bound. CURRENT-BUFFER is the buffer that
+ was current when the variable was bound. */
+ Lisp_Object symbol = specpdl_symbol (this_binding);
+ Lisp_Object where = specpdl_where (this_binding);
+ eassert (BUFFERP (where));
+
+ if (this_binding->kind == SPECPDL_LET_DEFAULT)
+ Fset_default (symbol, specpdl_old_value (this_binding));
+ /* If this was a local binding, reset the value in the appropriate
+ buffer, but only if that buffer's binding still exists. */
+ else if (!NILP (Flocal_variable_p (symbol, where)))
+ set_internal (symbol, specpdl_old_value (this_binding),
+ where, 1);
+ }
+ break;
+ }
+}
+
Lisp_Object
unbind_to (ptrdiff_t count, Lisp_Object value)
{