Make CXFA_FMExpression and its subclasses be garbage collected.

Unfortunately, these classes now need to copy stringviews
into strings so that the strings remain valid despite the
indeterminate lifetime of the GC'd objects.

Bug: pdfium:1563
Change-Id: I32c494387c6b311f65c9dbcedd42e409fb0a9cc9
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/73631
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fxjs/xfa/cfxjse_engine.cpp b/fxjs/xfa/cfxjse_engine.cpp
index adc6e68..fbd6c8b 100644
--- a/fxjs/xfa/cfxjse_engine.cpp
+++ b/fxjs/xfa/cfxjse_engine.cpp
@@ -140,7 +140,7 @@
           GetIsolate(), m_JsContext.get(), m_pDocument.Get());
     }
     Optional<CFX_WideTextBuf> wsJavaScript =
-        CFXJSE_FormCalcContext::Translate(wsScript);
+        CFXJSE_FormCalcContext::Translate(m_pDocument->GetHeap(), wsScript);
     if (!wsJavaScript.has_value()) {
       hRetValue->SetUndefined();
       return false;
diff --git a/fxjs/xfa/cfxjse_formcalc_context.cpp b/fxjs/xfa/cfxjse_formcalc_context.cpp
index 886820a..1606150 100644
--- a/fxjs/xfa/cfxjse_formcalc_context.cpp
+++ b/fxjs/xfa/cfxjse_formcalc_context.cpp
@@ -3201,8 +3201,8 @@
   }
 
   WideString wsCalcScript = WideString::FromUTF8(bsUtf8Script.AsStringView());
-  Optional<CFX_WideTextBuf> wsJavaScriptBuf =
-      CFXJSE_FormCalcContext::Translate(wsCalcScript.AsStringView());
+  Optional<CFX_WideTextBuf> wsJavaScriptBuf = CFXJSE_FormCalcContext::Translate(
+      pContext->GetDocument()->GetHeap(), wsCalcScript.AsStringView());
   if (!wsJavaScriptBuf.has_value()) {
     pContext->ThrowCompilerErrorException();
     return;
@@ -5011,8 +5011,8 @@
   }
 
   WideString wsCalcScript = WideString::FromUTF8(bsArg.AsStringView());
-  Optional<CFX_WideTextBuf> wsJavaScriptBuf =
-      CFXJSE_FormCalcContext::Translate(wsCalcScript.AsStringView());
+  Optional<CFX_WideTextBuf> wsJavaScriptBuf = CFXJSE_FormCalcContext::Translate(
+      pContext->GetDocument()->GetHeap(), wsCalcScript.AsStringView());
   if (!wsJavaScriptBuf.has_value()) {
     pContext->ThrowCompilerErrorException();
     return;
@@ -5647,14 +5647,14 @@
   return arg->ToString();
 }
 
-// static.
 Optional<CFX_WideTextBuf> CFXJSE_FormCalcContext::Translate(
+    cppgc::Heap* pHeap,
     WideStringView wsFormcalc) {
   if (wsFormcalc.IsEmpty())
     return CFX_WideTextBuf();
 
-  CXFA_FMParser parser(wsFormcalc);
-  std::unique_ptr<CXFA_FMAST> ast = parser.Parse();
+  CXFA_FMParser parser(pHeap, wsFormcalc);
+  CXFA_FMAST* ast = parser.Parse();
   if (!ast || parser.HasError())
     return pdfium::nullopt;
 
diff --git a/fxjs/xfa/cfxjse_formcalc_context.h b/fxjs/xfa/cfxjse_formcalc_context.h
index 8858d0e..ac1e3f3 100644
--- a/fxjs/xfa/cfxjse_formcalc_context.h
+++ b/fxjs/xfa/cfxjse_formcalc_context.h
@@ -19,6 +19,10 @@
 class CFX_WideTextBuf;
 class CXFA_Document;
 
+namespace cppgc {
+class Heap;
+}  // namespace cppgc
+
 class CFXJSE_FormCalcContext final : public CFXJSE_HostObject {
  public:
   CFXJSE_FormCalcContext(v8::Isolate* pScriptIsolate,
@@ -287,7 +291,6 @@
       CFXJSE_Value* pParentValue,
       std::vector<std::unique_ptr<CFXJSE_Value>>* resultValues,
       bool* bAttribute);
-
   static std::unique_ptr<CFXJSE_Value> GetSimpleValue(
       CFXJSE_HostObject* pThis,
       const v8::FunctionCallbackInfo<v8::Value>& info,
@@ -300,7 +303,8 @@
   static double ExtractDouble(CFXJSE_HostObject* pThis,
                               CFXJSE_Value* src,
                               bool* ret);
-  static Optional<CFX_WideTextBuf> Translate(WideStringView wsFormcalc);
+  static Optional<CFX_WideTextBuf> Translate(cppgc::Heap* pHeap,
+                                             WideStringView wsFormcalc);
 
   void GlobalPropertyGetter(CFXJSE_Value* pValue);
 
diff --git a/testing/fuzzers/BUILD.gn b/testing/fuzzers/BUILD.gn
index 0fe1021..bf9f05b 100644
--- a/testing/fuzzers/BUILD.gn
+++ b/testing/fuzzers/BUILD.gn
@@ -340,6 +340,7 @@
     pdfium_fuzzer("pdf_fm2js_fuzzer") {
       sources = [ "pdf_fm2js_fuzzer.cc" ]
       deps = [
+        ":fuzzer_utils",
         "../../core/fxcrt",
         "../../fxjs",
       ]
diff --git a/testing/fuzzers/pdf_fm2js_fuzzer.cc b/testing/fuzzers/pdf_fm2js_fuzzer.cc
index 929b811..fcb2071 100644
--- a/testing/fuzzers/pdf_fm2js_fuzzer.cc
+++ b/testing/fuzzers/pdf_fm2js_fuzzer.cc
@@ -9,9 +9,13 @@
 #include "core/fxcrt/fx_safe_types.h"
 #include "core/fxcrt/fx_string.h"
 #include "fxjs/xfa/cfxjse_formcalc_context.h"
+#include "testing/fuzzers/pdf_fuzzer_init_public.h"
+#include "testing/fuzzers/pdfium_fuzzer_util.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  auto* state = static_cast<PDFFuzzerPublic*>(FPDF_GetFuzzerPerProcessState());
   WideString input = WideString::FromUTF8(ByteStringView(data, size));
-  CFXJSE_FormCalcContext::Translate(input.AsStringView());
+  CFXJSE_FormCalcContext::Translate(state->GetHeap(), input.AsStringView());
+  state->MaybeForceGCAndPump();
   return 0;
 }
diff --git a/testing/fuzzers/pdf_formcalc_fuzzer.cc b/testing/fuzzers/pdf_formcalc_fuzzer.cc
index ad35e67..8e73d13 100644
--- a/testing/fuzzers/pdf_formcalc_fuzzer.cc
+++ b/testing/fuzzers/pdf_formcalc_fuzzer.cc
@@ -12,7 +12,7 @@
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   auto* state = static_cast<PDFFuzzerPublic*>(FPDF_GetFuzzerPerProcessState());
   WideString input = WideString::FromUTF8(ByteStringView(data, size));
-  CXFA_FMParser parser(input.AsStringView());
+  CXFA_FMParser parser(state->GetHeap(), input.AsStringView());
   parser.Parse();
   state->MaybeForceGCAndPump();
   return 0;
diff --git a/xfa/fxfa/fm2js/BUILD.gn b/xfa/fxfa/fm2js/BUILD.gn
index 3e151b4..a5855a3 100644
--- a/xfa/fxfa/fm2js/BUILD.gn
+++ b/xfa/fxfa/fm2js/BUILD.gn
@@ -18,7 +18,10 @@
     "cxfa_fmtojavascriptdepth.cpp",
     "cxfa_fmtojavascriptdepth.h",
   ]
-  deps = [ "../../../core/fxcrt" ]
+  deps = [
+    "../../../core/fxcrt",
+    "../../../fxjs:gc",
+  ]
   configs += [
     "../../../:pdfium_core_config",
     "../../:xfa_warnings",
@@ -32,6 +35,9 @@
     "cxfa_fmlexer_unittest.cpp",
     "cxfa_fmparser_unittest.cpp",
   ]
-  deps = [ ":fm2js" ]
+  deps = [
+    ":fm2js",
+    "../../../fxjs:gc",
+  ]
   pdfium_root_dir = "../../../"
 }
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
index 0a0fd7b..442fef9 100644
--- a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
@@ -12,7 +12,9 @@
 #include "core/fxcrt/autorestorer.h"
 #include "core/fxcrt/cfx_widetextbuf.h"
 #include "core/fxcrt/fx_extension.h"
+#include "fxjs/gc/container_trace.h"
 #include "third_party/base/logging.h"
+#include "v8/include/cppgc/visitor.h"
 #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
 
 namespace {
@@ -73,11 +75,9 @@
     {L"y", 0x01},
 };
 
-WideString IdentifierToName(WideStringView ident) {
-  if (ident.IsEmpty())
-    return WideString();
-  if (ident[0] != L'!')
-    return WideString(ident);
+WideString IdentifierToName(const WideString& ident) {
+  if (ident.IsEmpty() || ident[0] != L'!')
+    return ident;
   return L"pfm__excl__" + ident.Last(ident.GetLength() - 1);
 }
 
@@ -87,75 +87,31 @@
 
 CXFA_FMExpression::~CXFA_FMExpression() = default;
 
-CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op)
-    : m_op(op), m_bChainable(false) {}
+void CXFA_FMExpression::Trace(cppgc::Visitor* visitor) const {}
 
-CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op,
-                                                 bool chainable)
-    : m_op(op), m_bChainable(chainable) {}
+CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op) : m_op(op) {}
 
 CXFA_FMSimpleExpression::~CXFA_FMSimpleExpression() = default;
 
 CXFA_FMChainableExpression::CXFA_FMChainableExpression(
     XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMSimpleExpression(op, /*chainable=*/true),
-      m_pExp1(std::move(pExp1)),
-      m_pExp2(std::move(pExp2)) {}
+    CXFA_FMSimpleExpression* pExp1,
+    CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMSimpleExpression(op), m_pExp1(pExp1), m_pExp2(pExp2) {}
 
-CXFA_FMChainableExpression::~CXFA_FMChainableExpression() {
-  DeleteChain(std::move(m_pExp1));
-  DeleteChain(std::move(m_pExp2));
-}
+CXFA_FMChainableExpression::~CXFA_FMChainableExpression() = default;
 
-CXFA_FMSimpleExpression* CXFA_FMChainableExpression::GetFirstExpression()
-    const {
-  return m_pExp1.get();
-}
-
-CXFA_FMSimpleExpression* CXFA_FMChainableExpression::GetSecondExpression()
-    const {
-  return m_pExp2.get();
-}
-
-// static
-void CXFA_FMChainableExpression::DeleteChain(
-    std::unique_ptr<CXFA_FMSimpleExpression> pRoot) {
-  while (pRoot && pRoot->chainable()) {
-    auto* pRootChain = static_cast<CXFA_FMChainableExpression*>(pRoot.get());
-
-    // If either child is not a chainable expression (i.e. a leaf node), simply
-    // delete it.
-    if (pRootChain->m_pExp1 && !pRootChain->m_pExp1->chainable())
-      pRootChain->m_pExp1.reset();
-    if (pRootChain->m_pExp2 && !pRootChain->m_pExp2->chainable())
-      pRootChain->m_pExp2.reset();
-
-    // If the root is missing either child, delete the root and promote the only
-    // child to the root.
-    if (!pRootChain->m_pExp1) {
-      pRoot = std::move(pRootChain->m_pExp2);
-      continue;
-    }
-    if (!pRootChain->m_pExp2) {
-      pRoot = std::move(pRootChain->m_pExp1);
-      continue;
-    }
-
-    // Otherwise, perform a right tree rotation.
-    std::unique_ptr<CXFA_FMSimpleExpression> pPivot(
-        std::move(pRootChain->m_pExp1));
-    auto* pPivotChain = static_cast<CXFA_FMChainableExpression*>(pPivot.get());
-    pRootChain->m_pExp1 = std::move(pPivotChain->m_pExp2);
-    pPivotChain->m_pExp2 = std::move(pRoot);
-    pRoot = std::move(pPivot);
-  }
+void CXFA_FMChainableExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMSimpleExpression::Trace(visitor);
+  visitor->Trace(m_pExp1);
+  visitor->Trace(m_pExp2);
 }
 
 CXFA_FMNullExpression::CXFA_FMNullExpression()
     : CXFA_FMSimpleExpression(TOKnull) {}
 
+CXFA_FMNullExpression::~CXFA_FMNullExpression() = default;
+
 bool CXFA_FMNullExpression::ToJavaScript(CFX_WideTextBuf* js,
                                          ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -166,8 +122,8 @@
   return !CXFA_IsTooBig(*js);
 }
 
-CXFA_FMNumberExpression::CXFA_FMNumberExpression(WideStringView wsNumber)
-    : CXFA_FMSimpleExpression(TOKnumber), m_wsNumber(wsNumber) {}
+CXFA_FMNumberExpression::CXFA_FMNumberExpression(WideString wsNumber)
+    : CXFA_FMSimpleExpression(TOKnumber), m_wsNumber(std::move(wsNumber)) {}
 
 CXFA_FMNumberExpression::~CXFA_FMNumberExpression() = default;
 
@@ -181,8 +137,8 @@
   return !CXFA_IsTooBig(*js);
 }
 
-CXFA_FMStringExpression::CXFA_FMStringExpression(WideStringView wsString)
-    : CXFA_FMSimpleExpression(TOKstring), m_wsString(wsString) {}
+CXFA_FMStringExpression::CXFA_FMStringExpression(WideString wsString)
+    : CXFA_FMSimpleExpression(TOKstring), m_wsString(std::move(wsString)) {}
 
 CXFA_FMStringExpression::~CXFA_FMStringExpression() = default;
 
@@ -221,8 +177,9 @@
 }
 
 CXFA_FMIdentifierExpression::CXFA_FMIdentifierExpression(
-    WideStringView wsIdentifier)
-    : CXFA_FMSimpleExpression(TOKidentifier), m_wsIdentifier(wsIdentifier) {}
+    WideString wsIdentifier)
+    : CXFA_FMSimpleExpression(TOKidentifier),
+      m_wsIdentifier(std::move(wsIdentifier)) {}
 
 CXFA_FMIdentifierExpression::~CXFA_FMIdentifierExpression() = default;
 
@@ -256,11 +213,10 @@
   return !CXFA_IsTooBig(*js);
 }
 
-CXFA_FMAssignExpression::CXFA_FMAssignExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMChainableExpression(op, std::move(pExp1), std::move(pExp2)) {}
+CXFA_FMAssignExpression::CXFA_FMAssignExpression(XFA_FM_TOKEN op,
+                                                 CXFA_FMSimpleExpression* pExp1,
+                                                 CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMChainableExpression(op, pExp1, pExp2) {}
 
 CXFA_FMAssignExpression::~CXFA_FMAssignExpression() = default;
 
@@ -299,13 +255,11 @@
   return !CXFA_IsTooBig(*js);
 }
 
-CXFA_FMBinExpression::CXFA_FMBinExpression(
-    const WideString& opName,
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMChainableExpression(op, std::move(pExp1), std::move(pExp2)),
-      m_OpName(opName) {}
+CXFA_FMBinExpression::CXFA_FMBinExpression(const WideString& opName,
+                                           XFA_FM_TOKEN op,
+                                           CXFA_FMSimpleExpression* pExp1,
+                                           CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMChainableExpression(op, pExp1, pExp2), m_OpName(opName) {}
 
 CXFA_FMBinExpression::~CXFA_FMBinExpression() = default;
 
@@ -327,94 +281,103 @@
 
 CXFA_FMLogicalOrExpression::CXFA_FMLogicalOrExpression(
     XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"log_or_op",
-                           op,
-                           std::move(pExp1),
-                           std::move(pExp2)) {}
+    CXFA_FMSimpleExpression* pExp1,
+    CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"log_or_op", op, pExp1, pExp2) {}
+
+CXFA_FMLogicalOrExpression::~CXFA_FMLogicalOrExpression() = default;
 
 CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression(
     XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"log_and_op",
-                           op,
-                           std::move(pExp1),
-                           std::move(pExp2)) {}
+    CXFA_FMSimpleExpression* pExp1,
+    CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"log_and_op", op, pExp1, pExp2) {}
 
-CXFA_FMEqualExpression::CXFA_FMEqualExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"eq_op", op, std::move(pExp1), std::move(pExp2)) {}
+CXFA_FMLogicalAndExpression::~CXFA_FMLogicalAndExpression() = default;
+
+CXFA_FMEqualExpression::CXFA_FMEqualExpression(XFA_FM_TOKEN op,
+                                               CXFA_FMSimpleExpression* pExp1,
+                                               CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"eq_op", op, pExp1, pExp2) {}
+
+CXFA_FMEqualExpression::~CXFA_FMEqualExpression() = default;
 
 CXFA_FMNotEqualExpression::CXFA_FMNotEqualExpression(
     XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"neq_op", op, std::move(pExp1), std::move(pExp2)) {}
+    CXFA_FMSimpleExpression* pExp1,
+    CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"neq_op", op, pExp1, pExp2) {}
 
-CXFA_FMGtExpression::CXFA_FMGtExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"gt_op", op, std::move(pExp1), std::move(pExp2)) {}
+CXFA_FMNotEqualExpression::~CXFA_FMNotEqualExpression() = default;
 
-CXFA_FMGeExpression::CXFA_FMGeExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"ge_op", op, std::move(pExp1), std::move(pExp2)) {}
+CXFA_FMGtExpression::CXFA_FMGtExpression(XFA_FM_TOKEN op,
+                                         CXFA_FMSimpleExpression* pExp1,
+                                         CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"gt_op", op, pExp1, pExp2) {}
 
-CXFA_FMLtExpression::CXFA_FMLtExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"lt_op", op, std::move(pExp1), std::move(pExp2)) {}
+CXFA_FMGtExpression::~CXFA_FMGtExpression() = default;
 
-CXFA_FMLeExpression::CXFA_FMLeExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"le_op", op, std::move(pExp1), std::move(pExp2)) {}
+CXFA_FMGeExpression::CXFA_FMGeExpression(XFA_FM_TOKEN op,
+                                         CXFA_FMSimpleExpression* pExp1,
+                                         CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"ge_op", op, pExp1, pExp2) {}
 
-CXFA_FMPlusExpression::CXFA_FMPlusExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"plus_op", op, std::move(pExp1), std::move(pExp2)) {
-}
+CXFA_FMGeExpression::~CXFA_FMGeExpression() = default;
 
-CXFA_FMMinusExpression::CXFA_FMMinusExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"minus_op",
-                           op,
-                           std::move(pExp1),
-                           std::move(pExp2)) {}
+CXFA_FMLtExpression::CXFA_FMLtExpression(XFA_FM_TOKEN op,
+                                         CXFA_FMSimpleExpression* pExp1,
+                                         CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"lt_op", op, pExp1, pExp2) {}
 
-CXFA_FMMulExpression::CXFA_FMMulExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"mul_op", op, std::move(pExp1), std::move(pExp2)) {}
+CXFA_FMLtExpression::~CXFA_FMLtExpression() = default;
 
-CXFA_FMDivExpression::CXFA_FMDivExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"div_op", op, std::move(pExp1), std::move(pExp2)) {}
+CXFA_FMLeExpression::CXFA_FMLeExpression(XFA_FM_TOKEN op,
+                                         CXFA_FMSimpleExpression* pExp1,
+                                         CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"le_op", op, pExp1, pExp2) {}
 
-CXFA_FMUnaryExpression::CXFA_FMUnaryExpression(
-    const WideString& opName,
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMSimpleExpression(op), m_OpName(opName), m_pExp(std::move(pExp)) {}
+CXFA_FMLeExpression::~CXFA_FMLeExpression() = default;
+
+CXFA_FMPlusExpression::CXFA_FMPlusExpression(XFA_FM_TOKEN op,
+                                             CXFA_FMSimpleExpression* pExp1,
+                                             CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"plus_op", op, pExp1, pExp2) {}
+
+CXFA_FMPlusExpression::~CXFA_FMPlusExpression() = default;
+
+CXFA_FMMinusExpression::CXFA_FMMinusExpression(XFA_FM_TOKEN op,
+                                               CXFA_FMSimpleExpression* pExp1,
+                                               CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"minus_op", op, pExp1, pExp2) {}
+
+CXFA_FMMinusExpression::~CXFA_FMMinusExpression() = default;
+
+CXFA_FMMulExpression::CXFA_FMMulExpression(XFA_FM_TOKEN op,
+                                           CXFA_FMSimpleExpression* pExp1,
+                                           CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"mul_op", op, pExp1, pExp2) {}
+
+CXFA_FMMulExpression::~CXFA_FMMulExpression() = default;
+
+CXFA_FMDivExpression::CXFA_FMDivExpression(XFA_FM_TOKEN op,
+                                           CXFA_FMSimpleExpression* pExp1,
+                                           CXFA_FMSimpleExpression* pExp2)
+    : CXFA_FMBinExpression(L"div_op", op, pExp1, pExp2) {}
+
+CXFA_FMDivExpression::~CXFA_FMDivExpression() = default;
+
+CXFA_FMUnaryExpression::CXFA_FMUnaryExpression(const WideString& opName,
+                                               XFA_FM_TOKEN op,
+                                               CXFA_FMSimpleExpression* pExp)
+    : CXFA_FMSimpleExpression(op), m_OpName(opName), m_pExp(pExp) {}
 
 CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() = default;
 
+void CXFA_FMUnaryExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMSimpleExpression::Trace(visitor);
+  visitor->Trace(m_pExp);
+}
+
 bool CXFA_FMUnaryExpression::ToJavaScript(CFX_WideTextBuf* js,
                                           ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -428,29 +391,38 @@
   return !CXFA_IsTooBig(*js);
 }
 
-CXFA_FMPosExpression::CXFA_FMPosExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMUnaryExpression(L"pos_op", TOKplus, std::move(pExp)) {}
+CXFA_FMPosExpression::CXFA_FMPosExpression(CXFA_FMSimpleExpression* pExp)
+    : CXFA_FMUnaryExpression(L"pos_op", TOKplus, pExp) {}
 
-CXFA_FMNegExpression::CXFA_FMNegExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMUnaryExpression(L"neg_op", TOKminus, std::move(pExp)) {}
+CXFA_FMPosExpression::~CXFA_FMPosExpression() = default;
 
-CXFA_FMNotExpression::CXFA_FMNotExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMUnaryExpression(L"log_not_op", TOKksnot, std::move(pExp)) {}
+CXFA_FMNegExpression::CXFA_FMNegExpression(CXFA_FMSimpleExpression* pExp)
+    : CXFA_FMUnaryExpression(L"neg_op", TOKminus, pExp) {}
+
+CXFA_FMNegExpression::~CXFA_FMNegExpression() = default;
+
+CXFA_FMNotExpression::CXFA_FMNotExpression(CXFA_FMSimpleExpression* pExp)
+    : CXFA_FMUnaryExpression(L"log_not_op", TOKksnot, pExp) {}
+
+CXFA_FMNotExpression::~CXFA_FMNotExpression() = default;
 
 CXFA_FMCallExpression::CXFA_FMCallExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp,
-    std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments,
+    CXFA_FMSimpleExpression* pExp,
+    std::vector<cppgc::Member<CXFA_FMSimpleExpression>>&& pArguments,
     bool bIsSomMethod)
     : CXFA_FMSimpleExpression(TOKcall),
-      m_pExp(std::move(pExp)),
-      m_bIsSomMethod(bIsSomMethod),
-      m_Arguments(std::move(pArguments)) {}
+      m_pExp(pExp),
+      m_Arguments(std::move(pArguments)),
+      m_bIsSomMethod(bIsSomMethod) {}
 
 CXFA_FMCallExpression::~CXFA_FMCallExpression() = default;
 
+void CXFA_FMCallExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMSimpleExpression::Trace(visitor);
+  visitor->Trace(m_pExp);
+  ContainerTrace(visitor, m_Arguments);
+}
+
 bool CXFA_FMCallExpression::IsBuiltInFunc(CFX_WideTextBuf* funcName) const {
   if (funcName->GetLength() > g_BuiltInFuncsMaxLen)
     return false;
@@ -578,14 +550,12 @@
 }
 
 CXFA_FMDotAccessorExpression::CXFA_FMDotAccessorExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
+    CXFA_FMSimpleExpression* pAccessor,
     XFA_FM_TOKEN op,
-    WideStringView wsIdentifier,
-    std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
-    : CXFA_FMChainableExpression(op,
-                                 std::move(pAccessor),
-                                 std::move(pIndexExp)),
-      m_wsIdentifier(wsIdentifier) {}
+    WideString wsIdentifier,
+    CXFA_FMSimpleExpression* pIndexExp)
+    : CXFA_FMChainableExpression(op, pAccessor, pIndexExp),
+      m_wsIdentifier(std::move(wsIdentifier)) {}
 
 CXFA_FMDotAccessorExpression::~CXFA_FMDotAccessorExpression() = default;
 
@@ -632,15 +602,20 @@
 
 CXFA_FMIndexExpression::CXFA_FMIndexExpression(
     XFA_FM_AccessorIndex accessorIndex,
-    std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp,
+    CXFA_FMSimpleExpression* pIndexExp,
     bool bIsStarIndex)
     : CXFA_FMSimpleExpression(TOKlbracket),
-      m_pExp(std::move(pIndexExp)),
+      m_pExp(pIndexExp),
       m_accessorIndex(accessorIndex),
       m_bIsStarIndex(bIsStarIndex) {}
 
 CXFA_FMIndexExpression::~CXFA_FMIndexExpression() = default;
 
+void CXFA_FMIndexExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMSimpleExpression::Trace(visitor);
+  visitor->Trace(m_pExp);
+}
+
 bool CXFA_FMIndexExpression::ToJavaScript(CFX_WideTextBuf* js,
                                           ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -677,14 +652,12 @@
 }
 
 CXFA_FMDotDotAccessorExpression::CXFA_FMDotDotAccessorExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
+    CXFA_FMSimpleExpression* pAccessor,
     XFA_FM_TOKEN op,
-    WideStringView wsIdentifier,
-    std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
-    : CXFA_FMChainableExpression(op,
-                                 std::move(pAccessor),
-                                 std::move(pIndexExp)),
-      m_wsIdentifier(wsIdentifier) {}
+    WideString wsIdentifier,
+    CXFA_FMSimpleExpression* pIndexExp)
+    : CXFA_FMChainableExpression(op, pAccessor, pIndexExp),
+      m_wsIdentifier(std::move(wsIdentifier)) {}
 
 CXFA_FMDotDotAccessorExpression::~CXFA_FMDotDotAccessorExpression() = default;
 
@@ -714,11 +687,9 @@
 }
 
 CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pCallExp)
-    : CXFA_FMChainableExpression(TOKdot,
-                                 std::move(pAccessorExp1),
-                                 std::move(pCallExp)) {}
+    CXFA_FMSimpleExpression* pAccessorExp1,
+    CXFA_FMSimpleExpression* pCallExp)
+    : CXFA_FMChainableExpression(TOKdot, pAccessorExp1, pCallExp) {}
 
 CXFA_FMMethodCallExpression::~CXFA_FMMethodCallExpression() = default;
 
@@ -743,23 +714,23 @@
   return !CXFA_IsTooBig(*js);
 }
 
-bool CXFA_IsTooBig(const CFX_WideTextBuf& js) {
-  return js.GetSize() >= 256 * 1024 * 1024;
-}
-
 CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition(
-    WideStringView wsName,
-    std::vector<WideStringView>&& arguments,
-    std::vector<std::unique_ptr<CXFA_FMExpression>>&& expressions)
-    : CXFA_FMExpression(),
-      m_wsName(wsName),
+    WideString wsName,
+    std::vector<WideString>&& arguments,
+    std::vector<cppgc::Member<CXFA_FMExpression>>&& expressions)
+    : m_wsName(std::move(wsName)),
       m_pArguments(std::move(arguments)),
       m_pExpressions(std::move(expressions)) {
-  ASSERT(!wsName.IsEmpty());
+  ASSERT(!m_wsName.IsEmpty());
 }
 
 CXFA_FMFunctionDefinition::~CXFA_FMFunctionDefinition() = default;
 
+void CXFA_FMFunctionDefinition::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMExpression::Trace(visitor);
+  ContainerTrace(visitor, m_pExpressions);
+}
+
 bool CXFA_FMFunctionDefinition::ToJavaScript(CFX_WideTextBuf* js,
                                              ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -793,11 +764,15 @@
 }
 
 CXFA_FMAST::CXFA_FMAST(
-    std::vector<std::unique_ptr<CXFA_FMExpression>> expressions)
+    std::vector<cppgc::Member<CXFA_FMExpression>> expressions)
     : expressions_(std::move(expressions)) {}
 
 CXFA_FMAST::~CXFA_FMAST() = default;
 
+void CXFA_FMAST::Trace(cppgc::Visitor* visitor) const {
+  ContainerTrace(visitor, expressions_);
+}
+
 Optional<CFX_WideTextBuf> CXFA_FMAST::ToJavaScript() const {
   CFX_WideTextBuf js;
   if (expressions_.empty()) {
@@ -832,13 +807,17 @@
   return js;
 }
 
-CXFA_FMVarExpression::CXFA_FMVarExpression(
-    WideStringView wsName,
-    std::unique_ptr<CXFA_FMSimpleExpression> pInit)
-    : CXFA_FMExpression(), m_wsName(wsName), m_pInit(std::move(pInit)) {}
+CXFA_FMVarExpression::CXFA_FMVarExpression(WideString wsName,
+                                           CXFA_FMSimpleExpression* pInit)
+    : m_wsName(std::move(wsName)), m_pInit(pInit) {}
 
 CXFA_FMVarExpression::~CXFA_FMVarExpression() = default;
 
+void CXFA_FMVarExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMExpression::Trace(visitor);
+  visitor->Trace(m_pInit);
+}
+
 bool CXFA_FMVarExpression::ToJavaScript(CFX_WideTextBuf* js,
                                         ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -863,12 +842,16 @@
   return !CXFA_IsTooBig(*js);
 }
 
-CXFA_FMExpExpression::CXFA_FMExpExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pExpression)
-    : CXFA_FMExpression(), m_pExpression(std::move(pExpression)) {}
+CXFA_FMExpExpression::CXFA_FMExpExpression(CXFA_FMSimpleExpression* pExpression)
+    : m_pExpression(pExpression) {}
 
 CXFA_FMExpExpression::~CXFA_FMExpExpression() = default;
 
+void CXFA_FMExpExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMExpression::Trace(visitor);
+  visitor->Trace(m_pExpression);
+}
+
 bool CXFA_FMExpExpression::ToJavaScript(CFX_WideTextBuf* js,
                                         ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -908,11 +891,16 @@
 }
 
 CXFA_FMBlockExpression::CXFA_FMBlockExpression(
-    std::vector<std::unique_ptr<CXFA_FMExpression>>&& pExpressionList)
-    : CXFA_FMExpression(), m_ExpressionList(std::move(pExpressionList)) {}
+    std::vector<cppgc::Member<CXFA_FMExpression>>&& pExpressionList)
+    : m_ExpressionList(std::move(pExpressionList)) {}
 
 CXFA_FMBlockExpression::~CXFA_FMBlockExpression() = default;
 
+void CXFA_FMBlockExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMExpression::Trace(visitor);
+  ContainerTrace(visitor, m_ExpressionList);
+}
+
 bool CXFA_FMBlockExpression::ToJavaScript(CFX_WideTextBuf* js,
                                           ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -937,12 +925,16 @@
   return !CXFA_IsTooBig(*js);
 }
 
