996
|
1 /* -*- mode: C; coding: utf-8; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
|
|
2 *
|
|
3 * cfunge - A standard-conforming Befunge93/98/109 interpreter in C.
|
|
4 * Copyright (C) 2008-2009 Arvid Norlander <anmaster AT tele2 DOT se>
|
|
5 *
|
|
6 * This program is free software: you can redistribute it and/or modify
|
|
7 * it under the terms of the GNU General Public License as published by
|
|
8 * the Free Software Foundation, either version 3 of the License, or
|
|
9 * (at the proxy's option) any later version. Arvid Norlander is a
|
|
10 * proxy who can decide which future versions of the GNU General Public
|
|
11 * License can be used.
|
|
12 *
|
|
13 * This program is distributed in the hope that it will be useful,
|
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16 * GNU General Public License for more details.
|
|
17 *
|
|
18 * You should have received a copy of the GNU General Public License
|
|
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
20 */
|
|
21
|
|
22 #include "global.h"
|
|
23 #include "ip.h"
|
|
24
|
|
25 #include "diagnostic.h"
|
|
26 #include "interpreter.h"
|
|
27 #include "settings.h"
|
|
28 #include "stack.h"
|
|
29 #include "vector.h"
|
|
30
|
|
31 #include "fingerprints/manager.h"
|
|
32 #include "funge-space/funge-space.h"
|
|
33
|
|
34 #include <assert.h>
|
|
35 #include <string.h> /* memcpy */
|
|
36
|
|
37 /// For concurrent funge: how many new IPs to allocate in one go?
|
|
38 #define ALLOCCHUNKSIZE 1
|
|
39
|
|
40 FUNGE_ATTR_FAST FUNGE_ATTR_NONNULL FUNGE_ATTR_WARN_UNUSED
|
|
41 static inline bool ip_create_in_place(instructionPointer *me)
|
|
42 {
|
|
43 assert(me != NULL);
|
|
44 me->position.x = 0;
|
|
45 me->position.y = 0;
|
|
46 me->delta.x = 1;
|
|
47 me->delta.y = 0;
|
|
48 me->storageOffset.x = 0;
|
|
49 me->storageOffset.y = 0;
|
|
50 me->mode = ipmCODE;
|
|
51 me->needMove = true;
|
|
52 me->stringLastWasSpace = false;
|
|
53 me->fingerSUBRisRelative = false;
|
|
54 me->stackstack = stackstack_create();
|
|
55 if (FUNGE_UNLIKELY(!me->stackstack))
|
|
56 return false;
|
|
57 me->stack = me->stackstack->stacks[me->stackstack->current];
|
|
58 me->ID = 0;
|
|
59 // Zero the opcode stacks if needed.
|
|
60 if (FUNGE_LIKELY(!setting_disable_fingerprints)) {
|
|
61 memset(me->fingerOpcodes, 0, sizeof(fungeOpcodeStack) * FINGEROPCODECOUNT);
|
|
62 }
|
|
63 me->fingerHRTItimestamp = NULL;
|
|
64 return true;
|
|
65 }
|
|
66
|
|
67 #ifndef CONCURRENT_FUNGE
|
|
68 FUNGE_ATTR_FAST instructionPointer * ip_create(void)
|
|
69 {
|
|
70 instructionPointer * tmp = (instructionPointer*)cf_malloc(sizeof(instructionPointer));
|
|
71 if (FUNGE_UNLIKELY(!tmp))
|
|
72 return NULL;
|
|
73 if (FUNGE_UNLIKELY(!ip_create_in_place(tmp))) {
|
|
74 cf_free(tmp);
|
|
75 return NULL;
|
|
76 }
|
|
77 return tmp;
|
|
78 }
|
|
79 #endif
|
|
80
|
|
81 #ifdef CONCURRENT_FUNGE
|
|
82 FUNGE_ATTR_FAST FUNGE_ATTR_NONNULL FUNGE_ATTR_WARN_UNUSED
|
|
83 static inline bool ip_duplicate_in_place(const instructionPointer * restrict old, instructionPointer * restrict new)
|
|
84 {
|
|
85 assert(old != NULL);
|
|
86 assert(new != NULL);
|
|
87 memcpy(new, old, sizeof(instructionPointer));
|
|
88
|
|
89 new->stackstack = stackstack_duplicate(old->stackstack);
|
|
90 if (FUNGE_UNLIKELY(!new->stackstack))
|
|
91 return false;
|
|
92
|
|
93 new->stack = new->stackstack->stacks[new->stackstack->current];
|
|
94 if (FUNGE_LIKELY(!setting_disable_fingerprints)) {
|
|
95 manager_duplicate(old, new);
|
|
96 }
|
|
97 new->fingerHRTItimestamp = NULL;
|
|
98 return true;
|
|
99 }
|
|
100 #endif
|
|
101
|
|
102 #if defined(CONCURRENT_FUNGE) || !defined(NDEBUG)
|
|
103 FUNGE_ATTR_FAST static inline void ip_free_resources(instructionPointer * ip)
|
|
104 {
|
|
105 if (FUNGE_UNLIKELY(!ip))
|
|
106 return;
|
|
107 if (FUNGE_LIKELY(ip->stackstack)) {
|
|
108 stackstack_free(ip->stackstack);
|
|
109 ip->stackstack = NULL;
|
|
110 }
|
|
111 ip->stack = NULL;
|
|
112 if (FUNGE_LIKELY(!setting_disable_fingerprints)) {
|
|
113 manager_free(ip);
|
|
114 }
|
|
115 if (ip->fingerHRTItimestamp) {
|
|
116 cf_free(ip->fingerHRTItimestamp);
|
|
117 ip->fingerHRTItimestamp = NULL;
|
|
118 }
|
|
119 }
|
|
120 #endif
|
|
121
|
|
122 #if !defined(CONCURRENT_FUNGE) && !defined(NDEBUG)
|
|
123 FUNGE_ATTR_FAST void ip_free(instructionPointer * restrict ip)
|
|
124 {
|
|
125 if (!ip)
|
|
126 return;
|
|
127 ip_free_resources(ip);
|
|
128 cf_free(ip);
|
|
129 }
|
|
130 #endif
|
|
131
|
|
132 FUNGE_ATTR_FAST inline void ip_set_delta(instructionPointer * restrict ip, const funge_vector * restrict delta)
|
|
133 {
|
|
134 assert(ip != NULL);
|
|
135 assert(delta != NULL);
|
|
136 ip->delta.x = delta->x;
|
|
137 ip->delta.y = delta->y;
|
|
138 }
|
|
139
|
|
140 FUNGE_ATTR_FAST inline void ip_set_position(instructionPointer * restrict ip, const funge_vector * restrict position)
|
|
141 {
|
|
142 assert(ip != NULL);
|
|
143 assert(position != NULL);
|
|
144 ip->position.x = position->x;
|
|
145 ip->position.y = position->y;
|
|
146 fungespace_wrap(&ip->position, &ip->delta);
|
|
147 }
|
|
148
|
|
149
|
|
150 /***********
|
|
151 * IP list *
|
|
152 ***********/
|
|
153
|
|
154 #ifdef CONCURRENT_FUNGE
|
|
155 FUNGE_ATTR_FAST ipList* iplist_create(void)
|
|
156 {
|
|
157 ipList * tmp = (ipList*)cf_malloc(sizeof(ipList) + sizeof(instructionPointer[ALLOCCHUNKSIZE]));
|
|
158 if (FUNGE_UNLIKELY(!tmp))
|
|
159 return NULL;
|
|
160 if (FUNGE_UNLIKELY(!ip_create_in_place(&tmp->ips[0])))
|
|
161 return NULL;
|
|
162 tmp->size = ALLOCCHUNKSIZE;
|
|
163 tmp->top = 0;
|
|
164 tmp->highestID = 0;
|
|
165 return tmp;
|
|
166 }
|
|
167
|
|
168 #ifndef NDEBUG
|
|
169 FUNGE_ATTR_FAST void iplist_free(ipList* me)
|
|
170 {
|
|
171 if (FUNGE_UNLIKELY(!me))
|
|
172 return;
|
|
173 for (size_t i = 0; i <= me->top; i++) {
|
|
174 ip_free_resources(&me->ips[i]);
|
|
175 }
|
|
176 cf_free(me);
|
|
177 }
|
|
178 #endif
|
|
179
|
|
180 FUNGE_ATTR_FAST ssize_t iplist_duplicate_ip(ipList** me, size_t index)
|
|
181 {
|
|
182 ipList *list;
|
|
183
|
|
184 assert(me != NULL);
|
|
185 assert(*me != NULL);
|
|
186 assert(index <= (*me)->top);
|
|
187
|
|
188 list = *me;
|
|
189
|
|
190 // Grow if needed
|
|
191 if (list->size <= (list->top + 1)) {
|
|
192 list = (ipList*)cf_realloc(*me, sizeof(ipList) + sizeof(instructionPointer[(*me)->size + ALLOCCHUNKSIZE]));
|
|
193 if (FUNGE_UNLIKELY(!list))
|
|
194 return -1;
|
|
195 *me = list;
|
|
196 list->size += ALLOCCHUNKSIZE;
|
|
197 }
|
|
198 /*
|
|
199 * Splitting examples.
|
|
200 *
|
|
201 * Thread index 3 splits (to 3a)
|
|
202 * 0 | 1 | 2 | 3 | 4 | 5 | 6
|
|
203 * ---------------------------------
|
|
204 * t0 | t1 | t3 | t3 | t4 | t5 |
|
|
205 * t0 | t1 | t2 | t3 | t3a | t4 | t5
|
|
206 *
|
|
207 */
|
|
208 // Do we need to move any upwards?
|
|
209 if (index != list->top) {
|
|
210 /* Move upwards:
|
|
211 * t0 | t1 | t2 |
|
|
212 * t10| | t1 | t2
|
|
213 */
|
|
214 for (size_t i = list->top + 1; i > index; i--) {
|
|
215 list->ips[i] = list->ips[i - 1];
|
|
216 }
|
|
217 }
|
|
218 /* Duplicate:
|
|
219 * t0 | t1 | t2 |
|
|
220 * t0 | t0a | t1 | t2
|
|
221 */
|
|
222 if (FUNGE_UNLIKELY(!ip_duplicate_in_place(&list->ips[index], &list->ips[index + 1]))) {
|
|
223 // We are in trouble
|
|
224 DIAG_ERROR_LOC("Could not create IP, possibly out of memory?\nThings may be broken now, continuing anyway.");
|
|
225 }
|
|
226
|
|
227 // Here we mirror new IP and do ID changes.
|
|
228 index++;
|
|
229 ip_reverse(&list->ips[index]);
|
|
230 ip_forward(&list->ips[index]);
|
|
231 list->ips[index].ID = ++list->highestID;
|
|
232 list->top++;
|
|
233 return index - 1;
|
|
234 }
|
|
235
|
|
236
|
|
237 FUNGE_ATTR_FAST ssize_t iplist_terminate_ip(ipList** me, size_t index)
|
|
238 {
|
|
239 ipList *list;
|
|
240
|
|
241 assert(me != NULL);
|
|
242 assert(*me != NULL);
|
|
243
|
|
244 list = *me;
|
|
245
|
|
246 /*
|
|
247 * Terminate examples.
|
|
248 *
|
|
249 * Thread index 3 dies
|
|
250 * 0 | 1 | 2 | 3 | 4 | 5
|
|
251 * ---------------------------
|
|
252 * t0 | t1 | t2 | t3 | t4 | t5
|
|
253 * t0 | t1 | t3 | t4 | t5 |
|
|
254 *
|
|
255 */
|
|
256 ip_free_resources(&list->ips[index]);
|
|
257 // Do we need to move downwards?
|
|
258 if (index != list->top) {
|
|
259 /* Move downwards:
|
|
260 * t0 | | t2 | t3
|
|
261 * t0 | t2 | t3 |
|
|
262 */
|
|
263 for (size_t i = index; i < list->top; i++) {
|
|
264 list->ips[i] = list->ips[i + 1];
|
|
265 }
|
|
266 }
|
|
267 // Set stack to be invalid in the top one. This should help catch any bugs
|
|
268 // related to this.
|
|
269 list->ips[list->top].stackstack = NULL;
|
|
270 list->ips[list->top].stack = NULL;
|
|
271 list->top--;
|
|
272 // TODO: Shrink if difference is large
|
|
273 #if 0
|
|
274 if ((list->size - ALLOCCHUNKSIZE) > list->top) {
|
|
275 ipList *tmp;
|
|
276 tmp = (ipList*)cf_realloc(list, sizeof(ipList) + (list->size - ALLOCCHUNKSIZE) * sizeof(instructionPointer));
|
|
277 if (tmp) {
|
|
278 *me = tmp;
|
|
279 tmp->size - ALLOCCHUNKSIZE;
|
|
280 }
|
|
281 }
|
|
282 #endif
|
|
283 return (index > 0) ? index - 1 : 0;
|
|
284 }
|
|
285
|
|
286 #endif
|