/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/NPL/
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 *
 * The Original Code is mozilla.org code.
 *
 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation. All
 * Rights Reserved.
 *
 * Contributor(s): 
 */

#include "BytecodeTranslator.h"
#include "PrimitiveBuilders.h"
#include "MemoryAccess.h"
#include "FieldOrMethod.h"

static const UnaryBuilder *const unaryBuilders[] =
{
	&builder_Neg_II,		// bcINeg
	&builder_Neg_LL,		// bcLNeg
	&builder_Neg_FF,		// bcFNeg
	&builder_Neg_DD,		// bcDNeg
	0,						// bcIShl
	0,						// bcLShl
	0,						// bcIShr
	0,						// bcLShr
	0,						// bcIUShr
	0,						// bcLUShr
	0,						// bcIAnd
	0,						// bcLAnd
	0,						// bcIOr
	0,						// bcLOr
	0,						// bcIXor
	0,						// bcLXor
	0,						// bcIInc
	&builder_Conv_IL,		// bcI2L
	&builder_Conv_IF,		// bcI2F
	&builder_Conv_ID,		// bcI2D
	&builder_Conv_LI,		// bcL2I
	&builder_Conv_LF,		// bcL2F
	&builder_Conv_LD,		// bcL2D
	&builder_Conv_FI,		// bcF2I
	&builder_Conv_FL,		// bcF2L
	&builder_Conv_FD,		// bcF2D
	&builder_Conv_DI,		// bcD2I
	&builder_Conv_DL,		// bcD2L
	&builder_Conv_DF,		// bcD2F
	&builder_ExtB_II,		// bcInt2Byte
	&builder_ExtC_II,		// bcInt2Char
	&builder_ExtS_II		// bcInt2Short
};

static const BinaryBuilder *const binaryBuilders[] =
{
	&builder_AddCoal_III,	// bcIAdd
	&builder_AddCoal_LLL,	// bcLAdd
	&builder_Add_FFF,		// bcFAdd
	&builder_Add_DDD,		// bcDAdd
	&builder_SubCoal_III,	// bcISub
	&builder_SubCoal_LLL,	// bcLSub
	&builder_Sub_FFF,		// bcFSub
	&builder_Sub_DDD,		// bcDSub
	&builder_Mul_III,		// bcIMul
	&builder_Mul_LLL,		// bcLMul
	&builder_Mul_FFF,		// bcFMul
	&builder_Mul_DDD,		// bcDMul
	&builder_Div_III,		// bcIDiv
	&builder_Div_LLL,		// bcLDiv
	&builder_Div_FFF,		// bcFDiv
	&builder_Div_DDD,		// bcDDiv
	&builder_Mod_III,		// bcIRem
	&builder_Mod_LLL,		// bcLRem
	&builder_Rem_FFF,		// bcFRem
	&builder_Rem_DDD,		// bcDRem
	0,						// bcINeg
	0,						// bcLNeg
	0,						// bcFNeg
	0,						// bcDNeg
	&builder_Shl_III,		// bcIShl
	&builder_Shl_LIL,		// bcLShl
	&builder_Shr_III,		// bcIShr
	&builder_Shr_LIL,		// bcLShr
	&builder_UShr_III,		// bcIUShr
	&builder_UShr_LIL,		// bcLUShr
	&builder_And_III,		// bcIAnd
	&builder_And_LLL,		// bcLAnd
	&builder_Or_III,		// bcIOr
	&builder_Or_LLL,		// bcLOr
	&builder_Xor_III,		// bcIXor
	&builder_Xor_LLL,		// bcLXor
	0,						// bcIInc
	0,						// bcI2L
	0,						// bcI2F
	0,						// bcI2D
	0,						// bcL2I
	0,						// bcL2F
	0,						// bcL2D
	0,						// bcF2I
	0,						// bcF2L
	0,						// bcF2D
	0,						// bcD2I
	0,						// bcD2L
	0,						// bcD2F
	0,						// bcInt2Byte
	0,						// bcInt2Char
	0,						// bcInt2Short
	&builder_Cmp3_LLI,		// bcLCmp
	&builder_Cmp3L_FFI,		// bcFCmpL
	&builder_Cmp3G_FFI,		// bcFCmpG
	&builder_Cmp3L_DDI,		// bcDCmpL
	&builder_Cmp3G_DDI		// bcDCmpG
};

static const ComparisonBuilder<Int32> *const unaryComparisonBuilders[] =
{
	&builder_CmpEq_IIC,		// bcIfEq
	&builder_CmpEq_IIC,		// bcIfNe
	&builder_Cmp_IIC,		// bcIfLt
	&builder_Cmp_IIC,		// bcIfGe
	&builder_Cmp_IIC,		// bcIfGt
	&builder_Cmp_IIC		// bcIfLe
};

static const BinaryBuilder *const binaryComparisonBuilders[] =
{
	&builder_CmpEq_IIC,		// bcIf_ICmpEq
	&builder_CmpEq_IIC,		// bcIf_ICmpNe
	&builder_Cmp_IIC,		// bcIf_ICmpLt
	&builder_Cmp_IIC,		// bcIf_ICmpGe
	&builder_Cmp_IIC,		// bcIf_ICmpGt
	&builder_Cmp_IIC,		// bcIf_ICmpLe
	&builder_CmpUEq_AAC,	// bcIf_ACmpEq
	&builder_CmpUEq_AAC		// bcIf_ACmpNe
};


static const Condition2 bytecodeConditionals[] =
{
	condEq,		// bcIfEq
	condNe,		// bcIfNe
	condLt,		// bcIfLt
	condGe,		// bcIfGe
	condGt,		// bcIfGt
	condLe,		// bcIfLe
	condEq,		// bcIf_ICmpEq
	condNe,		// bcIf_ICmpNe
	condLt,		// bcIf_ICmpLt
	condGe,		// bcIf_ICmpGe
	condGt,		// bcIf_ICmpGt
	condLe,		// bcIf_ICmpLe
	condEq,		// bcIf_ACmpEq
	condNe,		// bcIf_ACmpNe
	cond0,		// bcGoto
	cond0,		// bcJsr
	cond0,		// bcRet
	cond0,		// bcTableSwitch
	cond0,		// bcLookupSwitch
	cond0,		// bcIReturn
	cond0,		// bcLReturn
	cond0,		// bcFReturn
	cond0,		// bcDReturn
	cond0,		// bcAReturn
	cond0,		// bcReturn
	cond0,		// bcGetStatic
	cond0,		// bcPutStatic
	cond0,		// bcGetField
	cond0,		// bcPutField
	cond0,		// bcInvokeVirtual
	cond0,		// bcInvokeSpecial
	cond0,		// bcInvokeStatic
	cond0,		// bcInvokeInterface
	cond0,		// bc_unused_
	cond0,		// bcNew
	cond0,		// bcNewArray
	cond0,		// bcANewArray
	cond0,		// bcArrayLength
	cond0,		// bcAThrow
	cond0,		// bcCheckCast
	cond0,		// bcInstanceOf
	cond0,		// bcMonitorEnter
	cond0,		// bcMonitorExit
	cond0,		// bcWide
	cond0,		// bcMultiANewArray
	condEq,		// bcIfNull
	condNe		// bcIfNonnull
};


const TypeKind arrayAccessTypeKinds[] =
{
	tkInt,		// bcIALoad, bcIAStore
	tkLong,		// bcLALoad, bcLAStore
	tkFloat,	// bcFALoad, bcFAStore
	tkDouble,	// bcDALoad, bcDAStore
	tkObject,	// bcAALoad, bcAAStore
	tkByte,		// bcBALoad, bcBAStore
	tkChar,		// bcCALoad, bcCAStore
	tkShort		// bcSALoad, bcSAStore
};


const LoadBuilder *const loadBuilders[] =
{
	0,						// tkVoid
	&builder_LdU_AB,		// tkBoolean
	&builder_LdU_AB,		// tkUByte
	&builder_LdS_AB,		// tkByte
	&builder_LdU_AH,		// tkChar
	&builder_LdS_AH,		// tkShort
	&builder_Ld_AI,			// tkInt
	&builder_Ld_AL,			// tkLong
	&builder_Ld_AF,			// tkFloat
	&builder_Ld_AD,			// tkDouble
	&builder_Ld_AA,			// tkObject
	&builder_Ld_AA,			// tkSpecial
	&builder_Ld_AA,			// tkArray
	&builder_Ld_AA			// tkInterface
};


const StoreBuilder *const storeBuilders[] =
{
	0,						// tkVoid
	&builder_St_AB,			// tkBoolean
	&builder_St_AB,			// tkUByte
	&builder_St_AB,			// tkByte
	&builder_St_AH,			// tkChar
	&builder_St_AH,			// tkShort
	&builder_St_AI,			// tkInt
	&builder_St_AL,			// tkLong
	&builder_St_AF,			// tkFloat
	&builder_St_AD,			// tkDouble
	&builder_St_AA,			// tkObject
	&builder_St_AA,			// tkSpecial
	&builder_St_AA,			// tkArray
	&builder_St_AA			// tkInterface
};


static const SysCall *const newArrayCalls[natLimit - natMin] =
{
	&scNewBooleanArray,	// natBoolean
	&scNewCharArray,	// natChar
	&scNewFloatArray,	// natFloat
	&scNewDoubleArray,	// natDouble
	&scNewByteArray,	// natByte
	&scNewShortArray,	// natShort
	&scNewIntArray,		// natInt
	&scNewLongArray		// natLong
};


static const SysCall *const typeToArrayCalls[nPrimitiveTypeKinds] =
{
	NULL,               // tkVoid
	&scNewBooleanArray,	// tkBoolean
	&scNewByteArray,	// tkUByte
	&scNewByteArray,	// tkByte
	&scNewCharArray,	// tkChar
	&scNewShortArray,	// tkShort
	&scNewIntArray,		// tkInt
	&scNewLongArray,	// tkLong
	&scNewFloatArray,	// tkFloat
	&scNewDoubleArray	// tkDouble
};


// ----------------------------------------------------------------------------
// BytecodeTranslator::BlockTranslator


//
// Create a new, empty control node to hold the rest of this BytecodeBlock and set cn
// to be that control node.  Make edge e be the one predecessor (so far) of the
// new control node.
//
void BytecodeTranslator::BlockTranslator::appendControlNode(ControlEdge &e)
{
	ControlNode &nextControlNode = getControlGraph().newControlNode();
	nextControlNode.addPredecessor(e);
	cn = &nextControlNode;
}


//
// Designate this ControlNode to be an Exc, Throw, or AExc node, depending on the given
// ControlKind.  This node will have zero (Throw) or one (Exc or AExc) normal successors
// (whose targets are not initialized -- the caller will have to do that) followed by as
// many exceptional successors as there are possible handlers for an exception of class
// exceptionClass thrown from within this BytecodeBlock.  The exceptional successor edges are
// fully initialized, as is the ExceptionExtra node's handlerFilters array.
//
// If the ControlNode will be an Exc or Throw node, tryPrimitive must be a primitive
// located inside this node that can throw an exception; if the ControlNode will be an
// AExc node, tryPrimitive must be nil.
//
// translationEnv's stack is ignored.
// This routine assumes ownership of translationEnv if canOwnEnv is true (thereby sometimes eliminating
// an unnecessary copy).
//
void BytecodeTranslator::BlockTranslator::genException(ControlKind ck, Primitive *tryPrimitive, const Class &exceptionClass,
													   bool canOwnEnv) const
{
	assert(cn && hasExceptionOutgoingEdges(ck));
	Uint32 nNormalSuccessors = ck != ckThrow;
	Uint32 maxNHandlers = block.handlersEnd - block.successorsEnd + 1;
	const Class **filters = new(primitivePool) const Class *[maxNHandlers];
	ControlEdge *successors = new(primitivePool) ControlEdge[nNormalSuccessors + maxNHandlers];

	// Copy the list of handlers from the BytecodeBlock to the ExceptionExtra.
	// Remove any handlers that can't apply.
	const Class **srcFilter = block.exceptionClasses;
	const Class **dstFilter = filters;
	BasicBlock **srcSuccessor = block.successorsEnd;
	ControlEdge *dstSuccessor = successors + nNormalSuccessors;
	BasicBlock *successor;
	while (--maxNHandlers) {
		const Class *filter = *srcFilter++;
		successor = *srcSuccessor++;

		assert(filter->implements(Standard::get(cThrowable)));
		if (filter == &Standard::get(cThrowable))
			goto haveCatchAll;
		if (exceptionClass.implements(*filter) || filter->implements(exceptionClass)) {
			*dstFilter++ = filter;
			bt.linkPredecessor(*successor, *dstSuccessor++, getEnv(), false);
		}
	}
	// We haven't reached a catch-all handler, so direct remaining exceptions to
	// the End block, which indicates that they are propagated out of this function.
	successor = bt.bytecodeGraph.endBlock;

  haveCatchAll:
	// Fill in the catch-all handler.
	*dstFilter++ = &Standard::get(cThrowable);
	bt.linkPredecessor(*successor, *dstSuccessor, getEnv(), canOwnEnv);

	cn->setControlException(ck, dstFilter - filters, filters, tryPrimitive, successors);
}


