Index: build/custom/msvc_2003/gc_gen/gc_gen.vcproj =================================================================== --- build/custom/msvc_2003/gc_gen/gc_gen.vcproj (revision 503992) +++ build/custom/msvc_2003/gc_gen/gc_gen.vcproj (working copy) @@ -160,14 +160,26 @@ RelativePath="..\..\..\..\vm\gc_gen\src\common\interior_pointer.h"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + find_max(_temp_vp->TNV_Table); + POINTER_SIZE_INT result = getVPC()->find_max(_temp_vp->TNV_Table); unlockProfile(); return result; } Index: vm/jitrino/src/optimizer/devirtualizer.h =================================================================== --- vm/jitrino/src/optimizer/devirtualizer.h (revision 503992) +++ vm/jitrino/src/optimizer/devirtualizer.h (working copy) @@ -38,7 +38,7 @@ void unguardCallsInRegion(IRManager& irm); static bool isGuardableVirtualCall(Inst* inst, MethodInst*& methodInst, Opnd*& base, - Opnd* & tauNullChecked, Opnd*&tauTypesChecked, uint32 &argOffset); + Opnd* & tauNullChecked, Opnd*&tauTypesChecked, uint32 &argOffset, bool &isIntfCall); private: Index: vm/jitrino/src/optimizer/devirtualizer.cpp =================================================================== --- vm/jitrino/src/optimizer/devirtualizer.cpp (revision 503992) +++ vm/jitrino/src/optimizer/devirtualizer.cpp (working copy) @@ -69,7 +69,7 @@ } bool -Devirtualizer::isGuardableVirtualCall(Inst* inst, MethodInst*& methodInst, Opnd*& base, Opnd*& tauNullChecked, Opnd *&tauTypesChecked, uint32 &argOffset) +Devirtualizer::isGuardableVirtualCall(Inst* inst, MethodInst*& methodInst, Opnd*& base, Opnd*& tauNullChecked, Opnd *&tauTypesChecked, uint32 &argOffset, bool &isIntfCall) { // // Returns true if this call site may be considered for guarded devirtualization @@ -120,10 +120,14 @@ (methodOpcode == Op_TauLdVirtFunAddr)) { Inst *vtableInst = methodSrc0->getInst(); Opcode vtableInstOpcode = vtableInst->getOpcode(); - if ((vtableInstOpcode == Op_TauLdVTableAddr) || - (vtableInstOpcode == Op_TauLdIntfcVTableAddr)) { + if (vtableInstOpcode == Op_TauLdVTableAddr) { + isIntfCall = false; + } else if (vtableInstOpcode == Op_TauLdIntfcVTableAddr) { + isIntfCall = true; } else { - // must be a copy or something, too hard to check + // Need a real example when this assertion fires + // This can be handled with copy propagation + assert(0); } } else { assert(base == methodInst->getSrc(0)); @@ -404,17 +408,17 @@ Opnd* tauNullChecked = 0; Opnd* tauTypesChecked = 0; uint32 argOffset = 0; - if(isGuardableVirtualCall(last, methodInst, base, tauNullChecked, tauTypesChecked, argOffset)) { + bool isIntfCall = false; + if(isGuardableVirtualCall(last, methodInst, base, tauNullChecked, tauTypesChecked, argOffset, isIntfCall)) { assert(methodInst && base && tauNullChecked && tauTypesChecked && argOffset); assert(base->getType()->isObject()); ObjectType* baseType = (ObjectType*) base->getType(); - bool intfCall = baseType->isInterface(); - if (! ((_devirtInterfaceCalls && intfCall) || (_devirtVirtualCalls && !intfCall))) { + if (! ((_devirtInterfaceCalls && isIntfCall) || (_devirtVirtualCalls && !isIntfCall))) { return; } // If base type is concrete, consider an explicit guarded test against it - if(!baseType->isNullObject() && ((_devirtInterfaceCalls && intfCall) || !baseType->isAbstract() || baseType->isArray())) { + if(!baseType->isNullObject() && ((_devirtInterfaceCalls && isIntfCall) || !baseType->isAbstract() || baseType->isArray())) { MethodDesc* origMethodDesc = methodInst->getMethodDesc(); MethodDesc* candidateMeth = NULL; int candidateExecCount = 0; Index: vm/jitrino/src/dynopt/ValueProfiler.cpp =================================================================== --- vm/jitrino/src/dynopt/ValueProfiler.cpp (revision 503992) +++ vm/jitrino/src/dynopt/ValueProfiler.cpp (working copy) @@ -59,7 +59,8 @@ Opnd* tauNullChecked = NULL; Opnd* tauTypesChecked = NULL; uint32 argOffset = 0; - if(Devirtualizer::isGuardableVirtualCall(lastInst, methodInst, base, tauNullChecked, tauTypesChecked, argOffset)) { + bool isIntfCall = false; + if(Devirtualizer::isGuardableVirtualCall(lastInst, methodInst, base, tauNullChecked, tauTypesChecked, argOffset, isIntfCall)) { assert(methodInst && base && tauNullChecked && tauTypesChecked && argOffset); assert(base->getType()->isObject()); @@ -75,17 +76,7 @@ } Inst* vtableInst = methodInst->getSrc(0)->getInst(); - Opcode vtableInstOpcode = vtableInst->getOpcode(); - if (vtableInstOpcode == Op_TauLdVTableAddr) { - // That is what we are looking for - if (debug) { - Log::out() << "\tFound ldVTable instruction to instrument: "; - vtableInst->print(Log::out()); - Log::out() << std::endl; - } - // Don't profile virtual calls so far - continue; - } else if (vtableInstOpcode == Op_TauLdIntfcVTableAddr) { + if (isIntfCall) { // Need to generate VTable loading Opnd* vTable = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(typeManager.getSystemObjectType())); Inst* ldVtableInst = instFactory.makeTauLdVTableAddr(vTable, base, tauNullChecked); @@ -97,6 +88,13 @@ 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; + } + // Don't profile virtual calls so far continue; } VectorHandler* bc2HIRMapHandler = new VectorHandler(bcOffset2HIRHandlerName, &md); Index: src/test/regression/H3121/run.test.xml =================================================================== --- src/test/regression/H3121/run.test.xml (revision 0) +++ src/test/regression/H3121/run.test.xml (revision 0) @@ -0,0 +1,8 @@ + + + + + + Index: src/test/regression/H3121/H3121.java =================================================================== --- src/test/regression/H3121/H3121.java (revision 0) +++ src/test/regression/H3121/H3121.java (revision 0) @@ -0,0 +1,39 @@ +package org.apache.harmony.drlvm.tests.regression.h3121; + +import junit.framework.TestCase; + + +/* The test checks that the JIT correctly optimizes virtual calls + * when the receiver is of interface type. Loops are needed to force + * JIT recompilation. The method vc() contains both an interface call + * and a virtual call, an attempt to devirtualize a virtual call caused + * segfault in the ValueProfileCollector (Harmony-3121 issue). + */ +public class H3121 extends TestCase { + + Intf io = new IntfClass(); + Object o = new Object(); + + public void test() { + boolean b = false; + for (int i = 0; i < 10000000; i++) { + b = vc(); + } + System.out.println("Test passed"); + } + + public boolean vc() { + io.fake(); + return io.equals(o); + } +} + +interface Intf { + public void fake(); +} + +class IntfClass implements Intf { + public void fake() { + for (int i = 0; i < 100; i++) {} + } +}