17dd7cddfSDavid du Colombier /* Copyright (C) 1989, 1995, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: zvmem.c,v 1.8 2004/08/04 19:36:13 stefan Exp $ */
187dd7cddfSDavid du Colombier /* "Virtual memory" operators */
197dd7cddfSDavid du Colombier #include "ghost.h"
207dd7cddfSDavid du Colombier #include "gsstruct.h"
217dd7cddfSDavid du Colombier #include "oper.h"
227dd7cddfSDavid du Colombier #include "estack.h" /* for checking in restore */
237dd7cddfSDavid du Colombier #include "ialloc.h"
247dd7cddfSDavid du Colombier #include "idict.h" /* ditto */
257dd7cddfSDavid du Colombier #include "igstate.h"
267dd7cddfSDavid du Colombier #include "isave.h"
277dd7cddfSDavid du Colombier #include "dstack.h"
287dd7cddfSDavid du Colombier #include "stream.h" /* for files.h */
297dd7cddfSDavid du Colombier #include "files.h" /* for e-stack processing */
307dd7cddfSDavid du Colombier #include "store.h"
317dd7cddfSDavid du Colombier #include "gsmatrix.h" /* for gsstate.h */
327dd7cddfSDavid du Colombier #include "gsstate.h"
337dd7cddfSDavid du Colombier
347dd7cddfSDavid du Colombier /* Define whether we validate memory before/after save/restore. */
357dd7cddfSDavid du Colombier /* Note that we only actually do this if DEBUG is set and -Z? is selected. */
363ff48bf5SDavid du Colombier private const bool I_VALIDATE_BEFORE_SAVE = true;
373ff48bf5SDavid du Colombier private const bool I_VALIDATE_AFTER_SAVE = true;
383ff48bf5SDavid du Colombier private const bool I_VALIDATE_BEFORE_RESTORE = true;
393ff48bf5SDavid du Colombier private const bool I_VALIDATE_AFTER_RESTORE = true;
407dd7cddfSDavid du Colombier
417dd7cddfSDavid du Colombier /* 'Save' structure */
427dd7cddfSDavid du Colombier typedef struct vm_save_s vm_save_t;
437dd7cddfSDavid du Colombier struct vm_save_s {
447dd7cddfSDavid du Colombier gs_state *gsave; /* old graphics state */
457dd7cddfSDavid du Colombier };
467dd7cddfSDavid du Colombier
477dd7cddfSDavid du Colombier gs_private_st_ptrs1(st_vm_save, vm_save_t, "savetype",
487dd7cddfSDavid du Colombier vm_save_enum_ptrs, vm_save_reloc_ptrs, gsave);
497dd7cddfSDavid du Colombier
507dd7cddfSDavid du Colombier /* Clean up the stacks and validate storage. */
517dd7cddfSDavid du Colombier private void
ivalidate_clean_spaces(i_ctx_t * i_ctx_p)527dd7cddfSDavid du Colombier ivalidate_clean_spaces(i_ctx_t *i_ctx_p)
537dd7cddfSDavid du Colombier {
547dd7cddfSDavid du Colombier if (gs_debug_c('?')) {
557dd7cddfSDavid du Colombier ref_stack_cleanup(&d_stack);
567dd7cddfSDavid du Colombier ref_stack_cleanup(&e_stack);
577dd7cddfSDavid du Colombier ref_stack_cleanup(&o_stack);
587dd7cddfSDavid du Colombier ivalidate_spaces();
597dd7cddfSDavid du Colombier }
607dd7cddfSDavid du Colombier }
617dd7cddfSDavid du Colombier
627dd7cddfSDavid du Colombier /* - save <save> */
637dd7cddfSDavid du Colombier int
zsave(i_ctx_t * i_ctx_p)647dd7cddfSDavid du Colombier zsave(i_ctx_t *i_ctx_p)
657dd7cddfSDavid du Colombier {
667dd7cddfSDavid du Colombier os_ptr op = osp;
677dd7cddfSDavid du Colombier uint space = icurrent_space;
687dd7cddfSDavid du Colombier vm_save_t *vmsave;
697dd7cddfSDavid du Colombier ulong sid;
707dd7cddfSDavid du Colombier int code;
717dd7cddfSDavid du Colombier gs_state *prev;
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier if (I_VALIDATE_BEFORE_SAVE)
747dd7cddfSDavid du Colombier ivalidate_clean_spaces(i_ctx_p);
757dd7cddfSDavid du Colombier ialloc_set_space(idmemory, avm_local);
767dd7cddfSDavid du Colombier vmsave = ialloc_struct(vm_save_t, &st_vm_save, "zsave");
777dd7cddfSDavid du Colombier ialloc_set_space(idmemory, space);
787dd7cddfSDavid du Colombier if (vmsave == 0)
797dd7cddfSDavid du Colombier return_error(e_VMerror);
807dd7cddfSDavid du Colombier sid = alloc_save_state(idmemory, vmsave);
817dd7cddfSDavid du Colombier if (sid == 0) {
827dd7cddfSDavid du Colombier ifree_object(vmsave, "zsave");
837dd7cddfSDavid du Colombier return_error(e_VMerror);
847dd7cddfSDavid du Colombier }
857dd7cddfSDavid du Colombier if_debug2('u', "[u]vmsave 0x%lx, id = %lu\n",
867dd7cddfSDavid du Colombier (ulong) vmsave, (ulong) sid);
877dd7cddfSDavid du Colombier code = gs_gsave_for_save(igs, &prev);
887dd7cddfSDavid du Colombier if (code < 0)
897dd7cddfSDavid du Colombier return code;
907dd7cddfSDavid du Colombier code = gs_gsave(igs);
917dd7cddfSDavid du Colombier if (code < 0)
927dd7cddfSDavid du Colombier return code;
937dd7cddfSDavid du Colombier vmsave->gsave = prev;
947dd7cddfSDavid du Colombier push(1);
957dd7cddfSDavid du Colombier make_tav(op, t_save, 0, saveid, sid);
967dd7cddfSDavid du Colombier if (I_VALIDATE_AFTER_SAVE)
977dd7cddfSDavid du Colombier ivalidate_clean_spaces(i_ctx_p);
987dd7cddfSDavid du Colombier return 0;
997dd7cddfSDavid du Colombier }
1007dd7cddfSDavid du Colombier
1017dd7cddfSDavid du Colombier /* <save> restore - */
102*593dc095SDavid du Colombier private int restore_check_operand(os_ptr, alloc_save_t **, gs_dual_memory_t *);
103*593dc095SDavid du Colombier private int restore_check_stack(const ref_stack_t *, const alloc_save_t *, bool);
104*593dc095SDavid du Colombier private void restore_fix_stack(ref_stack_t *, const alloc_save_t *, bool);
1057dd7cddfSDavid du Colombier int
zrestore(i_ctx_t * i_ctx_p)1067dd7cddfSDavid du Colombier zrestore(i_ctx_t *i_ctx_p)
1077dd7cddfSDavid du Colombier {
1087dd7cddfSDavid du Colombier os_ptr op = osp;
1097dd7cddfSDavid du Colombier alloc_save_t *asave;
1107dd7cddfSDavid du Colombier bool last;
1117dd7cddfSDavid du Colombier vm_save_t *vmsave;
1127dd7cddfSDavid du Colombier int code = restore_check_operand(op, &asave, idmemory);
1137dd7cddfSDavid du Colombier
1147dd7cddfSDavid du Colombier if (code < 0)
1157dd7cddfSDavid du Colombier return code;
1167dd7cddfSDavid du Colombier if_debug2('u', "[u]vmrestore 0x%lx, id = %lu\n",
1177dd7cddfSDavid du Colombier (ulong) alloc_save_client_data(asave),
1187dd7cddfSDavid du Colombier (ulong) op->value.saveid);
1197dd7cddfSDavid du Colombier if (I_VALIDATE_BEFORE_RESTORE)
1207dd7cddfSDavid du Colombier ivalidate_clean_spaces(i_ctx_p);
1217dd7cddfSDavid du Colombier /* Check the contents of the stacks. */
1227dd7cddfSDavid du Colombier osp--;
1237dd7cddfSDavid du Colombier {
1247dd7cddfSDavid du Colombier int code;
1257dd7cddfSDavid du Colombier
1267dd7cddfSDavid du Colombier if ((code = restore_check_stack(&o_stack, asave, false)) < 0 ||
1277dd7cddfSDavid du Colombier (code = restore_check_stack(&e_stack, asave, true)) < 0 ||
1287dd7cddfSDavid du Colombier (code = restore_check_stack(&d_stack, asave, false)) < 0
1297dd7cddfSDavid du Colombier ) {
1307dd7cddfSDavid du Colombier osp++;
1317dd7cddfSDavid du Colombier return code;
1327dd7cddfSDavid du Colombier }
1337dd7cddfSDavid du Colombier }
1347dd7cddfSDavid du Colombier /* Reset l_new in all stack entries if the new save level is zero. */
1357dd7cddfSDavid du Colombier /* Also do some special fixing on the e-stack. */
1367dd7cddfSDavid du Colombier restore_fix_stack(&o_stack, asave, false);
1377dd7cddfSDavid du Colombier restore_fix_stack(&e_stack, asave, true);
1387dd7cddfSDavid du Colombier restore_fix_stack(&d_stack, asave, false);
1397dd7cddfSDavid du Colombier /* Iteratively restore the state of memory, */
1407dd7cddfSDavid du Colombier /* also doing a grestoreall at each step. */
1417dd7cddfSDavid du Colombier do {
1427dd7cddfSDavid du Colombier vmsave = alloc_save_client_data(alloc_save_current(idmemory));
1437dd7cddfSDavid du Colombier /* Restore the graphics state. */
1447dd7cddfSDavid du Colombier gs_grestoreall_for_restore(igs, vmsave->gsave);
1457dd7cddfSDavid du Colombier /*
1467dd7cddfSDavid du Colombier * If alloc_save_space decided to do a second save, the vmsave
1477dd7cddfSDavid du Colombier * object was allocated one save level less deep than the
1487dd7cddfSDavid du Colombier * current level, so ifree_object won't actually free it;
1497dd7cddfSDavid du Colombier * however, it points to a gsave object that definitely
1507dd7cddfSDavid du Colombier * *has* been freed. In order not to trip up the garbage
1517dd7cddfSDavid du Colombier * collector, we clear the gsave pointer now.
1527dd7cddfSDavid du Colombier */
1537dd7cddfSDavid du Colombier vmsave->gsave = 0;
1547dd7cddfSDavid du Colombier /* Now it's safe to restore the state of memory. */
1557dd7cddfSDavid du Colombier last = alloc_restore_state_step(asave);
1567dd7cddfSDavid du Colombier }
1577dd7cddfSDavid du Colombier while (!last);
1587dd7cddfSDavid du Colombier {
1597dd7cddfSDavid du Colombier uint space = icurrent_space;
1607dd7cddfSDavid du Colombier
1617dd7cddfSDavid du Colombier ialloc_set_space(idmemory, avm_local);
1627dd7cddfSDavid du Colombier ifree_object(vmsave, "zrestore");
1637dd7cddfSDavid du Colombier ialloc_set_space(idmemory, space);
1647dd7cddfSDavid du Colombier }
1657dd7cddfSDavid du Colombier dict_set_top(); /* reload dict stack cache */
1667dd7cddfSDavid du Colombier if (I_VALIDATE_AFTER_RESTORE)
1677dd7cddfSDavid du Colombier ivalidate_clean_spaces(i_ctx_p);
1683ff48bf5SDavid du Colombier /* If the i_ctx_p LockFilePermissions is true, but the userparams */
1693ff48bf5SDavid du Colombier /* we just restored is false, we need to make sure that we do not */
1703ff48bf5SDavid du Colombier /* cause an 'invalidaccess' in setuserparams. Temporarily set */
1713ff48bf5SDavid du Colombier /* LockFilePermissions false until the gs_lev2.ps can do a */
1723ff48bf5SDavid du Colombier /* setuserparams from the restored userparam dictionary. */
1733ff48bf5SDavid du Colombier i_ctx_p->LockFilePermissions = false;
1747dd7cddfSDavid du Colombier return 0;
1757dd7cddfSDavid du Colombier }
1767dd7cddfSDavid du Colombier /* Check the operand of a restore. */
1777dd7cddfSDavid du Colombier private int
restore_check_operand(os_ptr op,alloc_save_t ** pasave,gs_dual_memory_t * idmem)1787dd7cddfSDavid du Colombier restore_check_operand(os_ptr op, alloc_save_t ** pasave,
1797dd7cddfSDavid du Colombier gs_dual_memory_t *idmem)
1807dd7cddfSDavid du Colombier {
1817dd7cddfSDavid du Colombier vm_save_t *vmsave;
1827dd7cddfSDavid du Colombier ulong sid;
1837dd7cddfSDavid du Colombier alloc_save_t *asave;
1847dd7cddfSDavid du Colombier
1857dd7cddfSDavid du Colombier check_type(*op, t_save);
1867dd7cddfSDavid du Colombier vmsave = r_ptr(op, vm_save_t);
1877dd7cddfSDavid du Colombier if (vmsave == 0) /* invalidated save */
1887dd7cddfSDavid du Colombier return_error(e_invalidrestore);
1897dd7cddfSDavid du Colombier sid = op->value.saveid;
1907dd7cddfSDavid du Colombier asave = alloc_find_save(idmem, sid);
1917dd7cddfSDavid du Colombier if (asave == 0)
1927dd7cddfSDavid du Colombier return_error(e_invalidrestore);
1937dd7cddfSDavid du Colombier *pasave = asave;
1947dd7cddfSDavid du Colombier return 0;
1957dd7cddfSDavid du Colombier }
1967dd7cddfSDavid du Colombier /* Check a stack to make sure all its elements are older than a save. */
1977dd7cddfSDavid du Colombier private int
restore_check_stack(const ref_stack_t * pstack,const alloc_save_t * asave,bool is_estack)1987dd7cddfSDavid du Colombier restore_check_stack(const ref_stack_t * pstack, const alloc_save_t * asave,
1997dd7cddfSDavid du Colombier bool is_estack)
2007dd7cddfSDavid du Colombier {
2017dd7cddfSDavid du Colombier ref_stack_enum_t rsenum;
2027dd7cddfSDavid du Colombier
2037dd7cddfSDavid du Colombier ref_stack_enum_begin(&rsenum, pstack);
2047dd7cddfSDavid du Colombier do {
2057dd7cddfSDavid du Colombier const ref *stkp = rsenum.ptr;
2067dd7cddfSDavid du Colombier uint size = rsenum.size;
2077dd7cddfSDavid du Colombier
2087dd7cddfSDavid du Colombier for (; size; stkp++, size--) {
2097dd7cddfSDavid du Colombier const void *ptr;
2107dd7cddfSDavid du Colombier
2117dd7cddfSDavid du Colombier switch (r_type(stkp)) {
2127dd7cddfSDavid du Colombier case t_array:
2137dd7cddfSDavid du Colombier ptr = stkp->value.refs;
2147dd7cddfSDavid du Colombier break;
2157dd7cddfSDavid du Colombier case t_dictionary:
2167dd7cddfSDavid du Colombier ptr = stkp->value.pdict;
2177dd7cddfSDavid du Colombier break;
2187dd7cddfSDavid du Colombier case t_file:
2197dd7cddfSDavid du Colombier /* Don't check executable or closed literal */
2207dd7cddfSDavid du Colombier /* files on the e-stack. */
2217dd7cddfSDavid du Colombier {
2227dd7cddfSDavid du Colombier stream *s;
2237dd7cddfSDavid du Colombier
2247dd7cddfSDavid du Colombier if (is_estack &&
2257dd7cddfSDavid du Colombier (r_has_attr(stkp, a_executable) ||
2267dd7cddfSDavid du Colombier file_is_invalid(s, stkp))
2277dd7cddfSDavid du Colombier )
2287dd7cddfSDavid du Colombier continue;
2297dd7cddfSDavid du Colombier }
2307dd7cddfSDavid du Colombier ptr = stkp->value.pfile;
2317dd7cddfSDavid du Colombier break;
2327dd7cddfSDavid du Colombier case t_name:
2337dd7cddfSDavid du Colombier /* Names are special because of how they are allocated. */
234*593dc095SDavid du Colombier if (alloc_name_is_since_save((const gs_memory_t *)pstack->memory,
235*593dc095SDavid du Colombier stkp, asave))
2367dd7cddfSDavid du Colombier return_error(e_invalidrestore);
2377dd7cddfSDavid du Colombier continue;
2387dd7cddfSDavid du Colombier case t_string:
2397dd7cddfSDavid du Colombier /* Don't check empty executable strings */
2407dd7cddfSDavid du Colombier /* on the e-stack. */
2417dd7cddfSDavid du Colombier if (r_size(stkp) == 0 &&
2427dd7cddfSDavid du Colombier r_has_attr(stkp, a_executable) && is_estack
2437dd7cddfSDavid du Colombier )
2447dd7cddfSDavid du Colombier continue;
2457dd7cddfSDavid du Colombier ptr = stkp->value.bytes;
2467dd7cddfSDavid du Colombier break;
2477dd7cddfSDavid du Colombier case t_mixedarray:
2487dd7cddfSDavid du Colombier case t_shortarray:
2497dd7cddfSDavid du Colombier ptr = stkp->value.packed;
2507dd7cddfSDavid du Colombier break;
2517dd7cddfSDavid du Colombier case t_device:
2527dd7cddfSDavid du Colombier ptr = stkp->value.pdevice;
2537dd7cddfSDavid du Colombier break;
2547dd7cddfSDavid du Colombier case t_fontID:
2557dd7cddfSDavid du Colombier case t_struct:
2567dd7cddfSDavid du Colombier case t_astruct:
2577dd7cddfSDavid du Colombier ptr = stkp->value.pstruct;
2587dd7cddfSDavid du Colombier break;
2597dd7cddfSDavid du Colombier default:
2607dd7cddfSDavid du Colombier continue;
2617dd7cddfSDavid du Colombier }
2627dd7cddfSDavid du Colombier if (alloc_is_since_save(ptr, asave))
2637dd7cddfSDavid du Colombier return_error(e_invalidrestore);
2647dd7cddfSDavid du Colombier }
2657dd7cddfSDavid du Colombier } while (ref_stack_enum_next(&rsenum));
2667dd7cddfSDavid du Colombier return 0; /* OK */
2677dd7cddfSDavid du Colombier }
2687dd7cddfSDavid du Colombier /*
2697dd7cddfSDavid du Colombier * If the new save level is zero, fix up the contents of a stack
2707dd7cddfSDavid du Colombier * by clearing the l_new bit in all the entries (since we can't tolerate
2717dd7cddfSDavid du Colombier * values with l_new set if the save level is zero).
2727dd7cddfSDavid du Colombier * Also, in any case, fix up the e-stack by replacing empty executable
2737dd7cddfSDavid du Colombier * strings and closed executable files that are newer than the save
2747dd7cddfSDavid du Colombier * with canonical ones that aren't.
2757dd7cddfSDavid du Colombier *
2767dd7cddfSDavid du Colombier * Note that this procedure is only called if restore_check_stack succeeded.
2777dd7cddfSDavid du Colombier */
2787dd7cddfSDavid du Colombier private void
restore_fix_stack(ref_stack_t * pstack,const alloc_save_t * asave,bool is_estack)2797dd7cddfSDavid du Colombier restore_fix_stack(ref_stack_t * pstack, const alloc_save_t * asave,
2807dd7cddfSDavid du Colombier bool is_estack)
2817dd7cddfSDavid du Colombier {
2827dd7cddfSDavid du Colombier ref_stack_enum_t rsenum;
2837dd7cddfSDavid du Colombier
2847dd7cddfSDavid du Colombier ref_stack_enum_begin(&rsenum, pstack);
2857dd7cddfSDavid du Colombier do {
2867dd7cddfSDavid du Colombier ref *stkp = rsenum.ptr;
2877dd7cddfSDavid du Colombier uint size = rsenum.size;
2887dd7cddfSDavid du Colombier
2897dd7cddfSDavid du Colombier for (; size; stkp++, size--) {
2907dd7cddfSDavid du Colombier r_clear_attrs(stkp, l_new); /* always do it, no harm */
2917dd7cddfSDavid du Colombier if (is_estack) {
2927dd7cddfSDavid du Colombier ref ofile;
2937dd7cddfSDavid du Colombier
2947dd7cddfSDavid du Colombier ref_assign(&ofile, stkp);
2957dd7cddfSDavid du Colombier switch (r_type(stkp)) {
2967dd7cddfSDavid du Colombier case t_string:
2977dd7cddfSDavid du Colombier if (r_size(stkp) == 0 &&
2987dd7cddfSDavid du Colombier alloc_is_since_save(stkp->value.bytes,
2997dd7cddfSDavid du Colombier asave)
3007dd7cddfSDavid du Colombier ) {
3017dd7cddfSDavid du Colombier make_empty_const_string(stkp,
3027dd7cddfSDavid du Colombier avm_foreign);
3037dd7cddfSDavid du Colombier break;
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier continue;
3067dd7cddfSDavid du Colombier case t_file:
3077dd7cddfSDavid du Colombier if (alloc_is_since_save(stkp->value.pfile,
3087dd7cddfSDavid du Colombier asave)
3097dd7cddfSDavid du Colombier ) {
3107dd7cddfSDavid du Colombier make_invalid_file(stkp);
3117dd7cddfSDavid du Colombier break;
3127dd7cddfSDavid du Colombier }
3137dd7cddfSDavid du Colombier continue;
3147dd7cddfSDavid du Colombier default:
3157dd7cddfSDavid du Colombier continue;
3167dd7cddfSDavid du Colombier }
3177dd7cddfSDavid du Colombier r_copy_attrs(stkp, a_all | a_executable,
3187dd7cddfSDavid du Colombier &ofile);
3197dd7cddfSDavid du Colombier }
3207dd7cddfSDavid du Colombier }
3217dd7cddfSDavid du Colombier } while (ref_stack_enum_next(&rsenum));
3227dd7cddfSDavid du Colombier }
3237dd7cddfSDavid du Colombier
3247dd7cddfSDavid du Colombier /* - vmstatus <save_level> <vm_used> <vm_maximum> */
3257dd7cddfSDavid du Colombier private int
zvmstatus(i_ctx_t * i_ctx_p)3267dd7cddfSDavid du Colombier zvmstatus(i_ctx_t *i_ctx_p)
3277dd7cddfSDavid du Colombier {
3287dd7cddfSDavid du Colombier os_ptr op = osp;
3297dd7cddfSDavid du Colombier gs_memory_status_t mstat, dstat;
3307dd7cddfSDavid du Colombier
3317dd7cddfSDavid du Colombier gs_memory_status(imemory, &mstat);
3327dd7cddfSDavid du Colombier if (imemory == imemory_global) {
3337dd7cddfSDavid du Colombier gs_memory_status_t sstat;
3347dd7cddfSDavid du Colombier
3357dd7cddfSDavid du Colombier gs_memory_status(imemory_system, &sstat);
3367dd7cddfSDavid du Colombier mstat.allocated += sstat.allocated;
3377dd7cddfSDavid du Colombier mstat.used += sstat.used;
3387dd7cddfSDavid du Colombier }
339*593dc095SDavid du Colombier gs_memory_status(imemory->non_gc_memory, &dstat);
3407dd7cddfSDavid du Colombier push(3);
3417dd7cddfSDavid du Colombier make_int(op - 2, imemory_save_level(iimemory_local));
3427dd7cddfSDavid du Colombier make_int(op - 1, mstat.used);
3437dd7cddfSDavid du Colombier make_int(op, mstat.allocated + dstat.allocated - dstat.used);
3447dd7cddfSDavid du Colombier return 0;
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier /* ------ Non-standard extensions ------ */
3487dd7cddfSDavid du Colombier
3497dd7cddfSDavid du Colombier /* <save> .forgetsave - */
3507dd7cddfSDavid du Colombier private int
zforgetsave(i_ctx_t * i_ctx_p)3517dd7cddfSDavid du Colombier zforgetsave(i_ctx_t *i_ctx_p)
3527dd7cddfSDavid du Colombier {
3537dd7cddfSDavid du Colombier os_ptr op = osp;
3547dd7cddfSDavid du Colombier alloc_save_t *asave;
3557dd7cddfSDavid du Colombier vm_save_t *vmsave;
3567dd7cddfSDavid du Colombier int code = restore_check_operand(op, &asave, idmemory);
3577dd7cddfSDavid du Colombier
3587dd7cddfSDavid du Colombier if (code < 0)
3597dd7cddfSDavid du Colombier return 0;
3607dd7cddfSDavid du Colombier vmsave = alloc_save_client_data(asave);
3617dd7cddfSDavid du Colombier /* Reset l_new in all stack entries if the new save level is zero. */
3627dd7cddfSDavid du Colombier restore_fix_stack(&o_stack, asave, false);
3637dd7cddfSDavid du Colombier restore_fix_stack(&e_stack, asave, false);
3647dd7cddfSDavid du Colombier restore_fix_stack(&d_stack, asave, false);
3657dd7cddfSDavid du Colombier /*
3667dd7cddfSDavid du Colombier * Forget the gsaves, by deleting the bottom gstate on
3677dd7cddfSDavid du Colombier * the current stack and the top one on the saved stack and then
3687dd7cddfSDavid du Colombier * concatenating the stacks together.
3697dd7cddfSDavid du Colombier */
3707dd7cddfSDavid du Colombier {
3717dd7cddfSDavid du Colombier gs_state *pgs = igs;
3727dd7cddfSDavid du Colombier gs_state *last;
3737dd7cddfSDavid du Colombier
3747dd7cddfSDavid du Colombier while (gs_state_saved(last = gs_state_saved(pgs)) != 0)
3757dd7cddfSDavid du Colombier pgs = last;
3767dd7cddfSDavid du Colombier gs_state_swap_saved(last, vmsave->gsave);
3777dd7cddfSDavid du Colombier gs_grestore(last);
3787dd7cddfSDavid du Colombier gs_grestore(last);
3797dd7cddfSDavid du Colombier }
3807dd7cddfSDavid du Colombier /* Forget the save in the memory manager. */
3817dd7cddfSDavid du Colombier alloc_forget_save(asave);
3827dd7cddfSDavid du Colombier {
3837dd7cddfSDavid du Colombier uint space = icurrent_space;
3847dd7cddfSDavid du Colombier
3857dd7cddfSDavid du Colombier ialloc_set_space(idmemory, avm_local);
3867dd7cddfSDavid du Colombier /* See above for why we clear the gsave pointer here. */
3877dd7cddfSDavid du Colombier vmsave->gsave = 0;
3887dd7cddfSDavid du Colombier ifree_object(vmsave, "zrestore");
3897dd7cddfSDavid du Colombier ialloc_set_space(idmemory, space);
3907dd7cddfSDavid du Colombier }
3917dd7cddfSDavid du Colombier pop(1);
3927dd7cddfSDavid du Colombier return 0;
3937dd7cddfSDavid du Colombier }
3947dd7cddfSDavid du Colombier
3957dd7cddfSDavid du Colombier /* ------ Initialization procedure ------ */
3967dd7cddfSDavid du Colombier
3977dd7cddfSDavid du Colombier const op_def zvmem_op_defs[] =
3987dd7cddfSDavid du Colombier {
3997dd7cddfSDavid du Colombier {"1.forgetsave", zforgetsave},
4007dd7cddfSDavid du Colombier {"1restore", zrestore},
4017dd7cddfSDavid du Colombier {"0save", zsave},
4027dd7cddfSDavid du Colombier {"0vmstatus", zvmstatus},
4037dd7cddfSDavid du Colombier op_def_end(0)
4047dd7cddfSDavid du Colombier };
405