diff src/buffer.c @ 107984:bef5d1738c0b

Make variable forwarding explicit rather the using special values. Basically, this makes the structure of buffer-local values and object forwarding explicit in the type of Lisp_Symbols rather than use special Lisp_Objects for that. This tends to lead to slightly more verbose code, but is more C-like, simpler, and makes it easier to make sure we handled all cases, among other things by letting the compiler help us check it. * lisp.h (enum Lisp_Misc_Type, union Lisp_Misc): Removing forwarding objects. (enum Lisp_Fwd_Type, enum symbol_redirect, union Lisp_Fwd): New types. (struct Lisp_Symbol): Make the various forms of variable-forwarding explicit rather than hiding them inside Lisp_Object "values". (XFWDTYPE): New macro. (XINTFWD, XBOOLFWD, XOBJFWD, XKBOARD_OBJFWD): Redefine. (XBUFFER_LOCAL_VALUE): Remove. (SYMBOL_VAL, SYMBOL_ALIAS, SYMBOL_BLV, SYMBOL_FWD, SET_SYMBOL_VAL) (SET_SYMBOL_ALIAS, SET_SYMBOL_BLV, SET_SYMBOL_FWD): New macros. (SYMBOL_VALUE, SET_SYMBOL_VALUE): Remove. (struct Lisp_Intfwd, struct Lisp_Boolfwd, struct Lisp_Objfwd) (struct Lisp_Buffer_Objfwd, struct Lisp_Kboard_Objfwd): Remove the Lisp_Misc_* header. (struct Lisp_Buffer_Local_Value): Redefine. (BLV_FOUND, SET_BLV_FOUND, BLV_VALUE, SET_BLV_VALUE): New macros. (struct Lisp_Misc_Any): Add filler to get the right size. (struct Lisp_Free): Use struct Lisp_Misc_Any rather than struct Lisp_Intfwd. (DEFVAR_LISP, DEFVAR_LISP_NOPRO, DEFVAR_BOOL, DEFVAR_INT) (DEFVAR_KBOARD): Allocate a forwarding object. * data.c (do_blv_forwarding, store_blv_forwarding): New macros. (let_shadows_global_binding_p): New function. (union Lisp_Val_Fwd): New type. (make_blv): New function. (swap_in_symval_forwarding, indirect_variable, do_symval_forwarding) (store_symval_forwarding, swap_in_global_binding, Fboundp) (swap_in_symval_forwarding, find_symbol_value, Fset) (let_shadows_buffer_binding_p, set_internal, default_value) (Fset_default, Fmake_variable_buffer_local, Fmake_local_variable) (Fkill_local_variable, Fmake_variable_frame_local) (Flocal_variable_p, Flocal_variable_if_set_p) (Fvariable_binding_locus): * xdisp.c (select_frame_for_redisplay): * lread.c (Fintern, Funintern, init_obarray, defvar_int) (defvar_bool, defvar_lisp_nopro, defvar_lisp, defvar_kboard): * frame.c (store_frame_param): * eval.c (Fdefvaralias, Fuser_variable_p, specbind, unbind_to): * bytecode.c (Fbyte_code) <varref, varset>: Adapt to the new symbol value structure. * buffer.c (PER_BUFFER_SYMBOL): Move from buffer.h. (clone_per_buffer_values): Only adjust markers into the current buffer. (reset_buffer_local_variables): PER_BUFFER_IDX is never -2. (Fbuffer_local_value, set_buffer_internal_1) (swap_out_buffer_local_variables): Adapt to the new symbol value structure. (DEFVAR_PER_BUFFER): Allocate a Lisp_Buffer_Objfwd object. (defvar_per_buffer): Take a new arg for the fwd object. (buffer_lisp_local_variables): Return a proper alist (different fix for bug#4138). * alloc.c (Fmake_symbol): Use SET_SYMBOL_VAL. (Fgarbage_collect): Don't handle buffer_defaults specially. (mark_object): Handle new symbol value structure rather than the old special Lisp_Misc_* objects. (gc_sweep) <symbols>: Free also the buffer-local-value objects. * term.c (set_tty_color_mode): * bidi.c (bidi_initialize): Don't access the ->value field directly. * buffer.h (PER_BUFFER_VAR_OFFSET): Don't bother with a buffer_local_flags. * print.c (print_object): Get rid of impossible forwarding objects.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Mon, 19 Apr 2010 21:50:52 -0400
parents 688679bd79f5
children 4b71850034e6
line wrap: on
line diff
--- a/src/buffer.c	Mon Apr 19 14:33:11 2010 -0400
+++ b/src/buffer.c	Mon Apr 19 21:50:52 2010 -0400
@@ -78,9 +78,6 @@
    be a DEFVAR_PER_BUFFER for the slot, there is no default value for it;
    and the corresponding slot in buffer_defaults is not used.
 
-   If a slot is -2, then there is no DEFVAR_PER_BUFFER for it,
-   but there is a default value which is copied into each buffer.
-
    If a slot in this structure corresponding to a DEFVAR_PER_BUFFER is
    zero, that is a bug */
 
@@ -94,6 +91,12 @@
 /* A Lisp_Object pointer to the above, used for staticpro */
 static Lisp_Object Vbuffer_local_symbols;
 
+/* Return the symbol of the per-buffer variable at offset OFFSET in
+   the buffer structure.  */
+
+#define PER_BUFFER_SYMBOL(OFFSET) \
+      (*(Lisp_Object *)((OFFSET) + (char *) &buffer_local_symbols))
+
 /* Flags indicating which built-in buffer-local variables
    are permanent locals.  */
 static char buffer_permanent_local_flags[MAX_PER_BUFFER_VARS];
@@ -507,7 +510,7 @@
 	continue;
 
       obj = PER_BUFFER_VALUE (from, offset);
-      if (MARKERP (obj))
+      if (MARKERP (obj) && XMARKER (obj)->buffer == from)
 	{
 	  struct Lisp_Marker *m = XMARKER (obj);
 	  obj = Fmake_marker ();
@@ -770,9 +773,7 @@
     {
       Lisp_Object tmp, prop, last = Qnil;
       for (tmp = b->local_var_alist; CONSP (tmp); tmp = XCDR (tmp))
-	if (CONSP (XCAR (tmp))
-	    && SYMBOLP (XCAR (XCAR (tmp)))
-	    && !NILP (prop = Fget (XCAR (XCAR (tmp)), Qpermanent_local)))
+	if (!NILP (prop = Fget (XCAR (XCAR (tmp)), Qpermanent_local)))
 	  {
 	    /* If permanent-local, keep it.  */
 	    last = tmp;
@@ -822,9 +823,7 @@
       int idx = PER_BUFFER_IDX (offset);
       if ((idx > 0
 	   && (permanent_too
-	       || buffer_permanent_local_flags[idx] == 0))
-	  /* Is -2 used anywhere?  */
-	  || idx == -2)
+	       || buffer_permanent_local_flags[idx] == 0)))
 	PER_BUFFER_VALUE (b, offset) = PER_BUFFER_DEFAULT (offset);
     }
 }
