blob: c76b0f80149c228addf6a1435de6524f01cc88a5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <iostream>
#include "Log.h"
#include "IRBuilder.h"
#include "JavaLabelPrepass.h"
#include "TranslatorIntfc.h"
#include "ExceptionInfo.h"
#include "simplifier.h" // for isExactType and isNonNullObject
namespace Jitrino {
VariableIncarnation::VariableIncarnation(U_32 offset, Type* t)
: definingOffset(offset), declaredType(t), opnd(NULL)
{
_prev = _next = NULL;
}
void VariableIncarnation::setMultipleDefs()
{
definingOffset = -1;
}
Type* VariableIncarnation::getDeclaredType()
{
return declaredType;
}
void VariableIncarnation::setDeclaredType(Type* t)
{
declaredType = t;
}
void VariableIncarnation::setCommonType(Type* t) {
declaredType = t;
VariableIncarnation* tmp;
tmp = (VariableIncarnation*)_prev;
while (tmp) {
tmp->declaredType = t;
tmp = (VariableIncarnation*)tmp->_prev;
}
tmp = (VariableIncarnation*)_next;
while (tmp) {
tmp->declaredType = t;
tmp = (VariableIncarnation*)tmp->_next;
}
}
void VariableIncarnation::linkIncarnations(VariableIncarnation* vi1, VariableIncarnation* vi2)
{
if (vi1==vi2) return;
while (vi1->_next) vi1 = (VariableIncarnation*)vi1->_next;
VariableIncarnation* tmp = vi2;
while (tmp->_next) tmp = (VariableIncarnation*)tmp->_next;
if (vi1==tmp) return;
while (vi2->_prev) vi2 = (VariableIncarnation*)vi2->_prev;
vi1->_next = vi2;
vi2->_prev = vi1;
}
void VariableIncarnation::mergeIncarnations(TypeManager* tm)
{
mergeIncarnations(0,tm);
}
void VariableIncarnation::mergeIncarnations(Type* t, TypeManager* tm)
{
VariableIncarnation* vi = this;
while (vi->_prev) vi = (VariableIncarnation*)vi->_prev;
// return if there is only one incarnation in chain.
if (!(t || vi->_next)) return;
if(Log::isEnabled()) {
Log::out() << "Merging incarnations:" << ::std::endl;
if (t) {
Log::out() << " assigning common type:";
t->print(Log::out());
Log::out() << ::std::endl;
}
VariableIncarnation* tmp = vi;
do {
tmp->getDeclaredType()->print(Log::out());
Log::out() << " (" << tmp << ",DO=" << tmp->definingOffset << ") <=>";
tmp = (VariableIncarnation*)tmp->_next;
} while (tmp);
Log::out() << " end-of-list";
}
Type* varType = (t ? tm->getCommonType(vi->getDeclaredType(),t) : vi->getDeclaredType());
// Since we merge only types which are live at use there should be a common type
assert(varType);
for (vi = (VariableIncarnation*)vi->_next; vi; vi = (VariableIncarnation*)vi->_next) {
varType = tm->getCommonType(varType, vi->getDeclaredType());
}
assert(varType);
if(Log::isEnabled()) {
Log::out() << " ;;set common type: ";
varType->print(Log::out());
Log::out() << ::std::endl;
}
setCommonType(varType);
setMultipleDefs();
}
void VariableIncarnation::linkAndMergeIncarnations(VariableIncarnation* vi1, VariableIncarnation* vi2, Type* t, TypeManager* tm) {
linkIncarnations(vi1, vi2);
vi1->mergeIncarnations(t, tm);
}
void VariableIncarnation::linkAndMergeIncarnations(VariableIncarnation* vi1, VariableIncarnation* vi2, TypeManager* tm) {
linkIncarnations(vi1, vi2);
vi1->mergeIncarnations(tm);
}
void VariableIncarnation::print(::std::ostream& out) {
VariableIncarnation* tmp = this;
do {
tmp->getDeclaredType()->print(out);
out << " (" << tmp << ",DO=" << tmp->definingOffset << ") <-i->";
tmp = (VariableIncarnation*)tmp->_next;
} while (tmp);
//out << ::std::endl;
}
void SlotVar::print(::std::ostream& out) {
SlotVar* tmp = this;
do {
VariableIncarnation* cur_var_inc = tmp->getVarIncarnation();
cur_var_inc->getDeclaredType()->print(out);
out << " (" << cur_var_inc << ",DO=" << cur_var_inc->definingOffset << ",LO=" << linkOffset << ") <->";
tmp = (SlotVar*)tmp->_next;
} while (tmp);
//out << ::std::endl;
}
bool SlotVar::addVarIncarnations(SlotVar* var, MemoryManager& mm, U_32 linkOffset) {
assert(var->_prev == NULL);
SlotVar* this_sv = this;
while(this_sv->_next) this_sv = (SlotVar*)this_sv->_next;
bool added = false;
bool found = false;
for (SlotVar* in_var = var; in_var; in_var = (SlotVar*)in_var->_next) {
found = false;
VariableIncarnation* var_inc = in_var->getVarIncarnation();
for (SlotVar* sv = this; sv; sv = (SlotVar*)sv->_next) {
if (var_inc == sv->getVarIncarnation()) {
found = true;
break;
}
}
if (found) continue;
this_sv->_next = new (mm) SlotVar(var_inc);
this_sv = (SlotVar*)this_sv->_next;
added = true;
}
if (added) this->linkOffset = linkOffset;
return added;
}
void SlotVar::mergeVarIncarnations(TypeManager* tm) {
for (SlotVar* tmp = (SlotVar*)_next; tmp; tmp = (SlotVar*)tmp->_next) {
VariableIncarnation* var_inc = tmp->getVarIncarnation();
VariableIncarnation::linkIncarnations(var, var_inc);
//var_inc ->setMultipleDefs();
}
var->mergeIncarnations(tm);
// _next = NULL;
}
Opnd* VariableIncarnation::getOpnd()
{
return opnd;
}
Opnd* VariableIncarnation::getOrCreateOpnd(IRBuilder* irBuilder)
{
if (!opnd)
createVarOpnd(irBuilder);
return opnd;
}
void VariableIncarnation::createVarOpnd(IRBuilder* irBuilder)
{
if (opnd) return;
opnd = irBuilder->genVarDef(declaredType, false);
if(Log::isEnabled()) {
Log::out() << "Create operand for VarIncarnation:" << ::std::endl;
Log::out() << " opnd:"; opnd->print(Log::out()); Log::out() << ::std::endl;
Log::out() << " VarInc:"; print(Log::out()); Log::out() << ::std::endl;
}
VariableIncarnation* tmp;
tmp = (VariableIncarnation*)_prev;
while (tmp) {
tmp->opnd = opnd;
tmp = (VariableIncarnation*)tmp->_prev;
}
tmp = (VariableIncarnation*)_next;
while (tmp) {
tmp->opnd = opnd;
tmp = (VariableIncarnation*)tmp->_next;
}
}
void VariableIncarnation::setTmpOpnd(Opnd* tmpOpnd)
{
assert(!opnd);
opnd = tmpOpnd;
}
void VariableIncarnation::createMultipleDefVarOpnd(IRBuilder* irBuilder)
{
if (definingOffset==-1) createVarOpnd(irBuilder);
}
StateInfo::SlotInfo& StateInfo::top() {
assert(stack && stackDepth != 0);
return stack[stackDepth - 1];
}
StateInfo::SlotInfo& StateInfo::push(Type *type) {
StateInfo::SlotInfo& slot = stack[stackDepth++];
slot.type = type;
slot.slotFlags = 0;
slot.vars = NULL;
slot.jsrLabelOffset = 0;
return slot;
}
void StateInfo::addCatchHandler(CatchHandler *info)
{
setCatchLabel();
info->setNextExceptionInfoAtOffset(exceptionInfo);
exceptionInfo = info;
}
void StateInfo::addExceptionInfo(CatchBlock *info) {
ExceptionInfo *exc;
ExceptionInfo *prev = NULL;
for (exc = exceptionInfo; exc != NULL; exc = exc->getNextExceptionInfoAtOffset()) {
if (exc->isCatchBlock() &&
((CatchBlock *)exc)->getExcTableIndex() > ((CatchBlock *)info)->getExcTableIndex()) {
break;
}
prev = exc;
}
if (prev == NULL) {
info->setNextExceptionInfoAtOffset(exceptionInfo);
exceptionInfo = info;
} else {
info->setNextExceptionInfoAtOffset(prev->getNextExceptionInfoAtOffset());
prev->setNextExceptionInfoAtOffset(info);
}
}
void StateInfo::cleanFinallyInfo(U_32 offset)
{
for (unsigned k=0; k < stackDepth; k++) {
if (stack[k].jsrLabelOffset == offset) {
stack[k].jsrLabelOffset = 0;
stack[k].type = 0;
stack[k].slotFlags = 0;
stack[k].vars = NULL;
stack[k].varNumber = 0;
}
}
}
class JavaExceptionParser {
public:
JavaExceptionParser(MemoryManager& mm,JavaLabelPrepass& p,
CompilationInterface& ci,MethodDesc* method)
: numCatch(0), memManager(mm), prepass(p),
compilationInterface(ci), enclosingMethod(method),
prevCatch(NULL), nextRegionId(0) {}
U_32 parseHandlers() {
U_32 numHandlers = enclosingMethod->getNumHandlers();
for (U_32 i=0; i<numHandlers; i++) {
unsigned short beginOffset,endOffset,handlerOffset,handlerClassIndex;
enclosingMethod->getHandlerInfo(i,&beginOffset,&endOffset,
&handlerOffset,&handlerClassIndex);
if (!catchBlock(beginOffset,endOffset-beginOffset,
handlerOffset,handlerClassIndex))
{
// handlerClass failed to be resolved. LinkingException throwing helper
// will be generated instead of method's body
return handlerClassIndex;
}
}
return MAX_UINT32; // all catchBlocks were processed successfully
}
void addHandlerForCatchBlock(CatchBlock* block,
U_32 handlerOffset,
Type* exceptionType) {
jitrino_assert( exceptionType);
assert(!exceptionType->isUnresolvedType());//must be resolved by verifier
if (Log::isEnabled()) Log::out() << "Catch Exception Type = " << exceptionType->getName() << ::std::endl;
// FIXME can we operate with just sole handler per offset, just merging exceptionTypes?
// need to check about handler for finally.
CatchHandler* handler = new (memManager)
CatchHandler(nextRegionId++,
handlerOffset,
handlerOffset,
exceptionType);
block->addHandler(handler);
StateInfo *hi = prepass.stateTable->createStateInfo(handlerOffset, prepass.getNumVars());
hi->addCatchHandler(handler);
StateInfo::SlotInfo* slot;
if (hi->stackDepth != prepass.getNumVars()) {
slot = &hi->top();
if (slot->type != exceptionType) {
slot->type = prepass.typeManager.getCommonType(exceptionType, slot->type);
StateInfo::clearExactType(slot);
}
} else {
slot = &hi->push(exceptionType);
StateInfo::setNonNull(slot);
}
assert(prepass.getNumVars() + 1 == (unsigned)hi->stackDepth);
slot->vars = new (memManager) SlotVar(
prepass.getOrCreateVarInc(handlerOffset, hi->stackDepth - 1, slot->type));
}
CatchBlock* splitBlockWithOffset(CatchBlock* block, U_32 offset)
{
CatchBlock* newBlock =
new (memManager) CatchBlock(nextRegionId++,
offset,
block->getEndOffset(),
block->getExcTableIndex());
assert(prepass.stateTable->getStateInfo(offset));
prepass.stateTable->getStateInfo(offset)->addExceptionInfo(newBlock);
block->setEndOffset(offset);
//
// copy all handlers
//
for (CatchHandler* handler = block->getHandlers();
handler != NULL;
handler = handler->getNextHandler() )
{
addHandlerForCatchBlock(newBlock, handler->getBeginOffset(), handler->getExceptionType());
}
return newBlock;
}
bool catchBlock(U_32 tryOffset,
U_32 tryLength,
U_32 handlerOffset,
U_32 exceptionTypeToken) {
if (Log::isEnabled()) Log::out() << "CatchBlock @ " << (int)tryOffset << ","
<< (int)tryOffset+(int)tryLength
<< " handler @ " << (int)handlerOffset << ","
<< " exception type " << (int)exceptionTypeToken << ","
<< " numCatch " << numCatch << ::std::endl;
U_32 endOffset = tryOffset + tryLength;
prepass.setLabel(handlerOffset);
prepass.setLabel(tryOffset);
prepass.setLabel(endOffset);
bool unnested_try_regions_found = false;
CatchBlock* catchBlock;
Type* exceptionType = NULL;
if (exceptionTypeToken != 0) {
exceptionType = compilationInterface.getNamedType(enclosingMethod->getParentHandle(),exceptionTypeToken, ResolveNewCheck_NoCheck);
assert(exceptionType);
if (exceptionType->isUnresolvedObject()) {
if(!compilationInterface.getTypeManager().isLazyResolutionMode()) {
// the type can not be resolved. LinkingException must be thrown
return 0;
}
//WORKAROUND! resolving exception type during a compilation session!!!
//Details: using singleton UnresolvedObjectType we unable to
//distinct exception types if there are several unresolved exceptions in a single try block
//usually verifier loads all exception types caught for in method
//but verifier is turned off for bootstrap classes
if (Log::isEnabled()) Log::out()<<"WARNING: resolving type from inside of compilation session!!"<<std::endl;
exceptionType = compilationInterface.resolveNamedType(enclosingMethod->getParentHandle(),exceptionTypeToken);
if (exceptionType->isUnresolvedType()) {
return 0;
}
}
} else {
//FIXME should use j.l.Throwable for correct type propagation ??
exceptionType = prepass.typeManager.getSystemObjectType();
}
if (prevCatch != NULL && prevCatch->equals(tryOffset, endOffset) == true) {
catchBlock = prevCatch;
addHandlerForCatchBlock(catchBlock, handlerOffset, exceptionType);
} else {
prepass.stateTable->createStateInfo(tryOffset);
//
// split all previous CatchBlocks that:
// 1. intersect with current CatchBlock
// 2. are not contained by current CatchBlock
// (CB splitting will result in CBs with same excTableIndex,
// but it is no problem since splitted CBs do not intersect)
// Our aim is to make all try-blocks nested
//
for ( JavaLabelPrepass::ExceptionTable::iterator block_it = prepass.exceptionTable.begin();
block_it != prepass.exceptionTable.end();
block_it++ ) {
CatchBlock* block = *block_it;
if ( block->offsetSplits(tryOffset) || block->offsetSplits(endOffset) ) {
if ( !unnested_try_regions_found ) {
unnested_try_regions_found = true;
if (Log::isEnabled()) Log::out() << "unnested try-regions encountered" << std::endl;
}
}
assert(tryOffset < endOffset);
if ( block->offsetSplits(tryOffset) ) {
block = splitBlockWithOffset(block, tryOffset);
prepass.exceptionTable.insert(block_it, block);
}
if ( block->offsetSplits(endOffset) ) {
prepass.stateTable->createStateInfo(endOffset);
block = splitBlockWithOffset(block, endOffset);
prepass.exceptionTable.insert(block_it, block);
}
assert( !(block->offsetSplits(tryOffset) || block->offsetSplits(endOffset)) );
}
//
// add new CatchBlock
//
if (handlerOffset < endOffset && handlerOffset > tryOffset) {
//self-handling block: add 2 CatchBlocks(ExceptionInfos) with the following boundaries:
//[tryOffset, handlerOffset], [handlerOffset, endOffset]
//The reason is to avoid loops with dispatch node as header:
// Details:
// For a single CatchBlock(ExceptionInfo) we have only 1 dispatch node today
// (dispatch node is referenced by LabelInfo field in ExceptionInfo structure)
// Having single dispatch node for self-catching regions we will have a loop with
// dispatch node as a loop-header.
// To avoid having dispatch nodes as a loop-header we create 2 (CatchBlocks)ExceptionInfos here:
// doing this we have 2 dispatch nodes for 2 ExceptionInfos and loop-header is automatically
// moved to the next (after the second dispatch)block node with CatchLabelInst instruction.
// Example to reproduce: comment out this if clause and check IR for monexit loops.
prevCatch = catchBlock = new (memManager) CatchBlock(nextRegionId++, tryOffset, handlerOffset, numCatch++);
prepass.stateTable->getStateInfo(tryOffset)->addExceptionInfo(catchBlock);
prepass.exceptionTable.push_back(catchBlock);
addHandlerForCatchBlock(catchBlock, handlerOffset, exceptionType);
prevCatch = catchBlock = new (memManager) CatchBlock(nextRegionId++, handlerOffset, endOffset, numCatch++);
prepass.stateTable->getStateInfo(handlerOffset)->addExceptionInfo(catchBlock);
prepass.exceptionTable.push_back(catchBlock);
addHandlerForCatchBlock(catchBlock, handlerOffset, exceptionType);
} else {
prevCatch = catchBlock = new (memManager) CatchBlock(nextRegionId++, tryOffset, endOffset, numCatch++);
prepass.stateTable->getStateInfo(tryOffset)->addExceptionInfo(catchBlock);
prepass.exceptionTable.push_back(catchBlock);
addHandlerForCatchBlock(catchBlock, handlerOffset, exceptionType);
}
}
return 1; // all exceptionTypes are OK
}
U_32 numCatch;
MemoryManager& memManager;
JavaLabelPrepass& prepass;
CompilationInterface& compilationInterface;
MethodDesc* enclosingMethod;
CatchBlock* prevCatch;
U_32 nextRegionId;
};
JavaLabelPrepass::JavaLabelPrepass(MemoryManager& mm,
TypeManager& tm,
MemoryManager& irManager,
MethodDesc& md,
CompilationInterface& ci,
Opnd **actualArgs)
: JavaByteCodeParserCallback(mm,md.getByteCodeSize()),
memManager(mm),
typeManager(tm),
methodDesc(md),
compilationInterface(ci),
localVars(mm),
jsrEntriesMap(mm),
retToSubEntryMap(mm),
exceptionTable(mm),
problemTypeToken(MAX_UINT32)
{
U_32 numByteCodes = methodDesc.getByteCodeSize();
//nextIsLabel = false;
int32Type = typeManager.getInt32Type();
int64Type = typeManager.getInt64Type();
singleType = typeManager.getSingleType();
doubleType= typeManager.getDoubleType();
numLabels = 0;
labels = new (memManager) BitSet(memManager,numByteCodes);
subroutines = new (memManager) BitSet(memManager,numByteCodes);
numVars = methodDesc.getNumVars();
int numStack = methodDesc.getMaxStack()+1;
stateInfo.stack = new (memManager) StateInfo::SlotInfo[numVars+numStack];
stateInfo.stackDepth = numVars;
for (U_32 k=0; k < numVars+numStack; k++) {
struct StateInfo::SlotInfo *slot = &stateInfo.stack[k];
slot->type = NULL;
slot->slotFlags = 0;
slot->vars = NULL;
slot->jsrLabelOffset = 0;
}
blockNumber = 0;
labelOffsets = NULL;
// exceptions
stateTable = new (memManager) StateTable(memManager,typeManager,*this,numStack,numVars);
// 1st count number of catch and finally blocks
// parse and create exception info
JavaExceptionParser exceptionTypes(irManager,*this,compilationInterface,&methodDesc);
// fix exception handlers
unsigned problemToken = exceptionTypes.parseHandlers();
if(problemToken != MAX_UINT32)
{
problemTypeToken = problemToken;
noNeedToParse = true;
numCatchHandlers = 0;
} else {
numCatchHandlers = exceptionTypes.numCatch;
}
hasJsrLabels = false;
isFallThruLabel = true;
U_32 numArgs = methodDesc.getNumParams();
for (U_32 i=0, j=0; i<numArgs; i++,j++) {
Type *type;
struct StateInfo::SlotInfo *slot = &stateInfo.stack[j];
if (actualArgs != NULL) {
// inlined version
Opnd *actual = actualArgs[i];
type = actual->getType();
if(Log::isEnabled()) {
Log::out() << "PARAM " << (int)i << " sig: ";
methodDesc.getParamType(i)->print(Log::out());
Log::out() << " actual: ";
type->print(Log::out()); Log::out() << ::std::endl;
}
slot->type = typeManager.toInternalType(type);
if (Simplifier::isNonNullObject(actual)) StateInfo::setNonNull(slot);
if (Simplifier::isNonNullParameter(actual)) StateInfo::setNonNull(slot);
if (Simplifier::isExactType(actual)) StateInfo::setExactType(slot);
} else {
type = methodDesc.getParamType(i);
if (!type) {
// linkage error will happen at the usage point of this parameter
// here we just keep it as NullObj
type = typeManager.getNullObjectType();
}
slot->type = typeManager.toInternalType(type);
}
slot->vars = new (memManager) SlotVar(getOrCreateVarInc(0, j, slot->type));
JavaVarType javaType = getJavaType(type);
if (javaType == L || javaType == D) j++;
}
stateTable->setStateInfo(&stateInfo, 0, false);
}
void JavaLabelPrepass::offset(U_32 offset) {
bytecodevisited->setBit(offset,true);
if (offset==0)
stateTable->restoreStateInfo(&stateInfo, offset);
if (labels->getBit(offset) == true) {
if (linearPassDone)
stateTable->restoreStateInfo(&stateInfo, offset);
setStackVars();
if (!linearPassDone) {
Log::out() << "LINEAR " << std::endl;
propagateStateInfo(offset,isFallThruLabel);
isFallThruLabel = true;
}
if (Log::isEnabled()) Log::out() << "BASICBLOCK " << (I_32)offset << " #" << blockNumber << std::endl;
++blockNumber;
visited->setBit(offset,true);
stateTable->restoreStateInfo(&stateInfo,offset);
if (stateInfo.isSubroutineEntry()) {
stateInfo.push(typeManager.getSystemObjectType());
stateInfo.top().jsrLabelOffset = offset;
}
}
}
void JavaLabelPrepass::setLabel(U_32 offset) {
if (labels->getBit(offset)) // this label is already seen
return;
if (Log::isEnabled()) Log::out() << "SET LABEL " << (int) offset << " #" << (int) numLabels << ::std::endl;
labels->setBit(offset,true);
numLabels++;
}
struct LabelOffsetVisitor : public BitSet::Visitor {
LabelOffsetVisitor(U_32* l) : labelOffset(l) {}
void visit(U_32 elem) {*labelOffset++ = elem;}
U_32* labelOffset;
};
// called to indicate end of parsing
void JavaLabelPrepass::parseDone() {
labelOffsets = new (memManager) U_32[numLabels];
struct LabelOffsetVisitor avisitor(labelOffsets);
labels->visitElems(avisitor);
if (Log::isEnabled()) Log::out() << ::std::endl << "================= PREPASS IS FINISHED =================" << ::std::endl << ::std::endl;
}
U_32 JavaLabelPrepass::getLabelId(U_32 offset) {
if (numLabels == 0)
return (U_32) -1;
U_32 lo = 0;
U_32 hi = numLabels-1;
if (offset > labelOffsets[hi] || offset < labelOffsets[lo])
// not in this set
return (U_32) -1;
while (hi-lo > 4) {
U_32 mid = lo + ((hi-lo) >> 1);
if (offset < labelOffsets[mid])
hi = mid;
else
lo = mid;
}
// hi-lo <= 4
while (lo <= hi) {
if (labelOffsets[lo] == offset)
return lo;
lo++;
}
return (U_32) -1;
}
VariableIncarnation* JavaLabelPrepass::getVarInc(U_32 offset, U_32 index)
{
int numStack = methodDesc.getMaxStack()+1;
U_32 key = offset*(numVars+numStack)+index;
StlHashMap<U_32,VariableIncarnation*>::iterator iter = localVars.find(key);
if (iter==localVars.end()) return NULL;
return (*iter).second;
}
VariableIncarnation* JavaLabelPrepass::getOrCreateVarInc(U_32 offset, U_32 index, Type* type)
{
int numStack = methodDesc.getMaxStack()+1;
U_32 key = offset*(numVars+numStack)+index;
StlHashMap<U_32,VariableIncarnation*>::iterator iter = localVars.find(key);
VariableIncarnation* var;
if (iter==localVars.end()) {
var = new(memManager) VariableIncarnation(offset, type);
localVars[key] = var;
} else {
var = (*iter).second;
}
return var;
}
void JavaLabelPrepass::createMultipleDefVarOpnds(IRBuilder* irBuilder)
{
StlHashMap<U_32,VariableIncarnation*>::iterator iter;
for(iter = localVars.begin(); iter!=localVars.end(); ++iter) {
VariableIncarnation* var = (*iter).second;
var->createMultipleDefVarOpnd(irBuilder);
}
}
//
// stack operations
//
StateInfo::SlotInfo& JavaLabelPrepass::topType() {
return stateInfo.stack[stateInfo.stackDepth-1];
}
StateInfo::SlotInfo& JavaLabelPrepass::popType() {
StateInfo::SlotInfo& top = stateInfo.stack[--stateInfo.stackDepth];
assert (stateInfo.stackDepth >= numVars);
return top;
}
void JavaLabelPrepass::popAndCheck(Type *type) {
StateInfo::SlotInfo& top = popType();
if( !(top.type == type) )
assert(0);
}
void JavaLabelPrepass::popAndCheck(JavaVarType type) {
StateInfo::SlotInfo& top = popType();
if(!(top.type && getJavaType(top.type) == type))
assert(0);
}
void JavaLabelPrepass::pushType(Type *type) {
stateInfo.push(type);
}
void JavaLabelPrepass::pushType(Type *type, U_32 varNumber) {
stateInfo.push(type).setVarNumber(varNumber);
}
void JavaLabelPrepass::pushType(StateInfo::SlotInfo& slot) {
stateInfo.stack[stateInfo.stackDepth++] = slot;
stateInfo.stack[stateInfo.stackDepth-1].jsrLabelOffset = 0;
}
void JavaLabelPrepass::setStackVars() {
if(Log::isEnabled()) {
Log::out() << "SET STACK VARS:" << ::std::endl;
}
for (unsigned i=numVars; i < stateInfo.stackDepth; i++) {
struct StateInfo::SlotInfo* slot = &stateInfo.stack[i];
if(Log::isEnabled()) {
Log::out() << "SLOT " << i << ":" << ::std::endl;
StateInfo::print(*slot, Log::out());
Log::out() << ::std::endl;
}
Type* type = slot->type;
assert(type);
SlotVar* sv = slot->vars;
VariableIncarnation* var = getOrCreateVarInc(currentOffset, i, type);
// Do not merge stack vars of incompatible types
if (sv) {
assert(sv->getVarIncarnation()->getDeclaredType());
assert(var->getDeclaredType());
UNUSED Type* commonType = typeManager.getCommonType(sv->getVarIncarnation()->getDeclaredType(),var->getDeclaredType());
assert(commonType);
VariableIncarnation::linkAndMergeIncarnations(sv->getVarIncarnation(),var,&typeManager);
var->setMultipleDefs();
} else {
slot->vars = new (memManager) SlotVar(var);
}
if(Log::isEnabled()) {
Log::out() << "AFTER" << ::std::endl;
StateInfo::print(*slot, Log::out());
Log::out() << ::std::endl;
}
}
if(Log::isEnabled()) {
Log::out() << "SET STACK VARS DONE." << ::std::endl;
}
}
void JavaLabelPrepass::parseError() {
}
//
// branches
//
void JavaLabelPrepass::checkTargetForRestart(U_32 target) {
// If the target of a branch has been visited, but has no state info, then we
// will not merge information such as variable incarnations from that first visit
// with the information from the current branch.
// Here we try to catch this and then force a revisit to merge the old information in
if (bytecodevisited->getBit(target) && !stateTable->getStateInfo(target)) {
// For now let's begin again from the start and hope it propagates to the target
pushRestart(0);
getVisited()->clear();
}
}
void JavaLabelPrepass::propagateStateInfo(U_32 offset, bool isFallThru) {
setLabel(offset);
stateTable->setStateInfo(&stateInfo,offset,isFallThru);
}
void JavaLabelPrepass::ifeq(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::ifne(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::iflt(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::ifge(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::ifgt(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::ifle(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::if_icmpeq(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::if_icmpne(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::if_icmplt(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::if_icmpge(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::if_icmpgt(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::if_icmple(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(int32Type);
popAndCheck(int32Type);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::if_acmpeq(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(A);
popAndCheck(A);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::if_acmpne(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(A);
popAndCheck(A);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::ifnull(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(A);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::ifnonnull(U_32 targetOffset,U_32 nextOffset) {
popAndCheck(A);
setStackVars();
checkTargetForRestart(targetOffset);
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
setLabel(nextOffset);
isFallThruLabel = targetOffset > nextOffset;
}
void JavaLabelPrepass::goto_(U_32 targetOffset,U_32 nextOffset) {
setStackVars();
checkTargetForRestart(targetOffset);
propagateStateInfo(targetOffset,false);
}
//
// returns
//
void JavaLabelPrepass::ireturn(U_32 off) {popAndCheck(int32Type); }
void JavaLabelPrepass::lreturn(U_32 off) {popAndCheck(int64Type); }
void JavaLabelPrepass::freturn(U_32 off) {popAndCheck(singleType);}
void JavaLabelPrepass::dreturn(U_32 off) {popAndCheck(doubleType);}
void JavaLabelPrepass::areturn(U_32 off) {popAndCheck(A); }
void JavaLabelPrepass::return_(U_32 off) { }
//
// jsr/ret
//
void JavaLabelPrepass::jsr(U_32 targetOffset, U_32 nextOffset) {
stateTable->createStateInfo(targetOffset)->setSubroutineEntry();
setSubroutineEntry(targetOffset);
hasJsrLabels = true;
setStackVars();
// propagate state info on both ways
propagateStateInfo(targetOffset,false);
propagateStateInfo(nextOffset,false);
// store information for filling slot->jsrNextOffset
// (in case the slot is a returnAddress)
//
jsrEntriesMap.insert(std::make_pair(targetOffset,nextOffset));
getVisited()->setBit(targetOffset,false);
}
void JavaLabelPrepass::ret(uint16 varIndex, const U_8* byteCodes) {
StateInfo::SlotInfo *slot = &stateInfo.stack[varIndex];
VariableIncarnation* var = slot->vars->getVarIncarnation();
assert(var);
var->setMultipleDefs();
setStackVars();
U_32 subEntryOffset = slot->jsrLabelOffset;
stateInfo.cleanFinallyInfo(subEntryOffset);
assert(retToSubEntryMap.find(currentOffset) == retToSubEntryMap.end() ||
retToSubEntryMap[currentOffset] == subEntryOffset);
retToSubEntryMap[currentOffset] = subEntryOffset;
JsrEntriesMapCIterRange sub_entry_range = jsrEntriesMap.equal_range(subEntryOffset);
JsrEntryToJsrNextMap::const_iterator iter;
for (iter = sub_entry_range.first; iter != sub_entry_range.second; iter++) {
assert((*iter).first == subEntryOffset);
U_32 jsrNextOffset = (*iter).second;
// according to JVM Spec:
// When executing the ret instruction, which implements a
// return from a subroutine, there must be only one possible
// subroutine from which the instruction can be returning. Two
// different subroutines cannot "merge" their execution to a
// single ret instruction.
//
// propagating new objects created in finally section
// to the instruction that follows the JSR
//
stateTable->setStateInfoFromFinally(&stateInfo, jsrNextOffset);
labelStack->push((U_8*)byteCodes + jsrNextOffset);
}
}
//
// switches
//
void JavaLabelPrepass::tableswitch(JavaSwitchTargetsIter* iter) {
popAndCheck(int32Type);
setStackVars();
while (iter->hasNext())
propagateStateInfo(iter->getNextTarget(),false);
propagateStateInfo(iter->getDefaultTarget(),false);
}
void JavaLabelPrepass::lookupswitch(JavaLookupSwitchTargetsIter* iter) {
popAndCheck(int32Type);
setStackVars();
U_32 dummy;
while (iter->hasNext())
propagateStateInfo(iter->getNextTarget(&dummy),false);
propagateStateInfo(iter->getDefaultTarget(),false);
}
//
// remaining instructions
//
void JavaLabelPrepass::nop() {}
void JavaLabelPrepass::aconst_null() { pushType(typeManager.getNullObjectType()); }
void JavaLabelPrepass::iconst(I_32 val) { pushType(int32Type); }
void JavaLabelPrepass::lconst(int64 val) { pushType(int64Type); }
void JavaLabelPrepass::fconst(float val) { pushType(singleType); }
void JavaLabelPrepass::dconst(double val) { pushType(doubleType); }
void JavaLabelPrepass::bipush(I_8 val) { pushType(int32Type); }
void JavaLabelPrepass::sipush(int16 val) { pushType(int32Type); }
void JavaLabelPrepass::iload(uint16 varIndex) { genLoad(int32Type,varIndex); }
void JavaLabelPrepass::lload(uint16 varIndex) { genLoad(int64Type,varIndex); }
void JavaLabelPrepass::fload(uint16 varIndex) { genLoad(singleType,varIndex); }
void JavaLabelPrepass::dload(uint16 varIndex) { genLoad(doubleType,varIndex); }
void JavaLabelPrepass::aload(uint16 varIndex) { genTypeLoad(varIndex); }
void JavaLabelPrepass::istore(uint16 varIndex,U_32 off) { genStore(int32Type,varIndex,off); }
void JavaLabelPrepass::lstore(uint16 varIndex,U_32 off) { genStore(int64Type,varIndex,off); }
void JavaLabelPrepass::fstore(uint16 varIndex,U_32 off) { genStore(singleType,varIndex,off); }
void JavaLabelPrepass::dstore(uint16 varIndex,U_32 off) { genStore(doubleType,varIndex,off); }
void JavaLabelPrepass::astore(uint16 varIndex,U_32 off) { genTypeStore(varIndex,off); }
void JavaLabelPrepass::iaload() { genArrayLoad(int32Type); }
void JavaLabelPrepass::laload() { genArrayLoad(int64Type); }
void JavaLabelPrepass::faload() { genArrayLoad(singleType); }
void JavaLabelPrepass::daload() { genArrayLoad(doubleType); }
void JavaLabelPrepass::aaload() { genTypeArrayLoad(); }
void JavaLabelPrepass::baload() { genArrayLoad(int32Type); }
void JavaLabelPrepass::caload() { genArrayLoad(int32Type); }
void JavaLabelPrepass::saload() { genArrayLoad(int32Type); }
void JavaLabelPrepass::iastore() { genArrayStore(int32Type);}
void JavaLabelPrepass::lastore() { genArrayStore(int64Type);}
void JavaLabelPrepass::fastore() { genArrayStore(singleType);}
void JavaLabelPrepass::dastore() { genArrayStore(doubleType);}
void JavaLabelPrepass::aastore() { genTypeArrayStore();}
void JavaLabelPrepass::bastore() { genArrayStore(int32Type);}
void JavaLabelPrepass::castore() { genArrayStore(int32Type);}
void JavaLabelPrepass::sastore() { genArrayStore(int32Type);}
void JavaLabelPrepass::iadd() { genBinary(int32Type); }
void JavaLabelPrepass::ladd() { genBinary(int64Type); }
void JavaLabelPrepass::fadd() { genBinary(singleType); }
void JavaLabelPrepass::dadd() { genBinary(doubleType); }
void JavaLabelPrepass::isub() { genBinary(int32Type); }
void JavaLabelPrepass::lsub() { genBinary(int64Type); }
void JavaLabelPrepass::fsub() { genBinary(singleType); }
void JavaLabelPrepass::dsub() { genBinary(doubleType); }
void JavaLabelPrepass::imul() { genBinary(int32Type); }
void JavaLabelPrepass::lmul() { genBinary(int64Type); }
void JavaLabelPrepass::fmul() { genBinary(singleType); }
void JavaLabelPrepass::dmul() { genBinary(doubleType); }
void JavaLabelPrepass::idiv() { genBinary(int32Type); }
void JavaLabelPrepass::ldiv() { genBinary(int64Type); }
void JavaLabelPrepass::fdiv() { genBinary(singleType); }
void JavaLabelPrepass::ddiv() { genBinary(doubleType); }
void JavaLabelPrepass::irem() { genBinary(int32Type); }
void JavaLabelPrepass::lrem() { genBinary(int64Type); }
void JavaLabelPrepass::frem() { genBinary(singleType); }
void JavaLabelPrepass::drem() { genBinary(doubleType); }
void JavaLabelPrepass::ineg() { genUnary (int32Type); }
void JavaLabelPrepass::lneg() { genUnary (int64Type); }
void JavaLabelPrepass::fneg() { genUnary (singleType); }
void JavaLabelPrepass::dneg() { genUnary (doubleType); }
void JavaLabelPrepass::ishl() { genShift (int32Type); }
void JavaLabelPrepass::lshl() { genShift (int64Type); }
void JavaLabelPrepass::ishr() { genShift (int32Type); }
void JavaLabelPrepass::lshr() { genShift (int64Type); }
void JavaLabelPrepass::iushr() { genShift (int32Type); }
void JavaLabelPrepass::lushr() { genShift (int64Type); }
void JavaLabelPrepass::iand() { genBinary(int32Type); }
void JavaLabelPrepass::land() { genBinary(int64Type); }
void JavaLabelPrepass::ior() { genBinary(int32Type); }
void JavaLabelPrepass::lor() { genBinary(int64Type); }
void JavaLabelPrepass::ixor() { genBinary(int32Type); }
void JavaLabelPrepass::lxor() { genBinary(int64Type); }
void JavaLabelPrepass::i2l() { genConv(int32Type,int64Type); }
void JavaLabelPrepass::i2f() { genConv(int32Type,singleType); }
void JavaLabelPrepass::i2d() { genConv(int32Type,doubleType); }
void JavaLabelPrepass::l2i() { genConv(int64Type,int32Type); }
void JavaLabelPrepass::l2f() { genConv(int64Type,singleType); }
void JavaLabelPrepass::l2d() { genConv(int64Type,doubleType); }
void JavaLabelPrepass::f2i() { genConv(singleType,int32Type); }
void JavaLabelPrepass::f2l() { genConv(singleType,int64Type); }
void JavaLabelPrepass::f2d() { genConv(singleType,doubleType); }
void JavaLabelPrepass::d2i() { genConv(doubleType,int32Type); }
void JavaLabelPrepass::d2l() { genConv(doubleType,int64Type); }
void JavaLabelPrepass::d2f() { genConv(doubleType,singleType); }
void JavaLabelPrepass::i2b() { genConv(int32Type,int32Type); }
void JavaLabelPrepass::i2c() { genConv(int32Type,int32Type); }
void JavaLabelPrepass::i2s() { genConv(int32Type,int32Type); }
void JavaLabelPrepass::lcmp() { genCompare(int64Type);}
void JavaLabelPrepass::fcmpl() { genCompare(singleType);}
void JavaLabelPrepass::fcmpg() { genCompare(singleType);}
void JavaLabelPrepass::dcmpl() { genCompare(doubleType);}
void JavaLabelPrepass::dcmpg() { genCompare(doubleType);}
void JavaLabelPrepass::new_(U_32 constPoolIndex) {
StateInfo::SlotInfo slot;
StateInfo::setNonNull(&slot);
StateInfo::setExactType(&slot);
Type* nType = compilationInterface.getNamedType(methodDesc.getParentHandle(), constPoolIndex, ResolveNewCheck_DoCheck);
assert(nType);
slot.type = nType;
slot.vars = NULL;
jitrino_assert( slot.type);
pushType(slot);
}
void JavaLabelPrepass::newarray(U_8 etype) {
popAndCheck(int32Type);
NamedType *elemType = NULL;
switch (etype) {
case 4: elemType = typeManager.getBooleanType(); break;
case 5: elemType = typeManager.getCharType(); break;
case 6: elemType = typeManager.getSingleType(); break;
case 7: elemType = typeManager.getDoubleType(); break;
case 8: elemType = typeManager.getInt8Type(); break;
case 9: elemType = typeManager.getInt16Type(); break;
case 10: elemType = typeManager.getInt32Type(); break;
case 11: elemType = typeManager.getInt64Type(); break;
default: jitrino_assert( 0);
}
StateInfo::SlotInfo slot;
StateInfo::setNonNull(&slot);
StateInfo::setExactType(&slot);
slot.type = typeManager.getArrayType(elemType);
slot.vars = NULL;
pushType(slot);
}
void JavaLabelPrepass::anewarray(U_32 constPoolIndex) {
popAndCheck(int32Type);
StateInfo::SlotInfo slot;
StateInfo::setNonNull(&slot);
StateInfo::setExactType(&slot);
Type* type = compilationInterface.getNamedType(methodDesc.getParentHandle(), constPoolIndex);
assert(type);
slot.type = typeManager.getArrayType(type);
slot.vars = NULL;
jitrino_assert( slot.type);
pushType(slot);
}
void JavaLabelPrepass::arraylength() {
popAndCheck(A);
pushType(int32Type);
}
void JavaLabelPrepass::athrow() {
popAndCheck(A);
}
void JavaLabelPrepass::checkcast(U_32 constPoolIndex) {
StateInfo::SlotInfo slot = stateInfo.stack[stateInfo.stackDepth - 1];
if ( (slot.type) &&
(slot.type->tag == Type::NullObject ) &&
(slot.vars == NULL) ) {
return;
}
Type* type = compilationInterface.getNamedType(methodDesc.getParentHandle(), constPoolIndex);
assert(type);
popAndCheck(A);
pushType(type);
}
int JavaLabelPrepass::instanceof(const U_8* bcp, U_32 constPoolIndex, U_32 off) {
popType();
pushType(int32Type);
return 3; // length of instanceof
}
void JavaLabelPrepass::monitorenter() { popAndCheck(A); }
void JavaLabelPrepass::monitorexit() { popAndCheck(A); }
void JavaLabelPrepass::iinc(uint16 varIndex,I_32 amount) {
stateInfo.stack[varIndex].vars->getVarIncarnation()->setMultipleDefs();
}
void JavaLabelPrepass::ldc(U_32 constPoolIndex) {
// load 32-bit quantity or string from constant pool
Type* constantType =
compilationInterface.getConstantType(&methodDesc,constPoolIndex);
if (constantType->isSystemString() || constantType->isSystemClass()) {
pushType(constantType);
} else if (constantType->isInt4()) {
pushType(int32Type);
} else if (constantType->isSingle()) {
pushType(singleType);
} else {
jitrino_assert( 0);
}
}
void JavaLabelPrepass::ldc2(U_32 constPoolIndex) {
// load 64-bit quantity from constant pool
Type* constantType =
compilationInterface.getConstantType(&methodDesc,constPoolIndex);
if (constantType->isInt8()) {
pushType(int64Type);
} else if (constantType->isDouble()) {
pushType(doubleType);
} else {
jitrino_assert( 0);
}
}
void JavaLabelPrepass::getstatic(U_32 constPoolIndex) {
FieldDesc *fdesc = compilationInterface.getStaticField(methodDesc.getParentHandle(), constPoolIndex, false);
Type* fieldType = 0;
if (fdesc && fdesc->isStatic()) {
fieldType = fdesc->getFieldType();
}
if (!fieldType){
fieldType = compilationInterface.getFieldType(methodDesc.getParentHandle(), constPoolIndex);
}
assert(fieldType);
pushType(typeManager.toInternalType(fieldType));
}
void JavaLabelPrepass::putstatic(U_32 constPoolIndex) {
FieldDesc *fdesc = compilationInterface.getStaticField(methodDesc.getParentHandle(), constPoolIndex, true);
Type* fieldType = fdesc ? fdesc->getFieldType() : NULL;
if (fieldType){
popAndCheck(getJavaType(fieldType));
} else {
// lazy resolution mode or
// throwing respective exception helper will be inserted at the Translator
popType();
}
}
void JavaLabelPrepass::getfield(U_32 constPoolIndex) {
popAndCheck(A);//obj
FieldDesc *fdesc = compilationInterface.getNonStaticField(methodDesc.getParentHandle(), constPoolIndex, false);
Type* fieldType = NULL;
if (fdesc) {
fieldType = fdesc->getFieldType();
}
if (!fieldType){
fieldType = compilationInterface.getFieldType(methodDesc.getParentHandle(), constPoolIndex);
}
assert(fieldType);
pushType(typeManager.toInternalType(fieldType));
}
void JavaLabelPrepass::putfield(U_32 constPoolIndex) {
FieldDesc *fdesc = compilationInterface.getNonStaticField(methodDesc.getParentHandle(), constPoolIndex, true);
Type* fieldType = fdesc ? fdesc->getFieldType() : NULL;
if (fieldType){
popAndCheck(getJavaType(fieldType));
} else {
// throwing respective exception helper will be inserted at the Translator
// TODO: why not check types for lazy-resolve mode?
popType();
}
popAndCheck(A);
}
void JavaLabelPrepass::invokevirtual(U_32 constPoolIndex){
MethodDesc *mdesc = compilationInterface.getVirtualMethod(methodDesc.getParentHandle(), constPoolIndex);
if (mdesc) {// resolution was successful
invoke(mdesc);
} else { // exception happens during resolving/linking
const char* methodSig_string = methodSignatureString(constPoolIndex);
popType(); // is not static
pseudoInvoke(methodSig_string);
}
}
void JavaLabelPrepass::invokespecial(U_32 constPoolIndex){
MethodDesc* mdesc = compilationInterface.getSpecialMethod(methodDesc.getParentHandle(),constPoolIndex);
if (mdesc) {// resolution was successful
invoke(mdesc);
} else {
// exception happens during resolving/linking or lazy resolution mode
const char* methodSig_string = methodSignatureString(constPoolIndex);
popType(); // is not static
pseudoInvoke(methodSig_string);
}
}
void JavaLabelPrepass::invokestatic(U_32 constPoolIndex) {
MethodDesc *mdesc = compilationInterface.getStaticMethod(methodDesc.getParentHandle(), constPoolIndex);
if (mdesc) {// resolution was successful
invoke(mdesc);
} else { // exception happens during resolving/linking
const char* methodSig_string = methodSignatureString(constPoolIndex);
pseudoInvoke(methodSig_string);
}
}
void JavaLabelPrepass::invokeinterface(U_32 constPoolIndex,U_32 count) {
MethodDesc *mdesc = compilationInterface.getInterfaceMethod(methodDesc.getParentHandle(), constPoolIndex);
if (mdesc) {// resolution was successful
invoke(mdesc);
} else { // exception happens during resolving/linking
const char* methodSig_string = methodSignatureString(constPoolIndex);
popType(); // is not static
pseudoInvoke(methodSig_string);
}
}
void JavaLabelPrepass::multianewarray(U_32 constPoolIndex,U_8 dimensions) {
for (int i =0; i < dimensions; i++) {
popAndCheck(int32Type);
}
Type *type = compilationInterface.getNamedType(methodDesc.getParentHandle(), constPoolIndex);
jitrino_assert(type);
pushType(type);
}
void JavaLabelPrepass::pseudoInvoke(const char* methodSig) {
assert(methodSig);
U_32 numArgs = getNumArgsBySignature(methodSig);
// pop numArgs items
for (int i=numArgs-1; i>=0; i--)
popType();
// recognize and push respective returnType
Type* retType = getRetTypeBySignature(compilationInterface, methodDesc.getParentHandle(), methodSig);
assert(retType);
// push the return type
if (retType->tag != Type::Void) {
pushType(typeManager.toInternalType(retType));
}
}
U_32 JavaLabelPrepass::getNumArgsBySignature(const char* methodSig)
{
assert(methodSig);
assert(*methodSig == '(');
U_32 numArgs = 0;
// start just after '(' and go until ')' counting 'numArgs'
for(++methodSig ;*methodSig != ')'; methodSig++) {
switch( *methodSig )
{
case 'L':
// skip class name
while( *(++methodSig) != ';' ) assert(*methodSig);
case 'B':
case 'C':
case 'D':
case 'F':
case 'I':
case 'J':
case 'S':
case 'Z':
numArgs++;
break;
case '[': // do nothing
break;
case '(': // we have started from index = 1
case ')': // must go out earlier
case 'V': // 'V' can not be in the argument list
default:
assert(0); // impossible! Verifier must check and catch this
break;
}
}
// the last observed index should point to ')' after getNumArgsBySignature call
assert(*methodSig == ')');
return numArgs;
}
Type* JavaLabelPrepass::getRetTypeBySignature(CompilationInterface& ci, Class_Handle enclClass, const char* origSig)
{
assert(*origSig== '(' || *origSig == ')');
while( *(origSig++) != ')' );
U_32 stub=0;
return getTypeByDescriptorString(ci, enclClass, origSig, stub);
}
Type* JavaLabelPrepass::getTypeByDescriptorString(CompilationInterface& ci, Class_Handle enclClass, const char* descriptorString, U_32& len) {
U_32 arrayDim = 0;
len=1;
Type* resType = NULL;
// collect array dimension if any
while( *(descriptorString) == '[' ) {
arrayDim++;
descriptorString++;
len++;
}
TypeManager& typeManager = ci.getTypeManager();
switch( *descriptorString )
{
case 'L':
{
if (!typeManager.isLazyResolutionMode()) {
resType = typeManager.getUnresolvedObjectType();
} else {
resType = ci.getTypeFromDescriptor(enclClass, descriptorString);
}
while( *(++descriptorString) != ';' ) {
len++;
assert(*descriptorString);
}
len++; //';' char
}
break;
case 'B':
resType = typeManager.getInt8Type();
break;
case 'C':
resType = typeManager.getCharType();
break;
case 'D':
resType = typeManager.getDoubleType();
break;
case 'F':
resType = typeManager.getSingleType();
break;
case 'I':
resType = typeManager.getInt32Type();
break;
case 'J':
resType = typeManager.getInt64Type();
break;
case 'S':
resType = typeManager.getInt16Type();
break;
case 'Z':
resType = typeManager.getBooleanType();
break;
case 'V':
resType = typeManager.getVoidType();
break; // leave stack as is
case '[': // all '[' are already skipped
case '(': // we have already pass it
case ')': // we have just leave it back
default: // impossible! Verifier must check and catch this
assert(0);
resType = typeManager.getUnresolvedObjectType();
break;
}
assert(resType);
if (arrayDim > 0) {
for (;arrayDim > 0; arrayDim--) {
resType = typeManager.getArrayType(resType, false);
}
}
return resType;
}
void JavaLabelPrepass::invoke(MethodDesc* methodDesc) {
// pop source operands
for (int i = methodDesc->getNumParams()-1; i>=0; i--)
popType();
Type* type = methodDesc->getReturnType();
// push the return type
if (type) {
if ( type->tag != Type::Void ) {
pushType(typeManager.toInternalType(type));
}
} else {
// type == NULL means that the returnType was not resolved successfully
// but it can be resolved later inside the callee (with some "magic" custom class loader for example)
// Or respective exception will be thrown there (in the callee) at the attempt to create (new)
// an object of unresolved type
pushType(typeManager.getNullObjectType());
}
}
void JavaLabelPrepass::pop() { popType(); }
void JavaLabelPrepass::pop2() {
StateInfo::SlotInfo& type = popType();
if (isCategory2(type))
return;
popType();
}
void JavaLabelPrepass::dup() {
pushType(topType());
}
void JavaLabelPrepass::dup_x1() {
StateInfo::SlotInfo opnd1 = popType();
StateInfo::SlotInfo opnd2 = popType();
pushType(opnd1);
pushType(opnd2);
pushType(opnd1);
}
void JavaLabelPrepass::dup_x2() {
StateInfo::SlotInfo opnd1 = popType();
StateInfo::SlotInfo opnd2 = popType();
if (isCategory2(opnd2)) {
pushType(opnd1);
pushType(opnd2);
pushType(opnd1);
return;
}
StateInfo::SlotInfo opnd3 = popType();
pushType(opnd1);
pushType(opnd3);
pushType(opnd2);
pushType(opnd1);
}
void JavaLabelPrepass::dup2() {
StateInfo::SlotInfo opnd1 = popType();
if (isCategory2(opnd1)) {
pushType(opnd1);
pushType(opnd1);
return;
}
StateInfo::SlotInfo opnd2 = popType();
pushType(opnd2);
pushType(opnd1);
pushType(opnd2);
pushType(opnd1);
}
void JavaLabelPrepass::dup2_x1() {
StateInfo::SlotInfo opnd1 = popType();
StateInfo::SlotInfo opnd2 = popType();
if (isCategory2(opnd1)) {
// opnd1 is a category 2 instruction
pushType(opnd1);
pushType(opnd2);
pushType(opnd1);
} else {
// opnd1 is a category 1 instruction
StateInfo::SlotInfo opnd3 = popType();
pushType(opnd2);
pushType(opnd1);
pushType(opnd3);
pushType(opnd2);
pushType(opnd1);
}
}
void JavaLabelPrepass::dup2_x2() {
StateInfo::SlotInfo opnd1 = popType();
StateInfo::SlotInfo opnd2 = popType();
if (isCategory2(opnd1)) {
// opnd1 is category 2
if (isCategory2(opnd2)) {
pushType(opnd1);
pushType(opnd2);
pushType(opnd1);
} else {
// opnd2 is category 1
StateInfo::SlotInfo opnd3 = popType();
assert(isCategory2(opnd3) == false);
pushType(opnd1);
pushType(opnd3);
pushType(opnd2);
pushType(opnd1);
}
} else {
assert(isCategory2(opnd2) == false);
// both opnd1 & opnd2 are category 1
StateInfo::SlotInfo opnd3 = popType();
if (isCategory2(opnd3)) {
pushType(opnd2);
pushType(opnd1);
pushType(opnd3);
pushType(opnd2);
pushType(opnd1);
} else {
// opnd1, opnd2, opnd3 all are category 1
StateInfo::SlotInfo opnd4 = popType();
assert(isCategory2(opnd4) == false);
pushType(opnd2);
pushType(opnd1);
pushType(opnd4);
pushType(opnd3);
pushType(opnd2);
pushType(opnd1);
}
}
}
void JavaLabelPrepass::swap() {
StateInfo::SlotInfo opnd1 = popType();
StateInfo::SlotInfo opnd2 = popType();
pushType(opnd1);
pushType(opnd2);
}
///////////////////////////////////////////////////////////////////////////////
// Helper methods
///////////////////////////////////////////////////////////////////////////////
void JavaLabelPrepass::genReturn(Type *type) {
}
void JavaLabelPrepass::genStore(Type *type, U_32 index, U_32 offset) {
stateInfo.stack[index].jsrLabelOffset = stateInfo.stack[stateInfo.stackDepth-1].jsrLabelOffset;
popAndCheck(type);
stateInfo.stack[index].type = type;
stateInfo.stack[index].slotFlags= 0;
stateInfo.stack[index].vars = new (memManager) SlotVar(getOrCreateVarInc(offset, index, type));
propagateLocalVarToHandlers(index);
}
void JavaLabelPrepass::genTypeStore(U_32 index, U_32 offset) {
StateInfo::SlotInfo& slot = popType();
Type *type = slot.type;
stateInfo.stack[index].type = type;
stateInfo.stack[index].slotFlags= slot.slotFlags;
VariableIncarnation* offset_varinc = getOrCreateVarInc(offset, index, type);
offset_varinc->setDeclaredType(typeManager.getCommonType(type, offset_varinc->getDeclaredType()));
stateInfo.stack[index].vars = new (memManager) SlotVar(offset_varinc);
if(Log::isEnabled()) {
Log::out() << "genTypeStore: offset=" << offset
<< " index=" << index
<< " vars: ";
stateInfo.stack[index].vars->print(Log::out());
Log::out() << ::std::endl;
}
stateInfo.stack[index].jsrLabelOffset = slot.jsrLabelOffset;
propagateLocalVarToHandlers(index);
}
void JavaLabelPrepass::genLoad(Type *type, U_32 index) {
assert(stateInfo.stack[index].type == type);
pushType(type,index);
stateInfo.stack[stateInfo.stackDepth-1].jsrLabelOffset = stateInfo.stack[index].jsrLabelOffset;
SlotVar* vars = stateInfo.stack[index].vars;
if (vars) {
vars->mergeVarIncarnations(&typeManager);
}
}
void JavaLabelPrepass::genTypeLoad(U_32 index) {
Type *type = stateInfo.stack[index].type;
SlotVar* vars = stateInfo.stack[index].vars;
if (vars) {
vars->mergeVarIncarnations(&typeManager);
type = vars->getVarIncarnation()->getDeclaredType();
}
pushType(type,index);
stateInfo.stack[stateInfo.stackDepth-1].jsrLabelOffset = stateInfo.stack[index].jsrLabelOffset;
}
void JavaLabelPrepass::genArrayLoad (Type *type) {
popAndCheck(int32Type);
popAndCheck(A);
pushType(type);
}
void JavaLabelPrepass::genTypeArrayLoad() {
popAndCheck(int32Type);
Type* type = popType().type;
assert(type->isArrayType() || type->isNullObject() || type->isUnresolvedObject());
if(type->isArrayType()) {
type = ((ArrayType*)type)->getElementType();
}
pushType(type);
}
void JavaLabelPrepass::genArrayStore(Type *type) {
popAndCheck(type);
popAndCheck(int32Type);
type = popType().type;
assert(type->isArrayType() || type->isNullObject());
}
void JavaLabelPrepass::genTypeArrayStore() {
popType();
popAndCheck(int32Type);
UNUSED Type *type = popType().type;
assert(type->isArrayType() || type->isNullObject() || type->isUnresolvedObject());
}
void JavaLabelPrepass::genBinary (Type *type) {
popAndCheck(type);
popAndCheck(type);
pushType(type);
}
void JavaLabelPrepass::genUnary (Type *type) {
popAndCheck(type);
pushType(type);
}
void JavaLabelPrepass::genShift (Type *type) {
popAndCheck(int32Type);
popAndCheck(type);
pushType(type);
}
void JavaLabelPrepass::genConv (Type *from, Type *to) {
popAndCheck(from);
pushType(to);
}
void JavaLabelPrepass::genCompare (Type *type) {
popAndCheck(type);
popAndCheck(type);
pushType(int32Type);
}
const char* JavaLabelPrepass::methodSignatureString(U_32 cpIndex) {
return compilationInterface.getSignatureString(&methodDesc,cpIndex);
}
void StateTable::copySlotInfo(StateInfo::SlotInfo& to, StateInfo::SlotInfo& from) {
to.jsrLabelOffset = from.jsrLabelOffset;
to.slotFlags = from.slotFlags;
to.type = from.type;
to.varNumber = from.varNumber;
to.vars = from.vars ? new (memManager) SlotVar(from.vars, memManager) : NULL;
}
void StateTable::setStateInfo(StateInfo *inState, U_32 offset, bool isFallThru, bool varsOnly) {
if(Log::isEnabled()) {
Log::out() << "SETSTATE offset=" <<(int)offset << " depth=" << inState->stackDepth << ::std::endl;
printState(inState);
}
StateInfo *state = hashtable[offset];
if (state == NULL) {
state = new (memManager) StateInfo();
hashtable[offset] = state;
if (isFallThru)
state->setFallThroughLabel();
} else if (!isFallThru)
state->clearFallThroughLabel();
assert(getStateInfo(offset) != NULL);
setStackInfo(inState, offset, true, !varsOnly);
if (!state->isVisited() ) {
state->setVisited();
for ( JavaLabelPrepass::ExceptionTable::const_iterator it = prepass.getExceptionTable().begin(),
end = prepass.getExceptionTable().end(); it != end; ++it ) {
CatchBlock* except = *it;
if ( except->hasOffset(offset) ) {
if (Log::isEnabled()) Log::out() << "try-region begin=" << (int)except->getBeginOffset()
<< " end=" << (int)except->getEndOffset() << ::std::endl;
ExceptionInfo *prev = state->exceptionInfo;
bool found = false;
for (ExceptionInfo *exc = state->exceptionInfo;
exc != NULL;
exc = exc->getNextExceptionInfoAtOffset()) {
//
// Although exceptionInfo at this offset is built for the first time,
// we can find that this part of list was build for another offset.
// So, we should not build CatchBlock-chain any more. Note, this only works
// for properly nested CatchBlocks
//
if ( exc->isCatchBlock() && exc->getId() == except->getId() ) {
found = true;
break;
}
prev = exc;
}
if (!found) {
if (prev == NULL) {
state->exceptionInfo = except;
} else {
prev->setNextExceptionInfoAtOffset(except);
}
}
}
}
}
}
void StateTable::setStackInfo(StateInfo *inState, U_32 offset, bool includeVars, bool includeStack)
{
if (Log::isEnabled()) Log::out() << "SETSTACK " << includeVars << ", " << includeStack << ::std::endl;
unsigned stackDepth = inState->stackDepth;
if (stackDepth > 0) {
StateInfo *state = hashtable[offset];
assert(state);
unsigned from = includeVars ? 0 : numVars;
unsigned to = includeStack ? stackDepth : numVars;
if (maxDepth < stackDepth) maxDepth = stackDepth;
if (Log::isEnabled()) Log::out() << "MAXDEPTH " << maxDepth << ::std::endl;
StateInfo::SlotInfo *stack = state->stack;
if (stack == NULL) {
if (Log::isEnabled()) Log::out() << "NEWSTACK" << ::std::endl;
stack = new (memManager) StateInfo::SlotInfo[stackDepth+1];
state->stack = stack;
for (unsigned i = from; i < to; i++) {
copySlotInfo(stack[i], inState->stack[i]);
}
state->stackDepth = to;
} else { // needs to merge the states
if(Log::isEnabled()) {
Log::out() << " before\n";
printState(state);
}
for (unsigned i = from; i < to; i++) {
struct StateInfo::SlotInfo *inSlot = &inState->stack[i];
struct StateInfo::SlotInfo *slot = &stack[i];
if(Log::isEnabled()) {
Log::out() << " i = " << i << ::std::endl;
Log::out() << " inSlot: ";StateInfo::print(*inSlot, Log::out());Log::out() << ::std::endl;
Log::out() << " slot: ";StateInfo::print(*slot, Log::out());Log::out() << ::std::endl;
}
if(i < state->stackDepth) {
mergeSlots(inSlot, slot, offset, i < (unsigned)numVars);
} else { // inState has more slots. Additional ones should not be merged.
rewriteSlots(inSlot, slot, offset, i < (unsigned)numVars);
}
}
if(includeStack) {
assert(state->stackDepth <= stackDepth);
if(state->stackDepth < stackDepth) {
prepass.getVisited()->setBit(offset,false);
state->stackDepth = stackDepth;
}
}
}
if(Log::isEnabled()) {
Log::out() << " after\n";
printState(state);
}
}
}
void StateTable::rewriteSlots(StateInfo::SlotInfo* inSlot, StateInfo::SlotInfo* slot, U_32 offset, bool isVar) {
Type *intype = inSlot->type;
slot->type = intype;
assert(inSlot->vars);
if(!slot->vars) {
VariableIncarnation* var_inc = inSlot->vars->getVarIncarnation();
assert(var_inc);
slot->vars = new (memManager) SlotVar(var_inc);
}
slot->vars->addVarIncarnations(inSlot->vars, memManager, offset);
if (!isVar) {
slot->vars->mergeVarIncarnations(&typeManager);
}
slot->slotFlags = inSlot->slotFlags;
slot->jsrLabelOffset = inSlot->jsrLabelOffset;
}
void StateTable::mergeSlots(StateInfo::SlotInfo* inSlot, StateInfo::SlotInfo* slot, U_32 offset, bool isVar) {
if (!getStateInfo(offset)->isVisited()) {
if (!slot->type && !slot->vars) {
copySlotInfo(*slot, *inSlot);
return;
} // else it is an node after (next) jsr. The state was propagated here from ret.
}
slot->jsrLabelOffset = inSlot->jsrLabelOffset;
slot->slotFlags = slot->slotFlags & inSlot->slotFlags;
SlotVar* in_vars = inSlot->vars;
SlotVar* vars = slot->vars;
Type *in_type = inSlot->type;
Type *type = slot->type;
if (!!in_vars != !!vars) {
slot->type = NULL;
slot->vars = NULL;
if (type) prepass.getVisited()->setBit(offset,false);
return;
}
if ((in_type == NULL) || (type == NULL)) {
assert(in_vars == NULL);
assert(vars == NULL);
slot->type = NULL;
if (type) prepass.getVisited()->setBit(offset,false);
return;
}
Type* new_type = typeManager.getCommonType(in_type,type);
if (new_type != NULL) {
if (vars) {
if(Log::isEnabled()) {
Log::out() << "addVarIncarnations to SlotVar:" << ::std::endl;
Log::out() << " vars:\t";vars->print(Log::out());Log::out() << ::std::endl;
Log::out() << "in_vars:\t";in_vars->print(Log::out());Log::out() << ::std::endl;
}
if (vars->addVarIncarnations(in_vars, memManager, offset)) {
prepass.getVisited()->setBit(offset,false);
}
if (!isVar) {
vars->mergeVarIncarnations(&typeManager);
}
if(Log::isEnabled()) {
Log::out() << "result_vars:\t";vars->print(Log::out());Log::out() << ::std::endl;
}
}
} else {
slot->vars = NULL;
}
slot->type = new_type;
if (type != new_type) {
prepass.getVisited()->setBit(offset,false);
}
}
void StateTable::setStateInfoFromFinally(StateInfo *inState, U_32 offset) {
if(Log::isEnabled()) {
Log::out() << "SETSTATE FROM FINALLY offset=" <<(int)offset << " depth=" << inState->stackDepth << ::std::endl;
printState(inState);
}
unsigned stackDepth = inState->stackDepth;
StateInfo *state = getStateInfo(offset);
assert(state);
assert(state->stackDepth <= stackDepth);
if(state != NULL && Log::isEnabled()) {
Log::out() << " before\n";
printState(state);
}
if (stackDepth > 0) {
if (maxDepth < stackDepth) {
maxDepth = stackDepth;
if (Log::isEnabled()) Log::out() << "MAXDEPTH " << maxDepth << ::std::endl;
}
struct StateInfo::SlotInfo *stack = state->stack;
state->stackDepth = stackDepth;
for (unsigned i=0; i < stackDepth; i++) {
struct StateInfo::SlotInfo *inSlot = &inState->stack[i];
struct StateInfo::SlotInfo *slot = &stack[i];
Type *intype = inSlot->type;
Type *type = slot->type;
// if (Log::isEnabled()) Log::out() << "STACK " << i << ": "<< type << ::std::endl;
if (!type && intype) { // don't merge, just rewrite!
rewriteSlots(inSlot, slot, offset, i < numVars);
prepass.getVisited()->setBit(offset,false);
} else if (!intype) {
continue;
} else {
mergeSlots(inSlot, slot, offset, i < numVars);
}
}
if(Log::isEnabled()) {
Log::out() << " after\n";
printState(state);
}
}
}
void JavaLabelPrepass::print_loc_vars(U_32 offset, U_32 index)
{
int numStack = methodDesc.getMaxStack()+1;
U_32 key = offset*(numVars+numStack)+index;
StlHashMap<U_32,VariableIncarnation*>::iterator iter = localVars.find(key);
if (iter==localVars.end()) {
Log::out() << "localVars[offset=" << offset
<< "][index=" << index << "] is empty" << ::std::endl;
} else {
Log::out() << "localVars[offset=" << offset << "][index=" << index << "].var->declT = ";
(*iter).second->getDeclaredType()->print(Log::out());
Log::out() << ::std::endl;
}
}
void JavaLabelPrepass::propagateLocalVarToHandlers(U_32 varIndex)
{
assert(varIndex < numVars);
struct StateInfo::SlotInfo *inSlot = &stateInfo.stack[varIndex];
for (ExceptionInfo *except = stateInfo.exceptionInfo;
except != NULL;
except = except->getNextExceptionInfoAtOffset()) {
if ( except->isCatchBlock() ) {
CatchBlock* block = (CatchBlock*)except;
for (CatchHandler* handler = block->getHandlers();
handler != NULL;
handler = handler->getNextHandler() ) {
U_32 handler_offset = handler->getBeginOffset();
struct StateInfo::SlotInfo *slot = &stateTable->getStateInfo(handler_offset)->stack[varIndex];
if (Log::isEnabled()) Log::out() << "HANDLER SLOT " << varIndex
<< " merged to offset " << handler_offset << ::std::endl;
stateTable->mergeSlots(inSlot, slot, handler_offset, true);
}
}
}
}
} //namespace Jitrino