Index: vm/include/open/em_profile_access.h =================================================================== --- vm/include/open/em_profile_access.h (revision 498558) +++ vm/include/open/em_profile_access.h (working copy) @@ -23,6 +23,7 @@ #include "open/types.h" #include "open/em.h" +#include #ifdef __cplusplus extern "C" { @@ -203,8 +204,8 @@ */ POINTER_SIZE_INT (*value_profiler_get_top_value) (Method_Profile_Handle mph, uint32 instructionKey); + void (*value_profiler_dump_values) (Method_Profile_Handle mph, std::ostream& os); - } EM_ProfileAccessInterface; Index: vm/em/src/NValueProfileCollector.cpp =================================================================== --- vm/em/src/NValueProfileCollector.cpp (revision 498558) +++ vm/em/src/NValueProfileCollector.cpp (working copy) @@ -64,6 +64,7 @@ } return (-1); } + void ValueProfileCollector::insert_into_tnv_table (struct Simple_TNV_Table* TNV_table, struct Simple_TNV_Table* TNV_clear_part, POINTER_SIZE_INT value_to_insert, uint32 times_met) { uint32 insert_index, temp_min_index; @@ -150,59 +151,20 @@ return profile; } - - -void ValueProfileCollector::addNewValue(Method_Profile_Handle mph, uint32 instructionKey, POINTER_SIZE_INT valueToAdd) -{ - POINTER_SIZE_INT curr_value = valueToAdd; - ValueMethodProfile* vmp = ((ValueMethodProfile*)mph); - vmp->lockProfile(); - VPInstructionProfileData* _temp_vp = vmp->ValueMap[instructionKey]; - POINTER_SIZE_INT* last_value = &(_temp_vp->last_value); - uint32* profile_tick = &(_temp_vp->profile_tick); - uint32* num_times_profiled = &(_temp_vp->num_times_profiled); - struct Simple_TNV_Table * TNV_clear_part = _temp_vp->TNV_clear_part; - struct Simple_TNV_Table * TNV_steady_part = _temp_vp->TNV_Table; - if ( TNV_algo_type == TNV_DIVIDED){ - if (*profile_tick == clear_interval){ - *profile_tick = 0; - simple_tnv_clear(TNV_clear_part); - } - (*profile_tick)++; - } - if (curr_value == *last_value){ - (*num_times_profiled)++; - } - else { - *num_times_profiled = 1; - insert_into_tnv_table (TNV_steady_part, TNV_clear_part, valueToAdd, *num_times_profiled); - *last_value = curr_value; - } - vmp->unlockProfile(); -} - POINTER_SIZE_INT ValueProfileCollector::find_max(Simple_TNV_Table *TNV_where) { POINTER_SIZE_INT max_value = 0; uint32 temp_index, temp_max_frequency = 0; - for (temp_index = 0; temp_index < TNV_steady_size; temp_index++) - if (TNV_where->frequency > temp_max_frequency){ - temp_max_frequency = TNV_where->frequency; - max_value = TNV_where->value; + for (temp_index = 0; temp_index < TNV_steady_size; temp_index++) { + Simple_TNV_Table *TNV_current = &(TNV_where[temp_index]); + if (TNV_current->frequency > temp_max_frequency){ + temp_max_frequency = TNV_current->frequency; + max_value = TNV_current->value; } + } return (max_value); } -POINTER_SIZE_INT ValueProfileCollector::getResult(Method_Profile_Handle mph, uint32 instructionKey) -{ - ValueMethodProfile* vmp = ((ValueMethodProfile*)mph); - vmp->lockProfile(); - VPInstructionProfileData* _temp_vp = vmp->ValueMap[instructionKey]; - POINTER_SIZE_INT result = (_temp_vp == NULL) ? 0 : find_max(_temp_vp->TNV_Table); - vmp->unlockProfile(); - return result; -} - ValueProfileCollector::ValueProfileCollector(EM_PC_Interface* em, const std::string& name, JIT_Handle genJit, uint32 _TNV_steady_size, uint32 _TNV_clear_size, uint32 _clear_interval, algotypes _TNV_algo_type) @@ -243,6 +205,108 @@ hymutex_destroy(lock); } +void ValueMethodProfile::addNewValue(uint32 instructionKey, POINTER_SIZE_INT valueToAdd) +{ + POINTER_SIZE_INT curr_value = valueToAdd; + lockProfile(); + VPInstructionProfileData* _temp_vp = ValueMap[instructionKey]; + POINTER_SIZE_INT* last_value = &(_temp_vp->last_value); + uint32* profile_tick = &(_temp_vp->profile_tick); + uint32* num_times_profiled = &(_temp_vp->num_times_profiled); + struct Simple_TNV_Table* TNV_clear_part = _temp_vp->TNV_clear_part; + struct Simple_TNV_Table* TNV_steady_part = _temp_vp->TNV_Table; + if ( getVPC()->TNV_algo_type == ValueProfileCollector::TNV_DIVIDED){ + if (*profile_tick == getVPC()->clear_interval){ + *profile_tick = 0; + getVPC()->simple_tnv_clear(TNV_clear_part); + } + (*profile_tick)++; + } + if (curr_value == *last_value){ + (*num_times_profiled)++; + } + else { + flushInstProfile(_temp_vp); + *num_times_profiled = 1; + getVPC()->insert_into_tnv_table (TNV_steady_part, TNV_clear_part, valueToAdd, *num_times_profiled); + *last_value = curr_value; + } + unlockProfile(); +} + + +POINTER_SIZE_INT ValueMethodProfile::getResult(uint32 instructionKey) +{ + lockProfile(); + VPInstructionProfileData* _temp_vp = ValueMap[instructionKey]; + flushInstProfile(_temp_vp); + POINTER_SIZE_INT result = (_temp_vp == NULL) ? 0 : getVPC()->find_max(_temp_vp->TNV_Table); + unlockProfile(); + return result; +} + +void ValueMethodProfile::flushInstProfile(VPInstructionProfileData* instProfile) +{ + POINTER_SIZE_INT last_value = instProfile->last_value; + uint32* num_times_profiled = &(instProfile->num_times_profiled); + struct Simple_TNV_Table* TNV_clear_part = instProfile->TNV_clear_part; + struct Simple_TNV_Table* TNV_steady_part = instProfile->TNV_Table; + getVPC()->insert_into_tnv_table (TNV_steady_part, TNV_clear_part, last_value, *num_times_profiled); + *num_times_profiled = 0; +} + +void ValueMethodProfile::dumpValues(std::ostream& os) +{ + std::map::const_iterator mapIter; + assert(pc->type == EM_PCTYPE_VALUE); + lockProfile(); + os << "===== Value profile dump, " << ValueMap.size() << " element(s) ===" << std::endl; + for (mapIter = ValueMap.begin(); mapIter != ValueMap.end(); mapIter++) { + os << "=== Instruction key: " << mapIter->first; + VPInstructionProfileData* _temp_vp = mapIter->second; + flushInstProfile(_temp_vp); + os << ", num_times_profiled: " << _temp_vp->num_times_profiled << ", profile_tick: " << _temp_vp->profile_tick << std::endl; + struct Simple_TNV_Table * TNV_steady_part = _temp_vp->TNV_Table; + if (TNV_steady_part != NULL) { + uint32 size = ((ValueProfileCollector*)pc)->TNV_steady_size; + os << "= TNV_steady_part, size = " << size << std::endl; + for (uint32 i = 0; i < size; i++) { + os << "== Frequency: " << TNV_steady_part[i].frequency << " = Value: "; + POINTER_SIZE_INT value = TNV_steady_part[i].value; + if (value != 0) { + os << class_get_name(vtable_get_class((VTable_Handle)value)); + } else { + os << "NULL"; + } + os << " ==" << std::endl; + } + } + struct Simple_TNV_Table * TNV_clear_part = _temp_vp->TNV_clear_part; + if (TNV_clear_part != NULL) { + uint32 size = ((ValueProfileCollector*)pc)->TNV_clear_size; + os << "= TNV_clear_part, size = " << size << std::endl; + for (uint32 i = 0; i < size; i++) { + os << "== " << TNV_clear_part[i].frequency << " = Value: "; + POINTER_SIZE_INT value = TNV_clear_part[i].value; + if (value != 0) { + os << class_get_name(vtable_get_class((VTable_Handle)value)); + } else { + os << "NULL"; + } + os << " ==" << std::endl; + } + } + } + unlockProfile(); + os << "====== End of dump ======================" << std::endl; +} + +ValueProfileCollector* ValueMethodProfile::getVPC() const { + assert(pc->type == EM_PCTYPE_VALUE); + return ((ValueProfileCollector*)pc); +} + + MethodProfile* ValueProfileCollector::getMethodProfile(Method_Handle mh) const { ValueProfilesMap::const_iterator it = profilesByMethod.find(mh); @@ -260,16 +324,27 @@ MethodProfile* mp = (MethodProfile*)mph; assert(mp->pc->type == EM_PCTYPE_VALUE); ValueMethodProfile* vmp = (ValueMethodProfile*)mp; - return ((ValueProfileCollector*)(vmp->pc))->getResult(mph, instructionKey); + return vmp->getResult(instructionKey); } + void value_profiler_add_value (Method_Profile_Handle mph, uint32 instructionKey, POINTER_SIZE_INT valueToAdd) { assert(mph != NULL); MethodProfile* mp = (MethodProfile*)mph; assert(mp->pc->type == EM_PCTYPE_VALUE); ValueMethodProfile* vmp = (ValueMethodProfile*)mp; - return ((ValueProfileCollector*)(vmp->pc))->addNewValue(mph, instructionKey, valueToAdd); + return vmp->addNewValue(instructionKey, valueToAdd); } + +void value_profiler_dump_values(Method_Profile_Handle mph, std::ostream& os) +{ + assert(mph != NULL); + MethodProfile* mp = (MethodProfile*)mph; + assert(mp->pc->type == EM_PCTYPE_VALUE); + ValueMethodProfile* vmp = (ValueMethodProfile*)mp; + vmp->dumpValues(os); +} + Method_Profile_Handle value_profiler_create_profile(PC_Handle pch, Method_Handle mh, uint32 numkeys, uint32 keys[]) { assert(pch!=NULL); Index: vm/em/src/DrlEMImpl.cpp =================================================================== --- vm/em/src/DrlEMImpl.cpp (revision 498558) +++ vm/em/src/DrlEMImpl.cpp (working copy) @@ -148,6 +148,7 @@ profileAccessInterface.value_profiler_create_profile = value_profiler_create_profile; profileAccessInterface.value_profiler_add_value = value_profiler_add_value; profileAccessInterface.value_profiler_get_top_value = value_profiler_get_top_value; + profileAccessInterface.value_profiler_dump_values = value_profiler_dump_values; return; } Index: vm/em/src/NValueProfileCollector.h =================================================================== --- vm/em/src/NValueProfileCollector.h (revision 498558) +++ vm/em/src/NValueProfileCollector.h (working copy) @@ -49,23 +49,22 @@ uint32 TNV_clear_size; uint32 clear_interval; algotypes TNV_algo_type; - struct Simple_TNV_Table * TNV_clear_part; - struct Simple_TNV_Table * TNV_steady_part; public: ValueProfileCollector(EM_PC_Interface* em, const std::string& name, JIT_Handle genJit, uint32 _TNV_steady_size, uint32 _TNV_clear_size, uint32 _clear_interval, algotypes _TNV_algo_type); virtual TbsEMClient* getTbsEmClient() const {return (NULL);} - virtual ~ValueProfileCollector(); MethodProfile* getMethodProfile(Method_Handle mh) const ; + virtual ~ValueProfileCollector(); + MethodProfile* getMethodProfile(Method_Handle mh) const ; ValueMethodProfile* createProfile(Method_Handle mh, uint32 numkeys, uint32 keys[]); - POINTER_SIZE_INT getResult(Method_Profile_Handle mph, uint32 instructionKey); - void addNewValue(Method_Profile_Handle mph, uint32 instructionKey, POINTER_SIZE_INT valueToAdd); -private: + int32 search_in_tnv_table (struct Simple_TNV_Table * TNV_where, POINTER_SIZE_INT value_to_search, uint32 number_of_objects); int32 min_in_tnv (struct Simple_TNV_Table * TNV_where, uint32 number_of_objects); void insert_into_tnv_table (struct Simple_TNV_Table* TNV_table, struct Simple_TNV_Table* TNV_clear_part, POINTER_SIZE_INT value_to_insert, uint32 times_met); POINTER_SIZE_INT find_max(struct Simple_TNV_Table* TNV_where); void simple_tnv_clear (struct Simple_TNV_Table* TNV_where); + +private: std::string catName; bool loggingEnabled; typedef std::map ValueProfilesMap; @@ -94,14 +93,20 @@ ~ValueMethodProfile(); void lockProfile() {hymutex_lock(lock);} void unlockProfile() {hymutex_unlock(lock);} + void dumpValues(std::ostream& os); + void addNewValue(uint32 instructionKey, POINTER_SIZE_INT valueToAdd); + POINTER_SIZE_INT getResult(uint32 instructionKey); private: + // unsynchronized method - must be called from synchronized ones + void flushInstProfile(VPInstructionProfileData* instProfile); + ValueProfileCollector* getVPC() const; + hymutex_t lock; }; -Method_Profile_Handle value_profiler_create_profile(PC_Handle ph, Method_Handle mh, uint32 instructionKey, ValueProfileCollector::algotypes, uint32 steadySize, uint32 clearSize, uint32 clearInterval); - POINTER_SIZE_INT value_profiler_get_top_value (Method_Profile_Handle mph, uint32 instructionKey); void value_profiler_add_value (Method_Profile_Handle mph, uint32 instructionKey, POINTER_SIZE_INT valueToAdd); Method_Profile_Handle value_profiler_create_profile(PC_Handle pch, Method_Handle mh, uint32 numkeys, uint32 keys[]); +void value_profiler_dump_values(Method_Profile_Handle mph, std::ostream& os); #endif Index: vm/jitrino/config/em64t/server.emconf =================================================================== --- vm/jitrino/config/em64t/server.emconf (revision 498558) +++ vm/jitrino/config/em64t/server.emconf (working copy) @@ -45,7 +45,8 @@ -XDjit.SD1_OPT.path=opt_init,translator,optimizer,hir2lir,codegen --XDjit.SD1_OPT.path.optimizer=ssa,simplify,dce,uce,vp_instrument,edge_instrument,dessa,statprof,markglobals +-XDjit.SD1_OPT.path.optimizer=ssa,simplify,dce,uce,vp_instrument,devirt_virtual,edge_instrument,dessa,statprof,markglobals +-XDjit.SD1_OPT.path.devirt_virtual=devirt -XDjit.SD1_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l-,early_prop-,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce-,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method -XDjit.SD1_OPT.path.dce1=cg_dce -XDjit.SD1_OPT.path.dce2=cg_dce @@ -61,7 +62,7 @@ -XDjit.SD2_OPT.path=opt_init,translator,optimizer,hir2lir,codegen --XDjit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,edge_annotate,devirt,inline,uce,purge,simplify,dce,uce,hvn,dce,uce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,abcd,dce,uce,gcm,dessa,statprof,markglobals +-XDjit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf,inline,uce,purge,simplify,dce,uce,hvn,dce,uce,dessa,statprof,peel,ssa,hvn,simplify,dce,uce,lower,dce,uce,memopt,reassoc,dce,uce,hvn,dce,uce,abcd,dce,uce,gcm,dessa,statprof,markglobals -XDjit.SD2_OPT.path.codegen=lock_method,bbp,gcpoints,cafl,dce1,i8l-,early_prop-,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce-,stack,break-,iprof-,emitter!,si_insts,gcmap,info,unlock_method -XDjit.SD2_OPT.path.dce1=cg_dce -XDjit.SD2_OPT.path.dce2=cg_dce @@ -69,11 +70,22 @@ -XDjit.SD2_OPT.path.bp_regalloc1=bp_regalloc -XDjit.SD2_OPT.path.bp_regalloc2=bp_regalloc +#devirt configuration +-XDjit.SD2_OPT.path.devirt_virtual=devirt +-XDjit.SD2_OPT.path.devirt_intf=devirt +-XDjit.SD2_OPT.arg.optimizer.devirt_intf.devirt_intf_calls=true +-XDjit.SD2_OPT.arg.optimizer.devirt_intf.devirt_virtual_calls=false + #inliner configuration -XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.filter=- --XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.path=ssa,simplify,dce,uce,edge_annotate,devirt +-XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.path=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf -XDjit.SD2_OPT.arg.optimizer.inline.pipeline=SD2_OPT_inliner_pipeline -XDjit.SD2_OPT.arg.optimizer.inline.connect_early=false +#devirt configuration for inliner pipeline +-XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.path.devirt_virtual=devirt +-XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.path.devirt_intf=devirt +-XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.arg.devirt_intf.devirt_intf_calls=true +-XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.arg.devirt_intf.devirt_virtual_calls=false -XDjit.SD2_OPT.arg.codegen.dce1.early=yes Index: vm/jitrino/config/ia32/server.emconf =================================================================== --- vm/jitrino/config/ia32/server.emconf (revision 498558) +++ vm/jitrino/config/ia32/server.emconf (working copy) @@ -45,7 +45,8 @@ -XDjit.SD1_OPT.path=opt_init,translator,optimizer,hir2lir,codegen --XDjit.SD1_OPT.path.optimizer=ssa,simplify,dce,uce,vp_instrument,edge_instrument,dessa,statprof,markglobals +-XDjit.SD1_OPT.path.optimizer=ssa,simplify,dce,uce,vp_instrument,devirt_virtual,edge_instrument,dessa,statprof,markglobals +-XDjit.SD1_OPT.path.devirt_virtual=devirt -XDjit.SD1_OPT.path.codegen=lock_method,bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info,unlock_method -XDjit.SD1_OPT.path.dce1=cg_dce -XDjit.SD1_OPT.path.dce2=cg_dce @@ -59,9 +60,10 @@ -XDjit.SD1_OPT.arg.codegen.btr.insertCMOVs=no -XDjit.SD1_OPT.arg.codegen.btr.removeConstCompare=yes + -XDjit.SD2_OPT.path=opt_init,translator,optimizer,hir2lir,codegen --XDjit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,edge_annotate,devirt,inline,uce,purge,simplify,dce,uce,lazyexc,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,statprof,markglobals +-XDjit.SD2_OPT.path.optimizer=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf,inline,uce,purge,simplify,dce,uce,lazyexc,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,statprof,markglobals -XDjit.SD2_OPT.path.codegen=lock_method,bbp,btr,gcpoints,cafl,dce1,i8l,api_magic,early_prop,peephole,itrace-,native,constraints,dce2,regalloc,spillgen,layout,copy,rce+,stack,break-,iprof-,peephole,emitter!,si_insts,gcmap,info,unlock_method -XDjit.SD2_OPT.path.dce1=cg_dce -XDjit.SD2_OPT.path.dce2=cg_dce @@ -69,11 +71,22 @@ -XDjit.SD2_OPT.path.bp_regalloc1=bp_regalloc -XDjit.SD2_OPT.path.bp_regalloc2=bp_regalloc +#devirt configuration +-XDjit.SD2_OPT.path.devirt_virtual=devirt +-XDjit.SD2_OPT.path.devirt_intf=devirt +-XDjit.SD2_OPT.arg.optimizer.devirt_intf.devirt_intf_calls=true +-XDjit.SD2_OPT.arg.optimizer.devirt_intf.devirt_virtual_calls=false + #inliner configuration -XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.filter=- --XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.path=ssa,simplify,dce,uce,edge_annotate,devirt +-XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.path=ssa,simplify,dce,uce,devirt_virtual,edge_annotate,unguard,devirt_intf -XDjit.SD2_OPT.arg.optimizer.inline.pipeline=SD2_OPT_inliner_pipeline -XDjit.SD2_OPT.arg.optimizer.inline.connect_early=false +#devirt configuration for inliner pipeline +-XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.path.devirt_virtual=devirt +-XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.path.devirt_intf=devirt +-XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.arg.devirt_intf.devirt_intf_calls=true +-XDjit.SD2_OPT.SD2_OPT_inliner_pipeline.arg.devirt_intf.devirt_virtual_calls=false #helper inliner configuration -XDjit.SD2_OPT.SD2_OPT_helper_inliner_pipeline.filter=- Index: vm/jitrino/src/optimizer/optimizer.h =================================================================== --- vm/jitrino/src/optimizer/optimizer.h (revision 498558) +++ vm/jitrino/src/optimizer/optimizer.h (working copy) @@ -97,7 +97,7 @@ bool devirt_skip_exception_path; float devirt_block_hotness_multiplier; bool devirt_skip_object_methods; - bool devirt_intf_methods; + bool devirt_intf_calls; //unguard int unguard_dcall_percent; Index: vm/jitrino/src/optimizer/devirtualizer.h =================================================================== --- vm/jitrino/src/optimizer/devirtualizer.h (revision 498558) +++ vm/jitrino/src/optimizer/devirtualizer.h (working copy) @@ -31,7 +31,7 @@ class Devirtualizer { public: - Devirtualizer(IRManager& irm); + Devirtualizer(IRManager& irm, SessionAction* sa = NULL); void guardCallsInRegion(IRManager& irm, DominatorTree* tree); @@ -45,7 +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); - + bool _hasProfileInfo; bool _doProfileOnlyGuardedDevirtualization; bool _doAggressiveGuardedDevirtualization; @@ -54,7 +54,8 @@ bool _devirtSkipExceptionPath; float _devirtBlockHotnessMultiplier; bool _devirtSkipJLObjectMethods; - bool _devirtInterfaceMethods; + bool _devirtInterfaceCalls; + bool _devirtVirtualCalls; //unguard pass params Index: vm/jitrino/src/optimizer/devirtualizer.cpp =================================================================== --- vm/jitrino/src/optimizer/devirtualizer.cpp (revision 498558) +++ vm/jitrino/src/optimizer/devirtualizer.cpp (working copy) @@ -36,7 +36,7 @@ GuardedDevirtualizationPass::_run(IRManager& irm) { computeDominators(irm); DominatorTree* dominatorTree = irm.getDominatorTree(); - Devirtualizer pass(irm); + Devirtualizer pass(irm, this); pass.guardCallsInRegion(irm, dominatorTree); } @@ -44,14 +44,15 @@ void GuardRemovalPass::_run(IRManager& irm) { - Devirtualizer pass(irm); + Devirtualizer pass(irm, this); pass.unguardCallsInRegion(irm); } -Devirtualizer::Devirtualizer(IRManager& irm) +Devirtualizer::Devirtualizer(IRManager& irm, SessionAction* sa) : _hasProfileInfo(irm.getFlowGraph().hasEdgeProfile()), _typeManager(irm.getTypeManager()), - _instFactory(irm.getInstFactory()), _opndManager (irm.getOpndManager()) { + _instFactory(irm.getInstFactory()), + _opndManager (irm.getOpndManager()) { const OptimizerFlags& optFlags = irm.getOptimizerFlags(); _doAggressiveGuardedDevirtualization = !_hasProfileInfo || optFlags.devirt_do_aggressive_guarded_devirtualization; @@ -60,7 +61,8 @@ _devirtSkipExceptionPath = optFlags.devirt_skip_exception_path; _devirtBlockHotnessMultiplier = optFlags.devirt_block_hotness_multiplier; _devirtSkipJLObjectMethods = optFlags.devirt_skip_object_methods; - _devirtInterfaceMethods = optFlags.devirt_intf_methods; + _devirtInterfaceCalls = sa ? sa->getBoolArg("devirt_intf_calls", false) : optFlags.devirt_intf_calls; + _devirtVirtualCalls = sa ? sa->getBoolArg("devirt_virtual_calls", true) : true; _directCallPercent = optFlags.unguard_dcall_percent; _directCallPercientOfEntry = optFlags.unguard_dcall_percent_of_entry; @@ -139,6 +141,13 @@ // Perform guarded de-virtualization on calls in region // + 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; + assert(dtree->isValid()); StlDeque dom_stack(regionIRM.getMemoryManager()); @@ -348,6 +357,7 @@ if (_devirtSkipJLObjectMethods) { const char* className = methodDesc.getParentType()->getName(); if (!strcmp(className, "java/lang/Object")) { + Log::out() << " Don't guard calls to java/lang/Object methods"<< std::endl; return false; } } @@ -356,6 +366,7 @@ // // In this mode, always guard in the first pass // + Log::out() << " Guarding calls to all methods aggressively"<< std::endl; return true; } @@ -364,12 +375,20 @@ // node and the apparent target. // if(!_hasProfileInfo) { + Log::out() << " The node doesn't have profile info - don't guard"<< std::endl; return false; } double methodCount = irm.getFlowGraph().getEntryNode()->getExecCount(); double blockCount = node->getExecCount(); - return (blockCount >= methodCount / _devirtBlockHotnessMultiplier); + if (blockCount < (methodCount / _devirtBlockHotnessMultiplier)) { + Log::out() << " Too small block count - don't guard"<< std::endl; + Log::out() << " methodCount: " << methodCount << ", blockCount = " << blockCount + << ", hotness factor: " << _devirtBlockHotnessMultiplier << std::endl; + return false; + } + + return true; } void @@ -390,10 +409,13 @@ assert(base->getType()->isObject()); ObjectType* baseType = (ObjectType*) base->getType(); - MethodDesc* origMethodDesc = methodInst->getMethodDesc(); - + bool intfCall = baseType->isInterface(); + if (! ((_devirtInterfaceCalls && intfCall) || (_devirtVirtualCalls && !intfCall))) { + return; + } // If base type is concrete, consider an explicit guarded test against it - if(!baseType->isNullObject() && ((_devirtInterfaceMethods && baseType->isInterface()) || !baseType->isAbstract() || baseType->isArray())) { + if(!baseType->isNullObject() && ((_devirtInterfaceCalls && intfCall) || !baseType->isAbstract() || baseType->isArray())) { + MethodDesc* origMethodDesc = methodInst->getMethodDesc(); MethodDesc* candidateMeth = NULL; int candidateExecCount = 0; CompilationContext* cc = regionIRM.getCompilationContext(); @@ -406,12 +428,16 @@ methDesc.printFullName(Log::out()); Log::out() << std::endl << "call to the method: " << std::endl << "\t"; origMethodDesc->printFullName(Log::out()); - Log::out() << std::endl; + 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 Index: vm/jitrino/src/optimizer/optimizer.cpp =================================================================== --- vm/jitrino/src/optimizer/optimizer.cpp (revision 498558) +++ vm/jitrino/src/optimizer/optimizer.cpp (working copy) @@ -164,8 +164,8 @@ 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); - optimizerFlags.devirt_intf_methods = getBoolArg("devirt_intf_methods", true); - + optimizerFlags.devirt_intf_calls = getBoolArg("devirt_intf_calls", false); + //unguard optimizerFlags.unguard_dcall_percent = getIntArg("unguard_dcall_percent", 30); optimizerFlags.unguard_dcall_percent_of_entry= getIntArg("unguard_dcall_percent_of_entry", 10); Index: vm/jitrino/src/vm/drl/DrlEMInterface.cpp =================================================================== --- vm/jitrino/src/vm/drl/DrlEMInterface.cpp (revision 498558) +++ vm/jitrino/src/vm/drl/DrlEMInterface.cpp (working copy) @@ -264,6 +264,11 @@ return profileAccessInterface->value_profiler_get_top_value(getHandle(), instructionKey); } +void DrlValueMethodProfile::dumpValues(std::ostream& os) const { + profileAccessInterface->value_profiler_dump_values(getHandle(), os); +} + + } //namespace Index: vm/jitrino/src/vm/drl/DrlEMInterface.h =================================================================== --- vm/jitrino/src/vm/drl/DrlEMInterface.h (revision 498558) +++ vm/jitrino/src/vm/drl/DrlEMInterface.h (working copy) @@ -104,6 +104,7 @@ public: DrlValueMethodProfile (Method_Profile_Handle handle, MethodDesc& md, EM_ProfileAccessInterface* profileAccessInterface); virtual POINTER_SIZE_INT getTopValue(uint32 instructionKey) const; + virtual void dumpValues(std::ostream& os) const; private: EM_ProfileAccessInterface* profileAccessInterface; Index: vm/jitrino/src/vm/EMInterface.h =================================================================== --- vm/jitrino/src/vm/EMInterface.h (revision 498558) +++ vm/jitrino/src/vm/EMInterface.h (working copy) @@ -132,7 +132,8 @@ public: ValueMethodProfile (Method_Profile_Handle handle, MethodDesc& md) : MethodProfile(handle, ProfileType_Value, md){} - virtual POINTER_SIZE_INT getTopValue(uint32 instructionKey) const = 0; + virtual POINTER_SIZE_INT getTopValue(uint32 instructionKey) const = 0; + virtual void dumpValues(std::ostream& os) const = 0; }; Index: vm/jitrino/src/dynopt/ValueProfiler.cpp =================================================================== --- vm/jitrino/src/dynopt/ValueProfiler.cpp (revision 498558) +++ vm/jitrino/src/dynopt/ValueProfiler.cpp (working copy) @@ -37,8 +37,6 @@ void ValueProfilerInstrumentationPass::_run(IRManager& irm) { // Currently value profile is used by interface devirtualization only - const OptimizerFlags& optFlags = irm.getOptimizerFlags(); - if (!optFlags.devirt_intf_methods) return; ControlFlowGraph& flowGraph = irm.getFlowGraph(); MemoryManager mm( 1024, "Value Profiler Instrumentation Pass"); @@ -116,8 +114,8 @@ const uint32 numArgs = 2; Opnd* args[numArgs] = {indexOpnd, valueOpnd}; Inst* addValueInst = instFactory.makeJitHelperCall(opndManager.getNullOpnd(), AddValueProfileValue, numArgs, args); - ((CFGInst *)loadIndexInst)->insertAfter(vtableInst); - ((CFGInst *)addValueInst)->insertAfter(loadIndexInst); + ((CFGInst *)addValueInst)->insertBefore(call); + ((CFGInst *)loadIndexInst)->insertBefore(addValueInst); } } }