//
// Generate an unconditional throw of the given exception, which is guaranteed not to
// have a null value.  The exception's class must be a subclass of exceptionClass, which
// must be a subclass of Throwable; exceptionClass is not checked for integrity.
//
// Set cn to nil to indicate that no more control nodes should be generated.
//
// This routine assumes ownership of translationEnv if canOwnEnv is true (thereby sometimes eliminating
// an unnecessary copy).
//
void BytecodeTranslator::BlockTranslator::genThrowCommon(const VariableOrConstant &exception, const Class &exceptionClass,
														 bool canOwnEnv)
{
	// asharma - fix me
	Primitive &prim = makeSysCall(scThrow, 0, 1, &exception, 0, 0, *cn, 0);
	genException(ckThrow, &prim, exceptionClass, canOwnEnv);
	cn = 0;
}


//
// Generate an unconditional throw of the given exception, which is a system-defined
// instance of Throwable or one of its subclasses; exceptionObject is not checked for
// integrity.  Set cn to nil to indicate that no more control nodes should be generated.
//
// This routine assumes ownership of translationEnv if canOwnEnv is true (thereby sometimes eliminating
// an unnecessary copy).
//
void BytecodeTranslator::BlockTranslator::genSimpleThrow(cobj exceptionObject, bool canOwnEnv)
{
	VariableOrConstant exception;
	exception.setConstant(objectAddress(exceptionObject));
	genThrowCommon(exception, exceptionObject->getClass(), canOwnEnv);
}


//
// Generate an exc node that indicates that prim might throw an exception
// of the given class or one of its subclasses; exceptionClass must be Throwable
// or one of its subclasses and is not checked for integrity.
// prim is the primitive inside cn that can throw exceptions.  There must be no
// other primitives in cn that rely on prim's outgoing data edge, if any.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock;
// that control node is always empty.
//
// This routine does not assume ownership of translationEnv.
//
void BytecodeTranslator::BlockTranslator::genPossibleThrow(Primitive &prim, const Class &exceptionClass)
{
	genException(ckExc, &prim, exceptionClass, false);
	appendControlNode(cn->getNormalSuccessor());
}


//
// Make cn into a basic block control node.  Allocate its ControlExtra record
// and link it to the successor BasicBlock.
// Set cn to nil to indicate that no more control nodes should be generated.
//
// If the basic block would be empty and have only one predecessor, eliminate it
// and instead link the successor to the predecessor.
//
void BytecodeTranslator::BlockTranslator::createBasicBlock(BasicBlock &successor)
{
	ControlEdge *edge;

	if (cn->empty() && cn->getPredecessors().lengthIs(1)) {
		// Eliminate this basic block and recycle its ControlNode.
		edge = &cn->getPredecessors().first();
		assert(block.getGeneratedControlNodes());
		if (block.getFirstControlNode() == cn)
			block.getFirstControlNode() = 0;
		edge->clearTarget();	// Clear cn's predecessor linked list.
		getControlGraph().recycle(*cn);
	} else {
		cn->setControlBlock();
		edge = &cn->getNormalSuccessor();
	}
	bt.linkPredecessor(successor, *edge, *translationEnv, true);
	cn = 0;
}


//
// Make cn into an IF control node.  Allocate its ControlExtra record and
// link it to the successor BasicBlocks.  c contains the condition variable.
// If c satisfies cond2 (or reverse(cond2) if reverseCond2 is true), the IF
// will branch to the true successor; otherwise, it will branch to the false
// successor.  On exit set cn to nil.
//
void BytecodeTranslator::BlockTranslator::createIf(Condition2 cond2, 
												   bool reverseCond2,
												   VariableOrConstant &c,
												   BasicBlock &successorFalse,
												   BasicBlock &successorTrue,
												   Uint32 bci)
{
	if (reverseCond2)
		cond2 = reverse(cond2);

	bool constResult;
	DataNode *cp = partialComputeComparison(cond2, c, constResult);
	if (cp) {
		// The value of the selector is not known at compile time.
		cn->setControlIf(cond2, *cp, bci);
		bt.linkPredecessor(successorTrue, cn->getTrueSuccessor(), *translationEnv, false);
		bt.linkPredecessor(successorFalse, cn->getFalseSuccessor(), *translationEnv, true);
		cn = 0;
	} else
		// The comparison result is known at compile time.
		createBasicBlock(constResult ? successorTrue : successorFalse);
}


//
// Same as createIf except that if the selector is false, continue processing this
// BytecodeBlock using the new control node in cn.  If the selector is true, go to
// successorTrue as in createIf.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock or
// nil if the selector is known to always be true.
//
void 
BytecodeTranslator::BlockTranslator::createContinuedIf(Condition2 cond2, 
													   bool reverseCond2, 
													   VariableOrConstant &c,
													   BasicBlock &successorTrue, 
													   Uint32 bci)   
{
	if (reverseCond2)
		cond2 = reverse(cond2);

	bool constResult;
	DataNode *cp = partialComputeComparison(cond2, c, constResult);
	if (cp) {
		// The value of the selector is not known at compile time.
		cn->setControlIf(cond2, *cp, bci);
		bt.linkPredecessor(successorTrue, cn->getTrueSuccessor(), *translationEnv, false);
		appendControlNode(cn->getFalseSuccessor());
	} else if (constResult)
		// The condition is always true.
		createBasicBlock(successorTrue);
}


//
// Create control and data flow nodes to make sure that arg (which must have
// pointer kind) is non-null.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock or
// nil if the rest of this BytecodeBlock is dead.
//
void BytecodeTranslator::BlockTranslator::genNullGuard(const VariableOrConstant &arg, Uint32 bci)
{
	Primitive *prim;

	switch (makeChkNull(arg, prim, cn, bci)) {
		case chkAlwaysOK:
			break;
		case chkNeverOK:
			genSimpleThrow(&Standard::get(oNullPointerException), true);
			break;
		default:
			genPossibleThrow(*prim, Standard::get(cNullPointerException));
	}
}


//
// Create control and data flow nodes for a tableswitch bytecode.
// bc points immediately after the tableswitch opcode.
//
// Set cn to nil to indicate that no more control nodes should be generated.
//
void BytecodeTranslator::BlockTranslator::genTableSwitch(const bytecode *bc,
														 Uint32 bci)
{
	VariableOrConstant arg1;
	VariableOrConstant arg2;
	VariableOrConstant arg3;
	TranslationEnv &env = *translationEnv;

	env.pop().extract(arg1, bci);
	bc = BytecodeGraph::switchAlign(bc) + 4;	// Skip past padding and default target.
	Int32 low = readBigSWord(bc);
	Int32 high = readBigSWord(bc + 4);
	bc += 8;
	assert(low <= high);
	Uint32 nCases = high - low + 1;
	bc += nCases * 4;
	assert(bc == block.bytecodesEnd);
	assert(block.nSuccessors() == nCases + 1);

	// Do the range check; jump to the default case if out of range.
	builder_AddCoal_III.specializeArgConst(arg1, -low, arg2, cn);
	Primitive *prim = builder_CmpU_IIC.specializeArgConst(arg2, (Int32)nCases, arg3, cn);
	createContinuedIf(condGe, prim != 0, arg3, block.getSuccessor(0), bci);

	BasicBlock **successorsEnd = block.successorsEnd;
	BasicBlock **nextSuccessor = block.successorsBegin + 1;
	if (cn)
		if (arg2.isConstant())
			// The switch argument is a constant, so go directly to the corresponding target.
			createBasicBlock(block.getSuccessor(1 + arg2.getConstant().i - low));
		else {
			// The value of the switch argument is not known at compile time.
			cn->setControlSwitch(arg2.getVariable(), nCases, bci);
			ControlEdge *ce = cn->getSwitchSuccessors();
			while (nextSuccessor != successorsEnd)
				bt.linkPredecessor(**nextSuccessor++, *ce++, env, false);
			cn = 0;
		}
}


//
// Create control and data flow nodes for a lookupswitch bytecode.
// bc points immediately after the lookupswitch opcode.
//
// Set cn to nil to indicate that no more control nodes should be generated.
//
void BytecodeTranslator::BlockTranslator::genLookupSwitch(const bytecode *bc,
														  Uint32 bci)
{
	VariableOrConstant arg;

	translationEnv->pop().extract(arg, bci);
	bc = BytecodeGraph::switchAlign(bc) + 4;	// Skip past padding and default target.
	Uint32 nPairs = readBigUWord(bc);
	bc += 4;
	assert(block.nSuccessors() == nPairs + 1);
	if (nPairs == 0)
		createBasicBlock(block.getSuccessor(0));
	else {
		BasicBlock **nextSuccessor = block.successorsBegin + 1;
		while (true) {
			VariableOrConstant result;
			Int32 match = readBigSWord(bc);
			bc += 8;
			Primitive *prim = builder_CmpEq_IIC.specializeArgConst(arg, match, result, cn);
			nPairs--;
			if (nPairs) {
				createContinuedIf(condEq, prim != 0, result,
								  **nextSuccessor++, bci);
				if (!cn) {
					// We're done early.
					bc += nPairs * 8;
					break;
				}
			} else {
				createIf(condEq, prim != 0, result, block.getSuccessor(0),
						 **nextSuccessor, bci);
				break;
			}
		}
	}
	assert(bc == block.bytecodesEnd);
}


//
// Create data flow nodes to read the type of an object.  The object pointer should
// already have been checked to make sure it is not null.
//
inline void 
BytecodeTranslator::BlockTranslator::genReadObjectType(const VariableOrConstant &object, VariableOrConstant &type, Uint32 bci) const {
	assert(objectTypeOffset == 0);
	builder_Ld_AA.makeLoad(0, object, type, false, true, cn, bci);
}


//
// Create data flow nodes for a getstatic bytecode.
// cpi is the constant table index of the static variable entry.
//
void BytecodeTranslator::BlockTranslator::genGetStatic(ConstantPoolIndex cpi, Uint32 bci) const
{
	ValueKind vk;
	addr address;
	bool isVolatile;
	bool isConstant;
	TypeKind tk = classFileSummary.lookupStaticField(cpi, vk, address, isVolatile, isConstant);
	TranslationEnv &env = *translationEnv;

	DataNode *memory = &env.memory().extract(bci);
	VariableOrConstant result;
	loadBuilders[tk]->makeLoad(&memory, address, result, isVolatile,
							   isConstant, cn, bci);
	env.memory().define(*memory);
	env.push1or2(isDoublewordKind(vk)).define(result, cn, envPool);
}


//
// Create data flow nodes for a putstatic bytecode.
// cpi is the constant table index of the static variable entry.
//
void BytecodeTranslator::BlockTranslator::genPutStatic(ConstantPoolIndex cpi,
													   Uint32 bci) const
{
	ValueKind vk;
	addr address;
	bool isVolatile;
	bool isConstant;
	TypeKind tk = classFileSummary.lookupStaticField(cpi, vk, address, isVolatile, isConstant);
	TranslationEnv &env = *translationEnv;

	if (isConstant)
		verifyError(VerifyError::writeToConst);
	VariableOrConstant a;
	a.setConstant(address);
	VariableOrConstant value;
	env.pop1or2(isDoublewordKind(vk)).extract(value, bci);
	Primitive &memoryOut = storeBuilders[tk]->makeStore(env.memory().extract(bci), a, value,
														isVolatile, cn, bci);
	env.memory().define(memoryOut);
}


