/* src/vm/jit/parse.c - parser for JavaVM to intermediate code translation

   Copyright (C) 1996-2005, 2006, 2007, 2008
   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO

   This file is part of CACAO.

   This program 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.

   This program 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 this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301, USA.

*/


#include "config.h"

#include <assert.h>
#include <string.h>

#include "vm/types.h"

#include "mm/memory.h"

#include "native/native.h"

#include "threads/lock-common.h"

#include "toolbox/logging.h"

#include "vm/builtin.h"
#include "vm/exceptions.h"
#include "vm/global.h"
#include "vm/stringlocal.h"

#include "vm/jit/asmpart.h"
#include "vm/jit/jit.h"
#include "vm/jit/parse.h"
#include "vm/jit/loop/loop.h"

#include "vm/jit/ir/bytecode.h"

#include "vmcore/linker.h"
#include "vmcore/loader.h"
#include "vmcore/options.h"
#include "vm/resolve.h"

#if defined(ENABLE_STATISTICS)
# include "vmcore/statistics.h"
#endif

#include "vmcore/suck.h"

#define INSTRUCTIONS_INCREMENT  5  /* number of additional instructions to    */
                                   /* allocate if space runs out              */


/* local macros ***************************************************************/

#define BYTECODEINDEX_TO_BASICBLOCK(dst) \
    do { \
        (dst).block = \
            parse_bytecodeindex_to_basicblock(jd, &pd, (dst).insindex); \
    } while (0)


/* parserdata_t ***************************************************************/

typedef struct parsedata_t parsedata_t;

struct parsedata_t {
	u1          *bytecodestart;         /* start of bytecode instructions     */
	u1          *basicblockstart;       /* start of bytecode basic-blocks     */

	s4          *bytecodemap;           /* bytecode to IR mapping             */
	
	instruction *instructions;          /* instruction array                  */
	s4           instructionslength;    /* length of the instruction array    */

	s4          *instructionmap;        /* IR to basic-block mapping          */
};


/* parse_setup *****************************************************************

   Fills the passed parsedata_t structure.

*******************************************************************************/

static void parse_setup(jitdata *jd, parsedata_t *pd)
{
	methodinfo *m;

	/* get required compiler data */

	m = jd->m;

	/* bytecode start array */

	pd->bytecodestart = DMNEW(u1, m->jcodelength + 1);
	MZERO(pd->bytecodestart, u1, m->jcodelength + 1);

	/* bytecode basic-block start array */

	pd->basicblockstart = DMNEW(u1, m->jcodelength + 1);
	MZERO(pd->basicblockstart, u1, m->jcodelength + 1);

	/* bytecode instruction index to IR instruction mapping */

	pd->bytecodemap = DMNEW(s4, m->jcodelength + 1);
	MSET(pd->bytecodemap, -1, s4, m->jcodelength + 1);

	/* allocate the instruction array */

	pd->instructionslength = m->jcodelength + 1;
	pd->instructions = DMNEW(instruction, pd->instructionslength);

	/* Zero the intermediate instructions array so we don't have any
	   invalid pointers in it if we cannot finish stack_analyse(). */

	MZERO(pd->instructions, instruction, pd->instructionslength);

	/* The instructionmap is allocated later when we know the count of
	   instructions. */

	pd->instructionmap = NULL;
}


/* parse_realloc_instructions **************************************************

   Reallocate the instructions array so there is room for at least N 
   additional instructions.

   RETURN VALUE:
       the new value for iptr

*******************************************************************************/

static instruction *parse_realloc_instructions(parsedata_t *pd, s4 icount, s4 n)
{
	/* increase the size of the instruction array */

	pd->instructionslength += (n + INSTRUCTIONS_INCREMENT);

	/* reallocate the array */

	pd->instructions = DMREALLOC(pd->instructions, instruction, icount,
								 pd->instructionslength);
	MZERO(pd->instructions + icount, instruction,
		  (pd->instructionslength - icount));

	/* return the iptr */

	return pd->instructions + icount;
}


/* parse_bytecodeindex_to_basicblock *******************************************

   Resolves a bytecode index to the corresponding basic block.

*******************************************************************************/

static basicblock *parse_bytecodeindex_to_basicblock(jitdata *jd,
													 parsedata_t *pd,
													 s4 bcindex)
{
	s4          irindex;
	basicblock *bb;

	irindex = pd->bytecodemap[bcindex];
	bb      = jd->basicblocks + pd->instructionmap[irindex];

	return bb;
}


/* parse_mark_exception_boundaries *********************************************

   Mark exception handlers and the boundaries of the handled regions as
   basic block boundaries.

   IN:
       jd...............current jitdata

   RETURN VALUE:
       true.............everything ok
	   false............an exception has been thrown

*******************************************************************************/

static bool parse_mark_exception_boundaries(jitdata *jd, parsedata_t *pd)
{
	s4                   bcindex;
	s4                   i;
	s4                   len;
	raw_exception_entry *rex;
	methodinfo          *m;

	m = jd->m;
	
	len = m->rawexceptiontablelength;

	if (len == 0)
		return true;

	rex = m->rawexceptiontable;

	for (i = 0; i < len; ++i, ++rex) {

		/* the start of the handled region becomes a basic block start */

   		bcindex = rex->startpc;
		CHECK_BYTECODE_INDEX(bcindex);
		MARK_BASICBLOCK(pd, bcindex);
		
		bcindex = rex->endpc; /* see JVM Spec 4.7.3 */
		CHECK_BYTECODE_INDEX_EXCLUSIVE(bcindex);

		/* check that the range is valid */

#if defined(ENABLE_VERIFIER)
		if (bcindex <= rex->startpc) {
			exceptions_throw_verifyerror(m, "Invalid exception handler range");
			return false;
		}
#endif
		
		/* End of handled region becomes a basic block boundary (if it
		   is the bytecode end, we'll use the special end block that
		   is created anyway). */

		if (bcindex < m->jcodelength)
			MARK_BASICBLOCK(pd, bcindex);
		else
			jd->branchtoend = true;

		/* the start of the handler becomes a basic block start  */

		bcindex = rex->handlerpc;
		CHECK_BYTECODE_INDEX(bcindex);
		MARK_BASICBLOCK(pd, bcindex);
	}

	/* everything ok */

	return true;

#if defined(ENABLE_VERIFIER)
throw_invalid_bytecode_index:
	exceptions_throw_verifyerror(m,
								 "Illegal bytecode index in exception table");
	return false;
#endif
}


