Merge remote-tracking branch 'origin/master' into for-steve
[sxemacs] / src / opaque.c
1 /* Opaque Lisp objects.
2    Copyright (C) 1993, 1994, 1995 Sun Microsystems, Inc.
3    Copyright (C) 1995, 1996 Ben Wing.
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: Not in FSF. */
22
23 /* Written by Ben Wing, October 1993. */
24
25 /* "Opaque" is used internally to hold keep track of allocated memory
26    so it gets GC'd properly, and to store arbitrary data in places
27    where a Lisp_Object is required and which may get GC'd. (e.g.  as
28    the argument to record_unwind_protect()).  Once created in C,
29    opaque objects cannot be resized.
30
31    OPAQUE OBJECTS SHOULD NEVER ESCAPE TO THE LISP LEVEL.  Some code
32    depends on this.  As such, opaque objects are a generalization
33    of the Qunbound marker.
34  */
35
36 #include <config.h>
37 #include "lisp.h"
38 #include "opaque.h"
39
40 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
41 Lisp_Object Vopaque_ptr_free_list;
42 #endif  /* !BDWGC */
43
44 /* Should never, ever be called. (except by an external debugger) */
45 static void
46 print_opaque(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
47 {
48         const Lisp_Opaque *p = XOPAQUE(obj);
49
50         write_fmt_str(printcharfun,
51                       "#<INTERNAL OBJECT (SXEmacs bug?) (opaque, size=%lu) 0x%lx>",
52                       (long)(p->size), (unsigned long)p);
53 }
54
55 static inline size_t
56 aligned_sizeof_opaque(size_t opaque_size)
57         __attribute__((always_inline));
58 static inline size_t
59 aligned_sizeof_opaque(size_t opaque_size)
60 {
61         return ALIGN_SIZE(offsetof(Lisp_Opaque, data) + opaque_size,
62                           ALIGNOF(max_align_t));
63 }
64
65 static size_t sizeof_opaque(const void *header)
66 {
67         return aligned_sizeof_opaque(((const Lisp_Opaque *)header)->size);
68 }
69
70 /* Return an opaque object of size SIZE.
71    If DATA is OPAQUE_CLEAR, the object's data is memset to '\0' bytes.
72    If DATA is OPAQUE_UNINIT, the object's data is uninitialized.
73    Else the object's data is initialized by copying from DATA. */
74 Lisp_Object
75 make_opaque(const void *data, size_t size)
76 {
77         Lisp_Opaque *p = (Lisp_Opaque *)
78                 alloc_lcrecord(aligned_sizeof_opaque(size), &lrecord_opaque);
79
80         assert(p!=NULL);
81         if(p != NULL) {
82                 p->size = size;
83
84                 if (data == OPAQUE_CLEAR)
85                         memset(p->data, '\0', size);
86                 else if (data == OPAQUE_UNINIT)
87                         DO_NOTHING;
88                 else
89                         memcpy(p->data, data, size);
90
91                 {
92                         Lisp_Object val;
93                         XSETOPAQUE(val, p);
94                         return val;
95                 }
96         }
97         return Qnil;
98 }
99
100 /* This will not work correctly for opaques with subobjects! */
101
102 static int equal_opaque(Lisp_Object obj1, Lisp_Object obj2, int depth)
103 {
104         size_t size;
105         return ((size = XOPAQUE_SIZE(obj1)) == XOPAQUE_SIZE(obj2) &&
106                 !memcmp(XOPAQUE_DATA(obj1), XOPAQUE_DATA(obj2), size));
107 }
108
109 /* This will not work correctly for opaques with subobjects! */
110
111 static unsigned long hash_opaque(Lisp_Object obj, int depth)
112 {
113         if (XOPAQUE_SIZE(obj) == sizeof(unsigned long))
114                 return *((unsigned long *)XOPAQUE_DATA(obj));
115         else
116                 return memory_hash(XOPAQUE_DATA(obj), XOPAQUE_SIZE(obj));
117 }
118
119 static const struct lrecord_description opaque_description[] = {
120         {XD_END}
121 };
122
123 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION("opaque", opaque,
124                                        0, print_opaque, 0,
125                                        equal_opaque, hash_opaque,
126                                        opaque_description,
127                                        sizeof_opaque, Lisp_Opaque);
128
129 /* stuff to handle opaque pointers */
130
131 /* Should never, ever be called. (except by an external debugger) */
132 static void
133 print_opaque_ptr(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
134 {
135         const Lisp_Opaque_Ptr *p = XOPAQUE_PTR(obj);
136
137         write_fmt_string(printcharfun,
138                          "#<INTERNAL OBJECT (SXEmacs bug?) "
139                          "(opaque-ptr, adr=%p) %p>", p->ptr, p);
140 }
141
142 static int equal_opaque_ptr(Lisp_Object obj1, Lisp_Object obj2, int depth)
143 {
144         return (XOPAQUE_PTR(obj1)->ptr == XOPAQUE_PTR(obj2)->ptr);
145 }
146
147 static unsigned long hash_opaque_ptr(Lisp_Object obj, int depth)
148 {
149         return (unsigned long)XOPAQUE_PTR(obj)->ptr;
150 }
151
152 DEFINE_LRECORD_IMPLEMENTATION("opaque-ptr", opaque_ptr,
153                               0, print_opaque_ptr, 0,
154                               equal_opaque_ptr, hash_opaque_ptr, 0,
155                               Lisp_Opaque_Ptr);
156
157 Lisp_Object make_opaque_ptr(void *val)
158 {
159 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
160         Lisp_Object res = wrap_object(
161                 alloc_lcrecord(sizeof(Lisp_Opaque_Ptr), &lrecord_opaque_ptr));
162 #else  /* !BDWGC */
163         Lisp_Object res = allocate_managed_lcrecord(Vopaque_ptr_free_list);
164 #endif  /* BDWGC */
165         /* escrow val */
166         set_opaque_ptr(res, val);
167         return res;
168 }
169
170 /* Be very very careful with this.  Same admonitions as with
171    free_cons() apply. */
172
173 void free_opaque_ptr(Lisp_Object ptr)
174 {
175 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
176         xfree(ptr);
177 #else  /* !BDWGC */
178         free_managed_lcrecord(Vopaque_ptr_free_list, ptr);
179 #endif  /* BDWGC */
180         return;
181 }
182
183 void
184 reinit_opaque_once_early(void)
185 {
186 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
187         Vopaque_ptr_free_list =
188                 make_lcrecord_list(sizeof(Lisp_Opaque_Ptr),
189                                    &lrecord_opaque_ptr);
190         staticpro_nodump(&Vopaque_ptr_free_list);
191 #endif  /* !BDWGC */
192         return;
193 }
194
195 void init_opaque_once_early(void)
196 {
197         INIT_LRECORD_IMPLEMENTATION(opaque);
198         INIT_LRECORD_IMPLEMENTATION(opaque_ptr);
199
200         reinit_opaque_once_early();
201 }