From 35557c3ce83cc6e26f07cf5d5c520ee6afd39a67 Mon Sep 17 00:00:00 2001 From: Dan Sinclair Date: Thu, 10 May 2018 14:01:25 +0000 Subject: Change formcalc javascript method output This CL changes the formcalc JS conversion code so that method calls no longer generate exponential amounts of JavaScript. Previously we'd duplicate the code to call into a method twice. This would then generate twice once for arrays and once for other types of object. This CL changes the code to wrap the actual method call into a JavaScript function which will be used from both the array and non-array calling code. For the referenced bug, the generated JS originally needed a buffer of 365meg to generate. With this CL, it needs a buffer of 7.5k. Bug: chromium:814840 Change-Id: Ibb5993fa52b7c13b20b325cf8848a306f82ae014 Reviewed-on: https://pdfium-review.googlesource.com/32312 Reviewed-by: Henrique Nakashima Reviewed-by: Ryan Harrison Commit-Queue: dsinclair --- xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp | 86 ++++++++++++++++++++++++++++++ xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp | 27 +++++----- 2 files changed, 100 insertions(+), 13 deletions(-) diff --git a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp index 1eedebfcca..0dba59c3bb 100644 --- a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp @@ -257,3 +257,89 @@ TEST(CXFA_FMParserTest, ParseDepthWithWideTree) { EXPECT_TRUE(parser->HasError()); } } + +TEST(CXFA_FMParserTest, ParseCallSmall) { + const wchar_t input[] = {L"i.f(O)"}; + const wchar_t ret[] = { + L"(function() {\n" + L"var pfm_ret = null;\n" + L"pfm_ret = pfm_rt.get_val((function () {\n" + L"let pfm_cb = function(obj) {\n" + L"return obj.f(pfm_rt.get_val(O));\n" + L"};\n" + L"if (pfm_rt.is_ary(i)) {\n" + L"let method_return_value = null;\n" + L"for (var index = i.length - 1; index > 1; index--) {\n" + L"method_return_value = pfm_cb(i[index]);\n" + L"}\n" + L"return method_return_value;\n" + L"} else {\n" + L"return pfm_cb(i);\n" + L"}}).call(this));\n" + L"return pfm_rt.get_val(pfm_ret);\n" + L"}).call(this);"}; + + auto parser = pdfium::MakeUnique(input); + std::unique_ptr ast = parser->Parse(); + EXPECT_FALSE(parser->HasError()); + + CXFA_FMToJavaScriptDepth::Reset(); + CFX_WideTextBuf buf; + EXPECT_TRUE(ast->ToJavaScript(buf)); + EXPECT_EQ(ret, buf.AsStringView()); +} + +TEST(CXFA_FMParserTest, ParseCallBig) { + const wchar_t input[] = {L"i.f(O.e(O.e(O)))"}; + const wchar_t ret[] = { + L"(function() {\n" + L"var pfm_ret = null;\n" + L"pfm_ret = pfm_rt.get_val((function () {\n" + L"let pfm_cb = function(obj) {\n" + L"return obj.f(pfm_rt.get_val((function () {\n" + L"let pfm_cb = function(obj) {\n" + L"return obj.e(pfm_rt.get_val((function () {\n" + L"let pfm_cb = function(obj) {\n" + L"return obj.e(pfm_rt.get_val(O));\n" + L"};\n" + L"if (pfm_rt.is_ary(O)) {\n" + L"let method_return_value = null;\n" + L"for (var index = O.length - 1; index > 1; index--) {\n" + L"method_return_value = pfm_cb(O[index]);\n" + L"}\n" + L"return method_return_value;\n" + L"} else {\n" + L"return pfm_cb(O);\n" + L"}}).call(this)));\n" + L"};\n" + L"if (pfm_rt.is_ary(O)) {\n" + L"let method_return_value = null;\n" + L"for (var index = O.length - 1; index > 1; index--) {\n" + L"method_return_value = pfm_cb(O[index]);\n" + L"}\n" + L"return method_return_value;\n" + L"} else {\n" + L"return pfm_cb(O);\n" + L"}}).call(this)));\n" + L"};\n" + L"if (pfm_rt.is_ary(i)) {\n" + L"let method_return_value = null;\n" + L"for (var index = i.length - 1; index > 1; index--) {\n" + L"method_return_value = pfm_cb(i[index]);\n" + L"}\n" + L"return method_return_value;\n" + L"} else {\n" + L"return pfm_cb(i);\n" + L"}}).call(this));\n" + L"return pfm_rt.get_val(pfm_ret);\n" + L"}).call(this);"}; + + auto parser = pdfium::MakeUnique(input); + std::unique_ptr ast = parser->Parse(); + EXPECT_FALSE(parser->HasError()); + + CXFA_FMToJavaScriptDepth::Reset(); + CFX_WideTextBuf buf; + EXPECT_TRUE(ast->ToJavaScript(buf)); + EXPECT_EQ(ret, buf.AsStringView()); +} diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp index 0cfb37e8d0..069899311e 100644 --- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp @@ -672,25 +672,26 @@ bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf& js, if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; - CFX_WideTextBuf exp2_txt; - if (!m_pExp2->ToJavaScript(exp2_txt, ReturnType::kInfered)) + CFX_WideTextBuf buf; + if (!m_pExp1->ToJavaScript(buf, ReturnType::kInfered)) return false; - js << L"(\nfunction ()\n{\n"; - js << L"var method_return_value = null;\n"; - js << L"var accessor_object = "; - if (!m_pExp1->ToJavaScript(js, ReturnType::kInfered)) + js << L"(function () {\n"; + js << L"let pfm_cb = function(obj) {\n"; + js << L"return obj."; + if (!m_pExp2->ToJavaScript(js, ReturnType::kInfered)) return false; js << L";\n"; - js << L"if (pfm_rt.is_ary(accessor_object))\n{\n"; - js << L"for(var index = accessor_object.length - 1; index > 1; " - L"index--)\n{\n"; - js << L"method_return_value = accessor_object[index]." << exp2_txt << L";\n"; - js << L"}\n}\nelse\n{\n"; - js << L"method_return_value = accessor_object." << exp2_txt << L";\n"; + js << L"};\n"; + js << L"if (pfm_rt.is_ary(" << buf << L")) {\n"; + js << L"let method_return_value = null;\n"; + js << L"for (var index = " << buf << L".length - 1; index > 1; index--) {\n"; + js << L"method_return_value = pfm_cb(" << buf << L"[index]);\n"; js << L"}\n"; js << L"return method_return_value;\n"; - js << L"}\n).call(this)"; + js << L"} else {\n"; + js << L"return pfm_cb(" << buf << L");\n"; + js << L"}}).call(this)"; return !CXFA_IsTooBig(js); } -- cgit v1.2.3