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

📄 jcf-write.c

📁 gcc-2.95.3 Linux下最常用的C编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Write out a Java(TM) class file.   Copyright (C) 1998, 1999 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING.  If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. Java and all Java-based marks are trademarks or registered trademarksof Sun Microsystems, Inc. in the United States and other countries.The Free Software Foundation is independent of Sun Microsystems, Inc.  */#include "config.h"#include "system.h"#include "jcf.h"#include "tree.h"#include "java-tree.h"#include "obstack.h"#undef AND#include "rtl.h"#include "flags.h"#include "java-opcodes.h"#include "parse.h" /* for BLOCK_EXPR_BODY */#include "buffer.h"#include "toplev.h"#ifndef DIR_SEPARATOR#define DIR_SEPARATOR '/'#endifextern struct obstack temporary_obstack;/* Base directory in which `.class' files should be written.   NULL means to put the file into the same directory as the   corresponding .java file.  */char *jcf_write_base_directory = NULL;/* Make sure bytecode.data is big enough for at least N more bytes. */#define RESERVE(N) \  do { CHECK_OP(state); \    if (state->bytecode.ptr + (N) > state->bytecode.limit) \    buffer_grow (&state->bytecode, N); } while (0)/* Add a 1-byte instruction/operand I to bytecode.data,   assuming space has already been RESERVE'd. */#define OP1(I) (*state->bytecode.ptr++ = (I), CHECK_OP(state))/* Like OP1, but I is a 2-byte big endian integer. */#define OP2(I) \  do { int _i = (I); OP1 (_i >> 8);  OP1 (_i); CHECK_OP(state); } while (0)/* Like OP1, but I is a 4-byte big endian integer. */#define OP4(I) \  do { int _i = (I);  OP1 (_i >> 24);  OP1 (_i >> 16); \       OP1 (_i >> 8); OP1 (_i); CHECK_OP(state); } while (0)/* Macro to call each time we push I words on the JVM stack. */#define NOTE_PUSH(I) \  do { state->code_SP += (I); \    if (state->code_SP > state->code_SP_max) \      state->code_SP_max = state->code_SP; } while (0)/* Macro to call each time we pop I words from the JVM stack. */#define NOTE_POP(I) \  do { state->code_SP -= (I); if (state->code_SP < 0) abort(); } while (0)/* A chunk or segment of a .class file. */struct chunk{  /* The next segment of this .class file. */  struct chunk *next;  /* The actual data in this segment to be written to the .class file. */  unsigned char *data;  /* The size of the segment to be written to the .class file. */  int size;};#define PENDING_CLEANUP_PC (-3)#define PENDING_EXIT_PC (-2)#define UNDEFINED_PC (-1)/* Each "block" represents a label plus the bytecode instructions following.   There may be branches out of the block, but no incoming jumps, except   to the beginning of the block.   If (pc < 0), the jcf_block is not an actual block (i.e. it has no   assocated code yet), but it is an undefined label.*/struct jcf_block{  /* For blocks that that are defined, the next block (in pc order).     For blocks that are the not-yet-defined end label of a LABELED_BLOCK_EXPR     or a cleanup expression (from a WITH_CLEANUP_EXPR),     this is the next (outer) such end label, in a stack headed by     labeled_blocks in jcf_partial. */  struct jcf_block *next;  /* In the not-yet-defined end label for an unfinished EXIT_BLOCK_EXPR.     pc is PENDING_EXIT_PC.     In the not-yet-defined end label for pending cleanup subroutine,     pc is PENDING_CLEANUP_PC.     For other not-yet-defined labels, pc is UNDEFINED_PC.     If the label has been defined:     Until perform_relocations is finished, this is the maximum possible     value of the bytecode offset at the begnning of this block.     After perform_relocations, it is the actual offset (pc). */  int pc;  int linenumber;  /* After finish_jcf_block is called, The actual instructions contained in this block.     Before than NULL, and the instructions are in state->bytecode. */  union {    struct chunk *chunk;    /* If pc==PENDING_CLEANUP_PC, start_label is the start of the region       coveed by the cleanup. */    struct jcf_block *start_label;  } v;  union {    /* Set of relocations (in reverse offset order) for this block. */    struct jcf_relocation *relocations;    /* If this block is that of the not-yet-defined end label of       a LABELED_BLOCK_EXPR, where LABELED_BLOCK is that LABELED_BLOCK_EXPR.       If pc==PENDING_CLEANUP_PC, the cleanup that needs to be run. */    tree labeled_block;  } u;};/* A "relocation" type for the 0-3 bytes of padding at the start   of a tableswitch or a lookupswitch. */#define SWITCH_ALIGN_RELOC 4/* A relocation type for the labels in a tableswitch or a lookupswitch;   these are relative to the start of the instruction, but (due to   th 0-3 bytes of padding), we don't know the offset before relocation. */#define BLOCK_START_RELOC 1struct jcf_relocation{  /* Next relocation for the current jcf_block. */  struct jcf_relocation *next;  /* The (byte) offset within the current block that needs to be relocated. */  HOST_WIDE_INT offset;  /* 0 if offset is a 4-byte relative offset.     4 (SWITCH_ALIGN_RELOC) if offset points to 0-3 padding bytes inserted     for proper alignment in tableswitch/lookupswitch instructions.     1 (BLOCK_START_RELOC) if offset points to a 4-byte offset relative     to the start of the containing block.     -1 if offset is a 2-byte relative offset.     < -1 if offset is the address of an instruction with a 2-byte offset     that does not have a corresponding 4-byte offset version, in which     case the absolute value of kind is the inverted opcode.     > 4 if offset is the address of an instruction (such as jsr) with a     2-byte offset that does have a corresponding 4-byte offset version,     in which case kind is the opcode of the 4-byte version (such as jsr_w). */  int kind;  /* The label the relocation wants to actually transfer to. */  struct jcf_block *label;};/* State for single catch clause. */struct jcf_handler{  struct jcf_handler *next;  struct jcf_block *start_label;  struct jcf_block *end_label;  struct jcf_block *handler_label;  /* The sub-class of Throwable handled, or NULL_TREE (for finally). */  tree type;};/* State for the current switch statement. */struct jcf_switch_state{  struct jcf_switch_state *prev;  struct jcf_block *default_label;  struct jcf_relocation *cases;  int num_cases;  HOST_WIDE_INT min_case, max_case;};/* This structure is used to contain the various pieces that will   become a .class file. */struct jcf_partial{  struct chunk *first;  struct chunk *chunk;  struct obstack *chunk_obstack;  tree current_method;  /* List of basic blocks for the current method. */  struct jcf_block *blocks;  struct jcf_block *last_block;  struct localvar_info *first_lvar;  struct localvar_info *last_lvar;  int lvar_count;  CPool cpool;  int linenumber_count;  /* Until perform_relocations, this is a upper bound on the number     of bytes (so far) in the instructions for the current method. */  int code_length;  /* Stack of undefined ending labels for LABELED_BLOCK_EXPR. */  struct jcf_block *labeled_blocks;    /* The current stack size (stack pointer) in the current method. */  int code_SP;  /* The largest extent of stack size (stack pointer) in the current method. */  int code_SP_max;  /* Contains a mapping from local var slot number to localvar_info. */  struct buffer localvars;  /* The buffer allocated for bytecode for the current jcf_block. */  struct buffer bytecode;  /* Chain of exception handlers for the current method. */  struct jcf_handler *handlers;  /* Last element in handlers chain. */  struct jcf_handler *last_handler;  /* Number of exception handlers for the current method. */  int num_handlers;  /* Number of finalizers we are currently nested within. */  int num_finalizers;  /* If non-NULL, use this for the return value. */  tree return_value_decl;  /* Information about the current switch statemenet. */  struct jcf_switch_state *sw_state;};static void generate_bytecode_insns PROTO ((tree, int, struct jcf_partial *));static struct chunk * alloc_chunk PROTO ((struct chunk *, unsigned char *,					  int, struct obstack *));static unsigned char * append_chunk PROTO ((unsigned char *, int,					    struct jcf_partial *));static void append_chunk_copy PROTO ((unsigned char *, int,				      struct jcf_partial *));static struct jcf_block * gen_jcf_label PROTO ((struct jcf_partial *));static void finish_jcf_block PROTO ((struct jcf_partial *));static void define_jcf_label PROTO ((struct jcf_block *,				     struct jcf_partial *));static struct jcf_block * get_jcf_label_here PROTO ((struct jcf_partial *));static void put_linenumber PROTO ((int, struct jcf_partial *));static void localvar_alloc PROTO ((tree, struct jcf_partial *));static int localvar_free PROTO ((tree, struct jcf_partial *));static int get_access_flags PROTO ((tree));static void write_chunks PROTO ((FILE *, struct chunk *));static int adjust_typed_op PROTO ((tree, int));static void generate_bytecode_conditional PROTO ((tree, struct jcf_block *,						  struct jcf_block *, int,						  struct jcf_partial *));static void generate_bytecode_return PROTO ((tree, struct jcf_partial *));static void perform_relocations PROTO ((struct jcf_partial *));static void init_jcf_state PROTO ((struct jcf_partial *, struct obstack *));static void init_jcf_method PROTO ((struct jcf_partial *, tree));static void release_jcf_state PROTO ((struct jcf_partial *));static struct chunk * generate_classfile PROTO ((tree, struct jcf_partial *));/* Utility macros for appending (big-endian) data to a buffer.   We assume a local variable 'ptr' points into where we want to   write next, and we assume enoygh space has been allocated. */#ifdef ENABLE_CHECKINGintCHECK_PUT(ptr, state, i)     void *ptr;     struct jcf_partial *state;     int i;{  if (ptr < state->chunk->data      || (char*)ptr + i > state->chunk->data + state->chunk->size)    fatal ("internal error - CHECK_PUT failed");  return 0;}#else#define CHECK_PUT(PTR, STATE, I) ((void)0)#endif#define PUT1(X)  (CHECK_PUT(ptr, state, 1), *ptr++ = (X))#define PUT2(X)  (PUT1((X) >> 8), PUT1((X) & 0xFF))#define PUT4(X)  (PUT2((X) >> 16), PUT2((X) & 0xFFFF))#define PUTN(P, N)  (CHECK_PUT(ptr, state, N), memcpy(ptr, P, N), ptr += (N))/* Allocate a new chunk on obstack WORK, and link it in after LAST.   Set the data and size fields to DATA and SIZE, respectively.   However, if DATA is NULL and SIZE>0, allocate a buffer as well. */static struct chunk *alloc_chunk (last, data, size, work)     struct chunk *last;     unsigned char *data;     int size;     struct obstack *work;{  struct chunk *chunk = (struct chunk *)    obstack_alloc (work, sizeof(struct chunk));  if (data == NULL && size > 0)    data = obstack_alloc (work, size);  chunk->next = NULL;  chunk->data = data;  chunk->size = size;  if (last != NULL)    last->next = chunk;  return chunk;}#ifdef ENABLE_CHECKINGintCHECK_OP(struct jcf_partial *state){  if (state->bytecode.ptr > state->bytecode.limit)    {      fatal("internal error - CHECK_OP failed");    }  return 0;}#else#define CHECK_OP(STATE) ((void)0)#endifstatic unsigned char *append_chunk (data, size, state)     unsigned char *data;     int size;     struct jcf_partial *state;{  state->chunk = alloc_chunk (state->chunk, data, size, state->chunk_obstack);  if (state->first == NULL)    state->first = state->chunk;  return state->chunk->data;}static voidappend_chunk_copy (data, size, state)     unsigned char *data;     int size;     struct jcf_partial *state;{  unsigned char *ptr = append_chunk (NULL, size, state);  memcpy (ptr, data, size);}static struct jcf_block *gen_jcf_label (state)     struct jcf_partial *state;{  struct jcf_block *block = (struct jcf_block *)    obstack_alloc (state->chunk_obstack, sizeof (struct jcf_block));  block->next =	NULL;  block->linenumber = -1;  block->pc = UNDEFINED_PC;  return block;}static voidfinish_jcf_block (state)     struct jcf_partial *state;{  struct jcf_block *block = state->last_block;  struct jcf_relocation *reloc;  int code_length = BUFFER_LENGTH (&state->bytecode);  int pc = state->code_length;  append_chunk_copy (state->bytecode.data, code_length, state);  BUFFER_RESET (&state->bytecode);  block->v.chunk = state->chunk;  /* Calculate code_length to the maximum value it can have. */  pc += block->v.chunk->size;  for (reloc = block->u.relocations;  reloc != NULL;  reloc = reloc->next)    {      int kind = reloc->kind;      if (kind == SWITCH_ALIGN_RELOC)	pc += 3;      else if (kind > BLOCK_START_RELOC)	pc += 2; /* 2-byte offset may grow to 4-byte offset */      else if (kind < -1)	pc += 5; /* May need to add a goto_w. */    }  state->code_length = pc;}static voiddefine_jcf_label (label, state)     struct jcf_block *label;     struct jcf_partial *state;{  if (state->last_block != NULL)    finish_jcf_block (state);  label->pc = state->code_length;  if (state->blocks == NULL)    state->blocks = label;  else    state->last_block->next = label;  state->last_block = label;  label->next = NULL;  label->u.relocations = NULL;}static struct jcf_block *get_jcf_label_here (state)     struct jcf_partial *state;{  if (state->last_block != NULL && BUFFER_LENGTH (&state->bytecode) == 0)    return state->last_block;  else    {

⌨️ 快捷键说明

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