blob: cc2ba4c722c918326669c455dc0485fbcd9d66df [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, George A. Timoshenko
*
*/
#include "Log.h"
#include "Opcode.h"
#include "Type.h"
#include "Stack.h"
#include "IRBuilder.h"
#include "ExceptionInfo.h"
#include "JavaFlowGraphBuilder.h"
#include "TranslatorIntfc.h"
#include "irmanager.h"
#include "FlowGraph.h"
#include <stdlib.h>
#include <string.h>
namespace Jitrino {
Node* JavaFlowGraphBuilder::genBlock(LabelInst* label) {
if (currentBlock == NULL) {
currentBlock = createBlockNodeOrdered(label);
assert(fg->getEntryNode()==NULL);
fg->setEntryNode(currentBlock);
} else {
currentBlock = createBlockNodeOrdered(label);
}
return currentBlock;
}
Node* JavaFlowGraphBuilder::genBlockAfterCurrent(LabelInst *label) {
// hidden exception info
void *exceptionInfo = ((LabelInst*)currentBlock->getFirstInst())->getState();
currentBlock = createBlockNodeAfter(currentBlock, label);
label->setState(exceptionInfo);
return currentBlock;
}
void JavaFlowGraphBuilder::edgeForFallthrough(Node* block) {
//
// find fall through basic block; skip handler nodes
//
NodeList::const_iterator niter = std::find(fallThruNodes.begin(), fallThruNodes.end(), block);
assert(niter != fallThruNodes.end());
for(++niter; niter != fallThruNodes.end(); ++niter) {
Node* node = *niter;
if (node->isBlockNode() && !((LabelInst*)node->getFirstInst())->isCatchLabel()) {
break;
}
}
assert(niter != fallThruNodes.end());
Node* fallthrough = *niter;
addEdge(block,fallthrough);
}
Node * JavaFlowGraphBuilder::edgesForBlock(Node* block) {
//
// find if this block has any region that could catch the exception
//
Node *dispatch = NULL;
ExceptionInfo *exceptionInfo = (CatchBlock*)((LabelInst*)block->getFirstInst())->getState();
if (exceptionInfo != NULL) {
dispatch = exceptionInfo->getLabelInst()->getNode();
}else{
dispatch = fg->getUnwindNode();
}
assert(dispatch->isDispatchNode());
//
// split the block so that
// each potentially-exceptional instruction ends a block
//
Inst* first = (Inst*)block->getFirstInst();
Inst* last = (Inst*)block->getLastInst();
Inst* lastExceptionalInstSeen = NULL;
for (Inst* inst = first->getNextInst(); inst != NULL; inst = inst->getNextInst()) {
if (lastExceptionalInstSeen != NULL) {
// start a new basic block
LabelInst* label = irBuilder.getInstFactory()->makeLabel();
Node *newblock = createBlockNodeAfter(block, label);
uint16 bcOffset = ILLEGAL_BC_MAPPING_VALUE;
for (Inst *ins = lastExceptionalInstSeen->getNextInst(), *nextIns = NULL; ins!=NULL; ins = nextIns) {
nextIns = ins->getNextInst();
ins->unlink();
newblock->appendInst(ins);
if (bcOffset == ILLEGAL_BC_MAPPING_VALUE) {
bcOffset = ins->getBCOffset();
}
}
label->setBCOffset(bcOffset);
// now fix up the CFG, duplicating edges
if (!lastExceptionalInstSeen->isThrow())
fg->addEdge(block,newblock);
//
// add an edge to handler entry node
//
assert(!block->findTargetEdge(dispatch));
fg->addEdge(block,dispatch);
block = newblock;
lastExceptionalInstSeen = NULL;
}
if (inst->getOperation().canThrow()) {
lastExceptionalInstSeen = inst;
}
}
//
// examine the last instruction and create appropriate CFG edges
//
switch(last->getOpcode()) {
case Op_Jump:
{
fg->addEdge(block,((BranchInst*)last)->getTargetLabel()->getNode());
last->unlink();
}
break;
case Op_Branch:
case Op_JSR:
addEdge(block, ((BranchInst*)last)->getTargetLabel()->getNode());
edgeForFallthrough(block);
break;
case Op_Throw:
case Op_ThrowSystemException:
case Op_ThrowLinkingException:
// throw/rethrow creates an edge to a handler that catches the exception
assert(dispatch != NULL);
assert(lastExceptionalInstSeen == last);
break;
case Op_Return:
addEdge(block, fg->getReturnNode());
break;
case Op_Ret:
break; // do not do anything
case Op_Switch:
{
SwitchInst *sw = (SwitchInst*)last;
U_32 num = sw->getNumTargets();
for (U_32 i = 0; i < num; i++) {
Node* target = sw->getTarget(i)->getNode();
// two switch values may go to the same block
if (!block->findTargetEdge(target)) {
fg->addEdge(block,target);
}
}
Node* target = sw->getDefaultTarget()->getNode();
if (!block->findTargetEdge(target)) {
fg->addEdge(block,target);
}
}
break;
default:;
if (block != fg->getReturnNode()) { // a fallthrough edge is needed
// if the basic block does not have any outgoing edge, add one fall through edge
if (block->getOutEdges().empty())
edgeForFallthrough(block);
}
}
//
// add an edge to handler entry node
//
if (lastExceptionalInstSeen != NULL)
addEdge(block,dispatch);
return block;
}
void JavaFlowGraphBuilder::edgesForHandler(Node* entry) {
CatchBlock *catchBlock = (CatchBlock*)((LabelInst*)entry->getFirstInst())->getState();
if(entry == fg->getUnwindNode())
// No local handlers for unwind.
return;
//
// create edges between handler entry and each catch
//
CatchHandler * handlers = catchBlock->getHandlers();
for (;handlers != NULL; handlers = handlers->getNextHandler()) {
fg->addEdge(entry,handlers->getLabelInst()->getNode());
}
// edges for uncaught exception
ExceptionInfo *nextBlock = NULL;
for (nextBlock = catchBlock->getNextExceptionInfoAtOffset();
nextBlock != NULL; nextBlock = nextBlock->getNextExceptionInfoAtOffset())
{
if (nextBlock->isCatchBlock()) {
Node *next = nextBlock->getLabelInst()->getNode();
fg->addEdge(entry,next);
break;
}
}
if(nextBlock == NULL) {
fg->addEdge(entry,fg->getUnwindNode());
}
}
void JavaFlowGraphBuilder::createCFGEdges() {
for (NodeList::iterator it = fallThruNodes.begin(); it!=fallThruNodes.end(); ++it) {
Node* node = *it;
if (node->isBlockNode())
node = edgesForBlock(node);
else if (node->isDispatchNode())
edgesForHandler(node);
else
assert(node == fg->getExitNode());
}
}
Node* JavaFlowGraphBuilder::createBlockNodeOrdered(LabelInst* label) {
assert(label != NULL);
Node* node = fg->createBlockNode(label);
fallThruNodes.push_back(node);
return node;
}
Node* JavaFlowGraphBuilder::createBlockNodeAfter(Node* node, LabelInst* label) {
NodeList::iterator it = std::find(fallThruNodes.begin(), fallThruNodes.end(), node);
assert(it!=fallThruNodes.end());
assert(label != NULL);
label->setState(((LabelInst*)node->getFirstInst())->getState());
Node* newNode = fg->createBlockNode(label);
fallThruNodes.insert(++it, newNode);
return newNode;
}
Node* JavaFlowGraphBuilder::createDispatchNode() {
Node* node = fg->createDispatchNode(irBuilder.getInstFactory()->makeLabel());
fallThruNodes.push_back(node);
return node;
}
void JavaFlowGraphBuilder::addEdge(Node* source, Node* target) {
if (source->findTargetEdge(target) == NULL) {
fg->addEdge(source, target);
}
}
//
// construct flow graph
//
void JavaFlowGraphBuilder::build() {
//
// create epilog, unwind, and exit
//
InstFactory* instFactory = irBuilder.getInstFactory();
fg->setReturnNode(createBlockNodeOrdered(instFactory->makeLabel()));
fg->setUnwindNode(createDispatchNode());
fg->setExitNode(fg->createNode(Node::Kind_Exit, instFactory->makeLabel()));
fg->addEdge(fg->getReturnNode(), fg->getExitNode());
fg->addEdge(fg->getUnwindNode(), fg->getExitNode());
//
// second phase: construct edges
//
createCFGEdges();
}
JavaFlowGraphBuilder::JavaFlowGraphBuilder(MemoryManager& mm, IRBuilder &irB) :
memManager(mm), currentBlock(NULL), irBuilder(irB), fallThruNodes(mm)
{
fg = irBuilder.getFlowGraph();
methodHandle = irBuilder.getIRManager()->getMethodDesc().getMethodHandle();
}
} //namespace Jitrino