1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
|
/* Copyright (C) 2001-2012 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
implied.
This software is distributed under license and may not be copied,
modified or distributed except as expressly authorized under the terms
of the license contained in the file LICENSE in this distribution.
Refer to licensing information at http://www.artifex.com or contact
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
CA 94903, U.S.A., +1(415)492-9861, for further information.
*/
/* Assignment-related macros */
#ifndef store_INCLUDED
# define store_INCLUDED
#include "ialloc.h" /* for imemory masks & checks */
#include "idosave.h"
/*
* Macros for storing a ref. We use macros for storing into objects,
* since the storage manager needs to be able to track stores for
* save/restore and also for global/local checking.
* We also use macros for other ref assignments, because (as it happens)
* Turbo C generates pretty awful code for doing this.
*
* There are three cases that we need to distinguish:
* - Storing to a stack (no special action);
* - Storing into a newly created object (set l_new);
* - Storing into a slot of an existing object (check l_new in
* old value, set in new value).
* The macros are called
* <make/store><new_type><case>(place_to_store, new_value)
* where <case> is nothing for storing to the stack, _new for storing into
* a new object, and _old for storing into an existing object.
* (The _old macros also take a client name for tracing and debugging.)
* <new_type> and new_value are chosen from the following alternatives:
* ref_assign POINTER TO arbitrary ref
* make_t type (only for null and mark)
* make_tv type, value field name, value
* (only for scalars, which don't have attributes)
* make_tav type, attributes, value field name, value
* make_tasv type, attributes, size, value field name, value
* There are also specialized make_ macros for specific types:
* make_array, make_int, make_real, make_bool, make_false, make_true,
* make_mark, make_null, make_oper, make_[const_]string, make_struct.
* Not all of the specialized make_ macros have _new and _old variants.
*
* For _tav and _tasv, we must store the value first, because sometimes
* it depends on the contents of the place being stored into.
*
* Note that for composite objects (dictionary, file, array, string, device,
* struct), we must set a_foreign if the contents are allocated statically
* (e.g., for constant C strings) or not by the Ghostscript allocator
* (e.g., with malloc).
*/
/*
* Define the most efficient ref assignment macro for the platform.
*/
/*
* Assigning the components individually is fastest on Turbo C,
* and on Watcom C when one or both of the addresses are
* already known or in a register.
*
* Though, it sends wrong signals to the compiler that believes it's okay-ish
* to update the structure in two calls, and risks very wrong reordering. This
* _MUST_ be done in one call, and trust the compiler to do the proper thing,
* if not too bad. And we're using GCC anyways on Debian.
*/
#define ref_assign_inline(pto,pfrom)\
(*(pto) = *(pfrom))
#ifdef __TURBOC__
/*
* Move the data in two 32-bit chunks, because
* otherwise the compiler calls SCOPY@.
* The cast to void is to discourage the compiler from
* wanting to deliver the value of the expression.
*/
# define ref_assign(pto,pfrom)\
discard(ref_assign_inline(pto, pfrom))
#else
/*
* Trust the compiler and hope for the best.
* The MIPS compiler doesn't like the cast to void.
*/
# define ref_assign(pto,pfrom)\
(*(pto) = *(pfrom))
#endif
#define ialloc_new_mask (idmemory->new_mask)
/*
* The mmem argument may be either a gs_dual_memory_t or a
* gs_ref_memory_t, since it is only used for accessing the masks.
*/
#define ref_saving_in(mmem)\
((mmem)->new_mask != 0)
#define ref_must_save_in(mmem,pto)\
((r_type_attrs(pto) & (mmem)->test_mask) == 0)
#define ref_must_save(pto) ref_must_save_in(idmemory, pto)
#define ref_do_save_in(mem, pcont, pto, cname)\
alloc_save_change_in(mem, pcont, (ref_packed *)(pto), cname)
#define ref_do_save(pcont, pto, cname)\
alloc_save_change(idmemory, pcont, (ref_packed *)(pto), cname)
#define ref_save_in(mem, pcont, pto, cname)\
discard((ref_must_save_in(mem, pto) ?\
ref_do_save_in(mem, pcont, pto, cname) : 0))
#define ref_save(pcont, pto, cname)\
discard((ref_must_save(pto) ? ref_do_save(pcont, pto, cname) : 0))
#define ref_mark_new_in(mmem,pto)\
((pto)->tas.type_attrs |= (mmem)->new_mask)
#define ref_mark_new(pto) ref_mark_new_in(idmemory, pto)
#define ref_assign_new_in(mem,pto,pfrom)\
discard((ref_assign(pto,pfrom), ref_mark_new_in(mem,pto)))
#define ref_assign_new(pto,pfrom)\
discard((ref_assign(pto,pfrom), ref_mark_new(pto)))
#define ref_assign_new_inline(pto,pfrom)\
discard((ref_assign_inline(pto,pfrom), ref_mark_new(pto)))
#define ref_assign_old_in(mem,pcont,pto,pfrom,cname)\
(ref_save_in(mem,pcont,pto,cname), ref_assign_new_in(mem,pto,pfrom))
#define ref_assign_old(pcont,pto,pfrom,cname)\
(ref_save(pcont,pto,cname), ref_assign_new(pto,pfrom))
#define ref_assign_old_inline(pcont,pto,pfrom,cname)\
(ref_save(pcont,pto,cname), ref_assign_new_inline(pto,pfrom))
/* ref_mark_old is only needed in very unusual situations, namely, */
/* when we want to do a ref_save just before a save instead of */
/* when the actual assignment occurs. */
#define ref_mark_old(pto) ((pto)->tas.type_attrs &= ~ialloc_new_mask)
/* Define macros for conditionally clearing the parts of a ref */
/* that aren't being set to anything useful. */
#ifdef DEBUG
# define and_fill_s(pref)\
, (gs_debug['$'] ? r_set_size(pref, 0xfeed) : 0)
/*
* The following nonsense avoids compiler warnings about signed/unsigned
* integer constants.
*/
#define DEADBEEF ((int)(((uint)0xdead << 16) | 0xbeef))
# define and_fill_sv(pref)\
, (gs_debug['$'] ? (r_set_size(pref, 0xfeed),\
(pref)->value.intval = DEADBEEF) : 0)
#else /* !DEBUG */
# define and_fill_s(pref) /* */
# define and_fill_sv(pref) /* */
#endif
/* make_t must set the attributes to 0 to clear a_local! */
#define make_ta(pref,newtype,newattrs)\
(r_set_type_attrs(pref, newtype, newattrs) and_fill_sv(pref))
#define make_t(pref,newtype)\
make_ta(pref, newtype, 0)
#define make_t_new_in(mem,pref,newtype)\
make_ta(pref, newtype, imemory_new_mask(mem))
#define make_t_new(pref,newtype)\
make_ta(pref, newtype, ialloc_new_mask)
#define make_t_old_in(mem,pcont,pref,newtype,cname)\
(ref_save_in(mem,pcont,pref,cname), make_t_new_in(mem,pref,newtype))
#define make_t_old(pcont,pref,newtype,cname)\
(ref_save(pcont,pref,cname), make_t_new(pref,newtype))
#define make_tav(pref,newtype,newattrs,valfield,newvalue)\
((pref)->value.valfield = (newvalue),\
r_set_type_attrs(pref, newtype, newattrs)\
and_fill_s(pref))
#define make_tav_new(pref,t,a,vf,v)\
make_tav(pref,t,(a)|ialloc_new_mask,vf,v)
#define make_tav_old(pcont,pref,t,a,vf,v,cname)\
(ref_save(pcont,pref,cname), make_tav_new(pref,t,a,vf,v))
#define make_tv(pref,newtype,valfield,newvalue)\
make_tav(pref,newtype,0,valfield,newvalue)
#define make_tv_new(pref,t,vf,v)\
make_tav_new(pref,t,0,vf,v)
#define make_tv_old(pcont,pref,t,vf,v,cname)\
make_tav_old(pcont,pref,t,0,vf,v,cname)
#define make_tasv(pref,newtype,newattrs,newsize,valfield,newvalue)\
((pref)->value.valfield = (newvalue),\
r_set_type_attrs(pref, newtype, newattrs),\
r_set_size(pref, newsize))
#define make_tasv_new(pref,t,a,s,vf,v)\
make_tasv(pref,t,(a)|ialloc_new_mask,s,vf,v)
#define make_tasv_old(pcont,pref,t,a,s,vf,v,cname)\
(ref_save(pcont,pref,cname), make_tasv_new(pref,t,a,s,vf,v))
/* Type-specific constructor macros for scalar (non-composite) types */
#define make_bool(pref,bval)\
make_tv(pref, t_boolean, boolval, bval)
#define make_false(pref)\
make_bool(pref, 0)
#define make_true(pref)\
make_bool(pref, 1)
#define make_int(pref,ival)\
make_tv(pref, t_integer, intval, ival)
#define make_int_new(pref,ival)\
make_tv_new(pref, t_integer, intval, ival)
#define make_mark(pref)\
make_t(pref, t_mark)
#define make_null(pref)\
make_t(pref, t_null)
#define make_null_new(pref)\
make_t_new(pref, t_null)
#define make_null_old_in(mem,pcont,pref,cname)\
make_t_old_in(mem, pcont, pref, t_null, cname)
#define make_null_old(pcont,pref,cname)\
make_t_old(pcont, pref, t_null, cname)
#define make_oper(pref,opidx,proc)\
make_tasv(pref, t_operator, a_executable, opidx, opproc, proc)
#define make_oper_new(pref,opidx,proc)\
make_tasv_new(pref, t_operator, a_executable, opidx, opproc, proc)
#define make_real(pref,rval)\
make_tv(pref, t_real, realval, rval)
#define make_real_new(pref,rval)\
make_tv_new(pref, t_real, realval, rval)
/* Type-specific constructor macros for composite types */
/* For composite types, the a_space field is relevant; however, */
/* as noted in ivmspace.h, a value of 0 designates the most static space, */
/* so for making empty composites, a space value of 0 is appropriate. */
#define make_array(pref,attrs,size,elts)\
make_tasv(pref, t_array, attrs, size, refs, elts)
#define make_array_new(pref,attrs,size,elts)\
make_tasv_new(pref, t_array, attrs, size, refs, elts)
#define make_const_array(pref,attrs,size,elts)\
make_tasv(pref, t_array, attrs, size, const_refs, elts)
#define make_empty_array(pref,attrs)\
make_array(pref, attrs, 0, (ref *)NULL)
#define make_empty_const_array(pref,attrs)\
make_const_array(pref, attrs, 0, (const ref *)NULL)
#define make_string(pref,attrs,size,chars)\
make_tasv(pref, t_string, attrs, size, bytes, chars)
#define make_const_string(pref,attrs,size,chars)\
make_tasv(pref, t_string, attrs, size, const_bytes, chars)
#define make_empty_string(pref,attrs)\
make_string(pref, attrs, 0, (byte *)NULL)
#define make_empty_const_string(pref,attrs)\
make_const_string(pref, attrs, 0, (const byte *)NULL)
#define make_struct(pref,attrs,ptr)\
make_tav(pref, t_struct, attrs, pstruct, (obj_header_t *)(ptr))
#define make_struct_new(pref,attrs,ptr)\
make_tav_new(pref, t_struct, attrs, pstruct, (obj_header_t *)(ptr))
#define make_astruct(pref,attrs,ptr)\
make_tav(pref, t_astruct, attrs, pstruct, (obj_header_t *)(ptr))
#define make_astruct_new(pref,attrs,ptr)\
make_tav_new(pref, t_astruct, attrs, pstruct, (obj_header_t *)(ptr))
#endif /* store_INCLUDED */
|