//
// Create control and data flow nodes for a getfield bytecode.
// cpi is the constant table index of the field entry.
//
// Set cn to a control node to use for the next statement of this BytecodeBlock or
// nil if the rest of this BytecodeBlock is dead.
//
void BytecodeTranslator::BlockTranslator::genGetField(ConstantPoolIndex cpi,
													  Uint32 bci)
{
	ValueKind vk;
	Uint32 offset;
	bool isVolatile;
	bool isConstant;
	TypeKind tk = classFileSummary.lookupInstanceField(cpi, vk, offset, isVolatile, isConstant);
	TranslationEnv &env = *translationEnv;

	VariableOrConstant objectAddr;
	env.pop().extract(objectAddr, bci);
	genNullGuard(objectAddr, bci);
	if (cn) {
		// Get the address of the field.
		VariableOrConstant fieldAddr;
		builder_Add_AIA.specializeArgConst(objectAddr, (Int32)offset, fieldAddr, cn);

		// Emit the load instruction.
		DataNode *memory = &env.memory().extract(bci);
		VariableOrConstant result;
		loadBuilders[tk]->makeLoad(&memory, fieldAddr, result, isVolatile, isConstant, cn, bci);
		env.memory().define(*memory);
		env.push1or2(isDoublewordKind(vk)).define(result, cn, envPool);
	}
}


//
// Create control and data flow nodes for a putfield bytecode.
// cpi is the constant table index of the field entry.
//
// Set cn to a control node to use for the next statement of this BytecodeBlock or
// nil if the rest of this BytecodeBlock is dead.
//
void BytecodeTranslator::BlockTranslator::genPutField(ConstantPoolIndex cpi,
													  Uint32 bci)
{
	ValueKind vk;
	Uint32 offset;
	bool isVolatile;
	bool isConstant;
	TypeKind tk = classFileSummary.lookupInstanceField(cpi, vk, offset, isVolatile, isConstant);
	TranslationEnv &env = *translationEnv;

	if (isConstant)
		verifyError(VerifyError::writeToConst);
	VariableOrConstant value;
	VariableOrConstant objectAddr;
	env.pop1or2(isDoublewordKind(vk)).extract(value, bci);
	env.pop().extract(objectAddr, bci);
	genNullGuard(objectAddr, bci);
	if (cn) {
		// Get the address of the field.
		VariableOrConstant fieldAddr;
		builder_Add_AIA.specializeArgConst(objectAddr, (Int32)offset, fieldAddr, cn);

		// Emit the store instruction.
		Primitive &memoryOut =
		storeBuilders[tk]->makeStore(env.memory().extract(bci), fieldAddr,
									 value, isVolatile, cn, bci);
		env.memory().define(memoryOut);
	}
}


//
// Create control and data flow nodes to read the length of an array.
// Make sure that arrayAddr isn't nil and return the array length in arrayLength.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock or
// nil if the rest of this BytecodeBlock is dead.
//
void BytecodeTranslator::BlockTranslator::genReadArrayLength(const VariableOrConstant &arrayAddr, VariableOrConstant &arrayLength, Uint32 bci)
{
	genNullGuard(arrayAddr, bci);
	if (cn) {
		// Get the address of the field.
		VariableOrConstant fieldAddr;
		builder_Add_AIA.specializeArgConst(arrayAddr, arrayLengthOffset, fieldAddr, cn);

		// Emit the load instruction.
		builder_Ld_AI.makeLoad(0, fieldAddr, arrayLength, false, true, cn, bci);
	}
}


//
// Create control and data flow nodes to make sure that the object can be
// written into the object array, which should already have been checked to
// make sure it is not null.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock or
// nil if the rest of this BytecodeBlock is dead.
//
void BytecodeTranslator::BlockTranslator::genArrayCastGuard(const VariableOrConstant &array, const VariableOrConstant &object)
{
	assert(object.hasKind(vkAddr) && array.hasKind(vkAddr));
	// We can write nil into any object array so we don't bother issuing a check
	// if we know that we're writing a nil.
	if (!object.isConstant() || !object.getConstant().a) {
		// Do we know the actual types of both the object and the array?
		Type *objectType = object.getDynamicType();
		if (objectType) {
			Type *arrayType = array.getDynamicType();
			if (arrayType) {
				// Yes.  Perform the check statically.
				assert(arrayType->typeKind == tkArray);
				if (!implements(*objectType, static_cast<Array *>(arrayType)->componentType))
					genSimpleThrow(&Standard::get(oArrayStoreException), true);
				return;
			}
		}

		VariableOrConstant args[2];
		args[0] = array;
		args[1] = object;
		// asharma - fix me
		Primitive &prim = makeSysCall(scCheckArrayStore, 0, 2, args, 0, 0, *cn, 0);
		genPossibleThrow(prim, Standard::get(cArrayStoreException));
	}
}


//
// Create control and data flow nodes for an array read or write bytecode.
// If write is true, the access is a write; otherwise it's a read.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock or
// nil if the rest of this BytecodeBlock is dead.
//
void BytecodeTranslator::BlockTranslator::genArrayEltAccess(TypeKind tk, bool
															write, Uint32 bci)
{
	VariableOrConstant value;
	VariableOrConstant index;
	VariableOrConstant length;	// Array length
	VariableOrConstant arrayAddrAndOffset[2];	// [0] is array address; [1] is index times element size
	TranslationEnv &env = *translationEnv;

	if (write)
		env.pop1or2(isDoublewordKind(tk)).extract(value, bci);
	env.pop().extract(index, bci);
	env.pop().extract(arrayAddrAndOffset[0], bci);
	genReadArrayLength(arrayAddrAndOffset[0], length, bci);

	if (cn) {
		// Check bounds
		Primitive *prim;
		CheckResult chkRes = makeLimit(index, length, prim, cn);
		if (chkRes == chkNeverOK)
			genSimpleThrow(&Standard::get(oArrayIndexOutOfBoundsException), true);
		else {
			if (chkRes != chkAlwaysOK)
				genPossibleThrow(*prim, Standard::get(cArrayIndexOutOfBoundsException));

			// Check cast if needed
			assert(isPrimitiveKind(tk) || tk == tkObject);
			if (write && tk == tkObject)
				genArrayCastGuard(arrayAddrAndOffset[0], value);

			if (cn) {
				// Get the address of the element.
				VariableOrConstant elementAddr;
				builder_Shl_III.specializeArgConst(index, getLgTypeKindSize(tk), arrayAddrAndOffset[1], cn);
				builder_Add_AIA.makeBinaryGeneric(arrayAddrAndOffset, elementAddr, cn);
				builder_AddCoal_AIA.specializeArgConst(elementAddr, arrayEltsOffset(tk), elementAddr, cn);

				DataNode *memory = &env.memory().extract(bci);
				if (write)
					// Emit the store instruction.
					env.memory().define(storeBuilders[tk]->makeStore(*memory, elementAddr, value, false, cn, bci));
				else {
					// Emit the load instruction.
					loadBuilders[tk]->makeLoad(&memory, elementAddr, value, false, false, cn, bci);
					env.push1or2(isDoublewordKind(tk)).define(value, cn, envPool);
				}
			}
		}
	}
}


//
// Create data flow nodes to check if a reference with class pointed
// at by the type argument is assignable to another reference of type
// targetInterface, which is either an interface type or the type of
// an array of interfaces.  type should be a variable, not a constant.
//
// results should be an array of two VariableOrConstants.  On exit
// results[0] and results[1] will be initialized to two integer variables
// that, if equal, indicate that the interface check succeeds and,
// if not equal, indicate that the interface check fails.
// 
void BytecodeTranslator::BlockTranslator::genCheckInterfaceAssignability(VariableOrConstant &type, const Type &targetInterface,
																		 VariableOrConstant *results, Uint32 bci) const
{
	assert(cn && type.isVariable());

    // Get the address of the class-specific interface assignability table used
    // to determine whether an instance of that class can be assigned to a
    // given interface (or interface array) type.
    VariableOrConstant vPointerToAssignableTableAddr;
    builder_Add_AIA.specializeArgConst(type, offsetof(Type, interfaceAssignableTable), vPointerToAssignableTableAddr, cn);
    VariableOrConstant vAssignableTableAddr;
    builder_Ld_AA.makeLoad(0, vPointerToAssignableTableAddr, vAssignableTableAddr, false, true, cn, bci);
    
    // Compute the address of the interface assignability table entry
    // corresponding to the given interface.
    Uint32 interfaceNumber = targetInterface.getInterfaceNumber();
    VariableOrConstant vAssignableTableEntryAddr;
    builder_Add_AIA.specializeArgConst(vAssignableTableAddr, interfaceNumber * sizeof(Uint16), vAssignableTableEntryAddr, cn);
    
    // Load the selected table entry, which will contain a value that we must match against
    VariableOrConstant &vAssignableValue = results[0];
    VariableOrConstant &vMatchValue = results[1];
    builder_LdU_AH.makeLoad(0, vAssignableTableEntryAddr, vAssignableValue, false, true, cn, bci);
    
    // Load the class-specific match value for comparison with the value found in the table
    VariableOrConstant vAddrOfAssignableMatchValue;
	builder_Add_AIA.specializeVarConst(type.getVariable(), offsetof(Type, assignableMatchValue), vAddrOfAssignableMatchValue, cn);
    builder_LdU_AH.makeLoad(0, vAddrOfAssignableMatchValue, vMatchValue, false, true, cn, bci);
}


//
// Create control and data flow nodes for a checkcast bytecode that checks
// that object arg is a member of type t.  Type t is guaranteed not to be Object,
// and arg is guaranteed to be nonnull.
//
// Set cn to a new, empty node to use for the next portion of this BytecodeBlock or
// to nil if an exception is always thrown.
//
void BytecodeTranslator::BlockTranslator::genCheckCastNonNull(const Type &t, const VariableOrConstant &arg, Uint32 bci)
{
	assert(!isPrimitiveKind(t.typeKind));

	VariableOrConstant type;
	genReadObjectType(arg, type, bci);

	if (type.isConstant()) {
		// We determined the type of arg at compile time.  Do nothing if it a subtype of t;
		// otherwise, always throw ClassCastException.
		if (!implements(addressAsType(type.getConstant().a), t))
			genSimpleThrow(&Standard::get(oClassCastException), true);
	} else {
		DataNode &dp = type.getVariable();
		Primitive *prim;

        if (t.final)
			// We're testing against a final type.  Emit a simple equality test
			// that ensures that arg is the same as the given final type.
			prim = makeChkCastA(dp, t, cn);
        else if ((t.typeKind == tkObject) ||
                 ((t.typeKind == tkArray) && (asArray(t).getElementType().typeKind != tkInterface))) {

			// We're testing against an object or an array type that is not an array of
			// interfaces.  Emit a vtable-based test that passes the given type and its subtypes.
			// The given type and each of its subtypes will have a pointer to type t
			// in the ventry at index nVTableSlots-1.

			// Make sure that we have a sufficient number of vEntries.
			VariableOrConstant nVEntriesAddr;
			builder_Add_AIA.specializeVarConst(dp, offsetof(Type, nVTableSlots), nVEntriesAddr, cn);
			VariableOrConstant nVEntries;
			builder_Ld_AI.makeLoad(0, nVEntriesAddr, nVEntries, false, true, cn, bci);
			Primitive *limPrim;
			CheckResult chkRes = makeLimCast(nVEntries, t.nVTableSlots, limPrim, cn);
			if (chkRes == chkNeverOK) {
				genSimpleThrow(&Standard::get(oClassCastException), true);
				return;
			}
			if (chkRes != chkAlwaysOK)
				genPossibleThrow(*limPrim, Standard::get(cClassCastException));

			// Get the value of the vEntry at index nVTableSlots-1.
			VariableOrConstant vEntryAddr;
			builder_Add_AIA.specializeVarConst(dp, vTableIndexToOffset(t.nVTableSlots - 1), vEntryAddr, cn);
			VariableOrConstant vEntryValue;
			builder_Ld_AA.makeLoad(0, vEntryAddr, vEntryValue, false, true, cn, bci);

			// Emit a test to make sure that the vEntry value is the type we desire.
			prim = makeChkCastA(vEntryValue.getVariable(), t, cn);
		} else {
			// We're testing against an interface or an array whose element type is an interface.
			assert((t.typeKind == tkInterface) || ((t.typeKind == tkArray) && (asArray(t).getElementType().typeKind == tkInterface)));

			// Generate a runtime assignability check
			VariableOrConstant cmpArgs[2];
			genCheckInterfaceAssignability(type, t, cmpArgs, bci);
			prim = makeChkCastI(cmpArgs[0].getVariable(), cmpArgs[1].getVariable(), cn);
 		}
	    genPossibleThrow(*prim, Standard::get(cClassCastException));
	}
}