@@ -938,59 +937,49 @@
   CHECK_SYMBOL (variable);
   CHECK_BUFFER (buffer);
   buf = XBUFFER (buffer);
-
-  sym = indirect_variable (XSYMBOL (variable));
-  XSETSYMBOL (variable, sym);
-
-  /* Look in local_var_list */
-  result = Fassoc (variable, buf->local_var_alist);
-  if (NILP (result))
+  sym = XSYMBOL (variable);
+
+ start:
+  switch (sym->redirect)
     {
-      int offset, idx;
-      int found = 0;
-
-      /* Look in special slots */
-      /* buffer-local Lisp variables start at `undo_list',
-	 tho only the ones from `name' on are GC'd normally.  */
-      for (offset = PER_BUFFER_VAR_OFFSET (undo_list);
-	   offset < sizeof (struct buffer);
-	   /* sizeof EMACS_INT == sizeof Lisp_Object */
-	   offset += (sizeof (EMACS_INT)))
-	{
-	  idx = PER_BUFFER_IDX (offset);
-	  if ((idx == -1 || PER_BUFFER_VALUE_P (buf, idx))
-	      && SYMBOLP (PER_BUFFER_SYMBOL (offset))
-	      && EQ (PER_BUFFER_SYMBOL (offset), variable))
-	    {
-	      result = PER_BUFFER_VALUE (buf, offset);
-	      found = 1;
-	      break;
-	    }
-	}
-
-      if (!found)
-	result = Fdefault_value (variable);
-    }
-  else
-    {
-      Lisp_Object valcontents;
-      Lisp_Object current_alist_element;
-
-      /* What binding is loaded right now?  */
-      valcontents = sym->value;
-      current_alist_element
-	= XCAR (XBUFFER_LOCAL_VALUE (valcontents)->cdr);
-
-      /* The value of the currently loaded binding is not
-	 stored in it, but rather in the realvalue slot.
-	 Store that value into the binding it belongs to
-	 in case that is the one we are about to use.  */
-
-      Fsetcdr (current_alist_element,
-	       do_symval_forwarding (XBUFFER_LOCAL_VALUE (valcontents)->realvalue));
-
-      /* Now get the (perhaps updated) value out of the binding.  */
-      result = XCDR (result);
+    case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
+    case SYMBOL_PLAINVAL: result = SYMBOL_VAL (sym); break;
+    case SYMBOL_LOCALIZED:
+      { /* Look in local_var_alist.  */
+	struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (sym);
+	XSETSYMBOL (variable, sym); /* Update In case of aliasing.  */
+	result = Fassoc (variable, buf->local_var_alist);
+	if (!NILP (result))
+	  {
+	    if (blv->fwd)
+	      { /* What binding is loaded right now?  */
+		Lisp_Object current_alist_element = blv->valcell;
+
+		/* The value of the currently loaded binding is not
+		   stored in it, but rather in the realvalue slot.
+		   Store that value into the binding it belongs to
+		   in case that is the one we are about to use.  */
+
+		XSETCDR (current_alist_element,
+			 do_symval_forwarding (blv->fwd));
+	      }
+	    /* Now get the (perhaps updated) value out of the binding.  */
+	    result = XCDR (result);
+	  }
+	else
+	  result = Fdefault_value (variable);
+	break;
+      }
+    case SYMBOL_FORWARDED:
+      {
+	union Lisp_Fwd *fwd = SYMBOL_FWD (sym);
+	if (BUFFER_OBJFWDP (fwd))
+	  result = PER_BUFFER_VALUE (buf, XBUFFER_OBJFWD (fwd)->offset);
+	else
+	  result = Fdefault_value (variable);
+	break;
+      }
+    default: abort ();
     }
 
   if (!EQ (result, Qunbound))
