📄 bc-emit.c
字号:
/* Emit data inline into bytecode. */voidbc_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. */intbc_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. */voidbc_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. */voidbc_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 ((char *) &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. */voidbc_align_const (align) int align;{ seg_align (bc_text_seg, align);}/* Emit const data. */voidbc_emit_const (data, size) char *data; unsigned int size;{ seg_data (bc_text_seg, data, size);}/* Emit a zero-filled constant skip. */voidbc_emit_const_skip (size) unsigned int size;{ seg_skip (bc_text_seg, size);}/* Emit a label definition in const data. */intbc_emit_const_labeldef (name) char *name;{ return seg_defsym (bc_text_seg, name);}/* Emit a label reference in const data. */voidbc_emit_const_labelref (name, offset) char *name; int offset;{ seg_refsym (bc_text_seg, name, offset);}/* Force alignment in data. */voidbc_align_data (align) int align;{ seg_align (bc_data_seg, align);}/* Emit data. */voidbc_emit_data (data, size) char *data; unsigned int size;{ seg_data (bc_data_seg, data, size);}/* Emit a zero-filled data skip. */voidbc_emit_data_skip (size) unsigned int size;{ seg_skip (bc_data_seg, size);}/* Emit label definition in data. */intbc_emit_data_labeldef (name) char *name;{ return seg_defsym (bc_data_seg, name);}/* Emit label reference in data. */voidbc_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. */intbc_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. */voidbc_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;voidbc_text (){ section = in_text;}voidbc_data (){ section = in_data;}voidbc_align (align) int align;{ if (section == in_text) bc_align_const (align); else bc_align_data (align);}voidbc_emit (data, size) char *data; unsigned int size;{ if (section == in_text) bc_emit_const (data, size); else bc_emit_data (data, size);}voidbc_emit_skip (size) unsigned int size;{ if (section == in_text) bc_emit_const_skip (size); else bc_emit_data_skip (size);}intbc_emit_labeldef (name) char *name;{ if (section == in_text) return bc_emit_const_labeldef (name); else return bc_emit_data_labeldef (name);}voidbc_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);}voidbc_write_file (file) FILE *file;{ BC_WRITE_FILE (file);}/* Allocate a new bytecode rtx. If you supply a null BC_LABEL, we generate one. */rtxbc_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 */voidbc_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. */voidbc_emit_bytecode (bytecode) enum bytecode_opcode bytecode;{ char byte; static int prev_lineno = -1; byte = (char) 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. */voidbc_emit_instruction VPROTO((enum bytecode_opcode opcode, ...)){#ifndef __STDC__ enum bytecode_opcode opcode;#endif va_list arguments; int nliteral, instruction; VA_START (arguments, opcode);#ifndef __STDC__ opcode = va_arg (arguments, enum bytecode_opcode);#endif /* Emit instruction bytecode */ bc_emit_bytecode (opcode); instruction = (int) opcode; /* Loop literals and emit as bytecode constants */ for (nliteral = 0; nliteral < arityvec[instruction].nliterals; nliteral++) { 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 (); } } va_end (arguments);#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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -