Fabric: Composing YGNode object inside ShadowNode to avoid memory allocation overhead

Summary:
Given that fact that life-time of YGNode and ShadowNode objects must be idential and that we always allocate ShadowNode on heap,
we can embed YGNode object right inside ShadowNode object and use pointer to it safely.
That allows us to save additional memory allocation for every single layoutable shadow node! Whoo-hoo!

Reviewed By: fkgozali

Differential Revision: D8070121

fbshipit-source-id: 6eefbca1b7ac0a8aad235513b4c4899d414835f2
This commit is contained in:
Valentin Shergin 2018-05-22 15:45:55 -07:00 committed by Facebook Github Bot
parent b8f30db0ae
commit d94a9e2640
3 changed files with 35 additions and 30 deletions

View File

@ -22,8 +22,7 @@ void RootShadowNode::layout() {
// This is the rare place where shadow node must layout (set `layoutMetrics`)
// itself because there is no a parent node which usually should do it.
YGNode *yogaNode = const_cast<YGNode *>(yogaNode_.get());
setLayoutMetrics(layoutMetricsFromYogaNode(*yogaNode));
setLayoutMetrics(layoutMetricsFromYogaNode(yogaNode_));
}
} // namespace react

View File

@ -33,56 +33,57 @@ SharedYogaConfig YogaLayoutableShadowNode::suitableYogaConfig() {
YogaLayoutableShadowNode::YogaLayoutableShadowNode(
const SharedYogaStylableProps &props,
const SharedShadowNodeSharedList &children
) {
):
yogaNode_({}) {
assert(props);
assert(children);
yogaNode_ = std::make_unique<YGNode>();
yogaNode_->setConfig(suitableYogaConfig().get());
yogaNode_->setStyle(props->yogaStyle);
yogaNode_->setContext(this);
yogaNode_->setDirty(true);
YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(yogaNode_.get(), children);
yogaNode_.setConfig(suitableYogaConfig().get());
yogaNode_.setStyle(props->yogaStyle);
yogaNode_.setContext(this);
yogaNode_.setDirty(true);
YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(&yogaNode_, children);
}
YogaLayoutableShadowNode::YogaLayoutableShadowNode(
const SharedYogaLayoutableShadowNode &shadowNode,
const SharedYogaStylableProps &props,
const SharedShadowNodeSharedList &children
) {
yogaNode_ = std::make_unique<YGNode>(*shadowNode->yogaNode_);
yogaNode_->setConfig(suitableYogaConfig().get());
yogaNode_->setContext(this);
yogaNode_->setOwner(nullptr);
yogaNode_->setDirty(true);
):
yogaNode_(shadowNode->yogaNode_) {
yogaNode_.setConfig(suitableYogaConfig().get());
yogaNode_.setContext(this);
yogaNode_.setOwner(nullptr);
yogaNode_.setDirty(true);
if (props) {
yogaNode_->setStyle(props->yogaStyle);
yogaNode_.setStyle(props->yogaStyle);
}
if (children) {
YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(yogaNode_.get(), children);
YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(&yogaNode_, children);
}
}
void YogaLayoutableShadowNode::cleanLayout() {
yogaNode_->setDirty(false);
yogaNode_.setDirty(false);
}
void YogaLayoutableShadowNode::dirtyLayout() {
yogaNode_->markDirtyAndPropogate();
yogaNode_.markDirtyAndPropogate();
}
bool YogaLayoutableShadowNode::getIsLayoutClean() const {
return !yogaNode_->isDirty();
return !yogaNode_.isDirty();
}
bool YogaLayoutableShadowNode::getHasNewLayout() const {
return yogaNode_->getHasNewLayout();
return yogaNode_.getHasNewLayout();
}
void YogaLayoutableShadowNode::setHasNewLayout(bool hasNewLayout) {
yogaNode_->setHasNewLayout(hasNewLayout);
yogaNode_.setHasNewLayout(hasNewLayout);
}
#pragma mark - Mutating Methods
@ -90,14 +91,14 @@ void YogaLayoutableShadowNode::setHasNewLayout(bool hasNewLayout) {
void YogaLayoutableShadowNode::enableMeasurement() {
ensureUnsealed();
yogaNode_->setMeasureFunc(YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector);
yogaNode_.setMeasureFunc(YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector);
}
void YogaLayoutableShadowNode::appendChild(SharedYogaLayoutableShadowNode child) {
ensureUnsealed();
auto yogaNodeRawPtr = yogaNode_.get();
auto childYogaNodeRawPtr = child->yogaNode_.get();
auto yogaNodeRawPtr = &yogaNode_;
auto childYogaNodeRawPtr = &child->yogaNode_;
yogaNodeRawPtr->insertChild(childYogaNodeRawPtr, yogaNodeRawPtr->getChildrenCount());
if (childYogaNodeRawPtr->getOwner() == nullptr) {
@ -109,7 +110,7 @@ void YogaLayoutableShadowNode::appendChild(SharedYogaLayoutableShadowNode child)
void YogaLayoutableShadowNode::layout(LayoutContext layoutContext) {
if (!getIsLayoutClean()) {
ensureUnsealed();
YGNodeCalculateLayout(yogaNode_.get(), YGUndefined, YGUndefined, YGDirectionInherit);
YGNodeCalculateLayout(&yogaNode_, YGUndefined, YGUndefined, YGDirectionInherit);
}
LayoutableShadowNode::layout(layoutContext);
@ -124,7 +125,7 @@ void YogaLayoutableShadowNode::layoutChildren(LayoutContext layoutContext) {
auto nonConstYogaLayoutableChild = std::const_pointer_cast<YogaLayoutableShadowNode>(yogaLayoutableChild);
LayoutMetrics childLayoutMetrics = layoutMetricsFromYogaNode(*nonConstYogaLayoutableChild->yogaNode_);
LayoutMetrics childLayoutMetrics = layoutMetricsFromYogaNode(nonConstYogaLayoutableChild->yogaNode_);
nonConstYogaLayoutableChild->setLayoutMetrics(childLayoutMetrics);
}
}
@ -160,7 +161,7 @@ YGNode *YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector(YGNode *oldYoga
std::dynamic_pointer_cast<const YogaLayoutableShadowNode>(parentShadowNodeRawPtr->cloneAndReplaceChild(oldShadowNode));
assert(newShadowNode);
return newShadowNode->yogaNode_.get();
return &newShadowNode->yogaNode_;
}
YGSize YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector(YGNode *yogaNode, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) {
@ -212,7 +213,7 @@ void YogaLayoutableShadowNode::setYogaNodeChildrenBasedOnShadowNodeChildren(YGNo
continue;
}
auto &&childYogaNodeRawPtr = (YGNode *)yogaLayoutableShadowNode->yogaNode_.get();
auto &&childYogaNodeRawPtr = &yogaLayoutableShadowNode->yogaNode_;
yogaNodeChildren.push_back(childYogaNodeRawPtr);

View File

@ -80,7 +80,12 @@ public:
void layoutChildren(LayoutContext layoutContext) override;
protected:
std::unique_ptr<YGNode> yogaNode_;
/*
* All Yoga functions only accept non-const arguments, so we have to mark
* Yoga node as `mutable` here to avoid `static_cast`ing the pointer to this
* all the time.
*/
mutable YGNode yogaNode_;
private:
static SharedYogaConfig suitableYogaConfig();