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