xref: /plan9-contrib/sys/src/cmd/gs/src/interp.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 1989, 2000, 2001 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: interp.c,v 1.20 2004/09/03 20:23:10 ray Exp $ */
187dd7cddfSDavid du Colombier /* Ghostscript language interpreter */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "string_.h"
217dd7cddfSDavid du Colombier #include "ghost.h"
227dd7cddfSDavid du Colombier #include "gsstruct.h"		/* for iastruct.h */
237dd7cddfSDavid du Colombier #include "stream.h"
24*593dc095SDavid du Colombier #include "ierrors.h"
257dd7cddfSDavid du Colombier #include "estack.h"
267dd7cddfSDavid du Colombier #include "ialloc.h"
277dd7cddfSDavid du Colombier #include "iastruct.h"
287dd7cddfSDavid du Colombier #include "icontext.h"
297dd7cddfSDavid du Colombier #include "icremap.h"
30*593dc095SDavid du Colombier #include "idebug.h"
317dd7cddfSDavid du Colombier #include "igstate.h"		/* for handling e_RemapColor */
327dd7cddfSDavid du Colombier #include "inamedef.h"
337dd7cddfSDavid du Colombier #include "iname.h"		/* for the_name_table */
347dd7cddfSDavid du Colombier #include "interp.h"
357dd7cddfSDavid du Colombier #include "ipacked.h"
367dd7cddfSDavid du Colombier #include "ostack.h"		/* must precede iscan.h */
377dd7cddfSDavid du Colombier #include "strimpl.h"		/* for sfilter.h */
387dd7cddfSDavid du Colombier #include "sfilter.h"		/* for iscan.h */
397dd7cddfSDavid du Colombier #include "iscan.h"
407dd7cddfSDavid du Colombier #include "iddict.h"
417dd7cddfSDavid du Colombier #include "isave.h"
427dd7cddfSDavid du Colombier #include "istack.h"
433ff48bf5SDavid du Colombier #include "itoken.h"
447dd7cddfSDavid du Colombier #include "iutil.h"		/* for array_get */
457dd7cddfSDavid du Colombier #include "ivmspace.h"
467dd7cddfSDavid du Colombier #include "dstack.h"
477dd7cddfSDavid du Colombier #include "files.h"		/* for file_check_read */
487dd7cddfSDavid du Colombier #include "oper.h"
497dd7cddfSDavid du Colombier #include "store.h"
50*593dc095SDavid du Colombier #include "gpcheck.h"
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier /*
537dd7cddfSDavid du Colombier  * We may or may not optimize the handling of the special fast operators
547dd7cddfSDavid du Colombier  * in packed arrays.  If we do this, they run much faster when packed, but
557dd7cddfSDavid du Colombier  * slightly slower when not packed.
567dd7cddfSDavid du Colombier  */
577dd7cddfSDavid du Colombier #define PACKED_SPECIAL_OPS 1
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier /*
607dd7cddfSDavid du Colombier  * Pseudo-operators (procedures of type t_oparray) record
617dd7cddfSDavid du Colombier  * the operand and dictionary stack pointers, and restore them if an error
627dd7cddfSDavid du Colombier  * occurs during the execution of the procedure and if the procedure hasn't
637dd7cddfSDavid du Colombier  * (net) decreased the depth of the stack.  While this obviously doesn't
647dd7cddfSDavid du Colombier  * do all the work of restoring the state if a pseudo-operator gets an
657dd7cddfSDavid du Colombier  * error, it's a big help.  The only downside is that pseudo-operators run
667dd7cddfSDavid du Colombier  * a little slower.
677dd7cddfSDavid du Colombier  */
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier /* GC descriptors for stacks */
707dd7cddfSDavid du Colombier extern_st(st_ref_stack);
717dd7cddfSDavid du Colombier public_st_dict_stack();
727dd7cddfSDavid du Colombier public_st_exec_stack();
737dd7cddfSDavid du Colombier public_st_op_stack();
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier /*
767dd7cddfSDavid du Colombier  * The procedure to call if an operator requests rescheduling.
777dd7cddfSDavid du Colombier  * This causes an error unless the context machinery has been installed.
787dd7cddfSDavid du Colombier  */
797dd7cddfSDavid du Colombier private int
no_reschedule(i_ctx_t ** pi_ctx_p)807dd7cddfSDavid du Colombier no_reschedule(i_ctx_t **pi_ctx_p)
817dd7cddfSDavid du Colombier {
827dd7cddfSDavid du Colombier     return_error(e_invalidcontext);
837dd7cddfSDavid du Colombier }
84*593dc095SDavid du Colombier int (*gs_interp_reschedule_proc)(i_ctx_t **) = no_reschedule;
857dd7cddfSDavid du Colombier 
867dd7cddfSDavid du Colombier /*
877dd7cddfSDavid du Colombier  * The procedure to call for time-slicing.
887dd7cddfSDavid du Colombier  * This is a no-op unless the context machinery has been installed.
897dd7cddfSDavid du Colombier  */
90*593dc095SDavid du Colombier int (*gs_interp_time_slice_proc)(i_ctx_t **) = 0;
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier /*
937dd7cddfSDavid du Colombier  * The number of interpreter "ticks" between calls on the time_slice_proc.
947dd7cddfSDavid du Colombier  * Currently, the clock ticks before each operator, and at each
957dd7cddfSDavid du Colombier  * procedure return.
967dd7cddfSDavid du Colombier  */
977dd7cddfSDavid du Colombier int gs_interp_time_slice_ticks = 0x7fff;
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier /*
1007dd7cddfSDavid du Colombier  * Apply an operator.  When debugging, we route all operator calls
1017dd7cddfSDavid du Colombier  * through a procedure.
1027dd7cddfSDavid du Colombier  */
1037dd7cddfSDavid du Colombier #ifdef DEBUG
1047dd7cddfSDavid du Colombier private int
call_operator(op_proc_t op_proc,i_ctx_t * i_ctx_p)1057dd7cddfSDavid du Colombier call_operator(op_proc_t op_proc, i_ctx_t *i_ctx_p)
1067dd7cddfSDavid du Colombier {
1077dd7cddfSDavid du Colombier     int code = op_proc(i_ctx_p);
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier     return code;
1107dd7cddfSDavid du Colombier }
1117dd7cddfSDavid du Colombier #else
1127dd7cddfSDavid du Colombier #  define call_operator(proc, p) ((*(proc))(p))
1137dd7cddfSDavid du Colombier #endif
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier /* Define debugging statistics. */
1167dd7cddfSDavid du Colombier #ifdef DEBUG
1177dd7cddfSDavid du Colombier struct stats_interp_s {
1187dd7cddfSDavid du Colombier     long top;
1197dd7cddfSDavid du Colombier     long lit, lit_array, exec_array, exec_operator, exec_name;
1207dd7cddfSDavid du Colombier     long x_add, x_def, x_dup, x_exch, x_if, x_ifelse,
1217dd7cddfSDavid du Colombier 	x_index, x_pop, x_roll, x_sub;
1227dd7cddfSDavid du Colombier     long find_name, name_lit, name_proc, name_oparray, name_operator;
1237dd7cddfSDavid du Colombier     long p_full, p_exec_operator, p_exec_oparray, p_exec_non_x_operator,
1247dd7cddfSDavid du Colombier 	p_integer, p_lit_name, p_exec_name;
1257dd7cddfSDavid du Colombier     long p_find_name, p_name_lit, p_name_proc;
1267dd7cddfSDavid du Colombier } stats_interp;
1277dd7cddfSDavid du Colombier # define INCR(v) (++(stats_interp.v))
1287dd7cddfSDavid du Colombier #else
1297dd7cddfSDavid du Colombier # define INCR(v) DO_NOTHING
1307dd7cddfSDavid du Colombier #endif
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier /* Forward references */
133*593dc095SDavid du Colombier private int estack_underflow(i_ctx_t *);
134*593dc095SDavid du Colombier private int interp(i_ctx_t **, const ref *, ref *);
135*593dc095SDavid du Colombier private int interp_exit(i_ctx_t *);
136*593dc095SDavid du Colombier private void set_gc_signal(i_ctx_t *, int *, int);
137*593dc095SDavid du Colombier private int copy_stack(i_ctx_t *, const ref_stack_t *, ref *);
138*593dc095SDavid du Colombier private int oparray_pop(i_ctx_t *);
139*593dc095SDavid du Colombier private int oparray_cleanup(i_ctx_t *);
140*593dc095SDavid du Colombier private int zsetstackprotect(i_ctx_t *);
141*593dc095SDavid du Colombier private int zcurrentstackprotect(i_ctx_t *);
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier /* Stack sizes */
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier /* The maximum stack sizes may all be set in the makefile. */
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier /*
1487dd7cddfSDavid du Colombier  * Define the initial maximum size of the operand stack (MaxOpStack
1497dd7cddfSDavid du Colombier  * user parameter).
1507dd7cddfSDavid du Colombier  */
1517dd7cddfSDavid du Colombier #ifndef MAX_OSTACK
1527dd7cddfSDavid du Colombier #  define MAX_OSTACK 800
1537dd7cddfSDavid du Colombier #endif
1547dd7cddfSDavid du Colombier /*
1557dd7cddfSDavid du Colombier  * The minimum block size for extending the operand stack is the larger of:
1567dd7cddfSDavid du Colombier  *      - the maximum number of parameters to an operator
1577dd7cddfSDavid du Colombier  *      (currently setcolorscreen, with 12 parameters);
1587dd7cddfSDavid du Colombier  *      - the maximum number of values pushed by an operator
1597dd7cddfSDavid du Colombier  *      (currently setcolortransfer, which calls zcolor_remap_one 4 times
1607dd7cddfSDavid du Colombier  *      and therefore pushes 16 values).
1617dd7cddfSDavid du Colombier  */
1627dd7cddfSDavid du Colombier #define MIN_BLOCK_OSTACK 16
1637dd7cddfSDavid du Colombier const int gs_interp_max_op_num_args = MIN_BLOCK_OSTACK;		/* for iinit.c */
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier /*
1667dd7cddfSDavid du Colombier  * Define the initial maximum size of the execution stack (MaxExecStack
1677dd7cddfSDavid du Colombier  * user parameter).
1687dd7cddfSDavid du Colombier  */
1697dd7cddfSDavid du Colombier #ifndef MAX_ESTACK
1703ff48bf5SDavid du Colombier #  define MAX_ESTACK 5000
1717dd7cddfSDavid du Colombier #endif
1727dd7cddfSDavid du Colombier /*
1737dd7cddfSDavid du Colombier  * The minimum block size for extending the execution stack is the largest
1747dd7cddfSDavid du Colombier  * size of a contiguous block surrounding an e-stack mark.  (At least,
1757dd7cddfSDavid du Colombier  * that's what the minimum value would be if we supported multi-block
1767dd7cddfSDavid du Colombier  * estacks, which we currently don't.)  Currently, the largest such block is
1777dd7cddfSDavid du Colombier  * the one created for text processing, which is 8 (snumpush) slots.
1787dd7cddfSDavid du Colombier  */
1797dd7cddfSDavid du Colombier #define MIN_BLOCK_ESTACK 8
1807dd7cddfSDavid du Colombier /*
1817dd7cddfSDavid du Colombier  * If we get an e-stack overflow, we need to cut it back far enough to
1827dd7cddfSDavid du Colombier  * have some headroom for executing the error procedure.
1837dd7cddfSDavid du Colombier  */
1847dd7cddfSDavid du Colombier #define ES_HEADROOM 20
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier /*
1877dd7cddfSDavid du Colombier  * Define the initial maximum size of the dictionary stack (MaxDictStack
1887dd7cddfSDavid du Colombier  * user parameter).  Again, this is also currently the block size for
1897dd7cddfSDavid du Colombier  * extending the d-stack.
1907dd7cddfSDavid du Colombier  */
1917dd7cddfSDavid du Colombier #ifndef MAX_DSTACK
1927dd7cddfSDavid du Colombier #  define MAX_DSTACK 20
1937dd7cddfSDavid du Colombier #endif
1947dd7cddfSDavid du Colombier /*
1957dd7cddfSDavid du Colombier  * The minimum block size for extending the dictionary stack is the number
1967dd7cddfSDavid du Colombier  * of permanent entries on the dictionary stack, currently 3.
1977dd7cddfSDavid du Colombier  */
1987dd7cddfSDavid du Colombier #define MIN_BLOCK_DSTACK 3
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier /* See estack.h for a description of the execution stack. */
2017dd7cddfSDavid du Colombier 
2027dd7cddfSDavid du Colombier /* The logic for managing icount and iref below assumes that */
2037dd7cddfSDavid du Colombier /* there are no control operators which pop and then push */
2047dd7cddfSDavid du Colombier /* information on the execution stack. */
2057dd7cddfSDavid du Colombier 
2067dd7cddfSDavid du Colombier /* Stacks */
2077dd7cddfSDavid du Colombier extern_st(st_ref_stack);
2087dd7cddfSDavid du Colombier #define OS_GUARD_UNDER 10
2097dd7cddfSDavid du Colombier #define OS_GUARD_OVER 10
2107dd7cddfSDavid du Colombier #define OS_REFS_SIZE(body_size)\
2117dd7cddfSDavid du Colombier   (stack_block_refs + OS_GUARD_UNDER + (body_size) + OS_GUARD_OVER)
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier #define ES_GUARD_UNDER 1
2147dd7cddfSDavid du Colombier #define ES_GUARD_OVER 10
2157dd7cddfSDavid du Colombier #define ES_REFS_SIZE(body_size)\
2167dd7cddfSDavid du Colombier   (stack_block_refs + ES_GUARD_UNDER + (body_size) + ES_GUARD_OVER)
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier #define DS_REFS_SIZE(body_size)\
2197dd7cddfSDavid du Colombier   (stack_block_refs + (body_size))
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier /* Extended types.  The interpreter may replace the type of operators */
2227dd7cddfSDavid du Colombier /* in procedures with these, to speed up the interpretation loop. */
2237dd7cddfSDavid du Colombier /****** NOTE: If you add or change entries in this list, */
2247dd7cddfSDavid du Colombier /****** you must change the three dispatches in the interpreter loop. */
2257dd7cddfSDavid du Colombier /* The operator procedures are declared in opextern.h. */
2267dd7cddfSDavid du Colombier #define tx_op t_next_index
2277dd7cddfSDavid du Colombier typedef enum {
2287dd7cddfSDavid du Colombier     tx_op_add = tx_op,
2297dd7cddfSDavid du Colombier     tx_op_def,
2307dd7cddfSDavid du Colombier     tx_op_dup,
2317dd7cddfSDavid du Colombier     tx_op_exch,
2327dd7cddfSDavid du Colombier     tx_op_if,
2337dd7cddfSDavid du Colombier     tx_op_ifelse,
2347dd7cddfSDavid du Colombier     tx_op_index,
2357dd7cddfSDavid du Colombier     tx_op_pop,
2367dd7cddfSDavid du Colombier     tx_op_roll,
2377dd7cddfSDavid du Colombier     tx_op_sub,
2387dd7cddfSDavid du Colombier     tx_next_op
2397dd7cddfSDavid du Colombier } special_op_types;
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier #define num_special_ops ((int)tx_next_op - tx_op)
2427dd7cddfSDavid du Colombier const int gs_interp_num_special_ops = num_special_ops;	/* for iinit.c */
2437dd7cddfSDavid du Colombier const int tx_next_index = tx_next_op;
2447dd7cddfSDavid du Colombier 
2457dd7cddfSDavid du Colombier /*
2467dd7cddfSDavid du Colombier  * Define the interpreter operators, which include the extended-type
2477dd7cddfSDavid du Colombier  * operators defined in the list above.  NOTE: if the size of this table
2487dd7cddfSDavid du Colombier  * ever exceeds 15 real entries, it will have to be split.
2497dd7cddfSDavid du Colombier  */
2507dd7cddfSDavid du Colombier const op_def interp_op_defs[] = {
2517dd7cddfSDavid du Colombier     /*
2527dd7cddfSDavid du Colombier      * The very first entry, which corresponds to operator index 0,
2537dd7cddfSDavid du Colombier      * must not contain an actual operator.
2547dd7cddfSDavid du Colombier      */
2557dd7cddfSDavid du Colombier     op_def_begin_dict("systemdict"),
2567dd7cddfSDavid du Colombier     /*
2577dd7cddfSDavid du Colombier      * The next entries must be the extended-type operators, in the
2587dd7cddfSDavid du Colombier      * correct order.
2597dd7cddfSDavid du Colombier      */
2607dd7cddfSDavid du Colombier     {"2add", zadd},
2617dd7cddfSDavid du Colombier     {"2def", zdef},
2627dd7cddfSDavid du Colombier     {"1dup", zdup},
2637dd7cddfSDavid du Colombier     {"2exch", zexch},
2647dd7cddfSDavid du Colombier     {"2if", zif},
2657dd7cddfSDavid du Colombier     {"3ifelse", zifelse},
2667dd7cddfSDavid du Colombier     {"1index", zindex},
2677dd7cddfSDavid du Colombier     {"1pop", zpop},
2687dd7cddfSDavid du Colombier     {"2roll", zroll},
2697dd7cddfSDavid du Colombier     {"2sub", zsub},
2707dd7cddfSDavid du Colombier     /*
2717dd7cddfSDavid du Colombier      * The remaining entries are internal operators.
2727dd7cddfSDavid du Colombier      */
2733ff48bf5SDavid du Colombier     {"0.currentstackprotect", zcurrentstackprotect},
2743ff48bf5SDavid du Colombier     {"1.setstackprotect", zsetstackprotect},
2757dd7cddfSDavid du Colombier     {"0%interp_exit", interp_exit},
2767dd7cddfSDavid du Colombier     {"0%oparray_pop", oparray_pop},
2777dd7cddfSDavid du Colombier     op_def_end(0)
2787dd7cddfSDavid du Colombier };
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier #define make_null_proc(pref)\
2817dd7cddfSDavid du Colombier   make_empty_const_array(pref, a_executable + a_readonly)
2827dd7cddfSDavid du Colombier 
2837dd7cddfSDavid du Colombier /* Initialize the interpreter. */
2847dd7cddfSDavid du Colombier int
gs_interp_init(i_ctx_t ** pi_ctx_p,const ref * psystem_dict,gs_dual_memory_t * dmem)2857dd7cddfSDavid du Colombier gs_interp_init(i_ctx_t **pi_ctx_p, const ref *psystem_dict,
2867dd7cddfSDavid du Colombier 	       gs_dual_memory_t *dmem)
2877dd7cddfSDavid du Colombier {
2887dd7cddfSDavid du Colombier     /* Create and initialize a context state. */
2897dd7cddfSDavid du Colombier     gs_context_state_t *pcst = 0;
2907dd7cddfSDavid du Colombier     int code = context_state_alloc(&pcst, psystem_dict, dmem);
2917dd7cddfSDavid du Colombier 
2927dd7cddfSDavid du Colombier     if (code >= 0)
2937dd7cddfSDavid du Colombier 	code = context_state_load(pcst);
2947dd7cddfSDavid du Colombier     if (code < 0)
2957dd7cddfSDavid du Colombier 	lprintf1("Fatal error %d in gs_interp_init!", code);
2967dd7cddfSDavid du Colombier     *pi_ctx_p = pcst;
2977dd7cddfSDavid du Colombier     return code;
2987dd7cddfSDavid du Colombier }
2997dd7cddfSDavid du Colombier /*
3007dd7cddfSDavid du Colombier  * Create initial stacks for the interpreter.
3017dd7cddfSDavid du Colombier  * We export this for creating new contexts.
3027dd7cddfSDavid du Colombier  */
3037dd7cddfSDavid du Colombier int
gs_interp_alloc_stacks(gs_ref_memory_t * mem,gs_context_state_t * pcst)3047dd7cddfSDavid du Colombier gs_interp_alloc_stacks(gs_ref_memory_t *mem, gs_context_state_t * pcst)
3057dd7cddfSDavid du Colombier {
3067dd7cddfSDavid du Colombier     gs_ref_memory_t *smem =
3077dd7cddfSDavid du Colombier 	(gs_ref_memory_t *)gs_memory_stable((gs_memory_t *)mem);
3087dd7cddfSDavid du Colombier     ref stk;
3097dd7cddfSDavid du Colombier 
3107dd7cddfSDavid du Colombier #define REFS_SIZE_OSTACK OS_REFS_SIZE(MAX_OSTACK)
3117dd7cddfSDavid du Colombier #define REFS_SIZE_ESTACK ES_REFS_SIZE(MAX_ESTACK)
3127dd7cddfSDavid du Colombier #define REFS_SIZE_DSTACK DS_REFS_SIZE(MAX_DSTACK)
3137dd7cddfSDavid du Colombier     gs_alloc_ref_array(smem, &stk, 0,
3147dd7cddfSDavid du Colombier 		       REFS_SIZE_OSTACK + REFS_SIZE_ESTACK +
3157dd7cddfSDavid du Colombier 		       REFS_SIZE_DSTACK, "gs_interp_alloc_stacks");
3167dd7cddfSDavid du Colombier 
3177dd7cddfSDavid du Colombier     {
3187dd7cddfSDavid du Colombier 	ref_stack_t *pos = &pcst->op_stack.stack;
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier 	r_set_size(&stk, REFS_SIZE_OSTACK);
3217dd7cddfSDavid du Colombier 	ref_stack_init(pos, &stk, OS_GUARD_UNDER, OS_GUARD_OVER, NULL,
3227dd7cddfSDavid du Colombier 		       smem, NULL);
3237dd7cddfSDavid du Colombier 	ref_stack_set_error_codes(pos, e_stackunderflow, e_stackoverflow);
3247dd7cddfSDavid du Colombier 	ref_stack_set_max_count(pos, MAX_OSTACK);
3257dd7cddfSDavid du Colombier 	stk.value.refs += REFS_SIZE_OSTACK;
3267dd7cddfSDavid du Colombier     }
3277dd7cddfSDavid du Colombier 
3287dd7cddfSDavid du Colombier     {
3297dd7cddfSDavid du Colombier 	ref_stack_t *pes = &pcst->exec_stack.stack;
3307dd7cddfSDavid du Colombier 	ref euop;
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier 	r_set_size(&stk, REFS_SIZE_ESTACK);
3337dd7cddfSDavid du Colombier 	make_oper(&euop, 0, estack_underflow);
3347dd7cddfSDavid du Colombier 	ref_stack_init(pes, &stk, ES_GUARD_UNDER, ES_GUARD_OVER, &euop,
3357dd7cddfSDavid du Colombier 		       smem, NULL);
3367dd7cddfSDavid du Colombier 	ref_stack_set_error_codes(pes, e_ExecStackUnderflow,
3377dd7cddfSDavid du Colombier 				  e_execstackoverflow);
3387dd7cddfSDavid du Colombier 	/**************** E-STACK EXPANSION IS NYI. ****************/
3397dd7cddfSDavid du Colombier 	ref_stack_allow_expansion(pes, false);
3407dd7cddfSDavid du Colombier 	ref_stack_set_max_count(pes, MAX_ESTACK);
3417dd7cddfSDavid du Colombier 	stk.value.refs += REFS_SIZE_ESTACK;
3427dd7cddfSDavid du Colombier     }
3437dd7cddfSDavid du Colombier 
3447dd7cddfSDavid du Colombier     {
3457dd7cddfSDavid du Colombier 	ref_stack_t *pds = &pcst->dict_stack.stack;
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier 	r_set_size(&stk, REFS_SIZE_DSTACK);
3487dd7cddfSDavid du Colombier 	ref_stack_init(pds, &stk, 0, 0, NULL, smem, NULL);
3497dd7cddfSDavid du Colombier 	ref_stack_set_error_codes(pds, e_dictstackunderflow,
3507dd7cddfSDavid du Colombier 				  e_dictstackoverflow);
3517dd7cddfSDavid du Colombier 	ref_stack_set_max_count(pds, MAX_DSTACK);
3527dd7cddfSDavid du Colombier     }
3537dd7cddfSDavid du Colombier 
3547dd7cddfSDavid du Colombier #undef REFS_SIZE_OSTACK
3557dd7cddfSDavid du Colombier #undef REFS_SIZE_ESTACK
3567dd7cddfSDavid du Colombier #undef REFS_SIZE_DSTACK
3577dd7cddfSDavid du Colombier     return 0;
3587dd7cddfSDavid du Colombier }
3597dd7cddfSDavid du Colombier /*
3607dd7cddfSDavid du Colombier  * Free the stacks when destroying a context.  This is the inverse of
3617dd7cddfSDavid du Colombier  * create_stacks.
3627dd7cddfSDavid du Colombier  */
3637dd7cddfSDavid du Colombier void
gs_interp_free_stacks(gs_ref_memory_t * smem,gs_context_state_t * pcst)3647dd7cddfSDavid du Colombier gs_interp_free_stacks(gs_ref_memory_t * smem, gs_context_state_t * pcst)
3657dd7cddfSDavid du Colombier {
3667dd7cddfSDavid du Colombier     /* Free the stacks in inverse order of allocation. */
3677dd7cddfSDavid du Colombier     ref_stack_release(&pcst->dict_stack.stack);
3687dd7cddfSDavid du Colombier     ref_stack_release(&pcst->exec_stack.stack);
3697dd7cddfSDavid du Colombier     ref_stack_release(&pcst->op_stack.stack);
3707dd7cddfSDavid du Colombier }
3717dd7cddfSDavid du Colombier void
gs_interp_reset(i_ctx_t * i_ctx_p)3727dd7cddfSDavid du Colombier gs_interp_reset(i_ctx_t *i_ctx_p)
3737dd7cddfSDavid du Colombier {   /* Reset the stacks. */
3747dd7cddfSDavid du Colombier     ref_stack_clear(&o_stack);
3757dd7cddfSDavid du Colombier     ref_stack_clear(&e_stack);
3767dd7cddfSDavid du Colombier     esp++;
3777dd7cddfSDavid du Colombier     make_oper(esp, 0, interp_exit);
3787dd7cddfSDavid du Colombier     ref_stack_pop_to(&d_stack, min_dstack_size);
3797dd7cddfSDavid du Colombier     dict_set_top();
3807dd7cddfSDavid du Colombier }
3817dd7cddfSDavid du Colombier /* Report an e-stack block underflow.  The bottom guard slots of */
3827dd7cddfSDavid du Colombier /* e-stack blocks contain a pointer to this procedure. */
3837dd7cddfSDavid du Colombier private int
estack_underflow(i_ctx_t * i_ctx_p)3847dd7cddfSDavid du Colombier estack_underflow(i_ctx_t *i_ctx_p)
3857dd7cddfSDavid du Colombier {
3867dd7cddfSDavid du Colombier     return e_ExecStackUnderflow;
3877dd7cddfSDavid du Colombier }
3887dd7cddfSDavid du Colombier 
3897dd7cddfSDavid du Colombier /*
3907dd7cddfSDavid du Colombier  * Create an operator during initialization.
3917dd7cddfSDavid du Colombier  * If operator is hard-coded into the interpreter,
3927dd7cddfSDavid du Colombier  * assign it a special type and index.
3937dd7cddfSDavid du Colombier  */
3947dd7cddfSDavid du Colombier void
gs_interp_make_oper(ref * opref,op_proc_t proc,int idx)3957dd7cddfSDavid du Colombier gs_interp_make_oper(ref * opref, op_proc_t proc, int idx)
3967dd7cddfSDavid du Colombier {
3977dd7cddfSDavid du Colombier     int i;
3987dd7cddfSDavid du Colombier 
3997dd7cddfSDavid du Colombier     for (i = num_special_ops; i > 0 && proc != interp_op_defs[i].proc; --i)
4007dd7cddfSDavid du Colombier 	DO_NOTHING;
4017dd7cddfSDavid du Colombier     if (i > 0)
4027dd7cddfSDavid du Colombier 	make_tasv(opref, tx_op + (i - 1), a_executable, i, opproc, proc);
4037dd7cddfSDavid du Colombier     else
4047dd7cddfSDavid du Colombier 	make_tasv(opref, t_operator, a_executable, idx, opproc, proc);
4057dd7cddfSDavid du Colombier }
4067dd7cddfSDavid du Colombier 
4077dd7cddfSDavid du Colombier /*
4087dd7cddfSDavid du Colombier  * Call the garbage collector, updating the context pointer properly.
4097dd7cddfSDavid du Colombier  */
410*593dc095SDavid du Colombier int
interp_reclaim(i_ctx_t ** pi_ctx_p,int space)4117dd7cddfSDavid du Colombier interp_reclaim(i_ctx_t **pi_ctx_p, int space)
4127dd7cddfSDavid du Colombier {
4137dd7cddfSDavid du Colombier     i_ctx_t *i_ctx_p = *pi_ctx_p;
4147dd7cddfSDavid du Colombier     gs_gc_root_t ctx_root;
4157dd7cddfSDavid du Colombier     int code;
4167dd7cddfSDavid du Colombier 
4177dd7cddfSDavid du Colombier     gs_register_struct_root(imemory_system, &ctx_root,
4187dd7cddfSDavid du Colombier 			    (void **)pi_ctx_p, "interp_reclaim(pi_ctx_p)");
4197dd7cddfSDavid du Colombier     code = (*idmemory->reclaim)(idmemory, space);
4207dd7cddfSDavid du Colombier     i_ctx_p = *pi_ctx_p;	/* may have moved */
4217dd7cddfSDavid du Colombier     gs_unregister_root(imemory_system, &ctx_root, "interp_reclaim(pi_ctx_p)");
4227dd7cddfSDavid du Colombier     return code;
4237dd7cddfSDavid du Colombier }
4247dd7cddfSDavid du Colombier 
4257dd7cddfSDavid du Colombier /*
4267dd7cddfSDavid du Colombier  * Invoke the interpreter.  If execution completes normally, return 0.
4277dd7cddfSDavid du Colombier  * If an error occurs, the action depends on user_errors as follows:
4287dd7cddfSDavid du Colombier  *    user_errors < 0: always return an error code.
4297dd7cddfSDavid du Colombier  *    user_errors >= 0: let the PostScript machinery handle all errors.
4307dd7cddfSDavid du Colombier  *      (This will eventually result in a fatal error if no 'stopped'
4317dd7cddfSDavid du Colombier  *      is active.)
4327dd7cddfSDavid du Colombier  * In case of a quit or a fatal error, also store the exit code.
4337dd7cddfSDavid du Colombier  * Set *perror_object to null or the error object.
4347dd7cddfSDavid du Colombier  */
435*593dc095SDavid du Colombier private int gs_call_interp(i_ctx_t **, ref *, int, int *, ref *);
4367dd7cddfSDavid du Colombier int
gs_interpret(i_ctx_t ** pi_ctx_p,ref * pref,int user_errors,int * pexit_code,ref * perror_object)4377dd7cddfSDavid du Colombier gs_interpret(i_ctx_t **pi_ctx_p, ref * pref, int user_errors, int *pexit_code,
4387dd7cddfSDavid du Colombier 	     ref * perror_object)
4397dd7cddfSDavid du Colombier {
4407dd7cddfSDavid du Colombier     i_ctx_t *i_ctx_p = *pi_ctx_p;
4417dd7cddfSDavid du Colombier     gs_gc_root_t error_root;
4427dd7cddfSDavid du Colombier     int code;
4437dd7cddfSDavid du Colombier 
4447dd7cddfSDavid du Colombier     gs_register_ref_root(imemory_system, &error_root,
4457dd7cddfSDavid du Colombier 			 (void **)&perror_object, "gs_interpret");
4467dd7cddfSDavid du Colombier     code = gs_call_interp(pi_ctx_p, pref, user_errors, pexit_code,
4477dd7cddfSDavid du Colombier 			  perror_object);
4487dd7cddfSDavid du Colombier     i_ctx_p = *pi_ctx_p;
4497dd7cddfSDavid du Colombier     gs_unregister_root(imemory_system, &error_root, "gs_interpret");
4507dd7cddfSDavid du Colombier     /* Avoid a dangling reference to a stack-allocated GC signal. */
4517dd7cddfSDavid du Colombier     set_gc_signal(i_ctx_p, NULL, 0);
4527dd7cddfSDavid du Colombier     return code;
4537dd7cddfSDavid du Colombier }
4547dd7cddfSDavid du Colombier private int
gs_call_interp(i_ctx_t ** pi_ctx_p,ref * pref,int user_errors,int * pexit_code,ref * perror_object)4557dd7cddfSDavid du Colombier gs_call_interp(i_ctx_t **pi_ctx_p, ref * pref, int user_errors,
4567dd7cddfSDavid du Colombier 	       int *pexit_code, ref * perror_object)
4577dd7cddfSDavid du Colombier {
4587dd7cddfSDavid du Colombier     ref *epref = pref;
4597dd7cddfSDavid du Colombier     ref doref;
4607dd7cddfSDavid du Colombier     ref *perrordict;
4617dd7cddfSDavid du Colombier     ref error_name;
4627dd7cddfSDavid du Colombier     int code, ccode;
4637dd7cddfSDavid du Colombier     ref saref;
4647dd7cddfSDavid du Colombier     int gc_signal = 0;
4657dd7cddfSDavid du Colombier     i_ctx_t *i_ctx_p = *pi_ctx_p;
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier     *pexit_code = 0;
4687dd7cddfSDavid du Colombier     ialloc_reset_requested(idmemory);
4697dd7cddfSDavid du Colombier again:
4707dd7cddfSDavid du Colombier     /* Avoid a dangling error object that might get traced by a future GC. */
4717dd7cddfSDavid du Colombier     make_null(perror_object);
4727dd7cddfSDavid du Colombier     o_stack.requested = e_stack.requested = d_stack.requested = 0;
4737dd7cddfSDavid du Colombier     while (gc_signal) {		/* Some routine below triggered a GC. */
4747dd7cddfSDavid du Colombier 	gs_gc_root_t epref_root;
4757dd7cddfSDavid du Colombier 
4767dd7cddfSDavid du Colombier 	gc_signal = 0;
4777dd7cddfSDavid du Colombier 	/* Make sure that doref will get relocated properly if */
4787dd7cddfSDavid du Colombier 	/* a garbage collection happens with epref == &doref. */
4797dd7cddfSDavid du Colombier 	gs_register_ref_root(imemory_system, &epref_root,
4807dd7cddfSDavid du Colombier 			     (void **)&epref, "gs_call_interp(epref)");
4817dd7cddfSDavid du Colombier 	code = interp_reclaim(pi_ctx_p, -1);
4827dd7cddfSDavid du Colombier 	i_ctx_p = *pi_ctx_p;
4837dd7cddfSDavid du Colombier 	gs_unregister_root(imemory_system, &epref_root,
4847dd7cddfSDavid du Colombier 			   "gs_call_interp(epref)");
4857dd7cddfSDavid du Colombier 	if (code < 0)
4867dd7cddfSDavid du Colombier 	    return code;
4877dd7cddfSDavid du Colombier     }
4887dd7cddfSDavid du Colombier     code = interp(pi_ctx_p, epref, perror_object);
4897dd7cddfSDavid du Colombier     i_ctx_p = *pi_ctx_p;
4907dd7cddfSDavid du Colombier     /* Prevent a dangling reference to the GC signal in ticks_left */
4917dd7cddfSDavid du Colombier     /* in the frame of interp, but be prepared to do a GC if */
4927dd7cddfSDavid du Colombier     /* an allocation in this routine asks for it. */
4937dd7cddfSDavid du Colombier     set_gc_signal(i_ctx_p, &gc_signal, 1);
4947dd7cddfSDavid du Colombier     if (esp < esbot)		/* popped guard entry */
4957dd7cddfSDavid du Colombier 	esp = esbot;
4967dd7cddfSDavid du Colombier     switch (code) {
4977dd7cddfSDavid du Colombier 	case e_Fatal:
4987dd7cddfSDavid du Colombier 	    *pexit_code = 255;
4997dd7cddfSDavid du Colombier 	    return code;
5007dd7cddfSDavid du Colombier 	case e_Quit:
5017dd7cddfSDavid du Colombier 	    *perror_object = osp[-1];
5027dd7cddfSDavid du Colombier 	    *pexit_code = code = osp->value.intval;
5037dd7cddfSDavid du Colombier 	    osp -= 2;
5047dd7cddfSDavid du Colombier 	    return
5057dd7cddfSDavid du Colombier 		(code == 0 ? e_Quit :
5067dd7cddfSDavid du Colombier 		 code < 0 && code > -100 ? code : e_Fatal);
5077dd7cddfSDavid du Colombier 	case e_InterpreterExit:
5087dd7cddfSDavid du Colombier 	    return 0;
5097dd7cddfSDavid du Colombier 	case e_ExecStackUnderflow:
5107dd7cddfSDavid du Colombier /****** WRONG -- must keep mark blocks intact ******/
5117dd7cddfSDavid du Colombier 	    ref_stack_pop_block(&e_stack);
5127dd7cddfSDavid du Colombier 	    doref = *perror_object;
5137dd7cddfSDavid du Colombier 	    epref = &doref;
5147dd7cddfSDavid du Colombier 	    goto again;
5157dd7cddfSDavid du Colombier 	case e_VMreclaim:
5167dd7cddfSDavid du Colombier 	    /* Do the GC and continue. */
5177dd7cddfSDavid du Colombier 	    code = interp_reclaim(pi_ctx_p,
5187dd7cddfSDavid du Colombier 				  (osp->value.intval == 2 ?
5197dd7cddfSDavid du Colombier 				   avm_global : avm_local));
5207dd7cddfSDavid du Colombier 	    i_ctx_p = *pi_ctx_p;
5217dd7cddfSDavid du Colombier 	    /****** What if code < 0? ******/
5227dd7cddfSDavid du Colombier 	    make_oper(&doref, 0, zpop);
5237dd7cddfSDavid du Colombier 	    epref = &doref;
5247dd7cddfSDavid du Colombier 	    goto again;
5257dd7cddfSDavid du Colombier 	case e_NeedInput:
5263ff48bf5SDavid du Colombier 	case e_NeedStdin:
5273ff48bf5SDavid du Colombier 	case e_NeedStdout:
5283ff48bf5SDavid du Colombier 	case e_NeedStderr:
5297dd7cddfSDavid du Colombier 	    return code;
5307dd7cddfSDavid du Colombier     }
5317dd7cddfSDavid du Colombier     /* Adjust osp in case of operand stack underflow */
5327dd7cddfSDavid du Colombier     if (osp < osbot - 1)
5337dd7cddfSDavid du Colombier 	osp = osbot - 1;
5347dd7cddfSDavid du Colombier     /* We have to handle stack over/underflow specially, because */
5357dd7cddfSDavid du Colombier     /* we might be able to recover by adding or removing a block. */
5367dd7cddfSDavid du Colombier     switch (code) {
5377dd7cddfSDavid du Colombier 	case e_dictstackoverflow:
5387dd7cddfSDavid du Colombier 	    if (ref_stack_extend(&d_stack, d_stack.requested) >= 0) {
5397dd7cddfSDavid du Colombier 		dict_set_top();
5407dd7cddfSDavid du Colombier 		doref = *perror_object;
5417dd7cddfSDavid du Colombier 		epref = &doref;
5427dd7cddfSDavid du Colombier 		goto again;
5437dd7cddfSDavid du Colombier 	    }
5447dd7cddfSDavid du Colombier 	    if (osp >= ostop) {
5457dd7cddfSDavid du Colombier 		if ((ccode = ref_stack_extend(&o_stack, 1)) < 0)
5467dd7cddfSDavid du Colombier 		    return ccode;
5477dd7cddfSDavid du Colombier 	    }
5487dd7cddfSDavid du Colombier 	    ccode = copy_stack(i_ctx_p, &d_stack, &saref);
5497dd7cddfSDavid du Colombier 	    if (ccode < 0)
5507dd7cddfSDavid du Colombier 		return ccode;
5517dd7cddfSDavid du Colombier 	    ref_stack_pop_to(&d_stack, min_dstack_size);
5527dd7cddfSDavid du Colombier 	    dict_set_top();
5537dd7cddfSDavid du Colombier 	    *++osp = saref;
5547dd7cddfSDavid du Colombier 	    break;
5557dd7cddfSDavid du Colombier 	case e_dictstackunderflow:
5567dd7cddfSDavid du Colombier 	    if (ref_stack_pop_block(&d_stack) >= 0) {
5577dd7cddfSDavid du Colombier 		dict_set_top();
5587dd7cddfSDavid du Colombier 		doref = *perror_object;
5597dd7cddfSDavid du Colombier 		epref = &doref;
5607dd7cddfSDavid du Colombier 		goto again;
5617dd7cddfSDavid du Colombier 	    }
5627dd7cddfSDavid du Colombier 	    break;
5637dd7cddfSDavid du Colombier 	case e_execstackoverflow:
5647dd7cddfSDavid du Colombier 	    /* We don't have to handle this specially: */
5657dd7cddfSDavid du Colombier 	    /* The only places that could generate it */
5667dd7cddfSDavid du Colombier 	    /* use check_estack, which does a ref_stack_extend, */
5677dd7cddfSDavid du Colombier 	    /* so if we get this error, it's a real one. */
5687dd7cddfSDavid du Colombier 	    if (osp >= ostop) {
5697dd7cddfSDavid du Colombier 		if ((ccode = ref_stack_extend(&o_stack, 1)) < 0)
5707dd7cddfSDavid du Colombier 		    return ccode;
5717dd7cddfSDavid du Colombier 	    }
5727dd7cddfSDavid du Colombier 	    ccode = copy_stack(i_ctx_p, &e_stack, &saref);
5737dd7cddfSDavid du Colombier 	    if (ccode < 0)
5747dd7cddfSDavid du Colombier 		return ccode;
5757dd7cddfSDavid du Colombier 	    {
5767dd7cddfSDavid du Colombier 		uint count = ref_stack_count(&e_stack);
5777dd7cddfSDavid du Colombier 		uint limit = ref_stack_max_count(&e_stack) - ES_HEADROOM;
5787dd7cddfSDavid du Colombier 
5797dd7cddfSDavid du Colombier 		if (count > limit) {
5807dd7cddfSDavid du Colombier 		    /*
5817dd7cddfSDavid du Colombier 		     * If there is an e-stack mark within MIN_BLOCK_ESTACK of
5827dd7cddfSDavid du Colombier 		     * the new top, cut the stack back to remove the mark.
5837dd7cddfSDavid du Colombier 		     */
5847dd7cddfSDavid du Colombier 		    int skip = count - limit;
5857dd7cddfSDavid du Colombier 		    int i;
5867dd7cddfSDavid du Colombier 
5877dd7cddfSDavid du Colombier 		    for (i = skip; i < skip + MIN_BLOCK_ESTACK; ++i) {
5887dd7cddfSDavid du Colombier 			const ref *ep = ref_stack_index(&e_stack, i);
5897dd7cddfSDavid du Colombier 
5907dd7cddfSDavid du Colombier 			if (r_has_type_attrs(ep, t_null, a_executable)) {
5917dd7cddfSDavid du Colombier 			    skip = i + 1;
5927dd7cddfSDavid du Colombier 			    break;
5937dd7cddfSDavid du Colombier 			}
5947dd7cddfSDavid du Colombier 		    }
5957dd7cddfSDavid du Colombier 		    pop_estack(i_ctx_p, skip);
5967dd7cddfSDavid du Colombier 		}
5977dd7cddfSDavid du Colombier 	    }
5987dd7cddfSDavid du Colombier 	    *++osp = saref;
5997dd7cddfSDavid du Colombier 	    break;
6007dd7cddfSDavid du Colombier 	case e_stackoverflow:
6017dd7cddfSDavid du Colombier 	    if (ref_stack_extend(&o_stack, o_stack.requested) >= 0) {	/* We can't just re-execute the object, because */
6027dd7cddfSDavid du Colombier 		/* it might be a procedure being pushed as a */
6037dd7cddfSDavid du Colombier 		/* literal.  We check for this case specially. */
6047dd7cddfSDavid du Colombier 		doref = *perror_object;
6057dd7cddfSDavid du Colombier 		if (r_is_proc(&doref)) {
6067dd7cddfSDavid du Colombier 		    *++osp = doref;
6077dd7cddfSDavid du Colombier 		    make_null_proc(&doref);
6087dd7cddfSDavid du Colombier 		}
6097dd7cddfSDavid du Colombier 		epref = &doref;
6107dd7cddfSDavid du Colombier 		goto again;
6117dd7cddfSDavid du Colombier 	    }
6127dd7cddfSDavid du Colombier 	    ccode = copy_stack(i_ctx_p, &o_stack, &saref);
6137dd7cddfSDavid du Colombier 	    if (ccode < 0)
6147dd7cddfSDavid du Colombier 		return ccode;
6157dd7cddfSDavid du Colombier 	    ref_stack_clear(&o_stack);
6167dd7cddfSDavid du Colombier 	    *++osp = saref;
6177dd7cddfSDavid du Colombier 	    break;
6187dd7cddfSDavid du Colombier 	case e_stackunderflow:
6197dd7cddfSDavid du Colombier 	    if (ref_stack_pop_block(&o_stack) >= 0) {
6207dd7cddfSDavid du Colombier 		doref = *perror_object;
6217dd7cddfSDavid du Colombier 		epref = &doref;
6227dd7cddfSDavid du Colombier 		goto again;
6237dd7cddfSDavid du Colombier 	    }
6247dd7cddfSDavid du Colombier 	    break;
6257dd7cddfSDavid du Colombier     }
6267dd7cddfSDavid du Colombier     if (user_errors < 0)
6277dd7cddfSDavid du Colombier 	return code;
6287dd7cddfSDavid du Colombier     if (gs_errorname(i_ctx_p, code, &error_name) < 0)
6297dd7cddfSDavid du Colombier 	return code;		/* out-of-range error code! */
6307dd7cddfSDavid du Colombier     if (dict_find_string(systemdict, "errordict", &perrordict) <= 0 ||
6317dd7cddfSDavid du Colombier 	dict_find(perrordict, &error_name, &epref) <= 0
6327dd7cddfSDavid du Colombier 	)
6337dd7cddfSDavid du Colombier 	return code;		/* error name not in errordict??? */
6347dd7cddfSDavid du Colombier     doref = *epref;
6357dd7cddfSDavid du Colombier     epref = &doref;
6367dd7cddfSDavid du Colombier     /* Push the error object on the operand stack if appropriate. */
6377dd7cddfSDavid du Colombier     if (!ERROR_IS_INTERRUPT(code))
6387dd7cddfSDavid du Colombier 	*++osp = *perror_object;
6397dd7cddfSDavid du Colombier     goto again;
6407dd7cddfSDavid du Colombier }
6417dd7cddfSDavid du Colombier private int
interp_exit(i_ctx_t * i_ctx_p)6427dd7cddfSDavid du Colombier interp_exit(i_ctx_t *i_ctx_p)
6437dd7cddfSDavid du Colombier {
6447dd7cddfSDavid du Colombier     return e_InterpreterExit;
6457dd7cddfSDavid du Colombier }
6467dd7cddfSDavid du Colombier 
6477dd7cddfSDavid du Colombier /* Set the GC signal for all VMs. */
6487dd7cddfSDavid du Colombier private void
set_gc_signal(i_ctx_t * i_ctx_p,int * psignal,int value)6497dd7cddfSDavid du Colombier set_gc_signal(i_ctx_t *i_ctx_p, int *psignal, int value)
6507dd7cddfSDavid du Colombier {
6517dd7cddfSDavid du Colombier     gs_memory_gc_status_t stat;
6527dd7cddfSDavid du Colombier     int i;
6537dd7cddfSDavid du Colombier 
6547dd7cddfSDavid du Colombier     for (i = 0; i < countof(idmemory->spaces_indexed); i++) {
6557dd7cddfSDavid du Colombier 	gs_ref_memory_t *mem = idmemory->spaces_indexed[i];
6567dd7cddfSDavid du Colombier 	gs_ref_memory_t *mem_stable;
6577dd7cddfSDavid du Colombier 
6587dd7cddfSDavid du Colombier 	if (mem == 0)
6597dd7cddfSDavid du Colombier 	    continue;
6607dd7cddfSDavid du Colombier 	for (;; mem = mem_stable) {
6617dd7cddfSDavid du Colombier 	    mem_stable = (gs_ref_memory_t *)
6627dd7cddfSDavid du Colombier 		gs_memory_stable((gs_memory_t *)mem);
6637dd7cddfSDavid du Colombier 	    gs_memory_gc_status(mem, &stat);
6647dd7cddfSDavid du Colombier 	    stat.psignal = psignal;
6657dd7cddfSDavid du Colombier 	    stat.signal_value = value;
6667dd7cddfSDavid du Colombier 	    gs_memory_set_gc_status(mem, &stat);
6677dd7cddfSDavid du Colombier 	    if (mem_stable == mem)
6687dd7cddfSDavid du Colombier 		break;
6697dd7cddfSDavid du Colombier 	}
6707dd7cddfSDavid du Colombier     }
6717dd7cddfSDavid du Colombier }
6727dd7cddfSDavid du Colombier 
6737dd7cddfSDavid du Colombier /* Copy the contents of an overflowed stack into a (local) array. */
6747dd7cddfSDavid du Colombier private int
copy_stack(i_ctx_t * i_ctx_p,const ref_stack_t * pstack,ref * arr)6757dd7cddfSDavid du Colombier copy_stack(i_ctx_t *i_ctx_p, const ref_stack_t * pstack, ref * arr)
6767dd7cddfSDavid du Colombier {
6777dd7cddfSDavid du Colombier     uint size = ref_stack_count(pstack);
6787dd7cddfSDavid du Colombier     uint save_space = ialloc_space(idmemory);
6797dd7cddfSDavid du Colombier     int code;
6807dd7cddfSDavid du Colombier 
6817dd7cddfSDavid du Colombier     ialloc_set_space(idmemory, avm_local);
6827dd7cddfSDavid du Colombier     code = ialloc_ref_array(arr, a_all, size, "copy_stack");
6837dd7cddfSDavid du Colombier     if (code >= 0)
6847dd7cddfSDavid du Colombier 	code = ref_stack_store(pstack, arr, size, 0, 1, true, idmemory,
6857dd7cddfSDavid du Colombier 			       "copy_stack");
6867dd7cddfSDavid du Colombier     ialloc_set_space(idmemory, save_space);
6877dd7cddfSDavid du Colombier     return code;
6887dd7cddfSDavid du Colombier }
6897dd7cddfSDavid du Colombier 
6907dd7cddfSDavid du Colombier /* Get the name corresponding to an error number. */
6917dd7cddfSDavid du Colombier int
gs_errorname(i_ctx_t * i_ctx_p,int code,ref * perror_name)6927dd7cddfSDavid du Colombier gs_errorname(i_ctx_t *i_ctx_p, int code, ref * perror_name)
6937dd7cddfSDavid du Colombier {
6947dd7cddfSDavid du Colombier     ref *perrordict, *pErrorNames;
6957dd7cddfSDavid du Colombier 
6967dd7cddfSDavid du Colombier     if (dict_find_string(systemdict, "errordict", &perrordict) <= 0 ||
6977dd7cddfSDavid du Colombier 	dict_find_string(systemdict, "ErrorNames", &pErrorNames) <= 0
6987dd7cddfSDavid du Colombier 	)
6997dd7cddfSDavid du Colombier 	return_error(e_undefined);	/* errordict or ErrorNames not found?! */
700*593dc095SDavid du Colombier     return array_get(imemory, pErrorNames, (long)(-code - 1), perror_name);
7017dd7cddfSDavid du Colombier }
7027dd7cddfSDavid du Colombier 
7037dd7cddfSDavid du Colombier /* Store an error string in $error.errorinfo. */
7047dd7cddfSDavid du Colombier /* This routine is here because of the proximity to the error handler. */
7057dd7cddfSDavid du Colombier int
gs_errorinfo_put_string(i_ctx_t * i_ctx_p,const char * str)7067dd7cddfSDavid du Colombier gs_errorinfo_put_string(i_ctx_t *i_ctx_p, const char *str)
7077dd7cddfSDavid du Colombier {
7087dd7cddfSDavid du Colombier     ref rstr;
7097dd7cddfSDavid du Colombier     ref *pderror;
7107dd7cddfSDavid du Colombier     int code = string_to_ref(str, &rstr, iimemory, "gs_errorinfo_put_string");
7117dd7cddfSDavid du Colombier 
7127dd7cddfSDavid du Colombier     if (code < 0)
7137dd7cddfSDavid du Colombier 	return code;
7147dd7cddfSDavid du Colombier     if (dict_find_string(systemdict, "$error", &pderror) <= 0 ||
7157dd7cddfSDavid du Colombier 	!r_has_type(pderror, t_dictionary) ||
7167dd7cddfSDavid du Colombier 	idict_put_string(pderror, "errorinfo", &rstr) < 0
7177dd7cddfSDavid du Colombier 	)
7187dd7cddfSDavid du Colombier 	return_error(e_Fatal);
7197dd7cddfSDavid du Colombier     return 0;
7207dd7cddfSDavid du Colombier }
7217dd7cddfSDavid du Colombier 
7227dd7cddfSDavid du Colombier /* Main interpreter. */
7237dd7cddfSDavid du Colombier /* If execution terminates normally, return e_InterpreterExit. */
7247dd7cddfSDavid du Colombier /* If an error occurs, leave the current object in *perror_object */
7257dd7cddfSDavid du Colombier /* and return a (negative) error code. */
7267dd7cddfSDavid du Colombier private int
interp(i_ctx_t ** pi_ctx_p,const ref * pref,ref * perror_object)7277dd7cddfSDavid du Colombier interp(i_ctx_t **pi_ctx_p /* context for execution, updated if resched */,
7287dd7cddfSDavid du Colombier        const ref * pref /* object to interpret */,
7297dd7cddfSDavid du Colombier        ref * perror_object)
7307dd7cddfSDavid du Colombier {
7317dd7cddfSDavid du Colombier     i_ctx_t *i_ctx_p = *pi_ctx_p;
7327dd7cddfSDavid du Colombier     /*
7337dd7cddfSDavid du Colombier      * Note that iref may actually be either a ref * or a ref_packed *.
7347dd7cddfSDavid du Colombier      * Certain DEC compilers assume that a ref * is ref-aligned even if it
7357dd7cddfSDavid du Colombier      * is cast to a short *, and generate code on this assumption, leading
7367dd7cddfSDavid du Colombier      * to "unaligned access" errors.  For this reason, we declare
7377dd7cddfSDavid du Colombier      * iref_packed, and use a macro to cast it to the more aligned type
7387dd7cddfSDavid du Colombier      * where necessary (which is almost everywhere it is used).  This may
7397dd7cddfSDavid du Colombier      * lead to compiler warnings about "cast increases alignment
7407dd7cddfSDavid du Colombier      * requirements", but this is less harmful than expensive traps at run
7417dd7cddfSDavid du Colombier      * time.
7427dd7cddfSDavid du Colombier      */
7437dd7cddfSDavid du Colombier     register const ref_packed *iref_packed = (const ref_packed *)pref;
7447dd7cddfSDavid du Colombier     /*
7457dd7cddfSDavid du Colombier      * To make matters worse, some versions of gcc/egcs have a bug that
7467dd7cddfSDavid du Colombier      * leads them to assume that if iref_packed is EVER cast to a ref *,
7477dd7cddfSDavid du Colombier      * it is ALWAYS ref-aligned.  We detect this in stdpre.h and provide
7487dd7cddfSDavid du Colombier      * the following workaround:
7497dd7cddfSDavid du Colombier      */
7507dd7cddfSDavid du Colombier #ifdef ALIGNMENT_ALIASING_BUG
7517dd7cddfSDavid du Colombier     const ref *iref_temp;
7527dd7cddfSDavid du Colombier #  define IREF (iref_temp = (const ref *)iref_packed, iref_temp)
7537dd7cddfSDavid du Colombier #else
7547dd7cddfSDavid du Colombier #  define IREF ((const ref *)iref_packed)
7557dd7cddfSDavid du Colombier #endif
7567dd7cddfSDavid du Colombier #define SET_IREF(rp) (iref_packed = (const ref_packed *)(rp))
7577dd7cddfSDavid du Colombier     register int icount = 0;	/* # of consecutive tokens at iref */
7587dd7cddfSDavid du Colombier     register os_ptr iosp = osp;	/* private copy of osp */
7597dd7cddfSDavid du Colombier     register es_ptr iesp = esp;	/* private copy of esp */
7607dd7cddfSDavid du Colombier     int code;
7617dd7cddfSDavid du Colombier     ref token;			/* token read from file or string, */
7627dd7cddfSDavid du Colombier 				/* must be declared in this scope */
7637dd7cddfSDavid du Colombier     register const ref *pvalue;
7647dd7cddfSDavid du Colombier     os_ptr whichp;
7657dd7cddfSDavid du Colombier 
7667dd7cddfSDavid du Colombier     /*
7677dd7cddfSDavid du Colombier      * We have to make the error information into a struct;
7687dd7cddfSDavid du Colombier      * otherwise, the Watcom compiler will assign it to registers
7697dd7cddfSDavid du Colombier      * strictly on the basis of textual frequency.
7707dd7cddfSDavid du Colombier      * We also have to use ref_assign_inline everywhere, and
7717dd7cddfSDavid du Colombier      * avoid direct assignments of refs, so that esi and edi
7727dd7cddfSDavid du Colombier      * will remain available on Intel processors.
7737dd7cddfSDavid du Colombier      */
7747dd7cddfSDavid du Colombier     struct interp_error_s {
7757dd7cddfSDavid du Colombier 	int code;
7767dd7cddfSDavid du Colombier 	int line;
7777dd7cddfSDavid du Colombier 	const ref *obj;
7787dd7cddfSDavid du Colombier 	ref full;
7797dd7cddfSDavid du Colombier     } ierror;
7807dd7cddfSDavid du Colombier 
7817dd7cddfSDavid du Colombier     /*
7827dd7cddfSDavid du Colombier      * Get a pointer to the name table so that we can use the
7837dd7cddfSDavid du Colombier      * inline version of name_index_ref.
7847dd7cddfSDavid du Colombier      */
785*593dc095SDavid du Colombier     const name_table *const int_nt = imemory->gs_lib_ctx->gs_name_table;
7867dd7cddfSDavid du Colombier 
7877dd7cddfSDavid du Colombier #define set_error(ecode)\
7887dd7cddfSDavid du Colombier   { ierror.code = ecode; ierror.line = __LINE__; }
7897dd7cddfSDavid du Colombier #define return_with_error(ecode, objp)\
7907dd7cddfSDavid du Colombier   { set_error(ecode); ierror.obj = objp; goto rwe; }
7917dd7cddfSDavid du Colombier #define return_with_error_iref(ecode)\
7927dd7cddfSDavid du Colombier   { set_error(ecode); goto rwei; }
7937dd7cddfSDavid du Colombier #define return_with_code_iref()\
7947dd7cddfSDavid du Colombier   { ierror.line = __LINE__; goto rweci; }
7957dd7cddfSDavid du Colombier #define return_with_error_code_op(nargs)\
7967dd7cddfSDavid du Colombier   return_with_code_iref()
7977dd7cddfSDavid du Colombier #define return_with_stackoverflow(objp)\
7987dd7cddfSDavid du Colombier   { o_stack.requested = 1; return_with_error(e_stackoverflow, objp); }
7997dd7cddfSDavid du Colombier #define return_with_stackoverflow_iref()\
8007dd7cddfSDavid du Colombier   { o_stack.requested = 1; return_with_error_iref(e_stackoverflow); }
8017dd7cddfSDavid du Colombier     int ticks_left = gs_interp_time_slice_ticks;
8027dd7cddfSDavid du Colombier 
8037dd7cddfSDavid du Colombier     /*
804*593dc095SDavid du Colombier      * If we exceed the VMThreshold, set ticks_left to -100
8057dd7cddfSDavid du Colombier      * to alert the interpreter that we need to garbage collect.
8067dd7cddfSDavid du Colombier      */
8077dd7cddfSDavid du Colombier     set_gc_signal(i_ctx_p, &ticks_left, -100);
8087dd7cddfSDavid du Colombier 
8097dd7cddfSDavid du Colombier     esfile_clear_cache();
8107dd7cddfSDavid du Colombier     /*
8117dd7cddfSDavid du Colombier      * From here on, if icount > 0, iref and icount correspond
8127dd7cddfSDavid du Colombier      * to the top entry on the execution stack: icount is the count
8137dd7cddfSDavid du Colombier      * of sequential entries remaining AFTER the current one.
8147dd7cddfSDavid du Colombier      */
8157dd7cddfSDavid du Colombier #define IREF_NEXT(ip)\
8167dd7cddfSDavid du Colombier   ((const ref_packed *)((const ref *)(ip) + 1))
8177dd7cddfSDavid du Colombier #define IREF_NEXT_EITHER(ip)\
8187dd7cddfSDavid du Colombier   ( r_is_packed(ip) ? (ip) + 1 : IREF_NEXT(ip) )
8197dd7cddfSDavid du Colombier #define store_state(ep)\
8207dd7cddfSDavid du Colombier   ( icount > 0 ? (ep->value.const_refs = IREF + 1, r_set_size(ep, icount)) : 0 )
8217dd7cddfSDavid du Colombier #define store_state_short(ep)\
8227dd7cddfSDavid du Colombier   ( icount > 0 ? (ep->value.packed = iref_packed + 1, r_set_size(ep, icount)) : 0 )
8237dd7cddfSDavid du Colombier #define store_state_either(ep)\
8247dd7cddfSDavid du Colombier   ( icount > 0 ? (ep->value.packed = IREF_NEXT_EITHER(iref_packed), r_set_size(ep, icount)) : 0 )
8257dd7cddfSDavid du Colombier #define next()\
8267dd7cddfSDavid du Colombier   if ( --icount > 0 ) { iref_packed = IREF_NEXT(iref_packed); goto top; } else goto out
8277dd7cddfSDavid du Colombier #define next_short()\
8287dd7cddfSDavid du Colombier   if ( --icount <= 0 ) { if ( icount < 0 ) goto up; iesp--; }\
8297dd7cddfSDavid du Colombier   ++iref_packed; goto top
8307dd7cddfSDavid du Colombier #define next_either()\
8317dd7cddfSDavid du Colombier   if ( --icount <= 0 ) { if ( icount < 0 ) goto up; iesp--; }\
8327dd7cddfSDavid du Colombier   iref_packed = IREF_NEXT_EITHER(iref_packed); goto top
8337dd7cddfSDavid du Colombier 
8347dd7cddfSDavid du Colombier #if !PACKED_SPECIAL_OPS
8357dd7cddfSDavid du Colombier #  undef next_either
8367dd7cddfSDavid du Colombier #  define next_either() next()
8377dd7cddfSDavid du Colombier #  undef store_state_either
8387dd7cddfSDavid du Colombier #  define store_state_either(ep) store_state(ep)
8397dd7cddfSDavid du Colombier #endif
8407dd7cddfSDavid du Colombier 
8417dd7cddfSDavid du Colombier     /* We want to recognize executable arrays here, */
8427dd7cddfSDavid du Colombier     /* so we push the argument on the estack and enter */
8437dd7cddfSDavid du Colombier     /* the loop at the bottom. */
8447dd7cddfSDavid du Colombier     if (iesp >= estop)
8457dd7cddfSDavid du Colombier 	return_with_error(e_execstackoverflow, pref);
8467dd7cddfSDavid du Colombier     ++iesp;
8477dd7cddfSDavid du Colombier     ref_assign_inline(iesp, pref);
8487dd7cddfSDavid du Colombier     goto bot;
8497dd7cddfSDavid du Colombier   top:
8507dd7cddfSDavid du Colombier 	/*
8517dd7cddfSDavid du Colombier 	 * This is the top of the interpreter loop.
8527dd7cddfSDavid du Colombier 	 * iref points to the ref being interpreted.
8537dd7cddfSDavid du Colombier 	 * Note that this might be an element of a packed array,
8547dd7cddfSDavid du Colombier 	 * not a real ref: we carefully arranged the first 16 bits of
8557dd7cddfSDavid du Colombier 	 * a ref and of a packed array element so they could be distinguished
8567dd7cddfSDavid du Colombier 	 * from each other.  (See ghost.h and packed.h for more detail.)
8577dd7cddfSDavid du Colombier 	 */
8587dd7cddfSDavid du Colombier     INCR(top);
8597dd7cddfSDavid du Colombier #ifdef DEBUG
8607dd7cddfSDavid du Colombier     /* Do a little validation on the top o-stack entry. */
8617dd7cddfSDavid du Colombier     if (iosp >= osbot &&
8627dd7cddfSDavid du Colombier 	(r_type(iosp) == t__invalid || r_type(iosp) >= tx_next_op)
8637dd7cddfSDavid du Colombier 	) {
8647dd7cddfSDavid du Colombier 	lprintf("Invalid value on o-stack!\n");
8657dd7cddfSDavid du Colombier 	return_with_error_iref(e_Fatal);
8667dd7cddfSDavid du Colombier     }
8677dd7cddfSDavid du Colombier     if (gs_debug['I'] ||
8687dd7cddfSDavid du Colombier 	(gs_debug['i'] &&
8697dd7cddfSDavid du Colombier 	 (r_is_packed(iref_packed) ?
8707dd7cddfSDavid du Colombier 	  r_packed_is_name(iref_packed) :
8717dd7cddfSDavid du Colombier 	  r_has_type(IREF, t_name)))
8727dd7cddfSDavid du Colombier 	) {
8737dd7cddfSDavid du Colombier 	os_ptr save_osp = osp;	/* avoid side-effects */
8747dd7cddfSDavid du Colombier 	es_ptr save_esp = esp;
8757dd7cddfSDavid du Colombier 
8767dd7cddfSDavid du Colombier 	osp = iosp;
8777dd7cddfSDavid du Colombier 	esp = iesp;
8787dd7cddfSDavid du Colombier 	dlprintf5("d%u,e%u<%u>0x%lx(%d): ",
8797dd7cddfSDavid du Colombier 		  ref_stack_count(&d_stack), ref_stack_count(&e_stack),
8807dd7cddfSDavid du Colombier 		  ref_stack_count(&o_stack), (ulong)IREF, icount);
881*593dc095SDavid du Colombier 	debug_print_ref(imemory, IREF);
8827dd7cddfSDavid du Colombier 	if (iosp >= osbot) {
8837dd7cddfSDavid du Colombier 	    dputs(" // ");
884*593dc095SDavid du Colombier 	    debug_print_ref(imemory, iosp);
8857dd7cddfSDavid du Colombier 	}
8867dd7cddfSDavid du Colombier 	dputc('\n');
8877dd7cddfSDavid du Colombier 	osp = save_osp;
8887dd7cddfSDavid du Colombier 	esp = save_esp;
8897dd7cddfSDavid du Colombier 	fflush(dstderr);
8907dd7cddfSDavid du Colombier     }
8917dd7cddfSDavid du Colombier #endif
8927dd7cddfSDavid du Colombier /* Objects that have attributes (arrays, dictionaries, files, and strings) */
8937dd7cddfSDavid du Colombier /* use lit and exec; other objects use plain and plain_exec. */
8947dd7cddfSDavid du Colombier #define lit(t) type_xe_value(t, a_execute)
8957dd7cddfSDavid du Colombier #define exec(t) type_xe_value(t, a_execute + a_executable)
8967dd7cddfSDavid du Colombier #define nox(t) type_xe_value(t, 0)
8977dd7cddfSDavid du Colombier #define nox_exec(t) type_xe_value(t, a_executable)
8987dd7cddfSDavid du Colombier #define plain(t) type_xe_value(t, 0)
8997dd7cddfSDavid du Colombier #define plain_exec(t) type_xe_value(t, a_executable)
9007dd7cddfSDavid du Colombier     /*
9017dd7cddfSDavid du Colombier      * We have to populate enough cases of the switch statement to force
9027dd7cddfSDavid du Colombier      * some compilers to use a dispatch rather than a testing loop.
9037dd7cddfSDavid du Colombier      * What a nuisance!
9047dd7cddfSDavid du Colombier      */
9057dd7cddfSDavid du Colombier     switch (r_type_xe(iref_packed)) {
9067dd7cddfSDavid du Colombier 	    /* Access errors. */
9077dd7cddfSDavid du Colombier #define cases_invalid()\
9087dd7cddfSDavid du Colombier   case plain(t__invalid): case plain_exec(t__invalid)
9097dd7cddfSDavid du Colombier 	  cases_invalid():
9107dd7cddfSDavid du Colombier 	    return_with_error_iref(e_Fatal);
9117dd7cddfSDavid du Colombier #define cases_nox()\
9127dd7cddfSDavid du Colombier   case nox_exec(t_array): case nox_exec(t_dictionary):\
9137dd7cddfSDavid du Colombier   case nox_exec(t_file): case nox_exec(t_string):\
9147dd7cddfSDavid du Colombier   case nox_exec(t_mixedarray): case nox_exec(t_shortarray)
9157dd7cddfSDavid du Colombier 	  cases_nox():
9167dd7cddfSDavid du Colombier 	    return_with_error_iref(e_invalidaccess);
9177dd7cddfSDavid du Colombier 	    /*
9187dd7cddfSDavid du Colombier 	     * Literal objects.  We have to enumerate all the types.
9197dd7cddfSDavid du Colombier 	     * In fact, we have to include some extra plain_exec entries
9207dd7cddfSDavid du Colombier 	     * just to populate the switch.  We break them up into groups
9217dd7cddfSDavid du Colombier 	     * to avoid overflowing some preprocessors.
9227dd7cddfSDavid du Colombier 	     */
9237dd7cddfSDavid du Colombier #define cases_lit_1()\
9247dd7cddfSDavid du Colombier   case lit(t_array): case nox(t_array):\
9257dd7cddfSDavid du Colombier   case plain(t_boolean): case plain_exec(t_boolean):\
9267dd7cddfSDavid du Colombier   case lit(t_dictionary): case nox(t_dictionary)
9277dd7cddfSDavid du Colombier #define cases_lit_2()\
9287dd7cddfSDavid du Colombier   case lit(t_file): case nox(t_file):\
9297dd7cddfSDavid du Colombier   case plain(t_fontID): case plain_exec(t_fontID):\
9307dd7cddfSDavid du Colombier   case plain(t_integer): case plain_exec(t_integer):\
9317dd7cddfSDavid du Colombier   case plain(t_mark): case plain_exec(t_mark)
9327dd7cddfSDavid du Colombier #define cases_lit_3()\
9337dd7cddfSDavid du Colombier   case plain(t_name):\
9347dd7cddfSDavid du Colombier   case plain(t_null):\
9357dd7cddfSDavid du Colombier   case plain(t_oparray):\
9367dd7cddfSDavid du Colombier   case plain(t_operator)
9377dd7cddfSDavid du Colombier #define cases_lit_4()\
9387dd7cddfSDavid du Colombier   case plain(t_real): case plain_exec(t_real):\
9397dd7cddfSDavid du Colombier   case plain(t_save): case plain_exec(t_save):\
9407dd7cddfSDavid du Colombier   case lit(t_string): case nox(t_string)
9417dd7cddfSDavid du Colombier #define cases_lit_5()\
9427dd7cddfSDavid du Colombier   case lit(t_mixedarray): case nox(t_mixedarray):\
9437dd7cddfSDavid du Colombier   case lit(t_shortarray): case nox(t_shortarray):\
9447dd7cddfSDavid du Colombier   case plain(t_device): case plain_exec(t_device):\
9457dd7cddfSDavid du Colombier   case plain(t_struct): case plain_exec(t_struct):\
9467dd7cddfSDavid du Colombier   case plain(t_astruct): case plain_exec(t_astruct)
9477dd7cddfSDavid du Colombier 	    /* Executable arrays are treated as literals in direct execution. */
9487dd7cddfSDavid du Colombier #define cases_lit_array()\
9497dd7cddfSDavid du Colombier   case exec(t_array): case exec(t_mixedarray): case exec(t_shortarray)
9507dd7cddfSDavid du Colombier 	  cases_lit_1():
9517dd7cddfSDavid du Colombier 	  cases_lit_2():
9527dd7cddfSDavid du Colombier 	  cases_lit_3():
9537dd7cddfSDavid du Colombier 	  cases_lit_4():
9547dd7cddfSDavid du Colombier 	  cases_lit_5():
9557dd7cddfSDavid du Colombier 	    INCR(lit);
9567dd7cddfSDavid du Colombier 	    break;
9577dd7cddfSDavid du Colombier 	  cases_lit_array():
9587dd7cddfSDavid du Colombier 	    INCR(lit_array);
9597dd7cddfSDavid du Colombier 	    break;
9607dd7cddfSDavid du Colombier 	    /* Special operators. */
9617dd7cddfSDavid du Colombier 	case plain_exec(tx_op_add):
9627dd7cddfSDavid du Colombier x_add:	    INCR(x_add);
9637dd7cddfSDavid du Colombier 	    if ((code = zop_add(iosp)) < 0)
9647dd7cddfSDavid du Colombier 		return_with_error_code_op(2);
9657dd7cddfSDavid du Colombier 	    iosp--;
9667dd7cddfSDavid du Colombier 	    next_either();
9677dd7cddfSDavid du Colombier 	case plain_exec(tx_op_def):
9687dd7cddfSDavid du Colombier x_def:	    INCR(x_def);
9697dd7cddfSDavid du Colombier 	    osp = iosp;	/* sync o_stack */
9707dd7cddfSDavid du Colombier 	    if ((code = zop_def(i_ctx_p)) < 0)
9717dd7cddfSDavid du Colombier 		return_with_error_code_op(2);
9727dd7cddfSDavid du Colombier 	    iosp -= 2;
9737dd7cddfSDavid du Colombier 	    next_either();
9747dd7cddfSDavid du Colombier 	case plain_exec(tx_op_dup):
9757dd7cddfSDavid du Colombier x_dup:	    INCR(x_dup);
9767dd7cddfSDavid du Colombier 	    if (iosp < osbot)
9777dd7cddfSDavid du Colombier 		return_with_error_iref(e_stackunderflow);
9787dd7cddfSDavid du Colombier 	    if (iosp >= ostop)
9797dd7cddfSDavid du Colombier 		return_with_stackoverflow_iref();
9807dd7cddfSDavid du Colombier 	    iosp++;
9817dd7cddfSDavid du Colombier 	    ref_assign_inline(iosp, iosp - 1);
9827dd7cddfSDavid du Colombier 	    next_either();
9837dd7cddfSDavid du Colombier 	case plain_exec(tx_op_exch):
9847dd7cddfSDavid du Colombier x_exch:	    INCR(x_exch);
9857dd7cddfSDavid du Colombier 	    if (iosp <= osbot)
9867dd7cddfSDavid du Colombier 		return_with_error_iref(e_stackunderflow);
9877dd7cddfSDavid du Colombier 	    ref_assign_inline(&token, iosp);
9887dd7cddfSDavid du Colombier 	    ref_assign_inline(iosp, iosp - 1);
9897dd7cddfSDavid du Colombier 	    ref_assign_inline(iosp - 1, &token);
9907dd7cddfSDavid du Colombier 	    next_either();
9917dd7cddfSDavid du Colombier 	case plain_exec(tx_op_if):
9927dd7cddfSDavid du Colombier x_if:	    INCR(x_if);
9937dd7cddfSDavid du Colombier 	    if (!r_has_type(iosp - 1, t_boolean))
9947dd7cddfSDavid du Colombier 		return_with_error_iref((iosp <= osbot ?
9957dd7cddfSDavid du Colombier 					e_stackunderflow : e_typecheck));
9967dd7cddfSDavid du Colombier 	    if (!r_is_proc(iosp))
9977dd7cddfSDavid du Colombier 		return_with_error_iref(check_proc_failed(iosp));
9987dd7cddfSDavid du Colombier 	    if (!iosp[-1].value.boolval) {
9997dd7cddfSDavid du Colombier 		iosp -= 2;
10007dd7cddfSDavid du Colombier 		next_either();
10017dd7cddfSDavid du Colombier 	    }
10027dd7cddfSDavid du Colombier 	    if (iesp >= estop)
10037dd7cddfSDavid du Colombier 		return_with_error_iref(e_execstackoverflow);
10047dd7cddfSDavid du Colombier 	    store_state_either(iesp);
10057dd7cddfSDavid du Colombier 	    whichp = iosp;
10067dd7cddfSDavid du Colombier 	    iosp -= 2;
10077dd7cddfSDavid du Colombier 	    goto ifup;
10087dd7cddfSDavid du Colombier 	case plain_exec(tx_op_ifelse):
10097dd7cddfSDavid du Colombier x_ifelse:   INCR(x_ifelse);
10107dd7cddfSDavid du Colombier 	    if (!r_has_type(iosp - 2, t_boolean))
10117dd7cddfSDavid du Colombier 		return_with_error_iref((iosp < osbot + 2 ?
10127dd7cddfSDavid du Colombier 					e_stackunderflow : e_typecheck));
10137dd7cddfSDavid du Colombier 	    if (!r_is_proc(iosp - 1))
10147dd7cddfSDavid du Colombier 		return_with_error_iref(check_proc_failed(iosp - 1));
10157dd7cddfSDavid du Colombier 	    if (!r_is_proc(iosp))
10167dd7cddfSDavid du Colombier 		return_with_error_iref(check_proc_failed(iosp));
10177dd7cddfSDavid du Colombier 	    if (iesp >= estop)
10187dd7cddfSDavid du Colombier 		return_with_error_iref(e_execstackoverflow);
10197dd7cddfSDavid du Colombier 	    store_state_either(iesp);
10207dd7cddfSDavid du Colombier 	    whichp = (iosp[-2].value.boolval ? iosp - 1 : iosp);
10217dd7cddfSDavid du Colombier 	    iosp -= 3;
10227dd7cddfSDavid du Colombier 	    /* Open code "up" for the array case(s) */
10237dd7cddfSDavid du Colombier 	  ifup:if ((icount = r_size(whichp) - 1) <= 0) {
10247dd7cddfSDavid du Colombier 		if (icount < 0)
10257dd7cddfSDavid du Colombier 		    goto up;	/* 0-element proc */
10267dd7cddfSDavid du Colombier 		SET_IREF(whichp->value.refs);	/* 1-element proc */
10277dd7cddfSDavid du Colombier 		if (--ticks_left > 0)
10287dd7cddfSDavid du Colombier 		    goto top;
10297dd7cddfSDavid du Colombier 	    }
10307dd7cddfSDavid du Colombier 	    ++iesp;
10317dd7cddfSDavid du Colombier 	    /* Do a ref_assign, but also set iref. */
10327dd7cddfSDavid du Colombier 	    iesp->tas = whichp->tas;
10337dd7cddfSDavid du Colombier 	    SET_IREF(iesp->value.refs = whichp->value.refs);
10347dd7cddfSDavid du Colombier 	    if (--ticks_left > 0)
10357dd7cddfSDavid du Colombier 		goto top;
10367dd7cddfSDavid du Colombier 	    goto slice;
10377dd7cddfSDavid du Colombier 	case plain_exec(tx_op_index):
10387dd7cddfSDavid du Colombier x_index:    INCR(x_index);
10397dd7cddfSDavid du Colombier 	    osp = iosp;	/* zindex references o_stack */
10407dd7cddfSDavid du Colombier 	    if ((code = zindex(i_ctx_p)) < 0)
10417dd7cddfSDavid du Colombier 		return_with_error_code_op(1);
10427dd7cddfSDavid du Colombier 	    next_either();
10437dd7cddfSDavid du Colombier 	case plain_exec(tx_op_pop):
10447dd7cddfSDavid du Colombier x_pop:	    INCR(x_pop);
10457dd7cddfSDavid du Colombier 	    if (iosp < osbot)
10467dd7cddfSDavid du Colombier 		return_with_error_iref(e_stackunderflow);
10477dd7cddfSDavid du Colombier 	    iosp--;
10487dd7cddfSDavid du Colombier 	    next_either();
10497dd7cddfSDavid du Colombier 	case plain_exec(tx_op_roll):
10507dd7cddfSDavid du Colombier x_roll:	    INCR(x_roll);
10517dd7cddfSDavid du Colombier 	    osp = iosp;	/* zroll references o_stack */
10527dd7cddfSDavid du Colombier 	    if ((code = zroll(i_ctx_p)) < 0)
10537dd7cddfSDavid du Colombier 		return_with_error_code_op(2);
10547dd7cddfSDavid du Colombier 	    iosp -= 2;
10557dd7cddfSDavid du Colombier 	    next_either();
10567dd7cddfSDavid du Colombier 	case plain_exec(tx_op_sub):
10577dd7cddfSDavid du Colombier x_sub:	    INCR(x_sub);
10587dd7cddfSDavid du Colombier 	    if ((code = zop_sub(iosp)) < 0)
10597dd7cddfSDavid du Colombier 		return_with_error_code_op(2);
10607dd7cddfSDavid du Colombier 	    iosp--;
10617dd7cddfSDavid du Colombier 	    next_either();
10627dd7cddfSDavid du Colombier 	    /* Executable types. */
10637dd7cddfSDavid du Colombier 	case plain_exec(t_null):
10647dd7cddfSDavid du Colombier 	    goto bot;
10657dd7cddfSDavid du Colombier 	case plain_exec(t_oparray):
10667dd7cddfSDavid du Colombier 	    /* Replace with the definition and go again. */
10677dd7cddfSDavid du Colombier 	    INCR(exec_array);
10687dd7cddfSDavid du Colombier 	    pvalue = IREF->value.const_refs;
10697dd7cddfSDavid du Colombier 	  opst:		/* Prepare to call a t_oparray procedure in *pvalue. */
10707dd7cddfSDavid du Colombier 	    store_state(iesp);
10717dd7cddfSDavid du Colombier 	  oppr:		/* Record the stack depths in case of failure. */
10727dd7cddfSDavid du Colombier 	    if (iesp >= estop - 3)
10737dd7cddfSDavid du Colombier 		return_with_error_iref(e_execstackoverflow);
10747dd7cddfSDavid du Colombier 	    iesp += 4;
10757dd7cddfSDavid du Colombier 	    osp = iosp;		/* ref_stack_count_inline needs this */
10767dd7cddfSDavid du Colombier 	    make_mark_estack(iesp - 3, es_other, oparray_cleanup);
10777dd7cddfSDavid du Colombier 	    make_int(iesp - 2, ref_stack_count_inline(&o_stack));
10787dd7cddfSDavid du Colombier 	    make_int(iesp - 1, ref_stack_count_inline(&d_stack));
10797dd7cddfSDavid du Colombier 	    make_op_estack(iesp, oparray_pop);
10807dd7cddfSDavid du Colombier 	    goto pr;
10817dd7cddfSDavid du Colombier 	  prst:		/* Prepare to call the procedure (array) in *pvalue. */
10827dd7cddfSDavid du Colombier 	    store_state(iesp);
10837dd7cddfSDavid du Colombier 	  pr:			/* Call the array in *pvalue.  State has been stored. */
10847dd7cddfSDavid du Colombier 	    if ((icount = r_size(pvalue) - 1) <= 0) {
10857dd7cddfSDavid du Colombier 		if (icount < 0)
10867dd7cddfSDavid du Colombier 		    goto up;	/* 0-element proc */
10877dd7cddfSDavid du Colombier 		SET_IREF(pvalue->value.refs);	/* 1-element proc */
10887dd7cddfSDavid du Colombier 		if (--ticks_left > 0)
10897dd7cddfSDavid du Colombier 		    goto top;
10907dd7cddfSDavid du Colombier 	    }
10917dd7cddfSDavid du Colombier 	    if (iesp >= estop)
10927dd7cddfSDavid du Colombier 		return_with_error_iref(e_execstackoverflow);
10937dd7cddfSDavid du Colombier 	    ++iesp;
10947dd7cddfSDavid du Colombier 	    /* Do a ref_assign, but also set iref. */
10957dd7cddfSDavid du Colombier 	    iesp->tas = pvalue->tas;
10967dd7cddfSDavid du Colombier 	    SET_IREF(iesp->value.refs = pvalue->value.refs);
10977dd7cddfSDavid du Colombier 	    if (--ticks_left > 0)
10987dd7cddfSDavid du Colombier 		goto top;
10997dd7cddfSDavid du Colombier 	    goto slice;
11007dd7cddfSDavid du Colombier 	case plain_exec(t_operator):
11017dd7cddfSDavid du Colombier 	    INCR(exec_operator);
11027dd7cddfSDavid du Colombier 	    if (--ticks_left <= 0) {	/* The following doesn't work, */
11037dd7cddfSDavid du Colombier 		/* and I can't figure out why. */
11047dd7cddfSDavid du Colombier /****** goto sst; ******/
11057dd7cddfSDavid du Colombier 	    }
11067dd7cddfSDavid du Colombier 	    esp = iesp;		/* save for operator */
11077dd7cddfSDavid du Colombier 	    osp = iosp;		/* ditto */
11087dd7cddfSDavid du Colombier 	    /* Operator routines take osp as an argument. */
11097dd7cddfSDavid du Colombier 	    /* This is just a convenience, since they adjust */
11107dd7cddfSDavid du Colombier 	    /* osp themselves to reflect the results. */
11117dd7cddfSDavid du Colombier 	    /* Operators that (net) push information on the */
11127dd7cddfSDavid du Colombier 	    /* operand stack must check for overflow: */
11137dd7cddfSDavid du Colombier 	    /* this normally happens automatically through */
11147dd7cddfSDavid du Colombier 	    /* the push macro (in oper.h). */
11157dd7cddfSDavid du Colombier 	    /* Operators that do not typecheck their operands, */
11167dd7cddfSDavid du Colombier 	    /* or take a variable number of arguments, */
11177dd7cddfSDavid du Colombier 	    /* must check explicitly for stack underflow. */
11187dd7cddfSDavid du Colombier 	    /* (See oper.h for more detail.) */
11197dd7cddfSDavid du Colombier 	    /* Note that each case must set iosp = osp: */
11207dd7cddfSDavid du Colombier 	    /* this is so we can switch on code without having to */
11217dd7cddfSDavid du Colombier 	    /* store it and reload it (for dumb compilers). */
11227dd7cddfSDavid du Colombier 	    switch (code = call_operator(real_opproc(IREF), i_ctx_p)) {
11237dd7cddfSDavid du Colombier 		case 0:	/* normal case */
11247dd7cddfSDavid du Colombier 		case 1:	/* alternative success case */
11257dd7cddfSDavid du Colombier 		    iosp = osp;
11267dd7cddfSDavid du Colombier 		    next();
11277dd7cddfSDavid du Colombier 		case o_push_estack:	/* store the state and go to up */
11287dd7cddfSDavid du Colombier 		    store_state(iesp);
11297dd7cddfSDavid du Colombier 		  opush:iosp = osp;
11307dd7cddfSDavid du Colombier 		    iesp = esp;
11317dd7cddfSDavid du Colombier 		    if (--ticks_left > 0)
11327dd7cddfSDavid du Colombier 			goto up;
11337dd7cddfSDavid du Colombier 		    goto slice;
11347dd7cddfSDavid du Colombier 		case o_pop_estack:	/* just go to up */
11357dd7cddfSDavid du Colombier 		  opop:iosp = osp;
11367dd7cddfSDavid du Colombier 		    if (esp == iesp)
11377dd7cddfSDavid du Colombier 			goto bot;
11387dd7cddfSDavid du Colombier 		    iesp = esp;
11397dd7cddfSDavid du Colombier 		    goto up;
11407dd7cddfSDavid du Colombier 		case o_reschedule:
11417dd7cddfSDavid du Colombier 		    store_state(iesp);
11427dd7cddfSDavid du Colombier 		    goto res;
11437dd7cddfSDavid du Colombier 		case e_RemapColor:
11447dd7cddfSDavid du Colombier oe_remap:	    store_state(iesp);
11457dd7cddfSDavid du Colombier remap:		    if (iesp + 2 >= estop) {
11467dd7cddfSDavid du Colombier 			esp = iesp;
11477dd7cddfSDavid du Colombier 			code = ref_stack_extend(&e_stack, 2);
11487dd7cddfSDavid du Colombier 			if (code < 0)
11497dd7cddfSDavid du Colombier 			    return_with_error_iref(code);
11507dd7cddfSDavid du Colombier 			iesp = esp;
11517dd7cddfSDavid du Colombier 		    }
1152*593dc095SDavid du Colombier 		    packed_get(imemory, iref_packed, iesp + 1);
11537dd7cddfSDavid du Colombier 		    make_oper(iesp + 2, 0,
11547dd7cddfSDavid du Colombier 			      r_ptr(&istate->remap_color_info,
11557dd7cddfSDavid du Colombier 				    int_remap_color_info_t)->proc);
11567dd7cddfSDavid du Colombier 		    iesp += 2;
11577dd7cddfSDavid du Colombier 		    goto up;
11587dd7cddfSDavid du Colombier 	    }
11597dd7cddfSDavid du Colombier 	    iosp = osp;
11607dd7cddfSDavid du Colombier 	    iesp = esp;
11617dd7cddfSDavid du Colombier 	    return_with_code_iref();
11627dd7cddfSDavid du Colombier 	case plain_exec(t_name):
11637dd7cddfSDavid du Colombier 	    INCR(exec_name);
11647dd7cddfSDavid du Colombier 	    pvalue = IREF->value.pname->pvalue;
11657dd7cddfSDavid du Colombier 	    if (!pv_valid(pvalue)) {
11667dd7cddfSDavid du Colombier 		uint nidx = names_index(int_nt, IREF);
11677dd7cddfSDavid du Colombier 		uint htemp;
11687dd7cddfSDavid du Colombier 
11697dd7cddfSDavid du Colombier 		INCR(find_name);
11707dd7cddfSDavid du Colombier 		if ((pvalue = dict_find_name_by_index_inline(nidx, htemp)) == 0)
11717dd7cddfSDavid du Colombier 		    return_with_error_iref(e_undefined);
11727dd7cddfSDavid du Colombier 	    }
11737dd7cddfSDavid du Colombier 	    /* Dispatch on the type of the value. */
11747dd7cddfSDavid du Colombier 	    /* Again, we have to over-populate the switch. */
11757dd7cddfSDavid du Colombier 	    switch (r_type_xe(pvalue)) {
11767dd7cddfSDavid du Colombier 		  cases_invalid():
11777dd7cddfSDavid du Colombier 		    return_with_error_iref(e_Fatal);
11787dd7cddfSDavid du Colombier 		  cases_nox():	/* access errors */
11797dd7cddfSDavid du Colombier 		    return_with_error_iref(e_invalidaccess);
11807dd7cddfSDavid du Colombier 		  cases_lit_1():
11817dd7cddfSDavid du Colombier 		  cases_lit_2():
11827dd7cddfSDavid du Colombier 		  cases_lit_3():
11837dd7cddfSDavid du Colombier 		  cases_lit_4():
11847dd7cddfSDavid du Colombier 		  cases_lit_5():
11857dd7cddfSDavid du Colombier 		      INCR(name_lit);
11867dd7cddfSDavid du Colombier 		    /* Just push the value */
11877dd7cddfSDavid du Colombier 		    if (iosp >= ostop)
11887dd7cddfSDavid du Colombier 			return_with_stackoverflow(pvalue);
11897dd7cddfSDavid du Colombier 		    ++iosp;
11907dd7cddfSDavid du Colombier 		    ref_assign_inline(iosp, pvalue);
11917dd7cddfSDavid du Colombier 		    next();
11927dd7cddfSDavid du Colombier 		case exec(t_array):
11937dd7cddfSDavid du Colombier 		case exec(t_mixedarray):
11947dd7cddfSDavid du Colombier 		case exec(t_shortarray):
11957dd7cddfSDavid du Colombier 		    INCR(name_proc);
11967dd7cddfSDavid du Colombier 		    /* This is an executable procedure, execute it. */
11977dd7cddfSDavid du Colombier 		    goto prst;
11987dd7cddfSDavid du Colombier 		case plain_exec(tx_op_add):
11997dd7cddfSDavid du Colombier 		    goto x_add;
12007dd7cddfSDavid du Colombier 		case plain_exec(tx_op_def):
12017dd7cddfSDavid du Colombier 		    goto x_def;
12027dd7cddfSDavid du Colombier 		case plain_exec(tx_op_dup):
12037dd7cddfSDavid du Colombier 		    goto x_dup;
12047dd7cddfSDavid du Colombier 		case plain_exec(tx_op_exch):
12057dd7cddfSDavid du Colombier 		    goto x_exch;
12067dd7cddfSDavid du Colombier 		case plain_exec(tx_op_if):
12077dd7cddfSDavid du Colombier 		    goto x_if;
12087dd7cddfSDavid du Colombier 		case plain_exec(tx_op_ifelse):
12097dd7cddfSDavid du Colombier 		    goto x_ifelse;
12107dd7cddfSDavid du Colombier 		case plain_exec(tx_op_index):
12117dd7cddfSDavid du Colombier 		    goto x_index;
12127dd7cddfSDavid du Colombier 		case plain_exec(tx_op_pop):
12137dd7cddfSDavid du Colombier 		    goto x_pop;
12147dd7cddfSDavid du Colombier 		case plain_exec(tx_op_roll):
12157dd7cddfSDavid du Colombier 		    goto x_roll;
12167dd7cddfSDavid du Colombier 		case plain_exec(tx_op_sub):
12177dd7cddfSDavid du Colombier 		    goto x_sub;
12187dd7cddfSDavid du Colombier 		case plain_exec(t_null):
12197dd7cddfSDavid du Colombier 		    goto bot;
12207dd7cddfSDavid du Colombier 		case plain_exec(t_oparray):
12217dd7cddfSDavid du Colombier 		    INCR(name_oparray);
12227dd7cddfSDavid du Colombier 		    pvalue = (const ref *)pvalue->value.const_refs;
12237dd7cddfSDavid du Colombier 		    goto opst;
12247dd7cddfSDavid du Colombier 		case plain_exec(t_operator):
12257dd7cddfSDavid du Colombier 		    INCR(name_operator);
12267dd7cddfSDavid du Colombier 		    {		/* Shortcut for operators. */
12277dd7cddfSDavid du Colombier 			/* See above for the logic. */
12287dd7cddfSDavid du Colombier 			if (--ticks_left <= 0) {	/* The following doesn't work, */
12297dd7cddfSDavid du Colombier 			    /* and I can't figure out why. */
12307dd7cddfSDavid du Colombier /****** goto sst; ******/
12317dd7cddfSDavid du Colombier 			}
12327dd7cddfSDavid du Colombier 			esp = iesp;
12337dd7cddfSDavid du Colombier 			osp = iosp;
12347dd7cddfSDavid du Colombier 			switch (code = call_operator(real_opproc(pvalue),
12357dd7cddfSDavid du Colombier 						     i_ctx_p)
12367dd7cddfSDavid du Colombier 				) {
12377dd7cddfSDavid du Colombier 			    case 0:	/* normal case */
12387dd7cddfSDavid du Colombier 			    case 1:	/* alternative success case */
12397dd7cddfSDavid du Colombier 				iosp = osp;
12407dd7cddfSDavid du Colombier 				next();
12417dd7cddfSDavid du Colombier 			    case o_push_estack:
12427dd7cddfSDavid du Colombier 				store_state(iesp);
12437dd7cddfSDavid du Colombier 				goto opush;
12447dd7cddfSDavid du Colombier 			    case o_pop_estack:
12457dd7cddfSDavid du Colombier 				goto opop;
12467dd7cddfSDavid du Colombier 			    case o_reschedule:
12477dd7cddfSDavid du Colombier 				store_state(iesp);
12487dd7cddfSDavid du Colombier 				goto res;
12497dd7cddfSDavid du Colombier 			    case e_RemapColor:
12507dd7cddfSDavid du Colombier 				goto oe_remap;
12517dd7cddfSDavid du Colombier 			}
12527dd7cddfSDavid du Colombier 			iosp = osp;
12537dd7cddfSDavid du Colombier 			iesp = esp;
12547dd7cddfSDavid du Colombier 			return_with_error(code, pvalue);
12557dd7cddfSDavid du Colombier 		    }
12567dd7cddfSDavid du Colombier 		case plain_exec(t_name):
12577dd7cddfSDavid du Colombier 		case exec(t_file):
12587dd7cddfSDavid du Colombier 		case exec(t_string):
12597dd7cddfSDavid du Colombier 		default:
12607dd7cddfSDavid du Colombier 		    /* Not a procedure, reinterpret it. */
12617dd7cddfSDavid du Colombier 		    store_state(iesp);
12627dd7cddfSDavid du Colombier 		    icount = 0;
12637dd7cddfSDavid du Colombier 		    SET_IREF(pvalue);
12647dd7cddfSDavid du Colombier 		    goto top;
12657dd7cddfSDavid du Colombier 	    }
12667dd7cddfSDavid du Colombier 	case exec(t_file):
12677dd7cddfSDavid du Colombier 	    {			/* Executable file.  Read the next token and interpret it. */
12687dd7cddfSDavid du Colombier 		stream *s;
12697dd7cddfSDavid du Colombier 		scanner_state sstate;
12707dd7cddfSDavid du Colombier 
12717dd7cddfSDavid du Colombier 		check_read_known_file(s, IREF, return_with_error_iref);
12723ff48bf5SDavid du Colombier 	    rt:
12733ff48bf5SDavid du Colombier 		if (iosp >= ostop)	/* check early */
12747dd7cddfSDavid du Colombier 		    return_with_stackoverflow_iref();
12757dd7cddfSDavid du Colombier 		osp = iosp;	/* scan_token uses ostack */
12763ff48bf5SDavid du Colombier 		scanner_state_init_options(&sstate, i_ctx_p->scanner_options);
12773ff48bf5SDavid du Colombier 	    again:
12783ff48bf5SDavid du Colombier 		code = scan_token(i_ctx_p, s, &token, &sstate);
12797dd7cddfSDavid du Colombier 		iosp = osp;	/* ditto */
12807dd7cddfSDavid du Colombier 		switch (code) {
12817dd7cddfSDavid du Colombier 		    case 0:	/* read a token */
12827dd7cddfSDavid du Colombier 			/* It's worth checking for literals, which make up */
12837dd7cddfSDavid du Colombier 			/* the majority of input tokens, before storing the */
12847dd7cddfSDavid du Colombier 			/* state on the e-stack.  Note that because of //, */
12857dd7cddfSDavid du Colombier 			/* the token may have *any* type and attributes. */
12867dd7cddfSDavid du Colombier 			/* Note also that executable arrays aren't executed */
12877dd7cddfSDavid du Colombier 			/* at the top level -- they're treated as literals. */
12887dd7cddfSDavid du Colombier 			if (!r_has_attr(&token, a_executable) ||
12897dd7cddfSDavid du Colombier 			    r_is_array(&token)
12907dd7cddfSDavid du Colombier 			    ) {	/* If scan_token used the o-stack, */
12917dd7cddfSDavid du Colombier 			    /* we know we can do a push now; if not, */
12927dd7cddfSDavid du Colombier 			    /* the pre-check is still valid. */
12937dd7cddfSDavid du Colombier 			    iosp++;
12947dd7cddfSDavid du Colombier 			    ref_assign_inline(iosp, &token);
12957dd7cddfSDavid du Colombier 			    goto rt;
12967dd7cddfSDavid du Colombier 			}
12977dd7cddfSDavid du Colombier 			store_state(iesp);
12987dd7cddfSDavid du Colombier 			/* Push the file on the e-stack */
12997dd7cddfSDavid du Colombier 			if (iesp >= estop)
13007dd7cddfSDavid du Colombier 			    return_with_error_iref(e_execstackoverflow);
13017dd7cddfSDavid du Colombier 			esfile_set_cache(++iesp);
13027dd7cddfSDavid du Colombier 			ref_assign_inline(iesp, IREF);
13037dd7cddfSDavid du Colombier 			SET_IREF(&token);
13047dd7cddfSDavid du Colombier 			icount = 0;
13057dd7cddfSDavid du Colombier 			goto top;
1306*593dc095SDavid du Colombier 		    case e_undefined:	/* //name undefined */
1307*593dc095SDavid du Colombier 			return_with_error(code, &token);
13087dd7cddfSDavid du Colombier 		    case scan_EOF:	/* end of file */
13097dd7cddfSDavid du Colombier 			esfile_clear_cache();
13107dd7cddfSDavid du Colombier 			goto bot;
13117dd7cddfSDavid du Colombier 		    case scan_BOS:
13127dd7cddfSDavid du Colombier 			/* Binary object sequences */
13137dd7cddfSDavid du Colombier 			/* ARE executed at the top level. */
13147dd7cddfSDavid du Colombier 			store_state(iesp);
13157dd7cddfSDavid du Colombier 			/* Push the file on the e-stack */
13167dd7cddfSDavid du Colombier 			if (iesp >= estop)
13177dd7cddfSDavid du Colombier 			    return_with_error_iref(e_execstackoverflow);
13187dd7cddfSDavid du Colombier 			esfile_set_cache(++iesp);
13197dd7cddfSDavid du Colombier 			ref_assign_inline(iesp, IREF);
13207dd7cddfSDavid du Colombier 			pvalue = &token;
13217dd7cddfSDavid du Colombier 			goto pr;
13227dd7cddfSDavid du Colombier 		    case scan_Refill:
13237dd7cddfSDavid du Colombier 			store_state(iesp);
13247dd7cddfSDavid du Colombier 			/* iref may point into the exec stack; */
13257dd7cddfSDavid du Colombier 			/* save its referent now. */
13267dd7cddfSDavid du Colombier 			ref_assign_inline(&token, IREF);
13277dd7cddfSDavid du Colombier 			/* Push the file on the e-stack */
13287dd7cddfSDavid du Colombier 			if (iesp >= estop)
13297dd7cddfSDavid du Colombier 			    return_with_error_iref(e_execstackoverflow);
13307dd7cddfSDavid du Colombier 			++iesp;
13317dd7cddfSDavid du Colombier 			ref_assign_inline(iesp, &token);
13327dd7cddfSDavid du Colombier 			esp = iesp;
13337dd7cddfSDavid du Colombier 			osp = iosp;
13347dd7cddfSDavid du Colombier 			code = scan_handle_refill(i_ctx_p, &token, &sstate,
13357dd7cddfSDavid du Colombier 						  true, true,
13367dd7cddfSDavid du Colombier 						  ztokenexec_continue);
13373ff48bf5SDavid du Colombier 		scan_cont:
13387dd7cddfSDavid du Colombier 			iosp = osp;
13397dd7cddfSDavid du Colombier 			iesp = esp;
13407dd7cddfSDavid du Colombier 			switch (code) {
13417dd7cddfSDavid du Colombier 			    case 0:
13427dd7cddfSDavid du Colombier 				iesp--;		/* don't push the file */
13437dd7cddfSDavid du Colombier 				goto again;	/* stacks are unchanged */
13447dd7cddfSDavid du Colombier 			    case o_push_estack:
13457dd7cddfSDavid du Colombier 				esfile_clear_cache();
13467dd7cddfSDavid du Colombier 				if (--ticks_left > 0)
13477dd7cddfSDavid du Colombier 				    goto up;
13487dd7cddfSDavid du Colombier 				goto slice;
13497dd7cddfSDavid du Colombier 			}
13507dd7cddfSDavid du Colombier 			/* must be an error */
13517dd7cddfSDavid du Colombier 			iesp--;	/* don't push the file */
13523ff48bf5SDavid du Colombier 			return_with_code_iref();
13533ff48bf5SDavid du Colombier 		    case scan_Comment:
13543ff48bf5SDavid du Colombier 		    case scan_DSC_Comment: {
13553ff48bf5SDavid du Colombier 			/* See scan_Refill above for comments. */
13563ff48bf5SDavid du Colombier 			ref file_token;
13573ff48bf5SDavid du Colombier 
13583ff48bf5SDavid du Colombier 			store_state(iesp);
13593ff48bf5SDavid du Colombier 			ref_assign_inline(&file_token, IREF);
13603ff48bf5SDavid du Colombier 			if (iesp >= estop)
13613ff48bf5SDavid du Colombier 			    return_with_error_iref(e_execstackoverflow);
13623ff48bf5SDavid du Colombier 			++iesp;
13633ff48bf5SDavid du Colombier 			ref_assign_inline(iesp, &file_token);
13643ff48bf5SDavid du Colombier 			esp = iesp;
13653ff48bf5SDavid du Colombier 			osp = iosp;
13663ff48bf5SDavid du Colombier 			code = ztoken_handle_comment(i_ctx_p, &file_token,
13673ff48bf5SDavid du Colombier 						     &sstate, &token,
13683ff48bf5SDavid du Colombier 						     code, true, true,
13693ff48bf5SDavid du Colombier 						     ztokenexec_continue);
13703ff48bf5SDavid du Colombier 		    }
13713ff48bf5SDavid du Colombier 			goto scan_cont;
13727dd7cddfSDavid du Colombier 		    default:	/* error */
13737dd7cddfSDavid du Colombier 			return_with_code_iref();
13747dd7cddfSDavid du Colombier 		}
13757dd7cddfSDavid du Colombier 	    }
13767dd7cddfSDavid du Colombier 	case exec(t_string):
13777dd7cddfSDavid du Colombier 	    {			/* Executable string.  Read a token and interpret it. */
13787dd7cddfSDavid du Colombier 		stream ss;
13797dd7cddfSDavid du Colombier 		scanner_state sstate;
13807dd7cddfSDavid du Colombier 
13813ff48bf5SDavid du Colombier 		scanner_state_init_options(&sstate, SCAN_FROM_STRING);
1382*593dc095SDavid du Colombier 		s_init(&ss, NULL);
13837dd7cddfSDavid du Colombier 		sread_string(&ss, IREF->value.bytes, r_size(IREF));
13847dd7cddfSDavid du Colombier 		osp = iosp;	/* scan_token uses ostack */
13857dd7cddfSDavid du Colombier 		code = scan_token(i_ctx_p, &ss, &token, &sstate);
13867dd7cddfSDavid du Colombier 		iosp = osp;	/* ditto */
13877dd7cddfSDavid du Colombier 		switch (code) {
13887dd7cddfSDavid du Colombier 		    case 0:	/* read a token */
13897dd7cddfSDavid du Colombier 		    case scan_BOS:	/* binary object sequence */
13907dd7cddfSDavid du Colombier 			store_state(iesp);
13917dd7cddfSDavid du Colombier 			/* If the updated string isn't empty, push it back */
13927dd7cddfSDavid du Colombier 			/* on the e-stack. */
13937dd7cddfSDavid du Colombier 			{
13947dd7cddfSDavid du Colombier 			    uint size = sbufavailable(&ss);
13957dd7cddfSDavid du Colombier 
13967dd7cddfSDavid du Colombier 			    if (size) {
13977dd7cddfSDavid du Colombier 				if (iesp >= estop)
13987dd7cddfSDavid du Colombier 				    return_with_error_iref(e_execstackoverflow);
13997dd7cddfSDavid du Colombier 				++iesp;
14007dd7cddfSDavid du Colombier 				iesp->tas.type_attrs = IREF->tas.type_attrs;
14017dd7cddfSDavid du Colombier 				iesp->value.const_bytes = sbufptr(&ss);
14027dd7cddfSDavid du Colombier 				r_set_size(iesp, size);
14037dd7cddfSDavid du Colombier 			    }
14047dd7cddfSDavid du Colombier 			}
14057dd7cddfSDavid du Colombier 			if (code == 0) {
14067dd7cddfSDavid du Colombier 			    SET_IREF(&token);
14077dd7cddfSDavid du Colombier 			    icount = 0;
14087dd7cddfSDavid du Colombier 			    goto top;
14097dd7cddfSDavid du Colombier 			}
14107dd7cddfSDavid du Colombier 			/* Handle BOS specially */
14117dd7cddfSDavid du Colombier 			pvalue = &token;
14127dd7cddfSDavid du Colombier 			goto pr;
14137dd7cddfSDavid du Colombier 		    case scan_EOF:	/* end of string */
14147dd7cddfSDavid du Colombier 			goto bot;
14157dd7cddfSDavid du Colombier 		    case scan_Refill:	/* error */
14167dd7cddfSDavid du Colombier 			code = gs_note_error(e_syntaxerror);
14177dd7cddfSDavid du Colombier 		    default:	/* error */
14187dd7cddfSDavid du Colombier 			return_with_code_iref();
14197dd7cddfSDavid du Colombier 		}
14207dd7cddfSDavid du Colombier 	    }
14217dd7cddfSDavid du Colombier 	    /* Handle packed arrays here by re-dispatching. */
14227dd7cddfSDavid du Colombier 	    /* This also picks up some anomalous cases of non-packed arrays. */
14237dd7cddfSDavid du Colombier 	default:
14247dd7cddfSDavid du Colombier 	    {
14257dd7cddfSDavid du Colombier 		uint index;
14267dd7cddfSDavid du Colombier 
14277dd7cddfSDavid du Colombier 		switch (*iref_packed >> r_packed_type_shift) {
14287dd7cddfSDavid du Colombier 		    case pt_full_ref:
14297dd7cddfSDavid du Colombier 		    case pt_full_ref + 1:
14307dd7cddfSDavid du Colombier 			INCR(p_full);
14317dd7cddfSDavid du Colombier 			if (iosp >= ostop)
14327dd7cddfSDavid du Colombier 			    return_with_stackoverflow_iref();
14337dd7cddfSDavid du Colombier 			/* We know this can't be an executable object */
14347dd7cddfSDavid du Colombier 			/* requiring special handling, so we just push it. */
14357dd7cddfSDavid du Colombier 			++iosp;
14367dd7cddfSDavid du Colombier 			/* We know that refs are properly aligned: */
14377dd7cddfSDavid du Colombier 			/* see packed.h for details. */
14387dd7cddfSDavid du Colombier 			ref_assign_inline(iosp, IREF);
14397dd7cddfSDavid du Colombier 			next();
14407dd7cddfSDavid du Colombier 		    case pt_executable_operator:
14417dd7cddfSDavid du Colombier 			index = *iref_packed & packed_value_mask;
14427dd7cddfSDavid du Colombier 			if (--ticks_left <= 0) {	/* The following doesn't work, */
14437dd7cddfSDavid du Colombier 			    /* and I can't figure out why. */
14447dd7cddfSDavid du Colombier /****** goto sst_short; ******/
14457dd7cddfSDavid du Colombier 			}
14467dd7cddfSDavid du Colombier 			if (!op_index_is_operator(index)) {
14477dd7cddfSDavid du Colombier 			    INCR(p_exec_oparray);
14487dd7cddfSDavid du Colombier 			    store_state_short(iesp);
14497dd7cddfSDavid du Colombier 			    /* Call the operator procedure. */
14507dd7cddfSDavid du Colombier 			    index -= op_def_count;
14517dd7cddfSDavid du Colombier 			    pvalue = (const ref *)
14527dd7cddfSDavid du Colombier 				(index < r_size(&op_array_table_global.table) ?
14537dd7cddfSDavid du Colombier 			      op_array_table_global.table.value.const_refs +
14547dd7cddfSDavid du Colombier 				 index :
14557dd7cddfSDavid du Colombier 			       op_array_table_local.table.value.const_refs +
14567dd7cddfSDavid du Colombier 			    (index - r_size(&op_array_table_global.table)));
14577dd7cddfSDavid du Colombier 			    goto oppr;
14587dd7cddfSDavid du Colombier 			}
14597dd7cddfSDavid du Colombier 			INCR(p_exec_operator);
14607dd7cddfSDavid du Colombier 			/* See the main plain_exec(t_operator) case */
14617dd7cddfSDavid du Colombier 			/* for details of what happens here. */
14627dd7cddfSDavid du Colombier #if PACKED_SPECIAL_OPS
14637dd7cddfSDavid du Colombier 			/*
14647dd7cddfSDavid du Colombier 			 * We arranged in iinit.c that the special ops
14657dd7cddfSDavid du Colombier 			 * have operator indices starting at 1.
14667dd7cddfSDavid du Colombier 			 *
14677dd7cddfSDavid du Colombier 			 * The (int) cast in the next line is required
14687dd7cddfSDavid du Colombier 			 * because some compilers don't allow arithmetic
14697dd7cddfSDavid du Colombier 			 * involving two different enumerated types.
14707dd7cddfSDavid du Colombier 			 */
14717dd7cddfSDavid du Colombier #  define case_xop(xop) case xop - (int)tx_op + 1
14727dd7cddfSDavid du Colombier 			switch (index) {
14737dd7cddfSDavid du Colombier 			      case_xop(tx_op_add):goto x_add;
14747dd7cddfSDavid du Colombier 			      case_xop(tx_op_def):goto x_def;
14757dd7cddfSDavid du Colombier 			      case_xop(tx_op_dup):goto x_dup;
14767dd7cddfSDavid du Colombier 			      case_xop(tx_op_exch):goto x_exch;
14777dd7cddfSDavid du Colombier 			      case_xop(tx_op_if):goto x_if;
14787dd7cddfSDavid du Colombier 			      case_xop(tx_op_ifelse):goto x_ifelse;
14797dd7cddfSDavid du Colombier 			      case_xop(tx_op_index):goto x_index;
14807dd7cddfSDavid du Colombier 			      case_xop(tx_op_pop):goto x_pop;
14817dd7cddfSDavid du Colombier 			      case_xop(tx_op_roll):goto x_roll;
14827dd7cddfSDavid du Colombier 			      case_xop(tx_op_sub):goto x_sub;
14837dd7cddfSDavid du Colombier 			    case 0:	/* for dumb compilers */
14847dd7cddfSDavid du Colombier 			    default:
14857dd7cddfSDavid du Colombier 				;
14867dd7cddfSDavid du Colombier 			}
14877dd7cddfSDavid du Colombier #  undef case_xop
14887dd7cddfSDavid du Colombier #endif
14897dd7cddfSDavid du Colombier 			INCR(p_exec_non_x_operator);
14907dd7cddfSDavid du Colombier 			esp = iesp;
14917dd7cddfSDavid du Colombier 			osp = iosp;
14927dd7cddfSDavid du Colombier 			switch (code = call_operator(op_index_proc(index), i_ctx_p)) {
14937dd7cddfSDavid du Colombier 			    case 0:
14947dd7cddfSDavid du Colombier 			    case 1:
14957dd7cddfSDavid du Colombier 				iosp = osp;
14967dd7cddfSDavid du Colombier 				next_short();
14977dd7cddfSDavid du Colombier 			    case o_push_estack:
14987dd7cddfSDavid du Colombier 				store_state_short(iesp);
14997dd7cddfSDavid du Colombier 				goto opush;
15007dd7cddfSDavid du Colombier 			    case o_pop_estack:
15017dd7cddfSDavid du Colombier 				iosp = osp;
15027dd7cddfSDavid du Colombier 				if (esp == iesp) {
15037dd7cddfSDavid du Colombier 				    next_short();
15047dd7cddfSDavid du Colombier 				}
15057dd7cddfSDavid du Colombier 				iesp = esp;
15067dd7cddfSDavid du Colombier 				goto up;
15077dd7cddfSDavid du Colombier 			    case o_reschedule:
15087dd7cddfSDavid du Colombier 				store_state_short(iesp);
15097dd7cddfSDavid du Colombier 				goto res;
15107dd7cddfSDavid du Colombier 			    case e_RemapColor:
15117dd7cddfSDavid du Colombier 				store_state_short(iesp);
15127dd7cddfSDavid du Colombier 				goto remap;
15137dd7cddfSDavid du Colombier 			}
15147dd7cddfSDavid du Colombier 			iosp = osp;
15157dd7cddfSDavid du Colombier 			iesp = esp;
15167dd7cddfSDavid du Colombier 			return_with_code_iref();
15177dd7cddfSDavid du Colombier 		    case pt_integer:
15187dd7cddfSDavid du Colombier 			INCR(p_integer);
15197dd7cddfSDavid du Colombier 			if (iosp >= ostop)
15207dd7cddfSDavid du Colombier 			    return_with_stackoverflow_iref();
15217dd7cddfSDavid du Colombier 			++iosp;
15227dd7cddfSDavid du Colombier 			make_int(iosp,
15237dd7cddfSDavid du Colombier 				 ((int)*iref_packed & packed_int_mask) +
15247dd7cddfSDavid du Colombier 				 packed_min_intval);
15257dd7cddfSDavid du Colombier 			next_short();
15267dd7cddfSDavid du Colombier 		    case pt_literal_name:
15277dd7cddfSDavid du Colombier 			INCR(p_lit_name);
15287dd7cddfSDavid du Colombier 			{
15297dd7cddfSDavid du Colombier 			    uint nidx = *iref_packed & packed_value_mask;
15307dd7cddfSDavid du Colombier 
15317dd7cddfSDavid du Colombier 			    if (iosp >= ostop)
15327dd7cddfSDavid du Colombier 				return_with_stackoverflow_iref();
15337dd7cddfSDavid du Colombier 			    ++iosp;
15347dd7cddfSDavid du Colombier 			    name_index_ref_inline(int_nt, nidx, iosp);
15357dd7cddfSDavid du Colombier 			    next_short();
15367dd7cddfSDavid du Colombier 			}
15377dd7cddfSDavid du Colombier 		    case pt_executable_name:
15387dd7cddfSDavid du Colombier 			INCR(p_exec_name);
15397dd7cddfSDavid du Colombier 			{
15407dd7cddfSDavid du Colombier 			    uint nidx = *iref_packed & packed_value_mask;
15417dd7cddfSDavid du Colombier 
15427dd7cddfSDavid du Colombier 			    pvalue = name_index_ptr_inline(int_nt, nidx)->pvalue;
15437dd7cddfSDavid du Colombier 			    if (!pv_valid(pvalue)) {
15447dd7cddfSDavid du Colombier 				uint htemp;
15457dd7cddfSDavid du Colombier 
15467dd7cddfSDavid du Colombier 				INCR(p_find_name);
15477dd7cddfSDavid du Colombier 				if ((pvalue = dict_find_name_by_index_inline(nidx, htemp)) == 0) {
15487dd7cddfSDavid du Colombier 				    names_index_ref(int_nt, nidx, &token);
15497dd7cddfSDavid du Colombier 				    return_with_error(e_undefined, &token);
15507dd7cddfSDavid du Colombier 				}
15517dd7cddfSDavid du Colombier 			    }
15527dd7cddfSDavid du Colombier 			    if (r_has_masked_attrs(pvalue, a_execute, a_execute + a_executable)) {	/* Literal, push it. */
15537dd7cddfSDavid du Colombier 				INCR(p_name_lit);
15547dd7cddfSDavid du Colombier 				if (iosp >= ostop)
15557dd7cddfSDavid du Colombier 				    return_with_stackoverflow_iref();
15567dd7cddfSDavid du Colombier 				++iosp;
15577dd7cddfSDavid du Colombier 				ref_assign_inline(iosp, pvalue);
15587dd7cddfSDavid du Colombier 				next_short();
15597dd7cddfSDavid du Colombier 			    }
15607dd7cddfSDavid du Colombier 			    if (r_is_proc(pvalue)) {	/* This is an executable procedure, */
15617dd7cddfSDavid du Colombier 				/* execute it. */
15627dd7cddfSDavid du Colombier 				INCR(p_name_proc);
15637dd7cddfSDavid du Colombier 				store_state_short(iesp);
15647dd7cddfSDavid du Colombier 				goto pr;
15657dd7cddfSDavid du Colombier 			    }
15667dd7cddfSDavid du Colombier 			    /* Not a literal or procedure, reinterpret it. */
15677dd7cddfSDavid du Colombier 			    store_state_short(iesp);
15687dd7cddfSDavid du Colombier 			    icount = 0;
15697dd7cddfSDavid du Colombier 			    SET_IREF(pvalue);
15707dd7cddfSDavid du Colombier 			    goto top;
15717dd7cddfSDavid du Colombier 			}
15727dd7cddfSDavid du Colombier 			/* default can't happen here */
15737dd7cddfSDavid du Colombier 		}
15747dd7cddfSDavid du Colombier 	    }
15757dd7cddfSDavid du Colombier     }
15767dd7cddfSDavid du Colombier     /* Literal type, just push it. */
15777dd7cddfSDavid du Colombier     if (iosp >= ostop)
15787dd7cddfSDavid du Colombier 	return_with_stackoverflow_iref();
15797dd7cddfSDavid du Colombier     ++iosp;
15807dd7cddfSDavid du Colombier     ref_assign_inline(iosp, IREF);
15817dd7cddfSDavid du Colombier   bot:next();
15827dd7cddfSDavid du Colombier   out:				/* At most 1 more token in the current procedure. */
15837dd7cddfSDavid du Colombier     /* (We already decremented icount.) */
15847dd7cddfSDavid du Colombier     if (!icount) {
15857dd7cddfSDavid du Colombier 	/* Pop the execution stack for tail recursion. */
15867dd7cddfSDavid du Colombier 	iesp--;
15877dd7cddfSDavid du Colombier 	iref_packed = IREF_NEXT(iref_packed);
15887dd7cddfSDavid du Colombier 	goto top;
15897dd7cddfSDavid du Colombier     }
15907dd7cddfSDavid du Colombier   up:if (--ticks_left < 0)
15917dd7cddfSDavid du Colombier 	goto slice;
15927dd7cddfSDavid du Colombier     /* See if there is anything left on the execution stack. */
15937dd7cddfSDavid du Colombier     if (!r_is_proc(iesp)) {
15947dd7cddfSDavid du Colombier 	SET_IREF(iesp--);
15957dd7cddfSDavid du Colombier 	icount = 0;
15967dd7cddfSDavid du Colombier 	goto top;
15977dd7cddfSDavid du Colombier     }
15987dd7cddfSDavid du Colombier     SET_IREF(iesp->value.refs);	/* next element of array */
15997dd7cddfSDavid du Colombier     icount = r_size(iesp) - 1;
16007dd7cddfSDavid du Colombier     if (icount <= 0) {		/* <= 1 more elements */
16017dd7cddfSDavid du Colombier 	iesp--;			/* pop, or tail recursion */
16027dd7cddfSDavid du Colombier 	if (icount < 0)
16037dd7cddfSDavid du Colombier 	    goto up;
16047dd7cddfSDavid du Colombier     }
16057dd7cddfSDavid du Colombier     goto top;
16067dd7cddfSDavid du Colombier res:
16077dd7cddfSDavid du Colombier     /* Some operator has asked for context rescheduling. */
16087dd7cddfSDavid du Colombier     /* We've done a store_state. */
16097dd7cddfSDavid du Colombier     *pi_ctx_p = i_ctx_p;
16107dd7cddfSDavid du Colombier     code = (*gs_interp_reschedule_proc)(pi_ctx_p);
16117dd7cddfSDavid du Colombier     i_ctx_p = *pi_ctx_p;
16127dd7cddfSDavid du Colombier   sched:			/* We've just called a scheduling procedure. */
16137dd7cddfSDavid du Colombier     /* The interpreter state is in memory; iref is not current. */
16147dd7cddfSDavid du Colombier     if (code < 0) {
16157dd7cddfSDavid du Colombier 	set_error(code);
16167dd7cddfSDavid du Colombier 	/*
16177dd7cddfSDavid du Colombier 	 * We need a real object to return as the error object.
16187dd7cddfSDavid du Colombier 	 * (It only has to last long enough to store in
16197dd7cddfSDavid du Colombier 	 * *perror_object.)
16207dd7cddfSDavid du Colombier 	 */
16217dd7cddfSDavid du Colombier 	make_null_proc(&ierror.full);
16227dd7cddfSDavid du Colombier 	SET_IREF(ierror.obj = &ierror.full);
16237dd7cddfSDavid du Colombier 	goto error_exit;
16247dd7cddfSDavid du Colombier     }
16257dd7cddfSDavid du Colombier     /* Reload state information from memory. */
16267dd7cddfSDavid du Colombier     iosp = osp;
16277dd7cddfSDavid du Colombier     iesp = esp;
16287dd7cddfSDavid du Colombier     goto up;
16297dd7cddfSDavid du Colombier #if 0				/****** ****** ***** */
16307dd7cddfSDavid du Colombier   sst:				/* Time-slice, but push the current object first. */
16317dd7cddfSDavid du Colombier     store_state(iesp);
16327dd7cddfSDavid du Colombier     if (iesp >= estop)
16337dd7cddfSDavid du Colombier 	return_with_error_iref(e_execstackoverflow);
16347dd7cddfSDavid du Colombier     iesp++;
16357dd7cddfSDavid du Colombier     ref_assign_inline(iesp, iref);
16367dd7cddfSDavid du Colombier #endif /****** ****** ***** */
16377dd7cddfSDavid du Colombier   slice:			/* It's time to time-slice or garbage collect. */
16387dd7cddfSDavid du Colombier     /* iref is not live, so we don't need to do a store_state. */
16397dd7cddfSDavid du Colombier     osp = iosp;
16407dd7cddfSDavid du Colombier     esp = iesp;
16417dd7cddfSDavid du Colombier     /* If ticks_left <= -100, we need to GC now. */
16427dd7cddfSDavid du Colombier     if (ticks_left <= -100) {	/* We need to garbage collect now. */
16437dd7cddfSDavid du Colombier 	*pi_ctx_p = i_ctx_p;
16447dd7cddfSDavid du Colombier 	code = interp_reclaim(pi_ctx_p, -1);
16457dd7cddfSDavid du Colombier 	i_ctx_p = *pi_ctx_p;
16467dd7cddfSDavid du Colombier     } else if (gs_interp_time_slice_proc) {
16477dd7cddfSDavid du Colombier 	*pi_ctx_p = i_ctx_p;
16487dd7cddfSDavid du Colombier 	code = (*gs_interp_time_slice_proc)(pi_ctx_p);
16497dd7cddfSDavid du Colombier 	i_ctx_p = *pi_ctx_p;
16507dd7cddfSDavid du Colombier     } else
16517dd7cddfSDavid du Colombier 	code = 0;
16527dd7cddfSDavid du Colombier     ticks_left = gs_interp_time_slice_ticks;
1653*593dc095SDavid du Colombier     set_code_on_interrupt(imemory, &code);
16547dd7cddfSDavid du Colombier     goto sched;
16557dd7cddfSDavid du Colombier 
16567dd7cddfSDavid du Colombier     /* Error exits. */
16577dd7cddfSDavid du Colombier 
16587dd7cddfSDavid du Colombier   rweci:
16597dd7cddfSDavid du Colombier     ierror.code = code;
16607dd7cddfSDavid du Colombier   rwei:
16617dd7cddfSDavid du Colombier     ierror.obj = IREF;
16627dd7cddfSDavid du Colombier   rwe:
16637dd7cddfSDavid du Colombier     if (!r_is_packed(iref_packed))
16647dd7cddfSDavid du Colombier 	store_state(iesp);
16657dd7cddfSDavid du Colombier     else {
16667dd7cddfSDavid du Colombier 	/*
16677dd7cddfSDavid du Colombier 	 * We need a real object to return as the error object.
16687dd7cddfSDavid du Colombier 	 * (It only has to last long enough to store in *perror_object.)
16697dd7cddfSDavid du Colombier 	 */
1670*593dc095SDavid du Colombier 	packed_get(imemory, (const ref_packed *)ierror.obj, &ierror.full);
16717dd7cddfSDavid du Colombier 	store_state_short(iesp);
16727dd7cddfSDavid du Colombier 	if (IREF == ierror.obj)
16737dd7cddfSDavid du Colombier 	    SET_IREF(&ierror.full);
16747dd7cddfSDavid du Colombier 	ierror.obj = &ierror.full;
16757dd7cddfSDavid du Colombier     }
16767dd7cddfSDavid du Colombier   error_exit:
16777dd7cddfSDavid du Colombier     if (ERROR_IS_INTERRUPT(ierror.code)) {	/* We must push the current object being interpreted */
16787dd7cddfSDavid du Colombier 	/* back on the e-stack so it will be re-executed. */
16797dd7cddfSDavid du Colombier 	/* Currently, this is always an executable operator, */
16807dd7cddfSDavid du Colombier 	/* but it might be something else someday if we check */
16817dd7cddfSDavid du Colombier 	/* for interrupts in the interpreter loop itself. */
16827dd7cddfSDavid du Colombier 	if (iesp >= estop)
16837dd7cddfSDavid du Colombier 	    code = e_execstackoverflow;
16847dd7cddfSDavid du Colombier 	else {
16857dd7cddfSDavid du Colombier 	    iesp++;
16867dd7cddfSDavid du Colombier 	    ref_assign_inline(iesp, IREF);
16877dd7cddfSDavid du Colombier 	}
16887dd7cddfSDavid du Colombier     }
16897dd7cddfSDavid du Colombier     esp = iesp;
16907dd7cddfSDavid du Colombier     osp = iosp;
16917dd7cddfSDavid du Colombier     ref_assign_inline(perror_object, ierror.obj);
16927dd7cddfSDavid du Colombier     return gs_log_error(ierror.code, __FILE__, ierror.line);
16937dd7cddfSDavid du Colombier }
16947dd7cddfSDavid du Colombier 
16957dd7cddfSDavid du Colombier /* Pop the bookkeeping information for a normal exit from a t_oparray. */
16967dd7cddfSDavid du Colombier private int
oparray_pop(i_ctx_t * i_ctx_p)16977dd7cddfSDavid du Colombier oparray_pop(i_ctx_t *i_ctx_p)
16987dd7cddfSDavid du Colombier {
16997dd7cddfSDavid du Colombier     esp -= 3;
17007dd7cddfSDavid du Colombier     return o_pop_estack;
17017dd7cddfSDavid du Colombier }
17027dd7cddfSDavid du Colombier 
17037dd7cddfSDavid du Colombier /* Restore the stack pointers after an error inside a t_oparray procedure. */
17047dd7cddfSDavid du Colombier /* This procedure is called only from pop_estack. */
17057dd7cddfSDavid du Colombier private int
oparray_cleanup(i_ctx_t * i_ctx_p)17067dd7cddfSDavid du Colombier oparray_cleanup(i_ctx_t *i_ctx_p)
17077dd7cddfSDavid du Colombier {				/* esp points just below the cleanup procedure. */
17087dd7cddfSDavid du Colombier     es_ptr ep = esp;
17097dd7cddfSDavid du Colombier     uint ocount_old = (uint) ep[2].value.intval;
17107dd7cddfSDavid du Colombier     uint dcount_old = (uint) ep[3].value.intval;
17117dd7cddfSDavid du Colombier     uint ocount = ref_stack_count(&o_stack);
17127dd7cddfSDavid du Colombier     uint dcount = ref_stack_count(&d_stack);
17137dd7cddfSDavid du Colombier 
17147dd7cddfSDavid du Colombier     if (ocount > ocount_old)
17157dd7cddfSDavid du Colombier 	ref_stack_pop(&o_stack, ocount - ocount_old);
17167dd7cddfSDavid du Colombier     if (dcount > dcount_old) {
17177dd7cddfSDavid du Colombier 	ref_stack_pop(&d_stack, dcount - dcount_old);
17187dd7cddfSDavid du Colombier 	dict_set_top();
17197dd7cddfSDavid du Colombier     }
17207dd7cddfSDavid du Colombier     return 0;
17217dd7cddfSDavid du Colombier }
17223ff48bf5SDavid du Colombier 
17233ff48bf5SDavid du Colombier /* Don't restore the stack pointers. */
17243ff48bf5SDavid du Colombier private int
oparray_no_cleanup(i_ctx_t * i_ctx_p)17253ff48bf5SDavid du Colombier oparray_no_cleanup(i_ctx_t *i_ctx_p)
17263ff48bf5SDavid du Colombier {
17273ff48bf5SDavid du Colombier     return 0;
17283ff48bf5SDavid du Colombier }
17293ff48bf5SDavid du Colombier 
17303ff48bf5SDavid du Colombier /* Find the innermost oparray. */
17313ff48bf5SDavid du Colombier private ref *
oparray_find(i_ctx_t * i_ctx_p)17323ff48bf5SDavid du Colombier oparray_find(i_ctx_t *i_ctx_p)
17333ff48bf5SDavid du Colombier {
17343ff48bf5SDavid du Colombier     long i;
17353ff48bf5SDavid du Colombier     ref *ep;
17363ff48bf5SDavid du Colombier 
17373ff48bf5SDavid du Colombier     for (i = 0; (ep = ref_stack_index(&e_stack, i)) != 0; ++i) {
17383ff48bf5SDavid du Colombier 	if (r_is_estack_mark(ep) &&
17393ff48bf5SDavid du Colombier 	    (ep->value.opproc == oparray_cleanup ||
17403ff48bf5SDavid du Colombier 	     ep->value.opproc == oparray_no_cleanup)
17413ff48bf5SDavid du Colombier 	    )
17423ff48bf5SDavid du Colombier 	    return ep;
17433ff48bf5SDavid du Colombier     }
17443ff48bf5SDavid du Colombier     return 0;
17453ff48bf5SDavid du Colombier }
17463ff48bf5SDavid du Colombier 
17473ff48bf5SDavid du Colombier /* <bool> .setstackprotect - */
17483ff48bf5SDavid du Colombier /* Set whether to protect the stack for the innermost oparray. */
17493ff48bf5SDavid du Colombier private int
zsetstackprotect(i_ctx_t * i_ctx_p)17503ff48bf5SDavid du Colombier zsetstackprotect(i_ctx_t *i_ctx_p)
17513ff48bf5SDavid du Colombier {
17523ff48bf5SDavid du Colombier     os_ptr op = osp;
17533ff48bf5SDavid du Colombier     ref *ep = oparray_find(i_ctx_p);
17543ff48bf5SDavid du Colombier 
17553ff48bf5SDavid du Colombier     check_type(*op, t_boolean);
17563ff48bf5SDavid du Colombier     if (ep == 0)
17573ff48bf5SDavid du Colombier 	return_error(e_rangecheck);
17583ff48bf5SDavid du Colombier     ep->value.opproc =
17593ff48bf5SDavid du Colombier 	(op->value.boolval ? oparray_cleanup : oparray_no_cleanup);
17603ff48bf5SDavid du Colombier     pop(1);
17613ff48bf5SDavid du Colombier     return 0;
17623ff48bf5SDavid du Colombier }
17633ff48bf5SDavid du Colombier 
17643ff48bf5SDavid du Colombier /* - .currentstackprotect <bool> */
17653ff48bf5SDavid du Colombier /* Return the stack protection status. */
17663ff48bf5SDavid du Colombier private int
zcurrentstackprotect(i_ctx_t * i_ctx_p)17673ff48bf5SDavid du Colombier zcurrentstackprotect(i_ctx_t *i_ctx_p)
17683ff48bf5SDavid du Colombier {
17693ff48bf5SDavid du Colombier     os_ptr op = osp;
17703ff48bf5SDavid du Colombier     ref *ep = oparray_find(i_ctx_p);
17713ff48bf5SDavid du Colombier 
17723ff48bf5SDavid du Colombier     if (ep == 0)
17733ff48bf5SDavid du Colombier 	return_error(e_rangecheck);
17743ff48bf5SDavid du Colombier     push(1);
17753ff48bf5SDavid du Colombier     make_bool(op, ep->value.opproc == oparray_cleanup);
17763ff48bf5SDavid du Colombier     return 0;
17773ff48bf5SDavid du Colombier }
1778