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