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 << "\", ";