/* parse_resolve_exception_table ***********************************************

   Enter the exception handlers and their ranges, resolved to basicblock *s,
   in the jitdata.

   IN:
       jd...............current jitdata

   RETURN VALUE:
	   true.............everything ok
	   false............an exception has been thrown

*******************************************************************************/

static bool parse_resolve_exception_table(jitdata *jd, parsedata_t *pd)
{
	methodinfo          *m;
	raw_exception_entry *rex;
	exception_entry     *ex;
	s4                   i;
	s4                   len;
	classinfo           *exclass;

	m = jd->m;

	len = m->rawexceptiontablelength;

	/* common case: no handler entries */

	if (len == 0)
		return true;

	/* allocate the exception table */

	jd->exceptiontablelength = len;
	jd->exceptiontable = DMNEW(exception_entry, len + 1); /* XXX why +1? */

	/* copy and resolve the entries */

	ex = jd->exceptiontable;
	rex = m->rawexceptiontable;

	for (i = 0; i < len; ++i, ++rex, ++ex) {
		/* resolve instruction indices to basic blocks */

		ex->start   = parse_bytecodeindex_to_basicblock(jd, pd, rex->startpc);
		ex->end     = parse_bytecodeindex_to_basicblock(jd, pd, rex->endpc);
		ex->handler = parse_bytecodeindex_to_basicblock(jd, pd, rex->handlerpc);

		/* lazily resolve the catchtype */

		if (rex->catchtype.any != NULL) {
			if (!resolve_classref_or_classinfo(m,
											   rex->catchtype,
											   resolveLazy, true, false,
											   &exclass))
				return false;

			/* if resolved, enter the result of resolution in the table */

			if (exclass != NULL)
				rex->catchtype.cls = exclass;
		}

		ex->catchtype = rex->catchtype;
		ex->next = NULL;   /* set by loop analysis */
		ex->down = ex + 1; /* link to next exception entry */
	}

	/* terminate the ->down linked list */

	assert(ex != jd->exceptiontable);
	ex[-1].down = NULL;

	return true;
}


/*******************************************************************************

	function 'parse' scans the JavaVM code and generates intermediate code

	During parsing the block index table is used to store at bit pos 0
	a flag which marks basic block starts and at position 1 to 31 the
	intermediate instruction index. After parsing the block index table
	is scanned, for marked positions a block is generated and the block
	number is stored in the block index table.

*******************************************************************************/

/*** macro for checking the length of the bytecode ***/

#if defined(ENABLE_VERIFIER)
#define CHECK_END_OF_BYTECODE(neededlength) \
	do { \
		if ((neededlength) > m->jcodelength) \
			goto throw_unexpected_end_of_bytecode; \
	} while (0)
#else /* !ENABLE_VERIFIER */
#define CHECK_END_OF_BYTECODE(neededlength)
#endif /* ENABLE_VERIFIER */

bool parse(jitdata *jd)
{
	methodinfo  *m;                     /* method being parsed                */
	codeinfo    *code;
	parsedata_t  pd;
	instruction *iptr;                  /* current ptr into instruction array */

	s4           bcindex;               /* bytecode instruction index         */
	s4           nextbc;                /* start of next bytecode instruction */
	s4           opcode;                /* bytecode instruction opcode        */

	s4           irindex;               /* IR instruction index               */
	s4           ircount;               /* IR instruction count               */

	s4           bbcount;               /* basic block count                  */

	int  s_count = 0;             /* stack element counter                    */
	bool blockend;                /* true if basic block end has been reached */
	bool iswide;                  /* true if last instruction was a wide      */

	constant_classref  *cr;
	constant_classref  *compr;
	classinfo          *c;
	builtintable_entry *bte;
	constant_FMIref    *fmi;
	methoddesc         *md;
	unresolved_method  *um;
	unresolved_field   *uf;

	resolve_result_t    result;
	u2                  lineindex = 0;
	u2                  currentline = 0;
	u2                  linepcchange = 0;
	u4                  flags;
	basicblock         *bptr;

 	int                *local_map; /* local pointer to renaming map           */
	                               /* is assigned to rd->local_map at the end */
	branch_target_t *table;
	lookup_target_t *lookup;
	s4               i;
	s4               j;

	/* get required compiler data */

	m    = jd->m;
	code = jd->code;

	/* allocate buffers for local variable renaming */

	local_map = DMNEW(int, m->maxlocals * 5);

	for (i = 0; i < m->maxlocals; i++) {
		local_map[i * 5 + 0] = 0;
		local_map[i * 5 + 1] = 0;
		local_map[i * 5 + 2] = 0;
		local_map[i * 5 + 3] = 0;
		local_map[i * 5 + 4] = 0;
	}

 	/* initialize the parse data structures */
  
 	parse_setup(jd, &pd);
  
 	/* initialize local variables */
  
 	iptr     = pd.instructions;
 	ircount  = 0;
	bbcount  = 0;
	blockend = false;
	iswide   = false;

	/* mark basic block boundaries for exception table */

	if (!parse_mark_exception_boundaries(jd, &pd))
		return false;

	/* initialize stack element counter */

	s_count = 1 + m->rawexceptiontablelength;

	/* setup line number info */

	currentline = 0;
	linepcchange = 0;

	if (m->linenumbercount == 0) {
		lineindex = 0;
	}
	else {
		linepcchange = m->linenumbers[0].start_pc;
	}

	/*** LOOP OVER ALL BYTECODE INSTRUCTIONS **********************************/

	for (bcindex = 0; bcindex < m->jcodelength; bcindex = nextbc) {

		/* mark this position as a valid bytecode instruction start */

		pd.bytecodestart[bcindex] = 1;

		/* change the current line number, if necessary */

		/* XXX rewrite this using pointer arithmetic */

		if (linepcchange == bcindex) {
			if (m->linenumbercount > lineindex) {
next_linenumber:
				currentline = m->linenumbers[lineindex].line_number;
				lineindex++;
				if (lineindex < m->linenumbercount) {
					linepcchange = m->linenumbers[lineindex].start_pc;
					if (linepcchange == bcindex)
						goto next_linenumber;
				}
			}
		}

fetch_opcode:
		/* fetch next opcode  */	

		opcode = SUCK_BE_U1(m->jcode + bcindex);

		/* If the previous instruction was a block-end instruction,
		   mark the current bytecode instruction as basic-block
		   starting instruction. */

		/* NOTE: Some compilers put a BC_nop after a blockend
		   instruction. */

		if (blockend && (opcode != BC_nop)) {
			MARK_BASICBLOCK(&pd, bcindex);
			blockend = false;
		}

		/* If the current bytecode instruction was marked as
		   basic-block starting instruction before (e.g. blockend,
		   forward-branch target), mark the current IR instruction
		   too. */

		if (pd.basicblockstart[bcindex] != 0) {
			/* We need a NOP as last instruction in each basic block
			   for basic block reordering (may be replaced with a GOTO
			   later). */

			INSTRUCTIONS_CHECK(1);
			OP(ICMD_NOP);
		}

		/* store intermediate instruction count (bit 0 mark block starts) */

		pd.bytecodemap[bcindex] = ircount;

		/* compute next instruction start */

		nextbc = bcindex + bytecode[opcode].length;

		CHECK_END_OF_BYTECODE(nextbc);

		/* add stack elements produced by this instruction */

		s_count += bytecode[opcode].slots;

		/* We check here for the space of 1 instruction in the
		   instruction array.  If an opcode is converted to more than
		   1 instruction, this is checked in the corresponding
		   case. */

		INSTRUCTIONS_CHECK(1);

		/* translate this bytecode instruction */
		switch (opcode) {

		case BC_nop:
			break;

		/* pushing constants onto the stack ***********************************/

		case BC_bipush:
			OP_LOADCONST_I(SUCK_BE_S1(m->jcode + bcindex + 1));
			break;

		case BC_sipush:
			OP_LOADCONST_I(SUCK_BE_S2(m->jcode + bcindex + 1));
			break;

		case BC_ldc1:
			i = SUCK_BE_U1(m->jcode + bcindex + 1);
			goto pushconstantitem;

		case BC_ldc2:
		case BC_ldc2w:
			i = SUCK_BE_U2(m->jcode + bcindex + 1);

		pushconstantitem:

#if defined(ENABLE_VERIFIER)
			if (i >= m->clazz->cpcount) {
				exceptions_throw_verifyerror(m,
					"Attempt to access constant outside range");
				return false;
			}
#endif

			switch (m->clazz->cptags[i]) {
			case CONSTANT_Integer:
				OP_LOADCONST_I(((constant_integer *) (m->clazz->cpinfos[i]))->value);
				break;
			case CONSTANT_Long:
				OP_LOADCONST_L(((constant_long *) (m->clazz->cpinfos[i]))->value);
				break;
			case CONSTANT_Float:
				OP_LOADCONST_F(((constant_float *) (m->clazz->cpinfos[i]))->value);
				break;
			case CONSTANT_Double:
				OP_LOADCONST_D(((constant_double *) (m->clazz->cpinfos[i]))->value);
				break;
			case CONSTANT_String:
				OP_LOADCONST_STRING(literalstring_new((utf *) (m->clazz->cpinfos[i])));
				break;
			case CONSTANT_Class:
				cr = (constant_classref *) (m->clazz->cpinfos[i]);

				if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
					return false;

				/* if not resolved, c == NULL */

				OP_LOADCONST_CLASSINFO_OR_CLASSREF_CHECK(c, cr);

				break;

#if defined(ENABLE_VERIFIER)
			default:
				exceptions_throw_verifyerror(m,
						"Invalid constant type to push");
				return false;
#endif
			}
			break;

		case BC_aconst_null:
			OP_LOADCONST_NULL();
			break;

		case BC_iconst_m1:
		case BC_iconst_0:
		case BC_iconst_1:
		case BC_iconst_2:
		case BC_iconst_3:
		case BC_iconst_4:
		case BC_iconst_5:
			OP_LOADCONST_I(opcode - BC_iconst_0);
			break;

		case BC_lconst_0:
		case BC_lconst_1:
			OP_LOADCONST_L(opcode - BC_lconst_0);
			break;

		case BC_fconst_0:
		case BC_fconst_1:
		case BC_fconst_2:
			OP_LOADCONST_F(opcode - BC_fconst_0);
			break;

		case BC_dconst_0:
		case BC_dconst_1:
			OP_LOADCONST_D(opcode - BC_dconst_0);
			break;

		/* stack operations ***************************************************/

		/* We need space for additional instruction so we can
		   translate these instructions to sequences of ICMD_COPY and
		   ICMD_MOVE instructions. */

		case BC_dup_x1:
			INSTRUCTIONS_CHECK(4);
			OP(opcode);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			break;

		case BC_dup_x2:
			INSTRUCTIONS_CHECK(6);
			OP(opcode);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			break;

		case BC_dup2:
			INSTRUCTIONS_CHECK(2);
			OP(opcode);
			OP(ICMD_NOP);
			break;

		case BC_dup2_x1:
			INSTRUCTIONS_CHECK(7);
			OP(opcode);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			break;

		case BC_dup2_x2:
			INSTRUCTIONS_CHECK(9);
			OP(opcode);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			break;

		case BC_swap:
			INSTRUCTIONS_CHECK(3);
			OP(opcode);
			OP(ICMD_NOP);
			OP(ICMD_NOP);
			break;

		/* local variable access instructions *********************************/

		case BC_iload:
		case BC_fload:
		case BC_aload:
			if (iswide == false) {
				i = SUCK_BE_U1(m->jcode + bcindex + 1);
			}
			else {
				i = SUCK_BE_U2(m->jcode + bcindex + 1);
				nextbc = bcindex + 3;
				iswide = false;
			}
			OP_LOAD_ONEWORD(opcode, i, opcode - BC_iload);
			break;

		case BC_lload:
		case BC_dload:
			if (iswide == false) {
				i = SUCK_BE_U1(m->jcode + bcindex + 1);
			}
			else {
				i = SUCK_BE_U2(m->jcode + bcindex + 1);
				nextbc = bcindex + 3;
				iswide = false;
			}
			OP_LOAD_TWOWORD(opcode, i, opcode - BC_iload);
			break;

		case BC_iload_0:
		case BC_iload_1:
		case BC_iload_2:
		case BC_iload_3:
			OP_LOAD_ONEWORD(ICMD_ILOAD, opcode - BC_iload_0, TYPE_INT);
			break;

		case BC_lload_0:
		case BC_lload_1:
		case BC_lload_2:
		case BC_lload_3:
			OP_LOAD_TWOWORD(ICMD_LLOAD, opcode - BC_lload_0, TYPE_LNG);
			break;

		case BC_fload_0:
		case BC_fload_1:
		case BC_fload_2:
		case BC_fload_3:
			OP_LOAD_ONEWORD(ICMD_FLOAD, opcode - BC_fload_0, TYPE_FLT);
			break;

		case BC_dload_0:
		case BC_dload_1:
		case BC_dload_2:
		case BC_dload_3:
			OP_LOAD_TWOWORD(ICMD_DLOAD, opcode - BC_dload_0, TYPE_DBL);
			break;

		case BC_aload_0:
		case BC_aload_1:
		case BC_aload_2:
		case BC_aload_3:
			OP_LOAD_ONEWORD(ICMD_ALOAD, opcode - BC_aload_0, TYPE_ADR);
			break;

		case BC_istore:
		case BC_fstore:
		case BC_astore:
			if (iswide == false) {
				i = SUCK_BE_U1(m->jcode + bcindex + 1);
			}
			else {
				i = SUCK_BE_U2(m->jcode + bcindex + 1);
				nextbc = bcindex + 3;
				iswide = false;
			}
			OP_STORE_ONEWORD(opcode, i, opcode - BC_istore);
			break;

		case BC_lstore:
		case BC_dstore:
			if (iswide == false) {
				i = SUCK_BE_U1(m->jcode + bcindex + 1);
			}
			else {
				i = SUCK_BE_U2(m->jcode + bcindex + 1);
				nextbc = bcindex + 3;
				iswide = false;
			}
			OP_STORE_TWOWORD(opcode, i, opcode - BC_istore);
			break;

		case BC_istore_0:
		case BC_istore_1:
		case BC_istore_2:
		case BC_istore_3:
			OP_STORE_ONEWORD(ICMD_ISTORE, opcode - BC_istore_0, TYPE_INT);
			break;

		case BC_lstore_0:
		case BC_lstore_1:
		case BC_lstore_2:
		case BC_lstore_3:
			OP_STORE_TWOWORD(ICMD_LSTORE, opcode - BC_lstore_0, TYPE_LNG);
			break;

		case BC_fstore_0:
		case BC_fstore_1:
		case BC_fstore_2:
		case BC_fstore_3:
			OP_STORE_ONEWORD(ICMD_FSTORE, opcode - BC_fstore_0, TYPE_FLT);
			break;

		case BC_dstore_0:
		case BC_dstore_1:
		case BC_dstore_2:
		case BC_dstore_3:
			OP_STORE_TWOWORD(ICMD_DSTORE, opcode - BC_dstore_0, TYPE_DBL);
			break;

		case BC_astore_0:
		case BC_astore_1:
		case BC_astore_2:
		case BC_astore_3:
			OP_STORE_ONEWORD(ICMD_ASTORE, opcode - BC_astore_0, TYPE_ADR);
			break;

		case BC_iinc:
			{
				int v;

				if (iswide == false) {
					i = SUCK_BE_U1(m->jcode + bcindex + 1);
					v = SUCK_BE_S1(m->jcode + bcindex + 2);
				}
				else {
					i = SUCK_BE_U2(m->jcode + bcindex + 1);
					v = SUCK_BE_S2(m->jcode + bcindex + 3);
					nextbc = bcindex + 5;
					iswide = false;
				}
				INDEX_ONEWORD(i);
				LOCALTYPE_USED(i, TYPE_INT);
				OP_LOCALINDEX_I(opcode, i, v);
			}
			break;

		/* wider index for loading, storing and incrementing ******************/

		case BC_wide:
			bcindex++;
			iswide = true;
			goto fetch_opcode;

		/* managing arrays ****************************************************/

		case BC_newarray:
			switch (SUCK_BE_S1(m->jcode + bcindex + 1)) {
			case 4:
				bte = builtintable_get_internal(BUILTIN_newarray_boolean);
				break;
			case 5:
				bte = builtintable_get_internal(BUILTIN_newarray_char);
				break;
			case 6:
				bte = builtintable_get_internal(BUILTIN_newarray_float);
				break;
			case 7:
				bte = builtintable_get_internal(BUILTIN_newarray_double);
				break;
			case 8:
				bte = builtintable_get_internal(BUILTIN_newarray_byte);
				break;
			case 9:
				bte = builtintable_get_internal(BUILTIN_newarray_short);
				break;
			case 10:
				bte = builtintable_get_internal(BUILTIN_newarray_int);
				break;
			case 11:
				bte = builtintable_get_internal(BUILTIN_newarray_long);
				break;
#if defined(ENABLE_VERIFIER)
			default:
				exceptions_throw_verifyerror(m, "Invalid array-type to create");
				return false;
#endif
			}
			OP_BUILTIN_CHECK_EXCEPTION(bte);
			break;

		case BC_anewarray:
			i = SUCK_BE_U2(m->jcode + bcindex + 1);
			compr = (constant_classref *) class_getconstant(m->clazz, i, CONSTANT_Class);
			if (compr == NULL)
				return false;

			if (!(cr = class_get_classref_multiarray_of(1, compr)))
				return false;

			if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
				return false;

			INSTRUCTIONS_CHECK(2);
			OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
			bte = builtintable_get_internal(BUILTIN_newarray);
			OP_BUILTIN_CHECK_EXCEPTION(bte);
			s_count++;
			break;

		case BC_multianewarray:
			i = SUCK_BE_U2(m->jcode + bcindex + 1);
 			j = SUCK_BE_U1(m->jcode + bcindex + 3);
  
 			cr = (constant_classref *) class_getconstant(m->clazz, i, CONSTANT_Class);
 			if (cr == NULL)
 				return false;
  
 			if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
 				return false;
  
 			/* if unresolved, c == NULL */
  
 			iptr->s1.argcount = j;
 			OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, INS_FLAG_CHECK);
			code_unflag_leafmethod(code);
			break;

		/* control flow instructions ******************************************/

		case BC_ifeq:
		case BC_iflt:
		case BC_ifle:
		case BC_ifne:
		case BC_ifgt:
		case BC_ifge:
		case BC_ifnull:
		case BC_ifnonnull:
		case BC_if_icmpeq:
		case BC_if_icmpne:
		case BC_if_icmplt:
		case BC_if_icmpgt:
		case BC_if_icmple:
		case BC_if_icmpge:
		case BC_if_acmpeq:
		case BC_if_acmpne:
		case BC_goto:
			i = bcindex + SUCK_BE_S2(m->jcode + bcindex + 1);
			CHECK_BYTECODE_INDEX(i);
			MARK_BASICBLOCK(&pd, i);
			blockend = true;
			OP_INSINDEX(opcode, i);
			break;

		case BC_goto_w:
			i = bcindex + SUCK_BE_S4(m->jcode + bcindex + 1);
			CHECK_BYTECODE_INDEX(i);
			MARK_BASICBLOCK(&pd, i);
			blockend = true;
			OP_INSINDEX(ICMD_GOTO, i);
			break;

		case BC_jsr:
			i = bcindex + SUCK_BE_S2(m->jcode + bcindex + 1);
jsr_tail:
			CHECK_BYTECODE_INDEX(i);
			MARK_BASICBLOCK(&pd, i);
			blockend = true;
			OP_PREPARE_ZEROFLAGS(BC_jsr);
			iptr->sx.s23.s3.jsrtarget.insindex = i;
			PINC;
			break;

		case BC_jsr_w:
			i = bcindex + SUCK_BE_S4(m->jcode + bcindex + 1);
			goto jsr_tail;

		case BC_ret:
			if (iswide == false) {
				i = SUCK_BE_U1(m->jcode + bcindex + 1);
			}
			else {
				i = SUCK_BE_U2(m->jcode + bcindex + 1);
				nextbc = bcindex + 3;
				iswide = false;
			}
			blockend = true;

			OP_LOAD_ONEWORD(opcode, i, TYPE_ADR);
			break;

		case BC_ireturn:
		case BC_lreturn:
		case BC_freturn:
		case BC_dreturn:
		case BC_areturn:
		case BC_return:
			blockend = true;
			/* XXX ARETURN will need a flag in the typechecker */
			OP(opcode);
			break;

		case BC_athrow:
			blockend = true;
			/* XXX ATHROW will need a flag in the typechecker */
			OP(opcode);
			break;


		/* table jumps ********************************************************/

		case BC_lookupswitch:
			{
				s4 num, j;
				lookup_target_t *lookup;
#if defined(ENABLE_VERIFIER)
				s4 prevvalue = 0;
#endif
				blockend = true;
				nextbc = MEMORY_ALIGN((bcindex + 1), 4);

				CHECK_END_OF_BYTECODE(nextbc + 8);

				OP_PREPARE_ZEROFLAGS(opcode);

				/* default target */

				j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
				iptr->sx.s23.s3.lookupdefault.insindex = j;
				nextbc += 4;
				CHECK_BYTECODE_INDEX(j);
				MARK_BASICBLOCK(&pd, j);

				/* number of pairs */

				num = SUCK_BE_U4(m->jcode + nextbc);
				iptr->sx.s23.s2.lookupcount = num;
				nextbc += 4;

				/* allocate the intermediate code table */

				lookup = DMNEW(lookup_target_t, num);
				iptr->dst.lookup = lookup;

				/* iterate over the lookup table */

				CHECK_END_OF_BYTECODE(nextbc + 8 * num);

				for (i = 0; i < num; i++) {
					/* value */

					j = SUCK_BE_S4(m->jcode + nextbc);
					lookup->value = j;

					nextbc += 4;

#if defined(ENABLE_VERIFIER)
					/* check if the lookup table is sorted correctly */

					if (i && (j <= prevvalue)) {
						exceptions_throw_verifyerror(m, "Unsorted lookup switch");
						return false;
					}
					prevvalue = j;
#endif
					/* target */

					j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
					lookup->target.insindex = j;
					lookup++;
					nextbc += 4;
					CHECK_BYTECODE_INDEX(j);
					MARK_BASICBLOCK(&pd, j);
				}

				PINC;
				break;
			}

		case BC_tableswitch:
			{
				s4 num, j;
				s4 deftarget;
				branch_target_t *table;

				blockend = true;
				nextbc = MEMORY_ALIGN((bcindex + 1), 4);

				CHECK_END_OF_BYTECODE(nextbc + 12);

				OP_PREPARE_ZEROFLAGS(opcode);

				/* default target */

				deftarget = bcindex + SUCK_BE_S4(m->jcode + nextbc);
				nextbc += 4;
				CHECK_BYTECODE_INDEX(deftarget);
				MARK_BASICBLOCK(&pd, deftarget);

				/* lower bound */

				j = SUCK_BE_S4(m->jcode + nextbc);
				iptr->sx.s23.s2.tablelow = j;
				nextbc += 4;

				/* upper bound */

				num = SUCK_BE_S4(m->jcode + nextbc);
				iptr->sx.s23.s3.tablehigh = num;
				nextbc += 4;

				/* calculate the number of table entries */

				num = num - j + 1;

#if defined(ENABLE_VERIFIER)
				if (num < 1) {
					exceptions_throw_verifyerror(m,
							"invalid TABLESWITCH: upper bound < lower bound");
					return false;
				}
#endif
				/* create the intermediate code table */
				/* the first entry is the default target */

				table = DMNEW(branch_target_t, 1 + num);
				iptr->dst.table = table;
				(table++)->insindex = deftarget;

				/* iterate over the target table */

				CHECK_END_OF_BYTECODE(nextbc + 4 * num);

				for (i = 0; i < num; i++) {
					j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
					(table++)->insindex = j;
					nextbc += 4;
					CHECK_BYTECODE_INDEX(j);
					MARK_BASICBLOCK(&pd, j);
				}

				PINC;
				break;
			}


		/* load and store of object fields ************************************/

		case BC_aastore:
			OP(opcode);
			code_unflag_leafmethod(code);
			break;

		case BC_getstatic:
		case BC_putstatic:
		case BC_getfield:
		case BC_putfield:
			i = SUCK_BE_U2(m->jcode + bcindex + 1);
			fmi = class_getconstant(m->clazz, i, CONSTANT_Fieldref);

			if (fmi == NULL)
				return false;

			OP_PREPARE_ZEROFLAGS(opcode);
			iptr->sx.s23.s3.fmiref = fmi;

			/* only with -noverify, otherwise the typechecker does this */

#if defined(ENABLE_VERIFIER)
			if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
#endif
				result = resolve_field_lazy(m, fmi);

				if (result == resolveFailed)
					return false;

				if (result != resolveSucceeded) {
					uf = resolve_create_unresolved_field(m->clazz, m, iptr);

					if (uf == NULL)
						return false;

					/* store the unresolved_field pointer */

					iptr->sx.s23.s3.uf = uf;
					iptr->flags.bits |= INS_FLAG_UNRESOLVED;
				}
#if defined(ENABLE_VERIFIER)
			}
#endif
			PINC;
			break;


		/* method invocation **************************************************/

		case BC_invokestatic:
			OP_PREPARE_ZEROFLAGS(opcode);

			i = SUCK_BE_U2(m->jcode + bcindex + 1);
			fmi = class_getconstant(m->clazz, i, CONSTANT_Methodref);

			if (fmi == NULL)
				return false;

			md = fmi->parseddesc.md;

			if (md->params == NULL)
				if (!descriptor_params_from_paramtypes(md, ACC_STATIC))
					return false;

			goto invoke_method;

		case BC_invokespecial:
			OP_PREPARE_FLAGS(opcode, INS_FLAG_CHECK);

			i = SUCK_BE_U2(m->jcode + bcindex + 1);
			fmi = class_getconstant(m->clazz, i, CONSTANT_Methodref);

			goto invoke_nonstatic_method;

		case BC_invokeinterface:
			OP_PREPARE_ZEROFLAGS(opcode);

			i = SUCK_BE_U2(m->jcode + bcindex + 1);
			fmi = class_getconstant(m->clazz, i, CONSTANT_InterfaceMethodref);

			goto invoke_nonstatic_method;

		case BC_invokevirtual:
			OP_PREPARE_ZEROFLAGS(opcode);

			i = SUCK_BE_U2(m->jcode + bcindex + 1);
			fmi = class_getconstant(m->clazz, i, CONSTANT_Methodref);

invoke_nonstatic_method:
			if (fmi == NULL)
				return false;

			md = fmi->parseddesc.md;

			if (md->params == NULL)
				if (!descriptor_params_from_paramtypes(md, 0))
					return false;

invoke_method:
			code_unflag_leafmethod(code);

			iptr->sx.s23.s3.fmiref = fmi;

			/* only with -noverify, otherwise the typechecker does this */

#if defined(ENABLE_VERIFIER)
			if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
#endif
				result = resolve_method_lazy(m, fmi, 
											 (opcode == BC_invokespecial));

				if (result == resolveFailed)
					return false;

				if (result == resolveSucceeded) {
					methodinfo *mi = iptr->sx.s23.s3.fmiref->p.method;

					/* if this call is monomorphic, turn it into an
					   INVOKESPECIAL */

					assert(IS_FMIREF_RESOLVED(iptr->sx.s23.s3.fmiref));

					if ((iptr->opc == ICMD_INVOKEVIRTUAL)
						&& (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
					{
						iptr->opc         = ICMD_INVOKESPECIAL;
						iptr->flags.bits |= INS_FLAG_CHECK;
					}
				}
				else {
					um = resolve_create_unresolved_method(m->clazz, m, fmi,
							(opcode == BC_invokestatic),
							(opcode == BC_invokespecial));

					if (um == NULL)
						return false;

					/* store the unresolved_method pointer */

					iptr->sx.s23.s3.um = um;
					iptr->flags.bits |= INS_FLAG_UNRESOLVED;
				}
#if defined(ENABLE_VERIFIER)
			}
#endif
			PINC;
			break;

		/* instructions taking class arguments ********************************/

		case BC_new:
			i = SUCK_BE_U2(m->jcode + bcindex + 1);
			cr = class_getconstant(m->clazz, i, CONSTANT_Class);

			if (cr == NULL)
				return false;

			if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
				return false;

			INSTRUCTIONS_CHECK(2);
			OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
			bte = builtintable_get_internal(BUILTIN_new);
			OP_BUILTIN_CHECK_EXCEPTION(bte);
			s_count++;
			break;

		case BC_checkcast:
			i = SUCK_BE_U2(m->jcode + bcindex + 1);
			cr = class_getconstant(m->clazz, i, CONSTANT_Class);

			if (cr == NULL)
				return false;

			if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
				return false;

			if (cr->name->text[0] == '[') {
				/* array type cast-check */
				flags = INS_FLAG_CHECK | INS_FLAG_ARRAY;
				code_unflag_leafmethod(code);
			}
			else {
				/* object type cast-check */
				flags = INS_FLAG_CHECK;
			}
			OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, flags);
			break;

		case BC_instanceof:
			i = SUCK_BE_U2(m->jcode + bcindex + 1);
			cr = class_getconstant(m->clazz, i, CONSTANT_Class);

			if (cr == NULL)
				return false;

			if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
				return false;

			if (cr->name->text[0] == '[') {
				/* array type cast-check */
				INSTRUCTIONS_CHECK(2);
				OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
				bte = builtintable_get_internal(BUILTIN_arrayinstanceof);
				OP_BUILTIN_NO_EXCEPTION(bte);
				s_count++;
			}
			else {
				/* object type cast-check */
				OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, 0 /* flags*/);
			}
			break;

		/* synchronization instructions ***************************************/

		case BC_monitorenter:
#if defined(ENABLE_THREADS)
			if (checksync) {
				bte = builtintable_get_internal(LOCK_monitor_enter);
				OP_BUILTIN_CHECK_EXCEPTION(bte);
			}
			else
#endif
			{
				OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
				OP(ICMD_POP);
			}
			break;

		case BC_monitorexit:
#if defined(ENABLE_THREADS)
			if (checksync) {
				bte = builtintable_get_internal(LOCK_monitor_exit);
				OP_BUILTIN_CHECK_EXCEPTION(bte);
			}
			else
#endif
			{
				OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
				OP(ICMD_POP);
			}
			break;

		/* arithmetic instructions that may become builtin functions **********/

		case BC_idiv:
#if !SUPPORT_DIVISION
			bte = builtintable_get_internal(BUILTIN_idiv);
			OP_BUILTIN_ARITHMETIC(opcode, bte);
#else
# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
			OP(opcode);
# else
			OP_CHECK_EXCEPTION(opcode);
# endif
#endif
			break;

		case BC_irem:
#if !SUPPORT_DIVISION
			bte = builtintable_get_internal(BUILTIN_irem);
			OP_BUILTIN_ARITHMETIC(opcode, bte);
#else
# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
			OP(opcode);
# else
			OP_CHECK_EXCEPTION(opcode);
# endif
#endif
			break;

		case BC_ldiv:
#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV)
			bte = builtintable_get_internal(BUILTIN_ldiv);
			OP_BUILTIN_ARITHMETIC(opcode, bte);
#else
# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
			OP(opcode);
# else
			OP_CHECK_EXCEPTION(opcode);
# endif
#endif
			break;

		case BC_lrem:
#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV)
			bte = builtintable_get_internal(BUILTIN_lrem);
			OP_BUILTIN_ARITHMETIC(opcode, bte);
#else
# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
			OP(opcode);
# else
			OP_CHECK_EXCEPTION(opcode);
# endif
#endif
			break;

		case BC_frem:
#if defined(__I386__)
			OP(opcode);
#else
			bte = builtintable_get_internal(BUILTIN_frem);
			OP_BUILTIN_NO_EXCEPTION(bte);
#endif
			break;

		case BC_drem:
#if defined(__I386__)
			OP(opcode);
#else
			bte = builtintable_get_internal(BUILTIN_drem);
			OP_BUILTIN_NO_EXCEPTION(bte);
#endif
			break;

		case BC_f2i:
#if defined(__ALPHA__)
			if (!opt_noieee) {
				bte = builtintable_get_internal(BUILTIN_f2i);
				OP_BUILTIN_NO_EXCEPTION(bte);
			}
			else