//
// Create control and data flow nodes for a checkcast bytecode that checks
// that object arg satisfies the type represented by cpi.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock or
// nil if the checkcast always throws an exception.
//
void BytecodeTranslator::BlockTranslator::genCheckCast(ConstantPoolIndex cpi, const VariableOrConstant &arg, Uint32 bci)
{
	const Type &t = classFileSummary.lookupType(cpi);

	// A cast to the type Object always succeeds.
	if (&t != &Standard::get(cObject)) {
		// Try to statically check whether the object is null.
		bool constResult;
		VariableOrConstant cond;
		builder_CmpUEq_AAC.specializeArgConst(arg, nullAddr, cond, cn);
		DataNode *cp = partialComputeComparison(condEq, cond, constResult);
		if (cp) {
			// We have to check whether the object is null at runtime.
			ControlNode *cnIf = cn;
			cnIf->setControlIf(condEq, *cp, bci);

			// Create a new ControlNode to hold the check code.
			appendControlNode(cnIf->getFalseSuccessor());
			genCheckCastNonNull(t, arg, bci);
			if (!cn)
				cn = &getControlGraph().newControlNode();

			// Attach the true arm of the if to the latest control node, which should
			// be empty at this point.
			assert(cn->empty());
			cn->addPredecessor(cnIf->getTrueSuccessor());
		} else
			// The object is either always or never null.  If it's always null, don't
			// bother emitting any code.
			if (!constResult)
				// The object is never null.
				genCheckCastNonNull(t, arg, bci);
	}
}


//
// Create control and data flow nodes for an instanceof bytecode that checks
// whether object arg is a member of type t and returns the int result (1 if arg is
// a member of type t, 0 if not) in result.  Type t is guaranteed not to be Object,
// and arg is guaranteed to be nonnull.
// cnFalse is either nil or a pointer to a control node that will store false in the
// result.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock.
// The outgoing cn will never be nil.
//
void BytecodeTranslator::BlockTranslator::genInstanceOfNonNull(const Type &t, const VariableOrConstant &arg, VariableOrConstant &result, ControlNode *cnFalse, Uint32 bci)
{
	assert(!isPrimitiveKind(t.typeKind));

	VariableOrConstant type;
	genReadObjectType(arg, type, bci);

	if (type.isConstant())
		// We determined the type of arg at compile time.
		// Return the constant 0 or 1, as appropriate.
		result.setConstant((Int32)implements(addressAsType(type.getConstant().a), t));

	else {
		DataNode &dp = type.getVariable();
		VariableOrConstant args[2];
		args[0].setVariable(dp);
		args[1].setConstant(objectAddress(&t));

		if (t.final)
			// We're testing against a final type.  Emit a simple equality test
			// that checks whether arg is the same as the given final type.
			builder_Eq_AAI.makeBinaryGeneric(args, result, cn);

		else if ((t.typeKind == tkObject) ||
                 ((t.typeKind == tkArray) && (asArray(t).getElementType().typeKind != tkInterface))) {

            // We're testing against an object or an array type where the elements
            // of the array are not interfaces.
			// Emit a vtable-based test that passes the given type and its subtypes.
			// The given type and each of its subtypes will have a pointer to type t
			// in the ventry at index nVTableSlots-1.

			// Make sure that we have a sufficient number of vEntries.
			VariableOrConstant nVEntriesAddr;
			builder_Add_AIA.specializeVarConst(dp, offsetof(Type, nVTableSlots), nVEntriesAddr, cn);
			VariableOrConstant nVEntries;
			builder_Ld_AI.makeLoad(0, nVEntriesAddr, nVEntries, false, true, cn, bci);

			// Emit the comparison and if node.
			VariableOrConstant argCmp;
			Primitive *reverseCmp = builder_Cmp_IIC.specializeArgConst(nVEntries, t.nVTableSlots, argCmp, cn);
			Condition2 cond2 = reverseCmp ? condGt : condLt;
			bool constResult;
			DataNode *cp = partialComputeComparison(cond2, argCmp, constResult);
			bool needJoin = false;
			if (!cp) {
                // The result of the if is known at compile time.
                //   (This should not be possible, because we've already
                //   tested for a type known at compile-time, above, but
                //   this code might be purposeful in the future.)
				if (constResult) {
					// The if is always true, so the result is always false.
					result.setConstant((Int32)0);
					return;
				}
				// The if is always false, so don't emit the if.
			} else {
				ControlNode *cnIf = cn;
				cnIf->setControlIf(cond2, *cp, bci);

				// Create a new control node for the false branch of the if and store it in cn.
				appendControlNode(cnIf->getFalseSuccessor());
				if (!cnFalse) {
					cnFalse = &getControlGraph().newControlNode();
					needJoin = true;
				}
				cnFalse->addPredecessor(cnIf->getTrueSuccessor());
			}

			// Get the value of the vEntry at index nVTableSlots-1.
			VariableOrConstant vEntryAddr;
			builder_Add_AIA.specializeVarConst(dp, vTableIndexToOffset(t.nVTableSlots - 1), vEntryAddr, cn);
			builder_Ld_AA.makeLoad(0, vEntryAddr, args[0], false, true, cn, bci);

			// Emit a test to make sure that the vEntry value is the type we desire.
			builder_Eq_AAI.makeBinaryGeneric(args, result, cn);

			// If we created our own control node for the true branch of the if, we must now join it
			// with the control flow leaving the false branch.
			if (needJoin) {
				ControlNode *predecessors[2];
				args[0] = result;
				args[1].setConstant((Int32)0);
				predecessors[0] = cn;
				predecessors[1] = cnFalse;
				cn = &joinControlFlows(2, predecessors, getControlGraph());
				joinDataFlows(2, *cn, args, result);
			}

        } else {
			// We're testing against an interface or an array whose element type is an interface.
			assert((t.typeKind == tkInterface) || ((t.typeKind == tkArray) && (asArray(t).getElementType().typeKind == tkInterface)));

			VariableOrConstant cmpArgs[2];
			genCheckInterfaceAssignability(type, asInterface(t), cmpArgs, bci);
        	builder_Eq_III.makeBinaryGeneric(cmpArgs, result, cn);
        }
	}
}


//
// Create control and data flow nodes for an instanceof bytecode that checks
// whether object arg is a member of the type represented by cpi.  However,
// unlike checkcast, nil is not considered to be a member of any type.
// The result VariableOrConstant gets an int result that is 1 if arg is a member
// of the type or 0 if not.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock.
// The outgoing cn will never be nil.
//
void BytecodeTranslator::BlockTranslator::genInstanceOf(ConstantPoolIndex cpi, const VariableOrConstant &arg, VariableOrConstant &result, Uint32 bci)
{
	const Type &t = classFileSummary.lookupType(cpi);

	if (&t == &Standard::get(cObject))
		// "x instanceof Object" succeeds if and only if x is non-nil.
		builder_Ne0_AI.makeUnaryGeneric(arg, result, cn);
	else {
		// Try to statically check whether the object is null.
		bool constResult;
		VariableOrConstant cond;
		builder_CmpUEq_AAC.specializeArgConst(arg, nullAddr, cond, cn);
		DataNode *cp = partialComputeComparison(condEq, cond, constResult);
		if (cp) {
			// We have to check whether the object is null at runtime.
			ControlNode *cnIf = cn;
			cnIf->setControlIf(condEq, *cp, bci);

			// Create a new ControlNode to hold the instanceof code for the null case.
			VariableOrConstant args[2];
			ControlNode *predecessors[2];
			appendControlNode(cnIf->getTrueSuccessor());
			args[1].setConstant((Int32)0);
			predecessors[1] = cn;

			// Create a new ControlNode to hold the instanceof code for the non-null case.
			appendControlNode(cnIf->getFalseSuccessor());
			genInstanceOfNonNull(t, arg, args[0], predecessors[1], bci);
			predecessors[0] = cn;

			// Merge the outputs of the above two ControlNodes.
			cn = &joinControlFlows(2, predecessors, getControlGraph());
			joinDataFlows(2, *cn, args, result);
		} else
			// The object is either always or never null.
			if (constResult)
				// The object is always null.
				result.setConstant((Int32)0);
			else
				// The object is never null.
				genInstanceOfNonNull(t, arg, result, 0, bci);
	}
}


//
// Create control and data flow nodes for a system call that receives
// a memory argument together with the given arguments and outputs a new
// memory state together with one one-word result and can throw any exception.
// Push the result onto the environment.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock.
//
void BytecodeTranslator::BlockTranslator::genNewCommon(const SysCall &sysCall, uint nArgs, const VariableOrConstant *args, Uint32 bci)
{
	VariableOrConstant result;
	TranslationEnv &env = *translationEnv;
	DataNode *memory = &env.memory().extract(bci);
	Primitive &prim = makeSysCall(sysCall, &memory, nArgs, args, 1, &result, *cn, bci);
	env.memory().define(*memory);
	env.push().define(result.getVariable()); // OK because result cannot be a constant here.
	genPossibleThrow(prim, Standard::get(sysCall.exceptionClass));
}


//
// Create code to allocate a temporary array for storing all the dimensions
// of a multi-dimensional array, which is pushed onto the environment.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock or
// nil if the rest of this BytecodeBlock is dead.
//
void BytecodeTranslator::BlockTranslator::genTempArrayOfDim(Int32 dim, Uint32 bci)
{
	VariableOrConstant args[2], arg, *dimargs;
	Int32 i;
	TranslationEnv &env = *translationEnv;

	// Pull all the dimensions out of the environment.
	dimargs = new(primitivePool) VariableOrConstant[dim];
	for (i=dim-1; i>=0; i--) {
		env.pop().extract(dimargs[i], bci);
		// check for negative dimension here
		assert(dimargs[i].hasKind(vkInt));
		if (dimargs[i].isConstant() && dimargs[i].getConstant().i < 0) {
			genSimpleThrow(&Standard::get(oNegativeArraySizeException), true);
			return;
		}
	}
	args[0].setConstant(dim);  // the number of ints to allocate
	genNewCommon(*typeToArrayCalls[tkInt], 1, args, bci);
	env.pop().extract(args[0], bci); // array now stored in args[0]
	// Now loop through dimensions and generate code to fill the array.
	// We need to do the following:
	// for each argument (picked from the environment in reverse order), 
	// store it in the array using the code for iastore 
	// (genArrayEltAccess(tkInt, 1)).
	// We proceed by pushing the array, followed by i, and dimargs[i].
	// Then, generate a call to genArrayEltAccess().
	// Return the resulting control node.
	for (i=0; i<dim; i++) {
		env.push().define(args[0], cn, envPool); // arr. WASTE!
		arg.setConstant(i);
		env.push().define(arg, cn, envPool); // i.
		env.push().define(dimargs[i], cn, envPool); // ith dimension
		genArrayEltAccess(tkInt, 1, bci);
	}
	env.push().define(args[0], cn, envPool);
}


//
// Create control and data flow nodes for a monitor call that receives a memory
// argument together with the given argument (the pointer to the object being
// acquired or released) and outputs a new memory state.  Set the primitive's slot
// to unknown for now.
//
Primitive &BytecodeTranslator::BlockTranslator::genMonitor(PrimitiveOperation op, const VariableOrConstant &arg, Uint32 bci) const
{
	assert(cn);
	TranslationEnv &env = *translationEnv;
	Primitive &prim = makeMonitorPrimitive(op, env.memory().extract(bci), arg, PrimMonitor::unknownSlot, cn, bci);
	env.memory().define(prim);
	return prim;
}


//
// Generate an unconditional throw of the given exception.  If the exception is null,
// throw NullPointerException instead.  Set cn to nil to indicate that no more control
// nodes should be generated.
//
// This routine assumes ownership of translationEnv.
//
void BytecodeTranslator::BlockTranslator::genThrow(const VariableOrConstant &exception)
{
	// asharma - fix me
	genNullGuard(exception, 0);
	if (cn)
		// We don't know the class of the exception object here, so conservatively assume Throwable.
		// A more detailed dataflow analysis might narrow down the possibilities.
		genThrowCommon(exception, Standard::get(cThrowable), true);
}


//
// Generate a null check for the receiver of a virtual or interface call.
// Return the receiver.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock or
// nil if the rest of this BytecodeBlock is dead because the receiver is always null.
//
void BytecodeTranslator::BlockTranslator::genReceiverNullCheck(const Signature &sig, VariableOrConstant &receiver, Uint32 bci)
{
	translationEnv->stackNth(sig.nArgumentSlots()).extract(receiver, bci);
	genNullGuard(receiver, bci);
}


