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