dstack.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /* Copyright (C) 1992, 1996, 1997, 1998, 1999, 2000 Aladdin Enterprises. All rights reserved.
  2. This software is provided AS-IS with no warranty, either express or
  3. implied.
  4. This software is distributed under license and may not be copied,
  5. modified or distributed except as expressly authorized under the terms
  6. of the license contained in the file LICENSE in this distribution.
  7. For more information about licensing, please refer to
  8. http://www.ghostscript.com/licensing/. For information on
  9. commercial licensing, go to http://www.artifex.com/licensing/ or
  10. contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. San Rafael, CA 94903, U.S.A., +1(415)492-9861.
  12. */
  13. /* $Id: dstack.h,v 1.6 2004/08/04 19:36:12 stefan Exp $ */
  14. /* Definitions for the interpreter's dictionary stack */
  15. #ifndef dstack_INCLUDED
  16. # define dstack_INCLUDED
  17. #include "idstack.h"
  18. #include "icstate.h" /* for access to dict_stack */
  19. /* Define the dictionary stack instance for operators. */
  20. #define idict_stack (i_ctx_p->dict_stack)
  21. #define d_stack (idict_stack.stack)
  22. /* Define the interpreter-specific versions of the generic dstack API. */
  23. #define min_dstack_size (idict_stack.min_size)
  24. #define dstack_userdict_index (idict_stack.userdict_index)
  25. #define dsspace (idict_stack.def_space)
  26. #define dtop_can_store(pvalue) ((int)r_space(pvalue) <= dsspace)
  27. #define dtop_keys (idict_stack.top_keys)
  28. #define dtop_npairs (idict_stack.top_npairs)
  29. #define dtop_values (idict_stack.top_values)
  30. #define dict_set_top() dstack_set_top(&idict_stack);
  31. #define dict_is_permanent_on_dstack(pdict)\
  32. dstack_dict_is_permanent(&idict_stack, pdict)
  33. #define dicts_gc_cleanup() dstack_gc_cleanup(&idict_stack)
  34. #define systemdict (&idict_stack.system_dict)
  35. /* Define the dictionary stack pointers. */
  36. #define dsbot (d_stack.bot)
  37. #define dsp (d_stack.p)
  38. #define dstop (d_stack.top)
  39. /* Macro to ensure enough room on the dictionary stack */
  40. #define check_dstack(n)\
  41. if ( dstop - dsp < (n) )\
  42. { d_stack.requested = (n); return_error(e_dictstackoverflow); }
  43. /*
  44. * The dictionary stack is implemented as a linked list of blocks;
  45. * operators that access the entire d-stack must take this into account.
  46. * These are:
  47. * countdictstack dictstack
  48. * In addition, name lookup requires searching the entire stack, not just
  49. * the top block, and the underflow check for the dictionary stack
  50. * (`end' operator) is not just a check for underflowing the top block.
  51. */
  52. /* Name lookup */
  53. #define dict_find_name_by_index(nidx)\
  54. dstack_find_name_by_index(&idict_stack, nidx)
  55. #define dict_find_name(pnref) dict_find_name_by_index(name_index(imemory, pnref))
  56. #define dict_find_name_by_index_inline(nidx, htemp)\
  57. dstack_find_name_by_index_inline(&idict_stack, nidx, htemp)
  58. #define if_dict_find_name_by_index_top(nidx, htemp, pvslot)\
  59. if_dstack_find_name_by_index_top(&idict_stack, nidx, htemp, pvslot)
  60. /*
  61. Notes on dictionary lookup performance
  62. ======================================
  63. We mark heavily used operations with a * below; moderately heavily used
  64. operations with a +.
  65. The following operations look up keys on the dictionary stack:
  66. *(interpreter name lookup)
  67. load
  68. where
  69. The following operations change the contents of dictionaries:
  70. *def, +put
  71. undef
  72. restore
  73. (grow)
  74. We implement store in PostScript, and copy as a series of puts. Many
  75. other operators also do puts (e.g., ScaleMatrix in makefont,
  76. Implementation in makepattern, ...). Note that put can do an implicit
  77. .setmaxlength (if it has to grow the dictionary).
  78. The following operations change the dictionary stack:
  79. +begin, +end
  80. +?(context switch)
  81. readonly (on a dictionary that is on the stack)
  82. noaccess (on a dictionary that is on the stack)
  83. We implement cleardictstack as a series of ends.
  84. Current design
  85. ==============
  86. Each name N has a pointer N.V that has one of 3 states:
  87. - This name has no definitions.
  88. - This name has exactly one definition, in systemdict or userdict.
  89. In this case, N.V points to the value slot.
  90. - This name has some other status.
  91. We cache some pointers to the top dictionary on the stack if it is a
  92. readable dictionary with packed keys, which allows us to do fast,
  93. single-probe lookups in this dictionary. We also cache a value that
  94. allows us to do a fast check for stores into the top dictionary
  95. (writability + space check).
  96. Improved design
  97. ===============
  98. Data structures
  99. ---------------
  100. With each dictionary stack (or equivalently with each context), we
  101. associate:
  102. * A name lookup cache, C. Each entry C[i] in the cache consists of:
  103. A key, K (a name index).
  104. A dictionary stack level (depth), L. C[i] is valid iff the
  105. current dictionary stack depth, |dstack|, is equal to L.
  106. (L is always less than or equal to |dstack|.)
  107. A value pointer, V, which points to some value slot of some
  108. dictionary on the stack.
  109. * A lookup cache restoration stack, R. Each entry R[j] on this stack
  110. consists of:
  111. An index i in C.
  112. The previous (K,D,V) of C[i].
  113. C needs to be large enough to satisfy the overwhelming majority of name
  114. lookups with only 1-3 probes. In a single-context system, C can be large
  115. (perhaps 8K entries = 80K bytes, which is enough to accommodate every name
  116. in a typical run with no reprobes). In a multiple-context system, one can
  117. choose a variety of different strategies for managing C, such as:
  118. A single cache that is cleared on every context switch;
  119. A small cache (e.g., .5K entries) for each context;
  120. A cache that starts out small and grows adaptively if the hit rate
  121. is too low.
  122. R needs to be able to grow dynamically; in the worst case, it may have |C|
  123. entries per level of the dictionary stack. We assume that R will always be
  124. able to grow as needed (i.e., inability to allocate space for R is a
  125. VMerror, like inability to allocate space for the undo-save information for
  126. 'save').
  127. With each entry E[j] on the dictionary stack, we associate:
  128. * A value U that gives the depth of R at the time that E[j] was pushed
  129. on the stack. E[j].U = 0 for 0 <= j < the initial depth of the dictionary
  130. stack (normally 3).
  131. With each dictionary D we associate:
  132. * A counter S that gives the total number of occurrences of D on all
  133. dictionary stacks. If this counter overflows, it is pinned at its maximum
  134. value.
  135. In order to be effective, D.S needs to be able to count up to a small
  136. multiple of the total number of contexts: 16 bits should be plenty.
  137. As at present, we also maintain a pair of pointers that bracket the value
  138. region of the top dictionary on the stack, for fast checking in def. If the
  139. top dictionary is readonly or noaccess, the pointers designate an empty
  140. area. We call this the "def region cache".
  141. Now we describe the implementation of each of the above operations.
  142. (name lookup)
  143. -------------
  144. To look up a name with index N, compute a hash index 0 <= i < |C|. There
  145. are three cases:
  146. 1. C[i].K == N and C[i].L == |dstack|. Nothing more is needed:
  147. C[i].V points to the N's value.
  148. 2. C[i].K == N but C[i].L < |dstack|. Look up N in the top |dstack|
  149. - L entries on the dictionary stack; push i and C[i] onto R; set
  150. C[i].V to point to the value if found, and in any case set C[i].L =
  151. |dstack|.
  152. 3. C[i].K != N. Reprobe some small number of times.
  153. If all reprobes fail, look up N on the (full) dictionary stack. Pick an
  154. index i (one of the probed entries) in C to replace. If C[i].L != |dstack|,
  155. push i and C[i] onto R. Then replace C[i] with K = N, L = |dstack|, and V
  156. pointing to N's value.
  157. load
  158. ----
  159. Proceed as for name lookup. However, it might be worth not making the new
  160. cache entry in case 3, since names looked up by load will rarely be looked
  161. up again.
  162. where
  163. -----
  164. Just do a full lookup, ignoring C.
  165. def
  166. ---
  167. As at present: start by doing one or two fast probes in the def region
  168. cache; if they succeed, just store the new value; otherwise, do a normal
  169. dictionary lookup and access check. If a new dictionary entry is created
  170. and the key is a name, check all possible probe slots of the name in C; if
  171. the name is present, update its entry in C as for a lookup. Then if D.S >
  172. 1, scan as for 'grow' below.
  173. put
  174. ---
  175. If the key is a name, the dictionary entry is new, and D.S != 0, scan as for
  176. 'grow' below.
  177. undef
  178. -----
  179. If the key is a name and D.S != 0, scan as for 'grow' below. It might be
  180. worth checking for D.S == 1 and D = the top dictionary on the stack as a
  181. special case, which only requires removing the name from C, similar to
  182. 'def'.
  183. restore
  184. -------
  185. The undo-save machinery must be enhanced so that grow, def/put, and undef
  186. operations can be recognized as such. TBD.
  187. (grow)
  188. ------
  189. If D.S == 0, do nothing special. Otherwise, scan C, R, and the dictionary
  190. stack (first for the current context, and then for other contexts if needed)
  191. until D.S occurrences of D have been processed. (If D is in local VM, it is
  192. only necessary to scan contexts that share local VM with the current one; if
  193. D is in global VM, it is necessary to scan contexts that share global VM
  194. with the current one.) Entries in C whose V pointed within D's old values
  195. array are updated; entries in R whose V pointed within the old values array
  196. are replaced with empty entries.
  197. begin
  198. -----
  199. After pushing the new dictionary, set dstack[|dstack| - 1].U = |R|. Reset
  200. the def region cache.
  201. end
  202. ---
  203. Before popping the top entry, for dstack[|dstack| - 1].U <= j < |R|, restore
  204. C[R[j].i] from R[j].(K,L,V), popping R. Reset the def region cache.
  205. (context switch)
  206. ----------------
  207. Reset the def region cache.
  208. readonly
  209. --------
  210. If the dictionary is the top one on the stack, reset the def region cache.
  211. noaccess
  212. --------
  213. If D.S != 0, scan as for 'grow' above, removing every C and R entry whose V
  214. points into D. Also reset the def region cache if the dictionary is the top
  215. one on the stack.
  216. (garbage collection)
  217. --------------------
  218. The garbage collector must mark names referenced from C and R. Dictionaries
  219. referenced from C and R are also referenced from the dictionary stack, so
  220. they do not need to be marked specially; however, pointers to those
  221. dictionaries' values arrays from C and R need to be relocated.
  222. */
  223. #endif /* dstack_INCLUDED */