⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 codegen.c

📁 idel虚拟机源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Internal code generator. * Copyright (C) 2001-2002 Darius Bacon * * Read an object file and generate the internal form of threaded code * implementing it. */#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "idel_private.h"/* Equivalent to die() but more pertinent to object-file parsing.  */static voidbad_input (const char *message, ...){  va_list args;  fprintf (stderr, "%s: Bad object file: ", program_name);  va_start(args, message);  vfprintf(stderr, message, args);  va_end(args);  fprintf(stderr, "\n");  exit (128);}/* Like bad_input() but giving the current defn #. */static voidbad_defn (const VM *vm, const char *message, ...){  va_list args;  fprintf (stderr, "%s: Bad object file in defn #%d: ", 	   program_name, vm->defn_number);  va_start(args, message);  vfprintf(stderr, message, args);  va_end(args);  fprintf(stderr, "\n");  exit (128);}/* Return a new vm with codegen-private fields initialized. */VM *vm_make (int stack_size, int data_size, int profiling){  VM *vm = vm_sort_of_make (stack_size, data_size);  assert (false == profiling || true == profiling);  vm->profiling = profiling;  vm->tallies_size = 0;  vm->num_tallies = 0;  vm->tallies = NULL;  vm->ns_size = stack_size;  vm->nesting = allot (stack_size * sizeof vm->nesting[0]);  vm->nsp = vm->nesting;  vm->height = vm->locals = vm->max_width = 0;  vm->returning = 0;  vm->at_jump_target = false;  vm->bb_end = NULL;  vm->defn_number = 0;  vm->block_start = vm->block_end = 0;  vm->entries_size = 256;  vm->entries = allot (vm->entries_size * sizeof vm->entries[0]);  vm->there = vm->chunks[0] + chunk_size;  vm->data_ptr = 0;  if (paranoid) vm_check (vm);  return vm;}/* Add a new tally entry with a 0 count for the [start..end] code block.   Return the index of the tally counter. */static intadd_tally (VM *vm, int defn, i32 *start, i32 *end){  int i = vm->num_tallies++;  if (i == vm->tallies_size)    {      if (0 == i)	{	  vm->tallies_size = 1;	  vm->tallies = allot (sizeof vm->tallies[0]);	}      else	{	  vm->tallies_size *= 2;	  vm->tallies = 	    reallot (vm->tallies, vm->tallies_size * sizeof vm->tallies[0]);	}    }  vm->tallies[i].count = 0;  vm->tallies[i].defn = defn;  vm->tallies[i].start = start;  vm->tallies[i].end = end;  return i;}/* Write vm's profile data to `out'. */voidvm_dump_profile (VM *vm, FILE *out){  int i;  for (i = 0; i < vm->num_tallies; ++i)    {      const Tally *t = &vm->tallies[i];      const i32 *p = t->start;      fprintf (out, "%10lu %3d", t->count, t->defn);      while (p != t->end)	{	  int opcode = lookup_op (*p);	  int operands = operand_count (opcode);	  assert (0 <= opcode && 0 <= operands);	  fprintf (out, " %s", format_opcode (opcode));	  p += 1 + operands;	}      fprintf (out, "\n");    }}/* Code emission *//* Ensure that vm's data space can hold at least one word at its data_ptr. */static voidensure_data_space (VM *vm){  if (vm->data_size <= vm->data_ptr)    bad_input ("Out of data space");}/* Append b to vm's data space. */static voidemit_data_byte (VM *vm, i8 b){  ensure_data_space (vm);  vm->data[endianness ^ vm->data_ptr] = b;  vm->data_ptr += 1;}/* Append i to vm's data space. */static voidemit_data_int (VM *vm, i32 i){  vm->data_ptr = word_align (vm->data_ptr);  ensure_data_space (vm);  *(i32 *)(vm->data + vm->data_ptr) = i;  vm->data_ptr += word_size;}/* Move vm's new-code pointer into a freshly allocated chunk, leaving   a JUMP to the former new-code location. */static voidmove_to_new_chunk (VM *vm){  if (paranoid) vm_check (vm);  /* Fill current chunk's unused space, just to make debugging easier */  {    i32 *p = vm->there - 1;    for (; vm->chunks[vm->num_chunks - 1] <= p; --p)      *p = -1;			/* garbage value */  }  /* Add another chunk to the chunks array */  if (vm->num_chunks == vm->chunks_size)    {      vm->chunks_size *= 2;      vm->chunks = reallot (vm->chunks, vm->chunks_size * sizeof vm->chunks[0]);    }  vm->chunks[vm->num_chunks] =     allot (chunk_size * sizeof vm->chunks[0][0]);  /* Set the code allocation pointer and emit a jump to where we left off */  {				    i32 *continue_point = vm->there;    vm->there = vm->chunks[vm->num_chunks] + chunk_size - 2;    vm->there[0] = (i32) opcode_labels[JUMP];    vm->there[1] = (i32) (continue_point);  }  vm->num_chunks++;  if (paranoid) vm_check (vm);}/* Ensure that vm's current chunk has space for an n-operand instruction.   Pre: 0 <= n < chunk_size */static voidreserve (VM *vm, int n){  if (vm->there <= vm->chunks[vm->num_chunks - 1] + n)    move_to_new_chunk (vm);}/* Prepend w to vm's code space. */static void emit_lit (VM *vm, i32 w){  reserve (vm, 0);  *--vm->there = w;}/* Pre: vm's current chunk has space for a 0-operand instruction.   Prepend a no-operand instruction to vm's code space. */static void really_emit (VM *vm, int opcode){  int combined_opcode = -1;  if (!vm->at_jump_target)    switch (opcode)      {#include "peep.inc"      }  if (0 <= combined_opcode)    vm->there[0] = (i32) opcode_labels[combined_opcode];  else    {      *--vm->there = (i32) opcode_labels[opcode];      vm->at_jump_target = false;    }}/* Pre: vm's current chunk has space for a 1-operand instruction.   Prepend a 1-operand instruction to vm's code space. */static voidreally_emit1 (VM *vm, int opcode, i32 operand){  int combined_opcode = -1;  if (!vm->at_jump_target)    switch (opcode)      {#include "peep1.inc"      }  if (0 <= combined_opcode)    {      vm->there[-1] = (i32) opcode_labels[combined_opcode];      vm->there[0] = operand;      vm->there -= 1;    }  else    {      vm->there[-2] = (i32) opcode_labels[opcode];      vm->there[-1] = operand;      vm->there -= 2;      vm->at_jump_target = false;    }}/* Prepend a no-operand instruction to vm's code space. */static void emit (VM *vm, int opcode){  reserve (vm, 0);  really_emit (vm, opcode);}/* Prepend a 1-operand instruction to vm's code space. */static voidemit1 (VM *vm, int opcode, i32 operand){  reserve (vm, 1);  really_emit1 (vm, opcode, operand);}/* Code generation */typedef struct Insn {  u8 opcode;  i32 operand;} Insn;/* Set up to generate a block of n defns. */static voidstart_defns (VM *vm, u32 n){  int i;  if (paranoid) vm_check (vm);  vm->block_start = vm->defn_number;  vm->block_end = vm->defn_number + n;  if (vm->entries_size < vm->block_end)    {      do {	vm->entries_size *= 2;      } while (vm->entries_size < vm->block_end);      vm->entries = reallot (vm->entries, 			     vm->entries_size * sizeof vm->entries[0]);    }  for (i = vm->block_start; i < vm->block_end; ++i)    {      vm->entries[i].address = NULL;      vm->entries[i].refs = NULL;    }  if (paranoid) vm_check (vm);}/* Finish generating the current defns block. */static voidfinish_defns (VM *vm){  if (paranoid)    {      /* Check that all references were resolved. */      int i;      for (i = vm->block_start; i < vm->block_end; ++i)	assert (vm->entries[i].address != NULL);      vm_check (vm);    }}/* Return the entry for defn #`defn'. */static Entry *defn_entry (const VM *vm, int defn){  if ((unsigned) vm->block_end <= (unsigned) defn)    bad_defn (vm, "Reference out of range");  return vm->entries + defn;}/* Pre: where != NULL   Record that the code for `defn' starts at `where'. */static voidresolve (VM *vm, int defn, i32 *where){  Entry *entry = defn_entry (vm, defn);  assert (where != NULL);  assert (entry->address == NULL);  {    Unresolved *u = entry->refs;    while (u != NULL)      {	Unresolved *v = u->next;	u->ref[0] = (i32) where;	free (u);	u = v;      }    entry->refs = NULL;  }  entry->address = where;}/* Pre: ref != NULL   Record that the code word at `ref' should hold the starting address of    the defn that `entry' denotes.   Return that address if known, else NULL. */static const i32 *reference (Entry *entry, i32 *ref){  if (entry->address == NULL)    {      Unresolved *u = allot (sizeof *u);      u->ref = ref;      u->next = entry->refs;      entry->refs = u;    }  return entry->address;}/* Pre: opcode is CALL or TAILCALL.   Emit a call to the defn that `entry' denotes. */static i32 *emit_call (VM *vm, int opcode, Entry *entry){  reserve (vm, 1);  {    i32 *after = vm->there;    really_emit1 (vm, opcode, (i32) reference (entry, after - 1));    return after;  }}/* Emit a branch to `target'. */static voidemit_branch (VM *vm, i32 *target){  reserve (vm, 1);  {    int d = target - vm->there;    if (2 <= d && d <= 9)      really_emit (vm, BRANCH2 + d-2);    else      really_emit1 (vm, BRANCH, (i32) target);  }}/* Emit a 1-operand instruction, possibly using a version of the   instruction customized to the particular operand value (if the   operand's in the range [lo..hi]). */static voidemit_immediate (VM *vm, int opcode, i32 operand,		int custom_base_opcode, i32 lo, i32 hi){  if (lo <= operand && operand <= hi)    emit (vm, custom_base_opcode + operand - lo);  else    emit1 (vm, opcode, operand);}static voidemit_drop (VM *vm, int count){  emit_immediate (vm, DROP, count, DROP1, 1, 4);}/* Restore the validity of max_width after a change to height or locals   that might have increased it. */static voidupdate_width (VM *vm){  if (vm->height + vm->locals > vm->max_width)    vm->max_width = vm->height + vm->locals;}/* Update the static stack height for an instruction with `using' inputs   off the stack and `delta' overall change in stack height.  (The old   stack state holds for *after* the instruction executes, and the new   state for *before* it.) */static voidupdate_stack (VM *vm, int using, int delta){  vm->height -= delta;  if (vm->height < using)    bad_defn (vm, "Inaccurate stack effect declaration (more results "	       "are yielded than declared)");}/* Update the static locals depth for an instruction that changes it by   `delta'.  (Used the same way as update_stack.  We don't need a `using'   parameter because underflow can't happen.) */static voidupdate_locals (VM *vm, int delta){  vm->locals -= delta;}/* Record that `code' is an address that may go on the return stack,   with `popping' as the number of stack elements the callee pops off.   Pre: This must be done right after the responsible instruction is   compiled, so the static stack state will be right.  (Ugh...) */static voidnote_frame_map (VM *vm, i32 *code, unsigned popping){  if (vm->num_fms == vm->fm_size)    {      vm->fm_size *= 2;      vm->fm = reallot (vm->fm, vm->fm_size * sizeof vm->fm[0]);    }  {    Frame_map *m = vm->fm + vm->num_fms++;    m->code = code;    m->height = vm->height - popping;    m->locals = vm->locals;  }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -