1 /* Header for reduction machine. 2 */ 3 4 /* 5 6 Copyright (C) 1991-2003 The National Gallery 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License along 19 with this program; if not, write to the Free Software Foundation, Inc., 20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 22 */ 23 24 /* 25 26 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk 27 28 */ 29 30 /* Huge :-( this pushes sizeof(Reduce) up to 14MB. But we need to be able to 31 * loop down very long lists, eg. for a 65k x 3 LUT held as a Matrix. Drop 32 * this down when we represent matricies more sensibly. 33 */ 34 #define SPINE_SIZE (80000) 35 36 /* Reduction machine state. Not very opaque ... see mark_reduce() 37 */ 38 struct _Reduce { 39 /* Stack of heap nodes for spine. 40 */ 41 HeapNode *nstack[SPINE_SIZE]; 42 43 /* Index of free element above node stack top. 44 */ 45 int sp; 46 47 /* Frame stack ... top of fstack is sp we block GET above. 48 */ 49 int fstack[SPINE_SIZE]; 50 51 /* Writeback stack ... where the result of each frame goes. 52 */ 53 PElement wbstack[SPINE_SIZE]; 54 55 /* Frame stack pointer. 56 */ 57 int fsp; 58 59 /* Heap we evaluate. 60 */ 61 Heap *heap; 62 63 /* Nested reductions ... need to be able to longjmp() out of stuff, 64 * and restore the machine state. 65 */ 66 int running; 67 jmp_buf error[SPINE_SIZE]; 68 int sps[SPINE_SIZE]; 69 int fsps[SPINE_SIZE]; 70 int tsp[SPINE_SIZE]; 71 }; 72 73 #define RSPUSH(RC,N) { \ 74 if( (RC)->sp == SPINE_SIZE ) { \ 75 error_top( _( "Stack overflow." ) ); \ 76 error_sub( _( "Spine stack overflow, runaway recursion?" ) ); \ 77 reduce_throw( (RC) ); \ 78 } \ 79 else \ 80 (RC)->nstack[(RC)->sp++]=(N); \ 81 } 82 83 /* Number of items in current frame. 84 */ 85 #define RSFRAMESIZE(RC) ((RC)->sp - (RC)->fstack[(RC)->fsp - 1]) 86 87 /* Check for at least N args present. 88 */ 89 #define RSCHECKARGS(RC,N) (RSFRAMESIZE(RC) >= (N)) 90 91 /* Frame is empty? 92 */ 93 #define RSFRAMEEMPTY(RC) (RSFRAMESIZE(RC) == 0) 94 95 /* Get offset from stack top, offset 0 is top item. 96 */ 97 #define RSGET(RC,N) ((RC)->nstack[(RC)->sp - ((N) + 1)]) 98 99 /* Get the writeback for this frame. 100 */ 101 #define RSGETWB(RC) ((RC)->wbstack[(RC)->fsp - 1]) 102 103 #define RSPUSHFRAME(RC,OUT) { \ 104 if( (RC)->fsp == SPINE_SIZE ) { \ 105 error_top( _( "Stack overflow." ) ); \ 106 error_sub( _( "Frame stack overflow, " \ 107 "expression too complex." ) ); \ 108 reduce_throw( (RC) ); \ 109 } \ 110 else { \ 111 (RC)->wbstack[(RC)->fsp] = *out; \ 112 (RC)->fstack[(RC)->fsp] = (RC)->sp; \ 113 (RC)->fsp++; \ 114 } \ 115 } 116 117 #define RSPOPFRAME(RC) { \ 118 if( (RC)->fsp == 0 ) { \ 119 error_top( _( "Stack underflow." ) ); \ 120 error_sub( _( "Frame stack underflow, you've found a bug!" ) ); \ 121 reduce_throw( (RC) ); \ 122 } \ 123 else { \ 124 (RC)->fsp--; \ 125 (RC)->sp = (RC)->fstack[(RC)->fsp]; \ 126 } \ 127 } 128 129 #define RSPOP(RC,N) { \ 130 if( !RSCHECKARGS(RC,N) ) { \ 131 error_top( _( "Stack underflow." ) ); \ 132 error_sub( _( "Spine stack underflow, you've found a bug!" ) ); \ 133 reduce_throw( (RC) ); \ 134 } \ 135 else \ 136 (RC)->sp -= (N); \ 137 } 138 139 /* Pop this code before any calls to reduce_*() to init stuff and catch 140 * errors. Arg is function return value. The missing running decrement is done 141 * by throw(). 142 */ 143 #define REDUCE_CATCH_START( R ) \ 144 { \ 145 rc->sps[rc->running] = rc->sp; \ 146 rc->fsps[rc->running] = rc->fsp; \ 147 rc->tsp[rc->running] = trace_get_mark(); \ 148 if( setjmp( rc->error[rc->running++] ) ) { \ 149 g_assert( rc->running >= 0 ); \ 150 rc->sp = rc->sps[rc->running]; \ 151 rc->fsp = rc->fsps[rc->running]; \ 152 trace_pop_to( rc->tsp[rc->running] ); \ 153 return( (R) ); \ 154 } \ 155 } 156 157 /* After any calls to reduce_*(). 158 */ 159 #define REDUCE_CATCH_STOP \ 160 { \ 161 rc->running -= 1; \ 162 g_assert( rc->running >= 0 ); \ 163 } 164 165 /* Util. 166 */ 167 void reduce_throw( Reduce *rc ) __attribute__((noreturn)); 168 169 typedef void *(*reduce_safe_pointer_fn)( Reduce *rc, PElement *, 170 void *, void *, void *, void * ); 171 void *reduce_safe_pointer( Reduce *rc, reduce_safe_pointer_fn fn, 172 void *a, void *b, void *c, void *d ); 173 174 void reduce_get_list( Reduce *rc, PElement *list ); 175 void reduce_error_typecheck( Reduce *rc, 176 PElement *e, const char *name, const char *type ); 177 typedef void *(*reduce_map_list_fn)( Reduce *rc, 178 PElement *, void *, void * ); 179 void *reduce_map_list( Reduce *rc, 180 PElement *base, reduce_map_list_fn fn, void *a, void *b ); 181 typedef void *(*reduce_map_dict_fn)( Reduce *, 182 const char *, PElement *, void *a, void *b ); 183 void *reduce_map_dict( Reduce *rc, 184 PElement *base, reduce_map_dict_fn fn, void *a, void *b ); 185 void reduce_clone_list( Reduce *rc, PElement *base, PElement *out ); 186 int reduce_get_string( Reduce *rc, PElement *base, char *buf, int n ); 187 int reduce_get_lstring( Reduce *rc, PElement *base, GSList **labels ); 188 gboolean reduce_get_bool( Reduce *rc, PElement *base ); 189 double reduce_get_real( Reduce *rc, PElement *base ); 190 void reduce_get_class( Reduce *rc, PElement *base ); 191 Imageinfo *reduce_get_image( Reduce *rc, PElement *base ); 192 int reduce_get_realvec( Reduce *rc, PElement *base, double *buf, int n ); 193 int reduce_get_imagevec( Reduce *rc, PElement *base, Imageinfo **buf, int n ); 194 int reduce_get_matrix( Reduce *rc, 195 PElement *base, double *buf, int n, int *xsize, int *ysize ); 196 void reduce_get_matrix_size( Reduce *rc, 197 PElement *base, int *xsize, int *ysize ); 198 gboolean reduce_is_elist( Reduce *rc, PElement *base ); 199 gboolean reduce_is_list( Reduce *rc, PElement *base ); 200 gboolean reduce_is_string( Reduce *rc, PElement *base ); 201 gboolean reduce_is_finitestring( Reduce *rc, PElement *base ); 202 gboolean reduce_is_realvec( Reduce *rc, PElement *base ); 203 gboolean reduce_is_imagevec( Reduce *rc, PElement *base ); 204 gboolean reduce_is_matrix( Reduce *rc, PElement *base ); 205 gboolean reduce_is_class( Reduce *rc, PElement *klass ); 206 int reduce_list_length( Reduce *rc, PElement *base ); 207 int reduce_list_length_max( Reduce *rc, PElement *base, int max_length ); 208 void reduce_list_index( Reduce *rc, PElement *base, int n, PElement *out ); 209 gboolean reduce_is_instanceof_exact( Reduce *rc, 210 const char *name, PElement *instance ); 211 gboolean reduce_is_instanceof( Reduce *rc, 212 const char *name, PElement *instance ); 213 214 /* Main. 215 */ 216 extern Reduce *reduce_context; 217 extern int reduce_total_recomputations; 218 219 void reduce_destroy( Reduce *rc ); 220 Reduce *reduce_new( void ); 221 gboolean reduce_regenerate( Expr *expr, PElement *out ); 222 gboolean reduce_regenerate_member( Expr *expr, PElement *ths, PElement *out ); 223 224 void reduce_spine( Reduce *rc, PElement *out ); 225 void reduce_spine_strict( Reduce *rc, PElement *out ); 226 227 gboolean reduce_pelement( Reduce *, ReduceFunction fn, PElement *out ); 228 229 /* Register and unregister values. 230 */ 231 void reduce_register( Symbol *sym ); 232 void reduce_unregister( Symbol *sym ); 233