@@ -1025,12 +1014,7 @@
       if (buf != current_buffer)
 	val = XCDR (elt);
 
-      /* If symbol is unbound, put just the symbol in the list.  */
-      if (EQ (val, Qunbound))
-	result = Fcons (XCAR (elt), result);
-      /* Otherwise, put (symbol . value) in the list.  */
-      else
-	result = Fcons (Fcons (XCAR (elt), val), result);
+      result = Fcons (Fcons (XCAR (elt), val), result);
     }
 
   return result;
@@ -1862,8 +1846,7 @@
      register struct buffer *b;
 {
   register struct buffer *old_buf;
-  register Lisp_Object tail, valcontents;
-  Lisp_Object tem;
+  register Lisp_Object tail;
 
 #ifdef USE_MMAP_FOR_BUFFERS
   if (b->text->beg == NULL)
@@ -1935,34 +1918,21 @@
   /* Look down buffer's list of local Lisp variables
      to find and update any that forward into C variables. */
 
-  for (tail = b->local_var_alist; CONSP (tail); tail = XCDR (tail))
+  do
     {
-      if (CONSP (XCAR (tail))
-	  && SYMBOLP (XCAR (XCAR (tail)))
-	  && (valcontents = SYMBOL_VALUE (XCAR (XCAR (tail))),
-	      (BUFFER_LOCAL_VALUEP (valcontents)))
-	  && (tem = XBUFFER_LOCAL_VALUE (valcontents)->realvalue,
-	      (BOOLFWDP (tem) || INTFWDP (tem) || OBJFWDP (tem))))
-	/* Just reference the variable to cause it to become set for
-	   this buffer.  */
-	Fsymbol_value (XCAR (XCAR (tail)));
+      for (tail = b->local_var_alist; CONSP (tail); tail = XCDR (tail))
+	{
+	  Lisp_Object var = XCAR (XCAR (tail));
+	  struct Lisp_Symbol *sym = XSYMBOL (var);
+	  if (sym->redirect == SYMBOL_LOCALIZED /* Just to be sure.  */
+	      && SYMBOL_BLV (sym)->fwd)
+	    /* Just reference the variable
+	       to cause it to become set for this buffer.  */
+	    Fsymbol_value (var);
+	}
     }
-
   /* Do the same with any others that were local to the previous buffer */
-
-  if (old_buf)
-    for (tail = old_buf->local_var_alist; CONSP (tail); tail = XCDR (tail))
-      {
-	if (CONSP (tail)
-	    && SYMBOLP (XCAR (XCAR (tail)))
-	    && (valcontents = SYMBOL_VALUE (XCAR (XCAR (tail))),
-		(BUFFER_LOCAL_VALUEP (valcontents)))
-	    && (tem = XBUFFER_LOCAL_VALUE (valcontents)->realvalue,
-		(BOOLFWDP (tem) || INTFWDP (tem) || OBJFWDP (tem))))
-	  /* Just reference the variable to cause it to become set for
-	     this buffer.  */
-	  Fsymbol_value (XCAR (XCAR (tail)));
-      }
+  while (b != old_buf && (b = old_buf, b));
 }
 
 /* Switch to buffer B temporarily for redisplay purposes.
@@ -2677,23 +2647,22 @@
 swap_out_buffer_local_variables (b)
      struct buffer *b;
 {
-  Lisp_Object oalist, alist, sym, buffer;
+  Lisp_Object oalist, alist, buffer;
 
   XSETBUFFER (buffer, b);
   oalist = b->local_var_alist;
 
   for (alist = oalist; CONSP (alist); alist = XCDR (alist))
     {
-      if (CONSP (XCAR (alist))
-	  && (sym = XCAR (XCAR (alist)), SYMBOLP (sym))
-	  /* Need not do anything if some other buffer's binding is
-	     now encached.  */
-	  && EQ (XBUFFER_LOCAL_VALUE (SYMBOL_VALUE (sym))->buffer,
-		 buffer))
+      Lisp_Object sym = XCAR (XCAR (alist));
+      eassert (XSYMBOL (sym)->redirect == SYMBOL_LOCALIZED);
+      /* Need not do anything if some other buffer's binding is
+	 now encached.  */
+      if (EQ (SYMBOL_BLV (XSYMBOL (sym))->where, buffer))
 	{
 	  /* Symbol is set up for this buffer's old local value:
 	     swap it out!  */
-	  swap_in_global_binding (sym);
+	  swap_in_global_binding (XSYMBOL (sym));
 	}
     }
 }
