1 /*
2 * This file is part of DGD, https://github.com/dworkin/dgd
3 * Copyright (C) 1993-2010 Dworkin B.V.
4 * Copyright (C) 2010-2013 DGD Authors (see the commit log for details)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 # include "dgd.h"
21 # include "str.h"
22 # include "array.h"
23 # include "object.h"
24 # include "xfloat.h"
25 # include "interpret.h"
26 # include "data.h"
27 # include "call_out.h"
28 # include "parse.h"
29 # include "csupport.h"
30
31
32 # define COP_ADD 0 /* add callout patch */
33 # define COP_REMOVE 1 /* remove callout patch */
34 # define COP_REPLACE 2 /* replace callout patch */
35
36 typedef struct _copatch_ {
37 short type; /* add, remove, replace */
38 uindex handle; /* callout handle */
39 dataplane *plane; /* dataplane */
40 Uint time; /* start time */
41 unsigned short mtime; /* start time millisec component */
42 uindex *queue; /* callout queue */
43 struct _copatch_ *next; /* next in linked list */
44 dcallout aco; /* added callout */
45 dcallout rco; /* removed callout */
46 } copatch;
47
48 # define COPCHUNKSZ 32
49
50 typedef struct _copchunk_ {
51 struct _copchunk_ *next; /* next in linked list */
52 copatch cop[COPCHUNKSZ]; /* callout patches */
53 } copchunk;
54
55 typedef struct _coptable_ {
56 copchunk *chunk; /* callout patch chunk */
57 unsigned short chunksz; /* size of callout patch chunk */
58 copatch *flist; /* free list of callout patches */
59 copatch *cop[COPATCHHTABSZ]; /* hash table of callout patches */
60 } coptable;
61
62 typedef struct {
63 array **itab; /* imported array replacement table */
64 Uint itabsz; /* size of table */
65 Uint narr; /* # of arrays */
66 } arrimport;
67
68 static dataplane *plist; /* list of dataplanes */
69 static uindex ncallout; /* # callouts added */
70 static dataspace *ifirst; /* list of dataspaces with imports */
71
72
73 /*
74 * NAME: ref_rhs()
75 * DESCRIPTION: reference the right-hand side in an assignment
76 */
ref_rhs(dataspace * data,value * rhs)77 static void ref_rhs(dataspace *data, value *rhs)
78 {
79 string *str;
80 array *arr;
81
82 switch (rhs->type) {
83 case T_STRING:
84 str = rhs->u.string;
85 if (str->primary != (strref *) NULL && str->primary->data == data) {
86 /* in this object */
87 str->primary->ref++;
88 data->plane->flags |= MOD_STRINGREF;
89 } else {
90 /* not in this object: ref imported string */
91 data->plane->schange++;
92 }
93 break;
94
95 case T_ARRAY:
96 case T_MAPPING:
97 case T_LWOBJECT:
98 arr = rhs->u.array;
99 if (arr->primary->data == data) {
100 /* in this object */
101 if (arr->primary->arr != (array *) NULL) {
102 /* swapped in */
103 arr->primary->ref++;
104 data->plane->flags |= MOD_ARRAYREF;
105 } else {
106 /* ref new array */
107 data->plane->achange++;
108 }
109 } else {
110 /* not in this object: ref imported array */
111 if (data->plane->imports++ == 0 && ifirst != data &&
112 data->iprev == (dataspace *) NULL) {
113 /* add to imports list */
114 data->iprev = (dataspace *) NULL;
115 data->inext = ifirst;
116 if (ifirst != (dataspace *) NULL) {
117 ifirst->iprev = data;
118 }
119 ifirst = data;
120 }
121 data->plane->achange++;
122 }
123 break;
124 }
125 }
126
127 /*
128 * NAME: del_lhs()
129 * DESCRIPTION: delete the left-hand side in an assignment
130 */
del_lhs(dataspace * data,value * lhs)131 static void del_lhs(dataspace *data, value *lhs)
132 {
133 string *str;
134 array *arr;
135
136 switch (lhs->type) {
137 case T_STRING:
138 str = lhs->u.string;
139 if (str->primary != (strref *) NULL && str->primary->data == data) {
140 /* in this object */
141 if (--(str->primary->ref) == 0) {
142 str->primary->str = (string *) NULL;
143 str->primary = (strref *) NULL;
144 str_del(str);
145 data->plane->schange++; /* last reference removed */
146 }
147 data->plane->flags |= MOD_STRINGREF;
148 } else {
149 /* not in this object: deref imported string */
150 data->plane->schange--;
151 }
152 break;
153
154 case T_ARRAY:
155 case T_MAPPING:
156 case T_LWOBJECT:
157 arr = lhs->u.array;
158 if (arr->primary->data == data) {
159 /* in this object */
160 if (arr->primary->arr != (array *) NULL) {
161 /* swapped in */
162 data->plane->flags |= MOD_ARRAYREF;
163 if ((--(arr->primary->ref) & ~ARR_MOD) == 0) {
164 d_get_elts(arr);
165 arr->primary->arr = (array *) NULL;
166 arr->primary = &arr->primary->plane->alocal;
167 arr_del(arr);
168 data->plane->achange++;
169 }
170 } else {
171 /* deref new array */
172 data->plane->achange--;
173 }
174 } else {
175 /* not in this object: deref imported array */
176 data->plane->imports--;
177 data->plane->achange--;
178 }
179 break;
180 }
181 }
182
183
184 /*
185 * NAME: data->alloc_call_out()
186 * DESCRIPTION: allocate a new callout
187 */
d_alloc_call_out(dataspace * data,uindex handle,Uint time,unsigned short mtime,int nargs,value * v)188 static uindex d_alloc_call_out(dataspace *data, uindex handle, Uint time,
189 unsigned short mtime, int nargs, value *v)
190 {
191 dcallout *co;
192
193 if (data->ncallouts == 0) {
194 /*
195 * the first in this object
196 */
197 co = data->callouts = ALLOC(dcallout, 1);
198 data->ncallouts = handle = 1;
199 data->plane->flags |= MOD_NEWCALLOUT;
200 } else {
201 if (data->callouts == (dcallout *) NULL) {
202 d_get_callouts(data);
203 }
204 if (handle != 0) {
205 /*
206 * get a specific callout from the free list
207 */
208 co = &data->callouts[handle - 1];
209 if (handle == data->fcallouts) {
210 data->fcallouts = co->co_next;
211 } else {
212 data->callouts[co->co_prev - 1].co_next = co->co_next;
213 if (co->co_next != 0) {
214 data->callouts[co->co_next - 1].co_prev = co->co_prev;
215 }
216 }
217 } else {
218 handle = data->fcallouts;
219 if (handle != 0) {
220 /*
221 * from free list
222 */
223 co = &data->callouts[handle - 1];
224 if (co->co_next == 0 || co->co_next > handle) {
225 /* take 1st free callout */
226 data->fcallouts = co->co_next;
227 } else {
228 /* take 2nd free callout */
229 co = &data->callouts[co->co_next - 1];
230 data->callouts[handle - 1].co_next = co->co_next;
231 if (co->co_next != 0) {
232 data->callouts[co->co_next - 1].co_prev = handle;
233 }
234 handle = co - data->callouts + 1;
235 }
236 data->plane->flags |= MOD_CALLOUT;
237 } else {
238 /*
239 * add new callout
240 */
241 handle = data->ncallouts;
242 co = data->callouts = REALLOC(data->callouts, dcallout, handle,
243 handle + 1);
244 co += handle;
245 data->ncallouts = ++handle;
246 data->plane->flags |= MOD_NEWCALLOUT;
247 }
248 }
249 }
250
251 co->time = time;
252 co->mtime = mtime;
253 co->nargs = nargs;
254 memcpy(co->val, v, sizeof(co->val));
255 switch (nargs) {
256 default:
257 ref_rhs(data, &v[3]);
258 case 2:
259 ref_rhs(data, &v[2]);
260 case 1:
261 ref_rhs(data, &v[1]);
262 case 0:
263 ref_rhs(data, &v[0]);
264 break;
265 }
266
267 return handle;
268 }
269
270 /*
271 * NAME: data->free_call_out()
272 * DESCRIPTION: free a callout
273 */
d_free_call_out(dataspace * data,unsigned int handle)274 static void d_free_call_out(dataspace *data, unsigned int handle)
275 {
276 dcallout *co;
277 value *v;
278 uindex n;
279
280 co = &data->callouts[handle - 1];
281 v = co->val;
282 switch (co->nargs) {
283 default:
284 del_lhs(data, &v[3]);
285 i_del_value(&v[3]);
286 case 2:
287 del_lhs(data, &v[2]);
288 i_del_value(&v[2]);
289 case 1:
290 del_lhs(data, &v[1]);
291 i_del_value(&v[1]);
292 case 0:
293 del_lhs(data, &v[0]);
294 str_del(v[0].u.string);
295 break;
296 }
297 v[0] = nil_value;
298
299 n = data->fcallouts;
300 if (n != 0) {
301 data->callouts[n - 1].co_prev = handle;
302 }
303 co->co_next = n;
304 data->fcallouts = handle;
305
306 data->plane->flags |= MOD_CALLOUT;
307 }
308
309
310 /*
311 * NAME: copatch->init()
312 * DESCRIPTION: initialize copatch table
313 */
cop_init(dataplane * plane)314 static void cop_init(dataplane *plane)
315 {
316 memset(plane->coptab = ALLOC(coptable, 1), '\0', sizeof(coptable));
317 }
318
319 /*
320 * NAME: copatch->clean()
321 * DESCRIPTION: free copatch table
322 */
cop_clean(dataplane * plane)323 static void cop_clean(dataplane *plane)
324 {
325 copchunk *c, *f;
326
327 c = plane->coptab->chunk;
328 while (c != (copchunk *) NULL) {
329 f = c;
330 c = c->next;
331 FREE(f);
332 }
333
334 FREE(plane->coptab);
335 plane->coptab = (coptable *) NULL;
336 }
337
338 /*
339 * NAME: copatch->new()
340 * DESCRIPTION: create a new callout patch
341 */
cop_new(dataplane * plane,copatch ** c,int type,unsigned int handle,dcallout * co,Uint time,unsigned int mtime,uindex * q)342 static copatch *cop_new(dataplane *plane, copatch **c, int type,
343 unsigned int handle, dcallout *co, Uint time, unsigned int mtime,
344 uindex *q)
345 {
346 coptable *tab;
347 copatch *cop;
348 int i;
349 value *v;
350
351 /* allocate */
352 tab = plane->coptab;
353 if (tab->flist != (copatch *) NULL) {
354 /* from free list */
355 cop = tab->flist;
356 tab->flist = cop->next;
357 } else {
358 /* newly allocated */
359 if (tab->chunk == (copchunk *) NULL || tab->chunksz == COPCHUNKSZ) {
360 copchunk *cc;
361
362 /* create new chunk */
363 cc = ALLOC(copchunk, 1);
364 cc->next = tab->chunk;
365 tab->chunk = cc;
366 tab->chunksz = 0;
367 }
368
369 cop = &tab->chunk->cop[tab->chunksz++];
370 }
371
372 /* initialize */
373 cop->type = type;
374 cop->handle = handle;
375 if (type == COP_ADD) {
376 cop->aco = *co;
377 } else {
378 cop->rco = *co;
379 }
380 for (i = (co->nargs > 3) ? 4 : co->nargs + 1, v = co->val; i > 0; --i) {
381 i_ref_value(v++);
382 }
383 cop->time = time;
384 cop->mtime = mtime;
385 cop->plane = plane;
386 cop->queue = q;
387
388 /* add to hash table */
389 cop->next = *c;
390 return *c = cop;
391 }
392
393 /*
394 * NAME: copatch->del()
395 * DESCRIPTION: delete a callout patch
396 */
cop_del(dataplane * plane,copatch ** c,bool del)397 static void cop_del(dataplane *plane, copatch **c, bool del)
398 {
399 copatch *cop;
400 dcallout *co;
401 int i;
402 value *v;
403 coptable *tab;
404
405 /* remove from hash table */
406 cop = *c;
407 *c = cop->next;
408
409 if (del) {
410 /* free referenced callout */
411 co = (cop->type == COP_ADD) ? &cop->aco : &cop->rco;
412 v = co->val;
413 for (i = (co->nargs > 3) ? 4 : co->nargs + 1; i > 0; --i) {
414 i_del_value(v++);
415 }
416 }
417
418 /* add to free list */
419 tab = plane->coptab;
420 cop->next = tab->flist;
421 tab->flist = cop;
422 }
423
424 /*
425 * NAME: copatch->replace()
426 * DESCRIPTION: replace one callout patch with another
427 */
cop_replace(copatch * cop,dcallout * co,Uint time,unsigned int mtime,uindex * q)428 static void cop_replace(copatch *cop, dcallout *co, Uint time,
429 unsigned int mtime, uindex *q)
430 {
431 int i;
432 value *v;
433
434 cop->type = COP_REPLACE;
435 cop->aco = *co;
436 for (i = (co->nargs > 3) ? 4 : co->nargs + 1, v = co->val; i > 0; --i) {
437 i_ref_value(v++);
438 }
439 cop->time = time;
440 cop->mtime = mtime;
441 cop->queue = q;
442 }
443
444 /*
445 * NAME: copatch->commit()
446 * DESCRIPTION: commit a callout replacement
447 */
cop_commit(copatch * cop)448 static void cop_commit(copatch *cop)
449 {
450 int i;
451 value *v;
452
453 cop->type = COP_ADD;
454 for (i = (cop->rco.nargs > 3) ? 4 : cop->rco.nargs + 1, v = cop->rco.val;
455 i > 0; --i) {
456 i_del_value(v++);
457 }
458 }
459
460 /*
461 * NAME: copatch->release()
462 * DESCRIPTION: remove a callout replacement
463 */
cop_release(copatch * cop)464 static void cop_release(copatch *cop)
465 {
466 int i;
467 value *v;
468
469 cop->type = COP_REMOVE;
470 for (i = (cop->aco.nargs > 3) ? 4 : cop->aco.nargs + 1, v = cop->aco.val;
471 i > 0; --i) {
472 i_del_value(v++);
473 }
474 }
475
476 /*
477 * NAME: copatch->discard()
478 * DESCRIPTION: discard replacement
479 */
cop_discard(copatch * cop)480 static void cop_discard(copatch *cop)
481 {
482 /* force unref of proper component later */
483 cop->type = COP_ADD;
484 }
485
486
487 /*
488 * NAME: data->new_plane()
489 * DESCRIPTION: create a new dataplane
490 */
d_new_plane(dataspace * data,Int level)491 void d_new_plane(dataspace *data, Int level)
492 {
493 dataplane *p;
494 Uint i;
495
496 p = ALLOC(dataplane, 1);
497
498 p->level = level;
499 p->flags = data->plane->flags;
500 p->schange = data->plane->schange;
501 p->achange = data->plane->achange;
502 p->imports = data->plane->imports;
503
504 /* copy value information from previous plane */
505 p->original = (value *) NULL;
506 p->alocal.arr = (array *) NULL;
507 p->alocal.plane = p;
508 p->alocal.data = data;
509 p->alocal.state = AR_CHANGED;
510 p->coptab = data->plane->coptab;
511
512 if (data->plane->arrays != (arrref *) NULL) {
513 arrref *a, *b;
514
515 p->arrays = ALLOC(arrref, i = data->narrays);
516 for (a = p->arrays, b = data->plane->arrays; i != 0; a++, b++, --i) {
517 if (b->arr != (array *) NULL) {
518 *a = *b;
519 a->arr->primary = a;
520 arr_ref(a->arr);
521 } else {
522 a->arr = (array *) NULL;
523 }
524 }
525 } else {
526 p->arrays = (arrref *) NULL;
527 }
528 p->achunk = (abchunk *) NULL;
529
530 if (data->plane->strings != (strref *) NULL) {
531 strref *s, *t;
532
533 p->strings = ALLOC(strref, i = data->nstrings);
534 for (s = p->strings, t = data->plane->strings; i != 0; s++, t++, --i) {
535 if (t->str != (string *) NULL) {
536 *s = *t;
537 s->str->primary = s;
538 str_ref(s->str);
539 } else {
540 s->str = (string *) NULL;
541 }
542 }
543 } else {
544 p->strings = (strref *) NULL;
545 }
546
547 p->prev = data->plane;
548 data->plane = p;
549 p->plist = plist;
550 plist = p;
551 }
552
553 /*
554 * NAME: commit_values()
555 * DESCRIPTION: commit non-swapped arrays among the values
556 */
commit_values(value * v,unsigned int n,Int level)557 static void commit_values(value *v, unsigned int n, Int level)
558 {
559 array *arr;
560
561 while (n != 0) {
562 if (T_INDEXED(v->type)) {
563 arr = v->u.array;
564 if (arr->primary->arr == (array *) NULL &&
565 arr->primary->plane->level > level) {
566 if (arr->hashmod) {
567 map_compact(arr->primary->data, arr);
568 }
569 arr->primary = &arr->primary->plane->prev->alocal;
570 commit_values(arr->elts, arr->size, level);
571 }
572
573 }
574 v++;
575 --n;
576 }
577 }
578
579 /*
580 * NAME: commit_callouts()
581 * DESCRIPTION: commit callout patches to previous plane
582 */
commit_callouts(dataplane * plane,bool merge)583 static void commit_callouts(dataplane *plane, bool merge)
584 {
585 dataplane *prev;
586 copatch **c, **n, *cop;
587 copatch **t, **next;
588 int i;
589
590 prev = plane->prev;
591 for (i = COPATCHHTABSZ, t = plane->coptab->cop; --i >= 0; t++) {
592 if (*t != (copatch *) NULL && (*t)->plane == plane) {
593 /*
594 * find previous plane in hash chain
595 */
596 next = t;
597 do {
598 next = &(*next)->next;
599 } while (*next != (copatch *) NULL && (*next)->plane == plane);
600
601 c = t;
602 do {
603 cop = *c;
604 if (cop->type != COP_REMOVE) {
605 commit_values(cop->aco.val + 1,
606 (cop->aco.nargs > 3) ? 3 : cop->aco.nargs,
607 prev->level);
608 }
609
610 if (prev->level == 0) {
611 /*
612 * commit to last plane
613 */
614 switch (cop->type) {
615 case COP_ADD:
616 co_new(plane->alocal.data->oindex, cop->handle,
617 cop->time, cop->mtime, cop->queue);
618 --ncallout;
619 break;
620
621 case COP_REMOVE:
622 co_del(plane->alocal.data->oindex, cop->handle,
623 cop->rco.time, cop->rco.mtime);
624 ncallout++;
625 break;
626
627 case COP_REPLACE:
628 co_del(plane->alocal.data->oindex, cop->handle,
629 cop->rco.time, cop->rco.mtime);
630 co_new(plane->alocal.data->oindex, cop->handle,
631 cop->time, cop->mtime, cop->queue);
632 cop_commit(cop);
633 break;
634 }
635
636 if (next == &cop->next) {
637 next = c;
638 }
639 cop_del(plane, c, TRUE);
640 } else {
641 /*
642 * commit to previous plane
643 */
644 cop->plane = prev;
645 if (merge) {
646 for (n = next;
647 *n != (copatch *) NULL && (*n)->plane == prev;
648 n = &(*n)->next) {
649 if (cop->handle == (*n)->handle) {
650 switch (cop->type) {
651 case COP_ADD:
652 /* turn old remove into replace, del new */
653 cop_replace(*n, &cop->aco, cop->time,
654 cop->mtime, cop->queue);
655 if (next == &cop->next) {
656 next = c;
657 }
658 cop_del(prev, c, TRUE);
659 break;
660
661 case COP_REMOVE:
662 if ((*n)->type == COP_REPLACE) {
663 /* turn replace back into remove */
664 cop_release(*n);
665 } else {
666 /* del old */
667 cop_del(prev, n, TRUE);
668 }
669 /* del new */
670 if (next == &cop->next) {
671 next = c;
672 }
673 cop_del(prev, c, TRUE);
674 break;
675
676 case COP_REPLACE:
677 if ((*n)->type == COP_REPLACE) {
678 /* merge replaces into old, del new */
679 cop_release(*n);
680 cop_replace(*n, &cop->aco, cop->time,
681 cop->mtime, cop->queue);
682 if (next == &cop->next) {
683 next = c;
684 }
685 cop_del(prev, c, TRUE);
686 } else {
687 /* make replace into add, remove old */
688 cop_del(prev, n, TRUE);
689 cop_commit(cop);
690 }
691 break;
692 }
693 break;
694 }
695 }
696 }
697
698 if (*c == cop) {
699 c = &cop->next;
700 }
701 }
702 } while (c != next);
703 }
704 }
705 }
706
707 /*
708 * NAME: data->commit_plane()
709 * DESCRIPTION: commit the current data plane
710 */
d_commit_plane(Int level,value * retval)711 void d_commit_plane(Int level, value *retval)
712 {
713 dataplane *p, *commit, **r, **cr;
714 dataspace *data;
715 value *v;
716 Uint i;
717 dataplane *clist;
718
719 /*
720 * pass 1: construct commit planes
721 */
722 clist = (dataplane *) NULL;
723 cr = &clist;
724 for (r = &plist, p = *r; p != (dataplane *) NULL && p->level == level;
725 r = &p->plist, p = *r) {
726 if (p->prev->level != level - 1) {
727 /* insert commit plane */
728 commit = ALLOC(dataplane, 1);
729 commit->level = level - 1;
730 commit->original = (value *) NULL;
731 commit->alocal.arr = (array *) NULL;
732 commit->alocal.plane = commit;
733 commit->alocal.data = p->alocal.data;
734 commit->alocal.state = AR_CHANGED;
735 commit->arrays = p->arrays;
736 commit->achunk = p->achunk;
737 commit->strings = p->strings;
738 commit->coptab = p->coptab;
739 commit->prev = p->prev;
740 *cr = commit;
741 cr = &commit->plist;
742
743 p->prev = commit;
744 } else {
745 p->flags |= PLANE_MERGE;
746 }
747 }
748 if (clist != (dataplane *) NULL) {
749 /* insert commit planes in plane list */
750 *cr = p;
751 *r = clist;
752 }
753 clist = *r; /* sentinel */
754
755 /*
756 * pass 2: commit
757 */
758 for (p = plist; p != clist; p = p->plist) {
759 /*
760 * commit changes to previous plane
761 */
762 data = p->alocal.data;
763 if (p->original != (value *) NULL) {
764 if (p->level == 1 || p->prev->original != (value *) NULL) {
765 /* free backed-up variable values */
766 for (v = p->original, i = data->nvariables; i != 0; v++, --i) {
767 i_del_value(v);
768 }
769 FREE(p->original);
770 } else {
771 /* move originals to previous plane */
772 p->prev->original = p->original;
773 }
774 commit_values(data->variables, data->nvariables, level - 1);
775 }
776
777 if (p->coptab != (coptable *) NULL) {
778 /* commit callout changes */
779 commit_callouts(p, p->flags & PLANE_MERGE);
780 if (p->level == 1) {
781 cop_clean(p);
782 } else {
783 p->prev->coptab = p->coptab;
784 }
785 }
786
787 arr_commit(&p->achunk, p->prev, p->flags & PLANE_MERGE);
788 if (p->flags & PLANE_MERGE) {
789 if (p->arrays != (arrref *) NULL) {
790 arrref *a;
791
792 /* remove old array refs */
793 for (a = p->prev->arrays, i = data->narrays; i != 0; a++, --i) {
794 if (a->arr != (array *) NULL) {
795 if (a->arr->primary == &p->alocal) {
796 a->arr->primary = &p->prev->alocal;
797 }
798 arr_del(a->arr);
799 }
800 }
801 FREE(p->prev->arrays);
802 p->prev->arrays = p->arrays;
803 }
804
805 if (p->strings != (strref *) NULL) {
806 strref *s;
807
808 /* remove old string refs */
809 for (s = p->prev->strings, i = data->nstrings; i != 0; s++, --i)
810 {
811 if (s->str != (string *) NULL) {
812 str_del(s->str);
813 }
814 }
815 FREE(p->prev->strings);
816 p->prev->strings = p->strings;
817 }
818 }
819 }
820 commit_values(retval, 1, level - 1);
821
822 /*
823 * pass 3: deallocate
824 */
825 for (p = plist; p != clist; p = plist) {
826 p->prev->flags = (p->flags & MOD_ALL) | MOD_SAVE;
827 p->prev->schange = p->schange;
828 p->prev->achange = p->achange;
829 p->prev->imports = p->imports;
830 p->alocal.data->plane = p->prev;
831 plist = p->plist;
832 FREE(p);
833 }
834 }
835
836 /*
837 * NAME: discard_callouts()
838 * DESCRIPTION: discard callout patches on current plane, restoring old callouts
839 */
discard_callouts(dataplane * plane)840 static void discard_callouts(dataplane *plane)
841 {
842 copatch *cop, **c, **t;
843 dataspace *data;
844 int i;
845
846 data = plane->alocal.data;
847 for (i = COPATCHHTABSZ, t = plane->coptab->cop; --i >= 0; t++) {
848 c = t;
849 while (*c != (copatch *) NULL && (*c)->plane == plane) {
850 cop = *c;
851 switch (cop->type) {
852 case COP_ADD:
853 d_free_call_out(data, cop->handle);
854 cop_del(plane, c, TRUE);
855 --ncallout;
856 break;
857
858 case COP_REMOVE:
859 d_alloc_call_out(data, cop->handle, cop->rco.time,
860 cop->rco.mtime, cop->rco.nargs, cop->rco.val);
861 cop_del(plane, c, FALSE);
862 ncallout++;
863 break;
864
865 case COP_REPLACE:
866 d_free_call_out(data, cop->handle);
867 d_alloc_call_out(data, cop->handle, cop->rco.time,
868 cop->rco.mtime, cop->rco.nargs, cop->rco.val);
869 cop_discard(cop);
870 cop_del(plane, c, TRUE);
871 break;
872 }
873 }
874 }
875 }
876
877 /*
878 * NAME: data->discard_plane()
879 * DESCRIPTION: discard the current data plane without committing it
880 */
d_discard_plane(Int level)881 void d_discard_plane(Int level)
882 {
883 dataplane *p;
884 dataspace *data;
885 value *v;
886 Uint i;
887
888 for (p = plist; p != (dataplane *) NULL && p->level == level; p = p->plist)
889 {
890 /*
891 * discard changes except for callout mods
892 */
893 p->prev->flags |= p->flags & (MOD_CALLOUT | MOD_NEWCALLOUT);
894
895 data = p->alocal.data;
896 if (p->original != (value *) NULL) {
897 /* restore original variable values */
898 for (v = data->variables, i = data->nvariables; i != 0; --i, v++) {
899 i_del_value(v);
900 }
901 memcpy(data->variables, p->original,
902 data->nvariables * sizeof(value));
903 FREE(p->original);
904 }
905
906 if (p->coptab != (coptable *) NULL) {
907 /* undo callout changes */
908 discard_callouts(p);
909 if (p->prev == &data->base) {
910 cop_clean(p);
911 } else {
912 p->prev->coptab = p->coptab;
913 }
914 }
915
916 arr_discard(&p->achunk);
917 if (p->arrays != (arrref *) NULL) {
918 arrref *a;
919
920 /* delete new array refs */
921 for (a = p->arrays, i = data->narrays; i != 0; a++, --i) {
922 if (a->arr != (array *) NULL) {
923 arr_del(a->arr);
924 }
925 }
926 FREE(p->arrays);
927 /* fix old ones */
928 for (a = p->prev->arrays, i = data->narrays; i != 0; a++, --i) {
929 if (a->arr != (array *) NULL) {
930 a->arr->primary = a;
931 }
932 }
933 }
934
935 if (p->strings != (strref *) NULL) {
936 strref *s;
937
938 /* delete new string refs */
939 for (s = p->strings, i = data->nstrings; i != 0; s++, --i) {
940 if (s->str != (string *) NULL) {
941 str_del(s->str);
942 }
943 }
944 FREE(p->strings);
945 /* fix old ones */
946 for (s = p->prev->strings, i = data->nstrings; i != 0; s++, --i) {
947 if (s->str != (string *) NULL) {
948 s->str->primary = s;
949 }
950 }
951 }
952
953 data->plane = p->prev;
954 plist = p->plist;
955 FREE(p);
956 }
957 }
958
959
960 /*
961 * NAME: data->commit_arr()
962 * DESCRIPTION: commit array to previous plane
963 */
d_commit_arr(array * arr,dataplane * prev,dataplane * old)964 abchunk **d_commit_arr(array *arr, dataplane *prev, dataplane *old)
965 {
966 if (arr->primary->plane != prev) {
967 if (arr->hashmod) {
968 map_compact(arr->primary->data, arr);
969 }
970
971 if (arr->primary->arr == (array *) NULL) {
972 arr->primary = &prev->alocal;
973 } else {
974 arr->primary->plane = prev;
975 }
976 commit_values(arr->elts, arr->size, prev->level);
977 }
978
979 return (prev == old) ? (abchunk **) NULL : &prev->achunk;
980 }
981
982 /*
983 * NAME: data->discard_arr()
984 * DESCRIPTION: restore array to previous plane
985 */
d_discard_arr(array * arr,dataplane * plane)986 void d_discard_arr(array *arr, dataplane *plane)
987 {
988 /* swapped-in arrays will be fixed later */
989 arr->primary = &plane->alocal;
990 }
991
992
993 /*
994 * NAME: data->ref_imports()
995 * DESCRIPTION: check the elements of an array for imports
996 */
d_ref_imports(array * arr)997 void d_ref_imports(array *arr)
998 {
999 dataspace *data;
1000 unsigned short n;
1001 value *v;
1002
1003 data = arr->primary->data;
1004 for (n = arr->size, v = arr->elts; n > 0; --n, v++) {
1005 if (T_INDEXED(v->type) && data != v->u.array->primary->data) {
1006 /* mark as imported */
1007 if (data->plane->imports++ == 0 && ifirst != data &&
1008 data->iprev == (dataspace *) NULL) {
1009 /* add to imports list */
1010 data->iprev = (dataspace *) NULL;
1011 data->inext = ifirst;
1012 if (ifirst != (dataspace *) NULL) {
1013 ifirst->iprev = data;
1014 }
1015 ifirst = data;
1016 }
1017 }
1018 }
1019 }
1020
1021 /*
1022 * NAME: data->assign_var()
1023 * DESCRIPTION: assign a value to a variable
1024 */
d_assign_var(dataspace * data,value * var,value * val)1025 void d_assign_var(dataspace *data, value *var, value *val)
1026 {
1027 if (var >= data->variables && var < data->variables + data->nvariables) {
1028 if (data->plane->level != 0 &&
1029 data->plane->original == (value *) NULL) {
1030 /*
1031 * back up variables
1032 */
1033 i_copy(data->plane->original = ALLOC(value, data->nvariables),
1034 data->variables, data->nvariables);
1035 }
1036 ref_rhs(data, val);
1037 del_lhs(data, var);
1038 data->plane->flags |= MOD_VARIABLE;
1039 }
1040
1041 i_ref_value(val);
1042 i_del_value(var);
1043
1044 *var = *val;
1045 var->modified = TRUE;
1046 }
1047
1048 /*
1049 * NAME: data->get_extravar()
1050 * DESCRIPTION: get an object's special value
1051 */
d_get_extravar(dataspace * data)1052 value *d_get_extravar(dataspace *data)
1053 {
1054 return d_get_variable(data, data->nvariables - 1);
1055 }
1056
1057 /*
1058 * NAME: data->set_extravar()
1059 * DESCRIPTION: set an object's special value
1060 */
d_set_extravar(dataspace * data,value * val)1061 void d_set_extravar(dataspace *data, value *val)
1062 {
1063 d_assign_var(data, d_get_variable(data, data->nvariables - 1), val);
1064 }
1065
1066 /*
1067 * NAME: data->wipe_extravar()
1068 * DESCRIPTION: wipe out an object's special value
1069 */
d_wipe_extravar(dataspace * data)1070 void d_wipe_extravar(dataspace *data)
1071 {
1072 d_assign_var(data, d_get_variable(data, data->nvariables - 1), &nil_value);
1073
1074 if (data->parser != (struct _parser_ *) NULL) {
1075 /*
1076 * get rid of the parser, too
1077 */
1078 ps_del(data->parser);
1079 data->parser = (struct _parser_ *) NULL;
1080 }
1081 }
1082
1083 /*
1084 * NAME: data->assign_elt()
1085 * DESCRIPTION: assign a value to an array element
1086 */
d_assign_elt(dataspace * data,array * arr,value * elt,value * val)1087 void d_assign_elt(dataspace *data, array *arr, value *elt, value *val)
1088 {
1089 if (data->plane->level != arr->primary->data->plane->level) {
1090 /*
1091 * bring dataspace of imported array up to the current plane level
1092 */
1093 d_new_plane(arr->primary->data, data->plane->level);
1094 }
1095
1096 data = arr->primary->data;
1097 if (arr->primary->plane != data->plane) {
1098 /*
1099 * backup array's current elements
1100 */
1101 arr_backup(&data->plane->achunk, arr);
1102 if (arr->primary->arr != (array *) NULL) {
1103 arr->primary->plane = data->plane;
1104 } else {
1105 arr->primary = &data->plane->alocal;
1106 }
1107 }
1108
1109 if (arr->primary->arr != (array *) NULL) {
1110 /*
1111 * the array is in the loaded dataspace of some object
1112 */
1113 if ((arr->primary->ref & ARR_MOD) == 0) {
1114 arr->primary->ref |= ARR_MOD;
1115 data->plane->flags |= MOD_ARRAY;
1116 }
1117 ref_rhs(data, val);
1118 del_lhs(data, elt);
1119 } else {
1120 if (T_INDEXED(val->type) && data != val->u.array->primary->data) {
1121 /* mark as imported */
1122 if (data->plane->imports++ == 0 && ifirst != data &&
1123 data->iprev == (dataspace *) NULL) {
1124 /* add to imports list */
1125 data->iprev = (dataspace *) NULL;
1126 data->inext = ifirst;
1127 if (ifirst != (dataspace *) NULL) {
1128 ifirst->iprev = data;
1129 }
1130 ifirst = data;
1131 }
1132 }
1133 if (T_INDEXED(elt->type) && data != elt->u.array->primary->data) {
1134 /* mark as unimported */
1135 data->plane->imports--;
1136 }
1137 }
1138
1139 i_ref_value(val);
1140 i_del_value(elt);
1141
1142 *elt = *val;
1143 elt->modified = TRUE;
1144 }
1145
1146 /*
1147 * NAME: data->change_map()
1148 * DESCRIPTION: mark a mapping as changed in size
1149 */
d_change_map(array * map)1150 void d_change_map(array *map)
1151 {
1152 arrref *a;
1153
1154 a = map->primary;
1155 if (a->state == AR_UNCHANGED) {
1156 a->plane->achange++;
1157 a->state = AR_CHANGED;
1158 }
1159 }
1160
1161
1162 /*
1163 * NAME: data->new_call_out()
1164 * DESCRIPTION: add a new callout
1165 */
d_new_call_out(dataspace * data,string * func,Int delay,unsigned int mdelay,frame * f,int nargs)1166 uindex d_new_call_out(dataspace *data, string *func, Int delay,
1167 unsigned int mdelay, frame *f, int nargs)
1168 {
1169 Uint ct, t;
1170 unsigned short m;
1171 uindex *q;
1172 value v[4];
1173 uindex handle;
1174
1175 ct = co_check(ncallout, delay, mdelay, &t, &m, &q);
1176 if (ct == 0 && q == (uindex *) NULL) {
1177 /* callouts are disabled */
1178 return 0;
1179 }
1180
1181 PUT_STRVAL(&v[0], func);
1182 switch (nargs) {
1183 case 3:
1184 v[3] = f->sp[2];
1185 case 2:
1186 v[2] = f->sp[1];
1187 case 1:
1188 v[1] = f->sp[0];
1189 case 0:
1190 break;
1191
1192 default:
1193 v[1] = f->sp[0];
1194 v[2] = f->sp[1];
1195 PUT_ARRVAL(&v[3], arr_new(data, nargs - 2L));
1196 memcpy(v[3].u.array->elts, f->sp + 2, (nargs - 2) * sizeof(value));
1197 d_ref_imports(v[3].u.array);
1198 break;
1199 }
1200 f->sp += nargs;
1201 handle = d_alloc_call_out(data, 0, ct, m, nargs, v);
1202
1203 if (data->plane->level == 0) {
1204 /*
1205 * add normal callout
1206 */
1207 co_new(data->oindex, handle, t, m, q);
1208 } else {
1209 dataplane *plane;
1210 copatch **c, *cop;
1211 dcallout *co;
1212 copatch **cc;
1213
1214 /*
1215 * add callout patch
1216 */
1217 plane = data->plane;
1218 if (plane->coptab == (coptable *) NULL) {
1219 cop_init(plane);
1220 }
1221 co = &data->callouts[handle - 1];
1222 cc = c = &plane->coptab->cop[handle % COPATCHHTABSZ];
1223 for (;;) {
1224 cop = *c;
1225 if (cop == (copatch *) NULL || cop->plane != plane) {
1226 /* add new */
1227 cop_new(plane, cc, COP_ADD, handle, co, t, m, q);
1228 break;
1229 }
1230
1231 if (cop->handle == handle) {
1232 /* replace removed */
1233 cop_replace(cop, co, t, m, q);
1234 break;
1235 }
1236
1237 c = &cop->next;
1238 }
1239
1240 ncallout++;
1241 }
1242
1243 return handle;
1244 }
1245
1246 /*
1247 * NAME: data->del_call_out()
1248 * DESCRIPTION: remove a callout
1249 */
d_del_call_out(dataspace * data,Uint handle,unsigned short * mtime)1250 Int d_del_call_out(dataspace *data, Uint handle, unsigned short *mtime)
1251 {
1252 dcallout *co;
1253 Int t;
1254
1255 *mtime = 0xffff;
1256 if (handle == 0 || handle > data->ncallouts) {
1257 /* no such callout */
1258 return -1;
1259 }
1260 if (data->callouts == (dcallout *) NULL) {
1261 d_get_callouts(data);
1262 }
1263
1264 co = &data->callouts[handle - 1];
1265 if (co->val[0].type != T_STRING) {
1266 /* invalid callout */
1267 return -1;
1268 }
1269
1270 *mtime = co->mtime;
1271 t = co_remaining(co->time, mtime);
1272 if (data->plane->level == 0) {
1273 /*
1274 * remove normal callout
1275 */
1276 co_del(data->oindex, (uindex) handle, co->time, co->mtime);
1277 } else {
1278 dataplane *plane;
1279 copatch **c, *cop;
1280 copatch **cc;
1281
1282 /*
1283 * add/remove callout patch
1284 */
1285 --ncallout;
1286
1287 plane = data->plane;
1288 if (plane->coptab == (coptable *) NULL) {
1289 cop_init(plane);
1290 }
1291 cc = c = &plane->coptab->cop[handle % COPATCHHTABSZ];
1292 for (;;) {
1293 cop = *c;
1294 if (cop == (copatch *) NULL || cop->plane != plane) {
1295 /* delete new */
1296 cop_new(plane, cc, COP_REMOVE, (uindex) handle, co, (Uint) 0, 0,
1297 (uindex *) NULL);
1298 break;
1299 }
1300 if (cop->handle == handle) {
1301 /* delete existing */
1302 if (cop->type == COP_REPLACE) {
1303 cop_release(cop);
1304 } else {
1305 cop_del(plane, c, TRUE);
1306 }
1307 break;
1308 }
1309 c = &cop->next;
1310 }
1311 }
1312 d_free_call_out(data, (uindex) handle);
1313
1314 return t;
1315 }
1316
1317 /*
1318 * NAME: data->get_call_out()
1319 * DESCRIPTION: get a callout
1320 */
d_get_call_out(dataspace * data,unsigned int handle,frame * f,int * nargs)1321 string *d_get_call_out(dataspace *data, unsigned int handle, frame *f,
1322 int *nargs)
1323 {
1324 string *str;
1325 dcallout *co;
1326 value *v, *o;
1327 uindex n;
1328
1329 if (data->callouts == (dcallout *) NULL) {
1330 d_get_callouts(data);
1331 }
1332
1333 co = &data->callouts[handle - 1];
1334 v = co->val;
1335 del_lhs(data, &v[0]);
1336 str = v[0].u.string;
1337
1338 i_grow_stack(f, (*nargs = co->nargs) + 1);
1339 *--f->sp = v[0];
1340
1341 switch (co->nargs) {
1342 case 3:
1343 del_lhs(data, &v[3]);
1344 *--f->sp = v[3];
1345 case 2:
1346 del_lhs(data, &v[2]);
1347 *--f->sp = v[2];
1348 case 1:
1349 del_lhs(data, &v[1]);
1350 *--f->sp = v[1];
1351 case 0:
1352 break;
1353
1354 default:
1355 n = co->nargs - 2;
1356 f->sp -= n;
1357 memcpy(f->sp, d_get_elts(v[3].u.array), n * sizeof(value));
1358 del_lhs(data, &v[3]);
1359 FREE(v[3].u.array->elts);
1360 v[3].u.array->elts = (value *) NULL;
1361 arr_del(v[3].u.array);
1362 del_lhs(data, &v[2]);
1363 *--f->sp = v[2];
1364 del_lhs(data, &v[1]);
1365 *--f->sp = v[1];
1366 break;
1367 }
1368
1369 /* wipe out destructed objects */
1370 for (n = co->nargs, v = f->sp; n > 0; --n, v++) {
1371 switch (v->type) {
1372 case T_OBJECT:
1373 if (DESTRUCTED(v)) {
1374 *v = nil_value;
1375 }
1376 break;
1377
1378 case T_LWOBJECT:
1379 o = d_get_elts(v->u.array);
1380 if (o->type == T_OBJECT && DESTRUCTED(o)) {
1381 arr_del(v->u.array);
1382 *v = nil_value;
1383 }
1384 break;
1385 }
1386 }
1387
1388 co->val[0] = nil_value;
1389 n = data->fcallouts;
1390 if (n != 0) {
1391 data->callouts[n - 1].co_prev = handle;
1392 }
1393 co->co_next = n;
1394 data->fcallouts = handle;
1395
1396 data->plane->flags |= MOD_CALLOUT;
1397 return str;
1398 }
1399
1400 /*
1401 * NAME: data->list_callouts()
1402 * DESCRIPTION: list all call_outs in an object
1403 */
d_list_callouts(dataspace * host,dataspace * data)1404 array *d_list_callouts(dataspace *host, dataspace *data)
1405 {
1406 uindex n, count, size;
1407 dcallout *co;
1408 value *v, *v2, *elts;
1409 array *list, *a;
1410 uindex max_args;
1411 xfloat flt;
1412
1413 if (data->ncallouts == 0) {
1414 return arr_new(host, 0L);
1415 }
1416 if (data->callouts == (dcallout *) NULL) {
1417 d_get_callouts(data);
1418 }
1419
1420 /* get the number of callouts in this object */
1421 count = data->ncallouts;
1422 for (n = data->fcallouts; n != 0; n = data->callouts[n - 1].co_next) {
1423 --count;
1424 }
1425 if (count > conf_array_size()) {
1426 return (array *) NULL;
1427 }
1428
1429 list = arr_new(host, (long) count);
1430 elts = list->elts;
1431 max_args = conf_array_size() - 3;
1432
1433 for (co = data->callouts; count > 0; co++) {
1434 if (co->val[0].type == T_STRING) {
1435 size = co->nargs;
1436 if (size > max_args) {
1437 /* unlikely, but possible */
1438 size = max_args;
1439 }
1440 a = arr_new(host, size + 3L);
1441 v = a->elts;
1442
1443 /* handle */
1444 PUT_INTVAL(v, co - data->callouts + 1);
1445 v++;
1446 /* function */
1447 PUT_STRVAL(v, co->val[0].u.string);
1448 v++;
1449 /* time */
1450 if (co->mtime == 0xffff) {
1451 PUT_INTVAL(v, co->time);
1452 } else {
1453 flt.low = co->time;
1454 flt.high = co->mtime;
1455 PUT_FLTVAL(v, flt);
1456 }
1457 v++;
1458
1459 /* copy arguments */
1460 switch (size) {
1461 case 3:
1462 *v++ = co->val[3];
1463 case 2:
1464 *v++ = co->val[2];
1465 case 1:
1466 *v++ = co->val[1];
1467 case 0:
1468 break;
1469
1470 default:
1471 n = size - 2;
1472 for (v2 = d_get_elts(co->val[3].u.array) + n; n > 0; --n) {
1473 *v++ = *--v2;
1474 }
1475 *v++ = co->val[2];
1476 *v++ = co->val[1];
1477 break;
1478 }
1479 while (size > 0) {
1480 i_ref_value(--v);
1481 --size;
1482 }
1483 d_ref_imports(a);
1484
1485 /* put in list */
1486 PUT_ARRVAL(elts, a);
1487 elts++;
1488 --count;
1489 }
1490 }
1491 co_list(list);
1492
1493 return list;
1494 }
1495
1496
1497 /*
1498 * NAME: data->set_varmap()
1499 * DESCRIPTION: add a variable mapping to a control block
1500 */
d_set_varmap(control * ctrl,unsigned short * vmap)1501 void d_set_varmap(control *ctrl, unsigned short *vmap)
1502 {
1503 ctrl->vmapsize = ctrl->nvariables + 1;
1504 ctrl->vmap = vmap;
1505 }
1506
1507 /*
1508 * NAME: data->get_varmap()
1509 * DESCRIPTION: get the variable mapping for an object
1510 */
d_get_varmap(object ** obj,Uint update,unsigned short * nvariables)1511 static unsigned short *d_get_varmap(object **obj, Uint update, unsigned short *nvariables)
1512 {
1513 object *tmpl;
1514 unsigned short nvar, *vmap;
1515
1516 tmpl = OBJ((*obj)->prev);
1517 if (O_UPGRADING(*obj)) {
1518 /* in the middle of an upgrade */
1519 tmpl = OBJ(tmpl->prev);
1520 }
1521 vmap = o_control(tmpl)->vmap;
1522 nvar = tmpl->ctrl->vmapsize;
1523
1524 if (tmpl->update != update) {
1525 unsigned short *m1, *m2, n;
1526
1527 m1 = vmap;
1528 vmap = ALLOC(unsigned short, n = nvar);
1529 do {
1530 tmpl = OBJ(tmpl->prev);
1531 m2 = o_control(tmpl)->vmap;
1532 while (n > 0) {
1533 *vmap++ = (NEW_VAR(*m1)) ? *m1++ : m2[*m1++];
1534 --n;
1535 }
1536 n = nvar;
1537 vmap -= n;
1538 m1 = vmap;
1539 } while (tmpl->update != update);
1540 }
1541
1542 *obj = tmpl;
1543 *nvariables = nvar;
1544 return vmap;
1545 }
1546
1547 /*
1548 * NAME: data->upgrade_data()
1549 * DESCRIPTION: upgrade the dataspace for one object
1550 */
d_upgrade_data(dataspace * data,unsigned int nvar,unsigned short * vmap,object * tmpl)1551 void d_upgrade_data(dataspace *data, unsigned int nvar, unsigned short *vmap,
1552 object *tmpl)
1553 {
1554 value *v;
1555 unsigned short n;
1556 value *vars;
1557
1558 /* make sure variables are in memory */
1559 vars = d_get_variable(data, 0);
1560
1561 /* map variables */
1562 for (n = nvar, v = ALLOC(value, n); n > 0; --n) {
1563 switch (*vmap) {
1564 case NEW_INT:
1565 *v++ = zero_int;
1566 break;
1567
1568 case NEW_FLOAT:
1569 *v++ = zero_float;
1570 break;
1571
1572 case NEW_POINTER:
1573 *v++ = nil_value;
1574 break;
1575
1576 default:
1577 *v = vars[*vmap];
1578 i_ref_value(v);
1579 v->modified = TRUE;
1580 ref_rhs(data, v++);
1581 break;
1582 }
1583 vmap++;
1584 }
1585 vars = v - nvar;
1586
1587 /* deref old values */
1588 v = data->variables;
1589 for (n = data->nvariables; n > 0; --n) {
1590 del_lhs(data, v);
1591 i_del_value(v++);
1592 }
1593
1594 /* replace old with new */
1595 FREE(data->variables);
1596 data->variables = vars;
1597
1598 data->base.flags |= MOD_VARIABLE;
1599 if (data->nvariables != nvar) {
1600 if (data->svariables != (svalue *) NULL) {
1601 FREE(data->svariables);
1602 data->svariables = (svalue *) NULL;
1603 }
1604 data->nvariables = nvar;
1605 data->base.achange++; /* force rebuild on swapout */
1606 }
1607
1608 o_upgraded(tmpl, OBJ(data->oindex));
1609 }
1610
1611 /*
1612 * NAME: data->upgrade_clone()
1613 * DESCRIPTION: upgrade a clone object
1614 */
d_upgrade_clone(dataspace * data)1615 void d_upgrade_clone(dataspace *data)
1616 {
1617 object *obj;
1618 unsigned short *vmap, nvar;
1619 Uint update;
1620
1621 /*
1622 * the program for the clone was upgraded since last swapin
1623 */
1624 obj = OBJ(data->oindex);
1625 update = obj->update;
1626 obj = OBJ(obj->u_master);
1627 vmap = d_get_varmap(&obj, update, &nvar);
1628 d_upgrade_data(data, nvar, vmap, obj);
1629 if (vmap != obj->ctrl->vmap) {
1630 FREE(vmap);
1631 }
1632 }
1633
1634 /*
1635 * NAME: data->upgrade_lwobj()
1636 * DESCRIPTION: upgrade a non-persistent object
1637 */
d_upgrade_lwobj(array * lwobj,object * obj)1638 object *d_upgrade_lwobj(array *lwobj, object *obj)
1639 {
1640 arrref *a;
1641 unsigned short n;
1642 value *v;
1643 Uint update;
1644 unsigned short nvar, *vmap;
1645 value *vars;
1646
1647 a = lwobj->primary;
1648 update = obj->update;
1649 vmap = d_get_varmap(&obj, (Uint) lwobj->elts[1].u.number, &nvar);
1650 --nvar;
1651
1652 /* map variables */
1653 v = ALLOC(value, nvar + 2);
1654 *v++ = lwobj->elts[0];
1655 *v = lwobj->elts[1];
1656 (v++)->u.objcnt = update;
1657
1658 vars = lwobj->elts + 2;
1659 for (n = nvar; n > 0; --n) {
1660 switch (*vmap) {
1661 case NEW_INT:
1662 *v++ = zero_int;
1663 break;
1664
1665 case NEW_FLOAT:
1666 *v++ = zero_float;
1667 break;
1668
1669 case NEW_POINTER:
1670 *v++ = nil_value;
1671 break;
1672
1673 default:
1674 *v = vars[*vmap];
1675 if (a->arr != (array *) NULL) {
1676 ref_rhs(a->data, v);
1677 }
1678 i_ref_value(v);
1679 (v++)->modified = TRUE;
1680 break;
1681 }
1682 vmap++;
1683 }
1684 vars = v - (nvar + 2);
1685
1686 vmap -= nvar;
1687 if (vmap != obj->ctrl->vmap) {
1688 FREE(vmap);
1689 }
1690
1691 v = lwobj->elts + 2;
1692 if (a->arr != (array *) NULL) {
1693 /* swapped-in */
1694 if (a->state == AR_UNCHANGED) {
1695 dataplane *p;
1696
1697 a->state = AR_CHANGED;
1698 for (p = a->data->plane; p != (dataplane *) NULL; p = p->prev) {
1699 p->achange++;
1700 }
1701 }
1702
1703 /* deref old values */
1704 for (n = lwobj->size - 2; n > 0; --n) {
1705 del_lhs(a->data, v);
1706 i_del_value(v++);
1707 }
1708 } else {
1709 /* deref old values */
1710 for (n = lwobj->size - 2; n > 0; --n) {
1711 i_del_value(v++);
1712 }
1713 }
1714
1715 /* replace old with new */
1716 lwobj->size = nvar + 2;
1717 FREE(lwobj->elts);
1718 lwobj->elts = vars;
1719
1720 return obj;
1721 }
1722
1723 /*
1724 * NAME: data->import()
1725 * DESCRIPTION: copy imported arrays to current dataspace
1726 */
d_import(arrimport * imp,dataspace * data,value * val,unsigned short n)1727 static void d_import(arrimport *imp, dataspace *data, value *val,
1728 unsigned short n)
1729 {
1730 while (n > 0) {
1731 if (T_INDEXED(val->type)) {
1732 array *a;
1733 Uint i, j;
1734
1735 a = val->u.array;
1736 if (a->primary->data != data) {
1737 /*
1738 * imported array
1739 */
1740 i = arr_put(a, imp->narr);
1741 if (i == imp->narr) {
1742 /*
1743 * first time encountered
1744 */
1745 imp->narr++;
1746
1747 if (a->hashed != (struct _maphash_ *) NULL) {
1748 map_rmhash(a);
1749 }
1750
1751 if (a->ref == 2) { /* + 1 for array merge table */
1752 /*
1753 * move array to new dataspace
1754 */
1755 a->prev->next = a->next;
1756 a->next->prev = a->prev;
1757 } else {
1758 /*
1759 * make new array
1760 */
1761 a = arr_alloc(a->size);
1762 a->tag = val->u.array->tag;
1763 a->odcount = val->u.array->odcount;
1764
1765 if (a->size > 0) {
1766 /*
1767 * copy elements
1768 */
1769 i_copy(a->elts = ALLOC(value, a->size),
1770 d_get_elts(val->u.array), a->size);
1771 }
1772
1773 /*
1774 * replace
1775 */
1776 arr_del(val->u.array);
1777 arr_ref(val->u.array = a);
1778
1779 /*
1780 * store in itab
1781 */
1782 if (i >= imp->itabsz) {
1783 /*
1784 * increase size of itab
1785 */
1786 for (j = imp->itabsz; j <= i; j += j) ;
1787 imp->itab = REALLOC(imp->itab, array*, imp->itabsz,
1788 j);
1789 imp->itabsz = j;
1790 }
1791 arr_put(imp->itab[i] = a, imp->narr++);
1792 }
1793
1794 a->primary = &data->base.alocal;
1795 a->prev = &data->alist;
1796 a->next = data->alist.next;
1797 a->next->prev = a;
1798 data->alist.next = a;
1799
1800 if (a->size > 0) {
1801 /*
1802 * import elements too
1803 */
1804 d_import(imp, data, a->elts, a->size);
1805 }
1806 } else {
1807 /*
1808 * array was previously replaced
1809 */
1810 arr_ref(a = imp->itab[i]);
1811 arr_del(val->u.array);
1812 val->u.array = a;
1813 }
1814 } else if (arr_put(a, imp->narr) == imp->narr) {
1815 /*
1816 * not previously encountered mapping or array
1817 */
1818 imp->narr++;
1819 if (a->hashed != (struct _maphash_ *) NULL) {
1820 map_rmhash(a);
1821 d_import(imp, data, a->elts, a->size);
1822 } else if (a->elts != (value *) NULL) {
1823 d_import(imp, data, a->elts, a->size);
1824 }
1825 }
1826 }
1827 val++;
1828 --n;
1829 }
1830 }
1831
1832 /*
1833 * NAME: data->export()
1834 * DESCRIPTION: handle exporting of arrays shared by more than one object
1835 */
d_export()1836 void d_export()
1837 {
1838 dataspace *data;
1839 Uint n;
1840 arrimport imp;
1841
1842 if (ifirst != (dataspace *) NULL) {
1843 imp.itab = ALLOC(array*, imp.itabsz = 64);
1844
1845 for (data = ifirst; data != (dataspace *) NULL; data = data->inext) {
1846 if (data->base.imports != 0) {
1847 data->base.imports = 0;
1848 arr_merge();
1849 imp.narr = 0;
1850
1851 if (data->variables != (value *) NULL) {
1852 d_import(&imp, data, data->variables, data->nvariables);
1853 }
1854 if (data->base.arrays != (arrref *) NULL) {
1855 arrref *a;
1856
1857 for (n = data->narrays, a = data->base.arrays; n > 0;
1858 --n, a++) {
1859 if (a->arr != (array *) NULL) {
1860 if (a->arr->hashed != (struct _maphash_ *) NULL) {
1861 /* mapping */
1862 map_rmhash(a->arr);
1863 d_import(&imp, data, a->arr->elts,
1864 a->arr->size);
1865 } else if (a->arr->elts != (value *) NULL) {
1866 d_import(&imp, data, a->arr->elts,
1867 a->arr->size);
1868 }
1869 }
1870 }
1871 }
1872 if (data->callouts != (dcallout *) NULL) {
1873 dcallout *co;
1874
1875 co = data->callouts;
1876 for (n = data->ncallouts; n > 0; --n) {
1877 if (co->val[0].type == T_STRING) {
1878 d_import(&imp, data, co->val,
1879 (co->nargs > 3) ? 4 : co->nargs + 1);
1880 }
1881 co++;
1882 }
1883 }
1884 arr_clear(); /* clear merge table */
1885 }
1886 data->iprev = (dataspace *) NULL;
1887 }
1888 ifirst = (dataspace *) NULL;
1889
1890 FREE(imp.itab);
1891 }
1892 }
1893
1894
1895 /*
1896 * NAME: data->del_control()
1897 * DESCRIPTION: delete a control block from swap and memory
1898 */
d_del_control(control * ctrl)1899 void d_del_control(control *ctrl)
1900 {
1901 if (ctrl->sectors != (sector *) NULL) {
1902 sw_wipev(ctrl->sectors, ctrl->nsectors);
1903 sw_delv(ctrl->sectors, ctrl->nsectors);
1904 }
1905 d_free_control(ctrl);
1906 }
1907
1908 /*
1909 * NAME: data->del_dataspace()
1910 * DESCRIPTION: delete a dataspace block from swap and memory
1911 */
d_del_dataspace(dataspace * data)1912 void d_del_dataspace(dataspace *data)
1913 {
1914 if (data->iprev != (dataspace *) NULL) {
1915 data->iprev->inext = data->inext;
1916 if (data->inext != (dataspace *) NULL) {
1917 data->inext->iprev = data->iprev;
1918 }
1919 } else if (ifirst == data) {
1920 ifirst = data->inext;
1921 if (ifirst != (dataspace *) NULL) {
1922 ifirst->iprev = (dataspace *) NULL;
1923 }
1924 }
1925
1926 if (data->ncallouts != 0) {
1927 Uint n;
1928 dcallout *co;
1929 unsigned short dummy;
1930
1931 /*
1932 * remove callouts from callout table
1933 */
1934 if (data->callouts == (dcallout *) NULL) {
1935 d_get_callouts(data);
1936 }
1937 for (n = data->ncallouts, co = data->callouts + n; n > 0; --n) {
1938 if ((--co)->val[0].type == T_STRING) {
1939 d_del_call_out(data, n, &dummy);
1940 }
1941 }
1942 }
1943 if (data->sectors != (sector *) NULL) {
1944 sw_wipev(data->sectors, data->nsectors);
1945 sw_delv(data->sectors, data->nsectors);
1946 }
1947 d_free_dataspace(data);
1948 }
1949