Gecko-dev Diary
Starting in August 2023 I'll be upgrading the Sailfish OS browser from Gecko version ESR 78 to ESR 91. This page catalogues my progress.
Latest code changes are in the gecko-dev sailfishos-esr91 branch.
There is an index of all posts in case you want to jump to a particular day.
Gecko
5 most recent items
1 Aug 2024 : Day 306 #
I expected this crash that's happening when the user pressed on a Selection list would be an easy one to fix. It's turning out to be far harder than I'd anticipated. The problem is simply that the mLayerManager member of the top level nsIWidget, which is of type EmbedLitePuppetWidget, is set to null. On ESR 78 it's correctly set to a value, but on ESR 91 that value is missing.
I've put together a sequence of steps for getting to the correct point in the code. It's a little intricate, but it does the trick. The steps are:
So here's the outcome of this test on ESR 78:
If you'd like to read any of my other gecko diary entries, they're all available on my Gecko-dev Diary page.
I've put together a sequence of steps for getting to the correct point in the code. It's a little intricate, but it does the trick. The steps are:
- Add breakpoints to PresShell::Paint() and PuppetWidgetBase::GetLayerManager().
- Disable the breakpoints.
- Run the browser and open the test page.
- Drop to the debugger and enable the Paint() breakpoint.
- Continue execution.
- Press on the problem Select widget on the web page.
- Wait for the breakpoint to hit.
- Disable the Paint() breakpoint and enable the GetLayerManager() breakpoint.
- Continue execution and wait for the breakpoint to hit.
(gdb) delete break Delete all breakpoints? (y or n) y (gdb) break PresShell::Paint Breakpoint 2 at 0x7ff40086f8: file layout/base/PresShell.cpp, line 6229. (gdb) break PuppetWidgetBase::GetLayerManager Breakpoint 3 at 0x7ff4c58000: file mobile/sailfishos/embedshared/ PuppetWidgetBase.cpp, line 419. (gdb) disable break (gdb) c Continuing. [...] # Wait for page to load: https://browser.sailfishos.org/tests/testselect.html ^C Thread 1 "sailfish-browse" received signal SIGINT, Interrupt. 0x0000007fef53e740 in poll () from /lib64/libc.so.6 (gdb) enable break 2 (gdb) c Continuing. # Press the selection list button Thread 10 "GeckoWorkerThre" hit Breakpoint 2, mozilla::PresShell:: Paint (this=this@entry=0x7fb90f3970, aViewToPaint=aViewToPaint@entry=0x7fb912ae80, aDirtyRegion=..., aFlags=aFlags@entry=mozilla::PaintFlags::PaintLayers) at layout/base/PresShell.cpp:6229 6229 PaintFlags aFlags) { (gdb) disable break 2 (gdb) enable break 3 (gdb) c Continuing. Thread 10 "GeckoWorkerThre" hit Breakpoint 3, mozilla::embedlite:: PuppetWidgetBase::GetLayerManager (this=this@entry=0x7fb8c99570, aShadowManager=aShadowManager@entry=0x0, aBackendHint=aBackendHint@entry=mozilla::layers::LayersBackend:: LAYERS_NONE, aPersistence=aPersistence@entry=nsIWidget::LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:419 419 { (gdb)Using these steps we can now more easily see the difference between ESR 78 and ESR 91. On ESR 78 we have this:
Thread 10 "GeckoWorkerThre" hit Breakpoint 12, mozilla::embedlite:: PuppetWidgetBase::GetLayerManager (this=this@entry=0x7f81216bb0, aShadowManager=aShadowManager@entry=0x0, aBackendHint=aBackendHint@entry=mozilla::layers::LayersBackend:: LAYERS_NONE, aPersistence=aPersistence@entry=nsIWidget::LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:420 420 if (Destroyed()) { (gdb) bt 9 #0 mozilla::embedlite::PuppetWidgetBase::GetLayerManager ( this=this@entry=0x7f81216bb0, aShadowManager=aShadowManager@entry=0x0, aBackendHint=aBackendHint@entry=mozilla::layers::LayersBackend:: LAYERS_NONE, aPersistence=aPersistence@entry=nsIWidget:: LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:424 #1 0x0000007fbca92868 in mozilla::embedlite::EmbedLitePuppetWidget:: GetLayerManager (this=0x7f81216bb0, aShadowManager=0x0, aBackendHint=mozilla::layers::LayersBackend::LAYERS_NONE, aPersistence=nsIWidget::LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/EmbedLitePuppetWidget.cpp:381 #2 0x0000007fbbf3ce10 in nsIWidget::GetLayerManager (this=<optimized out>) at obj-build-mer-qt-xr/dist/include/nsIWidget.h:1266 #3 mozilla::PresShell::Paint (this=this@entry=0x7f81266db0, aViewToPaint=aViewToPaint@entry=0x7f80ecb310, aDirtyRegion=..., aFlags=aFlags@entry=mozilla::PaintFlags::PaintLayers) at layout/base/PresShell.cpp:6134 #4 0x0000007fbbdb40ac in nsViewManager::ProcessPendingUpdatesPaint ( this=this@entry=0x7f80714980, aWidget=aWidget@entry=0x7f81216bb0) at obj-build-mer-qt-xr/dist/include/nsTArray.h:554 #5 0x0000007fbbdb43c0 in nsViewManager::ProcessPendingUpdatesForView ( this=this@entry=0x7f80714980, aView=<optimized out>, aFlushDirtyRegion=aFlushDirtyRegion@entry=true) at view/nsViewManager.cpp: 395 #6 0x0000007fbbdb4b50 in nsViewManager::ProcessPendingUpdates ( this=0x7f80714980) at view/nsViewManager.cpp:1018 #7 nsViewManager::ProcessPendingUpdates (this=this@entry=0x7f80714980) at view/nsViewManager.cpp:1004 #8 0x0000007fbbf13e4c in nsRefreshDriver::Tick (this=0x7f812166c0, aId=..., aId@entry=..., aNowTime=aNowTime@entry=...) at layout/base/nsRefreshDriver.cpp:2201 (More stack frames follow...) (gdb) n 530 bool Destroyed() const { return mOnDestroyCalled; } (gdb) n 424 if (mLayerManager) { (gdb) p mLayerManager $22 = {mRawPtr = 0x7f80b6c6a0}I've included the backtrace in the output here for both versions just to check that we really are in the same place. Here's the same on ESR 91:
Thread 10 "GeckoWorkerThre" hit Breakpoint 3, mozilla::embedlite:: PuppetWidgetBase::GetLayerManager (this=this@entry=0x7fb8c99570, aShadowManager=aShadowManager@entry=0x0, aBackendHint=aBackendHint@entry=mozilla::layers::LayersBackend:: LAYERS_NONE, aPersistence=aPersistence@entry=nsIWidget::LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:419 419 { (gdb) bt 8 #0 mozilla::embedlite::PuppetWidgetBase::GetLayerManager ( this=this@entry=0x7fb8c99570, aShadowManager=aShadowManager@entry=0x0, aBackendHint=aBackendHint@entry=mozilla::layers::LayersBackend:: LAYERS_NONE, aPersistence=aPersistence@entry=nsIWidget:: LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:424 #1 0x0000007ff4c52d40 in mozilla::embedlite::EmbedLitePuppetWidget:: GetLayerManager (this=0x7fb8c99570, aShadowManager=0x0, aBackendHint=mozilla::layers::LayersBackend::LAYERS_NONE, aPersistence=nsIWidget::LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/EmbedLitePuppetWidget.cpp:379 #2 0x0000007ff4008a24 in nsIWidget::GetLayerManager (this=<optimized out>) at ${PROJECT}/obj-build-mer-qt-xr/dist/include/nsIWidget.h:1303 #3 mozilla::PresShell::Paint (this=this@entry=0x7fb90f3970, aViewToPaint=aViewToPaint@entry=0x7fb912ae80, aDirtyRegion=..., aFlags=aFlags@entry=mozilla::PaintFlags::PaintLayers) at layout/base/PresShell.cpp:6274 #4 0x0000007ff3e41068 in nsViewManager::ProcessPendingUpdatesPaint ( this=this@entry=0x7fb90cdd70, aWidget=aWidget@entry=0x7fb8c99570) at ${PROJECT}/obj-build-mer-qt-xr/dist/include/mozilla/gfx/RectAbsolute.h:43 #5 0x0000007ff3e4141c in nsViewManager::ProcessPendingUpdatesForView ( this=this@entry=0x7fb90cdd70, aView=<optimized out>, aFlushDirtyRegion=aFlushDirtyRegion@entry=true) at view/nsViewManager.cpp:394 #6 0x0000007ff3e41a0c in nsViewManager::ProcessPendingUpdates ( this=this@entry=0x7fb90cdd70) at view/nsViewManager.cpp:972 #7 0x0000007ff3fe94bc in nsRefreshDriver::Tick (this=0x7fb90cd7a0, aId=..., aId@entry=..., aNowTime=aNowTime@entry=..., aIsExtraTick=aIsExtraTick@entry=nsRefreshDriver::IsExtraTick::No) at layout/base/nsRefreshDriver.cpp:2477 (More stack frames follow...) (gdb) n 564 bool Destroyed() const { return mOnDestroyCalled; } (gdb) n 424 if (mLayerManager) { (gdb) p mLayerManager $1 = {mRawPtr = 0x0} (gdb)As we can see from this, in the ESR 78 case we have a valid value for mLayerManager whereas on ESR 91 it's set to null. This leads to a different flow coming out of PuppetWidgetBase::GetLayerManager(). First on ESR 78:
(gdb) disable break (gdb) finish Run till exit from #0 mozilla::embedlite::PuppetWidgetBase::GetLayerManager ( this=this@entry=0x7f81216bb0, aShadowManager=aShadowManager@entry=0x0, aBackendHint=aBackendHint@entry=mozilla::layers::LayersBackend:: LAYERS_NONE, aPersistence=aPersistence@entry=nsIWidget:: LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:424 mozilla::embedlite::EmbedLitePuppetWidget::GetLayerManager (this=0x7f81216bb0, aShadowManager=0x0, aBackendHint=mozilla::layers::LayersBackend::LAYERS_NONE, aPersistence=nsIWidget::LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/EmbedLitePuppetWidget.cpp:382 382 if (lm) { Value returned is $23 = (mozilla::layers::LayerManager *) 0x7f80b6c6a0 (gdb) p lm $24 = (nsIWidget::LayerManager *) 0x7f80b6c6a0This is as things should be. But on ESR 91 the null value for the layer manager results in additional code being executed. Because this is the top level widget no attempt can be made to extract the layer manager from a parent widget and so the method returns null:
(gdb) disable break (gdb) finish Run till exit from #0 mozilla::embedlite::PuppetWidgetBase::GetLayerManager ( this=this@entry=0x7fb8c99570, aShadowManager=aShadowManager@entry=0x0, aBackendHint=aBackendHint@entry=mozilla::layers::LayersBackend:: LAYERS_NONE, aPersistence=aPersistence@entry=nsIWidget:: LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:424 [New LWP 22078] 0x0000007ff4c52d40 in mozilla::embedlite::EmbedLitePuppetWidget:: GetLayerManager (this=0x7fb8c99570, aShadowManager=0x0, aBackendHint=mozilla::layers::LayersBackend::LAYERS_NONE, aPersistence=nsIWidget::LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/EmbedLitePuppetWidget.cpp:379 379 LayerManager *lm = PuppetWidgetBase::GetLayerManager(aShadowManager, aBackendHint, aPersistence); Value returned is $2 = (mozilla::layers::LayerManager *) 0x0 (gdb) n 380 if (lm) { (gdb) p lm $3 = (nsIWidget::LayerManager *) 0x0 (gdb) n 385 if (EmbedLiteApp::GetInstance()->GetType() == EmbedLiteApp:: EMBED_INVALID) { (gdb) n 396 nsIWidget* topWidget = GetTopLevelWidget(); (gdb) n 397 if (topWidget && topWidget != this) { (gdb) p topWidget $4 = (nsIWidget *) 0x7fb8c99570 (gdb) p this $5 = (mozilla::embedlite::EmbedLitePuppetWidget * const) 0x7fb8c99570 (gdb)The obvious questions arises: "where is the layer manager actually created?". At this point I'm not really sure, but most of the opportunities to actually create the layer manager appear to happen inside nsBaseWidget. By placing breakpoints on all of the locations that trigger the creation of a layer manager, we should be able to find out which is the one creating it and where it's happening.
So here's the outcome of this test on ESR 78:
Thread 10 "GeckoWorkerThre" hit Breakpoint 14, nsBaseWidget:: CreateCompositor (this=0x7f80b6b4b0, aWidth=1080, aHeight=2520) at widget/nsBaseWidget.cpp:1260 1260 void nsBaseWidget::CreateCompositor(int aWidth, int aHeight) { (gdb) bt 10 #0 nsBaseWidget::CreateCompositor (this=0x7f80b6b4b0, aWidth=1080, aHeight=2520) at widget/nsBaseWidget.cpp:1260 #1 0x0000007fbca9a1fc in mozilla::embedlite::nsWindow::GetLayerManager ( this=0x7f80b6b4b0, aShadowManager=0x0, aBackendHint=<optimized out>, aPersistence=nsIWidget::LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/nsWindow.cpp:225 #2 0x0000007fbca99318 in nsIWidget::GetLayerManager (this=0x7f80b6b4b0) at widget/nsIWidget.h:1266 #3 mozilla::embedlite::PuppetWidgetBase::Invalidate (aRect=..., this=0x7f80b6b4b0) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:261 #4 mozilla::embedlite::PuppetWidgetBase::Invalidate (this=0x7f80b6b4b0, aRect=...) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:253 #5 0x0000007fbca9c1b4 in mozilla::embedlite::PuppetWidgetBase::UpdateBounds ( this=0x7f80b6b4b0, aRepaint=<optimized out>) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:395 #6 0x0000007fbcaa5950 in mozilla::embedlite::EmbedLiteWindowChild:: CreateWidget (this=0x7f80b73670) at mobile/sailfishos/embedshared/EmbedLiteWindowChild.cpp:198 #7 0x0000007fbca95474 in mozilla::detail::RunnableMethodArguments<>:: applyImpl<mozilla::embedlite::EmbedLiteWindowChild, void (mozilla:: embedlite::EmbedLiteWindowChild::*)()>(mozilla::embedlite:: EmbedLiteWindowChild*, void (mozilla::embedlite::EmbedLiteWindowChild::*)( ), mozilla::Tuple<>&, std::integer_sequence<unsigned long>) (args=..., m=<optimized out>, o=<optimized out>) at xpcom/threads/nsThreadUtils.h:1188 #8 mozilla::detail::RunnableMethodArguments<>::apply<mozilla::embedlite:: EmbedLiteWindowChild, void (mozilla::embedlite::EmbedLiteWindowChild::*)()> ( this=<optimized out>, m=<optimized out>, o=<optimized out>) at xpcom/threads/nsThreadUtils.h:1191 #9 mozilla::detail::RunnableMethodImpl<mozilla::embedlite:: EmbedLiteWindowChild*, void (mozilla::embedlite::EmbedLiteWindowChild::*)( ), true, (mozilla::RunnableKind)1>::Run (this=<optimized out>) at xpcom/ threads/nsThreadUtils.h:1237 (More stack frames follow...)As we can see, the creation happens in nsBaseWidget::CreateCompositor(). Interestingly on ESR 91 it's also being created in roughly the same place:
Thread 10 "GeckoWorkerThre" hit Breakpoint 2, nsBaseWidget:: CreateCompositor (this=this@entry=0x7fb8a426a0, aWidth=aWidth@entry=1080, aHeight=aHeight@entry=2520) at widget/nsBaseWidget.cpp:1415 1415 void nsBaseWidget::CreateCompositor(int aWidth, int aHeight) { (gdb) bt 10 #0 nsBaseWidget::CreateCompositor (this=this@entry=0x7fb8a426a0, aWidth=aWidth@entry=1080, aHeight=aHeight@entry=2520) at widget/nsBaseWidget.cpp:1415 #1 0x0000007ff4c58208 in mozilla::embedlite::nsWindow::CreateCompositor ( this=0x7fb8a426a0, aWidth=1080, aHeight=2520) at mobile/sailfishos/embedshared/nsWindow.cpp:159 #2 0x0000007ff4c572dc in mozilla::embedlite::nsWindow::CreateCompositor ( this=0x7fb8a426a0) at mobile/sailfishos/embedshared/nsWindow.cpp:152 #3 0x0000007ff4c5a100 in mozilla::embedlite::nsWindow::GetLayerManager ( this=0x7fb8a426a0, aShadowManager=<optimized out>, aBackendHint=<optimized out>, aPersistence=nsIWidget::LAYER_MANAGER_CURRENT) at mobile/sailfishos/embedshared/nsWindow.cpp:214 #4 0x0000007ff4c57d2c in nsIWidget::GetLayerManager (this=0x7fb8a426a0) at widget/nsIWidget.h:1303 #5 mozilla::embedlite::PuppetWidgetBase::Invalidate (this=0x7fb8a426a0, aRect=...) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:261 #6 0x0000007ff4c5c650 in mozilla::embedlite::PuppetWidgetBase::UpdateBounds ( this=0x7fb8a426a0, aRepaint=aRepaint@entry=true) at mobile/sailfishos/embedshared/PuppetWidgetBase.cpp:395 #7 0x0000007ff4c6583c in mozilla::embedlite::EmbedLiteWindowChild:: CreateWidget (this=0x7fb8b9c010) at xpcom/base/nsCOMPtr.h:851 #8 0x0000007ff4c55da8 in mozilla::detail::RunnableMethodArguments<>:: applyImpl<mozilla::embedlite::EmbedLiteWindowChild, void (mozilla:: embedlite::EmbedLiteWindowChild::*)()>(mozilla::embedlite:: EmbedLiteWindowChild*, void (mozilla::embedlite::EmbedLiteWindowChild::*)( ), mozilla::Tuple<>&, std::integer_sequence<unsigned long>) (args=..., m=<optimized out>, o=<optimized out>) at ${PROJECT}/obj-build-mer-qt-xr/dist/include/nsThreadUtils.h:1151 #9 mozilla::detail::RunnableMethodArguments<>::apply<mozilla::embedlite:: EmbedLiteWindowChild, void (mozilla::embedlite::EmbedLiteWindowChild::*)()> ( m=<optimized out>, o=<optimized out>, this=<optimized out>) at ${PROJECT}/obj-build-mer-qt-xr/dist/include/nsThreadUtils.h:1154 (More stack frames follow...)I say "roughly" because the stack trace isn't identical. The call to nsWindow::CreateCompositor() only happens on ESR 91, which is unexpected. The actual difference is happening inside nsWindow::GetLayerManager(). The code is similar on both, and where they end up in nsBaseWidget::CreateCompositor() is the same, but for some reason the backtrace on ESR 91 is including the two hops needed to get there, whereas they're being skipped in the ESR 78 backtrace. In both cases the call in nsWindow::GetLayerManager() is to CreateCompositor():
void nsWindow::CreateCompositor() { LOGT(); // Compositor should be created only for top level widgets, aka windows. MOZ_ASSERT(mWindow); LayoutDeviceIntRect size = mWindow->GetSize(); CreateCompositor(size.width, size.height); } void nsWindow::CreateCompositor(int aWidth, int aHeight) { LOGT(); nsBaseWidget::CreateCompositor(aWidth, aHeight); }I'll need to look in to this further, but it looks to me like this might just be a case of optimisation in the ESR 78 code. Unfortunately I've run out of time and energy for today, so I'll have to continue the investigation tomorrow.
If you'd like to read any of my other gecko diary entries, they're all available on my Gecko-dev Diary page.
Comments
Uncover Disqus comments