xref: /plan9/sys/src/cmd/gs/src/icontext.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1997, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: icontext.c,v 1.17 2003/10/09 00:13:30 igor Exp $ */
18 /* Context state operations */
19 #include "ghost.h"
20 #include "gsstruct.h"		/* for gxalloc.h */
21 #include "gxalloc.h"
22 #include "ierrors.h"
23 #include "stream.h"		/* for files.h */
24 #include "files.h"
25 #include "idict.h"
26 #include "igstate.h"
27 #include "icontext.h"
28 #include "interp.h"
29 #include "isave.h"
30 #include "dstack.h"
31 #include "estack.h"
32 #include "store.h"
33 
34 /* Declare the GC descriptors for embedded objects. */
35 extern_st(st_gs_dual_memory);
36 extern_st(st_ref_stack);
37 extern_st(st_dict_stack);
38 extern_st(st_exec_stack);
39 extern_st(st_op_stack);
40 
41 /* GC descriptors */
42 private
CLEAR_MARKS_PROC(context_state_clear_marks)43 CLEAR_MARKS_PROC(context_state_clear_marks)
44 {
45     gs_context_state_t *const pcst = vptr;
46 
47     r_clear_attrs(&pcst->stdio[0], l_mark);
48     r_clear_attrs(&pcst->stdio[1], l_mark);
49     r_clear_attrs(&pcst->stdio[2], l_mark);
50     r_clear_attrs(&pcst->userparams, l_mark);
51 }
52 private
ENUM_PTRS_WITH(context_state_enum_ptrs,gs_context_state_t * pcst)53 ENUM_PTRS_WITH(context_state_enum_ptrs, gs_context_state_t *pcst) {
54     index -= 5;
55     if (index < st_gs_dual_memory_num_ptrs)
56 	return ENUM_USING(st_gs_dual_memory, &pcst->memory,
57 			  sizeof(pcst->memory), index);
58     index -= st_gs_dual_memory_num_ptrs;
59     if (index < st_dict_stack_num_ptrs)
60 	return ENUM_USING(st_dict_stack, &pcst->dict_stack,
61 			  sizeof(pcst->dict_stack), index);
62     index -= st_dict_stack_num_ptrs;
63     if (index < st_exec_stack_num_ptrs)
64 	return ENUM_USING(st_exec_stack, &pcst->exec_stack,
65 			  sizeof(pcst->exec_stack), index);
66     index -= st_exec_stack_num_ptrs;
67     return ENUM_USING(st_op_stack, &pcst->op_stack,
68 		      sizeof(pcst->op_stack), index);
69     }
70     ENUM_PTR(0, gs_context_state_t, pgs);
71     case 1: ENUM_RETURN_REF(&pcst->stdio[0]);
72     case 2: ENUM_RETURN_REF(&pcst->stdio[1]);
73     case 3: ENUM_RETURN_REF(&pcst->stdio[2]);
74     case 4: ENUM_RETURN_REF(&pcst->userparams);
75 ENUM_PTRS_END
76 private RELOC_PTRS_WITH(context_state_reloc_ptrs, gs_context_state_t *pcst);
77     RELOC_PTR(gs_context_state_t, pgs);
78     RELOC_USING(st_gs_dual_memory, &pcst->memory, sizeof(pcst->memory));
79     RELOC_REF_VAR(pcst->stdio[0]);
80     RELOC_REF_VAR(pcst->stdio[1]);
81     RELOC_REF_VAR(pcst->stdio[2]);
82     RELOC_REF_VAR(pcst->userparams);
83     r_clear_attrs(&pcst->userparams, l_mark);
84     RELOC_USING(st_dict_stack, &pcst->dict_stack, sizeof(pcst->dict_stack));
85     RELOC_USING(st_exec_stack, &pcst->exec_stack, sizeof(pcst->exec_stack));
86     RELOC_USING(st_op_stack, &pcst->op_stack, sizeof(pcst->op_stack));
87 RELOC_PTRS_END
88 public_st_context_state();
89 
90 /* Allocate the state of a context. */
91 int
context_state_alloc(gs_context_state_t ** ppcst,const ref * psystem_dict,const gs_dual_memory_t * dmem)92 context_state_alloc(gs_context_state_t ** ppcst,
93 		    const ref *psystem_dict,
94 		    const gs_dual_memory_t * dmem)
95 {
96     gs_ref_memory_t *mem = dmem->space_local;
97     gs_context_state_t *pcst = *ppcst;
98     int code;
99     int i;
100 
101     if (pcst == 0) {
102 	pcst = gs_alloc_struct((gs_memory_t *) mem, gs_context_state_t,
103 			       &st_context_state, "context_state_alloc");
104 	if (pcst == 0)
105 	    return_error(e_VMerror);
106     }
107     code = gs_interp_alloc_stacks(mem, pcst);
108     if (code < 0)
109 	goto x0;
110     /*
111      * We have to initialize the dictionary stack early,
112      * for far-off references to systemdict.
113      */
114     pcst->dict_stack.system_dict = *psystem_dict;
115     pcst->dict_stack.min_size = 0;
116     pcst->dict_stack.userdict_index = 0;
117     pcst->pgs = int_gstate_alloc(dmem);
118     if (pcst->pgs == 0) {
119 	code = gs_note_error(e_VMerror);
120 	goto x1;
121     }
122     pcst->memory = *dmem;
123     pcst->language_level = 1;
124     make_false(&pcst->array_packing);
125     make_int(&pcst->binary_object_format, 0);
126     pcst->rand_state = rand_state_initial;
127     pcst->usertime_total = 0;
128     pcst->keep_usertime = false;
129     pcst->in_superexec = 0;
130     pcst->plugin_list = 0;
131     {	/*
132 	 * Create an empty userparams dictionary of the right size.
133 	 * If we can't determine the size, pick an arbitrary one.
134 	 */
135 	ref *puserparams;
136 	uint size;
137 	ref *system_dict = &pcst->dict_stack.system_dict;
138 
139 	if (dict_find_string(system_dict, "userparams", &puserparams) >= 0)
140 	    size = dict_length(puserparams);
141 	else
142 	    size = 30;
143 	code = dict_alloc(pcst->memory.space_local, size, &pcst->userparams);
144 	if (code < 0)
145 	    goto x2;
146 	/* PostScript code initializes the user parameters. */
147     }
148     pcst->scanner_options = 0;
149     pcst->LockFilePermissions = false;
150     pcst->starting_arg_file = false;
151     /* The initial stdio values are bogus.... */
152     make_file(&pcst->stdio[0], a_readonly | avm_invalid_file_entry, 1,
153 	      invalid_file_entry);
154     make_file(&pcst->stdio[1], a_all | avm_invalid_file_entry, 1,
155 	      invalid_file_entry);
156     make_file(&pcst->stdio[2], a_all | avm_invalid_file_entry, 1,
157 	      invalid_file_entry);
158     for (i = countof(pcst->memory.spaces_indexed); --i >= 0;)
159 	if (dmem->spaces_indexed[i] != 0)
160 	    ++(dmem->spaces_indexed[i]->num_contexts);
161     *ppcst = pcst;
162     return 0;
163   x2:gs_state_free(pcst->pgs);
164   x1:gs_interp_free_stacks(mem, pcst);
165   x0:if (*ppcst == 0)
166 	gs_free_object((gs_memory_t *) mem, pcst, "context_state_alloc");
167     return code;
168 }
169 
170 /* Load the interpreter state from a context. */
171 int
context_state_load(gs_context_state_t * i_ctx_p)172 context_state_load(gs_context_state_t * i_ctx_p)
173 {
174     gs_ref_memory_t *lmem = iimemory_local;
175     ref *system_dict = systemdict;
176     uint space = r_space(system_dict);
177     dict_stack_t *dstack = &idict_stack;
178     int code;
179 
180     /*
181      * Disable save checking, and space check for systemdict, while
182      * copying dictionaries.
183      */
184     alloc_set_not_in_save(idmemory);
185     r_set_space(system_dict, avm_max);
186     /*
187      * Switch references from systemdict to local objects.
188      * userdict.localdicts holds these objects.  We could optimize this by
189      * only doing it if we're changing to a different local VM relative to
190      * the same global VM, but the cost is low enough relative to other
191      * things that we don't bother.
192      */
193     {
194 	ref_stack_t *rdstack = &dstack->stack;
195 	const ref *puserdict =
196 	    ref_stack_index(rdstack, ref_stack_count(rdstack) - 1 -
197 			    dstack->userdict_index);
198 	ref *plocaldicts;
199 
200 	if (dict_find_string(puserdict, "localdicts", &plocaldicts) > 0 &&
201 	    r_has_type(plocaldicts, t_dictionary)
202 	    ) {
203 	    dict_copy(plocaldicts, system_dict, dstack);
204 	}
205     }
206     /*
207      * Set systemdict.userparams to the saved copy, and then
208      * set the actual user parameters.  Note that we must disable both
209      * space checking and save checking while doing this.  Also,
210      * we must do this after copying localdicts (if required), because
211      * userparams also appears in localdicts.
212      */
213     code = dict_put_string(system_dict, "userparams", &i_ctx_p->userparams,
214 			   dstack);
215     if (code >= 0)
216 	code = set_user_params(i_ctx_p, &i_ctx_p->userparams);
217     r_set_space(system_dict, space);
218     if (lmem->save_level > 0)
219 	alloc_set_in_save(idmemory);
220     estack_clear_cache(&iexec_stack);
221     dstack_set_top(&idict_stack);
222     return code;
223 }
224 
225 /* Store the interpreter state in a context. */
226 int
context_state_store(gs_context_state_t * pcst)227 context_state_store(gs_context_state_t * pcst)
228 {
229     ref_stack_cleanup(&pcst->dict_stack.stack);
230     ref_stack_cleanup(&pcst->exec_stack.stack);
231     ref_stack_cleanup(&pcst->op_stack.stack);
232     /*
233      * The user parameters in systemdict.userparams are kept
234      * up to date by PostScript code, but we still need to save
235      * systemdict.userparams to get the correct l_new flag.
236      */
237     {
238 	ref *puserparams;
239 	/* We need i_ctx_p for access to the d_stack. */
240 	i_ctx_t *i_ctx_p = pcst;
241 
242 	if (dict_find_string(systemdict, "userparams", &puserparams) < 0)
243 	    return_error(e_Fatal);
244 	pcst->userparams = *puserparams;
245     }
246     return 0;
247 }
248 
249 /* Free the contents of the state of a context, always to its local VM. */
250 /* Return a mask of which of its VMs, if any, we freed. */
251 int
context_state_free(gs_context_state_t * pcst)252 context_state_free(gs_context_state_t * pcst)
253 {
254     gs_ref_memory_t *mem = pcst->memory.space_local;
255     int freed = 0;
256     int i;
257 
258     /*
259      * If this context is the last one referencing a particular VM
260      * (local / global / system), free the entire VM space;
261      * otherwise, just free the context-related structures.
262      */
263     for (i = countof(pcst->memory.spaces_indexed); --i >= 0;) {
264 	if (pcst->memory.spaces_indexed[i] != 0 &&
265 	    !--(pcst->memory.spaces_indexed[i]->num_contexts)
266 	    ) {
267 /****** FREE THE ENTIRE SPACE ******/
268 	    freed |= 1 << i;
269 	}
270     }
271     /*
272      * If we freed any spaces at all, we must have freed the local
273      * VM where the context structure and its substructures were
274      * allocated.
275      */
276     if (freed)
277 	return freed;
278     {
279 	gs_state *pgs = pcst->pgs;
280 
281 	gs_grestoreall(pgs);
282 	/* Patch the saved pointer so we can do the last grestore. */
283 	{
284 	    gs_state *saved = gs_state_saved(pgs);
285 
286 	    gs_state_swap_saved(saved, saved);
287 	}
288 	gs_grestore(pgs);
289 	gs_state_swap_saved(pgs, (gs_state *) 0);
290 	gs_state_free(pgs);
291     }
292 /****** FREE USERPARAMS ******/
293     gs_interp_free_stacks(mem, pcst);
294     return 0;
295 }
296