g++ -O3 -fprofile-generate -o test{1,.C}; ./test1; g++ -O3 -fprofile-use -o test{2,.C}; ./test2 aborts when using g++ 8 or current trunk. struct nsISupports { virtual int QueryInterface (const int &aIID, void **aInstancePtr) = 0; virtual __attribute__((noinline, noclone)) unsigned AddRef (void) = 0; virtual unsigned Release (void) = 0; }; struct nsIObserver : public nsISupports { virtual int Observe (nsISupports * aSubject, const char *aTopic, const unsigned short *aData) = 0; }; struct nsISupportsWeakReference : public nsISupports { virtual int GetWeakReference (void **_retval) = 0; }; struct nsSupportsWeakReference : public nsISupportsWeakReference { nsSupportsWeakReference () : mProxy (0) {} virtual int GetWeakReference (void **_retval) override { return 0; } ~nsSupportsWeakReference () {} void NoticeProxyDestruction () { mProxy = nullptr; } void *mProxy; void ClearWeakReferences (); bool HasWeakReferences () const { return !!mProxy; } }; struct mozIPersonalDictionary : public nsISupports { virtual int Load (void) = 0; virtual int Save (void) = 0; virtual int GetWordList (void **aWordList) = 0; virtual int Check (const int &word, bool * _retval) = 0; virtual int AddWord (const int &word) = 0; virtual int RemoveWord (const int &word) = 0; virtual int IgnoreWord (const int &word) = 0; virtual int EndSession (void) = 0; }; struct mozPersonalDictionary final : public mozIPersonalDictionary, public nsIObserver, public nsSupportsWeakReference { virtual int QueryInterface (const int &aIID, void **aInstancePtr) override; virtual __attribute__((noinline, noclone)) unsigned AddRef (void) override; virtual unsigned Release (void) override; unsigned long mRefCnt; virtual int Load (void) override { return 0; } virtual int Save (void) override { return 0; } virtual int GetWordList (void **aWordList) override { return 0; } virtual int Check (const int &word, bool * _retval) override { return 0; } virtual int AddWord (const int &word) override { return 0; } virtual int RemoveWord (const int &word) override { return 0; } virtual int IgnoreWord (const int &word) override { return 0; } virtual int EndSession (void) override { return 0; } virtual int Observe (nsISupports * aSubject, const char *aTopic, const unsigned short *aData) override { return 0; } mozPersonalDictionary () : mRefCnt(0) {} int Init () { return 0; } virtual ~mozPersonalDictionary () {} bool mIsLoaded; bool mSavePending; void *mFile; char mMonitor[96]; char mMonitorSave[96]; char mDictionaryTable[32]; char mIgnoreTable[32]; }; unsigned mozPersonalDictionary::AddRef (void) { unsigned count = ++mRefCnt; return count; } unsigned mozPersonalDictionary::Release (void) { unsigned count = --mRefCnt; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } int mozPersonalDictionary::QueryInterface (const int &aIID, void **aInstancePtr) { nsISupports *foundInterface; if (aIID == 122) foundInterface = static_cast <mozIPersonalDictionary *>(this); else foundInterface = static_cast <nsISupportsWeakReference *>(this); int status; foundInterface->AddRef (); *aInstancePtr = foundInterface; return status; } __attribute__((noipa)) int foo (nsISupports *p, const int &i) { void *q; return p->QueryInterface (i, &q); } int main () { mozPersonalDictionary m; int j = 123; for (int i = 0; i < 100000; i++) foo (static_cast <nsISupportsWeakReference *>(&m), j); if (m.mRefCnt != 100000) __builtin_abort (); } Testcase reduced from firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1495742 The problem is that in the _ZThn8_N21mozPersonalDictionary14QueryInterfaceERKiPPv thunk we devirtualize incorrectly, call _ZThn8_N21mozPersonalDictionary6AddRefEv when we should have called _ZThn16_N21mozPersonalDictionary6AddRefEv instead.
Created attachment 45273 [details] Fix I am testing
Author: hubicka Date: Fri Dec 21 19:13:06 2018 New Revision: 267338 URL: https://gcc.gnu.org/viewcvs?rev=267338&root=gcc&view=rev Log: PR ipa/88561 * ipa-polymorphic-call.c (ipa_polymorphic_call_context::ipa_polymorphic_call_context): Handle arguments of thunks correctly. (ipa_polymorphic_call_context::get_dynamic_context): Be ready for NULL instance pinter. * lto-cgraph.c (lto_output_node): Always stream thunk info. Added: trunk/gcc/testsuite/g++.dg/tree-prof/devirt.C Modified: trunk/gcc/ChangeLog trunk/gcc/ipa-polymorphic-call.c trunk/gcc/lto-cgraph.c trunk/gcc/testsuite/ChangeLog
Author: marxin Date: Thu Dec 27 12:33:00 2018 New Revision: 267433 URL: https://gcc.gnu.org/viewcvs?rev=267433&root=gcc&view=rev Log: Backport r267338 2018-12-27 Martin Liska <mliska@suse.cz> Backport from mainline 2018-12-15 Jan Hubicka <hubicka@ucw.cz> PR ipa/88561 * ipa-polymorphic-call.c (ipa_polymorphic_call_context::ipa_polymorphic_call_context): Handle arguments of thunks correctly. (ipa_polymorphic_call_context::get_dynamic_context): Be ready for NULL instance pinter. * lto-cgraph.c (lto_output_node): Always stream thunk info. 2018-12-27 Martin Liska <mliska@suse.cz> Backport from mainline 2018-12-15 Jan Hubicka <hubicka@ucw.cz> PR ipa/88561 * g++.dg/tree-prof/devirt.C: New testcase. Added: branches/gcc-8-branch/gcc/testsuite/g++.dg/tree-prof/devirt.C Modified: branches/gcc-8-branch/gcc/ChangeLog branches/gcc-8-branch/gcc/ipa-polymorphic-call.c branches/gcc-8-branch/gcc/lto-cgraph.c branches/gcc-8-branch/gcc/testsuite/ChangeLog
Fixed on all active branches.
Author: jakub Date: Wed Jan 2 09:25:59 2019 New Revision: 267507 URL: https://gcc.gnu.org/viewcvs?rev=267507&root=gcc&view=rev Log: PR ipa/88561 * g++.dg/tree-prof/devirt.C: Expect _ZThn16 only for lp64 and llp64 targets and expect _ZThn8 for ilp32 targets. Modified: trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/g++.dg/tree-prof/devirt.C
Author: marxin Date: Thu Jan 3 08:49:04 2019 New Revision: 267546 URL: https://gcc.gnu.org/viewcvs?rev=267546&root=gcc&view=rev Log: Backport r267507 2019-01-03 Martin Liska <mliska@suse.cz> Backport from mainline 2019-01-02 Jakub Jelinek <jakub@redhat.com> PR ipa/88561 * g++.dg/tree-prof/devirt.C: Expect _ZThn16 only for lp64 and llp64 targets and expect _ZThn8 for ilp32 targets. Modified: branches/gcc-8-branch/gcc/testsuite/ChangeLog branches/gcc-8-branch/gcc/testsuite/g++.dg/tree-prof/devirt.C