#endif
			{
				OP(opcode);
			}
			break;

		case BC_f2l:
#if defined(__ALPHA__)
			if (!opt_noieee) {
				bte = builtintable_get_internal(BUILTIN_f2l);
				OP_BUILTIN_NO_EXCEPTION(bte);
			}
			else
#endif
			{
				OP(opcode);
			}
			break;

		case BC_d2i:
#if defined(__ALPHA__)
			if (!opt_noieee) {
				bte = builtintable_get_internal(BUILTIN_d2i);
				OP_BUILTIN_NO_EXCEPTION(bte);
			}
			else
#endif
			{
				OP(opcode);
			}
			break;

		case BC_d2l:
#if defined(__ALPHA__)
			if (!opt_noieee) {
				bte = builtintable_get_internal(BUILTIN_d2l);
				OP_BUILTIN_NO_EXCEPTION(bte);
			}
			else
#endif
			{
				OP(opcode);
			}
			break;


		/* invalid opcodes ****************************************************/

			/* check for invalid opcodes if the verifier is enabled */
#if defined(ENABLE_VERIFIER)
		case BC_breakpoint:
			exceptions_throw_verifyerror(m, "Quick instructions shouldn't appear, yet.");
			return false;


		/* Unused opcodes ************************************************** */

		case 186:
		case 203:
		case 204:
		case 205:
		case 206:
		case 207:
		case 208:
		case 209:
		case 210:
		case 211:
		case 212:
		case 213:
		case 214:
		case 215:
		case 216:
		case 217:
		case 218:
		case 219:
		case 220:
		case 221:
		case 222:
		case 223:
		case 224:
		case 225:
		case 226:
		case 227:
		case 228:
		case 229:
		case 230:
		case 231:
		case 232:
		case 233:
		case 234:
		case 235:
		case 236:
		case 237:
		case 238:
		case 239:
		case 240:
		case 241:
		case 242:
		case 243:
		case 244:
		case 245:
		case 246:
		case 247:
		case 248:
		case 249:
		case 250:
		case 251:
		case 252:
		case 253:
		case 254:
		case 255:
			exceptions_throw_verifyerror(m, "Illegal opcode %d at instr %d\n",
										 opcode, ircount);
			return false;
			break;
