emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Why isn't the string returned by symbol-name read-only?


From: alin.s
Subject: Re: Why isn't the string returned by symbol-name read-only?
Date: Sat, 23 Jan 2010 16:33:18 -0800 (PST)


This is an interesting question, and this is why I answer you.

In order to understand and use emacs at its real power you must learn
lisp. I recommend you to read and solve all the exercises from a book
like the original LISP Manual of McCarthy, or more recent course.

Emacs is a beautiful implementation of a Lisp system, and this is why
we love him.

To answer your question, first of all, try to compile thsese simple
programs:

main(){unix[(const char *)"emacs"]++;}
main(){unix[(const char[]){[0]="emacs"}]++;}

In the first case the constant "emacs" is put into .data, and in the
second into .rodata.

You will see that you get the same error.

Now let us see what happens when you declare a function CAR:
(extracted from data.c)



/* Extract and set components of lists */

DEFUN ("car", Fcar, Scar, 1, 1, 0,
       doc: /* Return the car of LIST.  If arg is nil, return nil.
Error if arg is not nil and not a cons cell.  See also `car-safe'.

See Info node `(elisp)Cons Cells' for a discussion of related basic
Lisp concepts such as car, cdr, cons cell and list.  */)
     (list)
     register Lisp_Object list;
{
  return CAR (list);
}

To see in detail what that does, you can expand it using gcc -E: you
do (rm data.o && VERBOSE=1; make):


gcc -E -D_BSD_SOURCE   -Demacs -DHAVE_CONFIG_H  -I. -I/emacs/src .......... 
data.c

You will get:


Lisp_Object Fcar (Lisp_Object) ; struct Lisp_Subr __attribute__
((__aligned__ (1 << 3))) Scar = { PVEC_SUBR | (sizeof (struct Lisp_Subr) /
sizeof (int)), Fcar, 1, 1, "car", 0, 0}; Lisp_Object Fcar

     (list)
     register Lisp_Object list;
{
   <definition of CAR>
}

You see that before to define the function Fcar, it defines the structure
Scar:

Lisp_Object Fcar (Lisp_Object) ; struct Lisp_Subr __attribute__
((__aligned__ (1 << 3))) Scar = { PVEC_SUBR | (sizeof (struct Lisp_Subr) /
sizeof (int)), Fcar, 1, 1, "car", 0, 0}; 

Now let us see how this structure looks like:


struct Lisp_Subr
  {
    EMACS_UINT size;
    Lisp_Object (*function) ();
    short min_args, max_args;
    const char *symbol_name;
    char *intspec;
    char *doc;
  };

You see that the 4th parameter is const char *symbol_name  = "car".

So emacs tries to define the names of the symbols defined with DEFUN
into a zone of memory that the compiler marks as read-only. That means
that the lisp evaluator must know that it is not allowed to change
that zone.

Let us see further what happens:

By definition of emacs lisp system , the lisp symbols have to be
interned into the function syms_of_<file>. In this case, inside
syms_of_data (), defsubr (&Scar); Inside this function,


void
defsubr (sname)
     struct Lisp_Subr *sname;
{
  Lisp_Object sym;
  sym = intern_c_string (sname->symbol_name);
  XSETPVECTYPE (sname, PVEC_SUBR);
  XSETSUBR (XSYMBOL (sym)->function, sname);
}

Inside intern_c_string (const char *str), it is checked whether the
symbol with the name STR is already interned inside the main obarray,
and if not, it is internet using the final call. The first call of
intern_c_string happens exactly from defsubr statement, and this call
forces the symbol to be interned using make_pure_c_string. Next calls
of intern_c_string(the same string) happens from READ lisp function
(see read1()), and they already find the symbol interned.


Lisp_Object
intern_c_string (const char *str)
{
............
  return Fintern (make_pure_c_string (str), obarray);
}

return Fintern (make_pure_c_string (str), obarray);

Here it is the point:

make_pure_c_string (str)


Lisp_Object
make_pure_c_string (const char *data)
{
  Lisp_Object string;
  struct Lisp_String *s;
  int nchars = strlen (data);

  s = (struct Lisp_String *) pure_alloc (sizeof *s, Lisp_String);
  s->size = nchars;
  s->size_byte = -1;
  s->data = (unsigned char *) data;
  s->intervals = NULL_INTERVAL;
  XSETSTRING (string, s);
  return string;
}

Now the function pure_alloc:


/* Allocate room for SIZE bytes from pure Lisp storage and return a
   pointer to it.  TYPE is the Lisp type for which the memory is
   allocated.  TYPE < 0 means it's not used for a Lisp object.  */


Now we see the second function that you use : aset. We look at its
definition, and see:




DEFUN ("aset", Faset, Saset, 3, 3, 0,
       doc: /* Store into the element of ARRAY at index IDX the value
NEWELT.
Return NEWELT.  ARRAY may be a vector, a string, a char-table or a
bool-vector.  IDX starts at 0.  */)
     (array, idx, newelt)
     register Lisp_Object array;
     Lisp_Object idx, newelt;
{
....

CHECK_IMPURE (array);

}

The definition of CHECK_IMPURE is :

/* Signal an error if OBJ is pure.  */
#define CHECK_IMPURE(obj) \
  { if (PURE_P (obj))     \
      pure_write_error (); }

and finally we get the result of the problem:


void
pure_write_error ()
{
  error ("Attempt to modify read-only object");
}


Here it is why the error is generated in the second case and not in
the first case.

In the first case, the symbol 'FOO is interned inside obarray during
the reading operation, while in the second case the symbol is interned
during the initialization of emacs, and this is different.

Note hoever in , that inside read1(), a symbol is interned inside pure
space if you set the variable Vpurify_flag accordingly. You can set
this variable using the evaluator (its name is pure, but its value is
not in pure storage, so the value can be changed ;) ).

I do not know why the idea of pure storage was introduced in emacs;
maybe in order to connect it to the idea of constant of C code, but I
am not absolutely sure. I have not met the idea of pure storage into a
standard course of Lisp. I do not know why Richard did want to insert
this concept.

I hope that my long message be useful. Sorry for any king of error
that mingled around.



Daniel Colascione-3 wrote:
> 
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Consider
> 
> (let ((name (symbol-name 'foo)))
>   (aset name 0 ?x)
>   (cons name (symbol-name 'foo)))
> 
> That yields ("xoo" . " xoo")
> 
> Now try
> 
> 
> (let ((name (symbol-name 'car)))
>   (aset name 0 ?x)
>   (cons name (symbol-name 'car)))
> 
> That returns in an error when you try to evaluate it. The object
> returned by (symbol-name 'car) must have some read-only bit set.
> 
> Why isn't that bit set for *all* symbol names?
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.10 (Darwin)
> 
> iEYEARECAAYFAktbYlAACgkQ17c2LVA10VsTLQCcCjDdAU9NSvOAVEMmVHfyhXxp
> PRMAmgPmovQuhwTUwKGIFvd5giGQyXy4
> =6FHg
> -----END PGP SIGNATURE-----
> 
> 
> 
> 

-- 
View this message in context: 
http://old.nabble.com/Why-isn%27t-the-string-returned-by-symbol-name-read-only--tp27289855p27291323.html
Sent from the Emacs - Dev mailing list archive at Nabble.com.





reply via email to

[Prev in Thread] Current Thread [Next in Thread]