blob: b30ab8c2884741a5447b04aee99c35d9a74279ec [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.
*/
/**
* @author Intel, Natalya V. Golovleva
*
*/
#include "lazyexceptionopt.h"
#include "FlowGraph.h"
#include "irmanager.h"
#include "Opnd.h"
#include "Inst.h"
#include "Stl.h"
#include "Log.h"
#include "Dominator.h"
#include "optimizer.h"
namespace Jitrino {
DEFINE_SESSION_ACTION(LazyExceptionOptPass, lazyexc, "Lazy Exception Throwing Optimization")
void LazyExceptionOptPass::_run(IRManager& irm) {
LazyExceptionOpt le(irm);
le.doLazyExceptionOpt();
}
int LazyExceptionOpt::level=0;
LazyExceptionOpt::LazyExceptionOpt(IRManager &ir_manager) :
irManager(ir_manager),
leMemManager("LazyExceptionOpt::doLazyExceptionOpt"),
compInterface(ir_manager.getCompilationInterface())
{
}
/**
* Executes lazy exception optimization pass.
*/
void
LazyExceptionOpt::doLazyExceptionOpt() {
MethodDesc &md = irManager.getMethodDesc();
BitSet excOpnds(leMemManager,irManager.getOpndManager().getNumSsaOpnds());
StlDeque<Inst*> candidateSet(leMemManager);
optCandidates = new (leMemManager) OptCandidates(leMemManager);
Method_Side_Effects m_sideEff = md.getSideEffect();
const Nodes& nodes = irManager.getFlowGraph().getNodes();
Nodes::const_iterator niter;
#ifdef _DEBUG
mtdDesc=&md;
#endif
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << std::endl;
for (int i=0; i<level; i++) Log::out() << " ";
Log::out() << "doLE "; md.printFullName(Log::out());
Log::out() << " SideEff " << (int)m_sideEff << std::endl;
}
#endif
level++;
U_32 opndId = 0;
isArgCheckNull = false;
isExceptionInit = md.isInstanceInitializer() &&
md.getParentType()->isLikelyExceptionType();
// core api exception init
if (m_sideEff == MSE_Unknown && isExceptionInit
&& strncmp(md.getParentType()->getName(),"java/lang/",10) == 0) {
m_sideEff = MSE_False;
md.setSideEffect(m_sideEff);
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " core api exc "; md.printFullName(Log::out());
Log::out() << " SideEff " << (int)m_sideEff << std::endl;
}
#endif
}
for(niter = nodes.begin(); niter != nodes.end(); ++niter) {
Node* node = *niter;
Inst *headInst = (Inst*)node->getFirstInst();
for (Inst* inst=headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) {
#ifdef _DEBUG
if (inst->getOpcode()==Op_DefArg && isExceptionInit) {
if (Log::isEnabled()) {
Log::out() << " defarg: ";
inst->print(Log::out()); Log::out() << std::endl;
Log::out() << " ";
Log::out() << (int)(inst->getDefArgModifier()) << " " <<
(inst->getDefArgModifier()==DefArgNoModifier) << " " <<
(inst->getDefArgModifier()==NonNullThisArg) << " " <<
(inst->getDefArgModifier()==SpecializedToExactType) << " " <<
(inst->getDefArgModifier()==DefArgBothModifiers) << std::endl;
}
}
#endif
if (inst->getOpcode()==Op_Throw) {
if (inst->getSrc(0)->getInst()->getOpcode()==Op_NewObj) {
excOpnds.setBit(opndId=inst->getSrc(0)->getId(),true);
if (!addOptCandidates(opndId,inst))
excOpnds.setBit(opndId,false); // different exc. edges
#ifdef _DEBUG
if (excOpnds.getBit(opndId)==1) {
if (Log::isEnabled()) {
Log::out() << " add opnd: ";
inst->print(Log::out()); Log::out() << std::endl;
Log::out() << " add obj: ";
inst->getSrc(0)->getInst()->print(Log::out()); Log::out() << std::endl;
}
}
#endif
}
}
if (m_sideEff == MSE_Unknown)
if (instHasSideEffect(inst)) {
m_sideEff = MSE_True;
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << "~~~~~~inst sideEff ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
}
}
}
if (md.getSideEffect() == MSE_Unknown) {
if (m_sideEff == MSE_Unknown) {
if (isExceptionInit && isArgCheckNull) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << "~~~~~~init sideEff reset: " << m_sideEff << " 3 ";
md.printFullName(Log::out()); Log::out() << std::endl;
}
#endif
m_sideEff = MSE_True_Null_Param;
} else
m_sideEff = MSE_False;
}
md.setSideEffect(m_sideEff);
}
for(niter = nodes.begin(); niter != nodes.end(); ++niter) {
Node* node = *niter;
Inst *headInst = (Inst*)node->getFirstInst();
Opnd* opnd;
for (Inst* inst=headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) {
U_32 nsrc = inst->getNumSrcOperands();
for (U_32 i=0; i<nsrc; i++) {
if (!(opnd=inst->getSrc(i))->isSsaOpnd()) // check ssa operands
continue;
if (excOpnds.getBit(opndId=opnd->getId())==0)
continue;
if (inst->getOpcode()==Op_DirectCall) {
MethodDesc* md = inst->asMethodInst()->getMethodDesc();
if (md->isInstanceInitializer() &&
md->getParentType()->isLikelyExceptionType()) {
if (!addOptCandidates(opndId,inst)) {
excOpnds.setBit(opndId,false);
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " - rem opnd " << opnd->getId() << " ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
}
} else {
excOpnds.setBit(opndId,false);
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " -- rem opnd " << opnd->getId() << " ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
}
} else {
if (inst->getOpcode()!=Op_Throw) {
excOpnds.setBit(opndId,false);
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " rem opnd " << opnd->getId() << " ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
}
}
}
}
}
if (!excOpnds.isEmpty()) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << "------LE: ";
md.printFullName(Log::out()); Log::out() << std::endl;
}
#endif
fixOptCandidates(&excOpnds);
}
level--;
#ifdef _DEBUG
if (Log::isEnabled()) {
for (int i=0; i<level; i++) Log::out() << " ";
Log::out() << "done "; md.printFullName(Log::out());
Log::out() << " SideEff " << (int)m_sideEff << std::endl;
}
#endif
};
/**
* Adds information to optCandidates list for specified exception object.
* @param id - an exception object operand Id
* @param inst - call, or throw instructions operating with this exception object
* @return <code>true</code> if an information is added;
* <code>false<code> if an exception object cannot be optimized.
*/
bool
LazyExceptionOpt::addOptCandidates(U_32 id, Inst* inst) {
OptCandidate* oc = NULL;
ThrowInsts* thrinst = NULL;
OptCandidates::iterator it;
if (optCandidates == NULL)
optCandidates = new (leMemManager) OptCandidates(leMemManager);
for (it = optCandidates->begin( ); it != optCandidates->end( ); it++ ) {
if ((*it)->opndId==id) {
oc = *it;
break;
}
}
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " addOptCandidates: ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
if (oc == NULL) {
if (inst->getOpcode()==Op_Throw) {
bool hasFinalize =
((NamedType*)inst->getSrc(0)->getType())->isFinalizable();
if (hasFinalize) {
#ifdef _DEBUG
Log::out() << " isFinalizable: "
<< hasFinalize << std::endl;
#endif
return false;
}
}
oc = new (leMemManager) OptCandidate;
oc->opndId = id;
oc->objInst = inst->getSrc(0)->getInst();
oc->initInst=NULL;
thrinst = new (leMemManager) ThrowInsts(leMemManager);
thrinst->push_back(inst);
oc->throwInsts = thrinst;
optCandidates->push_back(oc);
if (!isEqualExceptionNodes(oc->objInst,inst)) {
return false;
}
} else {
if (inst->getOpcode()==Op_Throw) {
oc->throwInsts->push_back(inst);
return true;
} else {
assert(inst->getOpcode()==Op_DirectCall);
assert(oc->initInst==NULL);
oc->initInst = inst;
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " addOptCandidates: call checkMC ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
U_32 nii_id=((Inst*)(inst->getNode()->getUnconditionalEdgeTarget()->getFirstInst()))->getId();
ThrowInsts::iterator it1;
for (it1 = oc->throwInsts->begin(); it1 !=oc->throwInsts->end(); it1++) {
if ((*it1)->getId() != nii_id) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << "?? addOptCandidates: throw ";
(*it1)->print(Log::out()); Log::out() << std::endl;
}
#endif
if (checkInSideEff((*it1),inst))
return false;
}
}
if (methodCallHasSideEffect(inst)) {
return false;
}
}
}
return true;
};
/**
* Checks if there is a side effect between throw_inst and init_inst instructions.
* @param throw_inst - the exception object throw instruction
* @param init_inst - the exception object constructor call instruction
* @return <code>true</code> if there is side effect;
* <code>false<code> if there is no side effect.
*/
bool
LazyExceptionOpt::checkInSideEff(Inst* throw_inst, Inst* init_inst) {
Node* node = throw_inst->getNode();
Inst* instfirst = (Inst*)node->getFirstInst();;
Inst* instlast = throw_inst;
Inst* inst;
bool dofind = true;
bool inSE = false;
if (throw_inst!=instfirst)
instlast=throw_inst->getPrevInst();
else {
node = node->getInEdges().front()->getSourceNode();
instlast = (Inst*)node->getLastInst();
}
while (dofind && node!=NULL) {
instfirst = (Inst*)node->getFirstInst();
for (inst = instlast; inst!=instfirst; inst=inst->getPrevInst()) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " checkInSE: see ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
if (inst==init_inst) {
dofind=false;
break;
}
if (!inSE) {
if (instHasSideEffect(inst)) {
inSE=true;
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " checkInSE: sideEff ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
break;
}
}
}
if (dofind){
node = node->getInEdges().front()->getSourceNode();
instlast = (Inst*)node->getLastInst();
}
}
if (dofind)
return true; // call init wasn't found
return inSE;
}
/**
* Checks that exception edges are equal for newobj instruction node and
* throw instruction node.
* @param oi - newobj instruction
* @param ti - throw instruction
* @return <code>true</code> if exception edges are equal;
* <code>false<code> otherwise.
*/
bool
LazyExceptionOpt::isEqualExceptionNodes(Inst* oi, Inst* ti) {
Edge* oedge = oi->getNode()->getExceptionEdge();
Edge* tedge = ti->getNode()->getExceptionEdge();
if (oedge->getTargetNode()!=tedge->getTargetNode()) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " addOptCandidates: diff.exc.edges for obj&throw ";
Log::out() << oedge->getTargetNode()->getId() << " ";
Log::out() << tedge->getTargetNode()->getId() << std::endl;
}
#endif
return false;
}
return true;
}
/**
* Prints information about optimization candidates.
* @param os - output stream
*/
void
LazyExceptionOpt::printOptCandidates(::std::ostream& os) {
OptCandidates::iterator it;
Inst* oinst;
Inst* iinst;
Inst* tinst;
if (optCandidates == NULL) {
return;
}
for (it = optCandidates->begin( ); it != optCandidates->end( ); it++ ) {
os << "~~ opndId " << (*it)->opndId << std::endl;
oinst = (*it)->objInst;
os << " obj ";
if (oinst != NULL)
oinst->print(os);
else
os << "newobj NULL";
os << std::endl;
iinst = (*it)->initInst;
os << " init ";
if (iinst != NULL)
iinst->print(os);
else
os << "call init NULL";
os << std::endl;
if ((*it)->throwInsts == NULL) {
os << " thr throw NULL";
os << std::endl;
continue;
}
ThrowInsts::iterator it1;
for (it1 = (*it)->throwInsts->begin(); it1 !=(*it)->throwInsts->end(); it1++) {
tinst = *it1;
assert(tinst != NULL);
os << " thr ";
tinst->print(os);
os << std::endl;
}
}
os << "end~~" << std::endl;
}
/**
* Checks that exception edges are equal for newobj instruction node and
* throw instruction node.
* @param bs - bit set of operands that may be optimized
*/
void
LazyExceptionOpt::fixOptCandidates(BitSet* bs) {
OptCandidates::iterator it;
Inst* oinst;
MethodCallInst* iinst;
Inst* tinst;
Inst* tlinst;
U_32 opcount;
Opnd **opnds = NULL;
if (optCandidates == NULL) {
return;
}
for (it = optCandidates->begin( ); it != optCandidates->end( ); it++ ) {
if (bs->getBit((*it)->opndId)) {
oinst = (*it)->objInst;
assert(oinst != NULL);
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " to remove ";
oinst->print(Log::out());
Log::out() << std::endl;
}
#endif
if ((*it)->initInst == NULL) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " init inst is null ";
Log::out() << std::endl;
}
#endif
continue;
}
iinst = (*it)->initInst->asMethodCallInst();
// inline info from constructor should be propagated to lazy
// exception if any
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " to remove ";
iinst->print(Log::out());
Log::out() << std::endl;
}
#endif
assert((*it)->throwInsts != NULL);
assert(iinst->getNumSrcOperands() >= 3);
if (!removeInsts(oinst,iinst))
continue; // to null bitset?
TypeManager& tm = irManager.getTypeManager();
Opnd* mpt = irManager.getOpndManager().createSsaTmpOpnd(
tm.getMethodPtrType(iinst->getMethodDesc()));
opcount = iinst->getNumSrcOperands()-2; //numSrc-3+1
if (opcount >0) {
opnds = new (leMemManager) Opnd*[opcount]; //local mem should be used
opnds[0] = mpt;
for (U_32 i = 0; i < opcount-1; i++)
opnds[i+1] = iinst->getSrc(i+3);
}
Inst* mptinst = irManager.getInstFactory().makeLdFunAddr(mpt,iinst->getMethodDesc());
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " 1st ";
mptinst->print(Log::out());
Log::out() << std::endl;
}
#endif
ThrowInsts::iterator it1;
for (it1 = (*it)->throwInsts->begin(); it1 !=(*it)->throwInsts->end(); it1++) {
tinst = *it1;
assert(tinst != NULL);
tlinst=irManager.getInstFactory().makeVMHelperCall(
OpndManager::getNullOpnd(), VM_RT_THROW_LAZY, opcount, opnds);
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " 2nd ";
tlinst->print(Log::out());
Log::out() << std::endl;
}
if (Log::isEnabled()) {
Log::out() << " to change ";
tinst->print(Log::out());
Log::out() << std::endl;
}
#endif
mptinst->insertBefore(tinst);
tlinst->insertBefore(tinst);
tinst->unlink();
uint16 bcOffset = iinst->getBCOffset();
mptinst->setBCOffset(bcOffset);
tlinst->setBCOffset(bcOffset);
}
}
}
}
/**
* Removes specified instructions if they have the same exception node.
* @param oinst - exception creating instruction
* @param iinst - constructor call instruction
* @return <code>true</code> if instruction were removed;
* <code>false<code> otherwise.
*/
bool
LazyExceptionOpt::removeInsts(Inst* oinst,Inst* iinst) {
ControlFlowGraph& fg = irManager.getFlowGraph();
Edge* oedge = oinst->getNode()->getExceptionEdge();
Edge* iedge = iinst->getNode()->getExceptionEdge();
Node* otn = oedge->getTargetNode();
Node* itn = iedge->getTargetNode();
if (otn!=itn) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " removeInsts: diff.exc.edges for obj&init ";
Log::out() << otn->getId() << " " << itn->getId() << std::endl;
Log::out() << " "; oinst->print(Log::out());
Log::out() << std::endl;
Log::out() << " "; iinst->print(Log::out());
Log::out() << std::endl;
}
#endif
return false;
}
oinst->unlink();
iinst->unlink();
if (otn->getInEdges().size() > 1) {
fg.removeEdge(oedge);
} else
removeNode(otn);
if (itn->getInEdges().size() > 1) {
fg.removeEdge(iedge);
} else
removeNode(itn);
return true;
}
/**
* Removes node from compiled method flow graph.
* @param node - removed node
*/
void
LazyExceptionOpt::removeNode(Node* node) {
const Edges &out_edges = node->getOutEdges();
Edges::const_iterator eit;
Node* n;
for (eit = out_edges.begin(); eit != out_edges.end(); ++eit) {
n = (*eit)->getTargetNode();
if (n->getInEdges().size() == 1)
removeNode(n);
}
irManager.getFlowGraph().removeNode(node);
}
void
LazyExceptionOpt::printInst1(::std::ostream& os, Inst* inst, std::string txt) {
U_32 nsrc = inst->getNumSrcOperands();
os << txt;
inst->print(os);
os << std::endl;
for (U_32 i=0; i<nsrc; i++) {
printInst1(os, inst->getSrc(i)->getInst(),txt+" ");
}
}
/**
* Checks a callee method side effect.
* @param inst - method call instruction
* @return <code>true</code> if method has side effect;
* <code>false<code> if method has no side effect.
*/
bool
LazyExceptionOpt::methodCallHasSideEffect(Inst* inst) {
U_32 opcode = inst->getOpcode();
MethodDesc* cmd = NULL;
Method_Side_Effects mse = MSE_Unknown;
if (opcode==Op_DirectCall || opcode==Op_TauVirtualCall) {
cmd = inst->asMethodCallInst()->getMethodDesc();
} else {
if (opcode==Op_IndirectCall || opcode==Op_IndirectMemoryCall) {
Type* type = inst->asCallInst()->getFunPtr()->getType();
if (type->isUnresolvedType()) {
return true;
}
cmd = type->asMethodPtrType()->getMethodDesc();
} else {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " checkMC: no check ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
return true;
}
}
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " checkMC: ";
cmd->printFullName(Log::out()); Log::out() << std::endl;
}
#endif
mse = cmd->getSideEffect();
#ifdef _DEBUG
if (mse != MSE_Unknown) {
if (Log::isEnabled()) {
Log::out() << " checkMC: prev.set sideEff " << mse << " ";
inst->print(Log::out()); Log::out() << std::endl;
}
}
#endif
if (mse == MSE_True) {
return true;
}
if (mse == MSE_False) {
return false;
}
// core api exception init
if (cmd->isInstanceInitializer() && cmd->getParentType()->isLikelyExceptionType()
&& strncmp(cmd->getParentType()->getName(),"java/lang/",10) == 0) {
cmd->setSideEffect(MSE_False);
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " checkMC: core api exc ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
return false;
}
if ( opcode!=Op_DirectCall && !cmd->isFinal() ) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " checkMC: not DirCall not final ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
return true;
}
if (!isExceptionInit &&
!(cmd->isInstanceInitializer()&&cmd->getParentType()->isLikelyExceptionType())) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " checkMC: no init ";
Log::out() << isExceptionInit << " ";
Log::out() << cmd->isInstanceInitializer() << " ";
Log::out() << cmd->getParentType()->isLikelyExceptionType() << " ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
return true;
}
/*
if (cmd->getParentType()->needsInitialization()) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " checkMC: need cinit ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
return true; // cannot compile <init> before <clinit> (to fix vm)
}
*/
if (mse == MSE_Unknown) { // try to compile method
//TODO: avoid compilation here. Use translator to perform analysis needed
bool allowRecursion = !compInterface.getTypeManager().isLazyResolutionMode();
if (!allowRecursion) {
return MSE_True;
}
if (!compInterface.compileMethod(cmd)) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " checkMC: method was not compiled " << std::endl;
}
#endif
return true;
} else {
mse = cmd->getSideEffect();
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " checkMC: method was compiled, sideEff "
<< mse << std::endl;
}
#endif
if (mse == MSE_True)
return true;
if (mse == MSE_False) {
return false;
}
}
}
if (mse == MSE_True_Null_Param) {
U_32 nsrc=inst->getNumSrcOperands();
bool mayBeNull;
if (nsrc>3) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " checkMC: exc.init ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
mayBeNull=false;
for (U_32 i=3; i<nsrc; i++) {
if (inst->getSrc(i)->getType()->isReference()) {
if (mayBeNullArg(inst,i))
mayBeNull=true;
}
}
if (!mayBeNull)
return false;
#ifdef _DEBUG
for (U_32 i=0; i<nsrc; i++) {
if (Log::isEnabled()) {
Log::out() << " "<<i<<" isRef: "<<
inst->getSrc(i)->getType()->isReference()<<" ";
inst->getSrc(i)->getInst()->print(Log::out());
Log::out() << std::endl;
}
}
#endif
return true;
}
#ifdef _DEBUG
else {
if (Log::isEnabled()) {
Log::out() << " ?????? MSE_NULL_PARAM & nsrc "<<
nsrc << std::endl;
}
}
#endif
}
return true;
}
/**
* Checks if a callee method agrument may be null.
* @param call_inst - method call instruction
* @param arg_n - callee method argument number
* @return <code>true</code> if a callee method argument may be null
* <code>false<code> if a callee method argument is not null
*/
bool
LazyExceptionOpt::mayBeNullArg(Inst* call_inst, U_32 arg_n) {
Opnd* arg_opnd = call_inst->getSrc(arg_n);
Inst* inst=arg_opnd->getInst();
while ((inst=inst->getNextInst())!=NULL) {
if (inst->getOpcode()==Op_TauCheckNull && inst->getSrc(0)==arg_opnd) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " check node: " << inst->getNode()->getId() << " ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
return false; // may not be null
}
}
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " chknull wasn,t found in node: "
<< arg_opnd->getInst()->getId()<< std::endl;
}
#endif
return true; // may be null
}
/**
* Checks if Op_TauStInd (stind) instruction has a side effect.
* @param inst - checked instruction
* @return <code>true</code> if an instruction has side effect;
* <code>false<code> if an instruction has no side effect.
*/
bool
LazyExceptionOpt::fieldUsageHasSideEffect(Inst* inst) {
Opnd* insOp = inst->getSrc(0);
Inst* instDef = insOp->getInst();
if (instDef->getOpcode() == Op_DefArg) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " fieldUsageHasSideEffect: ";
inst->print(Log::out()); Log::out() << std::endl;
Log::out() << " fieldUsageHasSideEffect: ";
instDef->print(Log::out()); Log::out() << std::endl;
Log::out() << " fieldUsageHasSideEffect: ";
Log::out() << (int)(instDef->getDefArgModifier()) << " " <<
(instDef->getDefArgModifier()==DefArgNoModifier) << " " <<
(instDef->getDefArgModifier()==NonNullThisArg) << " " <<
(instDef->getDefArgModifier()==DefArgBothModifiers) << std::endl;
}
#endif
if (instDef->getDefArgModifier()==NonNullThisArg && isExceptionInit)
return false;
}
return true;
}
/**
* Checks if there is a side effect between throw_inst and init_inst instructions.
* @param inst - checked instruction
* @return <code>true</code> if an instruction has side effect;
* <code>false<code> if an instruction has no side effect.
*/
bool
LazyExceptionOpt::instHasSideEffect(Inst* inst) {
switch (inst->getOpcode()) {
case Op_Add:
case Op_Mul:
case Op_Sub:
case Op_TauDiv:
case Op_TauRem:
case Op_Neg:
case Op_MulHi:
case Op_Min:
case Op_Max:
case Op_Abs:
case Op_And:
case Op_Or:
case Op_Xor:
case Op_Not:
case Op_Select:
return false;
case Op_Conv:
case Op_ConvZE:
case Op_ConvUnmanaged:
return true;
case Op_Shladd:
case Op_Shl:
case Op_Shr:
case Op_Cmp:
case Op_Cmp3:
case Op_Branch:
case Op_Jump:
case Op_Switch:
return false;
case Op_DirectCall:
case Op_TauVirtualCall:
case Op_IndirectCall:
case Op_IndirectMemoryCall:
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " instHasSideEffect: call checkMC ";
inst->print(Log::out()); Log::out() << std::endl;
}
#endif
return methodCallHasSideEffect(inst);
case Op_JitHelperCall:
case Op_VMHelperCall:
return true;
case Op_Return:
case Op_Catch:
return false;
case Op_PseudoThrow:
return false;
case Op_Throw:
case Op_ThrowSystemException:
case Op_ThrowLinkingException:
return true;
case Op_JSR: // deleted
case Op_Ret:
case Op_SaveRet:
return true;
case Op_Copy:
return true;
case Op_DefArg:
case Op_LdConstant:
case Op_LdRef:
case Op_LdVar:
case Op_LdVarAddr:
case Op_TauLdInd:
return false;
case Op_TauLdField:
return true;
case Op_LdStatic:
return true;
case Op_TauLdElem:
return false;
case Op_LdFieldAddr:
return false;
case Op_LdStaticAddr:
return true;
case Op_LdElemAddr:
return false; //
case Op_TauLdVTableAddr:
case Op_TauLdIntfcVTableAddr:
case Op_TauLdVirtFunAddr:
case Op_TauLdVirtFunAddrSlot:
case Op_LdFunAddr:
case Op_LdFunAddrSlot:
case Op_GetVTableAddr:
case Op_GetClassObj:
return false;
case Op_TauArrayLen:
case Op_LdArrayBaseAddr:
case Op_AddScaledIndex:
return true;
case Op_StVar:
return false;
case Op_TauStInd:
{
Inst* inst_src1 = inst->getSrc(1)->getInst();
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " stind: ";
inst->print(Log::out()); Log::out() << std::endl;
Log::out() << " ";
inst_src1->print(Log::out()); Log::out() << std::endl;
}
#endif
if (inst_src1->getOpcode()==Op_LdFieldAddr )
return fieldUsageHasSideEffect(inst_src1);
}
return true;
case Op_TauStRef:
{
Inst* inst_src1 = inst->getSrc(1)->getInst();
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " stref: ";
inst->print(Log::out()); Log::out() << std::endl;
Log::out() << " ";
inst_src1->print(Log::out()); Log::out() << std::endl;
}
#endif
if (inst_src1->getOpcode()==Op_LdFieldAddr )
return fieldUsageHasSideEffect(inst_src1);
}
return true;
case Op_TauStField:
return true; //
case Op_TauStElem:
case Op_TauStStatic:
case Op_TauCheckBounds:
case Op_TauCheckLowerBound:
case Op_TauCheckUpperBound:
return true;
case Op_TauCheckNull:
{
Inst* inst_src = inst->getSrc(0)->getInst();
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << " chknull: ";
inst->print(Log::out()); Log::out() << std::endl;
Log::out() << " ";
inst_src->print(Log::out()); Log::out() << std::endl;
}
#endif
if (inst_src->getOpcode()==Op_DefArg && isExceptionInit) {
isArgCheckNull = true;
return false;
}
}
return true; //
case Op_TauCheckZero:
case Op_TauCheckDivOpnds:
case Op_TauCheckElemType:
case Op_TauCheckFinite:
return true;
case Op_NewObj:
// core api
{
NamedType* nt = inst->getDst()->getType()->asNamedType();
if (strncmp(nt->getName(),"java/lang/",10)==0 && nt->isLikelyExceptionType()) {
#ifdef _DEBUG
if (Log::isEnabled()) {
Log::out() << "====newobj ";
inst->print(Log::out()); Log::out() << std::endl;
Log::out() << "core api exc " << nt->getName() << " "
<< strncmp(nt->getName(),"java/lang/",10)
<< " excType: " << nt->isLikelyExceptionType() << std::endl;
}
#endif
return false;
}
}
return true;
case Op_NewArray:
case Op_NewMultiArray:
case Op_TauMonitorEnter:
case Op_TauMonitorExit:
case Op_TypeMonitorEnter:
case Op_TypeMonitorExit:
case Op_LdLockAddr:
case Op_IncRecCount:
case Op_TauBalancedMonitorEnter:
case Op_BalancedMonitorExit:
case Op_TauOptimisticBalancedMonitorEnter:
case Op_OptimisticBalancedMonitorExit:
case Op_MonitorEnterFence:
case Op_MonitorExitFence:
return true;
case Op_TauStaticCast:
case Op_TauCast:
case Op_TauAsType:
case Op_TauInstanceOf:
case Op_InitType:
return true;
case Op_Label:
case Op_MethodEntry:
case Op_MethodEnd:
return false;
case Op_Phi:
case Op_TauPi:
return false;
case Op_IncCounter:
case Op_Prefetch:
return false;
case Op_UncompressRef:
case Op_CompressRef:
case Op_LdFieldOffset:
case Op_LdFieldOffsetPlusHeapbase:
case Op_LdArrayBaseOffset:
case Op_LdArrayBaseOffsetPlusHeapbase:
case Op_LdArrayLenOffset:
case Op_LdArrayLenOffsetPlusHeapbase:
case Op_AddOffset:
case Op_AddOffsetPlusHeapbase:
return true;
case Op_TauPoint:
case Op_TauEdge:
case Op_TauAnd:
case Op_TauUnsafe:
case Op_TauSafe:
return false;
case Op_TauCheckCast:
return true;
case Op_TauHasType:
case Op_TauHasExactType:
case Op_TauIsNonNull:
return false;
default:
return true;
}
}
} //namespace Jitrino