#endif /* defined(ENABLE_VERIFIER) */

		/* opcodes that don't require translation *****************************/

		default:
			/* Straight-forward translation to HIR. */
			OP(opcode);
			break;

		} /* end switch */

		/* verifier checks ****************************************************/

#if defined(ENABLE_VERIFIER)
		/* If WIDE was used correctly, iswide should have been reset by now. */
		if (iswide) {
			exceptions_throw_verifyerror(m,
					"Illegal instruction: WIDE before incompatible opcode");
			return false;
		}
#endif /* defined(ENABLE_VERIFIER) */

	} /* end for */

	if (JITDATA_HAS_FLAG_REORDER(jd)) {
		/* add a NOP to the last basic block */

		INSTRUCTIONS_CHECK(1);
		OP(ICMD_NOP);
	}

	/*** END OF LOOP **********************************************************/

	/* assert that we did not write more ICMDs than allocated */

	assert(ircount <= pd.instructionslength);
	assert(ircount == (iptr - pd.instructions));

	/*** verifier checks ******************************************************/

#if defined(ENABLE_VERIFIER)
	if (bcindex != m->jcodelength) {
		exceptions_throw_verifyerror(m,
				"Command-sequence crosses code-boundary");
		return false;
	}

	if (!blockend) {
		exceptions_throw_verifyerror(m, "Falling off the end of the code");
		return false;
	}