//
// Generate code to perform a virtual method lookup.  The receiver object
// is the "this" object and is guaranteed to be nonnull.  vIndex is the index
// (not offset!) of the virtual table entry.
// Store the looked-up function address in functionAddr.
//
void BytecodeTranslator::BlockTranslator::genVirtualLookup(const VariableOrConstant &receiver, Uint32 vIndex,
														   VariableOrConstant &functionAddr, Uint32 bci) const
{
	VariableOrConstant type;
	genReadObjectType(receiver, type, bci);

	// Get the address of the vEntry.
	VariableOrConstant vEntryAddr;
	builder_Add_AIA.specializeArgConst(type, vTableIndexToOffset(vIndex), vEntryAddr, cn);

	// Emit the load instruction.
	builder_Ld_AA.makeLoad(0, vEntryAddr, functionAddr, false, true, cn, bci);
}


//
// Generate code to perform an interface method lookup.  The receiver object
// is the "this" object and is guaranteed to be nonnull.  vIndex is the index
// (not offset!) of the virtual table entry.
// Store the looked-up function address in functionAddr.
//
void BytecodeTranslator::BlockTranslator::genInterfaceLookup(const VariableOrConstant &receiver, 
															 Uint32 interfaceNumber, 
															 Uint32 vIndex, 
															 const Method *interfaceMethod, 
															 VariableOrConstant &functionAddr, 
															 Uint32 bci) const
{
	VariableOrConstant type;
	genReadObjectType(receiver, type, bci);

    // Check for a receiver object of type known at compile-time.
    // In this case, we can statically determine the method within the
    // receiver's type that implements the interface method.
	if (type.isConstant()) {
        Type &receiverType = addressAsType(type.getConstant().a);
        ClassFileSummary *receiverSummary = NULL;

        if (receiverType.typeKind == tkObject) {
            receiverSummary = asClass(receiverType).summary;
        } else {
            assert(receiverType.typeKind == tkArray);
            /* Arrays never have interface methods */
            verifyError(VerifyError::noSuchMethod);
        }

        // Get the class method that implements the given interface method
        addr a;
        Uint32 vIndex;
        const Method *method;
        method = receiverSummary->lookupImplementationOfInterfaceMethod(interfaceMethod, vIndex, a);
        if (!method)
			verifyError(VerifyError::noSuchMethod);

        // Generate normal virtual function dispatch or set function address if it's
        //   known at compile-time.
        if (method)
            functionAddr.setConstant(a);
        else
            genVirtualLookup(receiver, vIndex, functionAddr, bci);

	} else {

		VariableOrConstant vVars[2];
		VariableOrConstant &vSubVTableOffset = vVars[1];
		VariableOrConstant &vEntryOffset = vVars[0];

		// Get the address of the class-specific interface table used to locate
		// the sub-vtable dedicated to the given interface within the class' vtable
		VariableOrConstant vPointerToInterfaceTableAddr;
		builder_Add_AIA.specializeArgConst(type, offsetof(Type, interfaceVIndexTable),
		                                   vPointerToInterfaceTableAddr, cn);
		VariableOrConstant vInterfaceTableAddr;
		builder_Ld_AA.makeLoad(0, vPointerToInterfaceTableAddr, vInterfaceTableAddr, false, true, cn, bci);

		// Compute the address of the interface table entry corresponding to the
		// given interface.
		VariableOrConstant vInterfaceTableEntryAddr;
		assert(sizeof(VTableOffset) == 4);
		builder_Add_AIA.specializeArgConst(vInterfaceTableAddr, interfaceNumber * sizeof(VTableOffset),
		                                   vInterfaceTableEntryAddr, cn);

		// Compute the offset into the class's VTable which corresponds to the base
		// of the sub-vtable for this interface
		builder_Ld_AI.makeLoad(0, vInterfaceTableEntryAddr, vSubVTableOffset, false, true, cn, bci);
		                                         
		// Get the offset of the vEntry within the interface's sub-vtable.
		builder_Add_AIA.specializeArgConst(type, vIndex * sizeof(VTableEntry), vEntryOffset, cn);

		// Compute the address of the vtable entry
		VariableOrConstant vVTableEntryAddr;
		builder_Add_AIA.makeBinaryGeneric(vVars, vVTableEntryAddr, cn);

		// Emit the load instruction to get the function's address from the vtable entry.
		builder_Ld_AA.makeLoad(0, vVTableEntryAddr, functionAddr, false, true, cn, bci);
	}
}

//
// Generate a function call.  opcode should be one of the four opcodes
// invokevirtual, invokespecial, invokestatic, or invokeinterface.
// cpi is the constant pool index of the method.
// If opcode is bcInvokeInterface, nArgs is the number of arguments.
//
// Set cn to a control node to use for the next portion of this BytecodeBlock or
// nil if the rest of this BytecodeBlock is dead.
//
void BytecodeTranslator::BlockTranslator::genInvoke(bytecode opcode, ConstantPoolIndex cpi, uint nArgs, Uint32 bci)
{
	Signature sig;
	VariableOrConstant receiver;
	VariableOrConstant function;
	const Method *method;
	TranslationEnv &env = *translationEnv;

	function.setConstant(nullAddr);
	switch (opcode) {
		case bcInvokeVirtual:
			{
				Uint32 vIndex;
				method = classFileSummary.lookupVirtualMethod(cpi, sig, vIndex, function.getConstant().a);
				genReceiverNullCheck(sig, receiver, bci);
				if (!cn)
					return;
				if (!method)
					genVirtualLookup(receiver, vIndex, function, bci);
			}
			break;
		case bcInvokeSpecial:
			{
				bool isInit;
				method = &classFileSummary.lookupSpecialMethod(cpi, sig, isInit, function.getConstant().a);
				genReceiverNullCheck(sig, receiver, bci);
				if (!cn)
					return;
			}
			break;
		case bcInvokeStatic:
			method = &classFileSummary.lookupStaticMethod(cpi, sig, function.getConstant().a);
			break;
		case bcInvokeInterface:
			{
				Uint32 vIndex, interfaceNumber;
				method = classFileSummary.lookupInterfaceMethod(cpi, sig, vIndex, interfaceNumber,
                                                                function.getConstant().a, nArgs);
				genReceiverNullCheck(sig, receiver, bci);
				if (!cn)
					return;
                assert(!method);
				genInterfaceLookup(receiver, interfaceNumber, vIndex, method, function, bci);
			}
			break;
		default:
			trespass("Bad invoke opcode");
			return;
	}

	VariableOrConstant result;
	VariableOrConstant args20[20];	// Hold arguments here if there are fewer than 20.
	VariableOrConstant *args = args20;
	uint nArguments = sig.nArguments;
	if (nArguments > 20)
		args = new(envPool) VariableOrConstant[nArguments];

	// Pop the arguments off the environment stack.
	const Type **argumentType = sig.argumentTypes + nArguments;
	VariableOrConstant *arg = args + nArguments;
	while (arg != args)
		env.pop1or2(isDoublewordKind((*--argumentType)->typeKind)).extract(*--arg, bci);

	// Create the call primitive.
	DataNode *memory = &env.memory().extract(bci);
	Primitive &prim = makeCall(sig, memory, function, method, args, &result, *cn, bci);
	env.memory().define(*memory);

	// Push the result onto the environment stack.
	if (sig.getNResults())
		env.push1or2(isDoublewordKind(result.getKind())).define(result, cn, envPool);
	genPossibleThrow(prim, Standard::get(cThrowable));
}