-CXFA_FMDoExpression::CXFA_FMDoExpression(
-    std::unique_ptr<CXFA_FMExpression> pList)
-    : CXFA_FMExpression(), m_pList(std::move(pList)) {}
+CXFA_FMDoExpression::CXFA_FMDoExpression(CXFA_FMExpression* pList)
+    : m_pList(pList) {}
 
 CXFA_FMDoExpression::~CXFA_FMDoExpression() = default;
 
+void CXFA_FMDoExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMExpression::Trace(visitor);
+  visitor->Trace(m_pList);
+}
+
 bool CXFA_FMDoExpression::ToJavaScript(CFX_WideTextBuf* js,
                                        ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -953,20 +945,27 @@
 }
 
 CXFA_FMIfExpression::CXFA_FMIfExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pExpression,
-    std::unique_ptr<CXFA_FMExpression> pIfExpression,
-    std::vector<std::unique_ptr<CXFA_FMIfExpression>> pElseIfExpressions,
-    std::unique_ptr<CXFA_FMExpression> pElseExpression)
-    : CXFA_FMExpression(),
-      m_pExpression(std::move(pExpression)),
-      m_pIfExpression(std::move(pIfExpression)),
+    CXFA_FMSimpleExpression* pExpression,
+    CXFA_FMExpression* pIfExpression,
+    std::vector<cppgc::Member<CXFA_FMIfExpression>>&& pElseIfExpressions,
+    CXFA_FMExpression* pElseExpression)
+    : m_pExpression(pExpression),
+      m_pIfExpression(pIfExpression),
       m_pElseIfExpressions(std::move(pElseIfExpressions)),
-      m_pElseExpression(std::move(pElseExpression)) {
+      m_pElseExpression(pElseExpression) {
   ASSERT(m_pExpression);
 }
 
 CXFA_FMIfExpression::~CXFA_FMIfExpression() = default;
 
+void CXFA_FMIfExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMExpression::Trace(visitor);
+  visitor->Trace(m_pExpression);
+  visitor->Trace(m_pIfExpression);
+  ContainerTrace(visitor, m_pElseIfExpressions);
+  visitor->Trace(m_pElseExpression);
+}
+
 bool CXFA_FMIfExpression::ToJavaScript(CFX_WideTextBuf* js,
                                        ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -1006,14 +1005,18 @@
 }
 
 CXFA_FMWhileExpression::CXFA_FMWhileExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pCondition,
-    std::unique_ptr<CXFA_FMExpression> pExpression)
-    : CXFA_FMExpression(),
-      m_pCondition(std::move(pCondition)),
-      m_pExpression(std::move(pExpression)) {}
+    CXFA_FMSimpleExpression* pCondition,
+    CXFA_FMExpression* pExpression)
+    : m_pCondition(pCondition), m_pExpression(pExpression) {}
 
 CXFA_FMWhileExpression::~CXFA_FMWhileExpression() = default;
 
+void CXFA_FMWhileExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMExpression::Trace(visitor);
+  visitor->Trace(m_pCondition);
+  visitor->Trace(m_pExpression);
+}
+
 bool CXFA_FMWhileExpression::ToJavaScript(CFX_WideTextBuf* js,
                                           ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -1065,23 +1068,29 @@
   return !CXFA_IsTooBig(*js);
 }
 
-CXFA_FMForExpression::CXFA_FMForExpression(
-    WideStringView wsVariant,
-    std::unique_ptr<CXFA_FMSimpleExpression> pAssignment,
-    std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
-    int32_t iDirection,
-    std::unique_ptr<CXFA_FMSimpleExpression> pStep,
-    std::unique_ptr<CXFA_FMExpression> pList)
-    : CXFA_FMExpression(),
-      m_wsVariant(wsVariant),
-      m_pAssignment(std::move(pAssignment)),
-      m_pAccessor(std::move(pAccessor)),
+CXFA_FMForExpression::CXFA_FMForExpression(WideString wsVariant,
+                                           CXFA_FMSimpleExpression* pAssignment,
+                                           CXFA_FMSimpleExpression* pAccessor,
+                                           int32_t iDirection,
+                                           CXFA_FMSimpleExpression* pStep,
+                                           CXFA_FMExpression* pList)
+    : m_wsVariant(std::move(wsVariant)),
       m_bDirection(iDirection == 1),
-      m_pStep(std::move(pStep)),
-      m_pList(std::move(pList)) {}
+      m_pAssignment(pAssignment),
+      m_pAccessor(pAccessor),
+      m_pStep(pStep),
+      m_pList(pList) {}
 
 CXFA_FMForExpression::~CXFA_FMForExpression() = default;
 
+void CXFA_FMForExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMExpression::Trace(visitor);
+  visitor->Trace(m_pAssignment);
+  visitor->Trace(m_pAccessor);
+  visitor->Trace(m_pStep);
+  visitor->Trace(m_pList);
+}
+
 bool CXFA_FMForExpression::ToJavaScript(CFX_WideTextBuf* js,
                                         ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -1128,16 +1137,21 @@
 }
 
 CXFA_FMForeachExpression::CXFA_FMForeachExpression(
-    WideStringView wsIdentifier,
-    std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pAccessors,
-    std::unique_ptr<CXFA_FMExpression> pList)
-    : CXFA_FMExpression(),
-      m_wsIdentifier(wsIdentifier),
+    WideString wsIdentifier,
+    std::vector<cppgc::Member<CXFA_FMSimpleExpression>>&& pAccessors,
+    CXFA_FMExpression* pList)
+    : m_wsIdentifier(std::move(wsIdentifier)),
       m_pAccessors(std::move(pAccessors)),
-      m_pList(std::move(pList)) {}
+      m_pList(pList) {}
 
 CXFA_FMForeachExpression::~CXFA_FMForeachExpression() = default;
 
+void CXFA_FMForeachExpression::Trace(cppgc::Visitor* visitor) const {
+  CXFA_FMExpression::Trace(visitor);
+  ContainerTrace(visitor, m_pAccessors);
+  visitor->Trace(m_pList);
+}
+
 bool CXFA_FMForeachExpression::ToJavaScript(CFX_WideTextBuf* js,
                                             ReturnType type) const {
   CXFA_FMToJavaScriptDepth depthManager;
@@ -1170,3 +1184,7 @@
   *js << "}\n";  // block
   return !CXFA_IsTooBig(*js);
 }
+
+bool CXFA_IsTooBig(const CFX_WideTextBuf& js) {
+  return js.GetSize() >= 256 * 1024 * 1024;
+}
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.h b/xfa/fxfa/fm2js/cxfa_fmexpression.h
index 1a33eff..13700c2 100644
--- a/xfa/fxfa/fm2js/cxfa_fmexpression.h
+++ b/xfa/fxfa/fm2js/cxfa_fmexpression.h
@@ -7,10 +7,13 @@
 #ifndef XFA_FXFA_FM2JS_CXFA_FMEXPRESSION_H_
 #define XFA_FXFA_FM2JS_CXFA_FMEXPRESSION_H_
 
-#include <memory>
 #include <vector>
 
+#include "core/fxcrt/fx_string.h"
+#include "fxjs/gc/heap.h"
 #include "third_party/base/optional.h"
+#include "v8/include/cppgc/garbage-collected.h"
+#include "v8/include/cppgc/member.h"
 #include "xfa/fxfa/fm2js/cxfa_fmlexer.h"
 
 class CFX_WideTextBuf;
@@ -24,9 +27,11 @@
 
 enum class ReturnType { kImplied, kInfered };
 
