Index: working_vm/vm/jitrino/src/optimizer/FlowGraph.cpp =================================================================== --- working_vm/vm/jitrino/src/optimizer/FlowGraph.cpp (revision 527390) +++ working_vm/vm/jitrino/src/optimizer/FlowGraph.cpp (working copy) @@ -589,6 +589,29 @@ Node* newEntry = _duplicateRegion(*irManager, entryJSR, nodesInJSR, defUses, *nodeRenameTable, *opndRenameTable, 0); + // update the BCMap + if(irManager->getCompilationInterface().isBCMapInfoRequired()) { + MethodDesc* meth = irManager->getCompilationInterface().getMethodToCompile(); + VectorHandler *bc2HIRmapHandler = new(inlineManager) VectorHandler(bcOffset2HIRHandlerName, meth); + + // update the BCMap for each copied node + NodeRenameTable::Iter nodeIter(nodeRenameTable); + Node* oldNode = NULL; + Node* newNode = NULL; + StlBitVector regionNodes(inlineManager); + while(nodeIter.getNextElem(oldNode, newNode)) { + Inst* oldLast = (Inst*)oldNode->getLastInst(); + Inst* newLast = (Inst*)newNode->getLastInst(); + if (oldLast->asMethodCallInst() || oldLast->asCallInst()) { + assert(newLast->asMethodCallInst() || newLast->asCallInst()); + uint32 bcOffset = bc2HIRmapHandler->getVectorEntry(oldLast->getId()); + assert((bcOffset != 0) && (bcOffset != ILLEGAL_VALUE)); + bc2HIRmapHandler->setVectorEntry(newLast->getId(), bcOffset); + } + + } + } + fg.removeEdge(block,retTarget); fg.removeEdge(block,entryJSR); jsrInst->unlink(); Index: working_vm/vm/jitrino/src/optimizer/devirtualizer.h =================================================================== --- working_vm/vm/jitrino/src/optimizer/devirtualizer.h (revision 527390) +++ working_vm/vm/jitrino/src/optimizer/devirtualizer.h (working copy) @@ -45,6 +45,7 @@ void guardCallsInBlock(IRManager& irm, Node* node); void genGuardedDirectCall(IRManager& irm, Node* node, Inst* call, MethodDesc* methodDesc, ObjectType* valuedType, Opnd *tauNullChecked, Opnd *tauTypesChecked, uint32 argOffset); bool doGuard(IRManager& irm, Node* node, MethodDesc& methodDesc); + ObjectType *getTopProfiledCalleeType(IRManager& irm, MethodDesc *origMethodDesc, Inst *call); bool _hasProfileInfo; bool _doProfileOnlyGuardedDevirtualization; @@ -56,6 +57,9 @@ bool _devirtSkipJLObjectMethods; bool _devirtInterfaceCalls; bool _devirtVirtualCalls; + bool _devirtAbstractCalls; + bool _devirtUsingProfile; + bool _devirtUsingProfileOnly; //unguard pass params Index: working_vm/vm/jitrino/src/optimizer/devirtualizer.cpp =================================================================== --- working_vm/vm/jitrino/src/optimizer/devirtualizer.cpp (revision 527390) +++ working_vm/vm/jitrino/src/optimizer/devirtualizer.cpp (working copy) @@ -62,6 +62,9 @@ _devirtSkipJLObjectMethods = optFlags.devirt_skip_object_methods; _devirtInterfaceCalls = sa ? sa->getBoolArg("devirt_intf_calls", false) : optFlags.devirt_intf_calls; _devirtVirtualCalls = sa ? sa->getBoolArg("devirt_virtual_calls", true) : true; + _devirtAbstractCalls = sa ? sa->getBoolArg("devirt_abstract_calls", false) : false; + _devirtUsingProfile = sa ? sa->getBoolArg("devirt_using_profile", false) : false; + _devirtUsingProfileOnly = sa ? sa->getBoolArg("devirt_using_profile_only", false) : false; _directCallPercent = optFlags.unguard_dcall_percent; _directCallPercientOfEntry = optFlags.unguard_dcall_percent_of_entry; @@ -150,6 +153,9 @@ Log::out() << " _devirtSkipJLObjectMethods: " << _devirtSkipJLObjectMethods << std::endl; Log::out() << " _devirtInterfaceCalls: " << _devirtInterfaceCalls << std::endl; Log::out() << " _devirtVirtualCalls: " << _devirtVirtualCalls << std::endl; + Log::out() << " _devirtAbstractCalls: " << _devirtAbstractCalls << std::endl; + Log::out() << " _devirtUsingProfile: " << _devirtUsingProfile << std::endl; + Log::out() << " _devirtUsingProfileOnly: " << _devirtUsingProfileOnly << std::endl; assert(dtree->isValid()); StlDeque dom_stack(regionIRM.getMemoryManager()); @@ -346,7 +352,7 @@ // Opnd* base = directCall->getSrc(2); // skip over taus assert(base->getType()->isObject()); - assert(base->getType()->isInterface() || (((ObjectType*) base->getType()) == objectType)); + assert(base->getType()->isInterface() || base->getType()->isAbstract() || (((ObjectType*) base->getType()) == objectType) || _devirtUsingProfile || _devirtUsingProfileOnly); Opnd* dynamicVTableAddr = _opndManager.createSsaTmpOpnd(_typeManager.getVTablePtrType(objectType)); Opnd* staticVTableAddr = _opndManager.createSsaTmpOpnd(_typeManager.getVTablePtrType(objectType)); guard->appendInst(_instFactory.makeTauLdVTableAddr(dynamicVTableAddr, base, tauNullChecked)); @@ -397,6 +403,50 @@ return true; } +ObjectType * +Devirtualizer::getTopProfiledCalleeType(IRManager& regionIRM, MethodDesc *origMethodDesc, Inst *call) { + assert(regionIRM.getCompilationInterface().isBCMapInfoRequired()); + CompilationContext* cc = regionIRM.getCompilationContext(); + Node *node = call->getNode(); + MethodDesc& methDesc = regionIRM.getMethodDesc(); + + Log::out() << std::endl << "Devirtualizing interface call in the method :" << std::endl << "\t"; + methDesc.printFullName(Log::out()); + Log::out() << std::endl << "call to the method: " << std::endl << "\t"; + origMethodDesc->printFullName(Log::out()); + Log::out() << std::endl << "from the CFG node: " << node->getId() << + ", node exec count: " << node->getExecCount() << std::endl; + + ProfilingInterface* pi = cc->getProfilingInterface(); + // Don't devirtualize if there is no value profile + if (!pi->hasMethodProfile(ProfileType_Value, methDesc)) return 0; + ValueMethodProfile* mp = pi->getValueMethodProfile(regionIRM.getMemoryManager(), methDesc); + if (Log::isLogEnabled(LogStream::DBG)) { + mp->dumpValues(Log::out()); + } + MethodDesc* rootMethodDesc = regionIRM.getCompilationInterface().getMethodToCompile(); + + // Get bytecode offset of the call + VectorHandler* bc2HIRMapHandler = new VectorHandler(bcOffset2HIRHandlerName, rootMethodDesc); + uint64 callInstId = (uint64)call->getId(); + uint32 bcOffset = (uint32)bc2HIRMapHandler->getVectorEntry(callInstId); + assert(bcOffset != 0); + assert(bcOffset != ILLEGAL_VALUE); + Log::out() << "Call instruction bcOffset = " << (int32)bcOffset << std::endl; + + // Get profiled vtable value + POINTER_SIZE_INT vtHandle = mp->getTopValue(bcOffset); + if (vtHandle == 0) { + // Do not devirtualize - there were no real calls here + return 0; + } + + // get desired MethodDesc object + assert(vtHandle != 0); + ObjectType* clssObjectType = _typeManager.getObjectType(VMInterface::getTypeHandleFromVTable((void*)vtHandle)); + return clssObjectType; +} + void Devirtualizer::guardCallsInBlock(IRManager& regionIRM, Node* node) { @@ -416,53 +466,45 @@ assert(base->getType()->isObject()); ObjectType* baseType = (ObjectType*) base->getType(); - if (! ((_devirtInterfaceCalls && isIntfCall) || (_devirtVirtualCalls && !isIntfCall))) { + if (! ((_devirtInterfaceCalls && isIntfCall) || (_devirtVirtualCalls && !isIntfCall) || + (baseType->isAbstract() && _devirtAbstractCalls))) { return; } // If base type is concrete, consider an explicit guarded test against it - if(!baseType->isNullObject() && ((_devirtInterfaceCalls && isIntfCall) || !baseType->isAbstract() || baseType->isArray())) { + if(!baseType->isNullObject() && ((_devirtInterfaceCalls && isIntfCall) || !baseType->isAbstract() || baseType->isArray() || (baseType->isAbstract() &&_devirtAbstractCalls))) { MethodDesc* origMethodDesc = methodInst->getMethodDesc(); MethodDesc* candidateMeth = NULL; int candidateExecCount = 0; CompilationContext* cc = regionIRM.getCompilationContext(); bool profileSelection = _devirtUseCHAWithProfile && cc->hasDynamicProfileToUse(); if (baseType->isInterface()) { - assert(regionIRM.getCompilationInterface().isBCMapInfoRequired()); - MethodDesc& methDesc = regionIRM.getMethodDesc(); - - Log::out() << std::endl << "Devirtualizing interface call in the method :" << std::endl << "\t"; - methDesc.printFullName(Log::out()); - Log::out() << std::endl << "call to the method: " << std::endl << "\t"; - origMethodDesc->printFullName(Log::out()); - Log::out() << std::endl << "from the CFG node: " << node->getId() << - ", node exec count: " << node->getExecCount() << std::endl; - - ProfilingInterface* pi = cc->getProfilingInterface(); - // Don't devirtualize if there is no value profile - if (!pi->hasMethodProfile(ProfileType_Value, methDesc)) return; - ValueMethodProfile* mp = pi->getValueMethodProfile(regionIRM.getMemoryManager(), methDesc); - if (Log::isLogEnabled(LogStream::DBG)) { - mp->dumpValues(Log::out()); + ObjectType* clssObjectType = getTopProfiledCalleeType(regionIRM, origMethodDesc, last); + if(clssObjectType == 0) { + return; } - MethodDesc* rootMethodDesc = regionIRM.getCompilationInterface().getMethodToCompile(); + Log::out() << "Valued type: "; + clssObjectType->print(Log::out()); + Log::out() << std::endl; + candidateMeth = regionIRM.getCompilationInterface().resolveMethod(clssObjectType, origMethodDesc->getName(), origMethodDesc->getSignatureString()); + Log::out() << "candidateMeth: "<< std::endl; + candidateMeth->printFullName(Log::out()); + Log::out() << std::endl; + + if(doGuard(regionIRM, node, *candidateMeth )) { + Log::out() << "Guard call to " << baseType->getName() << "::" << candidateMeth->getName() << std::endl; + genGuardedDirectCall(regionIRM, node, last, candidateMeth, clssObjectType, tauNullChecked, tauTypesChecked, argOffset); + Log::out() << "Done guarding call to " << baseType->getName() << "::" << candidateMeth->getName() << std::endl; + } else { + Log::out() << "Don't guard call to " << baseType->getName() << "::" << origMethodDesc->getName() << std::endl; + } + + return; - // Get bytecode offset of the call - VectorHandler* bc2HIRMapHandler = new VectorHandler(bcOffset2HIRHandlerName, rootMethodDesc); - uint64 callInstId = (uint64)last->getId(); - uint32 bcOffset = (uint32)bc2HIRMapHandler->getVectorEntry(callInstId); - assert(bcOffset != 0); - Log::out() << "Call instruction bcOffset = " << (int32)bcOffset << std::endl; - - // Get profiled vtable value - POINTER_SIZE_INT vtHandle = mp->getTopValue(bcOffset); - if (vtHandle == 0) { - // Do not devirtualize - there were no real calls here + } else if (baseType->isAbstract() && _devirtAbstractCalls) { + ObjectType* clssObjectType = getTopProfiledCalleeType(regionIRM, origMethodDesc, last); + if(clssObjectType == 0) { return; } - - // get desired MethodDesc object - assert(vtHandle != 0); - ObjectType* clssObjectType = _typeManager.getObjectType(VMInterface::getTypeHandleFromVTable((void*)vtHandle)); Log::out() << "Valued type: "; clssObjectType->print(Log::out()); Log::out() << std::endl; @@ -470,7 +512,7 @@ Log::out() << "candidateMeth: "<< std::endl; candidateMeth->printFullName(Log::out()); Log::out() << std::endl; - + if(doGuard(regionIRM, node, *candidateMeth )) { Log::out() << "Guard call to " << baseType->getName() << "::" << candidateMeth->getName() << std::endl; genGuardedDirectCall(regionIRM, node, last, candidateMeth, clssObjectType, tauNullChecked, tauTypesChecked, argOffset); @@ -497,10 +539,36 @@ } } } else { - NamedType* methodType = origMethodDesc->getParentType(); - if (_typeManager.isSubClassOf(baseType, methodType)) { - candidateMeth = regionIRM.getCompilationInterface().getOverriddenMethod(baseType, origMethodDesc); + ObjectType *clssObjectType = 0; + if(_devirtUsingProfile || _devirtUsingProfileOnly) { + clssObjectType = getTopProfiledCalleeType(regionIRM, origMethodDesc, last); } + + if (clssObjectType) { + // get desired MethodDesc object + Log::out() << "Valued type: "; + clssObjectType->print(Log::out()); + Log::out() << std::endl; + candidateMeth = regionIRM.getCompilationInterface().getOverriddenMethod(clssObjectType, origMethodDesc); + Log::out() << "candidateMeth: "<< std::endl; + candidateMeth->printFullName(Log::out()); + Log::out() << std::endl; + + if(doGuard(regionIRM, node, *candidateMeth )) { + Log::out() << "Guard call to " << baseType->getName() << "::" << candidateMeth->getName() << std::endl; + genGuardedDirectCall(regionIRM, node, last, candidateMeth, clssObjectType, tauNullChecked, tauTypesChecked, argOffset); + Log::out() << "Done guarding call to " << baseType->getName() << "::" << candidateMeth->getName() << std::endl; + } else { + Log::out() << "Don't guard call to " << baseType->getName() << "::" << origMethodDesc->getName() << std::endl; + } + + return; + } else if(!_devirtUsingProfileOnly) { + NamedType* methodType = origMethodDesc->getParentType(); + if (_typeManager.isSubClassOf(baseType, methodType)) { + candidateMeth = regionIRM.getCompilationInterface().getOverriddenMethod(baseType, origMethodDesc); + } + } } if (candidateMeth) { jitrino_assert(origMethodDesc->getParentType()->isClass()); Index: working_vm/vm/jitrino/src/dynopt/ValueProfiler.cpp =================================================================== --- working_vm/vm/jitrino/src/dynopt/ValueProfiler.cpp (revision 527390) +++ working_vm/vm/jitrino/src/dynopt/ValueProfiler.cpp (working copy) @@ -46,6 +46,14 @@ TypeManager& typeManager = irm.getTypeManager(); StlVector counterKeys(mm); bool debug = Log::isEnabled(); + bool profileAbstractCalls = getBoolArg("profile_abstract", false); + bool profileAllVirtualCalls = getBoolArg("profile_all_virtual", false); + + // Note: for some strange reason, we can't always positively identify abstract calls + if(profileAbstractCalls) { + profileAllVirtualCalls = true; + } + uint32 key = 0; StlVector nodes(mm); @@ -94,12 +102,32 @@ vtableInst->print(Log::out()); Log::out() << std::endl; } - // Don't profile virtual calls so far - continue; + + // profile abstract calls, or all virtual calls + ObjectType* baseType = (ObjectType*) base->getType(); + Log::out() << "type is " << baseType->getName() << std::endl; + if((baseType->isAbstract() && profileAbstractCalls) || profileAllVirtualCalls) { + Log::out() << "\tnon-interface call" << std::endl; + + // Need to generate VTable loading + Opnd* vTable = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(typeManager.getSystemObjectType())); + Inst* ldVtableInst = instFactory.makeTauLdVTableAddr(vTable, base, tauNullChecked); + ((CFGInst *)ldVtableInst)->insertBefore(call); + vtableInst = ldVtableInst; + if (debug) { + Log::out() << "\tInserted ldVTable instruction to instrument: "; + ldVtableInst->print(Log::out()); + Log::out() << std::endl; + } + } else { + continue; + } + } - VectorHandler* bc2HIRMapHandler = new VectorHandler(bcOffset2HIRHandlerName, &md); + VectorHandler* bc2HIRMapHandler = new (mm) VectorHandler(bcOffset2HIRHandlerName, &md); uint64 callInstId = (uint64)lastInst->getId(); key = (uint32)bc2HIRMapHandler->getVectorEntry(callInstId); + assert(key != ILLEGAL_VALUE); assert(key != 0); if (debug) { Log::out() << "Use call instruction bcOffset = " << (int32)key << std::endl;