//
// Create control and data flow nodes for the primitives inside this BytecodeBlock.
// Use and modify translationEnv to keep track of the locals' and stack temporaries' values.
//
// Set cn to nil when done.
//
void BytecodeTranslator::BlockTranslator::genLivePrimitives()
{
	BytecodeGraph &bg = bt.bytecodeGraph;
	TranslationEnv &env = *translationEnv;
	const AttributeCode *code = (AttributeCode *) 
		bg.method.getMethodInfo().getAttribute("Code");
	AttributeLocalVariableTable *localVariableTable = 
		(AttributeLocalVariableTable *) code->getAttribute("LocalVariableTable");
	const bytecode *const bytecodesEnd = block.bytecodesEnd;
	const bytecode *bc = block.bytecodesBegin;

	while (bc != bytecodesEnd) {
		assert(bc < bytecodesEnd);
		bytecode opcode = *bc++;
		ValueKind vk;
		Value v;
		Uint32 i;
		ConstantPoolIndex cpi;
		Int32 j;
		TranslationBinding *tb;
		VariableOrConstant args[4];
		VariableOrConstant result;
		Primitive *prim;
		const Type *cl;
		IntervalMapping	*mapping;
		Uint32 bci = bc - bg.bytecodesBegin;

		switch (opcode) {

			case bcNop:
				break;

			case bcAConst_Null:
				env.push().definePtr(nullAddr, cn, envPool);
				break;
			case bcIConst_m1:
			case bcIConst_0:
			case bcIConst_1:
			case bcIConst_2:
			case bcIConst_3:
			case bcIConst_4:
			case bcIConst_5:
				env.push().defineInt(opcode - bcIConst_0, cn, envPool);
				break;
			case bcLConst_0:
				env.push2().defineLong(0, cn, envPool);
				break;
			case bcLConst_1:
				env.push2().defineLong(1, cn, envPool);
				break;
			case bcFConst_0:
				env.push().defineFloat(0.0, cn, envPool);
				break;
			case bcFConst_1:
				env.push().defineFloat(1.0, cn, envPool);
				break;
			case bcFConst_2:
				env.push().defineFloat(2.0, cn, envPool);
				break;
			case bcDConst_0:
				env.push2().defineDouble(0.0, cn, envPool);
				break;
			case bcDConst_1:
				env.push2().defineDouble(1.0, cn, envPool);
				break;
			case bcBIPush:
				env.push().defineInt(*(Int8 *)bc, cn, envPool);
				bc++;
				break;
			case bcSIPush:
				env.push().defineInt(readBigSHalfwordUnaligned(bc), cn, envPool);
				bc += 2;
				break;
			case bcLdc:
				cpi = *(Uint8 *)bc;
				bc++;
				goto pushConst1;
			case bcLdc_W:
				cpi = readBigUHalfwordUnaligned(bc);
				bc += 2;
			  pushConst1:
				vk = classFileSummary.lookupConstant(cpi, v);
				assert(isWordKind(vk));
				env.push().define(vk, v, cn, envPool);
				break;
			case bcLdc2_W:
				vk = classFileSummary.lookupConstant(readBigUHalfwordUnaligned(bc), v);
				bc += 2;
				assert(isDoublewordKind(vk));
				env.push2().define(vk, v, cn, envPool);
				break;

			case bcILoad:
			case bcFLoad:
			case bcALoad:
				i = *(Uint8 *)bc;
				bc++;
			  pushLoad1:
				env.push() = env.local(i);
				break;
			case bcLLoad:
			case bcDLoad:
				i = *(Uint8 *)bc;
				bc++;
			  pushLoad2:
				assert(env.local(i+1).isSecondWord());
				env.push2() = env.local(i);
				break;
			case bcILoad_0:
			case bcILoad_1:
			case bcILoad_2:
			case bcILoad_3:
				i = opcode - bcILoad_0;
				goto pushLoad1;
			case bcLLoad_0:
			case bcLLoad_1:
			case bcLLoad_2:
			case bcLLoad_3:
				i = opcode - bcLLoad_0;
				goto pushLoad2;
			case bcFLoad_0:
			case bcFLoad_1:
			case bcFLoad_2:
			case bcFLoad_3:
				i = opcode - bcFLoad_0;
				goto pushLoad1;
			case bcDLoad_0:
			case bcDLoad_1:
			case bcDLoad_2:
			case bcDLoad_3:
				i = opcode - bcDLoad_0;
				goto pushLoad2;
			case bcALoad_0:
			case bcALoad_1:
			case bcALoad_2:
			case bcALoad_3:
				i = opcode - bcALoad_0;
				goto pushLoad1;

			case bcIALoad:
			case bcLALoad:
			case bcFALoad:
			case bcDALoad:
			case bcAALoad:
			case bcBALoad:
			case bcCALoad:
			case bcSALoad:
				genArrayEltAccess(arrayAccessTypeKinds[opcode - bcIALoad], false, bci);
				goto checkDeadRestOfBlock;

			case bcIStore:
			case bcFStore:
			case bcAStore:
				i = *(Uint8 *)bc;
				bc++;
			  popStore1:
				// asharma - label this one
				if (localVariableTable) {
					DoublyLinkedList<IntervalMapping> &mappings =
						localVariableTable->getEntry(i)->mappings;
					IntervalMapping *prev;
				
					mapping = new IntervalMapping();	// Fix me!
					mapping->setStart((Uint32) (bc - bg.bytecodesBegin));
					if (!mappings.empty()) {
						prev = &mappings.get(mappings.end());
						prev->setEnd((Uint32) (bc - bg.bytecodesBegin));
					}
					mappings.addLast(*mapping);
					tb = (TranslationBinding *) &env.stackNth(1);
					if (tb->isDataEdge()) {
						tb->extract(bci).mapping = mapping;
					}
				}				
				env.local(i) = env.pop();
				break;
			case bcLStore:
			case bcDStore:
				i = *(Uint8 *)bc;
				bc++;
			  popStore2:
				// asharma label this one
				env.local(i) = env.pop2();
				env.local(i+1).defineSecondWord();
				break;
			case bcIStore_0:
			case bcIStore_1:
			case bcIStore_2:
			case bcIStore_3:
				i = opcode - bcIStore_0;
				goto popStore1;
			case bcLStore_0:
			case bcLStore_1:
			case bcLStore_2:
			case bcLStore_3:
				i = opcode - bcLStore_0;
				goto popStore2;
			case bcFStore_0:
			case bcFStore_1:
			case bcFStore_2:
			case bcFStore_3:
				i = opcode - bcFStore_0;
				goto popStore1;
			case bcDStore_0:
			case bcDStore_1:
			case bcDStore_2:
			case bcDStore_3:
				i = opcode - bcDStore_0;
				goto popStore2;
			case bcAStore_0:
			case bcAStore_1:
			case bcAStore_2:
			case bcAStore_3:
				i = opcode - bcAStore_0;
				goto popStore1;

			case bcIAStore:
			case bcLAStore:
			case bcFAStore:
			case bcDAStore:
			case bcAAStore:
			case bcBAStore:
			case bcCAStore:
			case bcSAStore:
				genArrayEltAccess(arrayAccessTypeKinds[opcode - bcIAStore], true, bci);
				goto checkDeadRestOfBlock;

			case bcPop:
				env.drop(1);
				break;
			case bcPop2:
				env.drop(2);
				break;
			case bcDup:
				tb = &env.stackNth(1);
				env.push() = *tb;
				break;
			case bcDup_x1:
				env.raise(1);
				tb = env.stackTopN(3);
				tb[-1] = tb[-2];
				tb[-2] = tb[-3];
				tb[-3] = tb[-1];
				break;
			case bcDup_x2:
				env.raise(1);
				tb = env.stackTopN(4);
				tb[-1] = tb[-2];
				tb[-2] = tb[-3];
				tb[-3] = tb[-4];
				tb[-4] = tb[-1];
				break;
			case bcDup2:
				env.raise(2);
				tb = env.stackTopN(4);
				tb[-1] = tb[-3];
				tb[-2] = tb[-4];
				break;
			case bcDup2_x1:
				env.raise(2);
				tb = env.stackTopN(5);
				tb[-1] = tb[-3];
				tb[-2] = tb[-4];
				tb[-3] = tb[-5];
				tb[-4] = tb[-1];
				tb[-5] = tb[-2];
				break;
			case bcDup2_x2:
				env.raise(2);
				tb = env.stackTopN(6);
				tb[-1] = tb[-3];
				tb[-2] = tb[-4];
				tb[-3] = tb[-5];
				tb[-4] = tb[-6];
				tb[-5] = tb[-1];
				tb[-6] = tb[-2];
				break;
			case bcSwap:
				{
					TranslationBinding tempBinding;
					tb = env.stackTopN(2);
					tempBinding = tb[-1];
					tb[-1] = tb[-2];
					tb[-2] = tempBinding;
				}
				break;

			case bcIAdd:
			case bcFAdd:
			case bcISub:
			case bcFSub:
			case bcIMul:
			case bcFMul:
			case bcFDiv:
			case bcFRem:
			case bcIShl:
			case bcIShr:
			case bcIUShr:
			case bcIAnd:
			case bcIOr:
			case bcIXor:
			case bcFCmpL:
			case bcFCmpG:
				env.pop().extract(args[1], bci);
				tb = env.stackTopN(1) - 1;
			  genGenericBinary:
				tb->extract(args[0], bci);
			  genExtractedBinary:
				binaryBuilders[opcode - bcIAdd]->makeBinaryGeneric(args, result, cn);
				tb->define(result, cn, envPool);
				break;
			case bcLAdd:
			case bcDAdd:
			case bcLSub:
			case bcDSub:
			case bcLMul:
			case bcDMul:
			case bcDDiv:
			case bcDRem:
			case bcLAnd:
			case bcLOr:
			case bcLXor:
				env.pop2().extract(args[1], bci);
			  genLongShift:
				tb = env.stackTopN(2) - 2;
				assert(tb[1].isSecondWord());
				goto genGenericBinary;
			case bcLShl:
			case bcLShr:
			case bcLUShr:
				env.pop().extract(args[1], bci);
				goto genLongShift;
			case bcLCmp:
			case bcDCmpL:
			case bcDCmpG:
				env.pop2().extract(args[1], bci);
				env.pop2().extract(args[0], bci);
				tb = &env.push();
				goto genExtractedBinary;

			case bcIDiv:
			case bcIRem:
				env.pop().extract(args[1], bci);
				tb = env.stackTopN(1) - 1;
				assert(args[1].hasKind(vkInt));
				if (args[1].isConstant() && args[1].getConstant().i == 0) {
					// If the second argument is always zero, this operation becomes an unconditional throw.
					genSimpleThrow(&Standard::get(oArithmeticException), true);
					// The rest of this BytecodeBlock is dead.
					return;
				}
			  genIntegerDivRem:
				tb->extract(args[0], bci);
				prim = binaryBuilders[opcode - bcIAdd]->makeBinaryGeneric(args, result, cn);
				tb->define(result, cn, envPool);
				if (prim && prim->canRaiseException())
					genPossibleThrow(*prim, Standard::get(cArithmeticException));
				break;
			case bcLDiv:
			case bcLRem:
				env.pop2().extract(args[1], bci);
				tb = env.stackTopN(2) - 2;
				assert(tb[1].isSecondWord());
				assert(args[1].hasKind(vkLong));
				if (args[1].isConstant() && args[1].getConstant().l == 0) {
					// If the second argument is always zero, this operation becomes an unconditional throw.
					genSimpleThrow(&Standard::get(oArithmeticException), true);
					// The rest of this BytecodeBlock is dead.
					return;
				}
				goto genIntegerDivRem;

			case bcINeg:
			case bcFNeg:
			case bcI2F:
			case bcF2I:
			case bcInt2Byte:
			case bcInt2Char:
			case bcInt2Short:
				tb = env.stackTopN(1) - 1;
			  genGenericUnary:
				tb->extract(args[0], bci);
			  genExtractedUnary:
				unaryBuilders[opcode - bcINeg]->makeUnaryGeneric(args[0], result, cn);
				tb->define(result, cn, envPool);
				break;
			case bcLNeg:
			case bcDNeg:
			case bcL2D:
			case bcD2L:
				tb = env.stackTopN(2) - 2;
				assert(tb[1].isSecondWord());
				goto genGenericUnary;
			case bcI2L:
			case bcI2D:
			case bcF2L:
			case bcF2D:
				env.pop().extract(args[0], bci);
				tb = &env.push2();
				goto genExtractedUnary;
			case bcL2I:
			case bcL2F:
			case bcD2I:
			case bcD2F:
				env.pop2().extract(args[0], bci);
				tb = &env.push();
				goto genExtractedUnary;

			case bcIInc:
				i = *(Uint8 *)bc;
				bc++;
				j = *(Int8 *)bc;
				bc++;
			  incLocal:
				// asharma label this one
				env.local(i).extract(args[0], bci);
				builder_AddCoal_III.specializeArgConst(args[0], j, result, cn);
				env.local(i).define(result, cn, envPool);
				break;

			case bcIfEq:
			case bcIfNe:
			case bcIfLt:
			case bcIfGe:
			case bcIfGt:
			case bcIfLe:
				env.pop().extract(args[0], bci);
				prim = unaryComparisonBuilders[opcode - bcIfEq]->specializeArgConst(args[0], 0, result, cn);
			  genIf:
				// We should have exactly two successors.
				createIf(bytecodeConditionals[opcode - bcIfEq], prim != 0, result, block.getSuccessor(0), block.getSuccessor(1), bci);
				// We should be at the end of the basic block.
				assert(bc + 2 == bytecodesEnd);
				return;
			case bcIf_ICmpEq:
			case bcIf_ICmpNe:
			case bcIf_ICmpLt:
			case bcIf_ICmpGe:
			case bcIf_ICmpGt:
			case bcIf_ICmpLe:
			case bcIf_ACmpEq:
			case bcIf_ACmpNe:
				env.pop().extract(args[1], bci);
				env.pop().extract(args[0], bci);
				prim = binaryComparisonBuilders[opcode - bcIf_ICmpEq]->makeBinaryGeneric(args, result, cn);
				goto genIf;

			case bcGoto_W:
				bc += 2;
			case bcGoto:
				bc += 2;
				// We should be at the end of the basic block.
				assert(bc == bytecodesEnd);
				break;

			case bcJsr_W:
				bc += 2;
			case bcJsr:
				bc += 2;
				env.push().clear();	// Push the return address, which is not used since we eliminated all ret's already.
				// We should be at the end of the basic block.
				assert(bc == bytecodesEnd);
				break;

			case bcTableSwitch:
				genTableSwitch(bc, bci);
				return;
			case bcLookupSwitch:
				genLookupSwitch(bc, bci);
				return;

			case bcLReturn:
			case bcDReturn:
				env.pop2().extract(args[0], bci);
				goto genValueReturn;
			case bcIReturn:
			case bcFReturn:
			case bcAReturn:
				env.pop().extract(args[0], bci);
			  genValueReturn:
				vk = args[0].getKind();
				cn->setControlReturn(1, &vk, bci);
				cn->getReturnExtra()[0].getInput() = args[0];
				goto genReturn;
			case bcReturn:
				cn->setControlReturn(0, 0, bci);
			  genReturn:
				assert(block.nSuccessors() == 1);
				bt.linkPredecessor(*block.successorsBegin[0], cn->getReturnSuccessor(), env, true);
				cn = 0;
				assert(bc == bytecodesEnd);
				return;

			case bcGetStatic:
				genGetStatic(readBigUHalfwordUnaligned(bc), bci);
				bc += 2;
				break;
			case bcPutStatic:
				genPutStatic(readBigUHalfwordUnaligned(bc), bci);
				bc += 2;
				break;
			case bcGetField:
				genGetField(readBigUHalfwordUnaligned(bc), bci);
			  add2CheckDeadRestOfBlock:
				bc += 2;
				// Exit if the rest of this BytecodeBlock is dead.
			  checkDeadRestOfBlock:
				if (!cn) {
					// The rest of this BytecodeBlock is dead.
					assert(bc < bytecodesEnd);
					return;
				}
				break;
			case bcPutField:
				genPutField(readBigUHalfwordUnaligned(bc), bci);
				goto add2CheckDeadRestOfBlock;

			case bcInvokeVirtual:
			case bcInvokeSpecial:
			case bcInvokeStatic:
				genInvoke(opcode, readBigUHalfwordUnaligned(bc), 0, bci);
				goto add2CheckDeadRestOfBlock;
			case bcInvokeInterface:
				genInvoke(opcode, readBigUHalfwordUnaligned(bc), *(Uint8 *)(bc + 2), bci);
				bc += 4;
				goto checkDeadRestOfBlock;

			case bcNew:
				args[0].setConstant(objectAddress(&classFileSummary.lookupClass(readBigUHalfwordUnaligned(bc))));
				genNewCommon(scNew, 1, args, bci);
				goto add2CheckDeadRestOfBlock;

			case bcNewArray:
				i = *(Uint8 *)bc;
				bc++;
				i -= natMin;
				if (i >= natLimit - natMin)
					verifyError(VerifyError::badNewArrayType);
				env.pop().extract(args[0], bci);
				genNewCommon(*newArrayCalls[i], 1, args, bci);
				goto checkDeadRestOfBlock;

			case bcANewArray:
				args[0].setConstant(objectAddress(&classFileSummary.lookupType(readBigUHalfwordUnaligned(bc))));
				env.pop().extract(args[1], bci);
				genNewCommon(scNewObjectArray, 2, args, bci);
				goto add2CheckDeadRestOfBlock;

			case bcMultiANewArray:
				cl = &classFileSummary.lookupType(readBigUHalfwordUnaligned(bc));
				args[0].setConstant(objectAddress(cl)); // array type argument
				i = *(Uint8 *)(bc+2); // dimension
				bc += 3;
				switch (i) {
				case 1:
					cl = &asArray(*cl).getElementType();
					if (isPrimitiveKind(cl->typeKind)) { // converted to a base type
						env.pop().extract(args[0], bci); // number of elements
						genNewCommon(*typeToArrayCalls[cl->typeKind], 1, args, bci);
					}
					else { // converted to a class type
						env.pop().extract(args[1], bci); // number of elements
						genNewCommon(scNewObjectArray, 2, args, bci);
					}
					break;
				case 2:
					env.pop().extract(args[2], bci);  // first dimension
					env.pop().extract(args[1], bci);  // second dimension
					genNewCommon(scNew2DArray, 3, args, bci);
					break;
				case 3:
					env.pop().extract(args[3], bci);  // as above
					env.pop().extract(args[2], bci);
					env.pop().extract(args[1], bci);
					genNewCommon(scNew3DArray, 4, args, bci);
					break;
				default:
					// i>=4
					// generate temporary array to store all the dimensions in, and
					// push it onto the environment
					genTempArrayOfDim(i, bci);
					if (!cn)
						return; // temporary array construction will throw exception
					env.pop().extract(args[1], bci);
					genNewCommon(scNewNDArray, 2, args, bci);
					break;
				}			
				goto checkDeadRestOfBlock;

			case bcArrayLength:
				env.pop().extract(args[0], bci);
				genReadArrayLength(args[0], result, bci);
				if (!cn)
					return;	// The rest of this BytecodeBlock is dead.
				env.push().define(result, cn, envPool);
				break;

			case bcAThrow:
				env.pop().extract(args[0], bci);
				genThrow(args[0]);
				// The rest of this BytecodeBlock is dead, and we should be at the end of it.
				assert(bc == bytecodesEnd);
				return;

			case bcCheckCast:
				env.stackNth(1).extract(args[0], bci);
				genCheckCast(readBigUHalfwordUnaligned(bc), args[0], bci);
				goto add2CheckDeadRestOfBlock;

			case bcInstanceOf:
				env.pop().extract(args[0], bci);
				genInstanceOf(readBigUHalfwordUnaligned(bc), args[0], result, bci);
				assert(cn);	// instanceof can't throw exceptions.
				bc += 2;
				env.push().define(result, cn, envPool);
				break;

			case bcMonitorEnter:
				env.pop().extract(args[0], bci);
				genNullGuard(args[0], bci);
				if (cn)
					genPossibleThrow(genMonitor(poMEnter, args[0], bci), Standard::get(cError));
				else {
					// The rest of this BytecodeBlock is dead.
					assert(bc < bytecodesEnd);
					return;
				}
				break;

			case bcMonitorExit:
				env.pop().extract(args[0], bci);
				genMonitor(poMExit, args[0], bci);
				break;

			case bcWide:
				opcode = *bc++;
				i = readBigUHalfwordUnaligned(bc);
				bc += 2;
				switch (opcode) {
					case bcILoad:
					case bcFLoad:
					case bcALoad:
						goto pushLoad1;
					case bcLLoad:
					case bcDLoad:
						goto pushLoad2;

					case bcIStore:
					case bcFStore:
					case bcAStore:
						goto popStore1;
					case bcLStore:
					case bcDStore:
						goto popStore2;

					case bcIInc:
						j = readBigSHalfwordUnaligned(bc);
						bc += 2;
						goto incLocal;

					// We should not see these here; they should have been taken out by now.
					// case bcRet:
					default:
						verifyError(VerifyError::badBytecode);
				}
				break;

			case bcIfNull:
			case bcIfNonnull:
				env.pop().extract(args[0], bci);
				prim = builder_CmpUEq_AAC.specializeArgConst(args[0], nullAddr, result, cn);
				goto genIf;

			case bcBreakpoint:
				// Ignore breakpoints.
				break;

			// We should not see these here; they should have been taken out by now.
			// case bcRet:
			default:
				verifyError(VerifyError::badBytecode);
		}
	}

	// We fell off the last opcode of this basic block of bytecodes.
	// We should have exactly one successor.
	assert(block.nSuccessors() == 1);
	createBasicBlock(block.getSuccessor(0));
}