-class CXFA_FMExpression {
+class CXFA_FMExpression : public cppgc::GarbageCollected<CXFA_FMExpression> {
  public:
   virtual ~CXFA_FMExpression();
+  virtual void Trace(cppgc::Visitor* visitor) const;
+
   virtual bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const = 0;
 
  protected:
@@ -38,87 +43,93 @@
   ~CXFA_FMSimpleExpression() override;
 
   XFA_FM_TOKEN GetOperatorToken() const { return m_op; }
-  bool chainable() const { return m_bChainable; }
 
  protected:
   explicit CXFA_FMSimpleExpression(XFA_FM_TOKEN op);
-  CXFA_FMSimpleExpression(XFA_FM_TOKEN op, bool chainable);
 
  private:
   const XFA_FM_TOKEN m_op;
-  const bool m_bChainable;
 };
 
 class CXFA_FMChainableExpression : public CXFA_FMSimpleExpression {
  public:
   ~CXFA_FMChainableExpression() override;
+  void Trace(cppgc::Visitor* visitor) const override;
 
  protected:
   CXFA_FMChainableExpression(XFA_FM_TOKEN op,
-                             std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                             std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+                             CXFA_FMSimpleExpression* pExp1,
+                             CXFA_FMSimpleExpression* pExp2);
 
-  CXFA_FMSimpleExpression* GetFirstExpression() const;
-  CXFA_FMSimpleExpression* GetSecondExpression() const;
+  CXFA_FMSimpleExpression* GetFirstExpression() const { return m_pExp1; }
+  CXFA_FMSimpleExpression* GetSecondExpression() const { return m_pExp2; }
 
  private:
-  // Iteratively delete a chainable expression tree in linear time and constant
-  // space.
-  static void DeleteChain(std::unique_ptr<CXFA_FMSimpleExpression> pRoot);
-
-  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp1;
-  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp2;
+  cppgc::Member<CXFA_FMSimpleExpression> m_pExp1;
+  cppgc::Member<CXFA_FMSimpleExpression> m_pExp2;
 };
 
 class CXFA_FMNullExpression final : public CXFA_FMSimpleExpression {
  public:
-  CXFA_FMNullExpression();
-  ~CXFA_FMNullExpression() override = default;
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMNullExpression() override;
 
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ private:
+  CXFA_FMNullExpression();
 };
 
 class CXFA_FMNumberExpression final : public CXFA_FMSimpleExpression {
  public:
-  explicit CXFA_FMNumberExpression(WideStringView wsNumber);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMNumberExpression() override;
 
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  WideStringView m_wsNumber;
+  explicit CXFA_FMNumberExpression(WideString wsNumber);
+
+  WideString m_wsNumber;
 };
 
 class CXFA_FMStringExpression final : public CXFA_FMSimpleExpression {
  public:
-  explicit CXFA_FMStringExpression(WideStringView wsString);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMStringExpression() override;
 
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  WideStringView m_wsString;
+  explicit CXFA_FMStringExpression(WideString wsString);
+
+  WideString m_wsString;
 };
 
 class CXFA_FMIdentifierExpression final : public CXFA_FMSimpleExpression {
  public:
-  explicit CXFA_FMIdentifierExpression(WideStringView wsIdentifier);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMIdentifierExpression() override;
 
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  WideStringView m_wsIdentifier;
+  explicit CXFA_FMIdentifierExpression(WideString wsIdentifier);
+
+  WideString m_wsIdentifier;
 };
 
 class CXFA_FMAssignExpression final : public CXFA_FMChainableExpression {
  public:
-  CXFA_FMAssignExpression(XFA_FM_TOKEN op,
-                          std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                          std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMAssignExpression() override;
 
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ private:
+  CXFA_FMAssignExpression(XFA_FM_TOKEN op,
+                          CXFA_FMSimpleExpression* pExp1,
+                          CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMBinExpression : public CXFA_FMChainableExpression {
@@ -130,8 +141,8 @@
  protected:
   CXFA_FMBinExpression(const WideString& opName,
                        XFA_FM_TOKEN op,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+                       CXFA_FMSimpleExpression* pExp1,
+                       CXFA_FMSimpleExpression* pExp2);
 
  private:
   WideString m_OpName;
@@ -139,179 +150,232 @@
 
 class CXFA_FMLogicalOrExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMLogicalOrExpression() override;
+
+ private:
   CXFA_FMLogicalOrExpression(XFA_FM_TOKEN op,
-                             std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                             std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMLogicalOrExpression() override = default;
+                             CXFA_FMSimpleExpression* pExp1,
+                             CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMLogicalAndExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMLogicalAndExpression() override;
+
+ private:
   CXFA_FMLogicalAndExpression(XFA_FM_TOKEN op,
-                              std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                              std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMLogicalAndExpression() override = default;
+                              CXFA_FMSimpleExpression* pExp1,
+                              CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMEqualExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMEqualExpression() override;
+
+ private:
   CXFA_FMEqualExpression(XFA_FM_TOKEN op,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMEqualExpression() override = default;
+                         CXFA_FMSimpleExpression* pExp1,
+                         CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMNotEqualExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMNotEqualExpression() override;
+
+ private:
   CXFA_FMNotEqualExpression(XFA_FM_TOKEN op,
-                            std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                            std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMNotEqualExpression() override = default;
+                            CXFA_FMSimpleExpression* pExp1,
+                            CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMGtExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMGtExpression() override;
+
+ private:
   CXFA_FMGtExpression(XFA_FM_TOKEN op,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMGtExpression() override = default;
+                      CXFA_FMSimpleExpression* pExp1,
+                      CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMGeExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMGeExpression() override;
+
+ private:
   CXFA_FMGeExpression(XFA_FM_TOKEN op,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMGeExpression() override = default;
+                      CXFA_FMSimpleExpression* pExp1,
+                      CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMLtExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMLtExpression() override;
+
+ private:
   CXFA_FMLtExpression(XFA_FM_TOKEN op,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMLtExpression() override = default;
+                      CXFA_FMSimpleExpression* pExp1,
+                      CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMLeExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMLeExpression() override;
+
+ private:
   CXFA_FMLeExpression(XFA_FM_TOKEN op,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMLeExpression() override = default;
+                      CXFA_FMSimpleExpression* pExp1,
+                      CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMPlusExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMPlusExpression() override;
+
+ private:
   CXFA_FMPlusExpression(XFA_FM_TOKEN op,
-                        std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                        std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMPlusExpression() override = default;
+                        CXFA_FMSimpleExpression* pExp1,
+                        CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMMinusExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMMinusExpression() override;
+
+ private:
   CXFA_FMMinusExpression(XFA_FM_TOKEN op,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMMinusExpression() override = default;
+                         CXFA_FMSimpleExpression* pExp1,
+                         CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMMulExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMMulExpression() override;
+
+ private:
   CXFA_FMMulExpression(XFA_FM_TOKEN op,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMMulExpression() override = default;
+                       CXFA_FMSimpleExpression* pExp1,
+                       CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMDivExpression final : public CXFA_FMBinExpression {
  public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMDivExpression() override;
+
+ private:
   CXFA_FMDivExpression(XFA_FM_TOKEN op,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMDivExpression() override = default;
+                       CXFA_FMSimpleExpression* pExp1,
+                       CXFA_FMSimpleExpression* pExp2);
 };
 
 class CXFA_FMUnaryExpression : public CXFA_FMSimpleExpression {
  public:
   ~CXFA_FMUnaryExpression() override;
 
+  void Trace(cppgc::Visitor* visitor) const override;
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  protected:
   CXFA_FMUnaryExpression(const WideString& opName,
                          XFA_FM_TOKEN op,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pExp);
+                         CXFA_FMSimpleExpression* pExp);
 
  private:
   WideString m_OpName;
-  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
+  cppgc::Member<CXFA_FMSimpleExpression> m_pExp;
 };
 
 class CXFA_FMPosExpression final : public CXFA_FMUnaryExpression {
  public:
-  explicit CXFA_FMPosExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
-  ~CXFA_FMPosExpression() override = default;
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMPosExpression() override;
+
+ private:
+  explicit CXFA_FMPosExpression(CXFA_FMSimpleExpression* pExp);
 };
 
 class CXFA_FMNegExpression final : public CXFA_FMUnaryExpression {
  public:
-  explicit CXFA_FMNegExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
-  ~CXFA_FMNegExpression() override = default;
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMNegExpression() override;
+
+ private:
+  explicit CXFA_FMNegExpression(CXFA_FMSimpleExpression* pExp);
 };
 
 class CXFA_FMNotExpression final : public CXFA_FMUnaryExpression {
  public:
-  explicit CXFA_FMNotExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
-  ~CXFA_FMNotExpression() override = default;
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMNotExpression() override;
+
+ private:
+  explicit CXFA_FMNotExpression(CXFA_FMSimpleExpression* pExp);
 };
 
 class CXFA_FMCallExpression final : public CXFA_FMSimpleExpression {
  public:
-  CXFA_FMCallExpression(
-      std::unique_ptr<CXFA_FMSimpleExpression> pExp,
-      std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments,
-      bool bIsSomMethod);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMCallExpression() override;
 
+  void Trace(cppgc::Visitor* visitor) const override;
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
   bool IsBuiltInFunc(CFX_WideTextBuf* funcName) const;
   uint32_t IsMethodWithObjParam(const WideString& methodName) const;
 
  private:
-  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
+  CXFA_FMCallExpression(
+      CXFA_FMSimpleExpression* pExp,
+      std::vector<cppgc::Member<CXFA_FMSimpleExpression>>&& pArguments,
+      bool bIsSomMethod);
+
+  cppgc::Member<CXFA_FMSimpleExpression> m_pExp;
+  std::vector<cppgc::Member<CXFA_FMSimpleExpression>> m_Arguments;
   bool m_bIsSomMethod;
-  std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> m_Arguments;
 };
 
 class CXFA_FMDotAccessorExpression final : public CXFA_FMChainableExpression {
  public:
-  CXFA_FMDotAccessorExpression(
-      std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
-      XFA_FM_TOKEN op,
-      WideStringView wsIdentifier,
-      std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMDotAccessorExpression() override;
 
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  WideStringView m_wsIdentifier;
+  CXFA_FMDotAccessorExpression(CXFA_FMSimpleExpression* pAccessor,
+                               XFA_FM_TOKEN op,
+                               WideString wsIdentifier,
+                               CXFA_FMSimpleExpression* pIndexExp);
+
+  WideString m_wsIdentifier;
 };
 
 class CXFA_FMIndexExpression final : public CXFA_FMSimpleExpression {
  public:
-  CXFA_FMIndexExpression(XFA_FM_AccessorIndex accessorIndex,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp,
-                         bool bIsStarIndex);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMIndexExpression() override;
 
+  void Trace(cppgc::Visitor* visitor) const override;
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
+  CXFA_FMIndexExpression(XFA_FM_AccessorIndex accessorIndex,
+                         CXFA_FMSimpleExpression* pIndexExp,
+                         bool bIsStarIndex);
+
+  cppgc::Member<CXFA_FMSimpleExpression> m_pExp;
   XFA_FM_AccessorIndex m_accessorIndex;
   bool m_bIsStarIndex;
 };
@@ -319,190 +383,227 @@
 class CXFA_FMDotDotAccessorExpression final
     : public CXFA_FMChainableExpression {
  public:
-  CXFA_FMDotDotAccessorExpression(
-      std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
-      XFA_FM_TOKEN op,
-      WideStringView wsIdentifier,
-      std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMDotDotAccessorExpression() override;
 
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  WideStringView m_wsIdentifier;
+  CXFA_FMDotDotAccessorExpression(CXFA_FMSimpleExpression* pAccessor,
+                                  XFA_FM_TOKEN op,
+                                  WideString wsIdentifier,
+                                  CXFA_FMSimpleExpression* pIndexExp);
+
+  WideString m_wsIdentifier;
 };
 
 class CXFA_FMMethodCallExpression final : public CXFA_FMChainableExpression {
  public:
-  CXFA_FMMethodCallExpression(
-      std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1,
-      std::unique_ptr<CXFA_FMSimpleExpression> pCallExp);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMMethodCallExpression() override;
 
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
-};
-
-bool CXFA_IsTooBig(const CFX_WideTextBuf& js);
-
-class CXFA_FMFunctionDefinition final : public CXFA_FMExpression {
- public:
-  CXFA_FMFunctionDefinition(
-      WideStringView wsName,
-      std::vector<WideStringView>&& arguments,
-      std::vector<std::unique_ptr<CXFA_FMExpression>>&& expressions);
-  ~CXFA_FMFunctionDefinition() override;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  const WideStringView m_wsName;
-  std::vector<WideStringView> const m_pArguments;
-  std::vector<std::unique_ptr<CXFA_FMExpression>> const m_pExpressions;
+  CXFA_FMMethodCallExpression(CXFA_FMSimpleExpression* pAccessorExp1,
+                              CXFA_FMSimpleExpression* pCallExp);
+};
+
+class CXFA_FMFunctionDefinition final : public CXFA_FMExpression {
+ public:
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
+  ~CXFA_FMFunctionDefinition() override;
+
+  void Trace(cppgc::Visitor* visitor) const override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ private:
+  CXFA_FMFunctionDefinition(
+      WideString wsName,
+      std::vector<WideString>&& arguments,
+      std::vector<cppgc::Member<CXFA_FMExpression>>&& expressions);
+
+  const WideString m_wsName;
+  std::vector<WideString> const m_pArguments;
+  std::vector<cppgc::Member<CXFA_FMExpression>> const m_pExpressions;
 };
 
 class CXFA_FMVarExpression final : public CXFA_FMExpression {
  public:
-  CXFA_FMVarExpression(WideStringView wsName,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pInit);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMVarExpression() override;
 
+  void Trace(cppgc::Visitor* visitor) const override;
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  WideStringView const m_wsName;
-  std::unique_ptr<CXFA_FMSimpleExpression> const m_pInit;
+  CXFA_FMVarExpression(WideString wsName, CXFA_FMSimpleExpression* pInit);
+
+  WideString const m_wsName;
+  cppgc::Member<CXFA_FMSimpleExpression> const m_pInit;
 };
 
 class CXFA_FMExpExpression final : public CXFA_FMExpression {
  public:
-  explicit CXFA_FMExpExpression(
-      std::unique_ptr<CXFA_FMSimpleExpression> pExpression);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMExpExpression() override;
 
+  void Trace(cppgc::Visitor* visitor) const override;
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  std::unique_ptr<CXFA_FMSimpleExpression> const m_pExpression;
+  explicit CXFA_FMExpExpression(CXFA_FMSimpleExpression* pExpression);
+
+  cppgc::Member<CXFA_FMSimpleExpression> const m_pExpression;
 };
 
 class CXFA_FMBlockExpression final : public CXFA_FMExpression {
  public:
-  CXFA_FMBlockExpression(
-      std::vector<std::unique_ptr<CXFA_FMExpression>>&& pExpressionList);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMBlockExpression() override;
 
+  void Trace(cppgc::Visitor* visitor) const override;
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  std::vector<std::unique_ptr<CXFA_FMExpression>> const m_ExpressionList;
+  CXFA_FMBlockExpression(
+      std::vector<cppgc::Member<CXFA_FMExpression>>&& pExpressionList);
+
+  std::vector<cppgc::Member<CXFA_FMExpression>> const m_ExpressionList;
 };
 
 class CXFA_FMDoExpression final : public CXFA_FMExpression {
  public:
-  explicit CXFA_FMDoExpression(std::unique_ptr<CXFA_FMExpression> pList);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMDoExpression() override;
 
+  void Trace(cppgc::Visitor* visitor) const override;
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  std::unique_ptr<CXFA_FMExpression> const m_pList;
+  explicit CXFA_FMDoExpression(CXFA_FMExpression* pList);
+
+  cppgc::Member<CXFA_FMExpression> const m_pList;
 };
 
 class CXFA_FMIfExpression final : public CXFA_FMExpression {
  public:
-  CXFA_FMIfExpression(
-      std::unique_ptr<CXFA_FMSimpleExpression> pExpression,
-      std::unique_ptr<CXFA_FMExpression> pIfExpression,
-      std::vector<std::unique_ptr<CXFA_FMIfExpression>> pElseIfExpressions,
-      std::unique_ptr<CXFA_FMExpression> pElseExpression);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMIfExpression() override;
 
+  void Trace(cppgc::Visitor* visitor) const override;
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  std::unique_ptr<CXFA_FMSimpleExpression> const m_pExpression;
-  std::unique_ptr<CXFA_FMExpression> const m_pIfExpression;
-  std::vector<std::unique_ptr<CXFA_FMIfExpression>> const m_pElseIfExpressions;
-  std::unique_ptr<CXFA_FMExpression> const m_pElseExpression;
+  CXFA_FMIfExpression(
+      CXFA_FMSimpleExpression* pExpression,
+      CXFA_FMExpression* pIfExpression,
+      std::vector<cppgc::Member<CXFA_FMIfExpression>>&& pElseIfExpressions,
+      CXFA_FMExpression* pElseExpression);
+
+  cppgc::Member<CXFA_FMSimpleExpression> const m_pExpression;
+  cppgc::Member<CXFA_FMExpression> const m_pIfExpression;
+  std::vector<cppgc::Member<CXFA_FMIfExpression>> const m_pElseIfExpressions;
+  cppgc::Member<CXFA_FMExpression> const m_pElseExpression;
 };
 
 class CXFA_FMWhileExpression final : public CXFA_FMExpression {
  public:
-  CXFA_FMWhileExpression(std::unique_ptr<CXFA_FMSimpleExpression> pCodition,
-                         std::unique_ptr<CXFA_FMExpression> pExpression);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMWhileExpression() override;
 
+  void Trace(cppgc::Visitor* visitor) const override;
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  std::unique_ptr<CXFA_FMSimpleExpression> const m_pCondition;
-  std::unique_ptr<CXFA_FMExpression> const m_pExpression;
+  CXFA_FMWhileExpression(CXFA_FMSimpleExpression* pCodition,
+                         CXFA_FMExpression* pExpression);
+
+  cppgc::Member<CXFA_FMSimpleExpression> const m_pCondition;
+  cppgc::Member<CXFA_FMExpression> const m_pExpression;
 };
 
 class CXFA_FMBreakExpression final : public CXFA_FMExpression {
  public:
-  CXFA_FMBreakExpression();
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMBreakExpression() override;
 
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ private:
+  CXFA_FMBreakExpression();
 };
 
 class CXFA_FMContinueExpression final : public CXFA_FMExpression {
  public:
-  CXFA_FMContinueExpression();
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMContinueExpression() override;
 
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ private:
+  CXFA_FMContinueExpression();
 };
 
 class CXFA_FMForExpression final : public CXFA_FMExpression {
  public:
-  CXFA_FMForExpression(WideStringView wsVariant,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pAssignment,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
-                       int32_t iDirection,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pStep,
-                       std::unique_ptr<CXFA_FMExpression> pList);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMForExpression() override;
 
+  void Trace(cppgc::Visitor* visitor) const override;
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  const WideStringView m_wsVariant;
-  std::unique_ptr<CXFA_FMSimpleExpression> const m_pAssignment;
-  std::unique_ptr<CXFA_FMSimpleExpression> const m_pAccessor;
+  CXFA_FMForExpression(WideString wsVariant,
+                       CXFA_FMSimpleExpression* pAssignment,
+                       CXFA_FMSimpleExpression* pAccessor,
+                       int32_t iDirection,
+                       CXFA_FMSimpleExpression* pStep,
+                       CXFA_FMExpression* pList);
+
+  const WideString m_wsVariant;
   const bool m_bDirection;
-  std::unique_ptr<CXFA_FMSimpleExpression> const m_pStep;
-  std::unique_ptr<CXFA_FMExpression> const m_pList;
+  cppgc::Member<CXFA_FMSimpleExpression> const m_pAssignment;
+  cppgc::Member<CXFA_FMSimpleExpression> const m_pAccessor;
+  cppgc::Member<CXFA_FMSimpleExpression> const m_pStep;
+  cppgc::Member<CXFA_FMExpression> const m_pList;
 };
 
 class CXFA_FMForeachExpression final : public CXFA_FMExpression {
  public:
-  // Takes ownership of |pAccessors|.
-  CXFA_FMForeachExpression(
-      WideStringView wsIdentifier,
-      std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pAccessors,
-      std::unique_ptr<CXFA_FMExpression> pList);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMForeachExpression() override;
 
+  void Trace(cppgc::Visitor* visitor) const override;
   bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
 
  private:
-  const WideStringView m_wsIdentifier;
-  std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> const m_pAccessors;
-  std::unique_ptr<CXFA_FMExpression> const m_pList;
+  // Takes ownership of |pAccessors|.
+  CXFA_FMForeachExpression(
+      WideString wsIdentifier,
+      std::vector<cppgc::Member<CXFA_FMSimpleExpression>>&& pAccessors,
+      CXFA_FMExpression* pList);
+
+  const WideString m_wsIdentifier;
+  std::vector<cppgc::Member<CXFA_FMSimpleExpression>> const m_pAccessors;
+  cppgc::Member<CXFA_FMExpression> const m_pList;
 };
 
-class CXFA_FMAST {
+class CXFA_FMAST : public cppgc::GarbageCollected<CXFA_FMAST> {
  public:
-  explicit CXFA_FMAST(
-      std::vector<std::unique_ptr<CXFA_FMExpression>> expressions);
+  CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
   ~CXFA_FMAST();
 
+  void Trace(cppgc::Visitor* visitor) const;
   Optional<CFX_WideTextBuf> ToJavaScript() const;
 
  private:
-  std::vector<std::unique_ptr<CXFA_FMExpression>> const expressions_;
+  explicit CXFA_FMAST(
+      std::vector<cppgc::Member<CXFA_FMExpression>> expressions);
+
+  std::vector<cppgc::Member<CXFA_FMExpression>> const expressions_;
 };
 
+bool CXFA_IsTooBig(const CFX_WideTextBuf& js);
+
 #endif  // XFA_FXFA_FM2JS_CXFA_FMEXPRESSION_H_
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp
index 6903a0f..c0b70e3 100644
--- a/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp
@@ -9,23 +9,31 @@
 
 #include "core/fxcrt/cfx_widetextbuf.h"
 #include "core/fxcrt/fx_string.h"
+#include "testing/fxgc_unittest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "xfa/fxfa/fm2js/cxfa_fmlexer.h"
 #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
 
-TEST(FMCallExpressionTest, more_than_32_arguments) {
+class FMExpressionTest : public FXGCUnitTest {};
+class FMCallExpressionTest : public FXGCUnitTest {};
+class FMStringExpressionTest : public FXGCUnitTest {};
+
+TEST_F(FMCallExpressionTest, more_than_32_arguments) {
   // Use sign as it has 3 object parameters at positions 0, 5, and 6.
-  auto exp = std::make_unique<CXFA_FMIdentifierExpression>(L"sign");
+  auto* exp = cppgc::MakeGarbageCollected<CXFA_FMIdentifierExpression>(
+      heap()->GetAllocationHandle(), L"sign");
 
-  std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> args;
-  for (size_t i = 0; i < 50; i++)
-    args.push_back(std::make_unique<CXFA_FMNullExpression>());
-
+  std::vector<cppgc::Member<CXFA_FMSimpleExpression>> args;
+  for (size_t i = 0; i < 50; i++) {
+    args.push_back(cppgc::MakeGarbageCollected<CXFA_FMNullExpression>(
+        heap()->GetAllocationHandle()));
+  }
   CXFA_FMToJavaScriptDepth::Reset();
-  CXFA_FMCallExpression callExp(std::move(exp), std::move(args), true);
+  auto* callExp = cppgc::MakeGarbageCollected<CXFA_FMCallExpression>(
+      heap()->GetAllocationHandle(), exp, std::move(args), true);
 
   CFX_WideTextBuf js;
-  callExp.ToJavaScript(&js, ReturnType::kInfered);
+  callExp->ToJavaScript(&js, ReturnType::kInfered);
 
   // Generate the result javascript string.
   WideString result = L"sign(";
@@ -45,65 +53,74 @@
   EXPECT_EQ(result.AsStringView(), js.AsStringView());
 }
 
-TEST(FMStringExpressionTest, Empty) {
+TEST_F(FMStringExpressionTest, Empty) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(L"").ToJavaScript(&accumulator, ReturnType::kInfered);
+  auto* exp = cppgc::MakeGarbageCollected<CXFA_FMStringExpression>(
+      heap()->GetAllocationHandle(), L"");
+  exp->ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_EQ(L"", accumulator.AsStringView());
 }
 
-TEST(FMStringExpressionTest, Short) {
+TEST_F(FMStringExpressionTest, Short) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(L"a").ToJavaScript(&accumulator,
-                                             ReturnType::kInfered);
+  auto* exp = cppgc::MakeGarbageCollected<CXFA_FMStringExpression>(
+      heap()->GetAllocationHandle(), L"a");
+  exp->ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_EQ(L"a", accumulator.AsStringView());
 }
 
-TEST(FMStringExpressionTest, Medium) {
+TEST_F(FMStringExpressionTest, Medium) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(L".abcd.").ToJavaScript(&accumulator,
-                                                  ReturnType::kInfered);
+  auto* exp = cppgc::MakeGarbageCollected<CXFA_FMStringExpression>(
+      heap()->GetAllocationHandle(), L".abcd.");
+  exp->ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_EQ(L"\"abcd\"", accumulator.AsStringView());
 }
 
-TEST(FMStringExpressionTest, Long) {
+TEST_F(FMStringExpressionTest, Long) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
   std::vector<WideStringView::UnsignedType> vec(140000, L'A');
-  CXFA_FMStringExpression(WideStringView(vec))
-      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  auto* exp = cppgc::MakeGarbageCollected<CXFA_FMStringExpression>(
+      heap()->GetAllocationHandle(), WideString(WideStringView(vec)));
+  exp->ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_EQ(140000u, accumulator.GetLength());
 }
 
-TEST(FMStringExpressionTest, Quoted) {
+TEST_F(FMStringExpressionTest, Quoted) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(L".Simon says \"\"run\"\".")
-      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  auto* exp = cppgc::MakeGarbageCollected<CXFA_FMStringExpression>(
+      heap()->GetAllocationHandle(), L".Simon says \"\"run\"\".");
+  exp->ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_EQ(L"\"Simon says \\\"run\\\"\"", accumulator.AsStringView());
 }
 
-TEST(CXFA_FMExpressionTest, VarExpressionInitNull) {
+TEST_F(FMExpressionTest, VarExpressionInitNull) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
 
-  CXFA_FMVarExpression(L"s", nullptr)
-      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  auto* expr = cppgc::MakeGarbageCollected<CXFA_FMVarExpression>(
+      heap()->GetAllocationHandle(), L"s", nullptr);
+  expr->ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_STREQ(
       LR"***(var s = "";
 )***",
       accumulator.MakeString().c_str());
 }
 
-TEST(CXFA_FMExpressionTest, VarExpressionInitBlank) {
+TEST_F(FMExpressionTest, VarExpressionInitBlank) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
 
-  auto init = std::make_unique<CXFA_FMStringExpression>(LR"("")");
-  CXFA_FMVarExpression(L"s", std::move(init))
-      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  auto* init = cppgc::MakeGarbageCollected<CXFA_FMStringExpression>(
+      heap()->GetAllocationHandle(), LR"("")");
+  auto* expr = cppgc::MakeGarbageCollected<CXFA_FMVarExpression>(
+      heap()->GetAllocationHandle(), L"s", init);
+  expr->ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_STREQ(
       LR"***(var s = "";
 s = pfm_rt.var_filter(s);
@@ -111,13 +128,15 @@
       accumulator.MakeString().c_str());
 }
 
-TEST(CXFA_FMExpressionTest, VarExpressionInitString) {
+TEST_F(FMExpressionTest, VarExpressionInitString) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
 
-  auto init = std::make_unique<CXFA_FMStringExpression>(LR"("foo")");
-  CXFA_FMVarExpression(L"s", std::move(init))
-      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  auto* init = cppgc::MakeGarbageCollected<CXFA_FMStringExpression>(
+      heap()->GetAllocationHandle(), LR"("foo")");
+  auto* expr = cppgc::MakeGarbageCollected<CXFA_FMVarExpression>(
+      heap()->GetAllocationHandle(), L"s", init);
+  expr->ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_STREQ(
       LR"***(var s = "foo";
 s = pfm_rt.var_filter(s);
@@ -125,13 +144,15 @@
       accumulator.MakeString().c_str());
 }
 
-TEST(CXFA_FMExpressionTest, VarExpressionInitNumeric) {
+TEST_F(FMExpressionTest, VarExpressionInitNumeric) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
 
-  auto init = std::make_unique<CXFA_FMNumberExpression>(L"112");
-  CXFA_FMVarExpression(L"s", std::move(init))
-      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  auto* init = cppgc::MakeGarbageCollected<CXFA_FMNumberExpression>(
+      heap()->GetAllocationHandle(), L"112");
+  auto* expr = cppgc::MakeGarbageCollected<CXFA_FMVarExpression>(
+      heap()->GetAllocationHandle(), L"s", init);
+  expr->ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_STREQ(
       LR"***(var s = 112;
 s = pfm_rt.var_filter(s);
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser.cpp b/xfa/fxfa/fm2js/cxfa_fmparser.cpp
index 2f1cb7e..24742b1 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmparser.cpp
@@ -20,15 +20,16 @@
 
 }  // namespace
 
-CXFA_FMParser::CXFA_FMParser(WideStringView wsFormcalc)
-    : m_lexer(std::make_unique<CXFA_FMLexer>(wsFormcalc)),
+CXFA_FMParser::CXFA_FMParser(cppgc::Heap* pHeap, WideStringView wsFormcalc)
+    : m_heap(pHeap),
+      m_lexer(std::make_unique<CXFA_FMLexer>(wsFormcalc)),
       m_error(false),
       m_parse_depth(0),
       m_max_parse_depth(kMaxParseDepth) {}
 
 CXFA_FMParser::~CXFA_FMParser() = default;
 
-std::unique_ptr<CXFA_FMAST> CXFA_FMParser::Parse() {
+CXFA_FMAST* CXFA_FMParser::Parse() {
   m_token = m_lexer->NextToken();
   if (HasError())
     return nullptr;
@@ -41,7 +42,8 @@
   if (!m_lexer->IsComplete())
     return nullptr;
 
-  return std::make_unique<CXFA_FMAST>(std::move(expressions));
+  return cppgc::MakeGarbageCollected<CXFA_FMAST>(m_heap->GetAllocationHandle(),
+                                                 std::move(expressions));
 }
 
 bool CXFA_FMParser::NextToken() {
@@ -69,13 +71,13 @@
   return ++m_parse_depth < m_max_parse_depth;
 }
 
-std::vector<std::unique_ptr<CXFA_FMExpression>>
+std::vector<cppgc::Member<CXFA_FMExpression>>
 CXFA_FMParser::ParseExpressionList() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
-    return std::vector<std::unique_ptr<CXFA_FMExpression>>();
+    return std::vector<cppgc::Member<CXFA_FMExpression>>();
 
-  std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
+  std::vector<cppgc::Member<CXFA_FMExpression>> expressions;
   while (!HasError()) {
     if (m_token.m_type == TOKeof || m_token.m_type == TOKendfunc ||
         m_token.m_type == TOKendif || m_token.m_type == TOKelseif ||
@@ -85,19 +87,17 @@
       break;
     }
 
-    std::unique_ptr<CXFA_FMExpression> expr =
+    CXFA_FMExpression* expr =
         m_token.m_type == TOKfunc ? ParseFunction() : ParseExpression();
     if (!expr) {
       m_error = true;
-      return std::vector<std::unique_ptr<CXFA_FMExpression>>();
+      return std::vector<cppgc::Member<CXFA_FMExpression>>();
     }
-
     if (expressions.size() >= kMaxExpressionListSize) {
       m_error = true;
-      return std::vector<std::unique_ptr<CXFA_FMExpression>>();
+      return std::vector<cppgc::Member<CXFA_FMExpression>>();
     }
-
-    expressions.push_back(std::move(expr));
+    expressions.push_back(expr);
   }
   return expressions;
 }
@@ -105,7 +105,7 @@
 // Func := 'func' Identifier '(' ParameterList ')' do ExpressionList 'endfunc'
 // ParamterList := (Not actually defined in the grammar) .....
 //                 (Identifier (',' Identifier)*)?
-std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseFunction() {
+CXFA_FMExpression* CXFA_FMParser::ParseFunction() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
@@ -114,13 +114,13 @@
   if (m_token.m_type != TOKidentifier)
     return nullptr;
 
-  WideStringView ident = m_token.m_string;
+  WideString ident(m_token.m_string);
   if (!NextToken())
     return nullptr;
   if (!CheckThenNext(TOKlparen))
     return nullptr;
 
-  std::vector<WideStringView> arguments;
+  std::vector<WideString> arguments;
   bool last_was_comma = false;
   while (1) {
     if (m_token.m_type == TOKrparen)
@@ -130,7 +130,7 @@
 
     last_was_comma = false;
 
-    arguments.push_back(m_token.m_string);
+    arguments.emplace_back(m_token.m_string);
     if (!NextToken())
       return nullptr;
     if (m_token.m_type != TOKcomma)
@@ -145,26 +145,27 @@
   if (!CheckThenNext(TOKdo))
     return nullptr;
 
-  std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
+  std::vector<cppgc::Member<CXFA_FMExpression>> expressions;
   if (m_token.m_type != TOKendfunc)
     expressions = ParseExpressionList();
 
   if (!CheckThenNext(TOKendfunc))
     return nullptr;
 
-  return std::make_unique<CXFA_FMFunctionDefinition>(
-      ident, std::move(arguments), std::move(expressions));
+  return cppgc::MakeGarbageCollected<CXFA_FMFunctionDefinition>(
+      m_heap->GetAllocationHandle(), std::move(ident), std::move(arguments),
+      std::move(expressions));
 }
 
 // Expression := IfExpression | WhileExpression | ForExpression |
 //               ForEachExpression | AssignmentExpression |
 //               DeclarationExpression | SimpleExpression
-std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseExpression() {
+CXFA_FMExpression* CXFA_FMParser::ParseExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMExpression> expr;
+  CXFA_FMExpression* expr = nullptr;
   switch (m_token.m_type) {
     case TOKvar:
       expr = ParseDeclarationExpression();
@@ -195,12 +196,14 @@
       expr = ParseDoExpression();
       break;
     case TOKbreak:
-      expr = std::make_unique<CXFA_FMBreakExpression>();
+      expr = cppgc::MakeGarbageCollected<CXFA_FMBreakExpression>(
+          m_heap->GetAllocationHandle());
       if (!NextToken())
         return nullptr;
       break;
     case TOKcontinue:
-      expr = std::make_unique<CXFA_FMContinueExpression>();
+      expr = cppgc::MakeGarbageCollected<CXFA_FMContinueExpression>(
+          m_heap->GetAllocationHandle());
       if (!NextToken())
         return nullptr;
       break;
@@ -213,22 +216,19 @@
 // Declaration := 'var' Variable | 'var' Variable '=' SimpleExpression |
 //           'Func' Identifier '(' ParameterList ')' do ExpressionList 'EndFunc'
 // TODO(dsinclair): We appear to be handling the 'func' case elsewhere.
-std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseDeclarationExpression() {
+CXFA_FMExpression* CXFA_FMParser::ParseDeclarationExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  WideStringView ident;
-  if (!NextToken())
-    return nullptr;
-  if (m_token.m_type != TOKidentifier)
+  if (!NextToken() || m_token.m_type != TOKidentifier)
     return nullptr;
 
-  ident = m_token.m_string;
+  WideString ident(m_token.m_string);
   if (!NextToken())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> expr;
+  CXFA_FMSimpleExpression* expr = nullptr;
   if (m_token.m_type == TOKassign) {
     if (!NextToken())
       return nullptr;
@@ -238,12 +238,12 @@
       return nullptr;
   }
 
-  return std::make_unique<CXFA_FMVarExpression>(ident, std::move(expr));
+  return cppgc::MakeGarbageCollected<CXFA_FMVarExpression>(
+      m_heap->GetAllocationHandle(), std::move(ident), expr);
 }
 
 // SimpleExpression := LogicalOrExpression
-std::unique_ptr<CXFA_FMSimpleExpression>
-CXFA_FMParser::ParseSimpleExpression() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParseSimpleExpression() {
   if (HasError())
     return nullptr;
 
@@ -251,12 +251,12 @@
 }
 
 // Exp := SimpleExpression ( '=' SimpleExpression )?
-std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseExpExpression() {
+CXFA_FMExpression* CXFA_FMParser::ParseExpExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseSimpleExpression();
+  CXFA_FMSimpleExpression* pExp1 = ParseSimpleExpression();
   if (!pExp1)
     return nullptr;
 
@@ -264,25 +264,25 @@
     if (!NextToken())
       return nullptr;
 
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2 = ParseSimpleExpression();
+    CXFA_FMSimpleExpression* pExp2 = ParseSimpleExpression();
     if (!pExp2)
       return nullptr;
 
-    pExp1 = std::make_unique<CXFA_FMAssignExpression>(
-        TOKassign, std::move(pExp1), std::move(pExp2));
+    pExp1 = cppgc::MakeGarbageCollected<CXFA_FMAssignExpression>(
+        m_heap->GetAllocationHandle(), TOKassign, pExp1, pExp2);
   }
-  return std::make_unique<CXFA_FMExpExpression>(std::move(pExp1));
+  return cppgc::MakeGarbageCollected<CXFA_FMExpExpression>(
+      m_heap->GetAllocationHandle(), pExp1);
 }
 
 // LogicalOr := LogicalAndExpression |
 //              LogicalOrExpression LogicalOrOperator LogicalAndExpression
-std::unique_ptr<CXFA_FMSimpleExpression>
-CXFA_FMParser::ParseLogicalOrExpression() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParseLogicalOrExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseLogicalAndExpression();
+  CXFA_FMSimpleExpression* e1 = ParseLogicalAndExpression();
   if (!e1)
     return nullptr;
 
@@ -295,12 +295,11 @@
       case TOKksor: {
         if (!NextToken())
           return nullptr;
-        std::unique_ptr<CXFA_FMSimpleExpression> e2(
-            ParseLogicalAndExpression());
+        CXFA_FMSimpleExpression* e2 = ParseLogicalAndExpression();
         if (!e2)
           return nullptr;
-        e1 = std::make_unique<CXFA_FMLogicalOrExpression>(TOKor, std::move(e1),
-                                                          std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMLogicalOrExpression>(
+            m_heap->GetAllocationHandle(), TOKor, e1, e2);
         break;
       }
       default:
@@ -311,13 +310,12 @@
 
 // LogicalAnd := EqualityExpression |
 //               LogicalAndExpression LogicalAndOperator EqualityExpression
-std::unique_ptr<CXFA_FMSimpleExpression>
-CXFA_FMParser::ParseLogicalAndExpression() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParseLogicalAndExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseEqualityExpression();
+  CXFA_FMSimpleExpression* e1 = ParseEqualityExpression();
   if (!e1)
     return nullptr;
 
@@ -330,11 +328,11 @@
       case TOKksand: {
         if (!NextToken())
           return nullptr;
-        std::unique_ptr<CXFA_FMSimpleExpression> e2 = ParseEqualityExpression();
+        CXFA_FMSimpleExpression* e2 = ParseEqualityExpression();
         if (!e2)
           return nullptr;
-        e1 = std::make_unique<CXFA_FMLogicalAndExpression>(
-            TOKand, std::move(e1), std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMLogicalAndExpression>(
+            m_heap->GetAllocationHandle(), TOKand, e1, e2);
         break;
       }
       default:
@@ -345,13 +343,12 @@
 
 // Equality := RelationExpression |
 //             EqualityExpression EqulaityOperator RelationalExpression
-std::unique_ptr<CXFA_FMSimpleExpression>
-CXFA_FMParser::ParseEqualityExpression() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParseEqualityExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseRelationalExpression();
+  CXFA_FMSimpleExpression* e1 = ParseRelationalExpression();
   if (!e1)
     return nullptr;
 
@@ -364,24 +361,22 @@
       case TOKkseq: {
         if (!NextToken())
           return nullptr;
-        std::unique_ptr<CXFA_FMSimpleExpression> e2 =
-            ParseRelationalExpression();
+        CXFA_FMSimpleExpression* e2 = ParseRelationalExpression();
         if (!e2)
           return nullptr;
-        e1 = std::make_unique<CXFA_FMEqualExpression>(TOKeq, std::move(e1),
-                                                      std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMEqualExpression>(
+            m_heap->GetAllocationHandle(), TOKeq, e1, e2);
         break;
       }
       case TOKne:
       case TOKksne: {
         if (!NextToken())
           return nullptr;
-        std::unique_ptr<CXFA_FMSimpleExpression> e2 =
-            ParseRelationalExpression();
+        CXFA_FMSimpleExpression* e2 = ParseRelationalExpression();
         if (!e2)
           return nullptr;
-        e1 = std::make_unique<CXFA_FMNotEqualExpression>(TOKne, std::move(e1),
-                                                         std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMNotEqualExpression>(
+            m_heap->GetAllocationHandle(), TOKne, e1, e2);
         break;
       }
       default:
@@ -392,13 +387,12 @@
 
 // Relational := AdditiveExpression |
 //               RelationalExpression RelationalOperator AdditiveExpression
-std::unique_ptr<CXFA_FMSimpleExpression>
-CXFA_FMParser::ParseRelationalExpression() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParseRelationalExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseAdditiveExpression();
+  CXFA_FMSimpleExpression* e1 = ParseAdditiveExpression();
   if (!e1)
     return nullptr;
 
@@ -406,48 +400,51 @@
     if (!IncrementParseDepthAndCheck())
       return nullptr;
 
-    std::unique_ptr<CXFA_FMSimpleExpression> e2;
     switch (m_token.m_type) {
       case TOKlt:
-      case TOKkslt:
+      case TOKkslt: {
         if (!NextToken())
           return nullptr;
-        e2 = ParseAdditiveExpression();
+        CXFA_FMSimpleExpression* e2 = ParseAdditiveExpression();
         if (!e2)
           return nullptr;
-        e1 = std::make_unique<CXFA_FMLtExpression>(TOKlt, std::move(e1),
-                                                   std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMLtExpression>(
+            m_heap->GetAllocationHandle(), TOKlt, e1, e2);
         break;
+      }
       case TOKgt:
-      case TOKksgt:
+      case TOKksgt: {
         if (!NextToken())
           return nullptr;
-        e2 = ParseAdditiveExpression();
+        CXFA_FMSimpleExpression* e2 = ParseAdditiveExpression();
         if (!e2)
           return nullptr;
-        e1 = std::make_unique<CXFA_FMGtExpression>(TOKgt, std::move(e1),
-                                                   std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMGtExpression>(
+            m_heap->GetAllocationHandle(), TOKgt, e1, e2);
         break;
+      }
       case TOKle:
-      case TOKksle:
+      case TOKksle: {
         if (!NextToken())
           return nullptr;
-        e2 = ParseAdditiveExpression();
+        CXFA_FMSimpleExpression* e2 = ParseAdditiveExpression();
         if (!e2)
           return nullptr;
-        e1 = std::make_unique<CXFA_FMLeExpression>(TOKle, std::move(e1),
-                                                   std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMLeExpression>(
+            m_heap->GetAllocationHandle(), TOKle, e1, e2);
         break;
+      }
       case TOKge:
-      case TOKksge:
+      case TOKksge: {
         if (!NextToken())
           return nullptr;
-        e2 = ParseAdditiveExpression();
+        CXFA_FMSimpleExpression* e2 = ParseAdditiveExpression();
         if (!e2)
           return nullptr;
-        e1 = std::make_unique<CXFA_FMGeExpression>(TOKge, std::move(e1),
-                                                   std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMGeExpression>(
+            m_heap->GetAllocationHandle(), TOKge, e1, e2);
         break;
+      }
       default:
         return e1;
     }
@@ -456,13 +453,12 @@
 
 // Additive := MultiplicativeExpression |
 //             AdditiveExpression AdditiveOperator MultiplicativeExpression
-std::unique_ptr<CXFA_FMSimpleExpression>
-CXFA_FMParser::ParseAdditiveExpression() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParseAdditiveExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseMultiplicativeExpression();
+  CXFA_FMSimpleExpression* e1 = ParseMultiplicativeExpression();
   if (!e1)
     return nullptr;
 
@@ -470,29 +466,27 @@
     if (!IncrementParseDepthAndCheck())
       return nullptr;
 
-    std::unique_ptr<CXFA_FMSimpleExpression> e2;
     switch (m_token.m_type) {
-      case TOKplus:
+      case TOKplus: {
         if (!NextToken())
           return nullptr;
-        e2 = ParseMultiplicativeExpression();
+        CXFA_FMSimpleExpression* e2 = ParseMultiplicativeExpression();
         if (!e2)
           return nullptr;
-
-        e1 = std::make_unique<CXFA_FMPlusExpression>(TOKplus, std::move(e1),
-                                                     std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMPlusExpression>(
+            m_heap->GetAllocationHandle(), TOKplus, e1, e2);
         break;
-      case TOKminus:
+      }
+      case TOKminus: {
         if (!NextToken())
           return nullptr;
-
-        e2 = ParseMultiplicativeExpression();
+        CXFA_FMSimpleExpression* e2 = ParseMultiplicativeExpression();
         if (!e2)
           return nullptr;
-
-        e1 = std::make_unique<CXFA_FMMinusExpression>(TOKminus, std::move(e1),
-                                                      std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMMinusExpression>(
+            m_heap->GetAllocationHandle(), TOKminus, e1, e2);
         break;
+      }
       default:
         return e1;
     }
@@ -501,13 +495,12 @@
 
 // Multiplicative := UnaryExpression |
 //                 MultiplicateExpression MultiplicativeOperator UnaryExpression
-std::unique_ptr<CXFA_FMSimpleExpression>
-CXFA_FMParser::ParseMultiplicativeExpression() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParseMultiplicativeExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseUnaryExpression();
+  CXFA_FMSimpleExpression* e1 = ParseUnaryExpression();
   if (!e1)
     return nullptr;
 
@@ -515,26 +508,27 @@
     if (!IncrementParseDepthAndCheck())
       return nullptr;
 
-    std::unique_ptr<CXFA_FMSimpleExpression> e2;
     switch (m_token.m_type) {
-      case TOKmul:
+      case TOKmul: {
         if (!NextToken())
           return nullptr;
-        e2 = ParseUnaryExpression();
+        CXFA_FMSimpleExpression* e2 = ParseUnaryExpression();
         if (!e2)
           return nullptr;
-        e1 = std::make_unique<CXFA_FMMulExpression>(TOKmul, std::move(e1),
-                                                    std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMMulExpression>(
+            m_heap->GetAllocationHandle(), TOKmul, e1, e2);
         break;
-      case TOKdiv:
+      }
+      case TOKdiv: {
         if (!NextToken())
           return nullptr;
-        e2 = ParseUnaryExpression();
+        CXFA_FMSimpleExpression* e2 = ParseUnaryExpression();
         if (!e2)
           return nullptr;
-        e1 = std::make_unique<CXFA_FMDivExpression>(TOKdiv, std::move(e1),
-                                                    std::move(e2));
+        e1 = cppgc::MakeGarbageCollected<CXFA_FMDivExpression>(
+            m_heap->GetAllocationHandle(), TOKdiv, e1, e2);
         break;
+      }
       default:
         return e1;
     }
@@ -542,102 +536,101 @@
 }
 
 // Unary := PrimaryExpression | UnaryOperator UnaryExpression
-std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseUnaryExpression() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParseUnaryExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> expr;
   switch (m_token.m_type) {
-    case TOKplus:
+    case TOKplus: {
       if (!NextToken())
         return nullptr;
-
-      expr = ParseUnaryExpression();
+      CXFA_FMSimpleExpression* expr = ParseUnaryExpression();
       if (!expr)
         return nullptr;
-
-      expr = std::make_unique<CXFA_FMPosExpression>(std::move(expr));
-      break;
-    case TOKminus:
+      return cppgc::MakeGarbageCollected<CXFA_FMPosExpression>(
+          m_heap->GetAllocationHandle(), expr);
+    }
+    case TOKminus: {
       if (!NextToken())
         return nullptr;
-
-      expr = ParseUnaryExpression();
+      CXFA_FMSimpleExpression* expr = ParseUnaryExpression();
       if (!expr)
         return nullptr;
-
-      expr = std::make_unique<CXFA_FMNegExpression>(std::move(expr));
-      break;
-    case TOKksnot:
+      return cppgc::MakeGarbageCollected<CXFA_FMNegExpression>(
+          m_heap->GetAllocationHandle(), expr);
+    }
+    case TOKksnot: {
       if (!NextToken())
         return nullptr;
-
-      expr = ParseUnaryExpression();
+      CXFA_FMSimpleExpression* expr = ParseUnaryExpression();
       if (!expr)
         return nullptr;
-
-      expr = std::make_unique<CXFA_FMNotExpression>(std::move(expr));
-      break;
+      return cppgc::MakeGarbageCollected<CXFA_FMNotExpression>(
+          m_heap->GetAllocationHandle(), expr);
+    }
     default:
       return ParsePrimaryExpression();
   }
-  return expr;
 }
 
 // Primary := Literal | FunctionCall | Accessor ('.*' )? |
 //           '(' SimpleExpression ')'
-std::unique_ptr<CXFA_FMSimpleExpression>
-CXFA_FMParser::ParsePrimaryExpression() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParsePrimaryExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> expr = ParseLiteral();
+  CXFA_FMSimpleExpression* expr = ParseLiteral();
   if (expr)
-    return NextToken() ? std::move(expr) : nullptr;
+    return NextToken() ? expr : nullptr;
 
   switch (m_token.m_type) {
     case TOKidentifier: {
-      WideStringView wsIdentifier(m_token.m_string);
+      WideString wsIdentifier(m_token.m_string);
       if (!NextToken())
         return nullptr;
       if (m_token.m_type == TOKlbracket) {
-        std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
+        CXFA_FMSimpleExpression* s = ParseIndexExpression();
         if (!s)
           return nullptr;
-
-        expr = std::make_unique<CXFA_FMDotAccessorExpression>(
-            nullptr, TOKdot, wsIdentifier, std::move(s));
+        expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
+            m_heap->GetAllocationHandle(), nullptr, TOKdot,
+            std::move(wsIdentifier), s);
         if (!expr)
           return nullptr;
         if (!NextToken())
           return nullptr;
       } else {
-        expr = std::make_unique<CXFA_FMIdentifierExpression>(wsIdentifier);
+        expr = cppgc::MakeGarbageCollected<CXFA_FMIdentifierExpression>(
+            m_heap->GetAllocationHandle(), wsIdentifier);
       }
       break;
     }
-    case TOKlparen:
+    case TOKlparen: {
       expr = ParseParenExpression();
       if (!expr)
         return nullptr;
       break;
+    }
     default:
       return nullptr;
   }
-  return ParsePostExpression(std::move(expr));
+  return ParsePostExpression(expr);
 }
 
 // Literal := String | Number | Null
-std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseLiteral() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParseLiteral() {
   switch (m_token.m_type) {
     case TOKnumber:
-      return std::make_unique<CXFA_FMNumberExpression>(m_token.m_string);
+      return cppgc::MakeGarbageCollected<CXFA_FMNumberExpression>(
+          m_heap->GetAllocationHandle(), WideString(m_token.m_string));
     case TOKstring:
-      return std::make_unique<CXFA_FMStringExpression>(m_token.m_string);
+      return cppgc::MakeGarbageCollected<CXFA_FMStringExpression>(
+          m_heap->GetAllocationHandle(), WideString(m_token.m_string));
     case TOKnull:
-      return std::make_unique<CXFA_FMNullExpression>();
+      return cppgc::MakeGarbageCollected<CXFA_FMNullExpression>(
+          m_heap->GetAllocationHandle());
     default:
       return nullptr;
   }
@@ -645,8 +638,8 @@
 
 // TODO(dsinclair): Make this match up to the grammar
 // I believe this is parsing the accessor ( '.' | '..' | '.#' )
-std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParsePostExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> expr) {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParsePostExpression(
+    CXFA_FMSimpleExpression* expr) {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
@@ -662,24 +655,25 @@
 
     switch (m_token.m_type) {
       case TOKlparen: {
-        std::unique_ptr<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>>
+        Optional<std::vector<cppgc::Member<CXFA_FMSimpleExpression>>>
             expressions = ParseArgumentList();
-        if (!expressions)
+        if (!expressions.has_value())
           return nullptr;
 
-        expr = std::make_unique<CXFA_FMCallExpression>(
-            std::move(expr), std::move(*expressions), false);
+        expr = cppgc::MakeGarbageCollected<CXFA_FMCallExpression>(
+            m_heap->GetAllocationHandle(), expr, std::move(expressions.value()),
+            false);
         if (!NextToken())
           return nullptr;
         if (m_token.m_type != TOKlbracket)
           continue;
 
-        std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
+        CXFA_FMSimpleExpression* s = ParseIndexExpression();
         if (!s)
           return nullptr;
 
-        expr = std::make_unique<CXFA_FMDotAccessorExpression>(
-            std::move(expr), TOKcall, WideStringView(), std::move(s));
+        expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
+            m_heap->GetAllocationHandle(), expr, TOKcall, WideString(), s);
         break;
       }
       case TOKdot: {
@@ -688,45 +682,50 @@
         if (m_token.m_type != TOKidentifier)
           return nullptr;
 
-        WideStringView tempStr = m_token.m_string;
+        WideString tempStr(m_token.m_string);
         if (!NextToken())
           return nullptr;
         if (m_token.m_type == TOKlparen) {
-          std::unique_ptr<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>>
+          Optional<std::vector<cppgc::Member<CXFA_FMSimpleExpression>>>
               expressions = ParseArgumentList();
-          if (!expressions)
+          if (!expressions.has_value())
             return nullptr;
 
-          auto pIdentifier =
-              std::make_unique<CXFA_FMIdentifierExpression>(tempStr);
-          auto pExpCall = std::make_unique<CXFA_FMCallExpression>(
-              std::move(pIdentifier), std::move(*expressions), true);
-          expr = std::make_unique<CXFA_FMMethodCallExpression>(
-              std::move(expr), std::move(pExpCall));
+          auto* pIdentifier =
+              cppgc::MakeGarbageCollected<CXFA_FMIdentifierExpression>(
+                  m_heap->GetAllocationHandle(), std::move(tempStr));
+          auto* pExpCall = cppgc::MakeGarbageCollected<CXFA_FMCallExpression>(
+              m_heap->GetAllocationHandle(), pIdentifier,
+              std::move(expressions.value()), true);
+          expr = cppgc::MakeGarbageCollected<CXFA_FMMethodCallExpression>(
+              m_heap->GetAllocationHandle(), expr, pExpCall);
           if (!NextToken())
             return nullptr;
           if (m_token.m_type != TOKlbracket)
             continue;
 
-          std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
+          CXFA_FMSimpleExpression* s = ParseIndexExpression();
           if (!s)
             return nullptr;
 
-          expr = std::make_unique<CXFA_FMDotAccessorExpression>(
-              std::move(expr), TOKcall, WideStringView(), std::move(s));
+          expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
+              m_heap->GetAllocationHandle(), expr, TOKcall, WideString(), s);
         } else if (m_token.m_type == TOKlbracket) {
-          std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
+          CXFA_FMSimpleExpression* s = ParseIndexExpression();
           if (!s)
             return nullptr;
 
-          expr = std::make_unique<CXFA_FMDotAccessorExpression>(
-              std::move(expr), TOKdot, tempStr, std::move(s));
+          expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
+              m_heap->GetAllocationHandle(), expr, TOKdot, std::move(tempStr),
+              s);
         } else {
-          std::unique_ptr<CXFA_FMSimpleExpression> s =
-              std::make_unique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
-                                                       nullptr, false);
-          expr = std::make_unique<CXFA_FMDotAccessorExpression>(
-              std::move(expr), TOKdot, tempStr, std::move(s));
+          CXFA_FMSimpleExpression* s =
+              cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
+                  m_heap->GetAllocationHandle(), ACCESSOR_NO_INDEX, nullptr,
+                  false);
+          expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
+              m_heap->GetAllocationHandle(), expr, TOKdot, std::move(tempStr),
+              s);
           continue;
         }
         break;
@@ -737,22 +736,25 @@
         if (m_token.m_type != TOKidentifier)
           return nullptr;
 
-        WideStringView tempStr = m_token.m_string;
+        WideString tempStr(m_token.m_string);
         if (!NextToken())
           return nullptr;
         if (m_token.m_type == TOKlbracket) {
-          std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
+          CXFA_FMSimpleExpression* s = ParseIndexExpression();
           if (!s)
             return nullptr;
 
-          expr = std::make_unique<CXFA_FMDotDotAccessorExpression>(
-              std::move(expr), TOKdotdot, tempStr, std::move(s));
+          expr = cppgc::MakeGarbageCollected<CXFA_FMDotDotAccessorExpression>(
+              m_heap->GetAllocationHandle(), expr, TOKdotdot,
+              std::move(tempStr), s);
         } else {
-          std::unique_ptr<CXFA_FMSimpleExpression> s =
-              std::make_unique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
-                                                       nullptr, false);
-          expr = std::make_unique<CXFA_FMDotDotAccessorExpression>(
-              std::move(expr), TOKdotdot, tempStr, std::move(s));
+          CXFA_FMSimpleExpression* s =
+              cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
+                  m_heap->GetAllocationHandle(), ACCESSOR_NO_INDEX, nullptr,
+                  false);
+          expr = cppgc::MakeGarbageCollected<CXFA_FMDotDotAccessorExpression>(
+              m_heap->GetAllocationHandle(), expr, TOKdotdot,
+              std::move(tempStr), s);
           continue;
         }
         break;
@@ -763,33 +765,33 @@
         if (m_token.m_type != TOKidentifier)
           return nullptr;
 
-        WideStringView tempStr = m_token.m_string;
+        WideString tempStr(m_token.m_string);
         if (!NextToken())
           return nullptr;
 
         if (m_token.m_type != TOKlbracket) {
-          std::unique_ptr<CXFA_FMSimpleExpression> s =
-              std::make_unique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
-                                                       nullptr, false);
-          expr = std::make_unique<CXFA_FMDotAccessorExpression>(
-              std::move(expr), TOKdotscream, tempStr, std::move(s));
+          auto* s = cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
+              m_heap->GetAllocationHandle(), ACCESSOR_NO_INDEX, nullptr, false);
+          expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
+              m_heap->GetAllocationHandle(), expr, TOKdotscream,
+              std::move(tempStr), s);
           continue;
         }
 
-        std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
+        CXFA_FMSimpleExpression* s = ParseIndexExpression();
         if (!s)
           return nullptr;
 
-        expr = std::make_unique<CXFA_FMDotAccessorExpression>(
-            std::move(expr), TOKdotscream, tempStr, std::move(s));
+        expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
+            m_heap->GetAllocationHandle(), expr, TOKdotscream,
+            std::move(tempStr), s);
         break;
       }
       case TOKdotstar: {
-        std::unique_ptr<CXFA_FMSimpleExpression> s =
-            std::make_unique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX, nullptr,
-                                                     false);
-        expr = std::make_unique<CXFA_FMDotAccessorExpression>(
-            std::move(expr), TOKdotstar, L"*", std::move(s));
+        auto* s = cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
+            m_heap->GetAllocationHandle(), ACCESSOR_NO_INDEX, nullptr, false);
+        expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
+            m_heap->GetAllocationHandle(), expr, TOKdotstar, L"*", s);
         break;
       }
       default:
@@ -803,36 +805,35 @@
 
 // Argument lists are zero or more comma seperated simple expressions found
 // between '(' and ')'
-std::unique_ptr<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>>
+Optional<std::vector<cppgc::Member<CXFA_FMSimpleExpression>>>
 CXFA_FMParser::ParseArgumentList() {
   if (m_token.m_type != TOKlparen || !NextToken())
-    return nullptr;
+    return pdfium::nullopt;
 
-  auto expressions =
-      std::make_unique<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>>();
+  std::vector<cppgc::Member<CXFA_FMSimpleExpression>> expressions;
   bool first_arg = true;
   while (m_token.m_type != TOKrparen) {
     if (first_arg) {
       first_arg = false;
     } else {
       if (m_token.m_type != TOKcomma || !NextToken())
-        return nullptr;
+        return pdfium::nullopt;
     }
 
-    std::unique_ptr<CXFA_FMSimpleExpression> exp = ParseSimpleExpression();
+    CXFA_FMSimpleExpression* exp = ParseSimpleExpression();
     if (!exp)
-      return nullptr;
+      return pdfium::nullopt;
 
-    expressions->push_back(std::move(exp));
-    if (expressions->size() > kMaxPostExpressions)
-      return nullptr;
+    expressions.push_back(exp);
+    if (expressions.size() > kMaxPostExpressions)
+      return pdfium::nullopt;
   }
 
   return expressions;
 }
 
 // Index := '[' ('*' | '+' SimpleExpression | '-' SimpleExpression) ']'
-std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseIndexExpression() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParseIndexExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
@@ -840,8 +841,9 @@
     return nullptr;
 
   if (m_token.m_type == TOKmul) {
-    auto pExp = std::make_unique<CXFA_FMIndexExpression>(
-        ACCESSOR_NO_RELATIVEINDEX, nullptr, true);
+    auto* pExp = cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
+        m_heap->GetAllocationHandle(), ACCESSOR_NO_RELATIVEINDEX, nullptr,
+        true);
     if (!pExp || !NextToken())
       return nullptr;
 
@@ -863,18 +865,18 @@
       return nullptr;
   }
 
-  std::unique_ptr<CXFA_FMSimpleExpression> s = ParseSimpleExpression();
+  CXFA_FMSimpleExpression* s = ParseSimpleExpression();
   if (!s)
     return nullptr;
   if (m_token.m_type != TOKrbracket)
     return nullptr;
 
-  return std::make_unique<CXFA_FMIndexExpression>(accessorIndex, std::move(s),
-                                                  false);
+  return cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
+      m_heap->GetAllocationHandle(), accessorIndex, s, false);
 }
 
 // Paren := '(' SimpleExpression ')'
-std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseParenExpression() {
+CXFA_FMSimpleExpression* CXFA_FMParser::ParseParenExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
@@ -884,7 +886,7 @@
   if (m_token.m_type == TOKrparen)
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseSimpleExpression();
+  CXFA_FMSimpleExpression* pExp1 = ParseSimpleExpression();
   if (!pExp1)
     return nullptr;
 
@@ -897,7 +899,7 @@
 //       ('elseif' '(' SimpleExpression ')' 'then' ExpressionList)*
 //       ('else' ExpressionList)?
 //       'endif'
-std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseIfExpression() {
+CXFA_FMExpression* CXFA_FMParser::ParseIfExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
@@ -905,58 +907,60 @@
   if (!CheckThenNext(TOKif))
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> pCondition = ParseParenExpression();
+  CXFA_FMSimpleExpression* pCondition = ParseParenExpression();
   if (!pCondition)
     return nullptr;
   if (!CheckThenNext(TOKthen))
     return nullptr;
 
-  auto pIfExpressions =
-      std::make_unique<CXFA_FMBlockExpression>(ParseExpressionList());
+  auto* pIfExpressions = cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
+      m_heap->GetAllocationHandle(), ParseExpressionList());
 
-  std::vector<std::unique_ptr<CXFA_FMIfExpression>> pElseIfExpressions;
+  std::vector<cppgc::Member<CXFA_FMIfExpression>> pElseIfExpressions;
   while (m_token.m_type == TOKelseif) {
     if (!NextToken())
       return nullptr;
 
-    auto elseIfCondition = ParseParenExpression();
+    auto* elseIfCondition = ParseParenExpression();
     if (!elseIfCondition)
       return nullptr;
     if (!CheckThenNext(TOKthen))
       return nullptr;
 
     auto elseIfExprs = ParseExpressionList();
-    pElseIfExpressions.push_back(std::make_unique<CXFA_FMIfExpression>(
-        std::move(elseIfCondition),
-        std::make_unique<CXFA_FMBlockExpression>(std::move(elseIfExprs)),
-        std::vector<std::unique_ptr<CXFA_FMIfExpression>>(), nullptr));
+    pElseIfExpressions.push_back(
+        cppgc::MakeGarbageCollected<CXFA_FMIfExpression>(
+            m_heap->GetAllocationHandle(), elseIfCondition,
+            cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
+                m_heap->GetAllocationHandle(), std::move(elseIfExprs)),
+            std::vector<cppgc::Member<CXFA_FMIfExpression>>(), nullptr));
   }
 
-  std::unique_ptr<CXFA_FMExpression> pElseExpression;
+  CXFA_FMExpression* pElseExpression = nullptr;
   if (m_token.m_type == TOKelse) {
     if (!NextToken())
       return nullptr;
 
-    pElseExpression =
-        std::make_unique<CXFA_FMBlockExpression>(ParseExpressionList());
+    pElseExpression = cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
+        m_heap->GetAllocationHandle(), ParseExpressionList());
   }
   if (!CheckThenNext(TOKendif))
     return nullptr;
 
-  return std::make_unique<CXFA_FMIfExpression>(
-      std::move(pCondition), std::move(pIfExpressions),
-      std::move(pElseIfExpressions), std::move(pElseExpression));
+  return cppgc::MakeGarbageCollected<CXFA_FMIfExpression>(
+      m_heap->GetAllocationHandle(), pCondition, pIfExpressions,
+      std::move(pElseIfExpressions), pElseExpression);
 }
 
 // While := 'while' '(' SimpleExpression ')' 'do' ExpressionList 'endwhile'
-std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseWhileExpression() {
+CXFA_FMExpression* CXFA_FMParser::ParseWhileExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
   if (!CheckThenNext(TOKwhile))
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> pCondition = ParseParenExpression();
+  CXFA_FMSimpleExpression* pCondition = ParseParenExpression();
   if (!pCondition || !CheckThenNext(TOKdo))
     return nullptr;
 
@@ -964,16 +968,17 @@
   if (!CheckThenNext(TOKendwhile))
     return nullptr;
 
-  return std::make_unique<CXFA_FMWhileExpression>(
-      std::move(pCondition),
-      std::make_unique<CXFA_FMBlockExpression>(std::move(exprs)));
+  return cppgc::MakeGarbageCollected<CXFA_FMWhileExpression>(
+      m_heap->GetAllocationHandle(), pCondition,
+      cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
+          m_heap->GetAllocationHandle(), std::move(exprs)));
 }
 
 // For := 'for' Assignment 'upto' Accessor ('step' SimpleExpression)?
 //            'do' ExpressionList 'endfor' |
 //         'for' Assignment 'downto' Accessor ('step' SimpleExpression)?
 //            'do' ExpressionList 'endfor'
-std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseForExpression() {
+CXFA_FMExpression* CXFA_FMParser::ParseForExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
@@ -982,14 +987,13 @@
   if (m_token.m_type != TOKidentifier)
     return nullptr;
 
-  WideStringView wsVariant = m_token.m_string;
+  WideString wsVariant(m_token.m_string);
   if (!NextToken())
     return nullptr;
   if (!CheckThenNext(TOKassign))
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> pAssignment =
-      ParseSimpleExpression();
+  CXFA_FMSimpleExpression* pAssignment = ParseSimpleExpression();
   if (!pAssignment)
     return nullptr;
 
@@ -1004,11 +1008,11 @@
   if (!NextToken())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> pAccessor = ParseSimpleExpression();
+  CXFA_FMSimpleExpression* pAccessor = ParseSimpleExpression();
   if (!pAccessor)
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> pStep;
+  CXFA_FMSimpleExpression* pStep = nullptr;
   if (m_token.m_type == TOKstep) {
     if (!NextToken())
       return nullptr;
@@ -1023,15 +1027,16 @@
   if (!CheckThenNext(TOKendfor))
     return nullptr;
 
-  return std::make_unique<CXFA_FMForExpression>(
-      wsVariant, std::move(pAssignment), std::move(pAccessor), iDirection,
-      std::move(pStep),
-      std::make_unique<CXFA_FMBlockExpression>(std::move(exprs)));
+  return cppgc::MakeGarbageCollected<CXFA_FMForExpression>(
+      m_heap->GetAllocationHandle(), wsVariant, pAssignment, pAccessor,
+      iDirection, pStep,
+      cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
+          m_heap->GetAllocationHandle(), std::move(exprs)));
 }
 
 // Foreach := 'foreach' Identifier 'in' '(' ArgumentList ')'
 //            'do' ExpressionList 'endfor'
-std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseForeachExpression() {
+CXFA_FMExpression* CXFA_FMParser::ParseForeachExpression() {
   if (m_token.m_type != TOKforeach)
     return nullptr;
 
@@ -1043,17 +1048,17 @@
   if (m_token.m_type != TOKidentifier)
     return nullptr;
 
-  WideStringView wsIdentifier = m_token.m_string;
+  WideString wsIdentifier(m_token.m_string);
   if (!NextToken() || !CheckThenNext(TOKin) || !CheckThenNext(TOKlparen))
     return nullptr;
 
-  std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> pArgumentList;
+  std::vector<cppgc::Member<CXFA_FMSimpleExpression>> pArgumentList;
   while (m_token.m_type != TOKrparen) {
-    std::unique_ptr<CXFA_FMSimpleExpression> s = ParseSimpleExpression();
+    CXFA_FMSimpleExpression* s = ParseSimpleExpression();
     if (!s)
       return nullptr;
 
-    pArgumentList.push_back(std::move(s));
+    pArgumentList.push_back(s);
     if (m_token.m_type != TOKcomma)
       break;
     if (!NextToken())
@@ -1069,13 +1074,15 @@
   if (!CheckThenNext(TOKendfor))
     return nullptr;
 
-  return std::make_unique<CXFA_FMForeachExpression>(
-      wsIdentifier, std::move(pArgumentList),
-      std::make_unique<CXFA_FMBlockExpression>(std::move(exprs)));
+  return cppgc::MakeGarbageCollected<CXFA_FMForeachExpression>(
+      m_heap->GetAllocationHandle(), std::move(wsIdentifier),
+      std::move(pArgumentList),
+      cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
+          m_heap->GetAllocationHandle(), std::move(exprs)));
 }
 
 // Block := 'do' ExpressionList 'end'
-std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseDoExpression() {
+CXFA_FMExpression* CXFA_FMParser::ParseDoExpression() {
   if (m_token.m_type != TOKdo)
     return nullptr;
 
@@ -1089,8 +1096,10 @@
   if (!CheckThenNext(TOKend))
     return nullptr;
 
-  return std::make_unique<CXFA_FMDoExpression>(
-      std::make_unique<CXFA_FMBlockExpression>(std::move(exprs)));
+  return cppgc::MakeGarbageCollected<CXFA_FMDoExpression>(
+      m_heap->GetAllocationHandle(),
+      cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
+          m_heap->GetAllocationHandle(), std::move(exprs)));
 }
 
 bool CXFA_FMParser::HasError() const {
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser.h b/xfa/fxfa/fm2js/cxfa_fmparser.h
index ad2b367..007df6d 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser.h
+++ b/xfa/fxfa/fm2js/cxfa_fmparser.h
@@ -10,15 +10,23 @@
 #include <memory>
 #include <vector>
 
+#include "core/fxcrt/unowned_ptr.h"
+#include "fxjs/gc/heap.h"
+#include "third_party/base/optional.h"
+#include "v8/include/cppgc/macros.h"
+#include "v8/include/cppgc/member.h"
 #include "xfa/fxfa/fm2js/cxfa_fmexpression.h"
 #include "xfa/fxfa/fm2js/cxfa_fmlexer.h"
 
 class CXFA_FMParser {
+  CPPGC_STACK_ALLOCATED();  // Allow Raw/Unowned pointers.
+
  public:
-  explicit CXFA_FMParser(WideStringView wsFormcalc);
+  CXFA_FMParser(cppgc::Heap* heap, WideStringView wsFormcalc);
   ~CXFA_FMParser();
 
-  std::unique_ptr<CXFA_FMAST> Parse();
+  // Returned object is owned by cppgc heap.
+  CXFA_FMAST* Parse();
   bool HasError() const;
 
   void SetMaxParseDepthForTest(unsigned long max_depth) {
@@ -30,33 +38,33 @@
   bool CheckThenNext(XFA_FM_TOKEN op);
   bool IncrementParseDepthAndCheck();
 
-  std::vector<std::unique_ptr<CXFA_FMExpression>> ParseExpressionList();
-  std::unique_ptr<CXFA_FMExpression> ParseFunction();
-  std::unique_ptr<CXFA_FMExpression> ParseExpression();
-  std::unique_ptr<CXFA_FMExpression> ParseDeclarationExpression();
-  std::unique_ptr<CXFA_FMExpression> ParseExpExpression();
-  std::unique_ptr<CXFA_FMExpression> ParseIfExpression();
-  std::unique_ptr<CXFA_FMExpression> ParseWhileExpression();
-  std::unique_ptr<CXFA_FMExpression> ParseForExpression();
-  std::unique_ptr<CXFA_FMExpression> ParseForeachExpression();
-  std::unique_ptr<CXFA_FMExpression> ParseDoExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseParenExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseSimpleExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseLogicalOrExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseLogicalAndExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseEqualityExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseRelationalExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseAdditiveExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseMultiplicativeExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseUnaryExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParsePrimaryExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParsePostExpression(
-      std::unique_ptr<CXFA_FMSimpleExpression> e);
-  std::unique_ptr<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>>
+  std::vector<cppgc::Member<CXFA_FMExpression>> ParseExpressionList();
+  CXFA_FMExpression* ParseFunction();
+  CXFA_FMExpression* ParseExpression();
+  CXFA_FMExpression* ParseDeclarationExpression();
+  CXFA_FMExpression* ParseExpExpression();
+  CXFA_FMExpression* ParseIfExpression();
+  CXFA_FMExpression* ParseWhileExpression();
+  CXFA_FMExpression* ParseForExpression();
+  CXFA_FMExpression* ParseForeachExpression();
+  CXFA_FMExpression* ParseDoExpression();
+  CXFA_FMSimpleExpression* ParseParenExpression();
+  CXFA_FMSimpleExpression* ParseSimpleExpression();
+  CXFA_FMSimpleExpression* ParseLogicalOrExpression();
+  CXFA_FMSimpleExpression* ParseLogicalAndExpression();
+  CXFA_FMSimpleExpression* ParseEqualityExpression();
+  CXFA_FMSimpleExpression* ParseRelationalExpression();
+  CXFA_FMSimpleExpression* ParseAdditiveExpression();
+  CXFA_FMSimpleExpression* ParseMultiplicativeExpression();
+  CXFA_FMSimpleExpression* ParseUnaryExpression();
+  CXFA_FMSimpleExpression* ParsePrimaryExpression();
+  CXFA_FMSimpleExpression* ParsePostExpression(CXFA_FMSimpleExpression* e);
+  CXFA_FMSimpleExpression* ParseIndexExpression();
+  CXFA_FMSimpleExpression* ParseLiteral();
+  Optional<std::vector<cppgc::Member<CXFA_FMSimpleExpression>>>
   ParseArgumentList();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseIndexExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseLiteral();
 
+  UnownedPtr<cppgc::Heap> const m_heap;
   std::unique_ptr<CXFA_FMLexer> m_lexer;
   CXFA_FMToken m_token;
   bool m_error;
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
index 64f1a0b..7539e7b 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
@@ -5,14 +5,17 @@
 #include "xfa/fxfa/fm2js/cxfa_fmparser.h"
 
 #include "core/fxcrt/cfx_widetextbuf.h"
+#include "testing/fxgc_unittest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
 
-TEST(CXFA_FMParserTest, Empty) {
-  auto parser = std::make_unique<CXFA_FMParser>(L"");
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+class CXFA_FMParserTest : public FXGCUnitTest {};
+
+TEST_F(CXFA_FMParserTest, Empty) {
+  CXFA_FMParser parser(heap(), L"");
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
-  EXPECT_FALSE(parser->HasError());
+  EXPECT_FALSE(parser.HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
@@ -21,13 +24,13 @@
   EXPECT_STREQ(L"// comments only", buf.value().MakeString().c_str());
 }
 
-TEST(CXFA_FMParserTest, CommentOnlyIsError) {
-  auto parser = std::make_unique<CXFA_FMParser>(L"; Just comment");
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+TEST_F(CXFA_FMParserTest, CommentOnlyIsError) {
+  CXFA_FMParser parser(heap(), L"; Just comment");
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
   // TODO(dsinclair): This isn't allowed per the spec.
-  EXPECT_FALSE(parser->HasError());
-  // EXPECT_TRUE(parser->HasError());
+  EXPECT_FALSE(parser.HasError());
+  // EXPECT_TRUE(parser.HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
@@ -35,7 +38,7 @@
   EXPECT_STREQ(L"// comments only", buf.value().MakeString().c_str());
 }
 
-TEST(CXFA_FMParserTest, CommentThenValue) {
+TEST_F(CXFA_FMParserTest, CommentThenValue) {
   const wchar_t ret[] =
       LR"***((function() {
 let pfm_method_runner = function(obj, cb) {
@@ -53,10 +56,10 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(L"; Just comment\n12");
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  CXFA_FMParser parser(heap(), L"; Just comment\n12");
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
-  EXPECT_FALSE(parser->HasError());
+  EXPECT_FALSE(parser.HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
@@ -64,7 +67,7 @@
   EXPECT_STREQ(ret, buf.value().MakeString().c_str());
 }
 
-TEST(CXFA_FMParserTest, Parse) {
+TEST_F(CXFA_FMParserTest, Parse) {
   const wchar_t input[] =
       LR"***($ = Avg (-3, 5, -6, 12, -13);
 $ = Avg (Table2..Row[*].Cell1);
@@ -122,10 +125,10 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
-  EXPECT_FALSE(parser->HasError());
+  EXPECT_FALSE(parser.HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
@@ -133,31 +136,31 @@
   EXPECT_EQ(ret, buf.value().AsStringView());
 }
 
-TEST(CXFA_FMParserTest, MaxParseDepth) {
-  auto parser = std::make_unique<CXFA_FMParser>(L"foo(bar[baz(fizz[0])])");
-  parser->SetMaxParseDepthForTest(5);
-  EXPECT_EQ(nullptr, parser->Parse());
-  EXPECT_TRUE(parser->HasError());
+TEST_F(CXFA_FMParserTest, MaxParseDepth) {
+  CXFA_FMParser parser(heap(), L"foo(bar[baz(fizz[0])])");
+  parser.SetMaxParseDepthForTest(5);
+  EXPECT_EQ(nullptr, parser.Parse());
+  EXPECT_TRUE(parser.HasError());
 }
 
-TEST(CFXA_FMParserTest, chromium752201) {
-  auto parser = std::make_unique<CXFA_FMParser>(
-      LR"***(fTep a
+TEST_F(CXFA_FMParserTest, chromium752201) {
+  CXFA_FMParser parser(heap(),
+                       LR"***(fTep a
 .#
 fo@ =[=l)***");
-  EXPECT_EQ(nullptr, parser->Parse());
-  EXPECT_TRUE(parser->HasError());
+  EXPECT_EQ(nullptr, parser.Parse());
+  EXPECT_TRUE(parser.HasError());
 }
 
-TEST(CXFA_FMParserTest, MultipleAssignmentIsNotAllowed) {
-  auto parser = std::make_unique<CXFA_FMParser>(L"(a=(b=t))=u");
+TEST_F(CXFA_FMParserTest, MultipleAssignmentIsNotAllowed) {
+  CXFA_FMParser parser(heap(), L"(a=(b=t))=u");
 
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(!ast);
-  EXPECT_TRUE(parser->HasError());
+  EXPECT_TRUE(parser.HasError());
 }
 
-TEST(CXFA_FMParserTest, ParseFuncWithParams) {
+TEST_F(CXFA_FMParserTest, ParseFuncWithParams) {
   const wchar_t input[] =
       LR"***(func MyFunction(param1, param2) do
   param1 * param2
@@ -184,10 +187,10 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
-  EXPECT_FALSE(parser->HasError());
+  EXPECT_FALSE(parser.HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
@@ -195,7 +198,7 @@
   EXPECT_STREQ(ret, buf.value().MakeString().c_str());
 }
 
-TEST(CXFA_FMParserTest, ParseFuncWithoutParams) {
+TEST_F(CXFA_FMParserTest, ParseFuncWithoutParams) {
   const wchar_t input[] =
       LR"***(func MyFunction() do
   42
@@ -222,10 +225,10 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
-  EXPECT_FALSE(parser->HasError());
+  EXPECT_FALSE(parser.HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
@@ -233,58 +236,58 @@
   EXPECT_STREQ(ret, buf.value().MakeString().c_str());
 }
 
-TEST(CXFA_FMParserTest, ParseFuncWithBadParamsList) {
+TEST_F(CXFA_FMParserTest, ParseFuncWithBadParamsList) {
   const wchar_t input[] =
       LR"***(func MyFunction(param1,) do
   param1 * param2
 endfunc)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
-  EXPECT_TRUE(parser->HasError());
+  EXPECT_TRUE(parser.HasError());
 }
 
-TEST(CXFA_FMParserTest, ParseBadIfExpression) {
+TEST_F(CXFA_FMParserTest, ParseBadIfExpression) {
   const wchar_t input[] = L"if ( then";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
-  EXPECT_TRUE(parser->HasError());
+  EXPECT_TRUE(parser.HasError());
 }
 
-TEST(CXFA_FMParserTest, ParseBadElseIfExpression) {
+TEST_F(CXFA_FMParserTest, ParseBadElseIfExpression) {
   const wchar_t input[] =
       LR"***(if ($ ne -1) then"
 elseif( then)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
-  EXPECT_TRUE(parser->HasError());
+  EXPECT_TRUE(parser.HasError());
 }
 
-TEST(CXFA_FMParserTest, ParseDepthWithWideTree) {
+TEST_F(CXFA_FMParserTest, ParseDepthWithWideTree) {
   const wchar_t input[] = L"a <> b <> c <> d <> e <> f <> g <> h <> i <> j";
 
   {
-    auto parser = std::make_unique<CXFA_FMParser>(input);
-    std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+    CXFA_FMParser parser(heap(), input);
+    CXFA_FMAST* ast = parser.Parse();
     ASSERT_TRUE(ast);
-    EXPECT_TRUE(!parser->HasError());
+    EXPECT_TRUE(!parser.HasError());
   }
 
   {
-    auto parser = std::make_unique<CXFA_FMParser>(input);
-    parser->SetMaxParseDepthForTest(5);
-    std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+    CXFA_FMParser parser(heap(), input);
+    parser.SetMaxParseDepthForTest(5);
+    CXFA_FMAST* ast = parser.Parse();
     ASSERT_TRUE(ast == nullptr);
-    EXPECT_TRUE(parser->HasError());
+    EXPECT_TRUE(parser.HasError());
   }
 }
 
-TEST(CXFA_FMParserTest, ParseCallSmall) {
+TEST_F(CXFA_FMParserTest, ParseCallSmall) {
   const wchar_t input[] = L"i.f(O)";
   const wchar_t ret[] =
       LR"***((function() {
@@ -307,9 +310,9 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
-  EXPECT_FALSE(parser->HasError());
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
+  EXPECT_FALSE(parser.HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
@@ -317,7 +320,7 @@
   EXPECT_STREQ(ret, buf.value().MakeString().c_str());
 }
 
-TEST(CXFA_FMParserTest, ParseCallBig) {
+TEST_F(CXFA_FMParserTest, ParseCallBig) {
   const wchar_t input[] = L"i.f(O.e(O.e(O)))";
   const wchar_t ret[] =
       LR"***((function() {
@@ -348,9 +351,9 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
-  EXPECT_FALSE(parser->HasError());
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
+  EXPECT_FALSE(parser.HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
@@ -358,7 +361,7 @@
   EXPECT_STREQ(ret, buf.value().MakeString().c_str());
 }
 
-TEST(CXFA_FMParserTest, ParseVar) {
+TEST_F(CXFA_FMParserTest, ParseVar) {
   const wchar_t input[] = LR"(var s = "")";
   const wchar_t ret[] =
       LR"***((function() {
@@ -379,9 +382,9 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
-  EXPECT_FALSE(parser->HasError());
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
+  EXPECT_FALSE(parser.HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
@@ -389,7 +392,7 @@
   EXPECT_STREQ(ret, buf.value().MakeString().c_str());
 }
 
-TEST(CXFA_FMParserTest, ParseFunctionCallNoArguments) {
+TEST_F(CXFA_FMParserTest, ParseFunctionCallNoArguments) {
   const wchar_t input[] = L"P.x()";
   const wchar_t ret[] =
       LR"***((function() {
@@ -412,16 +415,16 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
-  EXPECT_FALSE(parser->HasError());
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
+  EXPECT_FALSE(parser.HasError());
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
   ASSERT_TRUE(buf.has_value());
   EXPECT_STREQ(ret, buf.value().MakeString().c_str());
 }
 
-TEST(CXFA_FMParserTest, ParseFunctionCallSingleArgument) {
+TEST_F(CXFA_FMParserTest, ParseFunctionCallSingleArgument) {
   const wchar_t input[] = L"P.x(foo)";
   const wchar_t ret[] =
       LR"***((function() {
@@ -444,16 +447,16 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
-  EXPECT_FALSE(parser->HasError());
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
+  EXPECT_FALSE(parser.HasError());
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
   ASSERT_TRUE(buf.has_value());
   EXPECT_STREQ(ret, buf.value().MakeString().c_str());
 }
 
-TEST(CXFA_FMParserTest, ParseFunctionCallMultipleArguments) {
+TEST_F(CXFA_FMParserTest, ParseFunctionCallMultipleArguments) {
   const wchar_t input[] = L"P.x(foo, bar, baz)";
   const wchar_t ret[] =
       LR"***((function() {
@@ -476,38 +479,38 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
-  EXPECT_FALSE(parser->HasError());
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
+  EXPECT_FALSE(parser.HasError());
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
   ASSERT_TRUE(buf.has_value());
   EXPECT_STREQ(ret, buf.value().MakeString().c_str());
 }
 
-TEST(CXFA_FMParserTest, ParseFunctionCallMissingCommas) {
+TEST_F(CXFA_FMParserTest, ParseFunctionCallMissingCommas) {
   const wchar_t input[] = L"P.x(!foo!bar!baz)";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
-  EXPECT_TRUE(parser->HasError());
+  EXPECT_TRUE(parser.HasError());
 }
 
-TEST(CXFA_FMParserTest, ParseFunctionCallTrailingComma) {
+TEST_F(CXFA_FMParserTest, ParseFunctionCallTrailingComma) {
   const wchar_t input[] = L"P.x(foo,bar,baz,)";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
-  EXPECT_TRUE(parser->HasError());
+  EXPECT_TRUE(parser.HasError());
 }
 
-TEST(CXFA_FMParserTest, ParseFunctionCallExtraComma) {
+TEST_F(CXFA_FMParserTest, ParseFunctionCallExtraComma) {
   const wchar_t input[] = L"P.x(foo,bar,,baz)";
 
-  auto parser = std::make_unique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  CXFA_FMParser parser(heap(), input);
+  CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
-  EXPECT_TRUE(parser->HasError());
+  EXPECT_TRUE(parser.HasError());
 }