Skip to content

Commit

Permalink
Introduce ElementStateFlag to Node
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=271498

Reviewed by Yusuke Suzuki.

Make Node::m_previous store 16-bit bit flags and use that in Element::~Element to avoid hash map lookup
for the element identifier.

* Source/WebCore/cssjit/SelectorCompiler.cpp:
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateWalkToPreviousAdjacentElement):
* Source/WebCore/dom/Element.cpp:
(WebCore::Element::~Element):
(WebCore::Element::identifier const):
* Source/WebCore/dom/Node.cpp:
(WebCore::Node::~Node):
* Source/WebCore/dom/Node.h:
(WebCore::Node::previousSibling const):
(WebCore::Node::protectedPreviousSibling const):
(WebCore::Node::previousSiblingPointerMask):
(WebCore::Node::setPreviousSibling):
(WebCore::Node::hasElementStateFlag const):
(WebCore::Node::clearElementStateFlag const):
(WebCore::Node::setElementStateFlag const):
* Source/WebCore/domjit/JSNodeDOMJIT.cpp:
(WebCore::createCallDOMGetterForOffsetAccess):
(WebCore::compileNodePreviousSiblingAttribute):

Canonical link: https://commits.webkit.org/276596@main
  • Loading branch information
rniwa committed Mar 23, 2024
1 parent 30df9b6 commit aff386a
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 13 deletions.
3 changes: 3 additions & 0 deletions Source/WebCore/cssjit/SelectorCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2648,6 +2648,9 @@ inline void SelectorCodeGenerator::generateWalkToPreviousAdjacentElement(Assembl
{
Assembler::Label loopStart = m_assembler.label();
m_assembler.loadPtr(Assembler::Address(workRegister, Node::previousSiblingMemoryOffset()), workRegister);
LocalRegister previousNodePointerMask(m_registerAllocator);
m_assembler.move(Assembler::TrustedImmPtr(Node::previousSiblingPointerMask()), previousNodePointerMask);
m_assembler.andPtr(previousNodePointerMask, workRegister);
failureCases.append(m_assembler.branchTestPtr(Assembler::Zero, workRegister));
DOMJIT::branchTestIsElementFlagOnNode(m_assembler, Assembler::Zero, workRegister).linkTo(loopStart, &m_assembler);
}
Expand Down
11 changes: 9 additions & 2 deletions Source/WebCore/dom/Element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,11 @@ Element::~Element()
ASSERT(!beforePseudoElement());
ASSERT(!afterPseudoElement());

elementIdentifiersMap().remove(*this);
if (UNLIKELY(hasElementStateFlag(ElementStateFlag::HasElementIdentifier)))
elementIdentifiersMap().remove(*this);
else
ASSERT(!elementIdentifiersMap().contains(*this));

ASSERT(!is<HTMLImageElement>(*this) || !intersectionObserverDataIfExists());
disconnectFromIntersectionObservers();

Expand Down Expand Up @@ -5465,7 +5469,10 @@ Vector<RefPtr<WebAnimation>> Element::getAnimations(std::optional<GetAnimationsO

ElementIdentifier Element::identifier() const
{
return elementIdentifiersMap().ensure(const_cast<Element&>(*this), [] { return ElementIdentifier::generate(); }).iterator->value;
return elementIdentifiersMap().ensure(const_cast<Element&>(*this), [&] {
setElementStateFlag(ElementStateFlag::HasElementIdentifier);
return ElementIdentifier::generate();
}).iterator->value;
}

Element* Element::fromIdentifier(ElementIdentifier identifier)
Expand Down
6 changes: 3 additions & 3 deletions Source/WebCore/dom/Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@

namespace WebCore {

WTF_MAKE_ISO_ALLOCATED_IMPL(Node);
WTF_MAKE_COMPACT_ISO_ALLOCATED_IMPL(Node);

using namespace HTMLNames;

Expand All @@ -117,7 +117,7 @@ struct SameSizeAsNode : EventTarget {
uint32_t nodeFlags;
void* parentNode;
void* treeScope;
void* previous;
uint8_t previous[8];
void* next;
uint8_t rendererWithStyleFlags[8];
uint8_t rareDataWithBitfields[8];
Expand Down Expand Up @@ -430,7 +430,7 @@ Node::~Node()

ASSERT(!renderer());
ASSERT(!parentNode());
ASSERT(!m_previous);
ASSERT(!m_previous.pointer());
ASSERT(!m_next);

{
Expand Down
32 changes: 27 additions & 5 deletions Source/WebCore/dom/Node.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ struct PseudoElementIdentifier;
}

WTF_ALLOW_COMPACT_POINTERS_TO_INCOMPLETE_TYPE(WebCore::RenderObject);
WTF_ALLOW_COMPACT_POINTERS_TO_INCOMPLETE_TYPE(WebCore::Node);
WTF_ALLOW_COMPACT_POINTERS_TO_INCOMPLETE_TYPE(WebCore::NodeRareData);

namespace WebCore {
Expand All @@ -95,7 +96,7 @@ const int initialNodeVectorSize = 11; // Covers 99.5%. See webkit.org/b/80706
typedef Vector<Ref<Node>, initialNodeVectorSize> NodeVector;

class Node : public EventTarget {
WTF_MAKE_ISO_ALLOCATED(Node);
WTF_MAKE_COMPACT_ISO_ALLOCATED(Node);

friend class Document;
friend class TreeScope;
Expand Down Expand Up @@ -149,9 +150,14 @@ class Node : public EventTarget {
static ptrdiff_t parentNodeMemoryOffset() { return OBJECT_OFFSETOF(Node, m_parentNode); }
inline Element* parentElement() const; // Defined in ElementInlines.h.
inline RefPtr<Element> protectedParentElement() const; // Defined in ElementInlines.h.
Node* previousSibling() const { return m_previous; }
RefPtr<Node> protectedPreviousSibling() const { return m_previous; }
Node* previousSibling() const { return m_previous.pointer(); }
RefPtr<Node> protectedPreviousSibling() const { return m_previous.pointer(); }
static ptrdiff_t previousSiblingMemoryOffset() { return OBJECT_OFFSETOF(Node, m_previous); }
#if CPU(ADDRESS64)
static uintptr_t previousSiblingPointerMask() { return CompactPointerTuple<Node*, uint16_t>::pointerMask; }
#else
static uintptr_t previousSiblingPointerMask() { return -1; }
#endif
Node* nextSibling() const { return m_next; }
RefPtr<Node> protectedNextSibling() const { return m_next; }
static ptrdiff_t nextSiblingMemoryOffset() { return OBJECT_OFFSETOF(Node, m_next); }
Expand Down Expand Up @@ -331,7 +337,7 @@ class Node : public EventTarget {
WEBCORE_EXPORT Element* enclosingLinkEventParentOrSelf();

// These low-level calls give the caller responsibility for maintaining the integrity of the tree.
void setPreviousSibling(Node* previous) { m_previous = previous; }
void setPreviousSibling(Node* previous) { m_previous.setPointer(previous); }
void setNextSibling(Node* next) { m_next = next; }

virtual bool canContainRangeEndPoint() const { return false; }
Expand Down Expand Up @@ -640,6 +646,11 @@ class Node : public EventTarget {
IsInCustomElementReactionQueue = 1 << 15,
};

enum class ElementStateFlag : uint16_t {
HasElementIdentifier = 1 << 0,
// 15-bits free.
};

enum class TabIndexState : uint8_t {
NotSet = 0,
Zero = 1,
Expand All @@ -666,6 +677,10 @@ class Node : public EventTarget {
void setStateFlag(StateFlag flag, bool value = true) const { m_stateFlags.set(flag, value); }
void clearStateFlag(StateFlag flag) const { setStateFlag(flag, false); }

bool hasElementStateFlag(ElementStateFlag flag) const { return OptionSet<ElementStateFlag>::fromRaw(m_previous.type()).contains(flag); }
inline void setElementStateFlag(ElementStateFlag, bool value = true) const;
void clearElementStateFlag(ElementStateFlag flag) const { setElementStateFlag(flag, false); }

RareDataBitFields rareDataBitfields() const { return bitwise_cast<RareDataBitFields>(m_rareDataWithBitfields.type()); }
void setRareDataBitfields(RareDataBitFields bitfields) { m_rareDataWithBitfields.setType(bitwise_cast<uint16_t>(bitfields)); }

Expand Down Expand Up @@ -784,7 +799,7 @@ class Node : public EventTarget {

ContainerNode* m_parentNode { nullptr };
TreeScope* m_treeScope { nullptr };
Node* m_previous { nullptr };
CompactPointerTuple<Node*, uint16_t> m_previous;
Node* m_next { nullptr };
CompactPointerTuple<RenderObject*, uint16_t> m_rendererWithStyleFlags;
CompactUniquePtrTuple<NodeRareData, uint16_t> m_rareDataWithBitfields;
Expand Down Expand Up @@ -896,6 +911,13 @@ inline ContainerNode* Node::parentNodeGuaranteedHostFree() const
return parentNode();
}

inline void Node::setElementStateFlag(ElementStateFlag flag, bool value) const
{
auto set = OptionSet<ElementStateFlag>::fromRaw(m_previous.type());
set.set(flag, value);
const_cast<Node&>(*this).m_previous.setType(set.toRaw());
}

ALWAYS_INLINE void Node::setStyleFlag(NodeStyleFlag flag)
{
auto bitfields = styleBitfields();
Expand Down
11 changes: 8 additions & 3 deletions Source/WebCore/domjit/JSNodeDOMJIT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ Ref<JSC::Snippet> checkSubClassSnippetForJSNode()
enum class IsContainerGuardRequirement { Required, NotRequired };

template<typename WrappedNode, typename ToWrapperOperation>
static Ref<JSC::DOMJIT::CallDOMGetterSnippet> createCallDOMGetterForOffsetAccess(ptrdiff_t offset, ToWrapperOperation operation, IsContainerGuardRequirement isContainerGuardRequirement)
static Ref<JSC::DOMJIT::CallDOMGetterSnippet> createCallDOMGetterForOffsetAccess(ptrdiff_t offset, ToWrapperOperation operation, IsContainerGuardRequirement isContainerGuardRequirement, std::optional<uintptr_t> mask = std::nullopt)
{
Ref<JSC::DOMJIT::CallDOMGetterSnippet> snippet = JSC::DOMJIT::CallDOMGetterSnippet::create();
snippet->numGPScratchRegisters = 1;
snippet->numGPScratchRegisters = mask ? 2 : 1;
snippet->setGenerator([=](CCallHelpers& jit, JSC::SnippetParams& params) {
JSValueRegs result = params[0].jsValueRegs();
GPRReg node = params[1].gpr();
Expand All @@ -68,6 +68,11 @@ static Ref<JSC::DOMJIT::CallDOMGetterSnippet> createCallDOMGetterForOffsetAccess
nullCases.append(jit.branchTest16(CCallHelpers::Zero, CCallHelpers::Address(scratch, Node::typeFlagsMemoryOffset()), CCallHelpers::TrustedImm32(Node::flagIsContainer())));

jit.loadPtr(CCallHelpers::Address(scratch, offset), scratch);
if (mask) {
GPRReg pointerMask = params.gpScratch(1);
jit.move(CCallHelpers::TrustedImmPtr(*mask), pointerMask);
jit.andPtr(pointerMask, scratch);
}
nullCases.append(jit.branchTestPtr(CCallHelpers::Zero, scratch));

DOMJIT::toWrapper<WrappedNode>(jit, params, scratch, globalObject, result, operation, globalObjectValue);
Expand Down Expand Up @@ -104,7 +109,7 @@ Ref<JSC::DOMJIT::CallDOMGetterSnippet> compileNodeNextSiblingAttribute()

Ref<JSC::DOMJIT::CallDOMGetterSnippet> compileNodePreviousSiblingAttribute()
{
auto snippet = createCallDOMGetterForOffsetAccess<Node>(Node::previousSiblingMemoryOffset(), DOMJIT::operationToJSNode, IsContainerGuardRequirement::NotRequired);
auto snippet = createCallDOMGetterForOffsetAccess<Node>(Node::previousSiblingMemoryOffset(), DOMJIT::operationToJSNode, IsContainerGuardRequirement::NotRequired, Node::previousSiblingPointerMask());
snippet->effect = JSC::DOMJIT::Effect::forDef(DOMJIT::AbstractHeapRepository::Node_previousSibling);
return snippet;
}
Expand Down

0 comments on commit aff386a

Please sign in to comment.