home *** CD-ROM | disk | FTP | other *** search
- /* Output bytecodes for GNU C-compiler.
- Copyright (C) 1993 Free Software Foundation, Inc.
-
- This file is part of GNU CC.
-
- GNU CC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
- #include "config.h"
- #include "gvarargs.h"
- #include "machmode.h"
- #include "rtl.h"
- #include "real.h"
- #include "obstack.h"
- #include "bytecode.h"
- #ifdef __GNUC__
- #include "bytetypes.h"
- #endif
- #include "bc-emit.h"
- #include "bc-opcode.h"
- #include "bc-typecd.h"
- #include "bi-run.h"
-
- #include <stdio.h>
-
- extern char *xmalloc (), *xrealloc ();
- extern void free ();
-
- extern struct obstack *rtl_obstack;
-
- /* Indexed by mode class, gives the narrowest mode for each class. */
-
- enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS];
-
- /* Commonly used modes. */
- /* Mode whose width is BITS_PER_UNIT */
- enum machine_mode byte_mode;
-
- /* Mode whose width is BITS_PER_WORD */
- enum machine_mode word_mode;
-
- /* Vector indexed by opcode giving info about the args for each opcode. */
- static struct arityvec arityvec[] = {
- #include "bc-arity.h"
- };
-
- /* How to print a symbol name for the assembler. */
- static void
- prsym (file, s)
- FILE *file;
- char *s;
- {
- if (*s == '*')
- fprintf (file, "%s", s + 1);
- else
-
- #ifdef NAMES_HAVE_UNDERSCORES
- fprintf (file, "_%s", s);
- #else
- fprintf (file, "%s", s);
- #endif
-
- }
-
- /* Maintain a bucket hash table for symbol names. */
-
- #define HASH_BITS 32
- #define HASH_SIZE 509
-
- static struct bc_sym *hashtab[HASH_SIZE];
-
- static unsigned int
- hash (name)
- char *name;
- {
- unsigned int hash = 0;
-
- while (*name)
- {
- hash = hash << 3 | hash >> HASH_BITS - 3;
- hash += *name++;
- }
-
- return hash % HASH_SIZE;
- }
-
-
- /* Look up the named symbol, creating it if it doesn't exist. */
- struct bc_sym *
- sym_lookup (name)
- char *name;
- {
- int i;
- struct bc_sym *s;
-
- i = hash (name);
- for (s = hashtab[i]; s; s = s->next)
- if (!strcmp (s->name, name))
- return s;
-
- s = (struct bc_sym *) xmalloc (sizeof (struct bc_sym));
- s->name = xmalloc (strlen (name) + 1);
- strcpy (s->name, name);
- s->defined = s->global = s->common = 0;
- s->val = 0;
- s->next = hashtab[i];
- hashtab[i] = s;
- return s;
- }
-
-
- /* Write out .globl and common symbols to the named file. */
- static void
- bc_sym_write (file)
- FILE *file;
- {
- int i;
- struct bc_sym *s;
-
- for (i = 0; i < HASH_SIZE; ++i)
- for (s = hashtab[i]; s; s = s->next)
- {
- if (s->global)
- {
- fprintf (file, "\n\t.globl ");
- prsym (file, s->name);
- putc ('\n', file);
- if (s->common)
- {
- fprintf (file, "\n\t.comm ");
- prsym (file, s->name);
- fprintf (file, ", %d\n", s->val);
- }
- }
- else if (s->common)
- {
- fprintf (file, "\n\t.lcomm ");
- prsym (file, s->name);
- fprintf (file, ", %d\n", s->val);
- }
- }
- }
-
-
-
-
- /* Create and initialize a new segment. */
- static struct bc_seg *
- seg_create ()
- {
- struct bc_seg *result;
-
- result = (struct bc_seg *) xmalloc (sizeof (struct bc_seg));
- result->alloc = 256;
- result->data = xmalloc (result->alloc);
- result->size = 0;
- result->syms = 0;
- result->relocs = 0;
- return result;
- }
-
-
- /* Advance the segment index to the next alignment boundary. */
- static void
- seg_align (seg, log)
- struct bc_seg *seg;
- int log;
- {
- unsigned int oldsize = seg->size;
-
- seg->size = seg->size + (1 << log) - 1 & ~((1 << log) - 1);
- if (seg->size > seg->alloc)
- {
- while (seg->size > seg->alloc)
- seg->alloc *= 2;
- seg->data = xrealloc (seg->data, seg->alloc);
- }
- bzero (seg->data + oldsize, seg->size - oldsize);
- }
-
-
- /* Append the given data to the given segment. */
- static void
- seg_data (seg, data, size)
- struct bc_seg *seg;
- char *data;
- unsigned int size;
- {
- if (seg->size + size > seg->alloc)
- {
- while (seg->size + size > seg->alloc)
- seg->alloc *= 2;
- seg->data = xrealloc (seg->data, seg->alloc);
- }
-
- bcopy (data, seg->data + seg->size, size);
- seg->size += size;
- }
-
-
- /* Append a zero-filled skip to the given segment. */
- static void
- seg_skip (seg, size)
- struct bc_seg *seg;
- unsigned int size;
- {
- if (seg->size + size > seg->alloc)
- {
- while (seg->size + size > seg->alloc)
- seg->alloc *= 2;
- seg->data = xrealloc (seg->data, seg->alloc);
- }
-
- memset (seg->data + seg->size, 0, size);
- seg->size += size;
- }
-
-
- /* Define the given name as the current offset in the given segment. It
- is an error if the name is already defined. Return 0 or 1 indicating
- failure or success respectively. */
- static int
- seg_defsym (seg, name)
- struct bc_seg *seg;
- char *name;
- {
- struct bc_sym *sym;
- struct bc_segsym *segsym;
-
- sym = sym_lookup (name);
- if (sym->defined)
- return 0;
-
- sym->defined = 1;
- sym->val = seg->size;
- segsym = (struct bc_segsym *) xmalloc (sizeof (struct bc_segsym));
- segsym->sym = sym;
- segsym->next = seg->syms;
- seg->syms = segsym;
- return 1;
- }
-
-
- /* Generate in seg's data a reference to the given sym, adjusted by
- the given offset. */
- static void
- seg_refsym (seg, name, offset)
- struct bc_seg *seg;
- char *name;
- int offset;
- {
- struct bc_sym *sym;
- struct bc_segreloc *segreloc;
-
- sym = sym_lookup (name);
- segreloc = (struct bc_segreloc *) xmalloc (sizeof (struct bc_segreloc));
- segreloc->offset = seg->size;
- segreloc->sym = sym;
- segreloc->next = seg->relocs;
- seg->relocs = segreloc;
- seg_data (seg, (char *) &offset, sizeof offset);
- }
-
-
- /* Concatenate the contents of given segments into the first argument. */
- static void
- seg_concat (result, seg)
- struct bc_seg *result, *seg;
- {
- unsigned int fix;
- struct bc_segsym *segsym;
- struct bc_segreloc *segreloc;
-
- seg_align (result, MACHINE_SEG_ALIGN);
- fix = result->size;
- seg_data (result, seg->data, seg->size);
- free (seg->data);
-
- /* Go through the symbols and relocs of SEG, adjusting their offsets
- for their new location in RESULT. */
- if (seg->syms)
- {
- segsym = seg->syms;
- do
- segsym->sym->val += fix;
- while (segsym->next && (segsym = segsym->next));
- segsym->next = result->syms;
- result->syms = seg->syms;
- }
- if (seg->relocs)
- {
- segreloc = seg->relocs;
- do
- segreloc->offset += fix;
- while (segreloc->next && (segreloc = segreloc->next));
- segreloc->next = result->relocs;
- result->relocs = seg->relocs;
- }
-
- free ((char *) seg);
- }
-
- /* Write a segment to a file. */
- static void
- bc_seg_write (seg, file)
- struct bc_seg *seg;
- FILE *file;
- {
- struct bc_segsym *segsym, *nsegsym, *psegsym;
- struct bc_segreloc *segreloc, *nsegreloc, *psegreloc;
- int i, offset, flag;
-
- /* Reverse the list of symbols. */
- for (psegsym = 0, segsym = seg->syms; segsym; segsym = nsegsym)
- {
- nsegsym = segsym->next;
- segsym->next = psegsym;
- psegsym = segsym;
- }
- seg->syms = psegsym;
-
- /* Reverse the list of relocs. */
- for (psegreloc = 0, segreloc = seg->relocs; segreloc; segreloc = nsegreloc)
- {
- nsegreloc = segreloc->next;
- segreloc->next = psegreloc;
- psegreloc = segreloc;
- }
- seg->relocs = psegreloc;
-
- /* Output each byte of the segment. */
- for (i = 0, segsym = seg->syms, segreloc = seg->relocs; i < seg->size; ++i)
- {
- while (segsym && segsym->sym->val == i)
- {
- if (i % 8 != 0)
- putc ('\n', file);
-
- BC_WRITE_SEGSYM (segsym, file);
- segsym = segsym->next;
- flag = 1;
- }
- if (segreloc && segreloc->offset == i)
- {
- if (i % 8 != 0)
- putc ('\n', file);
-
- offset = *(int *) (seg->data + i);
- i += sizeof (int) - 1;
-
- BC_WRITE_RELOC_ENTRY (segreloc, file, offset);
- segreloc = segreloc->next;
- flag = 1;
- }
- else
- {
- if (i % 8 == 0 || flag)
- BC_START_BYTECODE_LINE (file);
-
- BC_WRITE_BYTECODE (i % 8 == 0 || flag ? ' ' : ',',
- seg->data[i] & 0xFF,
- file);
- flag = 0;
- if (i % 8 == 7)
- putc ('\n', file);
- }
- }
-
- /* Paranoia check--we should have visited all syms and relocs during
- the output pass. */
-
- if (segsym || segreloc)
- abort ();
- }
-
-
-
- /* Text and data segments of the object file in making. */
- static struct bc_seg *bc_text_seg;
- static struct bc_seg *bc_data_seg;
-
- /* Called before anything else in this module. */
- void
- bc_initialize ()
- {
- int min_class_size[(int) MAX_MODE_CLASS];
- enum machine_mode mode;
- int i;
-
- bc_init_mode_to_code_map ();
-
- bc_text_seg = seg_create ();
- bc_data_seg = seg_create ();
-
- dconst0 = REAL_VALUE_ATOF ("0", DFmode);
- dconst1 = REAL_VALUE_ATOF ("1", DFmode);
- dconst2 = REAL_VALUE_ATOF ("2", DFmode);
- dconstm1 = REAL_VALUE_ATOF ("-1", DFmode);
-
- /* Find the narrowest mode for each class and compute the word and byte
- modes. */
-
- for (i = 0; i < (int) MAX_MODE_CLASS; i++)
- min_class_size[i] = 1000;
-
- for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
- mode = (enum machine_mode) ((int) mode + 1))
- {
- if (GET_MODE_SIZE (mode) < min_class_size[(int) GET_MODE_CLASS (mode)])
- {
- class_narrowest_mode[(int) GET_MODE_CLASS (mode)] = mode;
- min_class_size[(int) GET_MODE_CLASS (mode)] = GET_MODE_SIZE (mode);
- }
- if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_BITSIZE (mode) == BITS_PER_UNIT)
- byte_mode = mode;
-
- if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_BITSIZE (mode) == BITS_PER_WORD)
- word_mode = mode;
- }
- }
-
-
- /* External addresses referenced in a function. Rather than trying to
- work relocatable address directly into bytecoded functions (which would
- require us to provide hairy location info and possibly obey alignment
- rules imposed by the architecture) we build an auxilary table of
- pointer constants, and encode just offsets into this table into the
- actual bytecode. */
- static struct bc_seg *ptrconsts;
-
- /* Trampoline code for the function entry. */
- struct bc_seg *trampoline;
-
- /* Actual byte code of the function. */
- struct bc_seg *bytecode;
-
- /* List of labels defined in the function. */
- struct bc_label *labels;
-
- /* List of label references in the function. */
- struct bc_labelref *labelrefs;
-
-
- /* Add symbol to pointer table. Return offset into table where
- pointer was stored. The offset usually goes into the bytecode
- stream as a constP literal. */
- int
- bc_define_pointer (p)
- char *p;
- {
- int offset = ptrconsts->size;
-
- seg_refsym (ptrconsts, p, 0);
- return offset;
- }
-
-
- /* Begin a bytecoded function. */
- int
- bc_begin_function (name)
- char *name;
- {
- ptrconsts = seg_create ();
- trampoline = seg_create ();
- bytecode = seg_create ();
- return seg_defsym (trampoline, name);
- }
-
-
- /* Force alignment in inline bytecode. */
- void
- bc_align_bytecode (align)
- int align;
- {
- seg_align (bytecode, align);
- }
-
-
- /* Emit data inline into bytecode. */
- void
- bc_emit_bytecode_const (data, size)
- char *data;
- unsigned int size;
- {
- if (bytecode)
- seg_data (bytecode, data, size);
- }
-
-
- /* Create a new "bytecode label", to have its value defined later.
- Bytecode labels have nothing to do with the object file symbol table,
- and are purely local to a given bytecoded function. */
- struct bc_label *
- bc_get_bytecode_label ()
- {
- struct bc_label *result;
-
- result = (struct bc_label *) xmalloc (sizeof (struct bc_label));
- result->defined = 0;
- result->next = labels;
- result->uid = 0;
- labels = result;
- return result;
- }
-
-
- /* Define the given label with the current location counter. */
- int
- bc_emit_bytecode_labeldef (label)
- struct bc_label *label;
- {
- extern int bc_new_uid ();
-
- if (!label || label->defined)
- return 0;
-
- label->offset = bytecode->size;
- label->defined = 1;
- label->uid = bc_new_uid ();
-
- #ifdef DEBUG_PRINT_CODE
- fprintf (stderr, "$%lx:\n", label);
- #endif
-
- return 1;
- }
-
-
- /* Generate a location-relative reference to the given bytecode label.
- It need not be defined yet; label references will be backpatched later. */
- void
- bc_emit_bytecode_labelref (label)
- struct bc_label *label;
- {
- struct bc_labelref *labelref;
- static int zero;
-
- labelref = (struct bc_labelref *) xmalloc (sizeof (struct bc_labelref));
- labelref->label = label;
- labelref->offset = bytecode->size;
- labelref->next = labelrefs;
- labelrefs = labelref;
-
- #ifdef DEBUG_PRINT_CODE
- fprintf (stderr, " $%lx", label);
- #endif
-
- seg_data (bytecode, (char *) &zero, sizeof zero);
- }
-
-
- /* Emit a reference to an external address; generate the reference in the
- ptrconst area, and emit an offset in the bytecode. */
- void
- bc_emit_code_labelref (name, offset)
- char *name;
- int offset;
- {
- int ptroff;
-
- ptroff = ptrconsts->size / sizeof (char *);
- seg_data (bytecode, (char *) &ptroff, sizeof ptroff);
- seg_refsym (ptrconsts, name, offset);
-
- #ifdef DEBUG_PRINT_CODE
- fprintf (stderr, " [external <%x> %s]", ptroff, name);
- #endif
- }
-
-
- /* Backpatch label references in the byte code, and concatenate the bytecode
- and pointer constant segments to the cumulative text for the object file.
- Return a label name for the pointer constants region. */
- char *
- bc_end_function ()
- {
- int addr;
- struct bc_label *label, *next;
- struct bc_labelref *ref, *nextref;
- char ptrconsts_label[20];
- static int nlab;
-
- /* Backpatch bytecode label references. */
- for (ref = labelrefs; ref; ref = ref->next)
- if (ref->label->defined)
- {
- addr = ref->label->offset;
- bcopy (&addr, bytecode->data + ref->offset, sizeof addr);
- }
-
- /* Free the chains of labelrefs and labeldefs. */
- for (ref = labelrefs; ref; ref = nextref)
- {
- nextref = ref->next;
- free ((char *) ref);
- }
-
- for (label = labels; label; label = next)
- {
- next = label->next;
- free ((char *) label);
- }
-
- seg_concat (trampoline, bytecode);
- seg_align (trampoline, MACHINE_SEG_ALIGN);
- sprintf (ptrconsts_label, "*LP%d", nlab++);
- seg_defsym (trampoline, ptrconsts_label);
- seg_concat (trampoline, ptrconsts);
- seg_concat (bc_text_seg, trampoline);
-
- labels = 0;
- labelrefs = 0;
- trampoline = 0;
- bytecode = 0;
- ptrconsts = 0;
-
- return sym_lookup (ptrconsts_label)->name;
- }
-
- /* Force alignment in const data. */
- void
- bc_align_const (align)
- int align;
- {
- seg_align (bc_text_seg, align);
- }
-
- /* Emit const data. */
- void
- bc_emit_const (data, size)
- char *data;
- unsigned int size;
- {
- seg_data (bc_text_seg, data, size);
- }
-
- /* Emit a zero-filled constant skip. */
- void
- bc_emit_const_skip (size)
- unsigned int size;
- {
- seg_skip (bc_text_seg, size);
- }
-
- /* Emit a label definition in const data. */
- int
- bc_emit_const_labeldef (name)
- char *name;
- {
- return seg_defsym (bc_text_seg, name);
- }
-
- /* Emit a label reference in const data. */
- void
- bc_emit_const_labelref (name, offset)
- char *name;
- int offset;
- {
- seg_refsym (bc_text_seg, name, offset);
- }
-
- /* Force alignment in data. */
- void
- bc_align_data (align)
- int align;
- {
- seg_align (bc_data_seg, align);
- }
-
- /* Emit data. */
- void
- bc_emit_data (data, size)
- char *data;
- unsigned int size;
- {
- seg_data (bc_data_seg, data, size);
- }
-
- /* Emit a zero-filled data skip. */
- void
- bc_emit_data_skip (size)
- unsigned int size;
- {
- seg_skip (bc_data_seg, size);
- }
-
- /* Emit label definition in data. */
- int
- bc_emit_data_labeldef (name)
- char *name;
- {
- return seg_defsym (bc_data_seg, name);
- }
-
- /* Emit label reference in data. */
- void
- bc_emit_data_labelref (name, offset)
- char *name;
- int offset;
- {
- seg_refsym (bc_data_seg, name, offset);
- }
-
- /* Emit a common block of the given name and size. Note that
- when the .o file is actually written non-global "common"
- blocks will have to be turned into space in the data section. */
- int
- bc_emit_common (name, size)
- char *name;
- unsigned int size;
- {
- struct bc_sym *sym;
-
- sym = sym_lookup (name);
- if (sym->defined)
- return 0;
-
- sym->defined = 1;
- sym->common = 1;
- sym->val = size;
- return 1;
- }
-
- /* Globalize the given label. */
- void
- bc_globalize_label (name)
- char *name;
- {
- struct bc_sym *sym;
-
- sym = sym_lookup (name);
- sym->global = 1;
- }
-
- static enum { in_text, in_data } section = in_text;
-
- void
- bc_text ()
- {
- section = in_text;
- }
-
- void
- bc_data ()
- {
- section = in_data;
- }
-
- void
- bc_align (align)
- int align;
- {
- if (section == in_text)
- bc_align_const (align);
- else
- bc_align_data (align);
- }
-
- void
- bc_emit (data, size)
- char *data;
- unsigned int size;
- {
- if (section == in_text)
- bc_emit_const (data, size);
- else
- bc_emit_data (data, size);
- }
-
- void
- bc_emit_skip (size)
- unsigned int size;
- {
- if (section == in_text)
- bc_emit_const_skip (size);
- else
- bc_emit_data_skip (size);
- }
-
- int
- bc_emit_labeldef (name)
- char *name;
- {
- if (section == in_text)
- return bc_emit_const_labeldef (name);
- else
- return bc_emit_data_labeldef (name);
- }
-
- void
- bc_emit_labelref (name, offset)
- char *name;
- int offset;
- {
- if (section == in_text)
- bc_emit_const_labelref (name, offset);
- else
- bc_emit_data_labelref (name, offset);
- }
-
- void
- bc_write_file (file)
- FILE *file;
- {
- BC_WRITE_FILE (file);
- }
-
-
- /* Allocate a new bytecode rtx.
- If you supply a null BC_LABEL, we generate one. */
-
- rtx
- bc_gen_rtx (label, offset, bc_label)
- char *label;
- int offset;
- struct bc_label *bc_label;
- {
- rtx r;
-
- if (bc_label == 0)
- bc_label = (struct bc_label *) xmalloc (sizeof (struct bc_label));
-
- r = gen_rtx (CODE_LABEL, VOIDmode, label, bc_label);
- bc_label->offset = offset;
-
- return r;
- }
-
-
- /* Print bytecode rtx */
- void
- bc_print_rtl (fp, r)
- FILE *fp;
- rtx r;
- {
- #if 0 /* This needs to get fixed to really work again. */
- /* BC_WRITE_RTL has a definition
- that doesn't even make sense for this use. */
- BC_WRITE_RTL (r, fp);
- #endif
- }
-
-
- /* Emit a bytecode, keeping a running tally of the stack depth. */
- void
- bc_emit_bytecode (bytecode)
- enum bytecode_opcode bytecode;
- {
- char byte;
- int npushes = arityvec[(int) bytecode].noutputs - arityvec[(int) bytecode].ninputs;
- static int prev_lineno = -1;
-
- byte = bytecode;
-
- #ifdef BCDEBUG_PRINT_CODE
- if (lineno != prev_lineno)
- {
- fprintf (stderr, "<line %d>\n", lineno);
- prev_lineno = lineno;
- }
-
- fputs (opcode_name[(unsigned int) bytecode], stderr);
- #endif
-
- /* Due to errors we are often requested to output bytecodes that
- will cause an interpreter stack undeflow when executed. Instead of
- dumping core on such occasions, we omit the bytecode. Erroneous code
- should not be executed, regardless. This makes life much easier, since
- we don't have to deceive ourselves about the known stack depth. */
-
- bc_emit_bytecode_const (&byte, 1);
-
- if ((stack_depth -= arityvec[(int) bytecode].ninputs) >= 0)
- {
- if ((stack_depth += arityvec[(int) bytecode].noutputs) > max_stack_depth)
- max_stack_depth = stack_depth;
- }
-
- #ifdef VALIDATE_STACK_FOR_BC
- VALIDATE_STACK_FOR_BC ();
- #endif
- }
-
-
- #ifdef BCDEBUG_PRINT_CODE
- #define PRLIT(TYPE, PTR) fprintf (stderr, " [%x]", *(TYPE *) PTR)
- #else
- #define PRLIT(X,Y)
- #endif
-
- /* Emit a complete bytecode instruction, expecting the correct number
- of literal values in the call. First argument is the instruction, the
- remaining arguments are literals of size HOST_WIDE_INT or smaller. */
- void
- bc_emit_instruction (va_alist)
- va_dcl
- {
- va_list arguments;
- enum bytecode_opcode opcode;
- int nliteral, instruction;
-
-
- va_start (arguments);
-
- /* Emit instruction bytecode */
- opcode = va_arg (arguments, enum bytecode_opcode);
- bc_emit_bytecode (opcode);
- instruction = (int) opcode;
-
- /* Loop literals and emit as bytecode constants */
- for (nliteral = 0; nliteral < arityvec[instruction].nliterals; nliteral++)
- {
- HOST_WIDE_INT literal;
-
- switch (arityvec[instruction].literals[nliteral])
- {
- /* This conditional is a kludge, but it's necessary
- because TYPE might be long long. */
- #ifdef __GNUC__
- /* Expand definitions into case statements */
- #define DEFTYPECODE(CODE, NAME, MODE, TYPE) \
- case CODE: \
- { \
- TYPE temp = va_arg (arguments, TYPE); \
- bc_emit_bytecode_const ((void *) &temp, sizeof temp); \
- PRLIT (TYPE, &temp); } \
- break;
-
- #include "bc-typecd.def"
-
- #undef DEFTYPECODE
- #endif /* __GNUC__ */
-
- default:
- abort ();
- }
- }
-
- #ifdef BCDEBUG_PRINT_CODE
- fputc ('\n', stderr);
- #endif
- }
-
- /* Emit the machine-code interface trampoline at the beginning of a byte
- coded function. The argument is a label name of the interpreter
- bytecode callinfo structure; the return value is a label name for
- the beginning of the actual bytecode. */
- char *
- bc_emit_trampoline (callinfo)
- char *callinfo;
- {
- char mylab[20];
- static int n;
-
- sprintf (mylab, "*LB%d", n++);
-
- BC_EMIT_TRAMPOLINE (trampoline, callinfo);
-
- seg_defsym (bytecode, mylab);
- return sym_lookup (mylab)->name;
- }
-
-
- /* Simple strdup */
- char *
- bc_xstrdup (str)
- char *str;
- {
- char *tmp = xmalloc (strlen (str) + 1);
-
- strcpy (tmp, str);
- return tmp;
- }
-