Diff
Modified: trunk/Source/WebCore/ChangeLog (254748 => 254749)
--- trunk/Source/WebCore/ChangeLog 2020-01-17 16:14:22 UTC (rev 254748)
+++ trunk/Source/WebCore/ChangeLog 2020-01-17 16:16:03 UTC (rev 254749)
@@ -1,3 +1,69 @@
+2020-01-17 Antti Koivisto <[email protected]>
+
+ [LFC][IFC] Allocate InlineItems in a vector
+ https://bugs.webkit.org/show_bug.cgi?id=206411
+
+ Reviewed by Zalan Bujtas.
+
+ Even the largest InlineItem (InlineTextItem) is small (fits to 24 bytes), and they are allocated
+ in large numbers (one per word and per whitespace typically). Reduce heap allocations by turning
+ InlineItem into a fixed size type.
+
+ The InlineItem vector is immutable during layout so pointer to items can still be safely used.
+
+ * layout/inlineformatting/InlineFormattingContext.cpp:
+ (WebCore::Layout::InlineFormattingContext::collectInlineContentIfNeeded):
+ * layout/inlineformatting/InlineFormattingState.h:
+ (WebCore::Layout::InlineFormattingState::addInlineItem):
+ * layout/inlineformatting/InlineItem.cpp:
+ (WebCore::Layout::InlineItem::InlineItem): Deleted.
+ * layout/inlineformatting/InlineItem.h:
+ (WebCore::Layout::InlineItem::layoutBox const):
+ (WebCore::Layout::InlineItem::style const):
+ (WebCore::Layout::InlineItem::InlineItem):
+
+ Gather members from the subclasses as protected fields.
+
+ * layout/inlineformatting/InlineSoftLineBreakItem.h:
+
+ Move the field to the base class.
+
+ (WebCore::Layout::InlineSoftLineBreakItem::position const):
+ (WebCore::Layout::InlineSoftLineBreakItem::createSoftLineBreakItem):
+ (WebCore::Layout::InlineSoftLineBreakItem::InlineSoftLineBreakItem):
+ (): Deleted.
+ * layout/inlineformatting/InlineTextItem.cpp:
+ (WebCore::Layout::InlineTextItem::createWhitespaceItem): Deleted.
+ (WebCore::Layout::InlineTextItem::createNonWhitespaceItem): Deleted.
+ (WebCore::Layout::InlineTextItem::createEmptyItem): Deleted.
+ (WebCore::Layout::InlineTextItem::InlineTextItem): Deleted.
+ * layout/inlineformatting/InlineTextItem.h:
+
+ Move the fields to the base class.
+
+ (WebCore::Layout::InlineTextItem::start const):
+ (WebCore::Layout::InlineTextItem::width const):
+
+ Place width optional into a separate bit and a value as this allows better packing of members.
+
+ (WebCore::Layout::InlineTextItem::createWhitespaceItem):
+ (WebCore::Layout::InlineTextItem::createNonWhitespaceItem):
+ (WebCore::Layout::InlineTextItem::createEmptyItem):
+ (WebCore::Layout::InlineTextItem::InlineTextItem):
+
+ Inline construction functions.
+
+ (): Deleted.
+ * layout/inlineformatting/LineLayoutContext.cpp:
+ (WebCore::Layout::nextWrapOpportunity):
+ (WebCore::Layout::LineCandidateContent::appendFloat):
+
+ Use a raw pointer instead of a WeakPtr. InlineItems are immuttable during layout.
+
+ (WebCore::Layout::LineLayoutContext::close):
+ (WebCore::Layout::LineLayoutContext::nextContentForLine):
+ * layout/inlineformatting/LineLayoutContext.h:
+
2020-01-17 Zalan Bujtas <[email protected]>
[LFC][IFC] Optimize nextWrapOpportunity/isAtSoftWrapOpportunity for the most common inline content
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp (254748 => 254749)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp 2020-01-17 16:14:22 UTC (rev 254748)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp 2020-01-17 16:16:03 UTC (rev 254749)
@@ -345,7 +345,7 @@
if (!treatAsInlineContainer(layoutBox))
break;
// This is the start of an inline container (e.g. <span>).
- formattingState.addInlineItem(makeUnique<InlineItem>(layoutBox, InlineItem::Type::ContainerStart));
+ formattingState.addInlineItem({ layoutBox, InlineItem::Type::ContainerStart });
auto& container = downcast<Container>(layoutBox);
if (!container.hasInFlowOrFloatingChild())
break;
@@ -356,17 +356,17 @@
auto& layoutBox = *layoutQueue.takeLast();
// This is the end of an inline container (e.g. </span>).
if (treatAsInlineContainer(layoutBox))
- formattingState.addInlineItem(makeUnique<InlineItem>(layoutBox, InlineItem::Type::ContainerEnd));
+ formattingState.addInlineItem({ layoutBox, InlineItem::Type::ContainerEnd });
else if (layoutBox.isLineBreakBox())
- formattingState.addInlineItem(makeUnique<InlineItem>(layoutBox, InlineItem::Type::HardLineBreak));
+ formattingState.addInlineItem({ layoutBox, InlineItem::Type::HardLineBreak });
else if (layoutBox.isFloatingPositioned())
- formattingState.addInlineItem(makeUnique<InlineItem>(layoutBox, InlineItem::Type::Float));
+ formattingState.addInlineItem({ layoutBox, InlineItem::Type::Float });
else {
ASSERT(layoutBox.isInlineLevelBox());
if (layoutBox.hasTextContent())
InlineTextItem::createAndAppendTextItems(formattingState.inlineItems(), layoutBox);
else
- formattingState.addInlineItem(makeUnique<InlineItem>(layoutBox, InlineItem::Type::Box));
+ formattingState.addInlineItem({ layoutBox, InlineItem::Type::Box });
}
if (auto* nextSibling = layoutBox.nextInFlowOrFloatingSibling()) {
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingState.h (254748 => 254749)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingState.h 2020-01-17 16:14:22 UTC (rev 254748)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingState.h 2020-01-17 16:16:03 UTC (rev 254749)
@@ -35,7 +35,7 @@
namespace WebCore {
namespace Layout {
-using InlineItems = Vector<std::unique_ptr<InlineItem>, 30>;
+using InlineItems = Vector<InlineItem, 30>;
// InlineFormattingState holds the state for a particular inline formatting context tree.
class InlineFormattingState : public FormattingState {
@@ -46,7 +46,7 @@
InlineItems& inlineItems() { return m_inlineItems; }
const InlineItems& inlineItems() const { return m_inlineItems; }
- void addInlineItem(std::unique_ptr<InlineItem>&& inlineItem) { m_inlineItems.append(WTFMove(inlineItem)); }
+ void addInlineItem(InlineItem&& inlineItem) { m_inlineItems.append(WTFMove(inlineItem)); }
const Display::InlineContent* displayInlineContent() const { return m_displayInlineContent.get(); }
Display::InlineContent& ensureDisplayInlineContent();
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineItem.cpp (254748 => 254749)
--- trunk/Source/WebCore/layout/inlineformatting/InlineItem.cpp 2020-01-17 16:14:22 UTC (rev 254748)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineItem.cpp 2020-01-17 16:16:03 UTC (rev 254749)
@@ -33,12 +33,18 @@
namespace WebCore {
namespace Layout {
-InlineItem::InlineItem(const Box& layoutBox, Type type)
- : m_layoutBox(layoutBox)
- , m_type(type)
-{
-}
+struct SameSizeAsInlineItem {
+ void* layoutBox;
+ uint8_t enum1;
+ uint8_t enum2;
+ bool widthBool;
+ InlineLayoutUnit width;
+ unsigned start;
+ unsigned length;
+};
+static_assert(sizeof(InlineItem) == sizeof(SameSizeAsInlineItem), "");
+
}
}
#endif
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineItem.h (254748 => 254749)
--- trunk/Source/WebCore/layout/inlineformatting/InlineItem.h 2020-01-17 16:14:22 UTC (rev 254748)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineItem.h 2020-01-17 16:16:03 UTC (rev 254749)
@@ -28,20 +28,19 @@
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
#include "LayoutBox.h"
-#include <wtf/WeakPtr.h>
namespace WebCore {
namespace Layout {
-class InlineItem : public CanMakeWeakPtr<InlineItem> {
+class InlineItem {
WTF_MAKE_FAST_ALLOCATED;
public:
- enum class Type { Text, HardLineBreak, SoftLineBreak, Box, Float, ContainerStart, ContainerEnd };
+ enum class Type : uint8_t { Text, HardLineBreak, SoftLineBreak, Box, Float, ContainerStart, ContainerEnd };
InlineItem(const Box& layoutBox, Type);
Type type() const { return m_type; }
- const Box& layoutBox() const { return m_layoutBox; }
- const RenderStyle& style() const { return m_layoutBox.style(); }
+ const Box& layoutBox() const { return *m_layoutBox; }
+ const RenderStyle& style() const { return layoutBox().style(); }
bool isText() const { return type() == Type::Text; }
bool isBox() const { return type() == Type::Box; }
@@ -53,10 +52,27 @@
bool isContainerEnd() const { return type() == Type::ContainerEnd; }
private:
- const Box& m_layoutBox;
- const Type m_type;
+ const Box* m_layoutBox { nullptr };
+ Type m_type { };
+
+protected:
+ // For InlineTextItem
+ enum class TextItemType : uint8_t { Undefined, Whitespace, NonWhitespace };
+ TextItemType m_textItemType { TextItemType::Undefined };
+ bool m_hasWidth { false };
+ InlineLayoutUnit m_width { };
+ unsigned m_length { 0 };
+
+ // For InlineTextItem and InlineSoftLineBreakItem
+ unsigned m_startOrPosition { 0 };
};
+inline InlineItem::InlineItem(const Box& layoutBox, Type type)
+ : m_layoutBox(&layoutBox)
+ , m_type(type)
+{
+}
+
#define SPECIALIZE_TYPE_TRAITS_INLINE_ITEM(ToValueTypeName, predicate) \
SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::Layout::ToValueTypeName) \
static bool isType(const WebCore::Layout::InlineItem& inlineItem) { return inlineItem.predicate; } \
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineSoftLineBreakItem.h (254748 => 254749)
--- trunk/Source/WebCore/layout/inlineformatting/InlineSoftLineBreakItem.h 2020-01-17 16:14:22 UTC (rev 254748)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineSoftLineBreakItem.h 2020-01-17 16:16:03 UTC (rev 254749)
@@ -34,24 +34,22 @@
class InlineSoftLineBreakItem : public InlineItem {
public:
- static std::unique_ptr<InlineSoftLineBreakItem> createSoftLineBreakItem(const Box&, unsigned position);
+ static InlineSoftLineBreakItem createSoftLineBreakItem(const Box&, unsigned position);
- unsigned position() const { return m_position; }
+ unsigned position() const { return m_startOrPosition; }
InlineSoftLineBreakItem(const Box&, unsigned position);
-private:
- unsigned m_position { 0 };
};
-std::unique_ptr<InlineSoftLineBreakItem> InlineSoftLineBreakItem::createSoftLineBreakItem(const Box& inlineBox, unsigned position)
+inline InlineSoftLineBreakItem InlineSoftLineBreakItem::createSoftLineBreakItem(const Box& inlineBox, unsigned position)
{
- return makeUnique<InlineSoftLineBreakItem>(inlineBox, position);
+ return { inlineBox, position };
}
-InlineSoftLineBreakItem::InlineSoftLineBreakItem(const Box& inlineBox, unsigned position)
+inline InlineSoftLineBreakItem::InlineSoftLineBreakItem(const Box& inlineBox, unsigned position)
: InlineItem(inlineBox, Type::SoftLineBreak)
- , m_position(position)
{
+ m_startOrPosition = position;
}
}
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineTextItem.cpp (254748 => 254749)
--- trunk/Source/WebCore/layout/inlineformatting/InlineTextItem.cpp 2020-01-17 16:14:22 UTC (rev 254748)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineTextItem.cpp 2020-01-17 16:16:03 UTC (rev 254749)
@@ -36,6 +36,8 @@
namespace WebCore {
namespace Layout {
+static_assert(sizeof(InlineItem) == sizeof(InlineTextItem), "");
+
static inline bool isWhitespaceCharacter(UChar character, bool preserveNewline)
{
return character == ' ' || character == '\t' || (character == '\n' && !preserveNewline);
@@ -119,35 +121,6 @@
}
}
-std::unique_ptr<InlineTextItem> InlineTextItem::createWhitespaceItem(const Box& inlineBox, unsigned start, unsigned length, Optional<InlineLayoutUnit> width)
-{
- return makeUnique<InlineTextItem>(inlineBox, start, length, width, TextItemType::Whitespace);
-}
-
-std::unique_ptr<InlineTextItem> InlineTextItem::createNonWhitespaceItem(const Box& inlineBox, unsigned start, unsigned length, Optional<InlineLayoutUnit> width)
-{
- return makeUnique<InlineTextItem>(inlineBox, start, length, width, TextItemType::NonWhitespace);
-}
-
-std::unique_ptr<InlineTextItem> InlineTextItem::createEmptyItem(const Box& inlineBox)
-{
- return makeUnique<InlineTextItem>(inlineBox);
-}
-
-InlineTextItem::InlineTextItem(const Box& inlineBox, unsigned start, unsigned length, Optional<InlineLayoutUnit> width, TextItemType textItemType)
- : InlineItem(inlineBox, Type::Text)
- , m_start(start)
- , m_length(length)
- , m_width(width)
- , m_textItemType(textItemType)
-{
-}
-
-InlineTextItem::InlineTextItem(const Box& inlineBox)
- : InlineItem(inlineBox, Type::Text)
-{
-}
-
bool InlineTextItem::isEmptyContent() const
{
// FIXME: We should check for more zero width content and not just U+200B.
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineTextItem.h (254748 => 254749)
--- trunk/Source/WebCore/layout/inlineformatting/InlineTextItem.h 2020-01-17 16:14:22 UTC (rev 254748)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineTextItem.h 2020-01-17 16:16:03 UTC (rev 254749)
@@ -37,36 +37,61 @@
public:
static void createAndAppendTextItems(InlineItems&, const Box&);
- static std::unique_ptr<InlineTextItem> createWhitespaceItem(const Box&, unsigned start, unsigned length, Optional<InlineLayoutUnit> width);
- static std::unique_ptr<InlineTextItem> createNonWhitespaceItem(const Box&, unsigned start, unsigned length, Optional<InlineLayoutUnit> width);
- static std::unique_ptr<InlineTextItem> createEmptyItem(const Box&);
+ static InlineTextItem createWhitespaceItem(const Box&, unsigned start, unsigned length, Optional<InlineLayoutUnit> width);
+ static InlineTextItem createNonWhitespaceItem(const Box&, unsigned start, unsigned length, Optional<InlineLayoutUnit> width);
+ static InlineTextItem createEmptyItem(const Box&);
- unsigned start() const { return m_start; }
+ unsigned start() const { return m_startOrPosition; }
unsigned end() const { return start() + length(); }
unsigned length() const { return m_length; }
bool isWhitespace() const { return m_textItemType == TextItemType::Whitespace; }
bool isCollapsible() const { return isWhitespace() && style().collapseWhiteSpace(); }
- Optional<InlineLayoutUnit> width() const { return m_width; }
+ Optional<InlineLayoutUnit> width() const { return m_hasWidth ? makeOptional(m_width) : Optional<InlineLayoutUnit> { }; }
bool isEmptyContent() const;
std::unique_ptr<InlineTextItem> left(unsigned length) const;
std::unique_ptr<InlineTextItem> right(unsigned length) const;
- enum class TextItemType { Undefined, Whitespace, NonWhitespace };
+ using InlineItem::TextItemType;
+
InlineTextItem(const Box&, unsigned start, unsigned length, Optional<InlineLayoutUnit> width, TextItemType);
InlineTextItem(const Box&);
-
-private:
- unsigned m_start { 0 };
- unsigned m_length { 0 };
- Optional<InlineLayoutUnit> m_width;
- TextItemType m_textItemType { TextItemType::Undefined };
};
+inline InlineTextItem InlineTextItem::createWhitespaceItem(const Box& inlineBox, unsigned start, unsigned length, Optional<InlineLayoutUnit> width)
+{
+ return { inlineBox, start, length, width, TextItemType::Whitespace };
}
+
+inline InlineTextItem InlineTextItem::createNonWhitespaceItem(const Box& inlineBox, unsigned start, unsigned length, Optional<InlineLayoutUnit> width)
+{
+ return { inlineBox, start, length, width, TextItemType::NonWhitespace };
}
+inline InlineTextItem InlineTextItem::createEmptyItem(const Box& inlineBox)
+{
+ return { inlineBox };
+}
+
+inline InlineTextItem::InlineTextItem(const Box& inlineBox, unsigned start, unsigned length, Optional<InlineLayoutUnit> width, TextItemType textItemType)
+ : InlineItem(inlineBox, Type::Text)
+{
+ m_startOrPosition = start;
+ m_length = length;
+ m_hasWidth = !!width;
+ m_width = width.valueOr(0);
+ m_textItemType = textItemType;
+}
+
+inline InlineTextItem::InlineTextItem(const Box& inlineBox)
+ : InlineItem(inlineBox, Type::Text)
+{
+}
+
+}
+}
+
SPECIALIZE_TYPE_TRAITS_INLINE_ITEM(InlineTextItem, isText())
#endif
Modified: trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp (254748 => 254749)
--- trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp 2020-01-17 16:14:22 UTC (rev 254748)
+++ trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp 2020-01-17 16:16:03 UTC (rev 254749)
@@ -121,7 +121,7 @@
auto inlineItemIndexWithContent = [&] (auto index) {
// Break at the first text/box/line break inline item.
for (; index < inlineItemCount; ++index) {
- auto& inlineItem = *inlineContent[index];
+ auto& inlineItem = inlineContent[index];
if (inlineItem.isText() || inlineItem.isBox())
return index;
if (inlineItem.isLineBreak()) {
@@ -150,13 +150,13 @@
// We always stop at line breaks. The wrap position is after the line break.
return nextContentIndex + 1;
}
- if (isAtSoftWrapOpportunity(*inlineContent[startContentIndex], *inlineContent[nextContentIndex])) {
+ if (isAtSoftWrapOpportunity(inlineContent[startContentIndex], inlineContent[nextContentIndex])) {
// There's a soft wrap opportunity between the start and the nextContent.
// Now forward-find from the start position to see where we can actually wrap.
// [ex-][ample] vs. [ex-][container start][container end][ample]
// where [ex-] is startContent and [ample] is the nextContent.
for (auto candidateIndex = startContentIndex + 1; candidateIndex < nextContentIndex; ++candidateIndex) {
- if (inlineContent[candidateIndex]->isContainerStart()) {
+ if (inlineContent[candidateIndex].isContainerStart()) {
// inline content and [container start] and [container end] form unbreakable content.
// ex-<span></span>ample : wrap opportunity is after "ex-".
// ex-</span></span>ample : wrap opportunity is after "ex-</span></span>".
@@ -175,7 +175,7 @@
struct LineCandidateContent {
void appendInlineContent(const InlineItem&, InlineLayoutUnit logicalWidth);
void appendLineBreak(const InlineItem& inlineItem) { setTrailingLineBreak(inlineItem); }
- void appendFloat(const InlineItem& inlineItem) { m_floats.append(makeWeakPtr(inlineItem)); }
+ void appendFloat(const InlineItem& inlineItem) { m_floats.append(&inlineItem); }
bool hasIntrusiveFloats() const { return !m_floats.isEmpty(); }
const LineBreaker::RunList& inlineRuns() const { return m_inlineRuns; }
@@ -325,7 +325,7 @@
return LineBuilder::IsLastLineWithInlineContent::No;
// Omit floats to see if this is the last line with inline content.
for (auto i = m_inlineItems.size(); i--;) {
- if (!m_inlineItems[i]->isFloat())
+ if (!m_inlineItems[i].isFloat())
return i == trailingInlineItemIndex ? LineBuilder::IsLastLineWithInlineContent::Yes : LineBuilder::IsLastLineWithInlineContent::No;
}
// There has to be at least one non-float item.
@@ -349,7 +349,7 @@
if (partialLeadingContentLength) {
// Handle leading partial content first (split text from the previous line).
// Construct a partial leading inline item.
- m_partialLeadingTextItem = downcast<InlineTextItem>(*m_inlineItems[inlineItemIndex]).right(*partialLeadingContentLength);
+ m_partialLeadingTextItem = downcast<InlineTextItem>(m_inlineItems[inlineItemIndex]).right(*partialLeadingContentLength);
auto itemWidth = inlineItemWidth(*m_partialLeadingTextItem, currentLogicalRight);
candidateContent.appendInlineContent(*m_partialLeadingTextItem, itemWidth);
currentLogicalRight += itemWidth;
@@ -357,7 +357,7 @@
}
for (auto index = inlineItemIndex; index < softWrapOpportunityIndex; ++index) {
- auto& inlineItem = *m_inlineItems[index];
+ auto& inlineItem = m_inlineItems[index];
if (inlineItem.isText() || inlineItem.isContainerStart() || inlineItem.isContainerEnd()) {
auto inlineItenmWidth = inlineItemWidth(inlineItem, currentLogicalRight);
candidateContent.appendInlineContent(inlineItem, inlineItenmWidth);
Modified: trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.h (254748 => 254749)
--- trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.h 2020-01-17 16:14:22 UTC (rev 254748)
+++ trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.h 2020-01-17 16:16:03 UTC (rev 254749)
@@ -46,12 +46,12 @@
};
Optional<unsigned> trailingInlineItemIndex;
Optional<PartialContent> partialContent;
- Vector<WeakPtr<InlineItem>> floats;
+ Vector<const InlineItem*> floats;
const LineBuilder::RunList runList;
const Display::LineBox lineBox;
};
LineContent layoutLine(LineBuilder&, unsigned leadingInlineItemIndex, Optional<unsigned> partialLeadingContentLength);
- using FloatList = Vector<WeakPtr<InlineItem>>;
+ using FloatList = Vector<const InlineItem*>;
private:
void nextContentForLine(LineCandidateContent&, unsigned inlineItemIndex, Optional<unsigned> overflowLength, InlineLayoutUnit currentLogicalRight);