Avoid N^2 copies in CXFA_FMDotAccessorExpression::ToJavaScript().
The local tempExp1 will be repeatedly copied into its caller's
tempExp1 getting larger each time as the recursion unwinds. The
cost now is we may have to generate a string twice, but we do
so into a single buffer.
The referenced bug seems recurse until we hit the 5000 frame
limit in the depth manager.
We'll probably need a follow-up bug to look at the other temporaries.
Bug: chromium:1274018
Change-Id: Ieafcc1e3e1aab412cbcb447f5bcb87d43ab364a2
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/87732
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
index 6aac77f..ad3d5da 100644
--- a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
@@ -567,21 +567,22 @@
*js << "pfm_rt.dot_acc(";
- CFX_WideTextBuf tempExp1;
CXFA_FMSimpleExpression* exp1 = GetFirstExpression();
if (exp1) {
- if (!exp1->ToJavaScript(&tempExp1, ReturnType::kInferred))
+ // Write directly to the buffer with each recursion. Creating
+ // and copying temporaries here becomes expensive when there
+ // is deep recursion, even though we may need to re-create the
+ // same thing again below. See https://crbug.com/1274018.
+ if (!exp1->ToJavaScript(js, ReturnType::kInferred))
return false;
-
- *js << tempExp1;
} else {
*js << "null";
}
*js << ", \"";
-
- if (exp1 && exp1->GetOperatorToken() == TOKidentifier)
- *js << tempExp1;
-
+ if (exp1 && exp1->GetOperatorToken() == TOKidentifier) {
+ if (!exp1->ToJavaScript(js, ReturnType::kInferred))
+ return false;
+ }
*js << "\", ";
if (GetOperatorToken() == TOKdotscream)
*js << "\"#" << m_wsIdentifier << "\", ";