blob: 1ac8bf9669f8796e94490bb2b0c449a9f8236457 [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.
*/
/* COPYRIGHT_NOTICE */
/**
* @author Pavel Ozhdikhin
*/
#include "Jitrino.h"
#include "optpass.h"
#include "devirtualizer.h"
#include "irmanager.h"
#include "Inst.h"
#include "FlowGraph.h"
#include "EMInterface.h"
namespace Jitrino {
DEFINE_SESSION_ACTION(ValueProfilerInstrumentationPass, vp_instrument, "Perform value profiler instrumentation pass")
void ValueProfilerInstrumentationPass::_run(IRManager& irm)
{
// Currently value profile is used by interface devirtualization only
ControlFlowGraph& flowGraph = irm.getFlowGraph();
MemoryManager mm("Value Profiler Instrumentation Pass");
MethodDesc& md = irm.getMethodDesc();
InstFactory& instFactory = irm.getInstFactory();
OpndManager& opndManager = irm.getOpndManager();
TypeManager& typeManager = irm.getTypeManager();
StlVector<U_32> counterKeys(mm);
bool debug = Log::isEnabled();
bool profileAbstractCalls = getBoolArg("profile_abstract", false);
bool profileAllVirtualCalls = getBoolArg("profile_all_virtual", false);
U_32 key = 0;
StlVector<Node*> nodes(mm);
flowGraph.getNodesPostOrder(nodes);
for (StlVector<Node*>::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node* node = *it;
if(node->isBlockNode()) {
Inst* lastInst = (Inst*)node->getLastInst();
MethodInst* methodInst = NULL;
Opnd* base = NULL;
Opnd* tauNullChecked = NULL;
Opnd* tauTypesChecked = NULL;
U_32 argOffset = 0;
bool isIntfCall = false;
if(Devirtualizer::isGuardableVirtualCall(lastInst, methodInst, base, tauNullChecked, tauTypesChecked, argOffset, isIntfCall)) {
assert(methodInst && base && tauNullChecked && tauTypesChecked && argOffset);
assert(base->getType()->isObject());
CallInst* call = lastInst->asCallInst();
assert(call != NULL);
if (debug) {
Log::out() << "Indirect call detected. \n\tNode: ";
FlowGraph::printLabel(Log::out(), node);
Log::out() << "\n\tCall inst: ";
call->print(Log::out());
Log::out() << std::endl;
}
Inst* vtableInst = methodInst->getSrc(0)->getInst();
if (isIntfCall) {
// Need to generate VTable loading
Opnd* vTable = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(typeManager.getSystemObjectType()));
Inst* ldVtableInst = instFactory.makeTauLdVTableAddr(vTable, base, tauNullChecked);
((CFGInst *)ldVtableInst)->insertBefore(vtableInst);
vtableInst = ldVtableInst;
if (debug) {
Log::out() << "\tInserted ldVTable instruction to instrument: ";
ldVtableInst->print(Log::out());
Log::out() << std::endl;
}
} else {
// Profile abstract calls, or all virtual calls
ObjectType* baseType = (ObjectType*) base->getType();
if(!((baseType->isAbstract() && profileAbstractCalls) || profileAllVirtualCalls)) {
continue;
}
}
key = (U_32)lastInst->getBCOffset();
assert(key != ILLEGAL_BC_MAPPING_VALUE);
assert(key != 0);
if (debug) {
Log::out() << "Use call instruction bcOffset = " << (I_32)key << std::endl;
}
Opnd* indexOpnd = opndManager.createSsaTmpOpnd(typeManager.getInt32Type());
Inst* loadIndexInst = instFactory.makeLdConst(indexOpnd, (I_32)key);
counterKeys.push_back(key);
Opnd* valueOpnd = vtableInst->getDst();
const U_32 numArgs = 2;
Opnd* args[numArgs] = {indexOpnd, valueOpnd};
Inst* addValueInst = instFactory.makeJitHelperCall(opndManager.getNullOpnd(), AddValueProfileValue, NULL, NULL, numArgs, args);
addValueInst->setBCOffset(call->getBCOffset());
((CFGInst *)addValueInst)->insertBefore(call);
((CFGInst *)loadIndexInst)->insertBefore(addValueInst);
}
}
}
U_32 cc_size = (U_32)counterKeys.size();
if (cc_size == 0) return;
irm.getCompilationInterface().lockMethodData();
ProfilingInterface* pi = irm.getProfilingInterface();
if (!pi->hasMethodProfile(ProfileType_Value, md, JITProfilingRole_GEN)) {
pi->createValueMethodProfile(mm , md, cc_size, (U_32*)&counterKeys.front());
}
irm.getCompilationInterface().unlockMethodData();
if (debug) {
Log::out() << std::endl << "ValuePC:: instrumented, nCounters = " << cc_size << std::endl;
}
}
} //namespace