Index: vm/jitrino/config/em64t/server.emconf =================================================================== --- vm/jitrino/config/em64t/server.emconf (revision 540847) +++ vm/jitrino/config/em64t/server.emconf (working copy) @@ -58,6 +58,10 @@ -XX:jit.SD2_OPT.path=opt_init,translator,optimizer,hir2lir,codegen +#enable profiling of all virtual calls +-XX:jit.SD1_OPT.arg.optimizer.vp_instrument.profile_abstract=true + + -XX:jit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf,inline,uce,purge,simplify,dce,uce,so2-,simplify,dce,uce,escape,dce,uce,hvn,dce,uce,inline_helpers,purge,simplify,uce,dce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,abcd,dce,uce,gcm,dessa,fastArrayFill,statprof,markglobals -XX:jit.SD2_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l-,early_prop-,itrace-,native,cg_fastArrayFill,constraints,dce2,regalloc,spillgen,layout,copy,rce-,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method -XX:jit.SD2_OPT.path.dce1=cg_dce @@ -67,6 +71,7 @@ -XX:jit.SD2_OPT.path.devirt_virtual=devirt -XX:jit.SD2_OPT.path.devirt_intf=devirt -XX:jit.SD2_OPT.arg.optimizer.devirt_intf.devirt_intf_calls=true +-XX:jit.SD2_OPT.arg.optimizer.devirt_intf.devirt_abstract_calls=true -XX:jit.SD2_OPT.arg.optimizer.devirt_intf.devirt_virtual_calls=false #inliner configuration @@ -78,6 +83,7 @@ -XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.path.devirt_virtual=devirt -XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.path.devirt_intf=devirt -XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.arg.devirt_intf.devirt_intf_calls=true +-XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.arg.devirt_intf.devirt_abstract_calls=true -XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.arg.devirt_intf.devirt_virtual_calls=false Index: vm/jitrino/config/ia32/server.emconf =================================================================== --- vm/jitrino/config/ia32/server.emconf (revision 540847) +++ vm/jitrino/config/ia32/server.emconf (working copy) @@ -58,6 +58,10 @@ -XX:jit.SD1_OPT.path.regalloc=webmaker,cg_regalloc,spillgen -XX:jit.SD1_OPT.arg.codegen.regalloc.webmaker.calc=true +#enable profiling of all virtual calls +-XX:jit.SD1_OPT.arg.optimizer.vp_instrument.profile_abstract=true + + -XX:jit.SD2_OPT.path=opt_init,translator,optimizer,hir2lir,codegen -XX:jit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf,inline,uce,purge,simplify,dce,uce,lazyexc,so2-,simplify,dce,uce,escape,inline_helpers,purge,simplify,uce,dce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,abcd,dce,uce,gcm,dessa,fastArrayFill,statprof,markglobals @@ -69,6 +73,7 @@ -XX:jit.SD2_OPT.path.devirt_virtual=devirt -XX:jit.SD2_OPT.path.devirt_intf=devirt -XX:jit.SD2_OPT.arg.optimizer.devirt_intf.devirt_intf_calls=true +-XX:jit.SD2_OPT.arg.optimizer.devirt_intf.devirt_abstract_calls=true -XX:jit.SD2_OPT.arg.optimizer.devirt_intf.devirt_virtual_calls=false #inliner configuration @@ -80,6 +85,7 @@ -XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.path.devirt_virtual=devirt -XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.path.devirt_intf=devirt -XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.arg.devirt_intf.devirt_intf_calls=true +-XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.arg.devirt_intf.devirt_abstract_calls=true -XX:jit.SD2_OPT.SD2_OPT_inliner_pipeline.arg.devirt_intf.devirt_virtual_calls=false #helper inliner configuration Index: vm/jitrino/src/optimizer/optimizer.h =================================================================== --- vm/jitrino/src/optimizer/optimizer.h (revision 540847) +++ vm/jitrino/src/optimizer/optimizer.h (working copy) @@ -92,8 +92,6 @@ //devirt bool devirt_do_aggressive_guarded_devirtualization; - bool devirt_use_cha_with_profile; - int devirt_use_cha_with_profile_threshold; bool devirt_skip_exception_path; float devirt_block_hotness_multiplier; bool devirt_skip_object_methods; Index: vm/jitrino/src/optimizer/FlowGraph.cpp =================================================================== --- vm/jitrino/src/optimizer/FlowGraph.cpp (revision 540847) +++ vm/jitrino/src/optimizer/FlowGraph.cpp (working copy) @@ -591,6 +591,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: vm/jitrino/src/optimizer/devirtualizer.h =================================================================== --- vm/jitrino/src/optimizer/devirtualizer.h (revision 540847) +++ vm/jitrino/src/optimizer/devirtualizer.h (working copy) @@ -45,19 +45,19 @@ 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; bool _doAggressiveGuardedDevirtualization; - bool _devirtUseCHAWithProfile; - bool _devirtUseCHAWithProfileThreshold; bool _devirtSkipExceptionPath; float _devirtBlockHotnessMultiplier; bool _devirtSkipJLObjectMethods; bool _devirtInterfaceCalls; bool _devirtVirtualCalls; + bool _devirtAbstractCalls; + bool _devirtUsingProfile; - //unguard pass params int _directCallPercent; int _directCallPercientOfEntry; Index: vm/jitrino/src/optimizer/devirtualizer.cpp =================================================================== --- vm/jitrino/src/optimizer/devirtualizer.cpp (revision 540847) +++ vm/jitrino/src/optimizer/devirtualizer.cpp (working copy) @@ -55,13 +55,13 @@ const OptimizerFlags& optFlags = irm.getOptimizerFlags(); _doAggressiveGuardedDevirtualization = !_hasProfileInfo || optFlags.devirt_do_aggressive_guarded_devirtualization; - _devirtUseCHAWithProfile = optFlags.devirt_use_cha_with_profile; - _devirtUseCHAWithProfileThreshold = optFlags.devirt_use_cha_with_profile_threshold; _devirtSkipExceptionPath = optFlags.devirt_skip_exception_path; _devirtBlockHotnessMultiplier = optFlags.devirt_block_hotness_multiplier; _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; _directCallPercent = optFlags.unguard_dcall_percent; _directCallPercientOfEntry = optFlags.unguard_dcall_percent_of_entry; @@ -146,10 +146,11 @@ Log::out() << "Devirt params: " << std::endl; Log::out() << " _doAggressiveGuardedDevirtualization: " << _doAggressiveGuardedDevirtualization << std::endl; - Log::out() << " _devirtUseCHAWithProfile: " << _devirtUseCHAWithProfile << std::endl; 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; assert(dtree->isValid()); StlDeque dom_stack(regionIRM.getMemoryManager()); @@ -346,7 +347,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); Opnd* dynamicVTableAddr = _opndManager.createSsaTmpOpnd(_typeManager.getVTablePtrType(objectType)); Opnd* staticVTableAddr = _opndManager.createSsaTmpOpnd(_typeManager.getVTablePtrType(objectType)); guard->appendInst(_instFactory.makeTauLdVTableAddr(dynamicVTableAddr, base, tauNullChecked)); @@ -397,6 +398,43 @@ 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(); + + 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 +454,32 @@ assert(base->getType()->isObject()); ObjectType* baseType = (ObjectType*) base->getType(); - if (! ((_devirtInterfaceCalls && isIntfCall) || (_devirtVirtualCalls && !isIntfCall))) { + ObjectType* devirtType = NULL; + 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"; + if (_devirtUsingProfile || baseType->isInterface() || baseType->isAbstract()) { + + MethodDesc& methDesc = regionIRM.getMethodDesc(); + Log::out() << std::endl << "Devirtualizing interface/abstract 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()); - } - MethodDesc* rootMethodDesc = regionIRM.getCompilationInterface().getMethodToCompile(); - - // 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 + 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; @@ -471,47 +488,27 @@ 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; + devirtType = clssObjectType; - } else if (profileSelection) { - ClassHierarchyMethodIterator* iterator = regionIRM.getCompilationInterface().getClassHierarchyMethodIterator(baseType, origMethodDesc); - if(iterator->isValid()) { - ProfilingInterface* pi = cc->getProfilingInterface(); - while (iterator->hasNext()) { - MethodDesc* tmpMeth = iterator->getNext(); - int tmpCount = pi->getProfileMethodCount(*tmpMeth); - Log::out() << "CHA devirt profile-selection: " << baseType->getName() << "::" << tmpMeth->getName() << tmpMeth->getSignatureString() - << " exec_count=" << tmpCount << std::endl; - if (candidateExecCount < tmpCount) { - candidateExecCount = tmpCount; - candidateMeth = tmpMeth; - } - } - } } else { NamedType* methodType = origMethodDesc->getParentType(); if (_typeManager.isSubClassOf(baseType, methodType)) { - candidateMeth = regionIRM.getCompilationInterface().getOverriddenMethod(baseType, origMethodDesc); - } + candidateMeth = regionIRM.getCompilationInterface().getOverriddenMethod(baseType, origMethodDesc); + if (candidateMeth) { + jitrino_assert(origMethodDesc->getParentType()->isClass()); + methodInst->setMethodDesc(candidateMeth); + devirtType = baseType; + } + } } if (candidateMeth) { - jitrino_assert(origMethodDesc->getParentType()->isClass()); - methodInst->setMethodDesc(candidateMeth); // // Try to guard this call // + assert(devirtType); if(doGuard(regionIRM, node, *candidateMeth )) { - Log::out() << "Guard call to " << baseType->getName() << "::" << candidateMeth->getName() - <<" CHAWithProfile="<<(profileSelection ? "true":"false")<<" execCnt="<getName() << "::" << candidateMeth->getName() << std::endl; + genGuardedDirectCall(regionIRM, node, last, candidateMeth, devirtType, 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; Index: vm/jitrino/src/optimizer/optimizer.cpp =================================================================== --- vm/jitrino/src/optimizer/optimizer.cpp (revision 540847) +++ vm/jitrino/src/optimizer/optimizer.cpp (working copy) @@ -158,8 +158,6 @@ //devirtualizer flags optimizerFlags.devirt_do_aggressive_guarded_devirtualization = getBoolArg("devirt_aggressive", false); - optimizerFlags.devirt_use_cha_with_profile = getBoolArg("devirt_use_cha_with_profile", false); - optimizerFlags.devirt_use_cha_with_profile_threshold = getIntArg("devirt_use_cha_with_profile_threshold", -1); optimizerFlags.devirt_skip_exception_path = getBoolArg("devirt_skip_exception_path", true); optimizerFlags.devirt_block_hotness_multiplier= (float)getIntArg("devirt_block_hotness_multiplier", 10); optimizerFlags.devirt_skip_object_methods = getBoolArg("devirt_skip_object_methods", false); Index: vm/jitrino/src/dynopt/ValueProfiler.cpp =================================================================== --- vm/jitrino/src/dynopt/ValueProfiler.cpp (revision 540847) +++ vm/jitrino/src/dynopt/ValueProfiler.cpp (working copy) @@ -46,6 +46,9 @@ TypeManager& typeManager = irm.getTypeManager(); StlVector counterKeys(mm); bool debug = Log::isEnabled(); + bool profileAbstractCalls = getBoolArg("profile_abstract", false); + bool profileAllVirtualCalls = getBoolArg("profile_all_virtual", false); + uint32 key = 0; StlVector nodes(mm); @@ -88,18 +91,16 @@ Log::out() << std::endl; } } else { - // That is what we are looking for - if (debug) { - Log::out() << "\tFound ldVTable instruction to instrument: "; - vtableInst->print(Log::out()); - Log::out() << std::endl; + // Profile abstract calls, or all virtual calls + ObjectType* baseType = (ObjectType*) base->getType(); + if(!((baseType->isAbstract() && profileAbstractCalls) || profileAllVirtualCalls)) { + continue; } - // Don't profile virtual calls so far - 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;