@@ -5162,7 +5131,9 @@
   /* Make sure all markable slots in buffer_defaults
      are initialized reasonably, so mark_buffer won't choke.  */
   reset_buffer (&buffer_defaults);
+  eassert (EQ (buffer_defaults.name, make_number (0)));
   reset_buffer_local_variables (&buffer_defaults, 1);
+  eassert (EQ (buffer_local_symbols.name, make_number (0)));
   reset_buffer (&buffer_local_symbols);
   reset_buffer_local_variables (&buffer_local_symbols, 1);
   /* Prevent GC from getting confused.  */
@@ -5421,33 +5392,41 @@
    in the buffer that is current now. */
 
 /* TYPE is nil for a general Lisp variable.
-   An integer specifies a type; then only LIsp values
+   An integer specifies a type; then only Lisp values
    with that type code are allowed (except that nil is allowed too).
-   LNAME is the LIsp-level variable name.
+   LNAME is the Lisp-level variable name.
    VNAME is the name of the buffer slot.
    DOC is a dummy where you write the doc string as a comment.  */
-#define DEFVAR_PER_BUFFER(lname, vname, type, doc)  \
- defvar_per_buffer (lname, vname, type, 0)
+#define DEFVAR_PER_BUFFER(lname, vname, type, doc)			\
+  do {									\
+    static struct Lisp_Buffer_Objfwd bo_fwd;				\
+    defvar_per_buffer (&bo_fwd, lname, vname, type, 0);			\
+  } while (0)
 
 static void
-defvar_per_buffer (namestring, address, type, doc)
+defvar_per_buffer (bo_fwd, namestring, address, type, doc)
+     struct Lisp_Buffer_Objfwd *bo_fwd;
      char *namestring;
      Lisp_Object *address;
      Lisp_Object type;
      char *doc;
 {
-  Lisp_Object sym, val;
+  struct Lisp_Symbol *sym;
   int offset;
 
-  sym = intern (namestring);
-  val = allocate_misc ();
+  sym = XSYMBOL (intern (namestring));
   offset = (char *)address - (char *)current_buffer;
 
-  XMISCTYPE (val) = Lisp_Misc_Buffer_Objfwd;
-  XBUFFER_OBJFWD (val)->offset = offset;
-  XBUFFER_OBJFWD (val)->slottype = type;
-  SET_SYMBOL_VALUE (sym, val);
-  PER_BUFFER_SYMBOL (offset) = sym;
+  bo_fwd->type = Lisp_Fwd_Buffer_Obj;
+  bo_fwd->offset = offset;
+  bo_fwd->slottype = type;
+  sym->redirect = SYMBOL_FORWARDED;
+  {
+    /* I tried to do the job without a cast, but it seems impossible.
+       union Lisp_Fwd *fwd; &(fwd->u_buffer_objfwd) = bo_fwd;  */
+    SET_SYMBOL_FWD (sym, (union Lisp_Fwd *)bo_fwd);
+  }
+  XSETSYMBOL (PER_BUFFER_SYMBOL (offset), sym);
 
   if (PER_BUFFER_IDX (offset) == 0)
     /* Did a DEFVAR_PER_BUFFER without initializing the corresponding