xref: /plan9-contrib/sys/src/cmd/gs/src/icontext.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 1997, 2000 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: icontext.c,v 1.17 2003/10/09 00:13:30 igor Exp $ */
187dd7cddfSDavid du Colombier /* Context state operations */
197dd7cddfSDavid du Colombier #include "ghost.h"
207dd7cddfSDavid du Colombier #include "gsstruct.h"		/* for gxalloc.h */
217dd7cddfSDavid du Colombier #include "gxalloc.h"
22*593dc095SDavid du Colombier #include "ierrors.h"
237dd7cddfSDavid du Colombier #include "stream.h"		/* for files.h */
247dd7cddfSDavid du Colombier #include "files.h"
257dd7cddfSDavid du Colombier #include "idict.h"
267dd7cddfSDavid du Colombier #include "igstate.h"
277dd7cddfSDavid du Colombier #include "icontext.h"
287dd7cddfSDavid du Colombier #include "interp.h"
297dd7cddfSDavid du Colombier #include "isave.h"
307dd7cddfSDavid du Colombier #include "dstack.h"
317dd7cddfSDavid du Colombier #include "estack.h"
327dd7cddfSDavid du Colombier #include "store.h"
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier /* Declare the GC descriptors for embedded objects. */
357dd7cddfSDavid du Colombier extern_st(st_gs_dual_memory);
367dd7cddfSDavid du Colombier extern_st(st_ref_stack);
377dd7cddfSDavid du Colombier extern_st(st_dict_stack);
387dd7cddfSDavid du Colombier extern_st(st_exec_stack);
397dd7cddfSDavid du Colombier extern_st(st_op_stack);
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier /* GC descriptors */
427dd7cddfSDavid du Colombier private
CLEAR_MARKS_PROC(context_state_clear_marks)437dd7cddfSDavid du Colombier CLEAR_MARKS_PROC(context_state_clear_marks)
447dd7cddfSDavid du Colombier {
457dd7cddfSDavid du Colombier     gs_context_state_t *const pcst = vptr;
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier     r_clear_attrs(&pcst->stdio[0], l_mark);
487dd7cddfSDavid du Colombier     r_clear_attrs(&pcst->stdio[1], l_mark);
497dd7cddfSDavid du Colombier     r_clear_attrs(&pcst->stdio[2], l_mark);
507dd7cddfSDavid du Colombier     r_clear_attrs(&pcst->userparams, l_mark);
517dd7cddfSDavid du Colombier }
527dd7cddfSDavid du Colombier private
ENUM_PTRS_WITH(context_state_enum_ptrs,gs_context_state_t * pcst)537dd7cddfSDavid du Colombier ENUM_PTRS_WITH(context_state_enum_ptrs, gs_context_state_t *pcst) {
547dd7cddfSDavid du Colombier     index -= 5;
557dd7cddfSDavid du Colombier     if (index < st_gs_dual_memory_num_ptrs)
567dd7cddfSDavid du Colombier 	return ENUM_USING(st_gs_dual_memory, &pcst->memory,
577dd7cddfSDavid du Colombier 			  sizeof(pcst->memory), index);
587dd7cddfSDavid du Colombier     index -= st_gs_dual_memory_num_ptrs;
597dd7cddfSDavid du Colombier     if (index < st_dict_stack_num_ptrs)
607dd7cddfSDavid du Colombier 	return ENUM_USING(st_dict_stack, &pcst->dict_stack,
617dd7cddfSDavid du Colombier 			  sizeof(pcst->dict_stack), index);
627dd7cddfSDavid du Colombier     index -= st_dict_stack_num_ptrs;
637dd7cddfSDavid du Colombier     if (index < st_exec_stack_num_ptrs)
647dd7cddfSDavid du Colombier 	return ENUM_USING(st_exec_stack, &pcst->exec_stack,
657dd7cddfSDavid du Colombier 			  sizeof(pcst->exec_stack), index);
667dd7cddfSDavid du Colombier     index -= st_exec_stack_num_ptrs;
677dd7cddfSDavid du Colombier     return ENUM_USING(st_op_stack, &pcst->op_stack,
687dd7cddfSDavid du Colombier 		      sizeof(pcst->op_stack), index);
697dd7cddfSDavid du Colombier     }
707dd7cddfSDavid du Colombier     ENUM_PTR(0, gs_context_state_t, pgs);
717dd7cddfSDavid du Colombier     case 1: ENUM_RETURN_REF(&pcst->stdio[0]);
727dd7cddfSDavid du Colombier     case 2: ENUM_RETURN_REF(&pcst->stdio[1]);
737dd7cddfSDavid du Colombier     case 3: ENUM_RETURN_REF(&pcst->stdio[2]);
747dd7cddfSDavid du Colombier     case 4: ENUM_RETURN_REF(&pcst->userparams);
757dd7cddfSDavid du Colombier ENUM_PTRS_END
767dd7cddfSDavid du Colombier private RELOC_PTRS_WITH(context_state_reloc_ptrs, gs_context_state_t *pcst);
777dd7cddfSDavid du Colombier     RELOC_PTR(gs_context_state_t, pgs);
787dd7cddfSDavid du Colombier     RELOC_USING(st_gs_dual_memory, &pcst->memory, sizeof(pcst->memory));
797dd7cddfSDavid du Colombier     RELOC_REF_VAR(pcst->stdio[0]);
807dd7cddfSDavid du Colombier     RELOC_REF_VAR(pcst->stdio[1]);
817dd7cddfSDavid du Colombier     RELOC_REF_VAR(pcst->stdio[2]);
827dd7cddfSDavid du Colombier     RELOC_REF_VAR(pcst->userparams);
837dd7cddfSDavid du Colombier     r_clear_attrs(&pcst->userparams, l_mark);
847dd7cddfSDavid du Colombier     RELOC_USING(st_dict_stack, &pcst->dict_stack, sizeof(pcst->dict_stack));
857dd7cddfSDavid du Colombier     RELOC_USING(st_exec_stack, &pcst->exec_stack, sizeof(pcst->exec_stack));
867dd7cddfSDavid du Colombier     RELOC_USING(st_op_stack, &pcst->op_stack, sizeof(pcst->op_stack));
877dd7cddfSDavid du Colombier RELOC_PTRS_END
887dd7cddfSDavid du Colombier public_st_context_state();
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier /* Allocate the state of a context. */
917dd7cddfSDavid du Colombier int
context_state_alloc(gs_context_state_t ** ppcst,const ref * psystem_dict,const gs_dual_memory_t * dmem)927dd7cddfSDavid du Colombier context_state_alloc(gs_context_state_t ** ppcst,
937dd7cddfSDavid du Colombier 		    const ref *psystem_dict,
947dd7cddfSDavid du Colombier 		    const gs_dual_memory_t * dmem)
957dd7cddfSDavid du Colombier {
967dd7cddfSDavid du Colombier     gs_ref_memory_t *mem = dmem->space_local;
977dd7cddfSDavid du Colombier     gs_context_state_t *pcst = *ppcst;
987dd7cddfSDavid du Colombier     int code;
997dd7cddfSDavid du Colombier     int i;
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier     if (pcst == 0) {
1027dd7cddfSDavid du Colombier 	pcst = gs_alloc_struct((gs_memory_t *) mem, gs_context_state_t,
1037dd7cddfSDavid du Colombier 			       &st_context_state, "context_state_alloc");
1047dd7cddfSDavid du Colombier 	if (pcst == 0)
1057dd7cddfSDavid du Colombier 	    return_error(e_VMerror);
1067dd7cddfSDavid du Colombier     }
1077dd7cddfSDavid du Colombier     code = gs_interp_alloc_stacks(mem, pcst);
1087dd7cddfSDavid du Colombier     if (code < 0)
1097dd7cddfSDavid du Colombier 	goto x0;
1107dd7cddfSDavid du Colombier     /*
1117dd7cddfSDavid du Colombier      * We have to initialize the dictionary stack early,
1127dd7cddfSDavid du Colombier      * for far-off references to systemdict.
1137dd7cddfSDavid du Colombier      */
1147dd7cddfSDavid du Colombier     pcst->dict_stack.system_dict = *psystem_dict;
1157dd7cddfSDavid du Colombier     pcst->dict_stack.min_size = 0;
116*593dc095SDavid du Colombier     pcst->dict_stack.userdict_index = 0;
1177dd7cddfSDavid du Colombier     pcst->pgs = int_gstate_alloc(dmem);
1187dd7cddfSDavid du Colombier     if (pcst->pgs == 0) {
1197dd7cddfSDavid du Colombier 	code = gs_note_error(e_VMerror);
1207dd7cddfSDavid du Colombier 	goto x1;
1217dd7cddfSDavid du Colombier     }
1227dd7cddfSDavid du Colombier     pcst->memory = *dmem;
1237dd7cddfSDavid du Colombier     pcst->language_level = 1;
1247dd7cddfSDavid du Colombier     make_false(&pcst->array_packing);
1257dd7cddfSDavid du Colombier     make_int(&pcst->binary_object_format, 0);
1267dd7cddfSDavid du Colombier     pcst->rand_state = rand_state_initial;
1277dd7cddfSDavid du Colombier     pcst->usertime_total = 0;
1287dd7cddfSDavid du Colombier     pcst->keep_usertime = false;
1293ff48bf5SDavid du Colombier     pcst->in_superexec = 0;
130*593dc095SDavid du Colombier     pcst->plugin_list = 0;
1317dd7cddfSDavid du Colombier     {	/*
1327dd7cddfSDavid du Colombier 	 * Create an empty userparams dictionary of the right size.
1337dd7cddfSDavid du Colombier 	 * If we can't determine the size, pick an arbitrary one.
1347dd7cddfSDavid du Colombier 	 */
1357dd7cddfSDavid du Colombier 	ref *puserparams;
1367dd7cddfSDavid du Colombier 	uint size;
1377dd7cddfSDavid du Colombier 	ref *system_dict = &pcst->dict_stack.system_dict;
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier 	if (dict_find_string(system_dict, "userparams", &puserparams) >= 0)
1407dd7cddfSDavid du Colombier 	    size = dict_length(puserparams);
1417dd7cddfSDavid du Colombier 	else
142*593dc095SDavid du Colombier 	    size = 30;
1437dd7cddfSDavid du Colombier 	code = dict_alloc(pcst->memory.space_local, size, &pcst->userparams);
1447dd7cddfSDavid du Colombier 	if (code < 0)
1457dd7cddfSDavid du Colombier 	    goto x2;
1467dd7cddfSDavid du Colombier 	/* PostScript code initializes the user parameters. */
1477dd7cddfSDavid du Colombier     }
1483ff48bf5SDavid du Colombier     pcst->scanner_options = 0;
1493ff48bf5SDavid du Colombier     pcst->LockFilePermissions = false;
150*593dc095SDavid du Colombier     pcst->starting_arg_file = false;
1517dd7cddfSDavid du Colombier     /* The initial stdio values are bogus.... */
1527dd7cddfSDavid du Colombier     make_file(&pcst->stdio[0], a_readonly | avm_invalid_file_entry, 1,
1537dd7cddfSDavid du Colombier 	      invalid_file_entry);
1547dd7cddfSDavid du Colombier     make_file(&pcst->stdio[1], a_all | avm_invalid_file_entry, 1,
1557dd7cddfSDavid du Colombier 	      invalid_file_entry);
1567dd7cddfSDavid du Colombier     make_file(&pcst->stdio[2], a_all | avm_invalid_file_entry, 1,
1577dd7cddfSDavid du Colombier 	      invalid_file_entry);
1587dd7cddfSDavid du Colombier     for (i = countof(pcst->memory.spaces_indexed); --i >= 0;)
1597dd7cddfSDavid du Colombier 	if (dmem->spaces_indexed[i] != 0)
1607dd7cddfSDavid du Colombier 	    ++(dmem->spaces_indexed[i]->num_contexts);
1617dd7cddfSDavid du Colombier     *ppcst = pcst;
1627dd7cddfSDavid du Colombier     return 0;
1637dd7cddfSDavid du Colombier   x2:gs_state_free(pcst->pgs);
1647dd7cddfSDavid du Colombier   x1:gs_interp_free_stacks(mem, pcst);
1657dd7cddfSDavid du Colombier   x0:if (*ppcst == 0)
1667dd7cddfSDavid du Colombier 	gs_free_object((gs_memory_t *) mem, pcst, "context_state_alloc");
1677dd7cddfSDavid du Colombier     return code;
1687dd7cddfSDavid du Colombier }
1697dd7cddfSDavid du Colombier 
1707dd7cddfSDavid du Colombier /* Load the interpreter state from a context. */
1717dd7cddfSDavid du Colombier int
context_state_load(gs_context_state_t * i_ctx_p)1727dd7cddfSDavid du Colombier context_state_load(gs_context_state_t * i_ctx_p)
1737dd7cddfSDavid du Colombier {
1747dd7cddfSDavid du Colombier     gs_ref_memory_t *lmem = iimemory_local;
1757dd7cddfSDavid du Colombier     ref *system_dict = systemdict;
1767dd7cddfSDavid du Colombier     uint space = r_space(system_dict);
1773ff48bf5SDavid du Colombier     dict_stack_t *dstack = &idict_stack;
1787dd7cddfSDavid du Colombier     int code;
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier     /*
1813ff48bf5SDavid du Colombier      * Disable save checking, and space check for systemdict, while
1823ff48bf5SDavid du Colombier      * copying dictionaries.
1837dd7cddfSDavid du Colombier      */
1849a747e4fSDavid du Colombier     alloc_set_not_in_save(idmemory);
1853ff48bf5SDavid du Colombier     r_set_space(system_dict, avm_max);
1867dd7cddfSDavid du Colombier     /*
1873ff48bf5SDavid du Colombier      * Switch references from systemdict to local objects.
1883ff48bf5SDavid du Colombier      * userdict.localdicts holds these objects.  We could optimize this by
1893ff48bf5SDavid du Colombier      * only doing it if we're changing to a different local VM relative to
1903ff48bf5SDavid du Colombier      * the same global VM, but the cost is low enough relative to other
1913ff48bf5SDavid du Colombier      * things that we don't bother.
1927dd7cddfSDavid du Colombier      */
1933ff48bf5SDavid du Colombier     {
1947dd7cddfSDavid du Colombier 	ref_stack_t *rdstack = &dstack->stack;
1957dd7cddfSDavid du Colombier 	const ref *puserdict =
1967dd7cddfSDavid du Colombier 	    ref_stack_index(rdstack, ref_stack_count(rdstack) - 1 -
1977dd7cddfSDavid du Colombier 			    dstack->userdict_index);
1987dd7cddfSDavid du Colombier 	ref *plocaldicts;
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier 	if (dict_find_string(puserdict, "localdicts", &plocaldicts) > 0 &&
2017dd7cddfSDavid du Colombier 	    r_has_type(plocaldicts, t_dictionary)
2027dd7cddfSDavid du Colombier 	    ) {
2037dd7cddfSDavid du Colombier 	    dict_copy(plocaldicts, system_dict, dstack);
2047dd7cddfSDavid du Colombier 	}
2057dd7cddfSDavid du Colombier     }
2063ff48bf5SDavid du Colombier     /*
2073ff48bf5SDavid du Colombier      * Set systemdict.userparams to the saved copy, and then
2083ff48bf5SDavid du Colombier      * set the actual user parameters.  Note that we must disable both
2093ff48bf5SDavid du Colombier      * space checking and save checking while doing this.  Also,
2103ff48bf5SDavid du Colombier      * we must do this after copying localdicts (if required), because
2113ff48bf5SDavid du Colombier      * userparams also appears in localdicts.
2123ff48bf5SDavid du Colombier      */
2133ff48bf5SDavid du Colombier     code = dict_put_string(system_dict, "userparams", &i_ctx_p->userparams,
2143ff48bf5SDavid du Colombier 			   dstack);
2153ff48bf5SDavid du Colombier     if (code >= 0)
2163ff48bf5SDavid du Colombier 	code = set_user_params(i_ctx_p, &i_ctx_p->userparams);
2177dd7cddfSDavid du Colombier     r_set_space(system_dict, space);
2187dd7cddfSDavid du Colombier     if (lmem->save_level > 0)
2197dd7cddfSDavid du Colombier 	alloc_set_in_save(idmemory);
2207dd7cddfSDavid du Colombier     estack_clear_cache(&iexec_stack);
2217dd7cddfSDavid du Colombier     dstack_set_top(&idict_stack);
2227dd7cddfSDavid du Colombier     return code;
2237dd7cddfSDavid du Colombier }
2247dd7cddfSDavid du Colombier 
2257dd7cddfSDavid du Colombier /* Store the interpreter state in a context. */
2267dd7cddfSDavid du Colombier int
context_state_store(gs_context_state_t * pcst)2277dd7cddfSDavid du Colombier context_state_store(gs_context_state_t * pcst)
2287dd7cddfSDavid du Colombier {
2297dd7cddfSDavid du Colombier     ref_stack_cleanup(&pcst->dict_stack.stack);
2307dd7cddfSDavid du Colombier     ref_stack_cleanup(&pcst->exec_stack.stack);
2317dd7cddfSDavid du Colombier     ref_stack_cleanup(&pcst->op_stack.stack);
2327dd7cddfSDavid du Colombier     /*
2337dd7cddfSDavid du Colombier      * The user parameters in systemdict.userparams are kept
2347dd7cddfSDavid du Colombier      * up to date by PostScript code, but we still need to save
2357dd7cddfSDavid du Colombier      * systemdict.userparams to get the correct l_new flag.
2367dd7cddfSDavid du Colombier      */
2377dd7cddfSDavid du Colombier     {
2387dd7cddfSDavid du Colombier 	ref *puserparams;
2397dd7cddfSDavid du Colombier 	/* We need i_ctx_p for access to the d_stack. */
2407dd7cddfSDavid du Colombier 	i_ctx_t *i_ctx_p = pcst;
2417dd7cddfSDavid du Colombier 
2427dd7cddfSDavid du Colombier 	if (dict_find_string(systemdict, "userparams", &puserparams) < 0)
2437dd7cddfSDavid du Colombier 	    return_error(e_Fatal);
2447dd7cddfSDavid du Colombier 	pcst->userparams = *puserparams;
2457dd7cddfSDavid du Colombier     }
2467dd7cddfSDavid du Colombier     return 0;
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier 
2493ff48bf5SDavid du Colombier /* Free the contents of the state of a context, always to its local VM. */
2503ff48bf5SDavid du Colombier /* Return a mask of which of its VMs, if any, we freed. */
2513ff48bf5SDavid du Colombier int
context_state_free(gs_context_state_t * pcst)2527dd7cddfSDavid du Colombier context_state_free(gs_context_state_t * pcst)
2537dd7cddfSDavid du Colombier {
2547dd7cddfSDavid du Colombier     gs_ref_memory_t *mem = pcst->memory.space_local;
2557dd7cddfSDavid du Colombier     int freed = 0;
2567dd7cddfSDavid du Colombier     int i;
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier     /*
2597dd7cddfSDavid du Colombier      * If this context is the last one referencing a particular VM
2607dd7cddfSDavid du Colombier      * (local / global / system), free the entire VM space;
2617dd7cddfSDavid du Colombier      * otherwise, just free the context-related structures.
2627dd7cddfSDavid du Colombier      */
2637dd7cddfSDavid du Colombier     for (i = countof(pcst->memory.spaces_indexed); --i >= 0;) {
2647dd7cddfSDavid du Colombier 	if (pcst->memory.spaces_indexed[i] != 0 &&
2657dd7cddfSDavid du Colombier 	    !--(pcst->memory.spaces_indexed[i]->num_contexts)
2667dd7cddfSDavid du Colombier 	    ) {
2677dd7cddfSDavid du Colombier /****** FREE THE ENTIRE SPACE ******/
2687dd7cddfSDavid du Colombier 	    freed |= 1 << i;
2697dd7cddfSDavid du Colombier 	}
2707dd7cddfSDavid du Colombier     }
2717dd7cddfSDavid du Colombier     /*
2727dd7cddfSDavid du Colombier      * If we freed any spaces at all, we must have freed the local
2737dd7cddfSDavid du Colombier      * VM where the context structure and its substructures were
2747dd7cddfSDavid du Colombier      * allocated.
2757dd7cddfSDavid du Colombier      */
2767dd7cddfSDavid du Colombier     if (freed)
2777dd7cddfSDavid du Colombier 	return freed;
2787dd7cddfSDavid du Colombier     {
2797dd7cddfSDavid du Colombier 	gs_state *pgs = pcst->pgs;
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier 	gs_grestoreall(pgs);
2827dd7cddfSDavid du Colombier 	/* Patch the saved pointer so we can do the last grestore. */
2837dd7cddfSDavid du Colombier 	{
2847dd7cddfSDavid du Colombier 	    gs_state *saved = gs_state_saved(pgs);
2857dd7cddfSDavid du Colombier 
2867dd7cddfSDavid du Colombier 	    gs_state_swap_saved(saved, saved);
2877dd7cddfSDavid du Colombier 	}
2887dd7cddfSDavid du Colombier 	gs_grestore(pgs);
2897dd7cddfSDavid du Colombier 	gs_state_swap_saved(pgs, (gs_state *) 0);
2907dd7cddfSDavid du Colombier 	gs_state_free(pgs);
2917dd7cddfSDavid du Colombier     }
2927dd7cddfSDavid du Colombier /****** FREE USERPARAMS ******/
2937dd7cddfSDavid du Colombier     gs_interp_free_stacks(mem, pcst);
2943ff48bf5SDavid du Colombier     return 0;
2957dd7cddfSDavid du Colombier }
296