#endif /* defined(ENABLE_VERIFIER) */

	/*** setup the methodinfo, allocate stack and basic blocks ****************/

	/* identify basic blocks */

	/* check if first instruction is a branch target */

	if (pd.basicblockstart[0] == 1) {
		jd->branchtoentry = true;
	}
	else {
		/* first instruction always starts a basic block */

		iptr = pd.instructions;

		iptr->flags.bits |= INS_FLAG_BASICBLOCK;
	}

	/* Iterate over all bytecode instructions and set missing
	   basic-block starts in IR instructions. */

	for (bcindex = 0; bcindex < m->jcodelength; bcindex++) {
		/* Does the current bytecode instruction start a basic
		   block? */

		if (pd.basicblockstart[bcindex] == 1) {
#if defined(ENABLE_VERIFIER)
			/* Check if this bytecode basic-block start at the
			   beginning of a bytecode instruction. */

			if (pd.bytecodestart[bcindex] == 0) {
				exceptions_throw_verifyerror(m,
										 "Branch into middle of instruction");
				return false;
			}
#endif

			/* Get the IR instruction mapped to the bytecode
			   instruction and set the basic block flag. */

			irindex = pd.bytecodemap[bcindex];
			iptr    = pd.instructions + irindex;

			iptr->flags.bits |= INS_FLAG_BASICBLOCK;
		}
	}

	/* IR instruction index to basic-block index mapping */

	pd.instructionmap = DMNEW(s4, ircount);
	MZERO(pd.instructionmap, s4, ircount);

	/* Iterate over all IR instructions and count the basic blocks. */

	iptr = pd.instructions;

	bbcount = 0;

	for (i = 0; i < ircount; i++, iptr++) {
		if (INSTRUCTION_STARTS_BASICBLOCK(iptr)) {
			/* store the basic-block number in the IR instruction
			   map */

			pd.instructionmap[i] = bbcount;

			/* post-increment the basic-block count */

			bbcount++;
		}
	}

	/* Allocate basic block array (one more for end ipc). */

	jd->basicblocks = DMNEW(basicblock, bbcount + 1);
	MZERO(jd->basicblocks, basicblock, bbcount + 1);

	/* Now iterate again over all IR instructions and initialize the
	   basic block structures and, in the same loop, resolve the
	   branch-target instruction indices to basic blocks. */

	iptr = pd.instructions;
	bptr = jd->basicblocks;

	bbcount = 0;

	for (i = 0; i < ircount; i++, iptr++) {
		/* check for basic block */

		if (INSTRUCTION_STARTS_BASICBLOCK(iptr)) {
			/* intialize the basic block */

			BASICBLOCK_INIT(bptr, m);

			bptr->iinstr = iptr;

			if (bbcount > 0) {
				bptr[-1].icount = bptr->iinstr - bptr[-1].iinstr;
			}

			/* bptr->icount is set when the next block is allocated */

			bptr->nr = bbcount++;
			bptr++;
			bptr[-1].next = bptr;
		}

		/* resolve instruction indices to basic blocks */

		switch (iptr->opc) {
		case ICMD_IFEQ:
		case ICMD_IFLT:
		case ICMD_IFLE:
		case ICMD_IFNE:
		case ICMD_IFGT:
		case ICMD_IFGE:
		case ICMD_IFNULL:
		case ICMD_IFNONNULL:
		case ICMD_IF_ICMPEQ:
		case ICMD_IF_ICMPNE:
		case ICMD_IF_ICMPLT:
		case ICMD_IF_ICMPGT:
		case ICMD_IF_ICMPLE:
		case ICMD_IF_ICMPGE:
		case ICMD_IF_ACMPEQ:
		case ICMD_IF_ACMPNE:
		case ICMD_GOTO:
			BYTECODEINDEX_TO_BASICBLOCK(iptr->dst);
			break;

		case ICMD_JSR:
			BYTECODEINDEX_TO_BASICBLOCK(iptr->sx.s23.s3.jsrtarget);
			break;

		case ICMD_TABLESWITCH:
			table = iptr->dst.table;

			BYTECODEINDEX_TO_BASICBLOCK(*table);
			table++;

			j = iptr->sx.s23.s3.tablehigh - iptr->sx.s23.s2.tablelow + 1;

			while (--j >= 0) {
				BYTECODEINDEX_TO_BASICBLOCK(*table);
				table++;
			}
			break;

		case ICMD_LOOKUPSWITCH:
			BYTECODEINDEX_TO_BASICBLOCK(iptr->sx.s23.s3.lookupdefault);

			lookup = iptr->dst.lookup;

			j = iptr->sx.s23.s2.lookupcount;

			while (--j >= 0) {
				BYTECODEINDEX_TO_BASICBLOCK(lookup->target);
				lookup++;
			}
			break;
		}
	}

	/* set instruction count of last real block */

	if (bbcount > 0) {
		bptr[-1].icount = (pd.instructions + ircount) - bptr[-1].iinstr;
	}

	/* allocate additional block at end */

	BASICBLOCK_INIT(bptr, m);
	bptr->nr = bbcount;

	/* set basicblock pointers in exception table */

	if (!parse_resolve_exception_table(jd, &pd))
		return false;

	/* store the local map */

	jd->local_map = local_map;

	/* calculate local variable renaming */

	{
		s4 nlocals = 0;
		s4 i;
		s4 t;
		s4 varindex;
		s4 *mapptr;
		s4 *reversemap;

		mapptr = local_map;

		/* iterate over local_map[0..m->maxlocals*5-1] and allocate a unique */
		/* variable index for each _used_ (javaindex,type) pair.             */
		/* (local_map[javaindex*5+type] = cacaoindex)                        */
		/* Unused (javaindex,type) pairs are marked with UNUSED.             */

		for (i = 0; i < (m->maxlocals * 5); i++, mapptr++) {
			if (*mapptr)
				*mapptr = nlocals++;
			else
				*mapptr = UNUSED;
		}

		jd->localcount = nlocals;

		/* calculate the (maximum) number of variables needed */

		jd->varcount = 
			  nlocals                                      /* local variables */
			+ bbcount * m->maxstack                                 /* invars */
			+ s_count;         /* variables created within blocks (non-invar) */

		/* reserve the first indices for local variables */

		jd->vartop = nlocals;

		/* reserve extra variables needed by stack analyse */

		jd->varcount += STACK_EXTRA_VARS;
		jd->vartop   += STACK_EXTRA_VARS;

		/* The verifier needs space for saving invars in some cases and */
		/* extra variables.                                             */

#if defined(ENABLE_VERIFIER)
		jd->varcount += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
		jd->vartop   += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
#endif
		/* allocate and initialize the variable array */

		jd->var = DMNEW(varinfo, jd->varcount);
		MZERO(jd->var, varinfo, jd->varcount);

		/* set types of all locals in jd->var */
		/* and fill the reverselocalmap       */

		reversemap = DMNEW(s4, nlocals);

		for (i = 0; i < m->maxlocals; i++)
			for (t=0; t<5; t++) {
				varindex = local_map[5*i + t];
				if (varindex != UNUSED) {
					VAR(varindex)->type = t;
					reversemap[varindex] = i;
				}
			}

		jd->reverselocalmap = reversemap;
	}

	/* assign local variables to method variables */

	jd->instructions     = pd.instructions;
	jd->instructioncount = ircount;
	jd->basicblockcount  = bbcount;
	jd->stackcount       = s_count + bbcount * m->maxstack; /* in-stacks */

	/* allocate stack table */

	jd->stack = DMNEW(stackelement_t, jd->stackcount);

	/* everything's ok */

	return true;

	/*** goto labels for throwing verifier exceptions *************************/

#if defined(ENABLE_VERIFIER)

throw_unexpected_end_of_bytecode:
	exceptions_throw_verifyerror(m, "Unexpected end of bytecode");
	return false;

throw_invalid_bytecode_index:
	exceptions_throw_verifyerror(m, "Illegal target of branch instruction");
	return false;

throw_illegal_local_variable_number:
	exceptions_throw_verifyerror(m, "Illegal local variable number");
	return false;

#endif /* ENABLE_VERIFIER */
}


/*
 * These are local overrides for various environment variables in Emacs.
 * Please do not remove this and leave it at the end of the file, where
 * Emacs will automagically detect them.
 * ---------------------------------------------------------------------
 * Local variables:
 * mode: c
 * indent-tabs-mode: t
 * c-basic-offset: 4
 * tab-width: 4
 * End:
 * vim:noexpandtab:sw=4:ts=4:
 */
