1 /* -*- mode: c ; c-file-style: "canonware-c-style" -*-
2  ******************************************************************************
3  *
4  * Copyright (C) 1996-2005 Jason Evans <jasone@canonware.com>.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice(s), this list of conditions and the following disclaimer
12  *    unmodified other than the allowable addition of one or more
13  *    copyright notices.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice(s), this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  ******************************************************************************
32  *
33  * Version: Onyx 5.1.2
34  *
35  ******************************************************************************/
36 
37 typedef struct cw_nxo_s cw_nxo_t;
38 typedef struct cw_nxoe_s cw_nxoe_t;
39 
40 /* Declared here to avoid circular header dependencies. */
41 typedef struct cw_nx_s cw_nx_t;
42 typedef void cw_op_t(cw_nxo_t *);
43 typedef void cw_thread_start_t(cw_nxo_t *, cw_op_t *);
44 
45 typedef enum
46 {
47     NXOT_NO,
48     NXOT_ARRAY,
49     NXOT_BOOLEAN,
50 #ifdef CW_OOP
51     NXOT_CLASS,
52 #endif
53 #ifdef CW_THREADS
54     NXOT_CONDITION,
55 #endif
56     NXOT_DICT,
57     NXOT_FILE,
58     NXOT_FINO,
59 #ifdef CW_HANDLE
60     NXOT_HANDLE,
61 #endif
62 #ifdef CW_OOP
63     NXOT_INSTANCE,
64 #endif
65     NXOT_INTEGER,
66     NXOT_MARK,
67 #ifdef CW_THREADS
68     NXOT_MUTEX,
69 #endif
70     NXOT_NAME,
71     NXOT_NULL,
72     NXOT_OPERATOR,
73     NXOT_PMARK,
74 #ifdef CW_REAL
75     NXOT_REAL,
76 #endif
77 #ifdef CW_REGEX
78     NXOT_REGEX,
79     NXOT_REGSUB,
80 #endif
81     NXOT_STACK,
82     NXOT_STRING,
83     NXOT_THREAD
84 #define NXOT_LAST NXOT_THREAD
85 } cw_nxot_t;
86 
87 /* Attribute. */
88 typedef enum
89 {
90     NXOA_LITERAL,
91     NXOA_EXECUTABLE,
92     NXOA_EVALUABLE
93 #ifdef CW_OOP
94     ,
95     NXOA_CALLABLE,
96     NXOA_INVOKABLE,
97     NXOA_FETCHABLE
98 #endif
99 } cw_nxoa_t;
100 
101 typedef int64_t cw_nxoi_t;
102 typedef double cw_nxor_t;
103 
104 /* Main object structure. */
105 struct cw_nxo_s
106 {
107 #ifdef CW_DBG
108     uint32_t magic;
109 #define CW_NXO_MAGIC 0x398754ba
110 #endif
111 
112     /* We can't use bit fields here, since we need explicit knowledge of
113      * structure layout to avoid GC races in nxo_dup() and nxo_p_new().
114      * Therefore, use a single 32 bit variable and do the bit manipulation
115      * manually.
116      *
117      * . : Unused.
118      *
119      * C : Op code.  If this is an operator, and NXN_ZERO < op code <= NXN_LAST,
120      *     op code corresponds to the name of this operator.  This can be used
121      *     to print the operator name.
122      *
123      * A : Attribute (cw_nxoa_t).
124      *
125      * B : Array bound.  True if the bind operator has processed this array.
126      *     This is used to avoid infinite recursion in the bind operator
127      *     when binding recursive procedures.
128      *
129      * T : Type (cw_nxot_t).
130      *
131      * ........ .....CCC CCCCCCCA AABTTTTT
132      * */
133     uint32_t flags;
134 
135     union
136     {
137 	struct
138 	{
139 	    bool val;
140 	} boolean;
141 	struct
142 	{
143 	    cw_nxoi_t i;
144 	} integer;
145 	struct
146 	{
147 	    cw_nxor_t r;
148 	} real;
149 	struct
150 	{
151 	    uint32_t line;
152 	} pmark;
153 	struct
154 	{
155 	    cw_op_t *f;
156 	} oper;
157 	cw_nxoe_t *nxoe;
158     } o;
159 };
160 
161 /* All extended type objects contain a nxoe.  This provides a poor man's
162  * inheritance.  Since onyx's type system is non-extensible, this idiom is
163  * adequate. */
164 struct cw_nxoe_s
165 {
166 #ifdef CW_DBG
167     uint32_t magic;
168 #define CW_NXOE_MAGIC 0x0fa6e798
169 #endif
170 
171     /* Linkage for GC.  All nxoe's are in a single ring, which the GC uses to
172      * implement a Baker's Treadmill collector. */
173     qr(cw_nxoe_t) link;
174 
175     /* Object type.  We store this in nxoe's as well as nxo's, since various
176      * functions access nxoe's directly, rather than going through a referring
177      * nxo. */
178     cw_nxot_t type:5;
179 
180     /* If true, the origin of this object has been recorded. */
181     bool origin:1;
182 
183     /* If true, the string in the key is statically allocated, and should not be
184      * deallocated during destruction. */
185     bool name_static:1;
186 
187     /* The GC toggles this value at each collection in order to maintain
188      * state. */
189     bool color:1;
190 
191     /* True if this object has been registered with the GC.  It is possible for
192      * an object to be reachable by the GC (on a stack, for instance), but not
193      * be registered yet. */
194     bool registered:1;
195 
196 #ifdef CW_THREADS
197     /* If true, accesses to this object are locked.  This applies to arrays,
198      * dictionaries, files, and strings. */
199     bool locking:1;
200 #endif
201 
202     /* If true, this nxoe is a reference to another nxoe. */
203     bool indirect:1;
204 };
205 
206 int32_t
207 nxo_compare(const cw_nxo_t *a_a, const cw_nxo_t *a_b);
208 
209 cw_nxoe_t *
210 nxo_nxoe_get(const cw_nxo_t *a_nxo);
211 
212 #ifdef CW_THREADS
213 bool
214 nxo_ilocked(cw_nxo_t *a_nxo);
215 #endif
216 
217 #ifndef CW_USE_INLINES
218 void
219 nxo_dup(cw_nxo_t *a_to, cw_nxo_t *a_from);
220 
221 cw_nxot_t
222 nxo_type_get(const cw_nxo_t *a_nxo);
223 
224 cw_nxoa_t
225 nxo_attr_get(const cw_nxo_t *a_nxo);
226 
227 void
228 nxo_attr_set(cw_nxo_t *a_nxo, cw_nxoa_t a_attr);
229 
230 void
231 nxo_p_new(cw_nxo_t *a_nxo, cw_nxot_t a_type);
232 #endif
233 
234 #if (defined(CW_USE_INLINES) || defined(CW_NXO_C_))
235 CW_INLINE void
nxo_dup(cw_nxo_t * a_to,cw_nxo_t * a_from)236 nxo_dup(cw_nxo_t *a_to, cw_nxo_t *a_from)
237 {
238     cw_check_ptr(a_to);
239     cw_dassert(a_to->magic == CW_NXO_MAGIC);
240 
241     cw_check_ptr(a_from);
242     cw_dassert(a_from->magic == CW_NXO_MAGIC);
243 
244     /* The order of operations is important in order to avoid a GC race. */
245     a_to->flags = 0;
246     mb_write();
247     a_to->o = a_from->o;
248     mb_write();
249     a_to->flags = a_from->flags;
250 }
251 
252 CW_INLINE cw_nxot_t
nxo_type_get(const cw_nxo_t * a_nxo)253 nxo_type_get(const cw_nxo_t *a_nxo)
254 {
255     cw_check_ptr(a_nxo);
256     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
257 
258     return ((cw_nxot_t) (a_nxo->flags & 0x1f));
259 }
260 
261 CW_INLINE cw_nxoa_t
nxo_attr_get(const cw_nxo_t * a_nxo)262 nxo_attr_get(const cw_nxo_t *a_nxo)
263 {
264     cw_check_ptr(a_nxo);
265     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
266 
267     return ((cw_nxoa_t) (((a_nxo)->flags >> 6) & 7));
268 }
269 
270 CW_INLINE void
nxo_attr_set(cw_nxo_t * a_nxo,cw_nxoa_t a_attr)271 nxo_attr_set(cw_nxo_t *a_nxo, cw_nxoa_t a_attr)
272 {
273     cw_check_ptr(a_nxo);
274     cw_dassert(a_nxo->magic == CW_NXO_MAGIC);
275 
276     a_nxo->flags = (a_nxo->flags & 0xfffffe3f) | (a_attr << 6);
277 }
278 
279 /* Private, but various object constructor macros need its definition. */
280 CW_INLINE void
nxo_p_new(cw_nxo_t * a_nxo,cw_nxot_t a_type)281 nxo_p_new(cw_nxo_t *a_nxo, cw_nxot_t a_type)
282 {
283     /* The order of operations is important in order to avoid a GC race. */
284     a_nxo->flags = 0;
285 #ifdef CW_DBG
286     a_nxo->magic = CW_NXO_MAGIC;
287 #endif
288 
289     /* o.integer.i is assumed to be at least as big as all the other fields in
290      * the union. */
291     a_nxo->o.integer.i = 0;
292     mb_write();
293     a_nxo->flags = a_type;
294 }
295 #endif /* (defined(CW_USE_INLINES) || defined(CW_NXO_C_)) */
296