1 /****************************************************************************
2 *
3 *  This code is Public Domain.
4 *
5 *  ========================================================================
6 *
7 * Description:  implements the "fastpass" handling.
8 *               "fastpass" is an optimization which increases
9 *               assembly time speed by storing preprocessed lines
10 *               in memory during the first pass. In further passes,
11 *               those lines are "read" instead of the original assembly
12 *               source files.
13 *               Speed increase is significant if there's a large include
14 *               file at the top of an assembly source which contains
15 *               just equates and type definitions, because there's no need
16 *               to save such lines during pass one.
17 *
18 ****************************************************************************/
19 
20 #include <ctype.h>
21 
22 #include "globals.h"
23 #include "memalloc.h"
24 #include "parser.h"
25 #include "input.h"
26 #include "segment.h"
27 #include "fastpass.h"
28 
29 #if FASTPASS
30 
31 extern uint_32 list_pos;  /* current LST file position */
32 
33 static struct mod_state modstate; /* struct to store assembly status */
34 static struct {
35     struct line_item *head;
36     struct line_item *tail;
37 } LineStore;
38 struct line_item *LineStoreCurr; /* must be global! */
39 bool StoreState;
40 bool UseSavedState;
41 
42 /*
43  * save the current status (happens in pass one only) and
44  * switch to "save precompiled lines" mode.
45  * the status is then restored in further passes,
46  * and the precompiled lines are used for assembly then.
47  */
48 
SaveState(void)49 static void SaveState( void )
50 /***************************/
51 {
52     DebugMsg1(("SaveState enter\n" ));
53     StoreState = TRUE;
54     UseSavedState = TRUE;
55     modstate.init = TRUE;
56     modstate.Equ.head = modstate.Equ.tail = NULL;
57 
58     /* v2.13: save the current source file */
59     modstate.saved_src = get_curr_srcfile();
60     /* save the part of ModuleInfo that is NOT in module_vars */
61     memcpy( &modstate.modinfo, (uint_8 *)&ModuleInfo + sizeof( struct module_vars ), sizeof( modstate.modinfo ) );
62 
63     SegmentSaveState();
64     AssumeSaveState();
65     ContextSaveState(); /* save pushcontext/popcontext stack */
66 
67     DebugMsg(( "SaveState exit\n" ));
68 }
69 
StoreLine(const char * srcline,int flags,uint_32 lst_position)70 void StoreLine( const char *srcline, int flags, uint_32 lst_position )
71 /********************************************************************/
72 {
73     int i,j;
74     char *p;
75 
76 #ifdef DEBUG_OUT
77     if ( Options.nofastpass )
78         return;
79 #endif
80     if ( ModuleInfo.GeneratedCode ) /* don't store generated lines! */
81         return;
82     if ( StoreState == FALSE ) /* line store already started? */
83         SaveState();
84 
85     i = strlen( srcline );
86     j = ( ( ( flags & 1 ) && ModuleInfo.CurrComment ) ? strlen( ModuleInfo.CurrComment ) : 0 );
87     LineStoreCurr = LclAlloc( i + j + sizeof( struct line_item ) );
88     LineStoreCurr->next = NULL;
89     LineStoreCurr->lineno = GetLineNumber();
90     if ( MacroLevel ) {
91         LineStoreCurr->srcfile = 0xfff;
92     } else {
93         LineStoreCurr->srcfile = get_curr_srcfile();
94     }
95     LineStoreCurr->list_pos = ( lst_position ? lst_position : list_pos );
96     if ( j ) {
97         memcpy( LineStoreCurr->line, srcline, i );
98         memcpy( LineStoreCurr->line + i, ModuleInfo.CurrComment, j + 1 );
99     } else
100         memcpy( LineStoreCurr->line, srcline, i + 1 );
101 
102     DebugMsg1(("StoreLine(>%s<, lst_position=%u): cur=%X\n", LineStoreCurr->line, lst_position, LineStoreCurr ));
103 
104     /* v2.08: don't store % operator at pos 0 */
105     for ( p = LineStoreCurr->line; *p && isspace(*p); p++ );
106     if (*p == '%' && ( _memicmp( p+1, "OUT", 3 ) || is_valid_id_char( *(p+4) ) ) )
107         *p = ' ';
108 
109 #ifdef DEBUG_OUT
110     if ( Options.print_linestore )
111         printf("%s\n", LineStoreCurr->line );
112 #endif
113     if ( LineStore.head )
114         LineStore.tail->next = LineStoreCurr;
115     else
116         LineStore.head = LineStoreCurr;
117     LineStore.tail = LineStoreCurr;
118 }
119 
120 /* an error has been detected in pass one. it should be
121  reported in pass 2, so ensure that a full source scan is done then
122  */
123 
SkipSavedState(void)124 void SkipSavedState( void )
125 /*************************/
126 {
127     DebugMsg(("SkipSavedState called\n"));
128     UseSavedState = FALSE;
129 }
130 
131 /* for FASTPASS, just pass 1 is a full pass, the other passes
132  don't start from scratch and they just assemble the preprocessed
133  source. To be able to restart the assembly process from a certain
134  location within the source, it's necessary to save the value of
135  assembly time variables.
136  However, to reduce the number of variables that are saved, an
137  assembly-time variable is only saved when
138  - it is changed
139  - it was defined when StoreState() is called
140  */
141 
SaveVariableState(struct asym * sym)142 void SaveVariableState( struct asym *sym )
143 /****************************************/
144 {
145     struct equ_item *p;
146 
147     DebugMsg1(( "SaveVariableState(%s)=%d\n", sym->name, sym->value ));
148     sym->issaved = TRUE; /* don't try to save this symbol (anymore) */
149     p = LclAlloc( sizeof( struct equ_item ) );
150     p->next = NULL;
151     p->sym = sym;
152     p->lvalue    = sym->value;
153     p->hvalue    = sym->value3264; /* v2.05: added */
154     p->mem_type  = sym->mem_type;  /* v2.07: added */
155     p->isdefined = sym->isdefined;
156     if ( modstate.Equ.tail ) {
157         modstate.Equ.tail->next = p;
158         modstate.Equ.tail = p;
159     } else {
160         modstate.Equ.head = modstate.Equ.tail = p;
161     }
162 //    printf("state of symbol >%s< saved, value=%u, defined=%u\n", sym->name, sym->value, sym->defined);
163 }
164 
RestoreState(void)165 struct line_item *RestoreState( void )
166 /************************************/
167 {
168     DebugMsg1(("RestoreState enter\n"));
169     if ( modstate.init ) {
170         struct equ_item *curr;
171         /* restore values of assembly time variables */
172         for ( curr = modstate.Equ.head; curr; curr = curr->next ) {
173             DebugMsg1(("RestoreState: sym >%s<, value=%Xh (hvalue=%Xh), defined=%u\n", curr->sym->name, curr->lvalue, curr->hvalue, curr->isdefined ));
174             /* v2.07: MT_ABS is obsolete */
175             //if ( curr->sym->mem_type == MT_ABS ) {
176                 curr->sym->value     = curr->lvalue;
177                 curr->sym->value3264 = curr->hvalue;
178                 curr->sym->mem_type  = curr->mem_type; /* v2.07: added */
179                 curr->sym->isdefined = curr->isdefined;
180             //}
181         }
182         /* fields in module_vars are not to be restored.
183          * v2.10: the module_vars fields are not saved either.
184          */
185         //memcpy( &modstate.modinfo.g, &ModuleInfo.g, sizeof( ModuleInfo.g ) );
186         memcpy( (char *)&ModuleInfo + sizeof( struct module_vars ), &modstate.modinfo, sizeof( modstate.modinfo ) );
187         /* v2.13: restore the current source file */
188         set_curr_srcfile( modstate.saved_src, 0 );
189         SetOfssize();
190         SymSetCmpFunc();
191     }
192 
193 #if 0
194     /* v2.05: AFAICS this can't happen anymore. */
195     if ( LineStore.head == NULL ) {
196         struct line_item *endl = LclAlloc( sizeof( struct line_item ) + 3 );
197         endl->next = NULL;
198         endl->srcfile = 0;
199         endl->lineno = GetLineNumber();
200         endl->list_pos = 0;
201         strcpy( endl->line, "END");
202         LineStore.head = endl;
203         DebugMsg(("RestoreState: LineStore.head was NULL !!!\n" ));
204     }
205 #endif
206     return( LineStore.head );
207 }
208 
209 #if FASTMEM==0
210 /* this is debugging code only. Usually FASTPASS and FASTMEM
211  * are both either TRUE or FALSE.
212  * It's active if both DEBUG and TRMEM is set in Makefile.
213  */
FreeLineStore(void)214 void FreeLineStore( void )
215 /************************/
216 {
217     struct line_item *next;
218     for ( LineStoreCurr = LineStore.head; LineStoreCurr; ) {
219         next = LineStoreCurr->next;
220         LclFree( LineStoreCurr );
221         LineStoreCurr = next;
222     }
223 }
224 #endif
225 
FastpassInit(void)226 void FastpassInit( void )
227 /***********************/
228 {
229     StoreState = FALSE;
230     modstate.init = FALSE;
231     LineStore.head = NULL;
232     LineStore.tail = NULL;
233     UseSavedState = FALSE;
234 }
235 
236 #endif
237