xref: /plan9-contrib/sys/src/cmd/gs/src/zvmem.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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