//
// Adjust this BytecodeBlock's local environment to allow primitives to be generated
// for this BytecodeBlock before all of its predecessors have been generated.
// This means that local and stack variable bindings may have to be replaced by
// phantom phi nodes.  [This is inefficient, so this code should be revised to
// do a prepass figuring out exactly which phi nodes are needed.]
//
// Also create an aexc header node for the cycle.  Set cn to the ControlNode to use for
// the rest of this BytecodeBlock.
//
void BytecodeTranslator::BlockTranslator::genCycleHeader()
{
	translationEnv->anticipate(block);
	genException(ckAExc, 0, Standard::get(cThreadDeath), false);
	appendControlNode(cn->getNormalSuccessor());
}


// ----------------------------------------------------------------------------
// BytecodeTranslator


//
// If stackNormalization is either sn0, sn1, or sn2, pop all except the top
// zero, one, or two words from env, modifying it in place.
//
void BytecodeTranslator::normalizeEnv(TranslationEnv &env, BasicBlock::StackNormalization stackNormalization)
{
	TranslationBinding tempBinding;

	switch (stackNormalization) {
		case BasicBlock::snNoChange:
			return;
		case BasicBlock::sn0:
			break;
		case BasicBlock::sn1:
			tempBinding = env.pop();
			break;
		case BasicBlock::sn2:
			tempBinding = env.pop2();
			break;
	}
	env.dropAll();
	switch (stackNormalization) {
		case BasicBlock::sn0:
			break;
		case BasicBlock::sn1:
			env.push() = tempBinding;
			break;
		case BasicBlock::sn2:
			env.push2() = tempBinding;
			break;
		default:
			trespass("Bad stackNormalization");
	}
}


//
// Take notice that the control node(s) generated from BasicBlock block will have
// another predecessor, as given by controlEdge.  The controlEdge should be allocated
// out of the control graph's memory pool.
// Merge the BasicBlock's environment with predecessorEnv, adding phi nodes or
// phantom phi nodes as needed.  If canOwnEnv is true, the BasicBlock can assume
// ownership of predecessorEnv (thereby sometimes eliminating an unnecessary copy).
//
void BytecodeTranslator::linkPredecessor(BasicBlock &block, ControlEdge &controlEdge, TranslationEnv &predecessorEnv, bool canOwnEnv)
{
	BasicBlock::StackNormalization stackNormalization = block.stackNormalization;
	if (stackNormalization != BasicBlock::snNoChange && predecessorEnv.getSP() != (Uint32)(stackNormalization-BasicBlock::sn0))
		// We have to normalize the stack inside predecessorEnv.
		if (canOwnEnv)
			normalizeEnv(predecessorEnv, stackNormalization);
		else {
			TranslationEnv envCopy(predecessorEnv);
			normalizeEnv(envCopy, stackNormalization);
			linkPredecessor(block, controlEdge, envCopy, true);
			return;
		}

	ControlNode *first = block.getFirstControlNode();
	assert(block.getGeneratedControlNodes() == (first != 0));
	if (first) {
		// Only aexc nodes can be targets of backward edges.
		assert(block.hasIncomingBackEdges && first->hasControlKind(ckAExc));
		first->disengagePhis();
		first->addPredecessor(controlEdge);
	} else
		block.getPredecessors().addLast(controlEdge);

	if (block.getEnvInInitialized())
		block.getTranslationEnvIn().meet(predecessorEnv, block.hasKind(BasicBlock::bbEnd), block);
	else {
		if (canOwnEnv)
			block.getTranslationEnvIn().move(predecessorEnv);
		else
			block.getTranslationEnvIn() = predecessorEnv;
		block.getEnvInInitialized() = true;
	}
  #ifdef DEBUG
	if (first)
		first->reengagePhis();
  #endif
}



//
// Call finishedOnePredecessor on every successor.
//
void BytecodeTranslator::finishedOutgoingEdges(BasicBlock &block)
{
	BasicBlock **handlersEnd = block.handlersEnd;
	for (BasicBlock **bp = block.successorsBegin; bp != handlersEnd; bp++)
		finishedOnePredecessor(**bp);
}


//
// Create a new ControlNode for BasicBlock block.
// BasicBlock block must not be dead.
// Return the ControlNode to use for the rest of BasicBlock block.
// If mergeBlock is true and there is only one predecessor node that is a Block node,
// continue to use that Block node instead of making a new ControlNode.
//
ControlNode *BytecodeTranslator::createControlNode(BasicBlock &block, bool mergeBlock) const
{
	assert(!block.getGeneratedControlNodes());	// We shouldn't have generated anything for this node yet.

	if (mergeBlock && block.nPredecessors == block.getNSeenPredecessors() && block.getPredecessors().lengthIs(1)) {
		ControlNode &predNode = DoublyLinkedList<ControlEdge>::get(block.getPredecessors().begin()).getSource();
		if (predNode.hasControlKind(ckBlock)) {
			// This node has only one predecessor and it was a ckBlock node, so
			// merge this node and its predecessor now.
			predNode.unsetControlKind();
		  #ifdef DEBUG
			block.getGeneratedControlNodes() = true;
		  #endif
			return &predNode;
		}
	}

	ControlNode *cn = &controlGraph.newControlNode();
	block.getFirstControlNode() = cn;
	cn->movePredecessors(block.getPredecessors());
  #ifdef DEBUG
	block.getGeneratedControlNodes() = true;
  #endif
	return cn;
}


//
// Create control and data flow nodes out of the EndBlock.  genPrimitives must
// have been called on every other BasicBlock before calling this.
//
void BytecodeTranslator::genPrimitives(EndBlock &block) const
{
	// We should have seen all other blocks by now.
	assert(block.getNSeenPredecessors() == block.nPredecessors && !block.hasIncomingBackEdges);
	// The end block is never dead; either normal control flow or exceptions can always reach it.
	assert(block.getEnvInInitialized());

	assert(!block.getGeneratedControlNodes());	// We shouldn't have generated anything for this node yet.
	ControlNode &endNode = controlGraph.getEndNode();
	block.getFirstControlNode() = &endNode;
	block.getFirstControlNode()->movePredecessors(block.getPredecessors());
  #ifdef DEBUG
	block.getGeneratedControlNodes() = true;
  #endif

	// Initialize the finalMemory in the EndNode.
	// asharma - fix me
	endNode.getEndExtra().finalMemory.getInput().setVariable(block.getTranslationEnvIn().memory().extract(0));
}


//
// Create control and data flow nodes out of the CatchBlock.
//
void BytecodeTranslator::genPrimitives(CatchBlock &block) const
{
	// CatchBlocks cannot be targets of backward control edges.
	assert(block.getNSeenPredecessors() == block.nPredecessors);
	if (block.getEnvInInitialized()) {
		// This isn't a dead CatchBlock if some predecessor already jumps here.
		assert(block.getNSeenPredecessors());
		assert(block.nSuccessors() == 1);
		ControlNode *cn = createControlNode(block, false);
		// asharma fix me!
		block.getTranslationEnvIn().push().define(cn->setControlCatch(0));
		linkPredecessor(block.getHandler(), cn->getNormalSuccessor(), block.getTranslationEnvIn(), true);
	}

	// Adjust the nPredecessors counts of the successor BasicBlock.
	finishedOutgoingEdges(block);
}


