From 16e78d9ec455ee691a7eb47d0939494f5d277481 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 13 Apr 2017 20:27:52 -0700 Subject: [PATCH 01/19] Accumulate event region items into painted layers. (bug 1147538, r=mstange) If a painted layer would previously only contain an event regions item, we would not associate that item with any cached layer. As a result we would generate a new, empty, invisible painted layer each frame. This is disastrous on large layer trees as it can cause many needless repositions. Instead, we make sure to accumulate the invisible item. --- layout/painting/FrameLayerBuilder.cpp | 29 +++++++++++++-------------- layout/painting/nsDisplayList.cpp | 6 ++++++ layout/painting/nsDisplayList.h | 1 + 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/layout/painting/FrameLayerBuilder.cpp b/layout/painting/FrameLayerBuilder.cpp index 15a7d1a99229..37380f829784 100644 --- a/layout/painting/FrameLayerBuilder.cpp +++ b/layout/painting/FrameLayerBuilder.cpp @@ -3208,8 +3208,6 @@ void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueB } for (auto& item : data->mAssignedDisplayItems) { - MOZ_ASSERT(item.mItem->GetType() != nsDisplayItem::TYPE_LAYER_EVENT_REGIONS); - InvalidateForLayerChange(item.mItem, data->mLayer); mLayerBuilder->AddPaintedDisplayItem(data, item.mItem, item.mClip, *this, item.mLayerState, @@ -4467,6 +4465,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) topLeft); }); + nsIntRegion opaquePixels; if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) { nsDisplayLayerEventRegions* eventRegions = static_cast(item); @@ -4477,26 +4476,26 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) if (mManager->IsWidgetLayerManager()) { paintedLayerData->UpdateCommonClipCount(itemClip); } - nsIntRegion opaquePixels = ComputeOpaqueRect(item, + opaquePixels = ComputeOpaqueRect(item, animatedGeometryRoot, itemClip, aList, &paintedLayerData->mHideAllLayersBelow, &paintedLayerData->mOpaqueForAnimatedGeometryRootParent); MOZ_ASSERT(nsIntRegion(itemDrawRect).Contains(opaquePixels)); opaquePixels.AndWith(itemVisibleRect); - paintedLayerData->Accumulate(this, item, opaquePixels, - itemVisibleRect, itemClip, layerState); + } - if (!paintedLayerData->mLayer) { - // Try to recycle the old layer of this display item. - RefPtr layer = - AttemptToRecyclePaintedLayer(animatedGeometryRoot, item, topLeft); - if (layer) { - paintedLayerData->mLayer = layer; + paintedLayerData->Accumulate(this, item, opaquePixels, + itemVisibleRect, itemClip, layerState); + if (!paintedLayerData->mLayer) { + // Try to recycle the old layer of this display item. + RefPtr layer = + AttemptToRecyclePaintedLayer(animatedGeometryRoot, item, topLeft); + if (layer) { + paintedLayerData->mLayer = layer; - NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0, - "Layer already in list???"); - mNewChildLayers[paintedLayerData->mNewChildLayersIndex].mLayer = layer.forget(); - } + NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0, + "Layer already in list???"); + mNewChildLayers[paintedLayerData->mNewChildLayersIndex].mLayer = layer.forget(); } } } diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 0a6e4cc0965f..368542cba201 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -4444,6 +4444,12 @@ nsDisplayLayerEventRegions::WriteDebugInfo(std::stringstream& aStream) } } +mozilla::Maybe +nsDisplayLayerEventRegions::IsUniform(nsDisplayListBuilder* aBuilder) +{ + return Some(NS_RGBA(0,0,0,0)); +} + nsDisplayCaret::nsDisplayCaret(nsDisplayListBuilder* aBuilder, nsIFrame* aCaretFrame) : nsDisplayItem(aBuilder, aCaretFrame) diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h index 3f54402784f8..bbe0a8bf4f18 100644 --- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -3568,6 +3568,7 @@ public: { return true; } + virtual mozilla::Maybe IsUniform(nsDisplayListBuilder* aBuilder) override; NS_DISPLAY_DECL_NAME("LayerEventRegions", TYPE_LAYER_EVENT_REGIONS) From bc9324f621977387a410429b3525ee6fd55609bd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 13 Apr 2017 21:25:16 -0700 Subject: [PATCH 02/19] Make finer-grained decisions about whether to update hit testing trees. (bug 1352918, r=kats) Updating hit testing trees is very expensive for many layers, and often layer properties that change don't necessitate hit testing tree updates. While layer tree structure changes do, we can be smarter about individual layer attributes. --- gfx/layers/LayerAttributes.h | 21 +++++++ gfx/layers/apz/src/APZCTreeManager.cpp | 6 ++ gfx/layers/ipc/LayerTransactionParent.cpp | 71 ++++++++++++++--------- gfx/layers/ipc/LayerTransactionParent.h | 12 +++- 4 files changed, 83 insertions(+), 27 deletions(-) diff --git a/gfx/layers/LayerAttributes.h b/gfx/layers/LayerAttributes.h index 39d42e42176e..7e5c2844d6b5 100644 --- a/gfx/layers/LayerAttributes.h +++ b/gfx/layers/LayerAttributes.h @@ -170,6 +170,27 @@ public: return true; } + // This returns true if scrolling info is equivalent for the purposes of + // APZ hit testing. + bool HitTestingInfoIsEqual(const SimpleLayerAttributes& aOther) const { + if (mIsScrollbarContainer != aOther.mIsScrollbarContainer) { + return false; + } + if (mScrollbarTargetContainerId != aOther.mScrollbarTargetContainerId) { + return false; + } + if (mScrollbarDirection != aOther.mScrollbarDirection) { + return false; + } + if (FixedPositionScrollContainerId() != aOther.FixedPositionScrollContainerId()) { + return false; + } + if (mTransform != aOther.mTransform) { + return false; + } + return true; + } + // // Getters. // diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index b63bdf56eb9c..58299cf2fb4a 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -480,6 +480,9 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer, RefPtr node = nullptr; if (!needsApzc) { + // Note: if layer properties must be propagated to nodes, RecvUpdate in + // LayerTransactionParent.cpp must ensure that APZ will be notified + // when those properties change. node = RecycleOrCreateNode(aState, nullptr, aLayersId); AttachNodeToTree(node, aParent, aNextSibling); node->SetHitTestData( @@ -674,6 +677,9 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer, GetEventRegionsOverride(aParent, aLayer)); } + // Note: if layer properties must be propagated to nodes, RecvUpdate in + // LayerTransactionParent.cpp must ensure that APZ will be notified + // when those properties change. node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(), aLayer.GetScrollbarDirection(), aLayer.GetScrollThumbLength(), diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index 84d05e895c87..8cd47659ac14 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -172,8 +172,8 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) layer_manager()->BeginTransaction(); } - // not all edits require an update to the hit testing tree - bool updateHitTestingTree = false; + // Not all edits require an update to the hit testing tree. + mUpdateHitTestingTree = false; for (EditArray::index_type i = 0; i < aInfo.cset().Length(); ++i) { const Edit& edit = const_cast(aInfo.cset()[i]); @@ -188,7 +188,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "CreatePaintedLayer"); break; } case Edit::TOpCreateContainerLayer: { @@ -199,7 +199,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "CreateContainerLayer"); break; } case Edit::TOpCreateImageLayer: { @@ -210,7 +210,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "CreateImageLayer"); break; } case Edit::TOpCreateColorLayer: { @@ -221,7 +221,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "CreateColorLayer"); break; } case Edit::TOpCreateTextLayer: { @@ -232,18 +232,18 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "CreateTextLayer"); break; } case Edit::TOpCreateBorderLayer: { - MOZ_LAYERS_LOG(("[ParentSide] CreateTextLayer")); + MOZ_LAYERS_LOG(("[ParentSide] CreateBorderLayer")); RefPtr layer = layer_manager()->CreateBorderLayer(); if (!BindLayer(layer, edit.get_OpCreateBorderLayer())) { return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "CreateBorderLayer"); break; } case Edit::TOpCreateCanvasLayer: { @@ -254,7 +254,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "CreateCanvasLayer"); break; } case Edit::TOpCreateRefLayer: { @@ -265,7 +265,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "CreateRefLayer"); break; } case Edit::TOpSetDiagnosticTypes: { @@ -291,7 +291,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) } mRoot = newRoot; - updateHitTestingTree = true; + UpdateHitTestingTree(mRoot, "SetRoot"); break; } case Edit::TOpInsertAfter: { @@ -309,7 +309,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "InsertAfter"); break; } case Edit::TOpPrependChild: { @@ -326,7 +326,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "PrependChild"); break; } case Edit::TOpRemoveChild: { @@ -343,7 +343,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "RemoveChild"); break; } case Edit::TOpRepositionChild: { @@ -361,7 +361,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "RepositionChild"); break; } case Edit::TOpRaiseToTopChild: { @@ -381,7 +381,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; + UpdateHitTestingTree(layer, "RaiseToTopChild"); break; } case Edit::TCompositableOperation: { @@ -446,8 +446,12 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) if (!layer) { return IPC_FAIL_NO_REASON(this); } + const SimpleLayerAttributes& attrs = op.attrs(); + const SimpleLayerAttributes& orig = layer->GetSimpleAttributes(); + if (!attrs.HitTestingInfoIsEqual(orig)) { + UpdateHitTestingTree(layer, "scrolling info changed"); + } layer->SetSimpleAttributes(op.attrs()); - updateHitTestingTree = true; } // Process attribute updates. @@ -456,7 +460,6 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) if (!SetLayerAttributes(op)) { return IPC_FAIL_NO_REASON(this); } - updateHitTestingTree = true; } // Process paints separately, after all normal edits. @@ -466,7 +469,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) } } - mCompositorBridge->ShadowLayersUpdated(this, aInfo, updateHitTestingTree); + mCompositorBridge->ShadowLayersUpdated(this, aInfo, mUpdateHitTestingTree); { AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this)); @@ -521,16 +524,29 @@ LayerTransactionParent::SetLayerAttributes(const OpSetLayerAttributes& aOp) const LayerAttributes& attrs = aOp.attrs(); const CommonLayerAttributes& common = attrs.common(); - layer->SetVisibleRegion(common.visibleRegion()); - layer->SetEventRegions(common.eventRegions()); - layer->SetClipRect(common.useClipRect() ? Some(common.clipRect()) : Nothing()); + if (common.visibleRegion() != layer->GetVisibleRegion()) { + UpdateHitTestingTree(layer, "visible region changed"); + layer->SetVisibleRegion(common.visibleRegion()); + } + if (common.eventRegions() != layer->GetEventRegions()) { + UpdateHitTestingTree(layer, "event regions changed"); + layer->SetEventRegions(common.eventRegions()); + } + Maybe clipRect = common.useClipRect() ? Some(common.clipRect()) : Nothing(); + if (clipRect != layer->GetClipRect()) { + UpdateHitTestingTree(layer, "clip rect changed"); + layer->SetClipRect(clipRect); + } if (LayerHandle maskLayer = common.maskLayer()) { layer->SetMaskLayer(AsLayer(maskLayer)); } else { layer->SetMaskLayer(nullptr); } layer->SetCompositorAnimations(common.compositorAnimations()); - layer->SetScrollMetadata(common.scrollMetadata()); + if (common.scrollMetadata() != layer->GetAllScrollMetadata()) { + UpdateHitTestingTree(layer, "scroll metadata changed"); + layer->SetScrollMetadata(common.scrollMetadata()); + } layer->SetDisplayListLog(common.displayListLog().get()); // The updated invalid region is added to the existing one, since we can @@ -579,8 +595,10 @@ LayerTransactionParent::SetLayerAttributes(const OpSetLayerAttributes& aOp) containerLayer->SetInheritedScale(attrs.inheritedXScale(), attrs.inheritedYScale()); containerLayer->SetScaleToResolution(attrs.scaleToResolution(), attrs.presShellResolution()); - containerLayer->SetEventRegionsOverride(attrs.eventRegionsOverride()); - + if (attrs.eventRegionsOverride() != containerLayer->GetEventRegionsOverride()) { + UpdateHitTestingTree(layer, "event regions override changed"); + containerLayer->SetEventRegionsOverride(attrs.eventRegionsOverride()); + } break; } case Specific::TColorLayerAttributes: { @@ -640,6 +658,7 @@ LayerTransactionParent::SetLayerAttributes(const OpSetLayerAttributes& aOp) } refLayer->SetReferentId(specific.get_RefLayerAttributes().id()); refLayer->SetEventRegionsOverride(specific.get_RefLayerAttributes().eventRegionsOverride()); + UpdateHitTestingTree(layer, "event regions override changed"); break; } case Specific::TImageLayerAttributes: { diff --git a/gfx/layers/ipc/LayerTransactionParent.h b/gfx/layers/ipc/LayerTransactionParent.h index cab86de6a707..8409a8332aa3 100644 --- a/gfx/layers/ipc/LayerTransactionParent.h +++ b/gfx/layers/ipc/LayerTransactionParent.h @@ -171,6 +171,13 @@ protected: friend class CrossProcessCompositorBridgeParent; friend class layout::RenderFrameParent; +private: + // This is a function so we can log or breakpoint on why hit + // testing tree changes are made. + void UpdateHitTestingTree(Layer* aLayer, const char* aWhy) { + mUpdateHitTestingTree = true; + } + private: RefPtr mLayerManager; CompositorBridgeParentBase* mCompositorBridge; @@ -216,8 +223,11 @@ private: // transactions posted by the child. bool mDestroyed; - bool mIPCOpen; + + // This is set during RecvUpdate to track whether we'll need to update + // APZ's hit test regions. + bool mUpdateHitTestingTree; }; } // namespace layers From c9721c0a3b46a2833ad58df126c6723404b02b96 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Thu, 13 Apr 2017 16:57:33 -0600 Subject: [PATCH 03/19] Bug 1322532: Add support for live regions to the com handler dll; r=tbsaunde MozReview-Commit-ID: 1JPaUw5PrxU --HG-- extra : rebase_source : eef53f27be2d431c8b86c90e0681af9fb29c7d90 --- .../ipc/win/handler/AccessibleHandler.cpp | 7 + .../win/handler/AccessibleHandlerControl.cpp | 163 ++++++-- .../win/handler/AccessibleHandlerControl.h | 43 ++- .../ipc/win/handler/AccessibleTextTearoff.cpp | 359 ++++++++++++++++++ .../ipc/win/handler/AccessibleTextTearoff.h | 88 +++++ accessible/ipc/win/handler/HandlerData.idl | 5 + accessible/ipc/win/handler/moz.build | 1 + 7 files changed, 627 insertions(+), 39 deletions(-) create mode 100644 accessible/ipc/win/handler/AccessibleTextTearoff.cpp create mode 100644 accessible/ipc/win/handler/AccessibleTextTearoff.h diff --git a/accessible/ipc/win/handler/AccessibleHandler.cpp b/accessible/ipc/win/handler/AccessibleHandler.cpp index 6de902f6bab2..ee2e53171c51 100644 --- a/accessible/ipc/win/handler/AccessibleHandler.cpp +++ b/accessible/ipc/win/handler/AccessibleHandler.cpp @@ -12,6 +12,7 @@ #include "AccessibleHandler.h" #include "AccessibleHandlerControl.h" +#include "AccessibleTextTearoff.h" #include "Factory.h" #include "HandlerData.h" @@ -183,6 +184,12 @@ AccessibleHandler::QueryHandlerInterface(IUnknown* aProxyUnknown, REFIID aIid, return S_OK; } + if (aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext) { + RefPtr textTearoff(new AccessibleTextTearoff(this)); + textTearoff.forget(aOutInterface); + return S_OK; + } + if (aIid == IID_IProvideClassInfo) { RefPtr clsInfo(this); clsInfo.forget(aOutInterface); diff --git a/accessible/ipc/win/handler/AccessibleHandlerControl.cpp b/accessible/ipc/win/handler/AccessibleHandlerControl.cpp index 4f9e27fcfcab..278ceac7fdd4 100644 --- a/accessible/ipc/win/handler/AccessibleHandlerControl.cpp +++ b/accessible/ipc/win/handler/AccessibleHandlerControl.cpp @@ -22,6 +22,103 @@ namespace a11y { mscom::SingletonFactory gControlFactory; +namespace detail { + +TextChange::TextChange() + : mIA2UniqueId(0) + , mIsInsert(false) + , mText() +{ +} + +TextChange::TextChange(long aIA2UniqueId, bool aIsInsert, + NotNull aText) + : mIA2UniqueId(aIA2UniqueId) + , mIsInsert(aIsInsert) + , mText{BSTRCopy(aText->text), aText->start, aText->end} +{ +} + +TextChange::TextChange(TextChange&& aOther) + : mText() +{ + *this = Move(aOther); +} + +TextChange::TextChange(const TextChange& aOther) + : mText() +{ + *this = aOther; +} + +TextChange& +TextChange::operator=(TextChange&& aOther) +{ + mIA2UniqueId = aOther.mIA2UniqueId; + mIsInsert = aOther.mIsInsert; + aOther.mIA2UniqueId = 0; + ::SysFreeString(mText.text); + mText = aOther.mText; + aOther.mText.text = nullptr; + return *this; +} + +TextChange& +TextChange::operator=(const TextChange& aOther) +{ + mIA2UniqueId = aOther.mIA2UniqueId; + mIsInsert = aOther.mIsInsert; + ::SysFreeString(mText.text); + mText = {BSTRCopy(aOther.mText.text), aOther.mText.start, aOther.mText.end}; + return *this; +} + +TextChange::~TextChange() +{ + ::SysFreeString(mText.text); +} + +HRESULT +TextChange::GetOld(long aIA2UniqueId, NotNull aOutOldSegment) +{ + if (mIsInsert || aIA2UniqueId != mIA2UniqueId) { + return S_OK; + } + + return SegCopy(*aOutOldSegment, mText); +} + +HRESULT +TextChange::GetNew(long aIA2UniqueId, NotNull aOutNewSegment) +{ + if (!mIsInsert || aIA2UniqueId != mIA2UniqueId) { + return S_OK; + } + + return SegCopy(*aOutNewSegment, mText); +} + +/* static */ BSTR +TextChange::BSTRCopy(const BSTR& aIn) +{ + return ::SysAllocStringLen(aIn, ::SysStringLen(aIn)); +} + +/* static */ HRESULT +TextChange::SegCopy(IA2TextSegment& aDest, const IA2TextSegment& aSrc) +{ + aDest = {BSTRCopy(aSrc.text), aSrc.start, aSrc.end}; + if (aSrc.text && !aDest.text) { + return E_OUTOFMEMORY; + } + if (!::SysStringLen(aDest.text)) { + return S_FALSE; + } + return S_OK; +} + +} // namespace detail + HRESULT AccessibleHandlerControl::Create(AccessibleHandlerControl** aOutObject) { @@ -35,46 +132,14 @@ AccessibleHandlerControl::Create(AccessibleHandlerControl** aOutObject) } AccessibleHandlerControl::AccessibleHandlerControl() - : mRefCnt(0) - , mCacheGen(0) + : mCacheGen(0) , mIA2Proxy(mscom::RegisterProxy(L"ia2marshal.dll")) , mHandlerProxy(mscom::RegisterProxy()) { MOZ_ASSERT(mIA2Proxy); } -HRESULT -AccessibleHandlerControl::QueryInterface(REFIID aIid, void** aOutInterface) -{ - if (!aOutInterface) { - return E_INVALIDARG; - } - - if (aIid == IID_IUnknown || aIid == IID_IHandlerControl) { - RefPtr ctl(this); - ctl.forget(aOutInterface); - return S_OK; - } - - *aOutInterface = nullptr; - return E_NOINTERFACE; -} - -ULONG -AccessibleHandlerControl::AddRef() -{ - return ++mRefCnt; -} - -ULONG -AccessibleHandlerControl::Release() -{ - ULONG result = --mRefCnt; - if (!result) { - delete this; - } - return result; -} +IMPL_IUNKNOWN1(AccessibleHandlerControl, IHandlerControl) HRESULT AccessibleHandlerControl::Invalidate() @@ -83,6 +148,36 @@ AccessibleHandlerControl::Invalidate() return S_OK; } +HRESULT +AccessibleHandlerControl::OnTextChange(long aHwnd, long aIA2UniqueId, + VARIANT_BOOL aIsInsert, + IA2TextSegment* aText) +{ + if (!aText) { + return E_INVALIDARG; + } + + mTextChange = detail::TextChange(aIA2UniqueId, aIsInsert, WrapNotNull(aText)); + NotifyWinEvent(aIsInsert ? IA2_EVENT_TEXT_INSERTED : IA2_EVENT_TEXT_REMOVED, + reinterpret_cast(static_cast(aHwnd)), + OBJID_CLIENT, aIA2UniqueId); + return S_OK; +} + +HRESULT +AccessibleHandlerControl::GetNewText(long aIA2UniqueId, + NotNull aOutNewText) +{ + return mTextChange.GetNew(aIA2UniqueId, aOutNewText); +} + +HRESULT +AccessibleHandlerControl::GetOldText(long aIA2UniqueId, + NotNull aOutOldText) +{ + return mTextChange.GetOld(aIA2UniqueId, aOutOldText); +} + HRESULT AccessibleHandlerControl::GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo) { diff --git a/accessible/ipc/win/handler/AccessibleHandlerControl.h b/accessible/ipc/win/handler/AccessibleHandlerControl.h index 3c4b26d80efd..af29c8445d6c 100644 --- a/accessible/ipc/win/handler/AccessibleHandlerControl.h +++ b/accessible/ipc/win/handler/AccessibleHandlerControl.h @@ -13,37 +13,70 @@ #include "Factory.h" #include "HandlerData.h" +#include "IUnknownImpl.h" #include "mozilla/mscom/Registration.h" +#include "mozilla/NotNull.h" namespace mozilla { namespace a11y { +namespace detail { + +class TextChange final +{ +public: + TextChange(); + TextChange(long aIA2UniqueId, bool aIsInsert, NotNull aText); + TextChange(TextChange&& aOther); + TextChange(const TextChange& aOther); + + TextChange& operator=(TextChange&& aOther); + TextChange& operator=(const TextChange& aOther); + + ~TextChange(); + + HRESULT GetOld(long aIA2UniqueId, NotNull aOutOldSegment); + HRESULT GetNew(long aIA2UniqueId, NotNull aOutNewSegment); + +private: + static BSTR BSTRCopy(const BSTR& aIn); + static HRESULT SegCopy(IA2TextSegment& aDest, const IA2TextSegment& aSrc); + + long mIA2UniqueId; + bool mIsInsert; + IA2TextSegment mText; +}; + +} // namespace detail + class AccessibleHandlerControl final : public IHandlerControl { public: static HRESULT Create(AccessibleHandlerControl** aOutObject); - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override; - STDMETHODIMP_(ULONG) AddRef() override; - STDMETHODIMP_(ULONG) Release() override; + DECL_IUNKNOWN // IHandlerControl STDMETHODIMP Invalidate() override; + STDMETHODIMP OnTextChange(long aHwnd, long aIA2UniqueId, + VARIANT_BOOL aIsInsert, IA2TextSegment* aText) override; uint32_t GetCacheGen() const { return mCacheGen; } + HRESULT GetNewText(long aIA2UniqueId, NotNull aOutNewText); + HRESULT GetOldText(long aIA2UniqueId, NotNull aOutOldText); + HRESULT GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo); private: AccessibleHandlerControl(); ~AccessibleHandlerControl() = default; - ULONG mRefCnt; uint32_t mCacheGen; + detail::TextChange mTextChange; UniquePtr mIA2Proxy; UniquePtr mHandlerProxy; }; diff --git a/accessible/ipc/win/handler/AccessibleTextTearoff.cpp b/accessible/ipc/win/handler/AccessibleTextTearoff.cpp new file mode 100644 index 000000000000..2682a2795049 --- /dev/null +++ b/accessible/ipc/win/handler/AccessibleTextTearoff.cpp @@ -0,0 +1,359 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if defined(MOZILLA_INTERNAL_API) +#error This code is NOT for internal Gecko use! +#endif // defined(MOZILLA_INTERNAL_API) + +#include "AccessibleTextTearoff.h" + +#include "AccessibleHandlerControl.h" +#include "AccessibleText_i.c" +#include "AccessibleHypertext_i.c" +#include "Factory.h" + +#include "mozilla/Assertions.h" + +namespace mozilla { +namespace a11y { + +AccessibleTextTearoff::AccessibleTextTearoff(AccessibleHandler* aHandler) + : mHandler(aHandler) +{ + MOZ_ASSERT(aHandler); +} + +HRESULT +AccessibleTextTearoff::ResolveAccText() +{ + if (mAccTextProxy) { + return S_OK; + } + + RefPtr proxy(mHandler->GetProxy()); + if (!proxy) { + return E_UNEXPECTED; + } + + return proxy->QueryInterface(IID_IAccessibleText, + getter_AddRefs(mAccTextProxy)); +} + +HRESULT +AccessibleTextTearoff::ResolveAccHypertext() +{ + if (mAccHypertextProxy) { + return S_OK; + } + + RefPtr proxy(mHandler->GetProxy()); + if (!proxy) { + return E_UNEXPECTED; + } + + return proxy->QueryInterface(IID_IAccessibleHypertext, + getter_AddRefs(mAccHypertextProxy)); +} + +IMPL_IUNKNOWN_QUERY_HEAD(AccessibleTextTearoff) +IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleText) +IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleHypertext) +IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mHandler) + +HRESULT +AccessibleTextTearoff::addSelection(long startOffset, long endOffset) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->addSelection(startOffset, endOffset); +} + +HRESULT +AccessibleTextTearoff::get_attributes(long offset, long *startOffset, + long *endOffset, BSTR *textAttributes) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->get_attributes(offset, startOffset, endOffset, + textAttributes); +} + +HRESULT +AccessibleTextTearoff::get_caretOffset(long *offset) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->get_caretOffset(offset); +} + +HRESULT +AccessibleTextTearoff::get_characterExtents(long offset, + enum IA2CoordinateType coordType, + long *x, long *y, long *width, + long *height) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->get_characterExtents(offset, coordType, x, y, width, + height); +} + +HRESULT +AccessibleTextTearoff::get_nSelections(long *nSelections) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->get_nSelections(nSelections); +} + +HRESULT +AccessibleTextTearoff::get_offsetAtPoint(long x, long y, + enum IA2CoordinateType coordType, + long *offset) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->get_offsetAtPoint(x, y, coordType, offset); +} + +HRESULT +AccessibleTextTearoff::get_selection(long selectionIndex, long *startOffset, + long *endOffset) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->get_selection(selectionIndex, startOffset, endOffset); +} + +HRESULT +AccessibleTextTearoff::get_text(long startOffset, long endOffset, BSTR *text) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->get_text(startOffset, endOffset, text); +} + +HRESULT +AccessibleTextTearoff::get_textBeforeOffset(long offset, + enum IA2TextBoundaryType boundaryType, + long *startOffset, long *endOffset, + BSTR *text) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->get_textBeforeOffset(offset, boundaryType, startOffset, + endOffset, text); +} + +HRESULT +AccessibleTextTearoff::get_textAfterOffset(long offset, + enum IA2TextBoundaryType boundaryType, + long *startOffset, long *endOffset, + BSTR *text) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->get_textAfterOffset(offset, boundaryType, + startOffset, endOffset, text); +} + +HRESULT +AccessibleTextTearoff::get_textAtOffset(long offset, + enum IA2TextBoundaryType boundaryType, + long *startOffset, long *endOffset, + BSTR *text) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->get_textAtOffset(offset, boundaryType, startOffset, + endOffset, text); +} + +HRESULT +AccessibleTextTearoff::removeSelection(long selectionIndex) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->removeSelection(selectionIndex); +} + +HRESULT +AccessibleTextTearoff::setCaretOffset(long offset) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->setCaretOffset(offset); +} + +HRESULT +AccessibleTextTearoff::setSelection(long selectionIndex, long startOffset, + long endOffset) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->setSelection(selectionIndex, startOffset, endOffset); +} + +HRESULT +AccessibleTextTearoff::get_nCharacters(long *nCharacters) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->get_nCharacters(nCharacters); +} + +HRESULT +AccessibleTextTearoff::scrollSubstringTo(long startIndex, long endIndex, + enum IA2ScrollType scrollType) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->scrollSubstringTo(startIndex, endIndex, scrollType); +} + +HRESULT +AccessibleTextTearoff::scrollSubstringToPoint(long startIndex, long endIndex, + enum IA2CoordinateType coordinateType, + long x, long y) +{ + HRESULT hr = ResolveAccText(); + if (FAILED(hr)) { + return hr; + } + + return mAccTextProxy->scrollSubstringToPoint(startIndex, endIndex, + coordinateType, x, y); +} + +HRESULT +AccessibleTextTearoff::get_newText(IA2TextSegment *newText) +{ + if (!newText) { + return E_INVALIDARG; + } + + RefPtr ctl(gControlFactory.GetSingleton()); + MOZ_ASSERT(ctl); + if (!ctl) { + return S_OK; + } + + long id; + HRESULT hr = mHandler->get_uniqueID(&id); + if (FAILED(hr)) { + return hr; + } + + return ctl->GetNewText(id, WrapNotNull(newText)); +} + +HRESULT +AccessibleTextTearoff::get_oldText(IA2TextSegment *oldText) +{ + if (!oldText) { + return E_INVALIDARG; + } + + RefPtr ctl(gControlFactory.GetSingleton()); + MOZ_ASSERT(ctl); + if (!ctl) { + return S_OK; + } + + long id; + HRESULT hr = mHandler->get_uniqueID(&id); + if (FAILED(hr)) { + return hr; + } + + return ctl->GetOldText(id, WrapNotNull(oldText)); +} + +HRESULT +AccessibleTextTearoff::get_nHyperlinks(long *hyperlinkCount) +{ + HRESULT hr = ResolveAccHypertext(); + if (FAILED(hr)) { + return hr; + } + + return mAccHypertextProxy->get_nHyperlinks(hyperlinkCount); +} + +HRESULT +AccessibleTextTearoff::get_hyperlink(long index, + IAccessibleHyperlink **hyperlink) +{ + HRESULT hr = ResolveAccHypertext(); + if (FAILED(hr)) { + return hr; + } + + return mAccHypertextProxy->get_hyperlink(index, hyperlink); +} + +HRESULT +AccessibleTextTearoff::get_hyperlinkIndex(long charIndex, long *hyperlinkIndex) +{ + HRESULT hr = ResolveAccHypertext(); + if (FAILED(hr)) { + return hr; + } + + return mAccHypertextProxy->get_hyperlinkIndex(charIndex, hyperlinkIndex); +} + + +} // namespace a11y +} // namespace mozilla diff --git a/accessible/ipc/win/handler/AccessibleTextTearoff.h b/accessible/ipc/win/handler/AccessibleTextTearoff.h new file mode 100644 index 000000000000..8568f3c70653 --- /dev/null +++ b/accessible/ipc/win/handler/AccessibleTextTearoff.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if defined(MOZILLA_INTERNAL_API) +#error This code is NOT for internal Gecko use! +#endif // defined(MOZILLA_INTERNAL_API) + +#ifndef mozilla_a11y_AccessibleTextTearoff_h +#define mozilla_a11y_AccessibleTextTearoff_h + +#include "AccessibleHandler.h" +#include "AccessibleHypertext.h" +#include "IUnknownImpl.h" +#include "mozilla/RefPtr.h" + +namespace mozilla { +namespace a11y { + +class AccessibleTextTearoff final : public IAccessibleHypertext +{ +public: + explicit AccessibleTextTearoff(AccessibleHandler* aHandler); + + DECL_IUNKNOWN + + // IAccessibleText + STDMETHODIMP addSelection(long startOffset, long endOffset) override; + STDMETHODIMP get_attributes(long offset, long *startOffset, long *endOffset, + BSTR *textAttributes) override; + STDMETHODIMP get_caretOffset(long *offset) override; + STDMETHODIMP get_characterExtents(long offset, + enum IA2CoordinateType coordType, long *x, + long *y, long *width, long *height) override; + STDMETHODIMP get_nSelections(long *nSelections) override; + STDMETHODIMP get_offsetAtPoint(long x, long y, + enum IA2CoordinateType coordType, + long *offset) override; + STDMETHODIMP get_selection(long selectionIndex, long *startOffset, + long *endOffset) override; + STDMETHODIMP get_text(long startOffset, long endOffset, BSTR *text) override; + STDMETHODIMP get_textBeforeOffset(long offset, + enum IA2TextBoundaryType boundaryType, + long *startOffset, long *endOffset, + BSTR *text) override; + STDMETHODIMP get_textAfterOffset(long offset, + enum IA2TextBoundaryType boundaryType, + long *startOffset, long *endOffset, + BSTR *text) override; + STDMETHODIMP get_textAtOffset(long offset, + enum IA2TextBoundaryType boundaryType, + long *startOffset, long *endOffset, + BSTR *text) override; + STDMETHODIMP removeSelection(long selectionIndex) override; + STDMETHODIMP setCaretOffset(long offset) override; + STDMETHODIMP setSelection(long selectionIndex, long startOffset, + long endOffset) override; + STDMETHODIMP get_nCharacters(long *nCharacters) override; + STDMETHODIMP scrollSubstringTo(long startIndex, long endIndex, + enum IA2ScrollType scrollType) override; + STDMETHODIMP scrollSubstringToPoint(long startIndex, long endIndex, + enum IA2CoordinateType coordinateType, + long x, long y) override; + STDMETHODIMP get_newText(IA2TextSegment *newText) override; + STDMETHODIMP get_oldText(IA2TextSegment *oldText) override; + + // IAccessibleHypertext + STDMETHODIMP get_nHyperlinks(long *hyperlinkCount) override; + STDMETHODIMP get_hyperlink(long index, + IAccessibleHyperlink **hyperlink) override; + STDMETHODIMP get_hyperlinkIndex(long charIndex, long *hyperlinkIndex) override; + +private: + ~AccessibleTextTearoff() = default; + HRESULT ResolveAccText(); + HRESULT ResolveAccHypertext(); + + RefPtr mHandler; + RefPtr mAccTextProxy; + RefPtr mAccHypertextProxy; +}; + +} // namespace a11y +} // namespace mozilla + +#endif // mozilla_a11y_AccessibleTextTearoff_h diff --git a/accessible/ipc/win/handler/HandlerData.idl b/accessible/ipc/win/handler/HandlerData.idl index 24279f14cc1e..cd07f19cd7af 100644 --- a/accessible/ipc/win/handler/HandlerData.idl +++ b/accessible/ipc/win/handler/HandlerData.idl @@ -9,6 +9,8 @@ import "ocidl.idl"; import "ServProv.idl"; +import "AccessibleText.idl"; + typedef struct _IA2Data { long mUniqueId; @@ -84,6 +86,9 @@ interface HandlerData interface IHandlerControl : IUnknown { HRESULT Invalidate(); + HRESULT OnTextChange([in] long aHwnd, [in] long aIA2UniqueId, + [in] VARIANT_BOOL aIsInsert, + [in] IA2TextSegment* aText); } [object, diff --git a/accessible/ipc/win/handler/moz.build b/accessible/ipc/win/handler/moz.build index b4fea56d725f..7879edc57210 100644 --- a/accessible/ipc/win/handler/moz.build +++ b/accessible/ipc/win/handler/moz.build @@ -20,6 +20,7 @@ SOURCES += [ '!HandlerData_p.c', 'AccessibleHandler.cpp', 'AccessibleHandlerControl.cpp', + 'AccessibleTextTearoff.cpp', ] GENERATED_FILES += [ From 68616ae61ee97a47dc455bb0be0ce5dbd779bfd1 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Tue, 21 Feb 2017 11:27:33 -0700 Subject: [PATCH 04/19] Bug 1322532: Move a11y retrieval of native window handle to DocAccessibleChild; r=yzen MozReview-Commit-ID: DwLBfAQJkRJ --HG-- extra : rebase_source : b206229f4167979d79c71e7cad11d01d7d60f9ed --- accessible/ipc/win/DocAccessibleChild.cpp | 12 ++++++++++++ accessible/ipc/win/DocAccessibleChild.h | 2 +- accessible/windows/msaa/DocAccessibleWrap.cpp | 13 +------------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/accessible/ipc/win/DocAccessibleChild.cpp b/accessible/ipc/win/DocAccessibleChild.cpp index 913bbe3b2d54..e932036acb67 100644 --- a/accessible/ipc/win/DocAccessibleChild.cpp +++ b/accessible/ipc/win/DocAccessibleChild.cpp @@ -77,6 +77,18 @@ DocAccessibleChild::RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandl return IPC_OK(); } +HWND +DocAccessibleChild::GetNativeWindowHandle() const +{ + if (mEmulatedWindowHandle) { + return mEmulatedWindowHandle; + } + + auto tab = static_cast(Manager()); + MOZ_ASSERT(tab); + return reinterpret_cast(tab->GetNativeWindowHandle()); +} + void DocAccessibleChild::PushDeferredEvent(UniquePtr aEvent) { diff --git a/accessible/ipc/win/DocAccessibleChild.h b/accessible/ipc/win/DocAccessibleChild.h index 6a82025b8ffd..c99a04542aac 100644 --- a/accessible/ipc/win/DocAccessibleChild.h +++ b/accessible/ipc/win/DocAccessibleChild.h @@ -33,7 +33,7 @@ public: RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandle, const IAccessibleHolder& aEmulatedWindowCOMProxy) override; - HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; } + HWND GetNativeWindowHandle() const; IAccessible* GetEmulatedWindowIAccessible() const { return mEmulatedWindowProxy.get(); } IAccessible* GetParentIAccessible() const { return mParentProxy.get(); } diff --git a/accessible/windows/msaa/DocAccessibleWrap.cpp b/accessible/windows/msaa/DocAccessibleWrap.cpp index 79e61b8809c9..9daad7617e9c 100644 --- a/accessible/windows/msaa/DocAccessibleWrap.cpp +++ b/accessible/windows/msaa/DocAccessibleWrap.cpp @@ -131,18 +131,7 @@ DocAccessibleWrap::GetNativeWindow() const return nullptr; } - HWND hWnd = ipcDoc->GetEmulatedWindowHandle(); - if (hWnd) { - return hWnd; - } - - auto tab = static_cast(ipcDoc->Manager()); - MOZ_ASSERT(tab); - if (!tab) { - return nullptr; - } - - return reinterpret_cast(tab->GetNativeWindowHandle()); + return ipcDoc->GetNativeWindowHandle(); } else if (mHWND) { return mHWND; } From 1de2299a3a7d00e622a2d2e77ac408c686e01f42 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Thu, 13 Apr 2017 17:08:42 -0600 Subject: [PATCH 05/19] Bug 1322532: Add sync text event to PDocAccessible; r=tbsaunde, r=billm MozReview-Commit-ID: AFZMYghoOHe --HG-- extra : rebase_source : 22939e1a1208501fa646c02ee8199b72a16e14b5 extra : histedit_source : fd408d3d96578bc23c8d6627248c0578563e9b7e --- accessible/ipc/win/PDocAccessible.ipdl | 2 ++ ipc/ipdl/sync-messages.ini | 3 +++ 2 files changed, 5 insertions(+) diff --git a/accessible/ipc/win/PDocAccessible.ipdl b/accessible/ipc/win/PDocAccessible.ipdl index 6b7e1b342c0c..08145cd494bb 100644 --- a/accessible/ipc/win/PDocAccessible.ipdl +++ b/accessible/ipc/win/PDocAccessible.ipdl @@ -53,6 +53,8 @@ parent: async CaretMoveEvent(uint64_t aID, int32_t aOffset); async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen, bool aIsInsert, bool aFromUser); + sync SyncTextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, + uint32_t aLen, bool aIsInsert, bool aFromUser); async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType); async RoleChangedEvent(uint32_t aRole); diff --git a/ipc/ipdl/sync-messages.ini b/ipc/ipdl/sync-messages.ini index c34253dc3040..6c05189e386a 100644 --- a/ipc/ipdl/sync-messages.ini +++ b/ipc/ipdl/sync-messages.ini @@ -594,6 +594,9 @@ platform = notwin [PDocAccessible::GetWindowedPluginIAccessible] description = platform = win +[PDocAccessible::SyncTextChangeEvent] +description = +platform = win # CPOWs [PBrowser::RpcMessage] From 0ee7073299a024a93d5ec794bb9abc72c28e3a59 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Thu, 13 Apr 2017 20:35:32 -0600 Subject: [PATCH 06/19] Bug 1322532: Platform a11y changes to enable handler-based live regions; r=tbsaunde MozReview-Commit-ID: nNPvBy3ZGO --HG-- extra : rebase_source : d8a797c9ddfb3d8ab4f13c9f2f261fba04320beb extra : histedit_source : cc4f0bd8ba26cc88bcf9907f684e5d6c240d354f --- accessible/ipc/DocAccessibleParent.cpp | 15 ++++++ accessible/ipc/DocAccessibleParent.h | 7 +++ accessible/ipc/win/DocAccessibleChild.cpp | 7 +++ accessible/windows/msaa/AccessibleWrap.cpp | 58 ++++++++++++++++++++++ accessible/windows/msaa/AccessibleWrap.h | 2 + accessible/windows/msaa/Platform.cpp | 8 +++ 6 files changed, 97 insertions(+) diff --git a/accessible/ipc/DocAccessibleParent.cpp b/accessible/ipc/DocAccessibleParent.cpp index 61204940e383..2746fe204fdd 100644 --- a/accessible/ipc/DocAccessibleParent.cpp +++ b/accessible/ipc/DocAccessibleParent.cpp @@ -338,6 +338,21 @@ DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID, return IPC_OK(); } +#if defined(XP_WIN) + +mozilla::ipc::IPCResult +DocAccessibleParent::RecvSyncTextChangeEvent(const uint64_t& aID, + const nsString& aStr, + const int32_t& aStart, + const uint32_t& aLen, + const bool& aIsInsert, + const bool& aFromUser) +{ + return RecvTextChangeEvent(aID, aStr, aStart, aLen, aIsInsert, aFromUser); +} + +#endif // defined(XP_WIN) + mozilla::ipc::IPCResult DocAccessibleParent::RecvSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID, diff --git a/accessible/ipc/DocAccessibleParent.h b/accessible/ipc/DocAccessibleParent.h index e866891f79e0..67b455cd8ea3 100644 --- a/accessible/ipc/DocAccessibleParent.h +++ b/accessible/ipc/DocAccessibleParent.h @@ -88,6 +88,13 @@ public: const bool& aIsInsert, const bool& aFromUser) override; +#if defined(XP_WIN) + virtual mozilla::ipc::IPCResult RecvSyncTextChangeEvent(const uint64_t& aID, const nsString& aStr, + const int32_t& aStart, const uint32_t& aLen, + const bool& aIsInsert, + const bool& aFromUser) override; +#endif // defined(XP_WIN) + virtual mozilla::ipc::IPCResult RecvSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID, const uint32_t& aType) override; diff --git a/accessible/ipc/win/DocAccessibleChild.cpp b/accessible/ipc/win/DocAccessibleChild.cpp index e932036acb67..9165f3ca9b92 100644 --- a/accessible/ipc/win/DocAccessibleChild.cpp +++ b/accessible/ipc/win/DocAccessibleChild.cpp @@ -190,6 +190,13 @@ DocAccessibleChild::SendTextChangeEvent(const uint64_t& aID, const bool& aFromUser) { if (IsConstructedInParentProcess()) { + if (aStr.Contains(L'\xfffc')) { + // The AT is going to need to reenter content while the event is being + // dispatched synchronously. + return PDocAccessibleChild::SendSyncTextChangeEvent(aID, aStr, aStart, + aLen, aIsInsert, + aFromUser); + } return PDocAccessibleChild::SendTextChangeEvent(aID, aStr, aStart, aLen, aIsInsert, aFromUser); } diff --git a/accessible/windows/msaa/AccessibleWrap.cpp b/accessible/windows/msaa/AccessibleWrap.cpp index e31f1f4ca189..fc329cbf7347 100644 --- a/accessible/windows/msaa/AccessibleWrap.cpp +++ b/accessible/windows/msaa/AccessibleWrap.cpp @@ -43,6 +43,7 @@ #include "nsArrayUtils.h" #include "mozilla/Preferences.h" #include "nsIXULRuntime.h" +#include "mozilla/mscom/AsyncInvoker.h" #include "oleacc.h" @@ -1627,3 +1628,60 @@ AccessibleWrap::SetHandlerControl(DWORD aPid, RefPtr aCtrl) sHandlerControllers->AppendElement(Move(ctrlData)); } + +bool +AccessibleWrap::DispatchTextChangeToHandler(bool aIsInsert, + const nsString& aText, + int32_t aStart, uint32_t aLen) +{ + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(NS_IsMainThread()); + + if (!sHandlerControllers || sHandlerControllers->IsEmpty()) { + return false; + } + + HWND hwnd = GetHWNDFor(this); + MOZ_ASSERT(hwnd); + if (!hwnd) { + return false; + } + + long msaaId = GetChildIDFor(this); + + DWORD ourPid = ::GetCurrentProcessId(); + + // The handler ends up calling NotifyWinEvent, which should only be done once + // since it broadcasts the same event to every process who is subscribed. + // OTOH, if our chrome process contains a handler, we should prefer to + // broadcast the event from that process, as we want any DLLs injected by ATs + // to receive the event synchronously. Otherwise we simply choose the first + // handler in the list, for the lack of a better heuristic. + + nsTArray::index_type ctrlIndex = + sHandlerControllers->IndexOf(ourPid); + + if (ctrlIndex == nsTArray::NoIndex) { + ctrlIndex = 0; + } + + HandlerControllerData& controller = sHandlerControllers->ElementAt(ctrlIndex); + MOZ_ASSERT(controller.mPid); + MOZ_ASSERT(controller.mCtrl); + + VARIANT_BOOL isInsert = aIsInsert ? VARIANT_TRUE : VARIANT_FALSE; + + IA2TextSegment textSegment{::SysAllocStringLen(aText.get(), aText.Length()), + aStart, static_cast(aLen)}; + + ASYNC_INVOKER_FOR(IHandlerControl) invoker(controller.mCtrl, + Some(controller.mIsProxy)); + + HRESULT hr = ASYNC_INVOKE(invoker, OnTextChange, PtrToLong(hwnd), msaaId, + isInsert, &textSegment); + + ::SysFreeString(textSegment.text); + + return SUCCEEDED(hr); +} + diff --git a/accessible/windows/msaa/AccessibleWrap.h b/accessible/windows/msaa/AccessibleWrap.h index 5830ec9ff240..602a074cc7cb 100644 --- a/accessible/windows/msaa/AccessibleWrap.h +++ b/accessible/windows/msaa/AccessibleWrap.h @@ -192,6 +192,8 @@ public: // construction, destruction static void SetHandlerControl(DWORD aPid, RefPtr aCtrl); + bool DispatchTextChangeToHandler(bool aIsInsert, const nsString& aText, + int32_t aStart, uint32_t aLen); protected: virtual ~AccessibleWrap(); diff --git a/accessible/windows/msaa/Platform.cpp b/accessible/windows/msaa/Platform.cpp index 0d4fc394e59e..63f6111c1f3f 100644 --- a/accessible/windows/msaa/Platform.cpp +++ b/accessible/windows/msaa/Platform.cpp @@ -132,6 +132,14 @@ a11y::ProxyTextChangeEvent(ProxyAccessible* aText, const nsString& aStr, return; } + static const bool useHandler = + Preferences::GetBool("accessibility.handler.enabled", false); + + if (useHandler) { + wrapper->DispatchTextChangeToHandler(aInsert, aStr, aStart, aLen); + return; + } + auto text = static_cast(wrapper->AsHyperText()); if (text) { ia2AccessibleText::UpdateTextChangeData(text, aInsert, aStr, aStart, aLen); From 4d2ae56c584f0198cffb4399f262a6c9ea903a6d Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 11 Apr 2017 00:51:30 -0400 Subject: [PATCH 07/19] Bug 1352527 - Part 1: Add the nsPresContext::GetBidiEngine() API; r=jfkthame The nsBidi API requires the consumer to first call SetPara() in order to perform bidi resolution and that resets the data members, so there is no need to recreate nsBidi objects from scratch each time we need to perform bidi resolution. Having this API allows us to reuse this object across the calls to nsBidiPresUtils members. --- layout/base/nsBidi_ICU.h | 4 ++++ layout/base/nsBidi_noICU.h | 3 +++ layout/base/nsPresContext.cpp | 12 ++++++++++++ layout/base/nsPresContext.h | 6 ++++++ 4 files changed, 25 insertions(+) diff --git a/layout/base/nsBidi_ICU.h b/layout/base/nsBidi_ICU.h index 3ead6e2bb672..587232e4d94b 100644 --- a/layout/base/nsBidi_ICU.h +++ b/layout/base/nsBidi_ICU.h @@ -183,6 +183,10 @@ public: static nsresult ReorderVisual(const nsBidiLevel* aLevels, int32_t aLength, int32_t* aIndexMap); +private: + nsBidi(const nsBidi&) = delete; + void operator=(const nsBidi&) = delete; + protected: UBiDi* mBiDi; }; diff --git a/layout/base/nsBidi_noICU.h b/layout/base/nsBidi_noICU.h index a3f5aef1c3ea..2ddfa8488835 100644 --- a/layout/base/nsBidi_noICU.h +++ b/layout/base/nsBidi_noICU.h @@ -704,6 +704,9 @@ private: void ReorderLine(nsBidiLevel aMinLevel, nsBidiLevel aMaxLevel); static bool PrepareReorder(const nsBidiLevel *aLevels, int32_t aLength, int32_t *aIndexMap, nsBidiLevel *aMinLevel, nsBidiLevel *aMaxLevel); + + nsBidi(const nsBidi&) = delete; + void operator=(const nsBidi&) = delete; }; #endif // _nsBidi_noICU_h_ diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 12a7df8d2953..4082851bffc2 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -89,6 +89,7 @@ #include "nsCSSParser.h" #include "nsBidiUtils.h" #include "nsServiceManagerUtils.h" +#include "nsBidi.h" #include "mozilla/dom/URL.h" @@ -3012,6 +3013,17 @@ nsPresContext::GetRestyleGeneration() const return mRestyleManager->GetRestyleGeneration(); } +nsBidi& +nsPresContext::GetBidiEngine() +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!mBidiEngine) { + mBidiEngine.reset(new nsBidi()); + } + return *mBidiEngine; +} + nsRootPresContext::nsRootPresContext(nsIDocument* aDocument, nsPresContextType aType) : nsPresContext(aDocument, aType), diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index 72272feddb96..90005bf9e3f4 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -9,6 +9,7 @@ #define nsPresContext_h___ #include "mozilla/Attributes.h" +#include "mozilla/UniquePtr.h" #include "mozilla/WeakPtr.h" #include "nsColor.h" #include "nsCoord.h" @@ -45,6 +46,7 @@ #include "mozilla/StyleBackendType.h" class nsAString; +class nsBidi; class nsIPrintSettings; class nsDocShell; class nsIDocShell; @@ -1193,6 +1195,8 @@ public: mHasWarnedAboutTooLargeDashedOrDottedRadius = true; } + nsBidi& GetBidiEngine(); + protected: friend class nsRunnableMethod; void ThemeChangedInternal(); @@ -1349,6 +1353,8 @@ protected: nsCOMPtr mPrintSettings; nsCOMPtr mPrefChangedTimer; + mozilla::UniquePtr mBidiEngine; + FramePropertyTable mPropertyTable; struct TransactionInvalidations { From 83690b136c1fa28383e93024cf58354cd7014906 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Sat, 1 Apr 2017 22:26:41 -0400 Subject: [PATCH 08/19] Bug 1352527 - Part 2: Switch nsBidiPresUtils consumers of nsBidi to use nsLayoutUtils::GetBidiEngine(); r=jfkthame --- layout/base/nsBidiPresUtils.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index dd5da0e35506..624d05cc09e3 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -138,7 +138,6 @@ struct MOZ_STACK_CLASS BidiParagraphData bool mIsVisual; nsBidiLevel mParaLevel; nsIContent* mPrevContent; - nsBidi mBidiEngine; nsIFrame* mPrevFrame; #ifdef DEBUG // Only used for NOISY debug output. @@ -184,8 +183,9 @@ struct MOZ_STACK_CLASS BidiParagraphData nsresult SetPara() { - return mBidiEngine.SetPara(mBuffer.get(), BufferLength(), - mParaLevel); + return mPresContext->GetBidiEngine() + .SetPara(mBuffer.get(), BufferLength(), + mParaLevel); } /** @@ -197,7 +197,7 @@ struct MOZ_STACK_CLASS BidiParagraphData { nsBidiLevel paraLevel = mParaLevel; if (paraLevel == NSBIDI_DEFAULT_LTR || paraLevel == NSBIDI_DEFAULT_RTL) { - mBidiEngine.GetParaLevel(¶Level); + mPresContext->GetBidiEngine().GetParaLevel(¶Level); } return paraLevel; } @@ -205,18 +205,22 @@ struct MOZ_STACK_CLASS BidiParagraphData nsBidiDirection GetDirection() { nsBidiDirection dir; - mBidiEngine.GetDirection(&dir); + mPresContext->GetBidiEngine().GetDirection(&dir); return dir; } - nsresult CountRuns(int32_t *runCount){ return mBidiEngine.CountRuns(runCount); } + nsresult CountRuns(int32_t *runCount) + { + return mPresContext->GetBidiEngine().CountRuns(runCount); + } nsresult GetLogicalRun(int32_t aLogicalStart, int32_t* aLogicalLimit, nsBidiLevel* aLevel) { - nsresult rv = mBidiEngine.GetLogicalRun(aLogicalStart, - aLogicalLimit, aLevel); + nsresult rv = + mPresContext->GetBidiEngine().GetLogicalRun(aLogicalStart, + aLogicalLimit, aLevel); if (mIsVisual || NS_FAILED(rv)) *aLevel = GetParaLevel(); return rv; @@ -2152,7 +2156,8 @@ nsresult nsBidiPresUtils::ProcessText(const char16_t* aText, const char16_t* visualLeftPart; const char16_t* visualRightSide; if (dir == NSBIDI_RTL) { - // One day, son, this could all be replaced with mBidiEngine.GetVisualIndex ... + // One day, son, this could all be replaced with + // mPresContext->GetBidiEngine().GetVisualIndex() ... posResolve->visualIndex = visualStart + (subRunLength - (posResolve->logicalIndex + 1 - start)); // Skipping to the "left part". visualLeftPart = text + posResolve->logicalIndex + 1; @@ -2275,9 +2280,9 @@ nsresult nsBidiPresUtils::ProcessTextForRenderingContext(const char16_t* a aTextRunConstructionDrawTarget, &aFontMetrics, nsPoint(aX, aY)); - nsBidi bidiEngine; return ProcessText(aText, aLength, aBaseLevel, aPresContext, processor, - aMode, aPosResolve, aPosResolveCount, aWidth, &bidiEngine); + aMode, aPosResolve, aPosResolveCount, aWidth, + &aPresContext->GetBidiEngine()); } /* static */ From 68460d7321272cebb92d081d3bdf5ae1a4e8fbda Mon Sep 17 00:00:00 2001 From: Ya-Chieh Wu Date: Thu, 13 Apr 2017 18:39:00 +0800 Subject: [PATCH 09/19] Bug 1340995 - [pdfium] skip to render key in form when the key is being pressed with Control or Meta. r=ehung. --HG-- extra : rebase_source : d56f49b844a49e31a25a4f87831db28268618d53 --- browser/extensions/mortar/host/common/ppapi-runtime.jsm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/browser/extensions/mortar/host/common/ppapi-runtime.jsm b/browser/extensions/mortar/host/common/ppapi-runtime.jsm index 349dee9883b8..12fcd022170c 100644 --- a/browser/extensions/mortar/host/common/ppapi-runtime.jsm +++ b/browser/extensions/mortar/host/common/ppapi-runtime.jsm @@ -3294,7 +3294,9 @@ dump(`callFromJSON: < ${JSON.stringify(call)}\n`); PPB_KeyboardInputEvent_GetCharacterText: function(json) { let event = PP_Resource.lookup(json.character_event); let charCode = event.domEvent.charCode; - if (charCode === 0) { + if (charCode === 0 || + event.domEvent.getModifierState("Control") || + event.domEvent.getModifierState("Meta")) { return new PP_Var(); } return new String_PP_Var(String.fromCharCode(charCode)); From 5afdefe075ce1e5ad8c8710444eac46c4a369a6a Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Thu, 13 Apr 2017 23:59:49 -0700 Subject: [PATCH 10/19] Backed out changeset f179621a517b (bug 1147538) for osx reftest failures a=backout --- layout/painting/FrameLayerBuilder.cpp | 29 ++++++++++++++------------- layout/painting/nsDisplayList.cpp | 6 ------ layout/painting/nsDisplayList.h | 1 - 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/layout/painting/FrameLayerBuilder.cpp b/layout/painting/FrameLayerBuilder.cpp index 37380f829784..15a7d1a99229 100644 --- a/layout/painting/FrameLayerBuilder.cpp +++ b/layout/painting/FrameLayerBuilder.cpp @@ -3208,6 +3208,8 @@ void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueB } for (auto& item : data->mAssignedDisplayItems) { + MOZ_ASSERT(item.mItem->GetType() != nsDisplayItem::TYPE_LAYER_EVENT_REGIONS); + InvalidateForLayerChange(item.mItem, data->mLayer); mLayerBuilder->AddPaintedDisplayItem(data, item.mItem, item.mClip, *this, item.mLayerState, @@ -4465,7 +4467,6 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) topLeft); }); - nsIntRegion opaquePixels; if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) { nsDisplayLayerEventRegions* eventRegions = static_cast(item); @@ -4476,26 +4477,26 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) if (mManager->IsWidgetLayerManager()) { paintedLayerData->UpdateCommonClipCount(itemClip); } - opaquePixels = ComputeOpaqueRect(item, + nsIntRegion opaquePixels = ComputeOpaqueRect(item, animatedGeometryRoot, itemClip, aList, &paintedLayerData->mHideAllLayersBelow, &paintedLayerData->mOpaqueForAnimatedGeometryRootParent); MOZ_ASSERT(nsIntRegion(itemDrawRect).Contains(opaquePixels)); opaquePixels.AndWith(itemVisibleRect); - } + paintedLayerData->Accumulate(this, item, opaquePixels, + itemVisibleRect, itemClip, layerState); - paintedLayerData->Accumulate(this, item, opaquePixels, - itemVisibleRect, itemClip, layerState); - if (!paintedLayerData->mLayer) { - // Try to recycle the old layer of this display item. - RefPtr layer = - AttemptToRecyclePaintedLayer(animatedGeometryRoot, item, topLeft); - if (layer) { - paintedLayerData->mLayer = layer; + if (!paintedLayerData->mLayer) { + // Try to recycle the old layer of this display item. + RefPtr layer = + AttemptToRecyclePaintedLayer(animatedGeometryRoot, item, topLeft); + if (layer) { + paintedLayerData->mLayer = layer; - NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0, - "Layer already in list???"); - mNewChildLayers[paintedLayerData->mNewChildLayersIndex].mLayer = layer.forget(); + NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0, + "Layer already in list???"); + mNewChildLayers[paintedLayerData->mNewChildLayersIndex].mLayer = layer.forget(); + } } } } diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 368542cba201..0a6e4cc0965f 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -4444,12 +4444,6 @@ nsDisplayLayerEventRegions::WriteDebugInfo(std::stringstream& aStream) } } -mozilla::Maybe -nsDisplayLayerEventRegions::IsUniform(nsDisplayListBuilder* aBuilder) -{ - return Some(NS_RGBA(0,0,0,0)); -} - nsDisplayCaret::nsDisplayCaret(nsDisplayListBuilder* aBuilder, nsIFrame* aCaretFrame) : nsDisplayItem(aBuilder, aCaretFrame) diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h index bbe0a8bf4f18..3f54402784f8 100644 --- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -3568,7 +3568,6 @@ public: { return true; } - virtual mozilla::Maybe IsUniform(nsDisplayListBuilder* aBuilder) override; NS_DISPLAY_DECL_NAME("LayerEventRegions", TYPE_LAYER_EVENT_REGIONS) From 5c3c7eb8db94d3c88a9f4461f986ddaa89fd3cfa Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 14 Apr 2017 00:02:40 -0700 Subject: [PATCH 11/19] Backed out 4 changesets (bug 1322532) for windows static build failures a=backout Backed out changeset df4e3ee037d6 (bug 1322532) Backed out changeset 0acfde7a7a45 (bug 1322532) Backed out changeset 34bf061d8e29 (bug 1322532) Backed out changeset 954ea82470ed (bug 1322532) --- accessible/ipc/DocAccessibleParent.cpp | 15 - accessible/ipc/DocAccessibleParent.h | 7 - accessible/ipc/win/DocAccessibleChild.cpp | 19 - accessible/ipc/win/DocAccessibleChild.h | 2 +- accessible/ipc/win/PDocAccessible.ipdl | 2 - .../ipc/win/handler/AccessibleHandler.cpp | 7 - .../win/handler/AccessibleHandlerControl.cpp | 163 ++------ .../win/handler/AccessibleHandlerControl.h | 43 +-- .../ipc/win/handler/AccessibleTextTearoff.cpp | 359 ------------------ .../ipc/win/handler/AccessibleTextTearoff.h | 88 ----- accessible/ipc/win/handler/HandlerData.idl | 5 - accessible/ipc/win/handler/moz.build | 1 - accessible/windows/msaa/AccessibleWrap.cpp | 58 --- accessible/windows/msaa/AccessibleWrap.h | 2 - accessible/windows/msaa/DocAccessibleWrap.cpp | 13 +- accessible/windows/msaa/Platform.cpp | 8 - ipc/ipdl/sync-messages.ini | 3 - 17 files changed, 52 insertions(+), 743 deletions(-) delete mode 100644 accessible/ipc/win/handler/AccessibleTextTearoff.cpp delete mode 100644 accessible/ipc/win/handler/AccessibleTextTearoff.h diff --git a/accessible/ipc/DocAccessibleParent.cpp b/accessible/ipc/DocAccessibleParent.cpp index 2746fe204fdd..61204940e383 100644 --- a/accessible/ipc/DocAccessibleParent.cpp +++ b/accessible/ipc/DocAccessibleParent.cpp @@ -338,21 +338,6 @@ DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID, return IPC_OK(); } -#if defined(XP_WIN) - -mozilla::ipc::IPCResult -DocAccessibleParent::RecvSyncTextChangeEvent(const uint64_t& aID, - const nsString& aStr, - const int32_t& aStart, - const uint32_t& aLen, - const bool& aIsInsert, - const bool& aFromUser) -{ - return RecvTextChangeEvent(aID, aStr, aStart, aLen, aIsInsert, aFromUser); -} - -#endif // defined(XP_WIN) - mozilla::ipc::IPCResult DocAccessibleParent::RecvSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID, diff --git a/accessible/ipc/DocAccessibleParent.h b/accessible/ipc/DocAccessibleParent.h index 67b455cd8ea3..e866891f79e0 100644 --- a/accessible/ipc/DocAccessibleParent.h +++ b/accessible/ipc/DocAccessibleParent.h @@ -88,13 +88,6 @@ public: const bool& aIsInsert, const bool& aFromUser) override; -#if defined(XP_WIN) - virtual mozilla::ipc::IPCResult RecvSyncTextChangeEvent(const uint64_t& aID, const nsString& aStr, - const int32_t& aStart, const uint32_t& aLen, - const bool& aIsInsert, - const bool& aFromUser) override; -#endif // defined(XP_WIN) - virtual mozilla::ipc::IPCResult RecvSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID, const uint32_t& aType) override; diff --git a/accessible/ipc/win/DocAccessibleChild.cpp b/accessible/ipc/win/DocAccessibleChild.cpp index 9165f3ca9b92..913bbe3b2d54 100644 --- a/accessible/ipc/win/DocAccessibleChild.cpp +++ b/accessible/ipc/win/DocAccessibleChild.cpp @@ -77,18 +77,6 @@ DocAccessibleChild::RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandl return IPC_OK(); } -HWND -DocAccessibleChild::GetNativeWindowHandle() const -{ - if (mEmulatedWindowHandle) { - return mEmulatedWindowHandle; - } - - auto tab = static_cast(Manager()); - MOZ_ASSERT(tab); - return reinterpret_cast(tab->GetNativeWindowHandle()); -} - void DocAccessibleChild::PushDeferredEvent(UniquePtr aEvent) { @@ -190,13 +178,6 @@ DocAccessibleChild::SendTextChangeEvent(const uint64_t& aID, const bool& aFromUser) { if (IsConstructedInParentProcess()) { - if (aStr.Contains(L'\xfffc')) { - // The AT is going to need to reenter content while the event is being - // dispatched synchronously. - return PDocAccessibleChild::SendSyncTextChangeEvent(aID, aStr, aStart, - aLen, aIsInsert, - aFromUser); - } return PDocAccessibleChild::SendTextChangeEvent(aID, aStr, aStart, aLen, aIsInsert, aFromUser); } diff --git a/accessible/ipc/win/DocAccessibleChild.h b/accessible/ipc/win/DocAccessibleChild.h index c99a04542aac..6a82025b8ffd 100644 --- a/accessible/ipc/win/DocAccessibleChild.h +++ b/accessible/ipc/win/DocAccessibleChild.h @@ -33,7 +33,7 @@ public: RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandle, const IAccessibleHolder& aEmulatedWindowCOMProxy) override; - HWND GetNativeWindowHandle() const; + HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; } IAccessible* GetEmulatedWindowIAccessible() const { return mEmulatedWindowProxy.get(); } IAccessible* GetParentIAccessible() const { return mParentProxy.get(); } diff --git a/accessible/ipc/win/PDocAccessible.ipdl b/accessible/ipc/win/PDocAccessible.ipdl index 08145cd494bb..6b7e1b342c0c 100644 --- a/accessible/ipc/win/PDocAccessible.ipdl +++ b/accessible/ipc/win/PDocAccessible.ipdl @@ -53,8 +53,6 @@ parent: async CaretMoveEvent(uint64_t aID, int32_t aOffset); async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen, bool aIsInsert, bool aFromUser); - sync SyncTextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, - uint32_t aLen, bool aIsInsert, bool aFromUser); async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType); async RoleChangedEvent(uint32_t aRole); diff --git a/accessible/ipc/win/handler/AccessibleHandler.cpp b/accessible/ipc/win/handler/AccessibleHandler.cpp index ee2e53171c51..6de902f6bab2 100644 --- a/accessible/ipc/win/handler/AccessibleHandler.cpp +++ b/accessible/ipc/win/handler/AccessibleHandler.cpp @@ -12,7 +12,6 @@ #include "AccessibleHandler.h" #include "AccessibleHandlerControl.h" -#include "AccessibleTextTearoff.h" #include "Factory.h" #include "HandlerData.h" @@ -184,12 +183,6 @@ AccessibleHandler::QueryHandlerInterface(IUnknown* aProxyUnknown, REFIID aIid, return S_OK; } - if (aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext) { - RefPtr textTearoff(new AccessibleTextTearoff(this)); - textTearoff.forget(aOutInterface); - return S_OK; - } - if (aIid == IID_IProvideClassInfo) { RefPtr clsInfo(this); clsInfo.forget(aOutInterface); diff --git a/accessible/ipc/win/handler/AccessibleHandlerControl.cpp b/accessible/ipc/win/handler/AccessibleHandlerControl.cpp index 278ceac7fdd4..4f9e27fcfcab 100644 --- a/accessible/ipc/win/handler/AccessibleHandlerControl.cpp +++ b/accessible/ipc/win/handler/AccessibleHandlerControl.cpp @@ -22,103 +22,6 @@ namespace a11y { mscom::SingletonFactory gControlFactory; -namespace detail { - -TextChange::TextChange() - : mIA2UniqueId(0) - , mIsInsert(false) - , mText() -{ -} - -TextChange::TextChange(long aIA2UniqueId, bool aIsInsert, - NotNull aText) - : mIA2UniqueId(aIA2UniqueId) - , mIsInsert(aIsInsert) - , mText{BSTRCopy(aText->text), aText->start, aText->end} -{ -} - -TextChange::TextChange(TextChange&& aOther) - : mText() -{ - *this = Move(aOther); -} - -TextChange::TextChange(const TextChange& aOther) - : mText() -{ - *this = aOther; -} - -TextChange& -TextChange::operator=(TextChange&& aOther) -{ - mIA2UniqueId = aOther.mIA2UniqueId; - mIsInsert = aOther.mIsInsert; - aOther.mIA2UniqueId = 0; - ::SysFreeString(mText.text); - mText = aOther.mText; - aOther.mText.text = nullptr; - return *this; -} - -TextChange& -TextChange::operator=(const TextChange& aOther) -{ - mIA2UniqueId = aOther.mIA2UniqueId; - mIsInsert = aOther.mIsInsert; - ::SysFreeString(mText.text); - mText = {BSTRCopy(aOther.mText.text), aOther.mText.start, aOther.mText.end}; - return *this; -} - -TextChange::~TextChange() -{ - ::SysFreeString(mText.text); -} - -HRESULT -TextChange::GetOld(long aIA2UniqueId, NotNull aOutOldSegment) -{ - if (mIsInsert || aIA2UniqueId != mIA2UniqueId) { - return S_OK; - } - - return SegCopy(*aOutOldSegment, mText); -} - -HRESULT -TextChange::GetNew(long aIA2UniqueId, NotNull aOutNewSegment) -{ - if (!mIsInsert || aIA2UniqueId != mIA2UniqueId) { - return S_OK; - } - - return SegCopy(*aOutNewSegment, mText); -} - -/* static */ BSTR -TextChange::BSTRCopy(const BSTR& aIn) -{ - return ::SysAllocStringLen(aIn, ::SysStringLen(aIn)); -} - -/* static */ HRESULT -TextChange::SegCopy(IA2TextSegment& aDest, const IA2TextSegment& aSrc) -{ - aDest = {BSTRCopy(aSrc.text), aSrc.start, aSrc.end}; - if (aSrc.text && !aDest.text) { - return E_OUTOFMEMORY; - } - if (!::SysStringLen(aDest.text)) { - return S_FALSE; - } - return S_OK; -} - -} // namespace detail - HRESULT AccessibleHandlerControl::Create(AccessibleHandlerControl** aOutObject) { @@ -132,14 +35,46 @@ AccessibleHandlerControl::Create(AccessibleHandlerControl** aOutObject) } AccessibleHandlerControl::AccessibleHandlerControl() - : mCacheGen(0) + : mRefCnt(0) + , mCacheGen(0) , mIA2Proxy(mscom::RegisterProxy(L"ia2marshal.dll")) , mHandlerProxy(mscom::RegisterProxy()) { MOZ_ASSERT(mIA2Proxy); } -IMPL_IUNKNOWN1(AccessibleHandlerControl, IHandlerControl) +HRESULT +AccessibleHandlerControl::QueryInterface(REFIID aIid, void** aOutInterface) +{ + if (!aOutInterface) { + return E_INVALIDARG; + } + + if (aIid == IID_IUnknown || aIid == IID_IHandlerControl) { + RefPtr ctl(this); + ctl.forget(aOutInterface); + return S_OK; + } + + *aOutInterface = nullptr; + return E_NOINTERFACE; +} + +ULONG +AccessibleHandlerControl::AddRef() +{ + return ++mRefCnt; +} + +ULONG +AccessibleHandlerControl::Release() +{ + ULONG result = --mRefCnt; + if (!result) { + delete this; + } + return result; +} HRESULT AccessibleHandlerControl::Invalidate() @@ -148,36 +83,6 @@ AccessibleHandlerControl::Invalidate() return S_OK; } -HRESULT -AccessibleHandlerControl::OnTextChange(long aHwnd, long aIA2UniqueId, - VARIANT_BOOL aIsInsert, - IA2TextSegment* aText) -{ - if (!aText) { - return E_INVALIDARG; - } - - mTextChange = detail::TextChange(aIA2UniqueId, aIsInsert, WrapNotNull(aText)); - NotifyWinEvent(aIsInsert ? IA2_EVENT_TEXT_INSERTED : IA2_EVENT_TEXT_REMOVED, - reinterpret_cast(static_cast(aHwnd)), - OBJID_CLIENT, aIA2UniqueId); - return S_OK; -} - -HRESULT -AccessibleHandlerControl::GetNewText(long aIA2UniqueId, - NotNull aOutNewText) -{ - return mTextChange.GetNew(aIA2UniqueId, aOutNewText); -} - -HRESULT -AccessibleHandlerControl::GetOldText(long aIA2UniqueId, - NotNull aOutOldText) -{ - return mTextChange.GetOld(aIA2UniqueId, aOutOldText); -} - HRESULT AccessibleHandlerControl::GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo) { diff --git a/accessible/ipc/win/handler/AccessibleHandlerControl.h b/accessible/ipc/win/handler/AccessibleHandlerControl.h index af29c8445d6c..3c4b26d80efd 100644 --- a/accessible/ipc/win/handler/AccessibleHandlerControl.h +++ b/accessible/ipc/win/handler/AccessibleHandlerControl.h @@ -13,70 +13,37 @@ #include "Factory.h" #include "HandlerData.h" -#include "IUnknownImpl.h" #include "mozilla/mscom/Registration.h" -#include "mozilla/NotNull.h" namespace mozilla { namespace a11y { -namespace detail { - -class TextChange final -{ -public: - TextChange(); - TextChange(long aIA2UniqueId, bool aIsInsert, NotNull aText); - TextChange(TextChange&& aOther); - TextChange(const TextChange& aOther); - - TextChange& operator=(TextChange&& aOther); - TextChange& operator=(const TextChange& aOther); - - ~TextChange(); - - HRESULT GetOld(long aIA2UniqueId, NotNull aOutOldSegment); - HRESULT GetNew(long aIA2UniqueId, NotNull aOutNewSegment); - -private: - static BSTR BSTRCopy(const BSTR& aIn); - static HRESULT SegCopy(IA2TextSegment& aDest, const IA2TextSegment& aSrc); - - long mIA2UniqueId; - bool mIsInsert; - IA2TextSegment mText; -}; - -} // namespace detail - class AccessibleHandlerControl final : public IHandlerControl { public: static HRESULT Create(AccessibleHandlerControl** aOutObject); - DECL_IUNKNOWN + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override; + STDMETHODIMP_(ULONG) AddRef() override; + STDMETHODIMP_(ULONG) Release() override; // IHandlerControl STDMETHODIMP Invalidate() override; - STDMETHODIMP OnTextChange(long aHwnd, long aIA2UniqueId, - VARIANT_BOOL aIsInsert, IA2TextSegment* aText) override; uint32_t GetCacheGen() const { return mCacheGen; } - HRESULT GetNewText(long aIA2UniqueId, NotNull aOutNewText); - HRESULT GetOldText(long aIA2UniqueId, NotNull aOutOldText); - HRESULT GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo); private: AccessibleHandlerControl(); ~AccessibleHandlerControl() = default; + ULONG mRefCnt; uint32_t mCacheGen; - detail::TextChange mTextChange; UniquePtr mIA2Proxy; UniquePtr mHandlerProxy; }; diff --git a/accessible/ipc/win/handler/AccessibleTextTearoff.cpp b/accessible/ipc/win/handler/AccessibleTextTearoff.cpp deleted file mode 100644 index 2682a2795049..000000000000 --- a/accessible/ipc/win/handler/AccessibleTextTearoff.cpp +++ /dev/null @@ -1,359 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#if defined(MOZILLA_INTERNAL_API) -#error This code is NOT for internal Gecko use! -#endif // defined(MOZILLA_INTERNAL_API) - -#include "AccessibleTextTearoff.h" - -#include "AccessibleHandlerControl.h" -#include "AccessibleText_i.c" -#include "AccessibleHypertext_i.c" -#include "Factory.h" - -#include "mozilla/Assertions.h" - -namespace mozilla { -namespace a11y { - -AccessibleTextTearoff::AccessibleTextTearoff(AccessibleHandler* aHandler) - : mHandler(aHandler) -{ - MOZ_ASSERT(aHandler); -} - -HRESULT -AccessibleTextTearoff::ResolveAccText() -{ - if (mAccTextProxy) { - return S_OK; - } - - RefPtr proxy(mHandler->GetProxy()); - if (!proxy) { - return E_UNEXPECTED; - } - - return proxy->QueryInterface(IID_IAccessibleText, - getter_AddRefs(mAccTextProxy)); -} - -HRESULT -AccessibleTextTearoff::ResolveAccHypertext() -{ - if (mAccHypertextProxy) { - return S_OK; - } - - RefPtr proxy(mHandler->GetProxy()); - if (!proxy) { - return E_UNEXPECTED; - } - - return proxy->QueryInterface(IID_IAccessibleHypertext, - getter_AddRefs(mAccHypertextProxy)); -} - -IMPL_IUNKNOWN_QUERY_HEAD(AccessibleTextTearoff) -IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleText) -IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleHypertext) -IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mHandler) - -HRESULT -AccessibleTextTearoff::addSelection(long startOffset, long endOffset) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->addSelection(startOffset, endOffset); -} - -HRESULT -AccessibleTextTearoff::get_attributes(long offset, long *startOffset, - long *endOffset, BSTR *textAttributes) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->get_attributes(offset, startOffset, endOffset, - textAttributes); -} - -HRESULT -AccessibleTextTearoff::get_caretOffset(long *offset) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->get_caretOffset(offset); -} - -HRESULT -AccessibleTextTearoff::get_characterExtents(long offset, - enum IA2CoordinateType coordType, - long *x, long *y, long *width, - long *height) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->get_characterExtents(offset, coordType, x, y, width, - height); -} - -HRESULT -AccessibleTextTearoff::get_nSelections(long *nSelections) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->get_nSelections(nSelections); -} - -HRESULT -AccessibleTextTearoff::get_offsetAtPoint(long x, long y, - enum IA2CoordinateType coordType, - long *offset) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->get_offsetAtPoint(x, y, coordType, offset); -} - -HRESULT -AccessibleTextTearoff::get_selection(long selectionIndex, long *startOffset, - long *endOffset) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->get_selection(selectionIndex, startOffset, endOffset); -} - -HRESULT -AccessibleTextTearoff::get_text(long startOffset, long endOffset, BSTR *text) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->get_text(startOffset, endOffset, text); -} - -HRESULT -AccessibleTextTearoff::get_textBeforeOffset(long offset, - enum IA2TextBoundaryType boundaryType, - long *startOffset, long *endOffset, - BSTR *text) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->get_textBeforeOffset(offset, boundaryType, startOffset, - endOffset, text); -} - -HRESULT -AccessibleTextTearoff::get_textAfterOffset(long offset, - enum IA2TextBoundaryType boundaryType, - long *startOffset, long *endOffset, - BSTR *text) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->get_textAfterOffset(offset, boundaryType, - startOffset, endOffset, text); -} - -HRESULT -AccessibleTextTearoff::get_textAtOffset(long offset, - enum IA2TextBoundaryType boundaryType, - long *startOffset, long *endOffset, - BSTR *text) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->get_textAtOffset(offset, boundaryType, startOffset, - endOffset, text); -} - -HRESULT -AccessibleTextTearoff::removeSelection(long selectionIndex) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->removeSelection(selectionIndex); -} - -HRESULT -AccessibleTextTearoff::setCaretOffset(long offset) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->setCaretOffset(offset); -} - -HRESULT -AccessibleTextTearoff::setSelection(long selectionIndex, long startOffset, - long endOffset) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->setSelection(selectionIndex, startOffset, endOffset); -} - -HRESULT -AccessibleTextTearoff::get_nCharacters(long *nCharacters) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->get_nCharacters(nCharacters); -} - -HRESULT -AccessibleTextTearoff::scrollSubstringTo(long startIndex, long endIndex, - enum IA2ScrollType scrollType) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->scrollSubstringTo(startIndex, endIndex, scrollType); -} - -HRESULT -AccessibleTextTearoff::scrollSubstringToPoint(long startIndex, long endIndex, - enum IA2CoordinateType coordinateType, - long x, long y) -{ - HRESULT hr = ResolveAccText(); - if (FAILED(hr)) { - return hr; - } - - return mAccTextProxy->scrollSubstringToPoint(startIndex, endIndex, - coordinateType, x, y); -} - -HRESULT -AccessibleTextTearoff::get_newText(IA2TextSegment *newText) -{ - if (!newText) { - return E_INVALIDARG; - } - - RefPtr ctl(gControlFactory.GetSingleton()); - MOZ_ASSERT(ctl); - if (!ctl) { - return S_OK; - } - - long id; - HRESULT hr = mHandler->get_uniqueID(&id); - if (FAILED(hr)) { - return hr; - } - - return ctl->GetNewText(id, WrapNotNull(newText)); -} - -HRESULT -AccessibleTextTearoff::get_oldText(IA2TextSegment *oldText) -{ - if (!oldText) { - return E_INVALIDARG; - } - - RefPtr ctl(gControlFactory.GetSingleton()); - MOZ_ASSERT(ctl); - if (!ctl) { - return S_OK; - } - - long id; - HRESULT hr = mHandler->get_uniqueID(&id); - if (FAILED(hr)) { - return hr; - } - - return ctl->GetOldText(id, WrapNotNull(oldText)); -} - -HRESULT -AccessibleTextTearoff::get_nHyperlinks(long *hyperlinkCount) -{ - HRESULT hr = ResolveAccHypertext(); - if (FAILED(hr)) { - return hr; - } - - return mAccHypertextProxy->get_nHyperlinks(hyperlinkCount); -} - -HRESULT -AccessibleTextTearoff::get_hyperlink(long index, - IAccessibleHyperlink **hyperlink) -{ - HRESULT hr = ResolveAccHypertext(); - if (FAILED(hr)) { - return hr; - } - - return mAccHypertextProxy->get_hyperlink(index, hyperlink); -} - -HRESULT -AccessibleTextTearoff::get_hyperlinkIndex(long charIndex, long *hyperlinkIndex) -{ - HRESULT hr = ResolveAccHypertext(); - if (FAILED(hr)) { - return hr; - } - - return mAccHypertextProxy->get_hyperlinkIndex(charIndex, hyperlinkIndex); -} - - -} // namespace a11y -} // namespace mozilla diff --git a/accessible/ipc/win/handler/AccessibleTextTearoff.h b/accessible/ipc/win/handler/AccessibleTextTearoff.h deleted file mode 100644 index 8568f3c70653..000000000000 --- a/accessible/ipc/win/handler/AccessibleTextTearoff.h +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#if defined(MOZILLA_INTERNAL_API) -#error This code is NOT for internal Gecko use! -#endif // defined(MOZILLA_INTERNAL_API) - -#ifndef mozilla_a11y_AccessibleTextTearoff_h -#define mozilla_a11y_AccessibleTextTearoff_h - -#include "AccessibleHandler.h" -#include "AccessibleHypertext.h" -#include "IUnknownImpl.h" -#include "mozilla/RefPtr.h" - -namespace mozilla { -namespace a11y { - -class AccessibleTextTearoff final : public IAccessibleHypertext -{ -public: - explicit AccessibleTextTearoff(AccessibleHandler* aHandler); - - DECL_IUNKNOWN - - // IAccessibleText - STDMETHODIMP addSelection(long startOffset, long endOffset) override; - STDMETHODIMP get_attributes(long offset, long *startOffset, long *endOffset, - BSTR *textAttributes) override; - STDMETHODIMP get_caretOffset(long *offset) override; - STDMETHODIMP get_characterExtents(long offset, - enum IA2CoordinateType coordType, long *x, - long *y, long *width, long *height) override; - STDMETHODIMP get_nSelections(long *nSelections) override; - STDMETHODIMP get_offsetAtPoint(long x, long y, - enum IA2CoordinateType coordType, - long *offset) override; - STDMETHODIMP get_selection(long selectionIndex, long *startOffset, - long *endOffset) override; - STDMETHODIMP get_text(long startOffset, long endOffset, BSTR *text) override; - STDMETHODIMP get_textBeforeOffset(long offset, - enum IA2TextBoundaryType boundaryType, - long *startOffset, long *endOffset, - BSTR *text) override; - STDMETHODIMP get_textAfterOffset(long offset, - enum IA2TextBoundaryType boundaryType, - long *startOffset, long *endOffset, - BSTR *text) override; - STDMETHODIMP get_textAtOffset(long offset, - enum IA2TextBoundaryType boundaryType, - long *startOffset, long *endOffset, - BSTR *text) override; - STDMETHODIMP removeSelection(long selectionIndex) override; - STDMETHODIMP setCaretOffset(long offset) override; - STDMETHODIMP setSelection(long selectionIndex, long startOffset, - long endOffset) override; - STDMETHODIMP get_nCharacters(long *nCharacters) override; - STDMETHODIMP scrollSubstringTo(long startIndex, long endIndex, - enum IA2ScrollType scrollType) override; - STDMETHODIMP scrollSubstringToPoint(long startIndex, long endIndex, - enum IA2CoordinateType coordinateType, - long x, long y) override; - STDMETHODIMP get_newText(IA2TextSegment *newText) override; - STDMETHODIMP get_oldText(IA2TextSegment *oldText) override; - - // IAccessibleHypertext - STDMETHODIMP get_nHyperlinks(long *hyperlinkCount) override; - STDMETHODIMP get_hyperlink(long index, - IAccessibleHyperlink **hyperlink) override; - STDMETHODIMP get_hyperlinkIndex(long charIndex, long *hyperlinkIndex) override; - -private: - ~AccessibleTextTearoff() = default; - HRESULT ResolveAccText(); - HRESULT ResolveAccHypertext(); - - RefPtr mHandler; - RefPtr mAccTextProxy; - RefPtr mAccHypertextProxy; -}; - -} // namespace a11y -} // namespace mozilla - -#endif // mozilla_a11y_AccessibleTextTearoff_h diff --git a/accessible/ipc/win/handler/HandlerData.idl b/accessible/ipc/win/handler/HandlerData.idl index cd07f19cd7af..24279f14cc1e 100644 --- a/accessible/ipc/win/handler/HandlerData.idl +++ b/accessible/ipc/win/handler/HandlerData.idl @@ -9,8 +9,6 @@ import "ocidl.idl"; import "ServProv.idl"; -import "AccessibleText.idl"; - typedef struct _IA2Data { long mUniqueId; @@ -86,9 +84,6 @@ interface HandlerData interface IHandlerControl : IUnknown { HRESULT Invalidate(); - HRESULT OnTextChange([in] long aHwnd, [in] long aIA2UniqueId, - [in] VARIANT_BOOL aIsInsert, - [in] IA2TextSegment* aText); } [object, diff --git a/accessible/ipc/win/handler/moz.build b/accessible/ipc/win/handler/moz.build index 7879edc57210..b4fea56d725f 100644 --- a/accessible/ipc/win/handler/moz.build +++ b/accessible/ipc/win/handler/moz.build @@ -20,7 +20,6 @@ SOURCES += [ '!HandlerData_p.c', 'AccessibleHandler.cpp', 'AccessibleHandlerControl.cpp', - 'AccessibleTextTearoff.cpp', ] GENERATED_FILES += [ diff --git a/accessible/windows/msaa/AccessibleWrap.cpp b/accessible/windows/msaa/AccessibleWrap.cpp index fc329cbf7347..e31f1f4ca189 100644 --- a/accessible/windows/msaa/AccessibleWrap.cpp +++ b/accessible/windows/msaa/AccessibleWrap.cpp @@ -43,7 +43,6 @@ #include "nsArrayUtils.h" #include "mozilla/Preferences.h" #include "nsIXULRuntime.h" -#include "mozilla/mscom/AsyncInvoker.h" #include "oleacc.h" @@ -1628,60 +1627,3 @@ AccessibleWrap::SetHandlerControl(DWORD aPid, RefPtr aCtrl) sHandlerControllers->AppendElement(Move(ctrlData)); } - -bool -AccessibleWrap::DispatchTextChangeToHandler(bool aIsInsert, - const nsString& aText, - int32_t aStart, uint32_t aLen) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(NS_IsMainThread()); - - if (!sHandlerControllers || sHandlerControllers->IsEmpty()) { - return false; - } - - HWND hwnd = GetHWNDFor(this); - MOZ_ASSERT(hwnd); - if (!hwnd) { - return false; - } - - long msaaId = GetChildIDFor(this); - - DWORD ourPid = ::GetCurrentProcessId(); - - // The handler ends up calling NotifyWinEvent, which should only be done once - // since it broadcasts the same event to every process who is subscribed. - // OTOH, if our chrome process contains a handler, we should prefer to - // broadcast the event from that process, as we want any DLLs injected by ATs - // to receive the event synchronously. Otherwise we simply choose the first - // handler in the list, for the lack of a better heuristic. - - nsTArray::index_type ctrlIndex = - sHandlerControllers->IndexOf(ourPid); - - if (ctrlIndex == nsTArray::NoIndex) { - ctrlIndex = 0; - } - - HandlerControllerData& controller = sHandlerControllers->ElementAt(ctrlIndex); - MOZ_ASSERT(controller.mPid); - MOZ_ASSERT(controller.mCtrl); - - VARIANT_BOOL isInsert = aIsInsert ? VARIANT_TRUE : VARIANT_FALSE; - - IA2TextSegment textSegment{::SysAllocStringLen(aText.get(), aText.Length()), - aStart, static_cast(aLen)}; - - ASYNC_INVOKER_FOR(IHandlerControl) invoker(controller.mCtrl, - Some(controller.mIsProxy)); - - HRESULT hr = ASYNC_INVOKE(invoker, OnTextChange, PtrToLong(hwnd), msaaId, - isInsert, &textSegment); - - ::SysFreeString(textSegment.text); - - return SUCCEEDED(hr); -} - diff --git a/accessible/windows/msaa/AccessibleWrap.h b/accessible/windows/msaa/AccessibleWrap.h index 602a074cc7cb..5830ec9ff240 100644 --- a/accessible/windows/msaa/AccessibleWrap.h +++ b/accessible/windows/msaa/AccessibleWrap.h @@ -192,8 +192,6 @@ public: // construction, destruction static void SetHandlerControl(DWORD aPid, RefPtr aCtrl); - bool DispatchTextChangeToHandler(bool aIsInsert, const nsString& aText, - int32_t aStart, uint32_t aLen); protected: virtual ~AccessibleWrap(); diff --git a/accessible/windows/msaa/DocAccessibleWrap.cpp b/accessible/windows/msaa/DocAccessibleWrap.cpp index 9daad7617e9c..79e61b8809c9 100644 --- a/accessible/windows/msaa/DocAccessibleWrap.cpp +++ b/accessible/windows/msaa/DocAccessibleWrap.cpp @@ -131,7 +131,18 @@ DocAccessibleWrap::GetNativeWindow() const return nullptr; } - return ipcDoc->GetNativeWindowHandle(); + HWND hWnd = ipcDoc->GetEmulatedWindowHandle(); + if (hWnd) { + return hWnd; + } + + auto tab = static_cast(ipcDoc->Manager()); + MOZ_ASSERT(tab); + if (!tab) { + return nullptr; + } + + return reinterpret_cast(tab->GetNativeWindowHandle()); } else if (mHWND) { return mHWND; } diff --git a/accessible/windows/msaa/Platform.cpp b/accessible/windows/msaa/Platform.cpp index 63f6111c1f3f..0d4fc394e59e 100644 --- a/accessible/windows/msaa/Platform.cpp +++ b/accessible/windows/msaa/Platform.cpp @@ -132,14 +132,6 @@ a11y::ProxyTextChangeEvent(ProxyAccessible* aText, const nsString& aStr, return; } - static const bool useHandler = - Preferences::GetBool("accessibility.handler.enabled", false); - - if (useHandler) { - wrapper->DispatchTextChangeToHandler(aInsert, aStr, aStart, aLen); - return; - } - auto text = static_cast(wrapper->AsHyperText()); if (text) { ia2AccessibleText::UpdateTextChangeData(text, aInsert, aStr, aStart, aLen); diff --git a/ipc/ipdl/sync-messages.ini b/ipc/ipdl/sync-messages.ini index 6c05189e386a..c34253dc3040 100644 --- a/ipc/ipdl/sync-messages.ini +++ b/ipc/ipdl/sync-messages.ini @@ -594,9 +594,6 @@ platform = notwin [PDocAccessible::GetWindowedPluginIAccessible] description = platform = win -[PDocAccessible::SyncTextChangeEvent] -description = -platform = win # CPOWs [PBrowser::RpcMessage] From 01871513524a427839ecbc039ad124a3b30d613a Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Wed, 12 Apr 2017 08:42:02 +0200 Subject: [PATCH 12/19] Bug 1355136 - LUL on i686/x86_64-linux: allow CFAs to be arbitrary prefix expressions. r=froydnj. For reasons which are unclear, but possibly due to lack of any known use cases when the code was written, LUL on i686/x86_64-linux only accepts CFA (canonical frame address) expressions of the form SP+offset or FP+offset. However, on Fedora 25 x86_64 and Ubuntu 16.10 x86_64, at least one address range per object uses a Dwarf expression for the CFA, for example: 00000018 000000000024 0000001c FDE cie=00000000 pc=0000000031e0..0000000031f0 DW_CFA_def_cfa_offset: 16 DW_CFA_advance_loc: 6 to 00000000000031e6 DW_CFA_def_cfa_offset: 24 DW_CFA_advance_loc: 10 to 00000000000031f0 DW_CFA_def_cfa_expression( DW_OP_breg7 (rsp): 8; DW_OP_breg16 (rip): 0; DW_OP_lit15; DW_OP_and; DW_OP_lit11; DW_OP_ge; DW_OP_lit3; DW_OP_shl; DW_OP_plus) producing the following complaint from LUL: can't summarise: SVMA=0x31f0: rule for DW_REG_CFA: invalid |how|, expr=LExpr(PFXEXPR,0,0) Given that LUL is capable of handling such a CFA expression, it seems artificial to stop it doing so. This patch changes Summariser::Rule() so as to allow such expressions. --- tools/profiler/lul/LulDwarfSummariser.cpp | 36 ++++++++++++++++------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/tools/profiler/lul/LulDwarfSummariser.cpp b/tools/profiler/lul/LulDwarfSummariser.cpp index 174d2ea732e7..0b0938038932 100644 --- a/tools/profiler/lul/LulDwarfSummariser.cpp +++ b/tools/profiler/lul/LulDwarfSummariser.cpp @@ -246,19 +246,35 @@ Summariser::Rule(uintptr_t aAddress, int aNewReg, // is the heart of the summarisation process. switch (aNewReg) { - case DW_REG_CFA: - // This is a rule that defines the CFA. The only forms we can - // represent are: = SP+offset or = FP+offset. - if (how != NODEREF) { - reason1 = "rule for DW_REG_CFA: invalid |how|"; - goto cant_summarise; - } - if (oldReg != DW_REG_INTEL_XSP && oldReg != DW_REG_INTEL_XBP) { - reason1 = "rule for DW_REG_CFA: invalid |oldReg|"; - goto cant_summarise; + case DW_REG_CFA: { + // This is a rule that defines the CFA. The only forms we choose to + // represent are: = SP+offset, = FP+offset, or =prefix-expr. + switch (how) { + case NODEREF: + if (oldReg != DW_REG_INTEL_XSP && oldReg != DW_REG_INTEL_XBP) { + reason1 = "rule for DW_REG_CFA: invalid |oldReg|"; + goto cant_summarise; + } + break; + case DEREF: + reason1 = "rule for DW_REG_CFA: invalid |how|"; + goto cant_summarise; + case PFXEXPR: { + // Check that the prefix expression only mentions tracked registers. + const vector* pfxInstrs = mSecMap->GetPfxInstrs(); + reason2 = checkPfxExpr(pfxInstrs, offset); + if (reason2) { + reason1 = "rule for CFA: "; + goto cant_summarise; + } + break; + } + default: + goto cant_summarise; } mCurrRules.mCfaExpr = LExpr(how, oldReg, offset); break; + } case DW_REG_INTEL_XSP: case DW_REG_INTEL_XBP: case DW_REG_INTEL_XIP: { // This is a new rule for XSP, XBP or XIP (the return address). From 77bb87e5ebba608eb2f314b086ba671557c6071d Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Fri, 14 Apr 2017 12:24:07 +0300 Subject: [PATCH 13/19] Bug 1354810, CycleCollectedJSContext::Get() needs to be null-checked, r=baku --- dom/promise/Promise.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 822a19db3c81..9b583e437e73 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -570,6 +570,9 @@ Promise::PerformWorkerMicroTaskCheckpoint() MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!"); CycleCollectedJSContext* context = CycleCollectedJSContext::Get(); + if (!context) { + return; + } for (;;) { // For a normal microtask checkpoint, we try to use the debugger microtask @@ -604,6 +607,9 @@ Promise::PerformWorkerDebuggerMicroTaskCheckpoint() MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!"); CycleCollectedJSContext* context = CycleCollectedJSContext::Get(); + if (!context) { + return; + } for (;;) { // For a debugger microtask checkpoint, we always use the debugger microtask From 7ed5d1110de224305233d30c8cf40e68d9aa1791 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Fri, 14 Apr 2017 05:54:32 -0400 Subject: [PATCH 14/19] Bug 1325778 - Intermittent toolkit/components/passwordmgr/test/mochitest/test_insecure_form_field_autocomplete.html. disable the right test. r=mattn MozReview-Commit-ID: 1Ut8csGjudW --- toolkit/components/passwordmgr/test/mochitest/mochitest.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toolkit/components/passwordmgr/test/mochitest/mochitest.ini b/toolkit/components/passwordmgr/test/mochitest/mochitest.ini index a4170d7e0eca..a1d8ecad342a 100644 --- a/toolkit/components/passwordmgr/test/mochitest/mochitest.ini +++ b/toolkit/components/passwordmgr/test/mochitest/mochitest.ini @@ -29,11 +29,11 @@ skip-if = toolkit == 'android' # autocomplete [test_basic_form_autocomplete.html] skip-if = toolkit == 'android' # android:autocomplete. [test_insecure_form_field_autocomplete.html] -skip-if = toolkit == 'android' # android:autocomplete. +skip-if = toolkit == 'android' || os == 'linux' # android:autocomplete., linux: bug 1325778 [test_password_field_autocomplete.html] skip-if = toolkit == 'android' # android:autocomplete. [test_insecure_form_field_no_saved_login.html] -skip-if = toolkit == 'android' || os == 'linux' # android:autocomplete., linux: bug 1325778 +skip-if = toolkit == 'android' # android:autocomplete. [test_basic_form_html5.html] [test_basic_form_pwevent.html] [test_basic_form_pwonly.html] From 99137683e9e2a51ff54633177afe70b6ac017ab1 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Fri, 14 Apr 2017 05:54:36 -0400 Subject: [PATCH 15/19] Bug 1355089 - add BUG_COMPONENT to widget/* files. r=mstange,jimm MozReview-Commit-ID: 49Ug2HTqHnf --- widget/android/bindings/moz.build | 3 + widget/android/fennec/moz.build | 3 + widget/android/jni/moz.build | 3 + widget/android/moz.build | 3 + widget/cocoa/moz.build | 3 + widget/gonk/moz.build | 3 + widget/gtk/moz.build | 3 + widget/gtkxtbin/moz.build | 3 + widget/headless/moz.build | 3 + widget/moz.build | 24 +++++++ widget/tests/moz.build | 115 ++++++++++++++++++++++++++++++ widget/uikit/moz.build | 3 + widget/windows/moz.build | 3 + widget/x11/moz.build | 3 + widget/xremoteclient/moz.build | 3 + 15 files changed, 178 insertions(+) diff --git a/widget/android/bindings/moz.build b/widget/android/bindings/moz.build index 1bd71fa9570c..79137b5acfda 100644 --- a/widget/android/bindings/moz.build +++ b/widget/android/bindings/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Firefox for Android", "Graphics, Panning and Zooming") + # List of stems to generate .cpp and .h files for. To add a stem, add it to # this list and ensure that $(stem)-classes.txt exists in this directory. generated = [ diff --git a/widget/android/fennec/moz.build b/widget/android/fennec/moz.build index 0d6a8e0cd925..84e78db8174d 100644 --- a/widget/android/fennec/moz.build +++ b/widget/android/fennec/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Firefox for Android", "GeckoView") + EXPORTS += [ 'FennecJNINatives.h', 'FennecJNIWrappers.h', diff --git a/widget/android/jni/moz.build b/widget/android/jni/moz.build index 31d7d32e6cf4..65d87a0847b1 100644 --- a/widget/android/jni/moz.build +++ b/widget/android/jni/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Firefox for Android", "General") + EXPORTS.mozilla.jni += [ 'Accessors.h', 'Natives.h', diff --git a/widget/android/moz.build b/widget/android/moz.build index 2e48a72ba6a0..963e1a7e9775 100644 --- a/widget/android/moz.build +++ b/widget/android/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget: Android") + DIRS += [ 'bindings', 'fennec', diff --git a/widget/cocoa/moz.build b/widget/cocoa/moz.build index 9407117f95ed..4898e1899706 100644 --- a/widget/cocoa/moz.build +++ b/widget/cocoa/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + XPIDL_SOURCES += [ 'nsPIWidgetCocoa.idl', ] diff --git a/widget/gonk/moz.build b/widget/gonk/moz.build index 5ae518e17ab3..16a55c714f73 100644 --- a/widget/gonk/moz.build +++ b/widget/gonk/moz.build @@ -14,6 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget: Gonk") + EXPORTS += [ 'GeckoTouchDispatcher.h', 'GonkPermission.h', diff --git a/widget/gtk/moz.build b/widget/gtk/moz.build index 83cba2d15f61..dbb6363d4969 100644 --- a/widget/gtk/moz.build +++ b/widget/gtk/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget: Gtk") + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3': DIRS += ['mozgtk'] diff --git a/widget/gtkxtbin/moz.build b/widget/gtkxtbin/moz.build index 070aa5777855..1a8d9fcd6b37 100644 --- a/widget/gtkxtbin/moz.build +++ b/widget/gtkxtbin/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget: Gtk") + EXPORTS += [ 'gtk2xtbin.h', ] diff --git a/widget/headless/moz.build b/widget/headless/moz.build index f65fc955a891..6778723a634c 100644 --- a/widget/headless/moz.build +++ b/widget/headless/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget") + DIRS += ['tests'] LOCAL_INCLUDES += [ diff --git a/widget/moz.build b/widget/moz.build index dbf7bcea2e7f..ad8adabe1f57 100644 --- a/widget/moz.build +++ b/widget/moz.build @@ -4,6 +4,30 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget") + +with Files("crashtests/*1128214*"): + BUG_COMPONENT = ("Core", "Layout") + +with Files("crashtests/*303901*"): + BUG_COMPONENT = ("Core", "Graphics") + +with Files("crashtests/*380359*"): + BUG_COMPONENT = ("Core", "Widget") + +with Files("reftests/**"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("reftests/*fallback*"): + BUG_COMPONENT = ("Core", "Layout: Form Controls") + +with Files("*CompositorWidget*"): + BUG_COMPONENT = ("Core", "Graphics") + +with Files("*FontRange*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + toolkit = CONFIG['MOZ_WIDGET_TOOLKIT'] if toolkit in ('cocoa', 'android', 'gonk', 'uikit'): diff --git a/widget/tests/moz.build b/widget/tests/moz.build index 750202b48853..8054ad356cb6 100644 --- a/widget/tests/moz.build +++ b/widget/tests/moz.build @@ -4,6 +4,121 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget") + +with Files("unit/*macwebapputils*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("unit/*taskbar_jumplistitems*"): + BUG_COMPONENT = ("Core", "Widget: Win32") + +with Files("TestAppShellSteadyState.cpp"): + BUG_COMPONENT = ("Core", "DOM: IndexedDB") + +with Files("TestChromeMargin.cpp"): + BUG_COMPONENT = ("Core", "Widget: win32") + +with Files("*1151186*"): + BUG_COMPONENT = ("Core", "Event Handling") + +with Files("*413277*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*428405*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*429954*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*444800*"): + BUG_COMPONENT = ("Core", "Widget: Win32") + +with Files("*466599*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*478536*"): + BUG_COMPONENT = ("Core", "Event Handling") + +with Files("*485118*"): + BUG_COMPONENT = ("Toolkit", "XUL Widgets") + +with Files("*517396*"): + BUG_COMPONENT = ("Toolkit", "XUL Widgets") + +with Files("*522217*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*538242*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*565392*"): + BUG_COMPONENT = ("Core", "Serializers") + +with Files("*586713*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*593307*"): + BUG_COMPONENT = ("Core", "Widget: Win32") + +with Files("*596600*"): + BUG_COMPONENT = ("Core", "Event Handling") + +with Files("*673301*"): + BUG_COMPONENT = ("Firefox", "Bookmarks & History") + +with Files("test_assign_event_data.html"): + BUG_COMPONENT = ("Core", "Event Handling") + +with Files("test_input_events_on_deactive_window.xul"): + BUG_COMPONENT = ("Core", "Event Handling") + +with Files("*chrome_context_menus_win*"): + BUG_COMPONENT = ("Core", "General") + +with Files("*composition_text_querycontent*"): + BUG_COMPONENT = ("Core", "Internationalization") + +with Files("*key_event_counts*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*imestate*"): + BUG_COMPONENT = ("Core", "Internationalization") + +with Files("*mouse_scroll*"): + BUG_COMPONENT = ("Core", "Widget: Win32") + +with Files("*native*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*panel_mouse_coords*"): + BUG_COMPONENT = ("Core", "Widget: Gtk") + +with Files("*picker_no_crash*"): + BUG_COMPONENT = ("Core", "Widget: Win32") + +with Files("*platform_colors*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*plugin*"): + BUG_COMPONENT = ("Core", "Plug-ins") + +with Files("*position_on_resize*"): + BUG_COMPONENT = ("Core", "Widget: Gtk") + +with Files("test_sizemode_events.xul"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*system_status_bar*"): + BUG_COMPONENT = ("Core", "Widget: Cocoa") + +with Files("*taskbar_progress*"): + BUG_COMPONENT = ("Core", "Widget: Win32") + +with Files("*wheeltransaction*"): + BUG_COMPONENT = ("Core", "Event Handling") + + XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini'] MOCHITEST_MANIFESTS += ['mochitest.ini'] MOCHITEST_CHROME_MANIFESTS += ['chrome.ini'] diff --git a/widget/uikit/moz.build b/widget/uikit/moz.build index 50aed405ba4f..b506d4813d13 100644 --- a/widget/uikit/moz.build +++ b/widget/uikit/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget") + SOURCES += [ 'GfxInfo.cpp', 'nsAppShell.mm', diff --git a/widget/windows/moz.build b/widget/windows/moz.build index d1619f3f4e90..3c74cc1ac507 100644 --- a/widget/windows/moz.build +++ b/widget/windows/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget: Win32") + TEST_DIRS += ['tests'] EXPORTS += [ diff --git a/widget/x11/moz.build b/widget/x11/moz.build index 9b5dafb6d71c..9e3eadd38294 100644 --- a/widget/x11/moz.build +++ b/widget/x11/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget: Gtk") + SOURCES += [ 'keysym2ucs.c', ] diff --git a/widget/xremoteclient/moz.build b/widget/xremoteclient/moz.build index 8d3f01c827c9..cdbdb14ca370 100644 --- a/widget/xremoteclient/moz.build +++ b/widget/xremoteclient/moz.build @@ -4,6 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +with Files("**"): + BUG_COMPONENT = ("Core", "Widget") + FINAL_LIBRARY = 'xul' SOURCES += [ From 8051ffb6707406f7a3ea7ab510628d729c5ed772 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 14 Apr 2017 12:26:28 +0200 Subject: [PATCH 16/19] Bug 1353359 part 1 - Add BindNameIRGenerator and use it in Baseline. r=evilpie --HG-- extra : rebase_source : 613d7b790cc840f9ef20c4f99d98be79a60c9f8b --- js/src/jit/BaselineCacheIRCompiler.cpp | 4 +++- js/src/jit/BaselineIC.cpp | 18 ++++++++++++++++++ js/src/jit/CacheIR.cpp | 21 +++++++++++++++++++++ js/src/jit/CacheIR.h | 14 ++++++++++++++ js/src/jit/CodeGenerator.cpp | 1 + js/src/jit/IonCacheIRCompiler.cpp | 1 + js/src/jit/IonIC.cpp | 1 + 7 files changed, 59 insertions(+), 1 deletion(-) diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp index 3898a9958210..b97b6bcfd9dd 100644 --- a/js/src/jit/BaselineCacheIRCompiler.cpp +++ b/js/src/jit/BaselineCacheIRCompiler.cpp @@ -1855,10 +1855,11 @@ BaselineCacheIRCompiler::init(CacheKind kind) allocator.initInputLocation(2, BaselineFrameSlot(0)); break; case CacheKind::GetName: + case CacheKind::BindName: MOZ_ASSERT(numInputs == 1); allocator.initInputLocation(0, R0.scratchReg(), JSVAL_TYPE_OBJECT); #if defined(JS_NUNBOX32) - // availableGeneralRegs can't know that GetName is only using + // availableGeneralRegs can't know that GetName/BindName is only using // the payloadReg and not typeReg on x86. available.add(R0.typeReg()); #endif @@ -1900,6 +1901,7 @@ jit::AttachBaselineCacheIRStub(JSContext* cx, const CacheIRWriter& writer, switch (kind) { case CacheKind::In: case CacheKind::HasOwn: + case CacheKind::BindName: stubDataOffset = sizeof(ICCacheIR_Regular); stubKind = CacheIRStubKind::Regular; break; diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index ab070e068930..a5722e9bea12 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1426,6 +1426,24 @@ DoBindNameFallback(JSContext* cx, BaselineFrame* frame, ICBindName_Fallback* stu RootedPropertyName name(cx, frame->script()->getName(pc)); + if (stub->state().maybeTransition()) + stub->discardStubs(cx); + + if (stub->state().canAttachStub()) { + bool attached = false; + RootedScript script(cx, frame->script()); + BindNameIRGenerator gen(cx, script, pc, stub->state().mode(), envChain, name); + if (gen.tryAttachStub()) { + ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), + ICStubEngine::Baseline, script, stub, + &attached); + if (newStub) + JitSpew(JitSpew_BaselineIC, " Attached CacheIR stub"); + } + if (!attached) + stub->state().trackNotAttached(); + } + RootedObject scope(cx); if (!LookupNameUnqualified(cx, name, envChain, &scope)) return false; diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 697e37d2a32b..43a652c4371d 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -1857,6 +1857,27 @@ GetNameIRGenerator::tryAttachEnvironmentName(ObjOperandId objId, HandleId id) return true; } +BindNameIRGenerator::BindNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, + ICState::Mode mode, HandleObject env, + HandlePropertyName name) + : IRGenerator(cx, script, pc, CacheKind::BindName, mode), + env_(env), + name_(name) +{} + +bool +BindNameIRGenerator::tryAttachStub() +{ + MOZ_ASSERT(cacheKind_ == CacheKind::BindName); + + AutoAssertNoPendingException aanpe(cx_); + + ObjOperandId envId(writer.setInputOperandId(0)); + RootedId id(cx_, NameToId(name_)); + + return false; +} + InIRGenerator::InIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState::Mode mode, HandleValue key, HandleObject obj) : IRGenerator(cx, script, pc, CacheKind::In, mode), diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index 66169a507061..55e2e52900b2 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -139,6 +139,7 @@ class TypedOperandId : public OperandId _(GetName) \ _(SetProp) \ _(SetElem) \ + _(BindName) \ _(In) \ _(HasOwn) @@ -1108,6 +1109,19 @@ class MOZ_RAII GetNameIRGenerator : public IRGenerator bool tryAttachStub(); }; +// BindNameIRGenerator generates CacheIR for a BindName IC. +class MOZ_RAII BindNameIRGenerator : public IRGenerator +{ + HandleObject env_; + HandlePropertyName name_; + + public: + BindNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState::Mode mode, + HandleObject env, HandlePropertyName name); + + bool tryAttachStub(); +}; + // Information used by SetProp/SetElem stubs to check/update property types. class MOZ_RAII PropertyTypeCheckInfo { diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index a6ee16638939..e88fb0826374 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -310,6 +310,7 @@ CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool) return; } case CacheKind::In: + case CacheKind::BindName: MOZ_CRASH("Baseline-specific for now"); case CacheKind::HasOwn: { IonHasOwnIC* hasOwnIC = ic->asHasOwnIC(); diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp index 94be78bf70b4..e67876f355e2 100644 --- a/js/src/jit/IonCacheIRCompiler.cpp +++ b/js/src/jit/IonCacheIRCompiler.cpp @@ -427,6 +427,7 @@ IonCacheIRCompiler::init() break; } case CacheKind::In: + case CacheKind::BindName: MOZ_CRASH("Invalid cache"); case CacheKind::HasOwn: { IonHasOwnIC* ic = ic_->asHasOwnIC(); diff --git a/js/src/jit/IonIC.cpp b/js/src/jit/IonIC.cpp index aea196dac96f..567cec4e7e67 100644 --- a/js/src/jit/IonIC.cpp +++ b/js/src/jit/IonIC.cpp @@ -47,6 +47,7 @@ IonIC::scratchRegisterForEntryJump() case CacheKind::GetName: return asGetNameIC()->temp(); case CacheKind::In: + case CacheKind::BindName: MOZ_CRASH("Baseline-specific for now"); case CacheKind::HasOwn: return asHasOwnIC()->output(); From 8cbcd0470421d2c6cd717f1cbe08028aa283c5d1 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 14 Apr 2017 12:28:14 +0200 Subject: [PATCH 17/19] Bug 1353359 part 2 - Add BindName stub for global (BINDGNAME) lookups. r=evilpie --HG-- extra : rebase_source : 9390a21792ada55e086147eca9ea66743c292cbd --- .../tests/cacheir/bindname-lexical-errors.js | 26 ++++++++++++ js/src/jit/CacheIR.cpp | 42 +++++++++++++++++++ js/src/jit/CacheIR.h | 6 +++ js/src/jit/CacheIRCompiler.cpp | 14 +++++++ js/src/jit/CacheIRCompiler.h | 1 + 5 files changed, 89 insertions(+) create mode 100644 js/src/jit-test/tests/cacheir/bindname-lexical-errors.js diff --git a/js/src/jit-test/tests/cacheir/bindname-lexical-errors.js b/js/src/jit-test/tests/cacheir/bindname-lexical-errors.js new file mode 100644 index 000000000000..d31eecdafb83 --- /dev/null +++ b/js/src/jit-test/tests/cacheir/bindname-lexical-errors.js @@ -0,0 +1,26 @@ +const x = 1; +function testConst() { + for (var i = 0; i < 20; i++) { + try { + x = 2; + } catch (e) { + continue; + } + throw "Fail1"; + } + assertEq(x, 1); +} +testConst(); + +function testUninit() { + for (var i = 0; i < 20; i++) { + try { + y = 2; + } catch (e) { + continue; + } + throw "Fail2"; + } +} +testUninit(); +let y; diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 43a652c4371d..11a01b9802cf 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -1875,9 +1875,51 @@ BindNameIRGenerator::tryAttachStub() ObjOperandId envId(writer.setInputOperandId(0)); RootedId id(cx_, NameToId(name_)); + if (tryAttachGlobalName(envId, id)) + return true; + return false; } +bool +BindNameIRGenerator::tryAttachGlobalName(ObjOperandId objId, HandleId id) +{ + if (!IsGlobalOp(JSOp(*pc_)) || script_->hasNonSyntacticScope()) + return false; + + Handle globalLexical = env_.as(); + MOZ_ASSERT(globalLexical->isGlobal()); + + JSObject* result = nullptr; + if (Shape* shape = globalLexical->lookup(cx_, id)) { + // If this is an uninitialized lexical or a const, we need to return a + // RuntimeLexicalErrorObject. + if (globalLexical->getSlot(shape->slot()).isMagic() || !shape->writable()) + return false; + result = globalLexical; + } else { + result = &globalLexical->global(); + } + + if (result == globalLexical) { + // Lexical bindings are non-configurable so we can just return the + // global lexical. + writer.loadObjectResult(objId); + } else { + // If the property exists on the global and is non-configurable, it cannot be + // shadowed by the lexical scope so we can just return the global without a + // shape guard. + Shape* shape = result->as().lookup(cx_, id); + if (!shape || shape->configurable()) + writer.guardShape(objId, globalLexical->lastProperty()); + ObjOperandId globalId = writer.loadEnclosingEnvironment(objId); + writer.loadObjectResult(globalId); + } + writer.returnFromIC(); + + return true; +} + InIRGenerator::InIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState::Mode mode, HandleValue key, HandleObject obj) : IRGenerator(cx, script, pc, CacheKind::In, mode), diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index 55e2e52900b2..fcb8831ef150 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -237,6 +237,7 @@ extern const char* CacheKindNames[]; _(LoadFrameArgumentResult) \ _(LoadEnvironmentFixedSlotResult) \ _(LoadEnvironmentDynamicSlotResult) \ + _(LoadObjectResult) \ _(CallScriptedGetterResult) \ _(CallNativeGetterResult) \ _(CallProxyGetResult) \ @@ -892,6 +893,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter writeOpWithOperandId(CacheOp::LoadEnvironmentDynamicSlotResult, obj); addStubField(offset, StubField::Type::RawWord); } + void loadObjectResult(ObjOperandId obj) { + writeOpWithOperandId(CacheOp::LoadObjectResult, obj); + } void typeMonitorResult() { writeOp(CacheOp::TypeMonitorResult); @@ -1115,6 +1119,8 @@ class MOZ_RAII BindNameIRGenerator : public IRGenerator HandleObject env_; HandlePropertyName name_; + bool tryAttachGlobalName(ObjOperandId objId, HandleId id); + public: BindNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState::Mode mode, HandleObject env, HandlePropertyName name); diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp index cade3a23dda6..177fee6ce074 100644 --- a/js/src/jit/CacheIRCompiler.cpp +++ b/js/src/jit/CacheIRCompiler.cpp @@ -2109,6 +2109,20 @@ CacheIRCompiler::emitLoadTypedObjectResultShared(const Address& fieldAddr, Regis } } +bool +CacheIRCompiler::emitLoadObjectResult() +{ + AutoOutputRegister output(*this); + Register obj = allocator.useRegister(masm, reader.objOperandId()); + + if (output.hasValue()) + masm.tagValue(JSVAL_TYPE_OBJECT, obj, output.valueReg()); + else + MOZ_CRASH("NYI: Typed LoadObjectResult"); + + return true; +} + void CacheIRCompiler::emitStoreTypedObjectReferenceProp(ValueOperand val, ReferenceTypeDescr::Type type, const Address& dest, Register scratch) diff --git a/js/src/jit/CacheIRCompiler.h b/js/src/jit/CacheIRCompiler.h index 87c21a2d82af..b813c61e1aca 100644 --- a/js/src/jit/CacheIRCompiler.h +++ b/js/src/jit/CacheIRCompiler.h @@ -51,6 +51,7 @@ namespace jit { _(LoadDenseElementHoleExistsResult) \ _(LoadUnboxedArrayElementResult) \ _(LoadTypedElementResult) \ + _(LoadObjectResult) \ _(MegamorphicLoadSlotByValueResult) \ _(MegamorphicHasOwnResult) \ _(WrapResult) From 5191a73fa3b0ec7d17956c1128a357d9f3eb6540 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 14 Apr 2017 12:28:35 +0200 Subject: [PATCH 18/19] Bug 1353359 part 3 - Add BindName stub for non-global (BINDNAME) lookups. r=evilpie --HG-- extra : rebase_source : 543330c6037b30dddd61754d76d5fb9203ac162c --- js/src/jit/CacheIR.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++ js/src/jit/CacheIR.h | 1 + 2 files changed, 62 insertions(+) diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 11a01b9802cf..2862f79bb90d 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -1877,6 +1877,8 @@ BindNameIRGenerator::tryAttachStub() if (tryAttachGlobalName(envId, id)) return true; + if (tryAttachEnvironmentName(envId, id)) + return true; return false; } @@ -1920,6 +1922,65 @@ BindNameIRGenerator::tryAttachGlobalName(ObjOperandId objId, HandleId id) return true; } +bool +BindNameIRGenerator::tryAttachEnvironmentName(ObjOperandId objId, HandleId id) +{ + if (IsGlobalOp(JSOp(*pc_)) || script_->hasNonSyntacticScope()) + return false; + + RootedObject env(cx_, env_); + RootedShape shape(cx_); + while (true) { + if (!env->is() && !env->is()) + return false; + if (env->is()) + return false; + + MOZ_ASSERT(!env->hasUncacheableProto()); + + // When we reach an unqualified variables object (like the global) we + // have to stop looking and return that object. + if (env->isUnqualifiedVarObj()) + break; + + // Check for an 'own' property on the env. There is no need to + // check the prototype as non-with scopes do not inherit properties + // from any prototype. + shape = env->as().lookup(cx_, id); + if (shape) + break; + + env = env->enclosingEnvironment(); + } + + // If this is an uninitialized lexical or a const, we need to return a + // RuntimeLexicalErrorObject. + RootedNativeObject holder(cx_, &env->as()); + if (shape && + holder->is() && + (holder->getSlot(shape->slot()).isMagic() || !shape->writable())) + { + return false; + } + + ObjOperandId lastObjId = objId; + env = env_; + while (env) { + if (NeedEnvironmentShapeGuard(env) && !env->is()) + writer.guardShape(lastObjId, env->maybeShape()); + + if (env == holder) + break; + + lastObjId = writer.loadEnclosingEnvironment(lastObjId); + env = env->enclosingEnvironment(); + } + writer.loadObjectResult(lastObjId); + writer.returnFromIC(); + + return true; +} + InIRGenerator::InIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState::Mode mode, HandleValue key, HandleObject obj) : IRGenerator(cx, script, pc, CacheKind::In, mode), diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index fcb8831ef150..4a2243959bdc 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -1120,6 +1120,7 @@ class MOZ_RAII BindNameIRGenerator : public IRGenerator HandlePropertyName name_; bool tryAttachGlobalName(ObjOperandId objId, HandleId id); + bool tryAttachEnvironmentName(ObjOperandId objId, HandleId id); public: BindNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState::Mode mode, From 082b553b4c3f667286a861cdf3b9aa20d4be75bf Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 14 Apr 2017 12:29:15 +0200 Subject: [PATCH 19/19] Bug 1353359 part 4 - Use BindName IC in Ion and remove the old IonCache infrastructure. r=evilpie --HG-- extra : rebase_source : e2c081588b4658b5098f937a97a3897fe6eb622f --- js/src/gc/Verifier.cpp | 2 - js/src/gc/Zone.cpp | 114 +++--- js/src/jit/CacheIRCompiler.cpp | 2 +- js/src/jit/CodeGenerator.cpp | 141 ++----- js/src/jit/CodeGenerator.h | 4 - js/src/jit/Ion.cpp | 52 +-- js/src/jit/Ion.h | 1 - js/src/jit/IonCacheIRCompiler.cpp | 15 +- js/src/jit/IonCaches.cpp | 487 ----------------------- js/src/jit/IonCaches.h | 386 ------------------ js/src/jit/IonCode.h | 32 +- js/src/jit/IonIC.cpp | 37 +- js/src/jit/IonIC.h | 31 ++ js/src/jit/Lowering.cpp | 2 +- js/src/jit/shared/CodeGenerator-shared.h | 22 - js/src/jit/shared/LIR-shared.h | 8 +- js/src/jsgc.cpp | 8 - js/src/jsgc.h | 3 - 18 files changed, 171 insertions(+), 1176 deletions(-) diff --git a/js/src/gc/Verifier.cpp b/js/src/gc/Verifier.cpp index f77addbf67f5..a02d13e34ab4 100644 --- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -246,7 +246,6 @@ gc::GCRuntime::startVerifyPreBarriers() for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { MOZ_ASSERT(!zone->usedByHelperThread()); - PurgeJITCaches(zone); zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit); zone->arenas.purge(); } @@ -342,7 +341,6 @@ gc::GCRuntime::endVerifyPreBarriers() compartmentCreated = true; zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit); - PurgeJITCaches(zone); } /* diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 1cc9eedccf24..073fb46b2156 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -192,69 +192,67 @@ Zone::discardJitCode(FreeOp* fop, bool discardBaselineCode) if (!jitZone()) return; - if (isPreservingCode()) { - PurgeJITCaches(this); - } else { + if (isPreservingCode()) + return; - if (discardBaselineCode) { + if (discardBaselineCode) { #ifdef DEBUG - /* Assert no baseline scripts are marked as active. */ - for (auto script = cellIter(); !script.done(); script.next()) - MOZ_ASSERT_IF(script->hasBaselineScript(), !script->baselineScript()->active()); + /* Assert no baseline scripts are marked as active. */ + for (auto script = cellIter(); !script.done(); script.next()) + MOZ_ASSERT_IF(script->hasBaselineScript(), !script->baselineScript()->active()); #endif - /* Mark baseline scripts on the stack as active. */ - jit::MarkActiveBaselineScripts(this); - } - - /* Only mark OSI points if code is being discarded. */ - jit::InvalidateAll(fop, this); - - for (auto script = cellIter(); !script.done(); script.next()) { - jit::FinishInvalidation(fop, script); - - /* - * Discard baseline script if it's not marked as active. Note that - * this also resets the active flag. - */ - if (discardBaselineCode) - jit::FinishDiscardBaselineScript(fop, script); - - /* - * Warm-up counter for scripts are reset on GC. After discarding code we - * need to let it warm back up to get information such as which - * opcodes are setting array holes or accessing getter properties. - */ - script->resetWarmUpCounter(); - - /* - * Make it impossible to use the control flow graphs cached on the - * BaselineScript. They get deleted. - */ - if (script->hasBaselineScript()) - script->baselineScript()->setControlFlowGraph(nullptr); - } - - /* - * When scripts contains pointers to nursery things, the store buffer - * can contain entries that point into the optimized stub space. Since - * this method can be called outside the context of a GC, this situation - * could result in us trying to mark invalid store buffer entries. - * - * Defer freeing any allocated blocks until after the next minor GC. - */ - if (discardBaselineCode) { - jitZone()->optimizedStubSpace()->freeAllAfterMinorGC(this); - jitZone()->purgeIonCacheIRStubInfo(); - } - - /* - * Free all control flow graphs that are cached on BaselineScripts. - * Assuming this happens on the active thread and all control flow - * graph reads happen on the active thread, this is safe. - */ - jitZone()->cfgSpace()->lifoAlloc().freeAll(); + /* Mark baseline scripts on the stack as active. */ + jit::MarkActiveBaselineScripts(this); } + + /* Only mark OSI points if code is being discarded. */ + jit::InvalidateAll(fop, this); + + for (auto script = cellIter(); !script.done(); script.next()) { + jit::FinishInvalidation(fop, script); + + /* + * Discard baseline script if it's not marked as active. Note that + * this also resets the active flag. + */ + if (discardBaselineCode) + jit::FinishDiscardBaselineScript(fop, script); + + /* + * Warm-up counter for scripts are reset on GC. After discarding code we + * need to let it warm back up to get information such as which + * opcodes are setting array holes or accessing getter properties. + */ + script->resetWarmUpCounter(); + + /* + * Make it impossible to use the control flow graphs cached on the + * BaselineScript. They get deleted. + */ + if (script->hasBaselineScript()) + script->baselineScript()->setControlFlowGraph(nullptr); + } + + /* + * When scripts contains pointers to nursery things, the store buffer + * can contain entries that point into the optimized stub space. Since + * this method can be called outside the context of a GC, this situation + * could result in us trying to mark invalid store buffer entries. + * + * Defer freeing any allocated blocks until after the next minor GC. + */ + if (discardBaselineCode) { + jitZone()->optimizedStubSpace()->freeAllAfterMinorGC(this); + jitZone()->purgeIonCacheIRStubInfo(); + } + + /* + * Free all control flow graphs that are cached on BaselineScripts. + * Assuming this happens on the active thread and all control flow + * graph reads happen on the active thread, this is safe. + */ + jitZone()->cfgSpace()->lifoAlloc().freeAll(); } #ifdef JSGC_HASH_TABLE_CHECKS diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp index 177fee6ce074..a33b7888adf6 100644 --- a/js/src/jit/CacheIRCompiler.cpp +++ b/js/src/jit/CacheIRCompiler.cpp @@ -2118,7 +2118,7 @@ CacheIRCompiler::emitLoadObjectResult() if (output.hasValue()) masm.tagValue(JSVAL_TYPE_OBJECT, obj, output.valueReg()); else - MOZ_CRASH("NYI: Typed LoadObjectResult"); + masm.mov(obj, output.typedReg().gpr()); return true; } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index e88fb0826374..e107bb1df494 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -70,53 +70,6 @@ using JS::GenericNaN; namespace js { namespace jit { -// This out-of-line cache is used to do a double dispatch including it-self and -// the wrapped IonCache. -class OutOfLineUpdateCache : - public OutOfLineCodeBase, - public IonCacheVisitor -{ - private: - LInstruction* lir_; - size_t cacheIndex_; - RepatchLabel entry_; - - public: - OutOfLineUpdateCache(LInstruction* lir, size_t cacheIndex) - : lir_(lir), - cacheIndex_(cacheIndex) - { } - - void bind(MacroAssembler* masm) { - // The binding of the initial jump is done in - // CodeGenerator::visitOutOfLineCache. - } - - size_t getCacheIndex() const { - return cacheIndex_; - } - LInstruction* lir() const { - return lir_; - } - RepatchLabel& entry() { - return entry_; - } - - void accept(CodeGenerator* codegen) { - codegen->visitOutOfLineCache(this); - } - - // ICs' visit functions delegating the work to the CodeGen visit funtions. -#define VISIT_CACHE_FUNCTION(op) \ - void visit##op##IC(CodeGenerator* codegen) { \ - CodeGenerator::DataPtr ic(codegen, getCacheIndex()); \ - codegen->visit##op##IC(this, ic); \ - } - - IONCACHE_KIND_LIST(VISIT_CACHE_FUNCTION) -#undef VISIT_CACHE_FUNCTION -}; - class OutOfLineICFallback : public OutOfLineCodeBase { private: @@ -151,33 +104,6 @@ class OutOfLineICFallback : public OutOfLineCodeBase } }; -// This function is declared here because it needs to instantiate an -// OutOfLineUpdateCache, but we want to keep it visible inside the -// CodeGeneratorShared such as we can specialize inline caches in function of -// the architecture. -void -CodeGeneratorShared::addCache(LInstruction* lir, size_t cacheIndex) -{ - if (cacheIndex == SIZE_MAX) { - masm.setOOM(); - return; - } - - DataPtr cache(this, cacheIndex); - MInstruction* mir = lir->mirRaw()->toInstruction(); - if (mir->resumePoint()) - cache->setScriptedLocation(mir->block()->info().script(), - mir->resumePoint()->pc()); - else - cache->setIdempotent(); - - OutOfLineUpdateCache* ool = new(alloc()) OutOfLineUpdateCache(lir, cacheIndex); - addOutOfLineCode(ool, mir); - - cache->emitInitialJump(masm, ool->entry()); - masm.bind(ool->rejoin()); -} - void CodeGeneratorShared::addIC(LInstruction* lir, size_t cacheIndex) { @@ -208,19 +134,6 @@ CodeGeneratorShared::addIC(LInstruction* lir, size_t cacheIndex) cache->setRejoinLabel(CodeOffset(ool->rejoin()->offset())); } -void -CodeGenerator::visitOutOfLineCache(OutOfLineUpdateCache* ool) -{ - DataPtr cache(this, ool->getCacheIndex()); - - // Register the location of the OOL path in the IC. - cache->setFallbackLabel(masm.labelForPatch()); - masm.bind(&ool->entry()); - - // Dispatch to ICs' accept functions. - cache->accept(this, ool); -} - typedef bool (*IonGetPropertyICFn)(JSContext*, HandleScript, IonGetPropertyIC*, HandleValue, HandleValue, MutableHandleValue); static const VMFunction IonGetPropertyICInfo = @@ -241,6 +154,10 @@ typedef bool (*IonHasOwnICFn)(JSContext*, HandleScript, IonHasOwnIC*, HandleValu static const VMFunction IonHasOwnICInfo = FunctionInfo(IonHasOwnIC::update, "IonHasOwnIC::update"); +typedef JSObject* (*IonBindNameICFn)(JSContext*, HandleScript, IonBindNameIC*, HandleObject); +static const VMFunction IonBindNameICInfo = + FunctionInfo(IonBindNameIC::update, "IonBindNameIC::update"); + void CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool) { @@ -309,8 +226,24 @@ CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool) masm.jump(ool->rejoin()); return; } + case CacheKind::BindName: { + IonBindNameIC* bindNameIC = ic->asBindNameIC(); + + saveLive(lir); + + pushArg(bindNameIC->environment()); + icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1)); + pushArg(ImmGCPtr(gen->info().script())); + + callVM(IonBindNameICInfo, lir); + + StoreRegisterTo(bindNameIC->output()).generate(this); + restoreLiveIgnore(lir, StoreRegisterTo(bindNameIC->output()).clobbered()); + + masm.jump(ool->rejoin()); + return; + } case CacheKind::In: - case CacheKind::BindName: MOZ_CRASH("Baseline-specific for now"); case CacheKind::HasOwn: { IonHasOwnIC* hasOwnIC = ic->asHasOwnIC(); @@ -9626,7 +9559,6 @@ CodeGenerator::generateWasm(wasm::SigIdDesc sigId, wasm::BytecodeOffset trapOffs MOZ_ASSERT(graph.numConstants() == 0); MOZ_ASSERT(safepointIndices_.empty()); MOZ_ASSERT(osiIndices_.empty()); - MOZ_ASSERT(cacheList_.empty()); MOZ_ASSERT(icList_.empty()); MOZ_ASSERT(safepoints_.size() == 0); MOZ_ASSERT(!scriptCounts_); @@ -9848,7 +9780,7 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints) snapshots_.listSize(), snapshots_.RVATableSize(), recovers_.size(), bailouts_.length(), graph.numConstants(), safepointIndices_.length(), osiIndices_.length(), - cacheList_.length(), icList_.length(), runtimeData_.length(), + icList_.length(), runtimeData_.length(), safepoints_.size(), patchableBackedges_.length(), sharedStubs_.length(), optimizationLevel); if (!ionScript) @@ -10013,8 +9945,6 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints) // for generating inline caches during the execution. if (runtimeData_.length()) ionScript->copyRuntimeData(&runtimeData_[0]); - if (cacheList_.length()) - ionScript->copyCacheEntries(&cacheList_[0], masm); if (icList_.length()) ionScript->copyICEntries(&icList_[0], masm); @@ -10412,32 +10342,13 @@ CodeGenerator::visitGetPropertyCacheT(LGetPropertyCacheT* ins) void CodeGenerator::visitBindNameCache(LBindNameCache* ins) { + LiveRegisterSet liveRegs = ins->safepoint()->liveRegs(); Register envChain = ToRegister(ins->environmentChain()); Register output = ToRegister(ins->output()); - BindNameIC cache(envChain, ins->mir()->name(), output); - cache.setProfilerLeavePC(ins->mir()->profilerLeavePc()); + Register temp = ToRegister(ins->temp()); - addCache(ins, allocateCache(cache)); -} - -typedef JSObject* (*BindNameICFn)(JSContext*, HandleScript, size_t, HandleObject); -const VMFunction BindNameIC::UpdateInfo = - FunctionInfo(BindNameIC::update, "BindNameIC::update"); - -void -CodeGenerator::visitBindNameIC(OutOfLineUpdateCache* ool, DataPtr& ic) -{ - LInstruction* lir = ool->lir(); - saveLive(lir); - - pushArg(ic->environmentChainReg()); - pushArg(Imm32(ool->getCacheIndex())); - pushArg(ImmGCPtr(gen->info().script())); - callVM(BindNameIC::UpdateInfo, lir); - StoreRegisterTo(ic->outputReg()).generate(this); - restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered()); - - masm.jump(ool->rejoin()); + IonBindNameIC ic(liveRegs, envChain, output, temp); + addIC(ins, allocateIC(ic)); } void diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index edc69cb2bf56..058d5b7341f2 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -412,8 +412,6 @@ class CodeGenerator final : public CodeGeneratorSpecific void loadJSScriptForBlock(MBasicBlock* block, Register reg); void loadOutermostJSScript(Register reg); - // Inline caches visitors. - void visitOutOfLineCache(OutOfLineUpdateCache* ool); void visitOutOfLineICFallback(OutOfLineICFallback* ool); void visitGetPropertyCacheV(LGetPropertyCacheV* ins); @@ -424,8 +422,6 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitGetNameCache(LGetNameCache* ins); void visitHasOwnCache(LHasOwnCache* ins); - void visitBindNameIC(OutOfLineUpdateCache* ool, DataPtr& ic); - void visitAssertRangeI(LAssertRangeI* ins); void visitAssertRangeD(LAssertRangeD* ins); void visitAssertRangeF(LAssertRangeF* ins); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 8299ac86030f..4e263bbfd1e3 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -859,8 +859,6 @@ IonScript::IonScript() recompiling_(false), runtimeData_(0), runtimeSize_(0), - cacheIndex_(0), - cacheEntries_(0), icIndex_(0), icEntries_(0), safepointIndexOffset_(0), @@ -893,7 +891,7 @@ IonScript::New(JSContext* cx, RecompileInfo recompileInfo, size_t snapshotsListSize, size_t snapshotsRVATableSize, size_t recoversSize, size_t bailoutEntries, size_t constants, size_t safepointIndices, - size_t osiIndices, size_t cacheEntries, size_t icEntries, + size_t osiIndices, size_t icEntries, size_t runtimeSize, size_t safepointsSize, size_t backedgeEntries, size_t sharedStubEntries, OptimizationLevel optimizationLevel) @@ -916,7 +914,6 @@ IonScript::New(JSContext* cx, RecompileInfo recompileInfo, size_t paddedConstantsSize = AlignBytes(constants * sizeof(Value), DataAlignment); size_t paddedSafepointIndicesSize = AlignBytes(safepointIndices * sizeof(SafepointIndex), DataAlignment); size_t paddedOsiIndicesSize = AlignBytes(osiIndices * sizeof(OsiIndex), DataAlignment); - size_t paddedCacheEntriesSize = AlignBytes(cacheEntries * sizeof(uint32_t), DataAlignment); size_t paddedICEntriesSize = AlignBytes(icEntries * sizeof(uint32_t), DataAlignment); size_t paddedRuntimeSize = AlignBytes(runtimeSize, DataAlignment); size_t paddedSafepointSize = AlignBytes(safepointsSize, DataAlignment); @@ -929,7 +926,6 @@ IonScript::New(JSContext* cx, RecompileInfo recompileInfo, paddedConstantsSize + paddedSafepointIndicesSize + paddedOsiIndicesSize + - paddedCacheEntriesSize + paddedICEntriesSize + paddedRuntimeSize + paddedSafepointSize + @@ -946,10 +942,6 @@ IonScript::New(JSContext* cx, RecompileInfo recompileInfo, script->runtimeSize_ = runtimeSize; offsetCursor += paddedRuntimeSize; - script->cacheIndex_ = offsetCursor; - script->cacheEntries_ = cacheEntries; - offsetCursor += paddedCacheEntriesSize; - script->icIndex_ = offsetCursor; script->icEntries_ = icEntries; offsetCursor += paddedICEntriesSize; @@ -1028,9 +1020,6 @@ IonScript::trace(JSTracer* trc) } // Trace caches so that the JSScript pointer can be updated if moved. - for (size_t i = 0; i < numCaches(); i++) - getCacheFromIndex(i).trace(trc); - for (size_t i = 0; i < numICs(); i++) getICFromIndex(i).trace(trc); } @@ -1133,18 +1122,6 @@ IonScript::copyRuntimeData(const uint8_t* data) memcpy(runtimeData(), data, runtimeSize()); } -void -IonScript::copyCacheEntries(const uint32_t* caches, MacroAssembler& masm) -{ - memcpy(cacheIndex(), caches, numCaches() * sizeof(uint32_t)); - - // Jumps in the caches reflect the offset of those jumps in the compiled - // code, not the absolute positions of the jumps. Update according to the - // final code address now. - for (size_t i = 0; i < numCaches(); i++) - getCacheFromIndex(i).updateBaseAddress(method_, masm); -} - void IonScript::copyICEntries(const uint32_t* icEntries, MacroAssembler& masm) { @@ -1331,25 +1308,6 @@ IonScript::purgeOptimizedStubs(Zone* zone) #endif } -void -IonScript::purgeCaches() -{ - // Don't reset any ICs if we're invalidated, otherwise, repointing the - // inline jump could overwrite an invalidation marker. These ICs can - // no longer run, however, the IC slow paths may be active on the stack. - // ICs therefore are required to check for invalidation before patching, - // to ensure the same invariant. - if (invalidated()) - return; - - if (numCaches() == 0) - return; - - AutoWritableJitCode awjc(method()); - for (size_t i = 0; i < numCaches(); i++) - getCacheFromIndex(i).reset(DontReprotect); -} - void IonScript::purgeICs(Zone* zone) { @@ -3122,7 +3080,6 @@ InvalidateActivation(FreeOp* fop, const JitActivationIterator& activations, bool // Purge ICs before we mark this script as invalidated. This will // prevent lastJump_ from appearing to be a bogus pointer, just // in case anyone tries to read it. - ionScript->purgeCaches(); ionScript->purgeICs(script->zone()); ionScript->purgeOptimizedStubs(script->zone()); @@ -3531,13 +3488,6 @@ AutoFlushICache::~AutoFlushICache() #endif } -void -jit::PurgeCaches(JSScript* script) -{ - if (script->hasIonScript()) - script->ionScript()->purgeCaches(); -} - size_t jit::SizeOfIonData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf) { diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index 2116857f1cf2..acc88e242018 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -214,7 +214,6 @@ bool OffThreadCompilationAvailable(JSContext* cx); void ForbidCompilation(JSContext* cx, JSScript* script); -void PurgeCaches(JSScript* script); size_t SizeOfIonData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf); void DestroyJitScripts(FreeOp* fop, JSScript* script); void TraceJitScripts(JSTracer* trc, JSScript* script); diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp index e67876f355e2..b7db57f95435 100644 --- a/js/src/jit/IonCacheIRCompiler.cpp +++ b/js/src/jit/IonCacheIRCompiler.cpp @@ -426,8 +426,21 @@ IonCacheIRCompiler::init() allocator.initInputLocation(0, ic->environment(), JSVAL_TYPE_OBJECT); break; } + case CacheKind::BindName: { + IonBindNameIC* ic = ic_->asBindNameIC(); + Register output = ic->output(); + + available.add(output); + available.add(ic->temp()); + + liveRegs_.emplace(ic->liveRegs()); + outputUnchecked_.emplace(TypedOrValueRegister(MIRType::Object, AnyRegister(output))); + + MOZ_ASSERT(numInputs == 1); + allocator.initInputLocation(0, ic->environment(), JSVAL_TYPE_OBJECT); + break; + } case CacheKind::In: - case CacheKind::BindName: MOZ_CRASH("Invalid cache"); case CacheKind::HasOwn: { IonHasOwnIC* ic = ic_->asHasOwnIC(); diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index d0f7f8b3f107..391dbea1c0a0 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -38,8 +38,6 @@ using namespace js::jit; using mozilla::tl::FloorLog2; -typedef Rooted RootedTypedArrayObject; - void CodeLocationJump::repoint(JitCode* code, MacroAssembler* masm) { @@ -89,308 +87,6 @@ CodeOffsetJump::fixup(MacroAssembler* masm) #endif } -const char* -IonCache::CacheName(IonCache::Kind kind) -{ - static const char * const names[] = - { -#define NAME(x) #x, - IONCACHE_KIND_LIST(NAME) -#undef NAME - }; - return names[kind]; -} - -const size_t IonCache::MAX_STUBS = 16; - -// Helper class which encapsulates logic to attach a stub to an IC by hooking -// up rejoins and next stub jumps. -// -// The simplest stubs have a single jump to the next stub and look like the -// following: -// -// branch guard NEXTSTUB -// ... IC-specific code ... -// jump REJOIN -// -// This corresponds to: -// -// attacher.branchNextStub(masm, ...); -// ... emit IC-specific code ... -// attacher.jumpRejoin(masm); -// -// Whether the stub needs multiple next stub jumps look like: -// -// branch guard FAILURES -// ... IC-specific code ... -// branch another-guard FAILURES -// ... IC-specific code ... -// jump REJOIN -// FAILURES: -// jump NEXTSTUB -// -// This corresponds to: -// -// Label failures; -// masm.branchX(..., &failures); -// ... emit IC-specific code ... -// masm.branchY(..., failures); -// ... emit more IC-specific code ... -// attacher.jumpRejoin(masm); -// masm.bind(&failures); -// attacher.jumpNextStub(masm); -// -// A convenience function |branchNextStubOrLabel| is provided in the case that -// the stub sometimes has multiple next stub jumps and sometimes a single -// one. If a non-nullptr label is passed in, a |branchPtr| will be made to -// that label instead of a |branchPtrWithPatch| to the next stub. -class IonCache::StubAttacher -{ - protected: - bool hasNextStubOffset_ : 1; - bool hasStubCodePatchOffset_ : 1; - - IonCache& cache_; - - CodeLocationLabel rejoinLabel_; - CodeOffsetJump nextStubOffset_; - CodeOffsetJump rejoinOffset_; - CodeOffset stubCodePatchOffset_; - - public: - explicit StubAttacher(IonCache& cache) - : hasNextStubOffset_(false), - hasStubCodePatchOffset_(false), - cache_(cache), - rejoinLabel_(cache.rejoinLabel_), - nextStubOffset_(), - rejoinOffset_(), - stubCodePatchOffset_() - { } - - // Value used instead of the JitCode self-reference of generated - // stubs. This value is needed for marking calls made inside stubs. This - // value would be replaced by the attachStub function after the allocation - // of the JitCode. The self-reference is used to keep the stub path alive - // even if the IonScript is invalidated or if the IC is flushed. - static const void* const STUB_ADDR; - - template - void branchNextStub(MacroAssembler& masm, Assembler::Condition cond, T1 op1, T2 op2) { - MOZ_ASSERT(!hasNextStubOffset_); - RepatchLabel nextStub; - nextStubOffset_ = masm.branchPtrWithPatch(cond, op1, op2, &nextStub); - hasNextStubOffset_ = true; - masm.bind(&nextStub); - } - - template - void branchNextStubOrLabel(MacroAssembler& masm, Assembler::Condition cond, T1 op1, T2 op2, - Label* label) - { - if (label != nullptr) - masm.branchPtr(cond, op1, op2, label); - else - branchNextStub(masm, cond, op1, op2); - } - - void jumpRejoin(MacroAssembler& masm) { - RepatchLabel rejoin; - rejoinOffset_ = masm.jumpWithPatch(&rejoin); - masm.bind(&rejoin); - } - - void jumpNextStub(MacroAssembler& masm) { - MOZ_ASSERT(!hasNextStubOffset_); - RepatchLabel nextStub; - nextStubOffset_ = masm.jumpWithPatch(&nextStub); - hasNextStubOffset_ = true; - masm.bind(&nextStub); - } - - void pushStubCodePointer(MacroAssembler& masm) { - // Push the JitCode pointer for the stub we're generating. - // WARNING: - // WARNING: If JitCode ever becomes relocatable, the following code is incorrect. - // WARNING: Note that we're not marking the pointer being pushed as an ImmGCPtr. - // WARNING: This location will be patched with the pointer of the generated stub, - // WARNING: such as it can be marked when a call is made with this stub. Be aware - // WARNING: that ICs are not marked and so this stub will only be kept alive iff - // WARNING: it is on the stack at the time of the GC. No ImmGCPtr is needed as the - // WARNING: stubs are flushed on GC. - // WARNING: - MOZ_ASSERT(!hasStubCodePatchOffset_); - stubCodePatchOffset_ = masm.PushWithPatch(ImmPtr(STUB_ADDR)); - hasStubCodePatchOffset_ = true; - } - - void patchRejoinJump(MacroAssembler& masm, JitCode* code) { - rejoinOffset_.fixup(&masm); - CodeLocationJump rejoinJump(code, rejoinOffset_); - PatchJump(rejoinJump, rejoinLabel_); - } - - void patchStubCodePointer(JitCode* code) { - if (hasStubCodePatchOffset_) { - Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, stubCodePatchOffset_), - ImmPtr(code), ImmPtr(STUB_ADDR)); - } - } - - void patchNextStubJump(MacroAssembler& masm, JitCode* code) { - // If this path is not taken, we are producing an entry which can no - // longer go back into the update function. - if (hasNextStubOffset_) { - nextStubOffset_.fixup(&masm); - CodeLocationJump nextStubJump(code, nextStubOffset_); - PatchJump(nextStubJump, cache_.fallbackLabel_); - - // When the last stub fails, it fallback to the ool call which can - // produce a stub. Next time we generate a stub, we will patch the - // nextStub jump to try the new stub. - cache_.lastJump_ = nextStubJump; - } - } -}; - -const void* const IonCache::StubAttacher::STUB_ADDR = (void*)0xdeadc0de; - -void -IonCache::emitInitialJump(MacroAssembler& masm, RepatchLabel& entry) -{ - initialJump_ = masm.jumpWithPatch(&entry); - lastJump_ = initialJump_; - Label label; - masm.bind(&label); - rejoinLabel_ = CodeOffset(label.offset()); -} - -void -IonCache::attachStub(MacroAssembler& masm, StubAttacher& attacher, CodeLocationJump lastJump, - Handle code) -{ - MOZ_ASSERT(canAttachStub()); - incrementStubCount(); - - // Patch the previous nextStubJump of the last stub, or the jump from the - // codeGen, to jump into the newly allocated code. - PatchJump(lastJump, CodeLocationLabel(code), Reprotect); -} - -IonCache::LinkStatus -IonCache::linkCode(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher, IonScript* ion, - JitCode** code) -{ - Linker linker(masm); - *code = linker.newCode(cx, ION_CODE); - if (!*code) - return LINK_ERROR; - - if (ion->invalidated()) - return CACHE_FLUSHED; - - // Update the success path to continue after the IC initial jump. - attacher.patchRejoinJump(masm, *code); - - // Replace the STUB_ADDR constant by the address of the generated stub, such - // as it can be kept alive even if the cache is flushed (see - // MarkJitExitFrame). - attacher.patchStubCodePointer(*code); - - // Update the failure path. - attacher.patchNextStubJump(masm, *code); - - return LINK_GOOD; -} - -bool -IonCache::linkAndAttachStub(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher, - IonScript* ion, const char* attachKind, - JS::TrackedOutcome trackedOutcome) -{ - CodeLocationJump lastJumpBefore = lastJump_; - Rooted code(cx); - { - // Need to exit the AutoFlushICache context to flush the cache - // before attaching the stub below. - AutoFlushICache afc("IonCache"); - LinkStatus status = linkCode(cx, masm, attacher, ion, code.address()); - if (status != LINK_GOOD) - return status != LINK_ERROR; - } - - if (pc_) { - JitSpew(JitSpew_IonIC, "Cache %p(%s:%" PRIuSIZE "/%" PRIuSIZE ") generated %s %s stub at %p", - this, script_->filename(), script_->lineno(), script_->pcToOffset(pc_), - attachKind, CacheName(kind()), code->raw()); - } else { - JitSpew(JitSpew_IonIC, "Cache %p generated %s %s stub at %p", - this, attachKind, CacheName(kind()), code->raw()); - } - -#ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(code, "IonCache"); -#endif - - attachStub(masm, attacher, lastJumpBefore, code); - - // Add entry to native => bytecode mapping for this stub if needed. - if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime())) { - JitcodeGlobalEntry::IonCacheEntry entry; - entry.init(code, code->raw(), code->rawEnd(), rejoinAddress(), trackedOutcome); - - // Add entry to the global table. - JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable(); - if (!globalTable->addEntry(entry, cx->runtime())) { - entry.destroy(); - ReportOutOfMemory(cx); - return false; - } - - // Mark the jitcode as having a bytecode map. - code->setHasBytecodeMap(); - } else { - JitcodeGlobalEntry::DummyEntry entry; - entry.init(code, code->raw(), code->rawEnd()); - - // Add entry to the global table. - JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable(); - if (!globalTable->addEntry(entry, cx->runtime())) { - entry.destroy(); - ReportOutOfMemory(cx); - return false; - } - - // Mark the jitcode as having a bytecode map. - code->setHasBytecodeMap(); - } - - // Report masm OOM errors here, so all our callers can: - // return linkAndAttachStub(...); - if (masm.oom()) { - ReportOutOfMemory(cx); - return false; - } - - return true; -} - -void -IonCache::updateBaseAddress(JitCode* code, MacroAssembler& masm) -{ - fallbackLabel_.repoint(code, &masm); - initialJump_.repoint(code, &masm); - lastJump_.repoint(code, &masm); - rejoinLabel_.repoint(code, &masm); -} - -void -IonCache::trace(JSTracer* trc) -{ - if (script_) - TraceManuallyBarrieredEdge(trc, &script_, "IonCache::script_"); -} - void* jit::GetReturnAddressToIonCode(JSContext* cx) { @@ -523,21 +219,6 @@ jit::ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id, return true; } -void -IonCache::disable() -{ - reset(Reprotect); - this->disabled_ = 1; -} - -void -IonCache::reset(ReprotectCode reprotect) -{ - this->stubCount_ = 0; - PatchJump(initialJump_, fallbackLabel_, reprotect); - lastJump_ = initialJump_; -} - bool jit::IsCacheableSetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape) { @@ -642,171 +323,3 @@ jit::EmitIonStoreDenseElement(MacroAssembler& masm, const ConstantOrRegister& va masm.bind(&done); } - -bool -BindNameIC::attachGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion, - HandleObject envChain) -{ - MOZ_ASSERT(envChain->is()); - - MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_); - StubAttacher attacher(*this); - - // Guard on the env chain. - attacher.branchNextStub(masm, Assembler::NotEqual, environmentChainReg(), - ImmGCPtr(envChain)); - masm.movePtr(ImmGCPtr(envChain), outputReg()); - - attacher.jumpRejoin(masm); - - return linkAndAttachStub(cx, masm, attacher, ion, "global"); -} - -static inline void -GenerateEnvironmentChainGuard(MacroAssembler& masm, JSObject* envObj, - Register envObjReg, Shape* shape, Label* failures) -{ - if (envObj->is()) { - // We can skip a guard on the call object if the script's bindings are - // guaranteed to be immutable (and thus cannot introduce shadowing - // variables). - CallObject* callObj = &envObj->as(); - JSFunction* fun = &callObj->callee(); - // The function might have been relazified under rare conditions. - // In that case, we pessimistically create the guard, as we'd - // need to root various pointers to delazify, - if (fun->hasScript()) { - JSScript* script = fun->nonLazyScript(); - if (!script->funHasExtensibleScope()) - return; - } - } else if (envObj->is()) { - // If this is the last object on the scope walk, and the property we've - // found is not configurable, then we don't need a shape guard because - // the shape cannot be removed. - if (shape && !shape->configurable()) - return; - } - - Address shapeAddr(envObjReg, ShapedObject::offsetOfShape()); - masm.branchPtr(Assembler::NotEqual, shapeAddr, - ImmGCPtr(envObj->as().lastProperty()), failures); -} - -static void -GenerateEnvironmentChainGuards(MacroAssembler& masm, JSObject* envChain, JSObject* holder, - Register outputReg, Label* failures, bool skipLastGuard = false) -{ - JSObject* tobj = envChain; - - // Walk up the env chain. Note that IsCacheableEnvironmentChain guarantees the - // |tobj == holder| condition terminates the loop. - while (true) { - MOZ_ASSERT(IsCacheableEnvironment(tobj) || tobj->is()); - - if (skipLastGuard && tobj == holder) - break; - - GenerateEnvironmentChainGuard(masm, tobj, outputReg, nullptr, failures); - - if (tobj == holder) - break; - - // Load the next link. - tobj = &tobj->as().enclosingEnvironment(); - masm.extractObject(Address(outputReg, EnvironmentObject::offsetOfEnclosingEnvironment()), - outputReg); - } -} - -bool -BindNameIC::attachNonGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion, - HandleObject envChain, HandleObject holder) -{ - MOZ_ASSERT(IsCacheableEnvironment(envChain)); - - MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_); - StubAttacher attacher(*this); - - // Guard on the shape of the env chain. - Label failures; - attacher.branchNextStubOrLabel(masm, Assembler::NotEqual, - Address(environmentChainReg(), ShapedObject::offsetOfShape()), - ImmGCPtr(envChain->as().lastProperty()), - holder != envChain ? &failures : nullptr); - - if (holder != envChain) { - JSObject* parent = &envChain->as().enclosingEnvironment(); - masm.extractObject(Address(environmentChainReg(), - EnvironmentObject::offsetOfEnclosingEnvironment()), - outputReg()); - - GenerateEnvironmentChainGuards(masm, parent, holder, outputReg(), &failures); - } else { - masm.movePtr(environmentChainReg(), outputReg()); - } - - // At this point outputReg holds the object on which the property - // was found, so we're done. - attacher.jumpRejoin(masm); - - // All failures flow to here, so there is a common point to patch. - if (holder != envChain) { - masm.bind(&failures); - attacher.jumpNextStub(masm); - } - - return linkAndAttachStub(cx, masm, attacher, ion, "non-global"); -} - -static bool -IsCacheableNonGlobalEnvironmentChain(JSObject* envChain, JSObject* holder) -{ - while (true) { - if (!IsCacheableEnvironment(envChain)) { - JitSpew(JitSpew_IonIC, "Non-cacheable object on env chain"); - return false; - } - - if (envChain == holder) - return true; - - envChain = &envChain->as().enclosingEnvironment(); - if (!envChain) { - JitSpew(JitSpew_IonIC, "env chain indirect hit"); - return false; - } - } - - MOZ_CRASH("Invalid env chain"); -} - -JSObject* -BindNameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, - HandleObject envChain) -{ - IonScript* ion = outerScript->ionScript(); - BindNameIC& cache = ion->getCache(cacheIndex).toBindName(); - HandlePropertyName name = cache.name(); - - RootedObject holder(cx); - if (!LookupNameUnqualified(cx, name, envChain, &holder)) - return nullptr; - - // Stop generating new stubs once we hit the stub count limit, see - // GetPropertyCache. - if (cache.canAttachStub()) { - if (envChain->is()) { - if (!cache.attachGlobal(cx, outerScript, ion, envChain)) - return nullptr; - } else if (IsCacheableNonGlobalEnvironmentChain(envChain, holder)) { - if (!cache.attachNonGlobal(cx, outerScript, ion, envChain, holder)) - return nullptr; - } else { - JitSpew(JitSpew_IonIC, "BINDNAME uncacheable env chain"); - } - } - - return holder; -} - diff --git a/js/src/jit/IonCaches.h b/js/src/jit/IonCaches.h index d95bac58fcb9..4871979caaea 100644 --- a/js/src/jit/IonCaches.h +++ b/js/src/jit/IonCaches.h @@ -26,392 +26,6 @@ namespace js { namespace jit { -class LInstruction; - -#define IONCACHE_KIND_LIST(_) \ - _(BindName) - -// Forward declarations of Cache kinds. -#define FORWARD_DECLARE(kind) class kind##IC; -IONCACHE_KIND_LIST(FORWARD_DECLARE) -#undef FORWARD_DECLARE - -class IonCacheVisitor -{ - public: -#define VISIT_INS(op) \ - virtual void visit##op##IC(CodeGenerator* codegen) { \ - MOZ_CRASH("NYI: " #op "IC"); \ - } - - IONCACHE_KIND_LIST(VISIT_INS) -#undef VISIT_INS -}; - -// Common structure encoding the state of a polymorphic inline cache contained -// in the code for an IonScript. IonCaches are used for polymorphic operations -// where multiple implementations may be required. -// -// Roughly speaking, the cache initially jumps to an out of line fragment -// which invokes a cache function to perform the operation. The cache function -// may generate a stub to perform the operation in certain cases (e.g. a -// particular shape for an input object) and attach the stub to existing -// stubs, forming a daisy chain of tests for how to perform the operation in -// different circumstances. -// -// Eventually, if too many stubs are generated the cache function may disable -// the cache, by generating a stub to make a call and perform the operation -// within the VM. -// -// The caches initially generate a patchable jump to an out of line call -// to the cache function. Stubs are attached by appending: when attaching a -// new stub, we patch the any failure conditions in last generated stub to -// jump to the new stub. Failure conditions in the new stub jump to the cache -// function which may generate new stubs. -// -// Control flow Pointers -// =======# ----. .----> -// # | | -// #======> \-----/ -// -// Initial state: -// -// JIT Code -// +--------+ .---------------. -// | | | | -// |========| v +----------+ | -// |== IC ==|====>| Cache Fn | | -// |========| +----------+ | -// | |<=# # | -// | | #=======# | -// +--------+ Rejoin path | -// |________ | -// | | -// IC | | -// Entry | | -// +------------+ | -// | lastJump_ |---------------/ -// +------------+ -// | ... | -// +------------+ -// -// Attaching stubs: -// -// Patch the jump pointed to by lastJump_ to jump to the new stub. Update -// lastJump_ to be the new stub's failure jump. The failure jump of the new -// stub goes to the fallback label, which is the cache function. In this -// fashion, new stubs are _appended_ to the chain of stubs, as lastJump_ -// points to the _tail_ of the stub chain. -// -// JIT Code -// +--------+ #=======================# -// | | # v -// |========| # +----------+ +------+ -// |== IC ==|=# | Cache Fn |<====| Stub | -// |========| +----------+ ^ +------+ -// | |<=# # | # -// | | #======#=========|=====# -// +--------+ Rejoin path | -// |________ | -// | | -// IC | | -// Entry | | -// +------------+ | -// | lastJump_ |---------------/ -// +------------+ -// | ... | -// +------------+ -// -// While calls may be made to the cache function and other VM functions, the -// cache may still be treated as pure during optimization passes, such that -// LICM and GVN may be performed on operations around the cache as if the -// operation cannot reenter scripted code through an Invoke() or otherwise have -// unexpected behavior. This restricts the sorts of stubs which the cache can -// generate or the behaviors which called functions can have, and if a called -// function performs a possibly impure operation then the operation will be -// marked as such and the calling script will be recompiled. -// -// Similarly, despite the presence of functions and multiple stubs generated -// for a cache, the cache itself may be marked as idempotent and become hoisted -// or coalesced by LICM or GVN. This also constrains the stubs which can be -// generated for the cache. -// -// * IonCache usage -// -// IonCache is the base structure of an inline cache, which generates code stubs -// dynamically and attaches them to an IonScript. -// -// A cache must at least provide a static update function which will usualy have -// a JSContext*, followed by the cache index. The rest of the arguments of the -// update function are usualy corresponding to the register inputs of the cache, -// as it must perform the same operation as any of the stubs that it might -// produce. The update function call is handled by the visit function of -// CodeGenerator corresponding to this IC. -// -// The CodeGenerator visit function, as opposed to other visit functions, has -// two arguments. The first one is the OutOfLineUpdateCache which stores the LIR -// instruction. The second one is the IC object. This function would be called -// once the IC is registered with the addCache function of CodeGeneratorShared. -// -// To register a cache, you must call the addCache function as follow: -// -// MyCodeIC cache(inputReg1, inputValueReg2, outputReg); -// if (!addCache(lir, allocateCache(cache))) -// return false; -// -// Once the cache is allocated with the allocateCache function, any modification -// made to the cache would be ignored. -// -// The addCache function will produce a patchable jump at the location where -// it is called. This jump will execute generated stubs and fallback on the code -// of the visitMyCodeIC function if no stub match. -// -// Warning: As the addCache function fallback on a VMCall, calls to -// addCache should not be in the same path as another VMCall or in the same -// path of another addCache as this is not supported by the invalidation -// procedure. -class IonCache -{ - public: - class StubAttacher; - - enum Kind { -# define DEFINE_CACHEKINDS(ickind) Cache_##ickind, - IONCACHE_KIND_LIST(DEFINE_CACHEKINDS) -# undef DEFINE_CACHEKINDS - Cache_Invalid - }; - - // Cache testing and cast. -# define CACHEKIND_CASTS(ickind) \ - bool is##ickind() const { \ - return kind() == Cache_##ickind; \ - } \ - inline ickind##IC& to##ickind(); \ - inline const ickind##IC& to##ickind() const; - IONCACHE_KIND_LIST(CACHEKIND_CASTS) -# undef CACHEKIND_CASTS - - virtual Kind kind() const = 0; - - virtual void accept(CodeGenerator* codegen, IonCacheVisitor* visitor) = 0; - - public: - - static const char* CacheName(Kind kind); - - protected: - bool pure_ : 1; - bool idempotent_ : 1; - bool disabled_ : 1; - size_t stubCount_ : 5; - - CodeLocationLabel fallbackLabel_; - - // Location of this operation, nullptr for idempotent caches. - JSScript* script_; - jsbytecode* pc_; - - // Location to use when updating profiler pseudostack when leaving this - // IC code to enter a callee. - jsbytecode* profilerLeavePc_; - - CodeLocationJump initialJump_; - CodeLocationJump lastJump_; - CodeLocationLabel rejoinLabel_; - - private: - static const size_t MAX_STUBS; - void incrementStubCount() { - // The IC should stop generating stubs before wrapping stubCount. - stubCount_++; - MOZ_ASSERT(stubCount_); - } - - public: - - IonCache() - : pure_(false), - idempotent_(false), - disabled_(false), - stubCount_(0), - fallbackLabel_(), - script_(nullptr), - pc_(nullptr), - profilerLeavePc_(nullptr), - initialJump_(), - lastJump_(), - rejoinLabel_() - { - } - - void disable(); - inline bool isDisabled() const { - return disabled_; - } - - // Set the initial 'out-of-line' jump state of the cache. The fallbackLabel is - // the location of the out-of-line update (slow) path. This location will - // be set to the exitJump of the last generated stub. - void setFallbackLabel(CodeOffset fallbackLabel) { - fallbackLabel_ = fallbackLabel; - } - - void setProfilerLeavePC(jsbytecode* pc) { - MOZ_ASSERT(pc != nullptr); - profilerLeavePc_ = pc; - } - - // Get the address at which IC rejoins the mainline jitcode. - void* rejoinAddress() const { - return rejoinLabel_.raw(); - } - - void emitInitialJump(MacroAssembler& masm, RepatchLabel& entry); - void updateBaseAddress(JitCode* code, MacroAssembler& masm); - - // Reset the cache around garbage collection. - virtual void reset(ReprotectCode reprotect); - - bool canAttachStub() const { - return stubCount_ < MAX_STUBS; - } - bool empty() const { - return stubCount_ == 0; - } - - enum LinkStatus { - LINK_ERROR, - CACHE_FLUSHED, - LINK_GOOD - }; - - // Use the Linker to link the generated code and check if any - // monitoring/allocation caused an invalidation of the running ion script, - // this function returns CACHE_FLUSHED. In case of allocation issue this - // function returns LINK_ERROR. - LinkStatus linkCode(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher, IonScript* ion, - JitCode** code); - - // Fixup variables and update jumps in the list of stubs. Increment the - // number of attached stubs accordingly. - void attachStub(MacroAssembler& masm, StubAttacher& attacher, CodeLocationJump lastJump, - Handle code); - - // Combine both linkStub and attachStub into one function. In addition, it - // produces a spew augmented with the attachKind string. - MOZ_MUST_USE bool linkAndAttachStub(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher, - IonScript* ion, const char* attachKind, - JS::TrackedOutcome = JS::TrackedOutcome::ICOptStub_GenericSuccess); - -#ifdef DEBUG - bool isAllocated() { - return fallbackLabel_.isSet(); - } -#endif - - bool pure() const { - return pure_; - } - bool idempotent() const { - return idempotent_; - } - void setIdempotent() { - MOZ_ASSERT(!idempotent_); - MOZ_ASSERT(!script_); - MOZ_ASSERT(!pc_); - idempotent_ = true; - } - - void setScriptedLocation(JSScript* script, jsbytecode* pc) { - MOZ_ASSERT(!idempotent_); - script_ = script; - pc_ = pc; - } - - void getScriptedLocation(MutableHandleScript pscript, jsbytecode** ppc) const { - pscript.set(script_); - *ppc = pc_; - } - - jsbytecode* pc() const { - MOZ_ASSERT(pc_); - return pc_; - } - - void trace(JSTracer* trc); -}; - -// Define the cache kind and pre-declare data structures used for calling inline -// caches. -#define CACHE_HEADER(ickind) \ - Kind kind() const { \ - return IonCache::Cache_##ickind; \ - } \ - \ - void accept(CodeGenerator* codegen, IonCacheVisitor* visitor) { \ - visitor->visit##ickind##IC(codegen); \ - } \ - \ - static const VMFunction UpdateInfo; - -// Subclasses of IonCache for the various kinds of caches. These do not define -// new data members; all caches must be of the same size. - -class BindNameIC : public IonCache -{ - protected: - Register environmentChain_; - PropertyName* name_; - Register output_; - - public: - BindNameIC(Register envChain, PropertyName* name, Register output) - : environmentChain_(envChain), - name_(name), - output_(output) - { - } - - CACHE_HEADER(BindName) - - Register environmentChainReg() const { - return environmentChain_; - } - HandlePropertyName name() const { - return HandlePropertyName::fromMarkedLocation(&name_); - } - Register outputReg() const { - return output_; - } - - MOZ_MUST_USE bool attachGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion, - HandleObject envChain); - - MOZ_MUST_USE bool attachNonGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion, - HandleObject envChain, HandleObject holder); - - static JSObject* - update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, HandleObject envChain); -}; - -#undef CACHE_HEADER - -// Implement cache casts now that the compiler can see the inheritance. -#define CACHE_CASTS(ickind) \ - ickind##IC& IonCache::to##ickind() \ - { \ - MOZ_ASSERT(is##ickind()); \ - return *static_cast(this); \ - } \ - const ickind##IC& IonCache::to##ickind() const \ - { \ - MOZ_ASSERT(is##ickind()); \ - return *static_cast(this); \ - } -IONCACHE_KIND_LIST(CACHE_CASTS) -#undef OPCODE_CASTS - bool IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder); bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, PropertyResult prop); diff --git a/js/src/jit/IonCode.h b/js/src/jit/IonCode.h index 41c118668680..f2ac5cf67237 100644 --- a/js/src/jit/IonCode.h +++ b/js/src/jit/IonCode.h @@ -168,10 +168,8 @@ class RecoverWriter; class SafepointWriter; class SafepointIndex; class OsiIndex; -class IonCache; class IonIC; struct PatchableBackedgeInfo; -struct CacheLocation; // An IonScript attaches Ion-generated information to a JSScript. struct IonScript @@ -216,12 +214,6 @@ struct IonScript uint32_t runtimeData_; uint32_t runtimeSize_; - // State for polymorphic caches in the compiled code. All caches are stored - // in the runtimeData buffer and indexed by the cacheIndex which gives a - // relative offset in the runtimeData array. - uint32_t cacheIndex_; - uint32_t cacheEntries_; - // State for polymorphic caches in the compiled code. All caches are stored // in the runtimeData buffer and indexed by the icIndex which gives a // relative offset in the runtimeData array. @@ -322,9 +314,6 @@ struct IonScript OsiIndex* osiIndices() { return (OsiIndex*) &bottomBuffer()[osiIndexOffset_]; } - uint32_t* cacheIndex() { - return (uint32_t*) &bottomBuffer()[cacheIndex_]; - } uint32_t* icIndex() { return (uint32_t*) &bottomBuffer()[icIndex_]; } @@ -353,7 +342,7 @@ struct IonScript size_t snapshotsListSize, size_t snapshotsRVATableSize, size_t recoversSize, size_t bailoutEntries, size_t constants, size_t safepointIndexEntries, - size_t osiIndexEntries, size_t cacheEntries, size_t icEntries, + size_t osiIndexEntries, size_t icEntries, size_t runtimeSize, size_t safepointsSize, size_t backedgeEntries, size_t sharedStubEntries, OptimizationLevel optimizationLevel); @@ -501,18 +490,7 @@ struct IonScript } const OsiIndex* getOsiIndex(uint32_t disp) const; const OsiIndex* getOsiIndex(uint8_t* retAddr) const; - inline IonCache& getCacheFromIndex(uint32_t index) { - MOZ_ASSERT(index < cacheEntries_); - uint32_t offset = cacheIndex()[index]; - return getCache(offset); - } - inline IonCache& getCache(uint32_t offset) { - MOZ_ASSERT(offset < runtimeSize_); - return *(IonCache*) &runtimeData()[offset]; - } - size_t numCaches() const { - return cacheEntries_; - } + IonIC& getICFromIndex(uint32_t index) { MOZ_ASSERT(index < icEntries_); uint32_t offset = icIndex()[index]; @@ -534,12 +512,7 @@ struct IonScript size_t runtimeSize() const { return runtimeSize_; } - CacheLocation* getCacheLocs(uint32_t locIndex) { - MOZ_ASSERT(locIndex < runtimeSize_); - return (CacheLocation*) &runtimeData()[locIndex]; - } void toggleBarriers(bool enabled, ReprotectCode reprotect = Reprotect); - void purgeCaches(); void purgeICs(Zone* zone); void unlinkFromRuntime(FreeOp* fop); void copySnapshots(const SnapshotWriter* writer); @@ -549,7 +522,6 @@ struct IonScript void copySafepointIndices(const SafepointIndex* firstSafepointIndex, MacroAssembler& masm); void copyOsiIndices(const OsiIndex* firstOsiIndex, MacroAssembler& masm); void copyRuntimeData(const uint8_t* data); - void copyCacheEntries(const uint32_t* caches, MacroAssembler& masm); void copyICEntries(const uint32_t* caches, MacroAssembler& masm); void copySafepoints(const SafepointWriter* writer); void copyPatchableBackedges(JSContext* cx, JitCode* code, diff --git a/js/src/jit/IonIC.cpp b/js/src/jit/IonIC.cpp index 567cec4e7e67..01b058ebe101 100644 --- a/js/src/jit/IonIC.cpp +++ b/js/src/jit/IonIC.cpp @@ -46,8 +46,9 @@ IonIC::scratchRegisterForEntryJump() return asSetPropertyIC()->temp(); case CacheKind::GetName: return asGetNameIC()->temp(); - case CacheKind::In: case CacheKind::BindName: + return asBindNameIC()->temp(); + case CacheKind::In: MOZ_CRASH("Baseline-specific for now"); case CacheKind::HasOwn: return asHasOwnIC()->output(); @@ -286,13 +287,12 @@ IonGetNameIC::update(JSContext* cx, HandleScript outerScript, IonGetNameIC* ic, HandleObject envChain, MutableHandleValue res) { IonScript* ionScript = outerScript->ionScript(); + jsbytecode* pc = ic->pc(); + RootedPropertyName name(cx, ic->script()->getName(pc)); if (ic->state().maybeTransition()) ic->discardStubs(cx->zone()); - jsbytecode* pc = ic->pc(); - RootedPropertyName name(cx, ic->script()->getName(pc)); - if (ic->state().canAttachStub()) { bool attached = false; RootedScript script(cx, ic->script()); @@ -324,6 +324,35 @@ IonGetNameIC::update(JSContext* cx, HandleScript outerScript, IonGetNameIC* ic, return true; } +/* static */ JSObject* +IonBindNameIC::update(JSContext* cx, HandleScript outerScript, IonBindNameIC* ic, + HandleObject envChain) +{ + IonScript* ionScript = outerScript->ionScript(); + jsbytecode* pc = ic->pc(); + RootedPropertyName name(cx, ic->script()->getName(pc)); + + if (ic->state().maybeTransition()) + ic->discardStubs(cx->zone()); + + if (ic->state().canAttachStub()) { + bool attached = false; + RootedScript script(cx, ic->script()); + BindNameIRGenerator gen(cx, script, pc, ic->state().mode(), envChain, name); + if (gen.tryAttachStub()) + ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached); + + if (!attached) + ic->state().trackNotAttached(); + } + + RootedObject holder(cx); + if (!LookupNameUnqualified(cx, name, envChain, &holder)) + return nullptr; + + return holder; +} + /* static */ bool IonHasOwnIC::update(JSContext* cx, HandleScript outerScript, IonHasOwnIC* ic, HandleValue val, HandleValue idVal, int32_t* res) diff --git a/js/src/jit/IonIC.h b/js/src/jit/IonIC.h index 7276e792463c..3d1b26fd66ec 100644 --- a/js/src/jit/IonIC.h +++ b/js/src/jit/IonIC.h @@ -59,6 +59,7 @@ class IonICStub class IonGetPropertyIC; class IonSetPropertyIC; class IonGetNameIC; +class IonBindNameIC; class IonHasOwnIC; class IonIC @@ -145,6 +146,10 @@ class IonIC MOZ_ASSERT(kind_ == CacheKind::GetName); return (IonGetNameIC*)this; } + IonBindNameIC* asBindNameIC() { + MOZ_ASSERT(kind_ == CacheKind::BindName); + return (IonBindNameIC*)this; + } IonHasOwnIC* asHasOwnIC() { MOZ_ASSERT(kind_ == CacheKind::HasOwn); return (IonHasOwnIC*)this; @@ -280,6 +285,32 @@ class IonGetNameIC : public IonIC HandleObject envChain, MutableHandleValue res); }; +class IonBindNameIC : public IonIC +{ + LiveRegisterSet liveRegs_; + + Register environment_; + Register output_; + Register temp_; + + public: + IonBindNameIC(LiveRegisterSet liveRegs, Register environment, Register output, Register temp) + : IonIC(CacheKind::BindName), + liveRegs_(liveRegs), + environment_(environment), + output_(output), + temp_(temp) + { } + + Register environment() const { return environment_; } + Register output() const { return output_; } + Register temp() const { return temp_; } + LiveRegisterSet liveRegs() const { return liveRegs_; } + + static JSObject* update(JSContext* cx, HandleScript outerScript, IonBindNameIC* ic, + HandleObject envChain); +}; + class IonHasOwnIC : public IonIC { LiveRegisterSet liveRegs_; diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 8f930cf18c46..661be3b9969c 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3817,7 +3817,7 @@ LIRGenerator::visitBindNameCache(MBindNameCache* ins) MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object); MOZ_ASSERT(ins->type() == MIRType::Object); - LBindNameCache* lir = new(alloc()) LBindNameCache(useRegister(ins->environmentChain())); + LBindNameCache* lir = new(alloc()) LBindNameCache(useRegister(ins->environmentChain()), temp()); define(lir, ins); assignSafepoint(lir, ins); } diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index 0705a2cc3822..af54bc5f785b 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -27,7 +27,6 @@ namespace jit { class OutOfLineCode; class CodeGenerator; class MacroAssembler; -class IonCache; class IonIC; template @@ -102,9 +101,6 @@ class CodeGeneratorShared : public LElementVisitor // Allocated data space needed at runtime. js::Vector runtimeData_; - // Vector of information about generated polymorphic inline caches. - js::Vector cacheList_; - // Vector mapping each IC index to its offset in runtimeData_. js::Vector icList_; @@ -289,23 +285,6 @@ class CodeGeneratorShared : public LElementVisitor return !masm.oom(); } - // Ensure the cache is an IonCache while expecting the size of the derived - // class. We only need the cache list at GC time. Everyone else can just take - // runtimeData offsets. - template - inline size_t allocateCache(const T& cache) { - static_assert(mozilla::IsBaseOf::value, "T must inherit from IonCache"); - size_t index; - masm.propagateOOM(allocateData(sizeof(mozilla::AlignedStorage2), &index)); - masm.propagateOOM(cacheList_.append(index)); - if (masm.oom()) - return SIZE_MAX; - // Use the copy constructor on the allocated space. - MOZ_ASSERT(index == cacheList_.back()); - new (&runtimeData_[index]) T(cache); - return index; - } - template inline size_t allocateIC(const T& cache) { static_assert(mozilla::IsBaseOf::value, "T must inherit from IonIC"); @@ -497,7 +476,6 @@ class CodeGeneratorShared : public LElementVisitor inline OutOfLineCode* oolCallVM(const VMFunction& fun, LInstruction* ins, const ArgSeq& args, const StoreOutputTo& out); - void addCache(LInstruction* lir, size_t cacheIndex); void addIC(LInstruction* lir, size_t cacheIndex); ReciprocalMulConstants computeDivisionConstants(uint32_t d, int maxLog); diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index 9011efe89d6a..e7358f846ddc 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -6850,17 +6850,21 @@ class LSetPropertyPolymorphicT : public LInstructionHelper<0, 2, 1> } }; -class LBindNameCache : public LInstructionHelper<1, 1, 0> +class LBindNameCache : public LInstructionHelper<1, 1, 1> { public: LIR_HEADER(BindNameCache) - explicit LBindNameCache(const LAllocation& envChain) { + LBindNameCache(const LAllocation& envChain, const LDefinition& temp) { setOperand(0, envChain); + setTemp(0, temp); } const LAllocation* environmentChain() { return getOperand(0); } + const LDefinition* temp() { + return getTemp(0); + } const MBindNameCache* mir() const { return mir_->toBindNameCache(); } diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 9a064cdea721..afdcc49a3137 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -7243,14 +7243,6 @@ js::ReleaseAllJITCode(FreeOp* fop) } } -void -js::PurgeJITCaches(Zone* zone) -{ - /* Discard Ion caches. */ - for (auto script = zone->cellIter(); !script.done(); script.next()) - jit::PurgeCaches(script); -} - void ArenaLists::normalizeBackgroundFinalizeState(AllocKind thingKind) { diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 3de0b743f7a9..3cddd46fede9 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -1405,9 +1405,6 @@ struct MOZ_RAII AutoDisableCompactingGC JSContext* cx; }; -void -PurgeJITCaches(JS::Zone* zone); - // This is the same as IsInsideNursery, but not inlined. bool UninlinedIsInsideNursery(const gc::Cell* cell);