1 #ifdef RCSID
2 static char RCSid[] =
3 "$Header: d:/cvsroot/tads/tads3/tcgen.cpp,v 1.4 1999/07/11 00:46:58 MJRoberts Exp $";
4 #endif
5 
6 /*
7  *   Copyright (c) 1999, 2002 Michael J. Roberts.  All Rights Reserved.
8  *
9  *   Please see the accompanying license file, LICENSE.TXT, for information
10  *   on using and copying this software.
11  */
12 /*
13 Name
14   tcgen.cpp - TADS 3 Compiler code generator support classes
15 Function
16 
17 Notes
18 
19 Modified
20   05/09/99 MJRoberts  - Creation
21 */
22 
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "t3std.h"
27 #include "os.h"
28 #include "tcglob.h"
29 #include "tcgen.h"
30 #include "vmerr.h"
31 #include "tcerrnum.h"
32 #include "tctok.h"
33 #include "tcprs.h"
34 #include "tcmain.h"
35 #include "vmfile.h"
36 #include "tctarg.h"
37 
38 
39 /* ------------------------------------------------------------------------ */
40 /*
41  *   Data/Code Stream Parser-Allocated Object
42  */
43 
44 /*
45  *   allocate via a parser memory allocator
46  */
operator new(size_t siz,CTcPrsMem * allocator)47 void *CTcCSPrsAllocObj::operator new(size_t siz, CTcPrsMem *allocator)
48 {
49     /* allocate via the allocator */
50     return allocator->alloc(siz);
51 }
52 
53 /* ------------------------------------------------------------------------ */
54 /*
55  *   Data Stream
56  */
57 
58 /*
59  *   initialize
60  */
CTcDataStream(char stream_id)61 CTcDataStream::CTcDataStream(char stream_id)
62 {
63     /* remember my ID */
64     stream_id_ = stream_id;
65 
66     /* nothing is allocated yet */
67     ofs_ = 0;
68     obj_file_start_ofs_ = 0;
69     pages_ = 0;
70     page_slots_ = 0;
71     page_cnt_ = 0;
72     page_cur_ = 0;
73     rem_ = 0;
74     wp_ = 0;
75 
76     /* we have no anchors yet */
77     first_anchor_ = last_anchor_ = 0;
78 
79     /* create our parser memory allocator */
80     allocator_ = new CTcPrsMem();
81 }
82 
83 /*
84  *   delete
85  */
~CTcDataStream()86 CTcDataStream::~CTcDataStream()
87 {
88     size_t i;
89 
90     /* delete the page slots if we allocated any */
91     for (i = 0 ; i < page_cnt_ ; ++i)
92         t3free(pages_[i]);
93 
94     /* delete the page slot array if we allocated it */
95     if (pages_ != 0)
96         t3free(pages_);
97 
98     /* delete our label/fixup allocator */
99     delete allocator_;
100 }
101 
102 /*
103  *   Reset
104  */
reset()105 void CTcDataStream::reset()
106 {
107     /* move the write pointer back to the start */
108     ofs_ = 0;
109     obj_file_start_ofs_ = 0;
110 
111     /* back to the first page */
112     page_cur_ = 0;
113 
114     /* set up to write to the first page, if we have any pages at all */
115     if (pages_ != 0)
116     {
117         /* we have all of the first page available again */
118         wp_ = calc_addr(0);
119         rem_ = TCCS_PAGE_SIZE;
120     }
121 
122     /* reset the allocator */
123     allocator_->reset();
124 
125     /*
126      *   forget all of the anchors (no need to delete them explicitly -
127      *   they were allocated from our allocator pool, which we've reset to
128      *   completely discard everything it contained)
129      */
130     first_anchor_ = last_anchor_ = 0;
131 }
132 
133 /*
134  *   Decrement the write offset
135  */
dec_ofs(int amount)136 void CTcDataStream::dec_ofs(int amount)
137 {
138     /* adjust the offset */
139     ofs_ -= amount;
140 
141     /*
142      *   calculate the new page we're on, since this may take us to a
143      *   different page
144      */
145     page_cur_ = ofs_ / TCCS_PAGE_SIZE;
146 
147     /* calculate the remaining size in this page */
148     rem_ = TCCS_PAGE_SIZE - (ofs_ % TCCS_PAGE_SIZE);
149 
150     /* calculate the current write pointer */
151     wp_ = calc_addr(ofs_);
152 }
153 
154 /*
155  *   Get a pointer to a block at a given offset and a given length.
156  */
get_block_ptr(ulong ofs,ulong requested_len,ulong * available_len)157 const char *CTcDataStream::get_block_ptr(ulong ofs,
158                                          ulong requested_len,
159                                          ulong *available_len)
160 {
161     size_t page_rem;
162 
163     /*
164      *   determine how much is left on the page containing the offset
165      *   after the given offset
166      */
167     page_rem = TCCS_PAGE_SIZE - (ofs % TCCS_PAGE_SIZE);
168 
169     /*
170      *   if the amount remaining on the page is greater than the request
171      *   length, the available length is the entire request; otherwise,
172      *   the available length is the amount remaining on the page
173      */
174     if (page_rem >= requested_len)
175         *available_len = requested_len;
176     else
177         *available_len = page_rem;
178 
179     /* return the address at this offset */
180     return calc_addr(ofs);
181 }
182 
183 
184 /*
185  *   Write bytes to the stream at an earlier offset
186  */
write_at(ulong ofs,const char * buf,size_t len)187 void CTcDataStream::write_at(ulong ofs, const char *buf, size_t len)
188 {
189     /* if we're writing to the current offset, use the normal writer */
190     if (ofs == ofs_)
191         write(buf, len);
192 
193     /*
194      *   log an internal error, and skip writing anything, if the desired
195      *   range of offsets has not been previously written
196      */
197     if (ofs + len > ofs_)
198         G_tok->throw_internal_error(TCERR_WRITEAT_PAST_END);
199 
200     /* write the data to each page it spans */
201     while (len != 0)
202     {
203         size_t cur;
204 
205         /*
206          *   determine how much is left on the page containing the current
207          *   starting offset
208          */
209         cur = TCCS_PAGE_SIZE - (ofs % TCCS_PAGE_SIZE);
210 
211         /*
212          *   figure out how much we can copy - copy the whole remaining
213          *   size, but no more than the amount remaining on this page
214          */
215         if (cur > len)
216             cur = len;
217 
218         /* copy the data */
219         memcpy(calc_addr(ofs), buf, cur);
220 
221         /* advance past this chunk */
222         len -= cur;
223         ofs += cur;
224         buf += cur;
225     }
226 }
227 
228 /*
229  *   Copy a chunk of the stream to the given buffer
230  */
copy_to_buf(char * buf,ulong start_ofs,ulong len)231 void CTcDataStream::copy_to_buf(char *buf, ulong start_ofs, ulong len)
232 {
233     /* read the data from each page that the block spans */
234     while (len != 0)
235     {
236         size_t cur;
237 
238         /*
239          *   determine how much is left on the page containing the current
240          *   starting offset
241          */
242         cur = TCCS_PAGE_SIZE - (start_ofs % TCCS_PAGE_SIZE);
243 
244         /*
245          *   figure out how much we can copy - copy the whole remaining
246          *   size, but no more than the amount remaining on this page
247          */
248         if (cur > len)
249             cur = (size_t)len;
250 
251         /* copy the data */
252         memcpy(buf, calc_addr(start_ofs), cur);
253 
254         /* advance past this chunk */
255         len -= cur;
256         start_ofs += cur;
257         buf += cur;
258     }
259 }
260 
261 /*
262  *   Reserve space
263  */
reserve(size_t len)264 ulong CTcDataStream::reserve(size_t len)
265 {
266     ulong ret;
267 
268     /* we'll always return the offset current before the call */
269     ret = ofs_;
270 
271     /* if we have space on the current page, it's easy */
272     if (len <= rem_)
273     {
274         /* advance the output pointers */
275         ofs_ += len;
276         wp_ += len;
277         rem_ -= len;
278     }
279     else
280     {
281         /* keep going until we satisfy the request */
282         do
283         {
284             size_t cur;
285 
286             /* if necessary, allocate more memory */
287             if (rem_ == 0)
288                 alloc_page();
289 
290             /* limit this chunk to the space remaining on the current page */
291             cur = len;
292             if (cur > rem_)
293                 cur = rem_;
294 
295             /* skip past this chunk */
296             ofs_ += cur;
297             wp_ += cur;
298             rem_ -= cur;
299             len -= cur;
300 
301         } while (len != 0);
302     }
303 
304     /* return the starting offset */
305     return ret;
306 }
307 
308 /*
309  *   Append data from another stream.  The source stream is permanently
310  *   moved to the new stream, destroying the original stream.
311  */
append_stream(CTcDataStream * stream)312 void CTcDataStream::append_stream(CTcDataStream *stream)
313 {
314     ulong rem;
315     ulong ofs;
316     ulong start_ofs;
317     CTcStreamAnchor *anchor;
318     CTcStreamAnchor *nxt;
319 
320     /* remember the starting offset of the copy in my stream */
321     start_ofs = get_ofs();
322 
323     /* copy all data from the other stream */
324     for (ofs = 0, rem = stream->get_ofs() ; rem != 0 ; )
325     {
326         ulong request;
327         const char *ptr;
328         ulong actual;
329 
330         /*
331          *   request as much as possible from the other stream, up to the
332          *   remaining length or 64k, whichever is smaller
333          */
334         request = 65535;
335         if (rem < request)
336             request = rem;
337 
338         /* get the chunk from the source stream */
339         ptr = stream->get_block_ptr(ofs, request, &actual);
340 
341         /*
342          *   write this chunk (which we know is less than 64k and can thus
343          *   be safely cast to size_t, even on 16-bit machines)
344          */
345         write(ptr, (size_t)actual);
346 
347         /* advance our counters */
348         rem -= actual;
349         ofs += actual;
350     }
351 
352     /*
353      *   Now copy all of the anchors from the source stream to our stream.
354      *   This will ensure that fixups in the other stream have
355      *   corresponding fixups in this stream.  Note that we must adjust
356      *   the offset of each copied anchor by the offset of the start of
357      *   the copied data in our stream.
358      */
359     for (anchor = stream->get_first_anchor() ; anchor != 0 ; anchor = nxt)
360     {
361         /*
362          *   remember the old link to the next anchor, since we're going
363          *   to move the anchor to my list and thus forget about its
364          *   position in the old list
365          */
366         nxt = anchor->nxt_;
367 
368         /* adjust the anchor's offset */
369         anchor->ofs_ += start_ofs;
370 
371         /* unlink the anchor from its old stream */
372         anchor->nxt_ = 0;
373 
374         /* link it in to my anchor list */
375         if (last_anchor_ != 0)
376             last_anchor_->nxt_ = anchor;
377         else
378             first_anchor_ = anchor;
379         last_anchor_ = anchor;
380     }
381 }
382 
383 /*
384  *   Write bytes to the stream
385  */
write(const char * buf,size_t len)386 void CTcDataStream::write(const char *buf, size_t len)
387 {
388     /*
389      *   if possible, write it in one go (this is for efficiency, so that
390      *   we can avoid making a few comparisons in the most common case)
391      */
392     if (len <= rem_)
393     {
394         /* write the data */
395         memcpy(wp_, buf, len);
396 
397         /* advance the output pointers */
398         ofs_ += len;
399         wp_ += len;
400         rem_ -= len;
401     }
402     else
403     {
404         /* keep going until we satisfy the request */
405         do
406         {
407             size_t cur;
408 
409             /* if necessary, allocate more memory */
410             if (rem_ == 0)
411                 alloc_page();
412 
413             /* limit this chunk to the space remaining on the current page */
414             cur = len;
415             if (cur > rem_)
416                 cur = rem_;
417 
418             /* copy it to the page */
419             memcpy(wp_, buf, cur);
420 
421             /* skip past the space written in the destination */
422             ofs_ += cur;
423             wp_ += cur;
424             rem_ -= cur;
425 
426             /* advance past the space in the source */
427             buf += cur;
428             len -= cur;
429 
430         } while (len != 0);
431     }
432 }
433 
434 /*
435  *   allocate a new page
436  */
alloc_page()437 void CTcDataStream::alloc_page()
438 {
439     /*
440      *   if we're coming back to a page that was previously allocated, we
441      *   need merely re-establish the existing page
442      */
443     if (page_cur_ + 1 < page_cnt_)
444     {
445         /* move to the next page */
446         ++page_cur_;
447 
448         /* start writing at the start of the page */
449         wp_ = pages_[page_cur_];
450         rem_ = TCCS_PAGE_SIZE;
451 
452         /* we're done */
453         return;
454     }
455 
456     /*
457      *   if we don't have room for a new page in the page array, expand
458      *   the page array
459      */
460     if (page_cnt_ >= page_slots_)
461     {
462         /* increase the page slot count */
463         page_slots_ += 100;
464 
465         /* allocate or reallocate the page array */
466         if (pages_ == 0)
467             pages_ = (char **)t3malloc(page_slots_ * sizeof(pages_[0]));
468         else
469             pages_ = (char **)t3realloc(pages_,
470                                         page_slots_ * sizeof(pages_[0]));
471 
472         /* if that failed, throw an error */
473         if (pages_ == 0)
474             err_throw(TCERR_CODEGEN_NO_MEM);
475     }
476 
477     /* allocate the new page */
478     pages_[page_cnt_] = (char *)t3malloc(TCCS_PAGE_SIZE);
479 
480     /* throw an error if we couldn't allocate the page */
481     if (pages_[page_cnt_] == 0)
482         err_throw(TCERR_CODEGEN_NO_MEM);
483 
484     /* start writing at the start of the new page */
485     wp_ = pages_[page_cnt_];
486 
487     /* the entire page is free */
488     rem_ = TCCS_PAGE_SIZE;
489 
490     /* make the new page the current page */
491     page_cur_ = page_cnt_;
492 
493     /* count the new page */
494     ++page_cnt_;
495 }
496 
497 /*
498  *   Add an absolute fixup for this stream at the current write offset.
499  */
add_abs_fixup(CTcAbsFixup ** list_head)500 void CTcDataStream::add_abs_fixup(CTcAbsFixup **list_head)
501 {
502     /* add the fixup to the list at my current write location */
503     CTcAbsFixup::add_abs_fixup(list_head, this, get_ofs());
504 }
505 
506 
507 /*
508  *   Add an anchor at the current offset.
509  */
add_anchor(CTcSymbol * owner_sym,CTcAbsFixup ** fixup_list_head,ulong ofs)510 CTcStreamAnchor *CTcDataStream::add_anchor(CTcSymbol *owner_sym,
511                                            CTcAbsFixup **fixup_list_head,
512                                            ulong ofs)
513 {
514     CTcStreamAnchor *anchor;
515 
516     /* allocate the anchor, giving it our current offset */
517     anchor = new (allocator_) CTcStreamAnchor(owner_sym,
518                                               fixup_list_head, ofs);
519 
520     /* append it to our list */
521     if (last_anchor_ != 0)
522         last_anchor_->nxt_ = anchor;
523     else
524         first_anchor_ = anchor;
525     last_anchor_ = anchor;
526 
527     /* return the new anchor */
528     return anchor;
529 }
530 
531 /*
532  *   Find an anchor with the given stream offset
533  */
find_anchor(ulong ofs) const534 CTcStreamAnchor *CTcDataStream::find_anchor(ulong ofs) const
535 {
536     CTcStreamAnchor *cur;
537 
538     /* scan the anchor list */
539     for (cur = first_anchor_ ; cur != 0 ; cur = cur->nxt_)
540     {
541         /* if this one has the desired offset, return it */
542         if (cur->get_ofs() == ofs)
543             return cur;
544     }
545 
546     /* didn't find it */
547     return 0;
548 }
549 
550 /*
551  *   Write an object ID
552  */
write_obj_id(ulong obj_id)553 void CTcDataStream::write_obj_id(ulong obj_id)
554 {
555     /*
556      *   if there's an object ID fixup list, and this is a valid object
557      *   reference (not a 'nil' reference), add this reference
558      */
559     if (G_keep_objfixups && obj_id != TCTARG_INVALID_OBJ)
560         CTcIdFixup::add_fixup(&G_objfixup, this, get_ofs(), obj_id);
561 
562     /* write the ID */
563     write4(obj_id);
564 }
565 
566 /*
567  *   Write an object ID self-reference
568  */
write_obj_id_selfref(CTcSymObj * obj_sym)569 void CTcDataStream::write_obj_id_selfref(CTcSymObj *obj_sym)
570 {
571     /*
572      *   Add a fixup list entry to the symbol.  This type of reference
573      *   must be kept with the symbol rather than in the global list,
574      *   because we must apply this type of fixup each time we renumber
575      *   the symbol.
576      */
577     obj_sym->add_self_ref_fixup(this, get_ofs());
578 
579     /* write the ID to the stream */
580     write4(obj_sym->get_obj_id());
581 }
582 
583 
584 /*
585  *   Write a property ID
586  */
write_prop_id(uint prop_id)587 void CTcDataStream::write_prop_id(uint prop_id)
588 {
589     /* if there's an object ID fixup list, add this reference */
590     if (G_keep_propfixups)
591         CTcIdFixup::add_fixup(&G_propfixup, this, get_ofs(), prop_id);
592 
593     /* write the ID */
594     write2(prop_id);
595 }
596 
597 /*
598  *   Write an enumerator ID
599  */
write_enum_id(ulong enum_id)600 void CTcDataStream::write_enum_id(ulong enum_id)
601 {
602     /* if there's a fixup list, add this reference */
603     if (G_keep_enumfixups)
604         CTcIdFixup::add_fixup(&G_enumfixup, this, get_ofs(), enum_id);
605 
606     /* write the ID */
607     write4(enum_id);
608 }
609 
610 /*
611  *   Write the stream, its anchors, and its fixups to an object file.
612  */
write_to_object_file(CVmFile * fp)613 void CTcDataStream::write_to_object_file(CVmFile *fp)
614 {
615     ulong ofs;
616     CTcStreamAnchor *anchor;
617     long cnt;
618 
619     /*
620      *   First, write the data stream bytes.  Write the length prefix
621      *   followed by the data.  Just blast the whole thing out in one huge
622      *   byte stream, one page at a time.
623      */
624     fp->write_int4(ofs_);
625 
626     /* write the data one page at a time */
627     for (ofs = 0 ; ofs < ofs_ ; )
628     {
629         size_t cur;
630 
631         /*
632          *   write out one whole page, or the balance of the current page
633          *   if we have less than a whole page remaining
634          */
635         cur = TCCS_PAGE_SIZE;
636         if (ofs + cur > ofs_)
637             cur = (size_t)(ofs_ - ofs);
638 
639         /* write out this chunk */
640         fp->write_bytes(calc_addr(ofs), cur);
641 
642         /* move to the next page's offset */
643         ofs += cur;
644     }
645 
646     /* count the anchors */
647     for (cnt = 0, anchor = first_anchor_ ; anchor != 0 ;
648          anchor = anchor->nxt_, ++cnt) ;
649 
650     /* write the count */
651     fp->write_int4(cnt);
652 
653     /*
654      *   Write all of the anchors, and all of their fixups.  (We have the
655      *   code to write the anchor and fixup information in-line here for
656      *   efficiency - there will normally be a large number of these tiny
657      *   objects, so anything we can do to improve the speed of this loop
658      *   will help quite a lot in the overall write performance.)
659      */
660     for (anchor = first_anchor_ ; anchor != 0 ; anchor = anchor->nxt_)
661     {
662         char buf[6];
663 
664         /* write the stream offset */
665         oswp4(buf, anchor->get_ofs());
666 
667         /*
668          *   If the anchor has an external fixup list, write the symbol's
669          *   name to the file; otherwise write a zero length to indicate
670          *   that we have an internal fixup list.
671          */
672         if (anchor->get_fixup_owner_sym() == 0)
673         {
674             /* no external list - indicate with a zero symbol length */
675             oswp2(buf+4, 0);
676             fp->write_bytes(buf, 6);
677         }
678         else
679         {
680             /* external list - write the symbol length and name */
681             oswp2(buf+4, anchor->get_fixup_owner_sym()->get_sym_len());
682             fp->write_bytes(buf, 6);
683             fp->write_bytes(anchor->get_fixup_owner_sym()->get_sym(),
684                             anchor->get_fixup_owner_sym()->get_sym_len());
685         }
686 
687         /* write the fixup list */
688         CTcAbsFixup::
689             write_fixup_list_to_object_file(fp, *anchor->fixup_list_head_);
690     }
691 }
692 
693 /*
694  *   Read a stream from an object file
695  */
load_object_file(CVmFile * fp,const textchar_t * fname)696 void CTcDataStream::load_object_file(CVmFile *fp,
697                                      const textchar_t *fname)
698 {
699     ulong stream_len;
700     ulong rem;
701     char buf[1024];
702     ulong start_ofs;
703     ulong anchor_cnt;
704 
705     /* read the length of the stream */
706     stream_len = (ulong)fp->read_int4();
707 
708     /* remember my starting offset */
709     start_ofs = get_ofs();
710 
711     /* read the stream bytes */
712     for (rem = stream_len ; rem != 0 ; )
713     {
714         size_t cur;
715 
716         /* read up to a buffer-full, or however much is left */
717         cur = sizeof(buf);
718         if (cur > rem)
719             cur = rem;
720 
721         /* read this chunk */
722         fp->read_bytes(buf, cur);
723 
724         /* add this chunk to the stream */
725         write(buf, cur);
726 
727         /* deduct the amount we've read from the amount remaining */
728         rem -= cur;
729     }
730 
731     /*
732      *   Read the anchors.  For each anchor, we must fix up the anchor by
733      *   adding the base address of the stream we just read - the original
734      *   anchor offsets in the object file reflect a base stream offset of
735      *   zero, but we could be loading the stream after a bunch of other
736      *   data have already been loaded into the stream.
737      *
738      *   First, read the number of anchors, then loop through the anchors
739      *   and read each one.
740      */
741     for (anchor_cnt = (ulong)fp->read_int4() ; anchor_cnt != 0 ;
742          --anchor_cnt)
743     {
744         ulong anchor_ofs;
745         size_t sym_len;
746         CTcStreamAnchor *anchor;
747 
748         /* read this anchor */
749         fp->read_bytes(buf, 6);
750 
751         /* get the offset, and adjust for the new stream base offset */
752         anchor_ofs = osrp4(buf) + start_ofs;
753 
754         /* get the length of the owning symbol's name, if any */
755         sym_len = osrp2(buf+4);
756 
757         /* if there's a symbol name, read it */
758         if (sym_len != 0)
759         {
760             CTcSymbol *owner_sym;
761 
762             /* read the symbol name */
763             fp->read_bytes(buf, sym_len);
764 
765             /* look it up in the global symbol table */
766             owner_sym = G_prs->get_global_symtab()->find(buf, sym_len);
767             if (owner_sym == 0)
768             {
769                 /*
770                  *   the owner symbol doesn't exist - this is an internal
771                  *   inconsistency in the object file, because the anchor
772                  *   symbol must always be defined in the same file and
773                  *   hence should have been loaded already; complain and
774                  *   go on
775                  */
776                 G_tcmain->log_error(0, 0, TC_SEV_ERROR,
777                                     TCERR_OBJFILE_INT_SYM_MISSING,
778                                     (int)sym_len, buf, fname);
779 
780                 /* we can't create the anchor */
781                 anchor = 0;
782             }
783             else
784             {
785                 /* create the anchor based on the symbol */
786                 anchor = add_anchor(owner_sym,
787                                     owner_sym->get_fixup_list_anchor(),
788                                     anchor_ofs);
789 
790                 /* set the anchor in the symbol */
791                 owner_sym->set_anchor(anchor);
792             }
793         }
794         else
795         {
796             /* create the anchor with no external references */
797             anchor = add_anchor(0, 0, anchor_ofs);
798         }
799 
800         /* load the fixup list */
801         CTcAbsFixup::
802             load_fixup_list_from_object_file(fp, fname,
803                                              anchor->fixup_list_head_);
804     }
805 }
806 
807 /*
808  *   Given a stream ID, get the stream
809  */
810 CTcDataStream *CTcDataStream::
get_stream_from_id(char stream_id,const textchar_t * obj_fname)811    get_stream_from_id(char stream_id, const textchar_t *obj_fname)
812 {
813     switch(stream_id)
814     {
815     case TCGEN_DATA_STREAM:
816         return G_ds;
817 
818     case TCGEN_CODE_STREAM:
819         return G_cs_main;
820 
821     case TCGEN_STATIC_CODE_STREAM:
822         return G_cs_static;
823 
824     case TCGEN_OBJECT_STREAM:
825         return G_os;
826 
827     case TCGEN_ICMOD_STREAM:
828         return G_icmod_stream;
829 
830     case TCGEN_BIGNUM_STREAM:
831         return G_bignum_stream;
832 
833     case TCGEN_STATIC_INIT_ID_STREAM:
834         return G_static_init_id_stream;
835 
836     default:
837         G_tcmain->log_error(0, 0, TC_SEV_ERROR,
838                             TCERR_OBJFILE_INVAL_STREAM_ID, obj_fname);
839         return 0;
840     }
841 }
842 
843 
844 /* ------------------------------------------------------------------------ */
845 /*
846  *   Code Stream
847  */
848 
849 /*
850  *   create the code stream
851  */
CTcCodeStream(char stream_id)852 CTcCodeStream::CTcCodeStream(char stream_id)
853     : CTcDataStream(stream_id)
854 {
855     /* no switch yet */
856     cur_switch_ = 0;
857 
858     /* no enclosing statement yet */
859     enclosing_ = 0;
860 
861     /* no code body being generated yet */
862     code_body_ = 0;
863 
864     /* start writing at offset zero */
865     ofs_ = 0;
866 
867     /* no symbol tables yet */
868     symtab_ = 0;
869     goto_symtab_ = 0;
870 
871     /* no labels yet */
872     active_lbl_ = 0;
873     free_lbl_ = 0;
874 
875     /* no fixups yet */
876     free_fixup_ = 0;
877 
878     /* allocate an initial set of line record pages */
879     line_pages_alloc_ = 0;
880     line_pages_ = 0;
881     alloc_line_pages(5);
882 
883     /* no line records in use yet */
884     line_cnt_ = 0;
885 }
886 
887 
888 /*
889  *   destroy the code stream
890  */
~CTcCodeStream()891 CTcCodeStream::~CTcCodeStream()
892 {
893     size_t i;
894 
895     /* release all active labels */
896     release_labels();
897 
898     /* delete the line records pages */
899     for (i = 0 ; i < line_pages_alloc_ ; ++i)
900         t3free(line_pages_[i]);
901 
902     /* delete the master list of pages */
903     t3free(line_pages_);
904 }
905 
906 /*
907  *   Reset
908  */
reset()909 void CTcCodeStream::reset()
910 {
911     /* inherit default */
912     CTcDataStream::reset();
913 
914     /* clear the line records */
915     clear_line_recs();
916 
917     /*
918      *   forget all of the labels and fixups - they're allocated from the
919      *   allocator pool, which we've completely reset now
920      */
921     free_lbl_ = active_lbl_ = 0;
922     free_fixup_ = 0;
923 
924     /* forget all of the symbol tables */
925     symtab_ = 0;
926     goto_symtab_ = 0;
927 
928     /* forget the frame list */
929     frame_head_ = frame_tail_ = 0;
930     cur_frame_ = 0;
931     frame_cnt_ = 0;
932 
933     /* forget all of the statement settings */
934     cur_switch_ = 0;
935     enclosing_ = 0;
936     code_body_ = 0;
937 
938     /* presume 'self' is not available */
939     self_available_ = FALSE;
940 }
941 
942 /*
943  *   Allocate line record pages
944  */
alloc_line_pages(size_t number_to_add)945 void CTcCodeStream::alloc_line_pages(size_t number_to_add)
946 {
947     size_t siz;
948     size_t i;
949 
950     /* create or expand the master page array */
951     siz = (line_pages_alloc_ + number_to_add) * sizeof(tcgen_line_page_t *);
952     if (line_pages_ == 0)
953         line_pages_ = (tcgen_line_page_t **)t3malloc(siz);
954     else
955         line_pages_ = (tcgen_line_page_t **)t3realloc(line_pages_, siz);
956 
957     /* allocate the new pages */
958     for (i = line_pages_alloc_ ; i < line_pages_alloc_ + number_to_add ; ++i)
959     {
960         /* allocate this page */
961         line_pages_[i] = (tcgen_line_page_t *)
962                          t3malloc(sizeof(tcgen_line_page_t));
963     }
964 
965     /* remember the new allocation */
966     line_pages_alloc_ += number_to_add;
967 }
968 
969 /*
970  *   Allocate a new label object
971  */
alloc_label()972 CTcCodeLabel *CTcCodeStream::alloc_label()
973 {
974     CTcCodeLabel *ret;
975 
976     /* if there's anything in the free list, use it */
977     if (free_lbl_ != 0)
978     {
979         /* take the first one off the free list */
980         ret = free_lbl_;
981 
982         /* unlink it from the list */
983         free_lbl_ = free_lbl_->nxt;
984     }
985     else
986     {
987         /* allocate a new label */
988         ret = new (allocator_) CTcCodeLabel;
989 
990         /* throw an error if allocation failed */
991         if (ret == 0)
992             err_throw(TCERR_CODEGEN_NO_MEM);
993     }
994 
995     /* add the label to the active list */
996     ret->nxt = active_lbl_;
997     active_lbl_ = ret;
998 
999     /* return the allocated label */
1000     return ret;
1001 }
1002 
1003 /*
1004  *   Allocate a new fixup object
1005  */
alloc_fixup()1006 CTcLabelFixup *CTcCodeStream::alloc_fixup()
1007 {
1008     CTcLabelFixup *ret;
1009 
1010     /* if there's anything in the free list, use it */
1011     if (free_fixup_ != 0)
1012     {
1013         /* take the first one off the free list */
1014         ret = free_fixup_;
1015 
1016         /* unlink it from the list */
1017         free_fixup_ = free_fixup_->nxt;
1018     }
1019     else
1020     {
1021         /* allocate a new fixup */
1022         ret = new (allocator_) CTcLabelFixup;
1023 
1024         /* throw an error if allocation failed */
1025         if (ret == 0)
1026             err_throw(TCERR_CODEGEN_NO_MEM);
1027     }
1028 
1029     /* return the allocated fixup */
1030     return ret;
1031 }
1032 
1033 /*
1034  *   Release all active labels.  If any labels are undefined, log an
1035  *   internal error.
1036  */
release_labels()1037 void CTcCodeStream::release_labels()
1038 {
1039     int err_cnt;
1040 
1041     /* we haven't found any errors yet */
1042     err_cnt = 0;
1043 
1044     /* run through the list of active labels */
1045     while (active_lbl_ != 0)
1046     {
1047         CTcCodeLabel *lbl;
1048 
1049         /* pull this label off of the active list */
1050         lbl = active_lbl_;
1051         active_lbl_ = active_lbl_->nxt;
1052 
1053         /* put this label on the free list */
1054         lbl->nxt = free_lbl_;
1055         free_lbl_ = lbl;
1056 
1057         /* check for unresolved fixups */
1058         while (lbl->fhead != 0)
1059         {
1060             CTcLabelFixup *fixup;
1061 
1062             /* pull this fixup off of the active list */
1063             fixup = lbl->fhead;
1064             lbl->fhead = lbl->fhead->nxt;
1065 
1066             /* put this fixup on the free list */
1067             fixup->nxt = free_fixup_;
1068             free_fixup_ = fixup;
1069 
1070             /* count the unresolved label */
1071             ++err_cnt;
1072         }
1073     }
1074 
1075     /*
1076      *   if we found any unresolved fixups, log the error; there's not
1077      *   much point in logging each error individually, since this is an
1078      *   internal compiler error that the user can't do anything about,
1079      *   but at least give the user a count for compiler diagnostic
1080      *   purposes
1081      */
1082     if (err_cnt != 0)
1083         G_tcmain->log_error(0, 0, TC_SEV_INTERNAL,
1084                           TCERR_UNRES_TMP_FIXUP, err_cnt);
1085 }
1086 
1087 /*
1088  *   Allocate a new label at the current code offset
1089  */
new_label_here()1090 CTcCodeLabel *CTcCodeStream::new_label_here()
1091 {
1092     CTcCodeLabel *lbl;
1093 
1094     /* allocate a new label */
1095     lbl = alloc_label();
1096 
1097     /* set the label's location to the current write position */
1098     lbl->ofs = ofs_;
1099     lbl->is_known = TRUE;
1100 
1101     /* return the new label */
1102     return lbl;
1103 }
1104 
1105 /*
1106  *   Allocate a new forward-reference label
1107  */
new_label_fwd()1108 CTcCodeLabel *CTcCodeStream::new_label_fwd()
1109 {
1110     CTcCodeLabel *lbl;
1111 
1112     /* allocate a new label */
1113     lbl = alloc_label();
1114 
1115     /* the label's location is not yet known */
1116     lbl->ofs = 0;
1117     lbl->is_known = FALSE;
1118 
1119     /* return the new label */
1120     return lbl;
1121 }
1122 
1123 /*
1124  *   Define the position of a label, resolving any fixups associated with
1125  *   the label.
1126  */
def_label_pos(CTcCodeLabel * lbl)1127 void CTcCodeStream::def_label_pos(CTcCodeLabel *lbl)
1128 {
1129     /* set the label's position */
1130     lbl->ofs = ofs_;
1131     lbl->is_known = TRUE;
1132 
1133     /* resolve each fixup */
1134     while (lbl->fhead != 0)
1135     {
1136         CTcLabelFixup *fixup;
1137         long diff;
1138         char buf[4];
1139 
1140         /* pull this fixup off of the active list */
1141         fixup = lbl->fhead;
1142         lbl->fhead = lbl->fhead->nxt;
1143 
1144         /*
1145          *   calculate the offset from the fixup position to the label
1146          *   position, applying the bias to the fixup position
1147          */
1148         diff = lbl->ofs - (fixup->ofs + fixup->bias);
1149 
1150         /* convert the offset to the correct format and write it out */
1151         if (fixup->is_long)
1152         {
1153             /* write an INT4 offset value */
1154             oswp4(buf, diff);
1155             write_at(fixup->ofs, buf, 4);
1156         }
1157         else
1158         {
1159             /* write an INT2 offset value */
1160             oswp2(buf, diff);
1161             write_at(fixup->ofs, buf, 2);
1162         }
1163 
1164         /* add this fixup to the free list, since we're finished with it */
1165         fixup->nxt = free_fixup_;
1166         free_fixup_ = fixup;
1167     }
1168 }
1169 
1170 /*
1171  *   Determine if a label has a fixup at a particular offset
1172  */
has_fixup_at_ofs(CTcCodeLabel * lbl,ulong ofs)1173 int CTcCodeStream::has_fixup_at_ofs(CTcCodeLabel *lbl, ulong ofs)
1174 {
1175     CTcLabelFixup *fixup;
1176 
1177     /* scan for a match */
1178     for (fixup = lbl->fhead ; fixup != 0 ; fixup = fixup->nxt)
1179     {
1180         /* if this is a match, indicate success */
1181         if (fixup->ofs == ofs)
1182             return TRUE;
1183     }
1184 
1185     /* we didn't find a match */
1186     return FALSE;
1187 }
1188 
1189 /*
1190  *   Remove a label's fixup at a particular offset
1191  */
remove_fixup_at_ofs(CTcCodeLabel * lbl,ulong ofs)1192 void CTcCodeStream::remove_fixup_at_ofs(CTcCodeLabel *lbl, ulong ofs)
1193 {
1194     CTcLabelFixup *fixup;
1195     CTcLabelFixup *prv;
1196     CTcLabelFixup *nxt;
1197 
1198     /* scan for a match */
1199     for (prv = 0, fixup = lbl->fhead ; fixup != 0 ; prv = fixup, fixup = nxt)
1200     {
1201         /* remember the next one */
1202         nxt = fixup->nxt;
1203 
1204         /* if this is a match, remove it */
1205         if (fixup->ofs == ofs)
1206         {
1207             /* unlink this fixup from the list */
1208             if (prv == 0)
1209                 lbl->fhead = nxt;
1210             else
1211                 prv->nxt = nxt;
1212 
1213             /* move it to the free list */
1214             fixup->nxt = free_fixup_;
1215             free_fixup_ = fixup;
1216         }
1217     }
1218 }
1219 
1220 /*
1221  *   Write an offset value to the given label
1222  */
write_ofs(CTcCodeLabel * lbl,int bias,int is_long)1223 void CTcCodeStream::write_ofs(CTcCodeLabel *lbl, int bias, int is_long)
1224 {
1225     /* if the label is known, write it; otherwise, generate a fixup */
1226     if (lbl->is_known)
1227     {
1228         long diff;
1229 
1230         /*
1231          *   calculate the branch offset from the current position,
1232          *   applying the bias to the current position
1233          */
1234         diff = lbl->ofs - (ofs_ + bias);
1235 
1236         /* convert the offset to the correct format and write it out */
1237         if (is_long)
1238             write4(diff);
1239         else
1240             write2(diff);
1241     }
1242     else
1243     {
1244         CTcLabelFixup *fixup;
1245 
1246         /* allocate a fixup */
1247         fixup = alloc_fixup();
1248 
1249         /* set up the fixup data */
1250         fixup->ofs = ofs_;
1251         fixup->bias = bias;
1252         fixup->is_long = is_long;
1253 
1254         /* link the fixup into the label's fixup list */
1255         fixup->nxt = lbl->fhead;
1256         lbl->fhead = fixup;
1257 
1258         /* write a placeholder to the code stream */
1259         if (is_long)
1260             write4(0);
1261         else
1262             write2(0);
1263     }
1264 }
1265 
1266 /*
1267  *   Add a new line record at the current code offset
1268  */
add_line_rec(CTcTokFileDesc * file,long linenum)1269 void CTcCodeStream::add_line_rec(CTcTokFileDesc *file, long linenum)
1270 {
1271     tcgen_line_t *rec;
1272     ulong cur_ofs;
1273     int reuse;
1274 
1275     /* if there's no file descriptor, there's nothing to add */
1276     if (file == 0)
1277         return;
1278 
1279     /* compute the current offset, relative to the start of the method */
1280     cur_ofs = G_cs->get_ofs() - method_ofs_;
1281 
1282     /* presume we won't re-use the previous record */
1283     reuse = FALSE;
1284 
1285     /*
1286      *   If we haven't added any code since the previous line record,
1287      *   overwrite the previous record - it doesn't refer to any
1288      *   executable code, so it's an unnecessary record.  Similarly, if
1289      *   the previous record is at the same source position, don't add a
1290      *   separate line record for it, since the debugger won't be able to
1291      *   treat the two lines separately.
1292      */
1293     if (line_cnt_ > 0)
1294     {
1295         /* get the previous record */
1296         rec = get_line_rec(line_cnt_ - 1);
1297 
1298         /*
1299          *   if it refers to the same code offset, replace the old record
1300          *   with one at this location
1301          */
1302         if (rec->ofs == cur_ofs)
1303             reuse = TRUE;
1304 
1305         /*
1306          *   if it has the identical source file location, don't bother
1307          *   adding a new record at all
1308          */
1309         if (rec->source_id == file->get_index()
1310             && rec->source_line == linenum)
1311             return;
1312     }
1313 
1314     /* if we're not re-using the previous record, allocate a new one */
1315     if (!reuse)
1316     {
1317         /*
1318          *   we need a new record - if we've used all the allocated space,
1319          *   allocate more
1320          */
1321         if (line_cnt_ >= line_pages_alloc_ * TCGEN_LINE_PAGE_SIZE)
1322             alloc_line_pages(5);
1323 
1324         /* get a pointer to the next available entry */
1325         rec = get_line_rec(line_cnt_);
1326 
1327         /* count the new record */
1328         ++line_cnt_;
1329     }
1330 
1331     /* store the code offset relative to the start of the current method */
1332     rec->ofs = cur_ofs;
1333 
1334     /* store the file information */
1335     rec->source_id = file->get_index();
1336     rec->source_line = linenum;
1337 
1338     /* store the frame information */
1339     rec->frame = cur_frame_;
1340 }
1341 
1342 /*
1343  *   Get the nth line record
1344  */
get_line_rec(size_t n)1345 tcgen_line_t *CTcCodeStream::get_line_rec(size_t n)
1346 {
1347     return &(line_pages_[n / TCGEN_LINE_PAGE_SIZE]
1348              ->lines[n % TCGEN_LINE_PAGE_SIZE]);
1349 }
1350 
1351 /*
1352  *   Add a frame to the list of local frames in the method
1353  */
add_local_frame(CTcPrsSymtab * symtab)1354 void CTcCodeStream::add_local_frame(CTcPrsSymtab *symtab)
1355 {
1356     /*
1357      *   If this is the global symbol table, or it's null, or it's already
1358      *   in a list, ignore it.  Note that we can tell if the item is in a
1359      *   list by checking its index value - a value of zero is never a
1360      *   valid index and thus indicates that the item isn't in a list yet.
1361      */
1362     if (symtab == G_prs->get_global_symtab()
1363         || symtab == 0
1364         || symtab->get_list_index() != 0)
1365         return;
1366 
1367     /* link the frame in at the tail of our list */
1368     symtab->set_list_next(0);
1369     if (frame_tail_ == 0)
1370         frame_head_ = symtab;
1371     else
1372         frame_tail_->set_list_next(symtab);
1373     frame_tail_ = symtab;
1374 
1375     /* count the new entry in the list */
1376     ++frame_cnt_;
1377 
1378     /*
1379      *   Set this frame's index in the list.  Note that we've already
1380      *   incremented the index value, so the first frame in the list will
1381      *   have index 1, as is required.
1382      */
1383     symtab->set_list_index(frame_cnt_);
1384 }
1385 
1386 /* ------------------------------------------------------------------------ */
1387 /*
1388  *   Data stream anchor
1389  */
1390 
1391 /*
1392  *   Get the length.  We can deduce the length by subtracting our offset
1393  *   from the next item's offset, or, if we're the last item, from the
1394  *   length of the stream.
1395  */
get_len(CTcDataStream * ds) const1396 ulong CTcStreamAnchor::get_len(CTcDataStream *ds) const
1397 {
1398     if (nxt_ != 0)
1399     {
1400         /*
1401          *   there's another item after me - my length is the difference
1402          *   between the next item's offset and my offset
1403          */
1404         return (nxt_->ofs_ - ofs_);
1405     }
1406     else
1407     {
1408         /* I'm the last item - my length is whatever is left in the stream */
1409         return (ds->get_ofs() - ofs_);
1410     }
1411 }
1412 
1413 /*
1414  *   Set the finaly absoluate address, and apply fixups.  The code
1415  *   generator must invoke this during the link phase once this object's
1416  *   final address is known.
1417  */
set_addr(ulong addr)1418 void CTcStreamAnchor::set_addr(ulong addr)
1419 {
1420     /* remember my address */
1421     addr_ = addr;
1422 
1423     /* apply all outstanding fixups for this object */
1424     CTcAbsFixup::fix_abs_fixup(*fixup_list_head_, addr);
1425 }
1426 
1427 /* ------------------------------------------------------------------------ */
1428 /*
1429  *   Absolute Fixup Object
1430  */
1431 
1432 /*
1433  *   Add an absolute fixup at the current stream location to a given fixup
1434  *   list.
1435  */
add_abs_fixup(CTcAbsFixup ** list_head,CTcDataStream * ds,ulong ofs)1436 void CTcAbsFixup::add_abs_fixup(CTcAbsFixup **list_head,
1437                                 CTcDataStream *ds, ulong ofs)
1438 {
1439     CTcAbsFixup *fixup;
1440 
1441     /*
1442      *   create the fixup object - allocate it out of our fixup allocator
1443      *   pool, since this fixup object has the same attributes (small and
1444      *   long-lived) as other fixup objects
1445      */
1446     fixup = (CTcAbsFixup *)G_prsmem->alloc(sizeof(CTcAbsFixup));
1447 
1448     /* set the fixup location to the current offset */
1449     fixup->ds = ds;
1450     fixup->ofs = ofs;
1451 
1452     /* link it in to the caller's list */
1453     fixup->nxt = *list_head;
1454     *list_head = fixup;
1455 }
1456 
1457 /*
1458  *   Fix up a fix-up list
1459  */
fix_abs_fixup(CTcAbsFixup * list_head,ulong final_ofs)1460 void CTcAbsFixup::fix_abs_fixup(CTcAbsFixup *list_head, ulong final_ofs)
1461 {
1462     CTcAbsFixup *cur;
1463 
1464     /* scan the list and fix up each entry */
1465     for (cur = list_head ; cur != 0 ; cur = cur->nxt)
1466     {
1467         /*
1468          *   fix this entry by writing the final offset in UINT4 format to
1469          *   the target stream at the target offset
1470          */
1471         cur->ds->write4_at(cur->ofs, final_ofs);
1472     }
1473 }
1474 
1475 /*
1476  *   Write a fixup list to an object file
1477  */
1478 void CTcAbsFixup::
write_fixup_list_to_object_file(CVmFile * fp,CTcAbsFixup * list_head)1479    write_fixup_list_to_object_file(CVmFile *fp, CTcAbsFixup *list_head)
1480 {
1481     int cnt;
1482     CTcAbsFixup *fixup;
1483 
1484     /* count the fixups */
1485     for (cnt = 0, fixup = list_head ; fixup != 0 ;
1486          fixup = fixup->nxt, ++cnt) ;
1487 
1488     /* write the count */
1489     fp->write_int2(cnt);
1490 
1491         /* write the fixup list */
1492     for (fixup = list_head ; fixup != 0 ; fixup = fixup->nxt)
1493     {
1494         char buf[5];
1495 
1496         /* write the data stream ID */
1497         buf[0] = fixup->ds->get_stream_id();
1498 
1499         /* write the data stream offset of the reference */
1500         oswp4(buf+1, fixup->ofs);
1501 
1502         /* write the data */
1503         fp->write_bytes(buf, 5);
1504     }
1505 }
1506 
1507 /*
1508  *   Read a fixup list from an object file
1509  */
1510 void CTcAbsFixup::
load_fixup_list_from_object_file(CVmFile * fp,const textchar_t * obj_fname,CTcAbsFixup ** list_head)1511    load_fixup_list_from_object_file(CVmFile *fp,
1512                                     const textchar_t *obj_fname,
1513                                     CTcAbsFixup **list_head)
1514 {
1515     uint fixup_cnt;
1516 
1517     /* read the fixups */
1518     for (fixup_cnt = fp->read_uint2() ; fixup_cnt != 0 ; --fixup_cnt)
1519     {
1520         char buf[5];
1521         char stream_id;
1522         ulong fixup_ofs;
1523         CTcDataStream *stream;
1524 
1525         /* read the fixup data */
1526         fp->read_bytes(buf, 5);
1527         stream_id = buf[0];
1528         fixup_ofs = osrp4(buf+1);
1529 
1530         /* find the stream for the ID */
1531         stream = CTcDataStream::get_stream_from_id(stream_id, obj_fname);
1532 
1533         /* if the stream is invalid, ignore this record */
1534         if (stream == 0)
1535             continue;
1536 
1537         /*
1538          *   the fixup offset is relative to the starting offset of the
1539          *   stream for the current object file - adjust it accordingly
1540          */
1541         fixup_ofs += stream->get_object_file_start_ofs();
1542 
1543         /* create the fixup and add it to the list */
1544         add_abs_fixup(list_head, stream, fixup_ofs);
1545     }
1546 }
1547 
1548 /* ------------------------------------------------------------------------ */
1549 /*
1550  *   Object/property ID fixups
1551  */
1552 
1553 /*
1554  *   add a fixup to a list
1555  */
add_fixup(CTcIdFixup ** list_head,class CTcDataStream * ds,ulong ofs,ulong id)1556 void CTcIdFixup::add_fixup(CTcIdFixup **list_head, class CTcDataStream *ds,
1557                            ulong ofs, ulong id)
1558 {
1559     CTcIdFixup *fixup;
1560 
1561     /* create the new fixup object */
1562     fixup = new (G_prsmem) CTcIdFixup(ds, ofs, id);
1563 
1564     /* link it in at the head of the list */
1565     fixup->nxt_ = *list_head;
1566     *list_head = fixup;
1567 }
1568 
1569 /*
1570  *   Apply this fixup
1571  */
apply_fixup(ulong final_id,size_t siz)1572 void CTcIdFixup::apply_fixup(ulong final_id, size_t siz)
1573 {
1574     /* write the fixup */
1575     if (siz == 2)
1576         ds_->write2_at(ofs_, (uint)final_id);
1577     else
1578         ds_->write4_at(ofs_, final_id);
1579 }
1580 
1581 /*
1582  *   Write a fixup list to an object file
1583  */
write_to_object_file(CVmFile * fp,CTcIdFixup * head)1584 void CTcIdFixup::write_to_object_file(CVmFile *fp, CTcIdFixup *head)
1585 {
1586     ulong cnt;
1587     CTcIdFixup *cur;
1588 
1589     /* count the elements in the list */
1590     for (cur = head, cnt = 0 ; cur != 0 ; cur = cur->nxt_, ++cnt) ;
1591 
1592     /* write the count */
1593     fp->write_int4(cnt);
1594 
1595     /* write the fixups */
1596     for (cur = head ; cur != 0 ; cur = cur->nxt_)
1597     {
1598         char buf[9];
1599 
1600         /* prepare a buffer with the data in portable format */
1601         buf[0] = cur->ds_->get_stream_id();
1602         oswp4(buf+1, cur->ofs_);
1603         oswp4(buf+5, cur->id_);
1604 
1605         /* write the data */
1606         fp->write_bytes(buf, 9);
1607     }
1608 }
1609 
1610 /*
1611  *   Read an object ID fixup list from an object file
1612  */
load_object_file(CVmFile * fp,const void * xlat,ulong xlat_cnt,tcgen_xlat_type xlat_type,size_t stream_element_size,const textchar_t * fname,CTcIdFixup ** fixup_list_head)1613 void CTcIdFixup::load_object_file(CVmFile *fp,
1614                                   const void *xlat,
1615                                   ulong xlat_cnt,
1616                                   tcgen_xlat_type xlat_type,
1617                                   size_t stream_element_size,
1618                                   const textchar_t *fname,
1619                                   CTcIdFixup **fixup_list_head)
1620 {
1621     ulong cnt;
1622 
1623     /* read the count, then read the fixups */
1624     for (cnt = (ulong)fp->read_int4() ; cnt != 0 ; --cnt)
1625     {
1626         char buf[9];
1627         ulong ofs;
1628         ulong old_id;
1629         ulong new_id;
1630         CTcDataStream *stream;
1631 
1632         /* read the next fixup */
1633         fp->read_bytes(buf, 9);
1634         stream = CTcDataStream::get_stream_from_id(buf[0], fname);
1635         ofs = osrp4(buf+1);
1636         old_id = osrp4(buf+5);
1637 
1638         /* if the stream was invalid, ignore this record */
1639         if (stream == 0)
1640             continue;
1641 
1642         /* adjust the offset for the stream's start in this object file */
1643         ofs += stream->get_object_file_start_ofs();
1644 
1645         /* apply the fixup if a translation table was provided */
1646         if (xlat != 0)
1647         {
1648             /* make sure the count is in range - if it's not, ignore it */
1649             if (old_id >= xlat_cnt)
1650             {
1651                 /* note the problem */
1652                 G_tcmain->log_error(0, 0, TC_SEV_ERROR,
1653                                     TCERR_OBJFILE_INVAL_OBJ_ID, fname);
1654 
1655                 /* ignore the record */
1656                 continue;
1657             }
1658 
1659             /* look up the new ID */
1660             switch(xlat_type)
1661             {
1662             case TCGEN_XLAT_OBJ:
1663                 new_id = ((const tctarg_obj_id_t *)xlat)[old_id];
1664                 break;
1665 
1666             case TCGEN_XLAT_PROP:
1667                 new_id = ((const tctarg_prop_id_t *)xlat)[old_id];
1668                 break;
1669 
1670             case TCGEN_XLAT_ENUM:
1671                 new_id = ((const ulong *)xlat)[old_id];
1672                 break;
1673             }
1674 
1675             /* apply the fixup */
1676             if (stream_element_size == 2)
1677                 stream->write2_at(ofs, (uint)new_id);
1678             else
1679                 stream->write4_at(ofs, new_id);
1680         }
1681         else
1682         {
1683             /* use the original ID for now */
1684             new_id = old_id;
1685         }
1686 
1687         /*
1688          *   If we're keeping object fixups in the new file, create a
1689          *   fixup for the reference.  Note that the fixup is for the new
1690          *   ID, not the old ID, because we've already translated the
1691          *   value in the stream to the new ID.
1692          */
1693         if (fixup_list_head != 0)
1694             CTcIdFixup::add_fixup(fixup_list_head, stream, ofs, new_id);
1695     }
1696 }
1697 
1698