//
// Create control and data flow nodes out of the BytecodeBlock.
//
void BytecodeTranslator::genPrimitives(BytecodeBlock &block) const
{
	assert(block.getNSeenPredecessors() <= block.nPredecessors);
	if (block.getNSeenPredecessors() != block.nPredecessors || block.getEnvInInitialized()) {
		// This isn't a dead BytecodeBlock if either some predecessor already jumps
		// here or we haven't examined all of the predecessor BasicBlocks yet.
		assert(block.getNSeenPredecessors());
		BlockTranslator translator(*this, block.getTranslationEnvIn(), block, createControlNode(block, true));

		if (block.getNSeenPredecessors() == block.nPredecessors)
			// We've seen all the predecessors already.  Modify envIn directly -- we won't
			// need it any more for merging additional predecessors.
			translator.genLivePrimitives();
		else {
			// If this block has unseen predecessors in the depth-first order,
			// then this block must be the header of a cycle.  Use a copy of envIn to
			// process this block's primitives.
			assert(block.hasIncomingBackEdges);
			translator.genCycleHeader();
			TranslationEnv cycleEnv(block.getTranslationEnvIn());
			translator.setEnv(cycleEnv);
			translator.genLivePrimitives();
			// cycleEnv must be live up to this point.
		}
		assert(translator.translatorDone());
	}

	// Adjust the nPredecessors counts of successor BasicBlocks.
	finishedOutgoingEdges(block);
}


//
// Create control and data flow nodes out of this BytecodeGraph.
//
void BytecodeTranslator::genRawPrimitiveGraph() const
{
	BasicBlock **blockArray = bytecodeGraph.getDFSList();
	for (Uint32 i = bytecodeGraph.getDFSListLength() - 1; i; i--) {
		BasicBlock *block = *blockArray++;
		assert(block->hasKind(BasicBlock::bbBytecode) || block->hasKind(BasicBlock::bbCatch));
		if (block->hasKind(BasicBlock::bbBytecode))
			genPrimitives(*static_cast<BytecodeBlock *>(block));
		else
			genPrimitives(*static_cast<CatchBlock *>(block));
	}
	assert((*blockArray)->hasKind(BasicBlock::bbEnd));
	genPrimitives(*static_cast<EndBlock *>(*blockArray));
}


//
// Add a synchronization primitive to acquire the syncHolder object's lock on
// method entry.  Return the exc control node that contains the MEnter primitive.
//
static ControlNode &addEnterNode(ControlGraph &cg, VariableOrConstant &syncHolder)
{
	Pool &pool = cg.pool;
	DoublyLinkedList<ControlEdge>::iterator where;
	ControlNode &beginNode = cg.getBeginNode();
	ControlNode &endNode = cg.getEndNode();
	ControlNode *secondNode;
	DataNode &beginMemory = beginNode.getBeginExtra().initialMemory;

	// Insert a new exc node (called enterNode) immediately after the begin node.
	// The exc node's normal outgoing edge will go to the node (secondNode) that used to
	// be the successor of the begin node.  The exc node will also have one outgoing exception
	// edge that goes directly to the end node.
	ControlNode &enterNode = insertControlNodeAfter(beginNode, secondNode, where); // Disengages secondNode's phi nodes.
	const Class **filter = new(pool) const Class *;
	filter[0] = &Standard::get(cThrowable);
	ControlEdge *enterSuccessors = new(pool) ControlEdge[2];
	// asharma - fix me
	Primitive &primEnter = makeMonitorPrimitive(poMEnter, beginMemory, syncHolder, 0, &enterNode, 0);
	enterNode.setControlException(ckExc, 1, filter, &primEnter, enterSuccessors);

	// Link the enterNode to its normal successor.
	secondNode->addPredecessor(enterSuccessors[0], where);
	secondNode->reengagePhis();

	// Link the enterNode's exception edge to the end node,
	// adjusting the end node's memory phi node as necessary.
	VariableOrConstant memoryOutVOC;
	memoryOutVOC.setVariable(primEnter);
	endNode.disengagePhis();
	endNode.addPredecessor(enterSuccessors[1]);
	addDataFlow(endNode, endNode.getEndExtra().finalMemory.getInput(), memoryOutVOC);
	endNode.reengagePhis();

	// Replace the function's incoming memory edge by the memory edge (primEnter) generated by the MEnter
	// everywhere except in the MEnter itself.
	const DoublyLinkedList<DataConsumer> &beginMemoryConsumers = beginMemory.getConsumers();
	for (DoublyLinkedList<DataConsumer>::iterator i = beginMemoryConsumers.begin(); !beginMemoryConsumers.done(i);) {
		DataConsumer &c = beginMemoryConsumers.get(i);
		i = beginMemoryConsumers.advance(i);
		if (&c.getNode() != &primEnter) {
			c.clearVariable();
			c.setVariable(primEnter);
		}
	}
	return enterNode;
}


//
// Add a synchronization primitive to release the syncHolder object's lock on
// normal method exit via the return node if there is one.
//
static void addNormalExitNode(ControlGraph &cg, VariableOrConstant &syncHolder)
{
	ControlNode *returnNode = cg.getReturnNode();
	if (returnNode) {
		ControlNode &endNode = cg.getEndNode();
		ControlEdge &returnEdge = returnNode->getReturnSuccessor();

		// Add an MExit primitive to the return node, consuming the return node's
		// current outgoing memory edge and producing a new memory edge.
		DataConsumer &finalMemory = endNode.getEndExtra().finalMemory.getInput();
		DataNode &returnMemory = followVariableBack(finalMemory, endNode, returnEdge).getVariable();
		// asharma - fix me
		Primitive &returnMemoryOut = makeMonitorPrimitive(poMExit, returnMemory, syncHolder, 0, returnNode, 0);

		// Fix up the end node's memory phi node (creating one if needed) to receive the
		// memory edge outgoing from our new MonitorExit primitive when control comes to the end
		// node from the return node.
		VariableOrConstant returnMemoryOutVOC;
		returnMemoryOutVOC.setVariable(returnMemoryOut);
		changeDataFlow(endNode, returnEdge, finalMemory, returnMemoryOutVOC);
	}
}


class ExceptionEdgeIteratee: public Function1<bool, ControlEdge &>
{
	ControlNode *enterNode;

  public:
	explicit ExceptionEdgeIteratee(ControlNode *enterNode): enterNode(enterNode) {}

	bool operator()(ControlEdge &e);
};


//
// Edge e is an edge pointing to the end node in a synchronized method.
// Return true if that method's synchronization lock should be released if
// control follows edge e.
// Given our implementation of addEnterNode and addNormalExitNode, this
// method returns false for edges originating in:
//   the return node,
//   the node at the beginning of the method that acquires the monitor, and
//   the node just before the return node that releases the monitor on normal exit.
// For all other edges this method returns true.
//
bool ExceptionEdgeIteratee::operator()(ControlEdge &e)
{
	ControlNode &source = e.getSource();
	return !(source.hasControlKind(ckReturn) || &source == enterNode);
}


//
// Add a synchronization primitive to release the syncHolder object's lock on
// exceptional method exit.
//
static void addExceptionalExitNode(ControlGraph &cg, VariableOrConstant &syncHolder, ControlNode &enterNode, Uint32 bci)
{
	ExceptionEdgeIteratee eei(&enterNode);
	ControlNode &endNode = cg.getEndNode();
	ControlNode *exitCatchNode = insertControlNodeBefore(endNode, eei); // Disengages endNode's phi nodes if returns non-nil.
	if (exitCatchNode) {
		// We have at least one exceptional method exit path that doesn't come from
		// the (already inserted) MEnter exc node.

		// Make the newly inserted node into a catch node that intercepts all exceptions
		// thrown out of this method except those coming from our new MEnter exc node.
		// Connect this catch node's outgoing edge directly to the end node for now.
		PrimCatch &primCatch = exitCatchNode->setControlCatch(bci);
		ControlEdge &exitCatchSuccessorEdge = exitCatchNode->getNormalSuccessor();
		endNode.addPredecessor(exitCatchSuccessorEdge);
		endNode.reengagePhis();

		// exitMemoryIn will be the memory input to the MonitorExit primitive we're
		// about to insert.
		DataConsumer &finalMemory = endNode.getEndExtra().finalMemory.getInput();
		DataNode &exitMemoryIn = followVariableBack(finalMemory, endNode, exitCatchSuccessorEdge).getVariable();

		// Insert a new throw node (called exitNode) immediately after the catch node.
		// The throw node will have an MExit primitive followed by a throw primitive that
		// rethrows the caught exception.  The throw node will have one outgoing exception
		// edge that goes directly to the end node.
		ControlNode *successor;
		DoublyLinkedList<ControlEdge>::iterator where;
		ControlNode &exitNode = insertControlNodeAfter(*exitCatchNode, successor, where); // Disengages endNode's phi nodes.
		assert(successor == &endNode);
		// asharma - fix me
		Primitive &exitMemoryOut = makeMonitorPrimitive(poMExit, exitMemoryIn, syncHolder, 0, &exitNode, 0);

		// Initialize the throw primitive to rethrow the caught exception.
		Pool &pool = cg.pool;
		const Class **filter = new(pool) const Class *;
		filter[0] = &Standard::get(cThrowable);
		ControlEdge *throwSuccessors = new(pool) ControlEdge;
		VariableOrConstant primCatchVOC;
		primCatchVOC.setVariable(primCatch);
		Primitive &throwPrim = makeSysCall(scThrow, 0, 1, &primCatchVOC, 0, 0, exitNode, bci);
		exitNode.setControlException(ckThrow, 1, filter, &throwPrim, throwSuccessors);

		// Link the throw node's outgoing edge to the end node at location where,
		// adjusting the end node's memory phi node as necessary.
		VariableOrConstant exitMemoryOutVOC;
		exitMemoryOutVOC.setVariable(exitMemoryOut);
		endNode.addPredecessor(throwSuccessors[0], where);
		endNode.reengagePhis();
		changeDataFlow(endNode, throwSuccessors[0], finalMemory, exitMemoryOutVOC);
	}
}


//
// Add synchronization primitives to acquire the syncHolder object's lock on method
// entry and release that lock on normal or exceptional method exit.  The ControlGraph
// should already have been generated for this method.
//
void BytecodeTranslator::addSynchronization(VariableOrConstant &syncHolder, Uint32 bci) const
{
	ControlGraph &cg = controlGraph;
	ControlNode &enterNode = addEnterNode(cg, syncHolder);
	addNormalExitNode(cg, syncHolder);
	addExceptionalExitNode(cg, syncHolder, enterNode, bci);
}


//
// Create a ControlGraph with data flow nodes out of this BytecodeGraph.
// Return the newly allocated ControlGraph or nil if an illegal bytecode was found.
// The BytecodeGraph must be complete and depthFirstSearch must have been called
// before calling this function; the usual way to do these is to call divideIntoBlocks.
//
ControlGraph *BytecodeTranslator::genPrimitiveGraph(BytecodeGraph &bytecodeGraph, Pool &primitivePool, Pool &tempPool)
{
	ControlGraph &cg = *new(primitivePool)
		ControlGraph(primitivePool, bytecodeGraph.nArguments, bytecodeGraph.argumentKinds, bytecodeGraph.isInstanceMethod, 1 /***** FIX ME *****/);

	BytecodeTranslator translator(bytecodeGraph, cg, tempPool);
	BasicBlock **block = bytecodeGraph.getDFSList();
	BasicBlock **dfsListEnd = block + bytecodeGraph.getDFSListLength();
	while (block != dfsListEnd)
		(*block++)->initTranslation(translator);

	BytecodeBlock *beginBlock = bytecodeGraph.beginBlock;
	if (beginBlock) {
		// Set up the locals and arguments
		TranslationEnv env(translator);

		env.init();
		ControlNode::BeginExtra &beginExtra = cg.getBeginNode().getBeginExtra();
		env.memory().define(beginExtra.initialMemory);
		uint nArgs = bytecodeGraph.nArguments;
		uint slotOffset = 0;
		const ValueKind *ak = bytecodeGraph.argumentKinds;
		for (uint n = 0; n != nArgs; n++) {
			env.local(slotOffset++).define(beginExtra[n]);
			if (isDoublewordKind(*ak++))
				env.local(slotOffset++).defineSecondWord();
		}
		translator.linkPredecessor(*beginBlock, cg.getBeginNode().getNormalSuccessor(), env, true);
		translator.finishedOnePredecessor(*beginBlock);
	}

	translator.genRawPrimitiveGraph();
	if (bytecodeGraph.isSynchronized) {
		VariableOrConstant sync;
		if (bytecodeGraph.isInstanceMethod)
			sync.setVariable(cg.getBeginNode().getBeginExtra()[0]);
		else
			sync.setConstant(objectAddress(bytecodeGraph.classFileSummary.getThisClass()));
		// asharma fix me!
		translator.addSynchronization(sync, 0);
	}
	return &cg;
}

