Push v8::Isolate into CFXJS_Engine class

Nearly all the "loose" functions in FXJS become methods on
the CFJXS_Engine.

This is the "missing link" wrt some layering violatons that
have been around forever. We can stop passing &m_ variables
from CJS_ down into FXJS Initialization as a result.

Review-Url: https://codereview.chromium.org/2245863002
diff --git a/fpdfsdk/javascript/Consts.cpp b/fpdfsdk/javascript/Consts.cpp
index 19988a6..c224ad0 100644
--- a/fpdfsdk/javascript/Consts.cpp
+++ b/fpdfsdk/javascript/Consts.cpp
@@ -99,11 +99,12 @@
 END_JS_STATIC_CONST()
 IMPLEMENT_JS_CLASS_CONST(CJS_Zoomtype, zoomtype)
 
-#define GLOBAL_STRING(rt, name, value)                                         \
-  FXJS_DefineGlobalConst(                                                      \
-      (rt)->GetIsolate(), (name),                                              \
-      [](const v8::FunctionCallbackInfo<v8::Value>& info) {                    \
-        info.GetReturnValue().Set(FXJS_NewString(info.GetIsolate(), (value))); \
+#define GLOBAL_STRING(rt, name, value)                                \
+  (rt)->DefineGlobalConst(                                            \
+      (name), [](const v8::FunctionCallbackInfo<v8::Value>& info) {   \
+        info.GetReturnValue().Set(                                    \
+            CFXJS_Engine::CurrentEngineFromIsolate(info.GetIsolate()) \
+                ->NewString(value));                                  \
       })
 
 void CJS_GlobalConsts::DefineJSObjects(CJS_Runtime* pRuntime) {
@@ -137,21 +138,20 @@
   GLOBAL_STRING(pRuntime, L"IDS_STARTUP_CONSOLE_MSG", L"** ^ _ ^ **");
 }
 
-#define GLOBAL_ARRAY(rt, name, ...)                                        \
-  {                                                                        \
-    const FX_WCHAR* values[] = {__VA_ARGS__};                              \
-    v8::Local<v8::Array> array = FXJS_NewArray((rt)->GetIsolate());        \
-    for (size_t i = 0; i < FX_ArraySize(values); ++i)                      \
-      array->Set(i, FXJS_NewString((rt)->GetIsolate(), values[i]));        \
-    rt->SetConstArray(name, array);                                        \
-    FXJS_DefineGlobalConst(                                                \
-        (rt)->GetIsolate(), (name),                                        \
-        [](const v8::FunctionCallbackInfo<v8::Value>& info) {              \
-          CJS_Runtime* pLocalRuntime = static_cast<CJS_Runtime*>(          \
-              FXJS_GetCurrentEngineFromIsolate(info.GetIsolate()));        \
-          if (pLocalRuntime)                                               \
-            info.GetReturnValue().Set(pLocalRuntime->GetConstArray(name)); \
-        });                                                                \
+#define GLOBAL_ARRAY(rt, name, ...)                                          \
+  {                                                                          \
+    const FX_WCHAR* values[] = {__VA_ARGS__};                                \
+    v8::Local<v8::Array> array = (rt)->NewArray();                           \
+    for (size_t i = 0; i < FX_ArraySize(values); ++i)                        \
+      array->Set(i, (rt)->NewString(values[i]));                             \
+    (rt)->SetConstArray((name), array);                                      \
+    (rt)->DefineGlobalConst(                                                 \
+        (name), [](const v8::FunctionCallbackInfo<v8::Value>& info) {        \
+          CJS_Runtime* pCurrentRuntime =                                     \
+              CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());     \
+          if (pCurrentRuntime)                                               \
+            info.GetReturnValue().Set(pCurrentRuntime->GetConstArray(name)); \
+        });                                                                  \
   }
 
 void CJS_GlobalArrays::DefineJSObjects(CJS_Runtime* pRuntime) {
diff --git a/fpdfsdk/javascript/Document.cpp b/fpdfsdk/javascript/Document.cpp
index a55bf81..7ddd571 100644
--- a/fpdfsdk/javascript/Document.cpp
+++ b/fpdfsdk/javascript/Document.cpp
@@ -28,12 +28,6 @@
 #include "fpdfsdk/javascript/resource.h"
 #include "third_party/base/numerics/safe_math.h"
 
-static v8::Isolate* GetIsolate(IJS_Context* cc) {
-  CJS_Context* pContext = (CJS_Context*)cc;
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  return pRuntime->GetIsolate();
-}
-
 BEGIN_JS_STATIC_CONST(CJS_PrintParamsObj)
 END_JS_STATIC_CONST()
 
@@ -148,12 +142,10 @@
   CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(pIRuntime);
   Document* pDoc = static_cast<Document*>(GetEmbedObject());
   pDoc->AttachDoc(pRuntime->GetReaderDocument());
-  pDoc->SetIsolate(pRuntime->GetIsolate());
 }
 
 Document::Document(CJS_Object* pJSObject)
     : CJS_EmbedObj(pJSObject),
-      m_isolate(nullptr),
       m_pDocument(nullptr),
       m_cwBaseURL(L""),
       m_bDelay(FALSE) {}
@@ -289,9 +281,7 @@
   }
 
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
-
-  CFX_WideString wideName = params[0].ToCFXWideString(pIsolate);
+  CFX_WideString wideName = params[0].ToCFXWideString(pRuntime);
   CPDFSDK_InterForm* pInterForm = m_pDocument->GetInterForm();
   CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
   if (pPDFForm->CountFields(wideName) <= 0) {
@@ -300,10 +290,9 @@
   }
 
   v8::Local<v8::Object> pFieldObj =
-      FXJS_NewFxDynamicObj(pIsolate, pRuntime, CJS_Field::g_nObjDefnID);
-
+      pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
   CJS_Field* pJSField =
-      static_cast<CJS_Field*>(FXJS_GetPrivate(pIsolate, pFieldObj));
+      static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pFieldObj));
   Field* pField = static_cast<Field*>(pJSField->GetEmbedObject());
   pField->AttachField(this, wideName);
 
@@ -317,16 +306,13 @@
                                   CJS_Value& vRet,
                                   CFX_WideString& sError) {
   CJS_Context* pContext = static_cast<CJS_Context*>(cc);
+  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
 
   if (params.size() != 1) {
     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
     return FALSE;
   }
-
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
-
-  int nIndex = params[0].ToInt(pIsolate);
+  int nIndex = params[0].ToInt(pRuntime);
   if (nIndex < 0) {
     sError = JSGetStringFromID(pContext, IDS_STRING_JSVALUEERROR);
     return FALSE;
@@ -378,21 +364,19 @@
                            CJS_Value& vRet,
                            CFX_WideString& sError) {
   CJS_Context* pContext = static_cast<CJS_Context*>(cc);
+  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
 
   if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS))
     return FALSE;
 
   int iLength = params.size();
-  CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
-
-  FX_BOOL bUI = iLength > 0 ? params[0].ToBool(pIsolate) : TRUE;
-  CFX_WideString cTo = iLength > 1 ? params[1].ToCFXWideString(pIsolate) : L"";
-  CFX_WideString cCc = iLength > 2 ? params[2].ToCFXWideString(pIsolate) : L"";
-  CFX_WideString cBcc = iLength > 3 ? params[3].ToCFXWideString(pIsolate) : L"";
+  FX_BOOL bUI = iLength > 0 ? params[0].ToBool(pRuntime) : TRUE;
+  CFX_WideString cTo = iLength > 1 ? params[1].ToCFXWideString(pRuntime) : L"";
+  CFX_WideString cCc = iLength > 2 ? params[2].ToCFXWideString(pRuntime) : L"";
+  CFX_WideString cBcc = iLength > 3 ? params[3].ToCFXWideString(pRuntime) : L"";
   CFX_WideString cSubject =
-      iLength > 4 ? params[4].ToCFXWideString(pIsolate) : L"";
-  CFX_WideString cMsg = iLength > 5 ? params[5].ToCFXWideString(pIsolate) : L"";
+      iLength > 4 ? params[4].ToCFXWideString(pRuntime) : L"";
+  CFX_WideString cMsg = iLength > 5 ? params[5].ToCFXWideString(pRuntime) : L"";
 
   CPDFSDK_InterForm* pInterForm = m_pDocument->GetInterForm();
   CFX_ByteTextBuf textBuf;
@@ -414,7 +398,6 @@
                         CFX_WideString& sError) {
   CJS_Context* pContext = static_cast<CJS_Context*>(cc);
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
 
   FX_BOOL bUI = TRUE;
   int nStart = 0;
@@ -428,9 +411,10 @@
   int nlength = params.size();
   if (nlength == 9) {
     if (params[8].GetType() == CJS_Value::VT_object) {
-      v8::Local<v8::Object> pObj = params[8].ToV8Object(pIsolate);
-      if (FXJS_GetObjDefnID(pObj) == CJS_PrintParamsObj::g_nObjDefnID) {
-        if (CJS_Object* pJSObj = params[8].ToCJSObject(pIsolate)) {
+      v8::Local<v8::Object> pObj = params[8].ToV8Object(pRuntime);
+      if (CFXJS_Engine::GetObjDefnID(pObj) ==
+          CJS_PrintParamsObj::g_nObjDefnID) {
+        if (CJS_Object* pJSObj = params[8].ToCJSObject(pRuntime)) {
           if (PrintParamsObj* pprintparamsObj =
                   static_cast<PrintParamsObj*>(pJSObj->GetEmbedObject())) {
             bUI = pprintparamsObj->bUI;
@@ -447,21 +431,21 @@
     }
   } else {
     if (nlength >= 1)
-      bUI = params[0].ToBool(pIsolate);
+      bUI = params[0].ToBool(pRuntime);
     if (nlength >= 2)
-      nStart = params[1].ToInt(pIsolate);
+      nStart = params[1].ToInt(pRuntime);
     if (nlength >= 3)
-      nEnd = params[2].ToInt(pIsolate);
+      nEnd = params[2].ToInt(pRuntime);
     if (nlength >= 4)
-      bSilent = params[3].ToBool(pIsolate);
+      bSilent = params[3].ToBool(pRuntime);
     if (nlength >= 5)
-      bShrinkToFit = params[4].ToBool(pIsolate);
+      bShrinkToFit = params[4].ToBool(pRuntime);
     if (nlength >= 6)
-      bPrintAsImage = params[5].ToBool(pIsolate);
+      bPrintAsImage = params[5].ToBool(pRuntime);
     if (nlength >= 7)
-      bReverse = params[6].ToBool(pIsolate);
+      bReverse = params[6].ToBool(pRuntime);
     if (nlength >= 8)
-      bAnnotations = params[7].ToBool(pIsolate);
+      bAnnotations = params[7].ToBool(pRuntime);
   }
 
   if (CPDFDoc_Environment* pEnv = m_pDocument->GetEnv()) {
@@ -492,9 +476,8 @@
   }
 
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
 
-  CFX_WideString sFieldName = params[0].ToCFXWideString(pIsolate);
+  CFX_WideString sFieldName = params[0].ToCFXWideString(pRuntime);
   CPDFSDK_InterForm* pInterForm = m_pDocument->GetInterForm();
   std::vector<CPDFSDK_Widget*> widgets;
   pInterForm->GetWidgets(sFieldName, &widgets);
@@ -547,22 +530,21 @@
   }
 
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
 
   switch (params[0].GetType()) {
     default:
-      aName.Attach(params[0].ToV8Array(pIsolate));
+      aName.Attach(params[0].ToV8Array(pRuntime));
       break;
     case CJS_Value::VT_string:
-      aName.SetElement(pRuntime->GetIsolate(), 0, params[0]);
+      aName.SetElement(pRuntime, 0, params[0]);
       break;
   }
 
   std::vector<CPDF_FormField*> aFields;
-  for (int i = 0, isz = aName.GetLength(); i < isz; ++i) {
+  for (int i = 0, isz = aName.GetLength(pRuntime); i < isz; ++i) {
     CJS_Value valElement(pRuntime);
-    aName.GetElement(pRuntime->GetIsolate(), i, valElement);
-    CFX_WideString swVal = valElement.ToCFXWideString(pIsolate);
+    aName.GetElement(pRuntime, i, valElement);
+    CFX_WideString swVal = valElement.ToCFXWideString(pRuntime);
     for (int j = 0, jsz = pPDFForm->CountFields(swVal); j < jsz; ++j)
       aFields.push_back(pPDFForm->GetField(j, swVal));
   }
@@ -601,37 +583,35 @@
   FX_BOOL bEmpty = FALSE;
 
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
 
   CJS_Value v = params[0];
   if (v.GetType() == CJS_Value::VT_string) {
-    strURL = params[0].ToCFXWideString(pIsolate);
+    strURL = params[0].ToCFXWideString(pRuntime);
     if (nSize > 1)
-      bFDF = params[1].ToBool(pIsolate);
+      bFDF = params[1].ToBool(pRuntime);
     if (nSize > 2)
-      bEmpty = params[2].ToBool(pIsolate);
+      bEmpty = params[2].ToBool(pRuntime);
     if (nSize > 3)
-      aFields.Attach(params[3].ToV8Array(pIsolate));
+      aFields.Attach(params[3].ToV8Array(pRuntime));
   } else if (v.GetType() == CJS_Value::VT_object) {
-    v8::Local<v8::Object> pObj = params[0].ToV8Object(pIsolate);
-    v8::Local<v8::Value> pValue =
-        FXJS_GetObjectProperty(pIsolate, pObj, L"cURL");
+    v8::Local<v8::Object> pObj = params[0].ToV8Object(pRuntime);
+    v8::Local<v8::Value> pValue = pRuntime->GetObjectProperty(pObj, L"cURL");
     if (!pValue.IsEmpty())
-      strURL = CJS_Value(pRuntime, pValue).ToCFXWideString(pIsolate);
+      strURL = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
 
-    pValue = FXJS_GetObjectProperty(pIsolate, pObj, L"bFDF");
-    bFDF = CJS_Value(pRuntime, pValue).ToBool(pIsolate);
+    pValue = pRuntime->GetObjectProperty(pObj, L"bFDF");
+    bFDF = CJS_Value(pRuntime, pValue).ToBool(pRuntime);
 
-    pValue = FXJS_GetObjectProperty(pIsolate, pObj, L"bEmpty");
-    bEmpty = CJS_Value(pRuntime, pValue).ToBool(pIsolate);
+    pValue = pRuntime->GetObjectProperty(pObj, L"bEmpty");
+    bEmpty = CJS_Value(pRuntime, pValue).ToBool(pRuntime);
 
-    pValue = FXJS_GetObjectProperty(pIsolate, pObj, L"aFields");
-    aFields.Attach(CJS_Value(pRuntime, pValue).ToV8Array(pIsolate));
+    pValue = pRuntime->GetObjectProperty(pObj, L"aFields");
+    aFields.Attach(CJS_Value(pRuntime, pValue).ToV8Array(pRuntime));
   }
 
   CPDFSDK_InterForm* pInterForm = m_pDocument->GetInterForm();
   CPDF_InterForm* pPDFInterForm = pInterForm->GetInterForm();
-  if (aFields.GetLength() == 0 && bEmpty) {
+  if (aFields.GetLength(pRuntime) == 0 && bEmpty) {
     if (pPDFInterForm->CheckRequiredFields(nullptr, true)) {
       pRuntime->BeginBlock();
       pInterForm->SubmitForm(strURL, FALSE);
@@ -641,11 +621,11 @@
   }
 
   std::vector<CPDF_FormField*> fieldObjects;
-  for (int i = 0, sz = aFields.GetLength(); i < sz; ++i) {
+  for (int i = 0, sz = aFields.GetLength(pRuntime); i < sz; ++i) {
     CJS_Value valName(pRuntime);
-    aFields.GetElement(pRuntime->GetIsolate(), i, valName);
+    aFields.GetElement(pRuntime, i, valName);
 
-    CFX_WideString sName = valName.ToCFXWideString(pIsolate);
+    CFX_WideString sName = valName.ToCFXWideString(pRuntime);
     CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
     for (int j = 0, jsz = pPDFForm->CountFields(sName); j < jsz; ++j) {
       CPDF_FormField* pField = pPDFForm->GetField(j, sName);
@@ -694,42 +674,40 @@
   CFX_WideString cMsg = L"";
 
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
 
   if (params.size() >= 1)
-    bUI = params[0].ToBool(pIsolate);
+    bUI = params[0].ToBool(pRuntime);
   if (params.size() >= 2)
-    cTo = params[1].ToCFXWideString(pIsolate);
+    cTo = params[1].ToCFXWideString(pRuntime);
   if (params.size() >= 3)
-    cCc = params[2].ToCFXWideString(pIsolate);
+    cCc = params[2].ToCFXWideString(pRuntime);
   if (params.size() >= 4)
-    cBcc = params[3].ToCFXWideString(pIsolate);
+    cBcc = params[3].ToCFXWideString(pRuntime);
   if (params.size() >= 5)
-    cSubject = params[4].ToCFXWideString(pIsolate);
+    cSubject = params[4].ToCFXWideString(pRuntime);
   if (params.size() >= 6)
-    cMsg = params[5].ToCFXWideString(pIsolate);
+    cMsg = params[5].ToCFXWideString(pRuntime);
 
   if (params.size() >= 1 && params[0].GetType() == CJS_Value::VT_object) {
-    v8::Local<v8::Object> pObj = params[0].ToV8Object(pIsolate);
+    v8::Local<v8::Object> pObj = params[0].ToV8Object(pRuntime);
 
-    v8::Local<v8::Value> pValue =
-        FXJS_GetObjectProperty(pIsolate, pObj, L"bUI");
-    bUI = CJS_Value(pRuntime, pValue).ToInt(pIsolate);
+    v8::Local<v8::Value> pValue = pRuntime->GetObjectProperty(pObj, L"bUI");
+    bUI = CJS_Value(pRuntime, pValue).ToInt(pRuntime);
 
-    pValue = FXJS_GetObjectProperty(pIsolate, pObj, L"cTo");
-    cTo = CJS_Value(pRuntime, pValue).ToCFXWideString(pIsolate);
+    pValue = pRuntime->GetObjectProperty(pObj, L"cTo");
+    cTo = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
 
-    pValue = FXJS_GetObjectProperty(pIsolate, pObj, L"cCc");
-    cCc = CJS_Value(pRuntime, pValue).ToCFXWideString(pIsolate);
+    pValue = pRuntime->GetObjectProperty(pObj, L"cCc");
+    cCc = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
 
-    pValue = FXJS_GetObjectProperty(pIsolate, pObj, L"cBcc");
-    cBcc = CJS_Value(pRuntime, pValue).ToCFXWideString(pIsolate);
+    pValue = pRuntime->GetObjectProperty(pObj, L"cBcc");
+    cBcc = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
 
-    pValue = FXJS_GetObjectProperty(pIsolate, pObj, L"cSubject");
-    cSubject = CJS_Value(pRuntime, pValue).ToCFXWideString(pIsolate);
+    pValue = pRuntime->GetObjectProperty(pObj, L"cSubject");
+    cSubject = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
 
-    pValue = FXJS_GetObjectProperty(pIsolate, pObj, L"cMsg");
-    cMsg = CJS_Value(pRuntime, pValue).ToCFXWideString(pIsolate);
+    pValue = pRuntime->GetObjectProperty(pObj, L"cMsg");
+    cMsg = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
   }
 
   pRuntime->BeginBlock();
@@ -772,19 +750,17 @@
 
   CJS_Context* pContext = (CJS_Context*)cc;
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Local<v8::Object> pObj =
-      FXJS_NewFxDynamicObj(pRuntime->GetIsolate(), pRuntime, -1);
 
-  v8::Isolate* isolate = GetIsolate(cc);
-  FXJS_PutObjectString(isolate, pObj, L"Author", cwAuthor);
-  FXJS_PutObjectString(isolate, pObj, L"Title", cwTitle);
-  FXJS_PutObjectString(isolate, pObj, L"Subject", cwSubject);
-  FXJS_PutObjectString(isolate, pObj, L"Keywords", cwKeywords);
-  FXJS_PutObjectString(isolate, pObj, L"Creator", cwCreator);
-  FXJS_PutObjectString(isolate, pObj, L"Producer", cwProducer);
-  FXJS_PutObjectString(isolate, pObj, L"CreationDate", cwCreationDate);
-  FXJS_PutObjectString(isolate, pObj, L"ModDate", cwModDate);
-  FXJS_PutObjectString(isolate, pObj, L"Trapped", cwTrapped);
+  v8::Local<v8::Object> pObj = pRuntime->NewFxDynamicObj(-1);
+  pRuntime->PutObjectString(pObj, L"Author", cwAuthor);
+  pRuntime->PutObjectString(pObj, L"Title", cwTitle);
+  pRuntime->PutObjectString(pObj, L"Subject", cwSubject);
+  pRuntime->PutObjectString(pObj, L"Keywords", cwKeywords);
+  pRuntime->PutObjectString(pObj, L"Creator", cwCreator);
+  pRuntime->PutObjectString(pObj, L"Producer", cwProducer);
+  pRuntime->PutObjectString(pObj, L"CreationDate", cwCreationDate);
+  pRuntime->PutObjectString(pObj, L"ModDate", cwModDate);
+  pRuntime->PutObjectString(pObj, L"Trapped", cwTrapped);
 
   // It's to be compatible to non-standard info dictionary.
   for (const auto& it : *pDictionary) {
@@ -792,11 +768,11 @@
     CPDF_Object* pValueObj = it.second;
     CFX_WideString wsKey = CFX_WideString::FromUTF8(bsKey.AsStringC());
     if (pValueObj->IsString() || pValueObj->IsName()) {
-      FXJS_PutObjectString(isolate, pObj, wsKey, pValueObj->GetUnicodeText());
+      pRuntime->PutObjectString(pObj, wsKey, pValueObj->GetUnicodeText());
     } else if (pValueObj->IsNumber()) {
-      FXJS_PutObjectNumber(isolate, pObj, wsKey, (float)pValueObj->GetNumber());
+      pRuntime->PutObjectNumber(pObj, wsKey, (float)pValueObj->GetNumber());
     } else if (pValueObj->IsBoolean()) {
-      FXJS_PutObjectBoolean(isolate, pObj, wsKey, !!pValueObj->GetInteger());
+      pRuntime->PutObjectBoolean(pObj, wsKey, !!pValueObj->GetInteger());
     }
   }
   vp << pObj;
@@ -1108,22 +1084,21 @@
   }
 
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
 
-  CFX_WideString swIconName = params[0].ToCFXWideString(pIsolate);
+  CFX_WideString swIconName = params[0].ToCFXWideString(pRuntime);
 
   if (params[1].GetType() != CJS_Value::VT_object) {
     sError = JSGetStringFromID(pContext, IDS_STRING_JSTYPEERROR);
     return FALSE;
   }
 
-  v8::Local<v8::Object> pJSIcon = params[1].ToV8Object(pIsolate);
-  if (FXJS_GetObjDefnID(pJSIcon) != CJS_Icon::g_nObjDefnID) {
+  v8::Local<v8::Object> pJSIcon = params[1].ToV8Object(pRuntime);
+  if (pRuntime->GetObjDefnID(pJSIcon) != CJS_Icon::g_nObjDefnID) {
     sError = JSGetStringFromID(pContext, IDS_STRING_JSTYPEERROR);
     return FALSE;
   }
 
-  CJS_EmbedObj* pEmbedObj = params[1].ToCJSObject(pIsolate)->GetEmbedObject();
+  CJS_EmbedObj* pEmbedObj = params[1].ToCJSObject(pRuntime)->GetEmbedObject();
   if (!pEmbedObj) {
     sError = JSGetStringFromID(pContext, IDS_STRING_JSTYPEERROR);
     return FALSE;
@@ -1153,12 +1128,13 @@
 
   int i = 0;
   for (const auto& pIconElement : m_IconList) {
-    v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj(
-        pRuntime->GetIsolate(), pRuntime, CJS_Icon::g_nObjDefnID);
+    v8::Local<v8::Object> pObj =
+        pRuntime->NewFxDynamicObj(CJS_Icon::g_nObjDefnID);
     if (pObj.IsEmpty())
       return FALSE;
 
-    CJS_Icon* pJS_Icon = (CJS_Icon*)FXJS_GetPrivate(m_isolate, pObj);
+    CJS_Icon* pJS_Icon =
+        static_cast<CJS_Icon*>(pRuntime->GetObjectPrivate(pObj));
     if (!pJS_Icon)
       return FALSE;
 
@@ -1168,8 +1144,7 @@
 
     pIcon->SetStream(pIconElement->IconStream->GetStream());
     pIcon->SetIconName(pIconElement->IconName);
-    Icons.SetElement(pRuntime->GetIsolate(), i++,
-                     CJS_Value(pRuntime, pJS_Icon));
+    Icons.SetElement(pRuntime, i++, CJS_Value(pRuntime, pJS_Icon));
   }
 
   vp << Icons;
@@ -1190,20 +1165,20 @@
     return FALSE;
 
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
 
-  CFX_WideString swIconName = params[0].ToCFXWideString(pIsolate);
+  CFX_WideString swIconName = params[0].ToCFXWideString(pRuntime);
 
   for (const auto& pIconElement : m_IconList) {
     if (pIconElement->IconName == swIconName) {
       Icon* pRetIcon = pIconElement->IconStream;
 
-      v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj(
-          pRuntime->GetIsolate(), pRuntime, CJS_Icon::g_nObjDefnID);
+      v8::Local<v8::Object> pObj =
+          pRuntime->NewFxDynamicObj(CJS_Icon::g_nObjDefnID);
       if (pObj.IsEmpty())
         return FALSE;
 
-      CJS_Icon* pJS_Icon = (CJS_Icon*)FXJS_GetPrivate(m_isolate, pObj);
+      CJS_Icon* pJS_Icon =
+          static_cast<CJS_Icon*>(pRuntime->GetObjectPrivate(pObj));
       if (!pJS_Icon)
         return FALSE;
 
@@ -1275,11 +1250,10 @@
     return FALSE;
 
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
 
-  int nPageNo = params.size() > 0 ? params[0].ToInt(pIsolate) : 0;
-  int nWordNo = params.size() > 1 ? params[1].ToInt(pIsolate) : 0;
-  bool bStrip = params.size() > 2 ? params[2].ToBool(pIsolate) : true;
+  int nPageNo = params.size() > 0 ? params[0].ToInt(pRuntime) : 0;
+  int nWordNo = params.size() > 1 ? params[1].ToInt(pRuntime) : 0;
+  bool bStrip = params.size() > 2 ? params[2].ToBool(pRuntime) : true;
 
   CPDF_Document* pDocument = m_pDocument->GetPDFDocument();
   if (!pDocument)
@@ -1340,9 +1314,8 @@
     return FALSE;
 
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Isolate* pIsolate = pRuntime->GetIsolate();
 
-  int nPageNo = params.size() > 0 ? params[0].ToInt(pIsolate) : 0;
+  int nPageNo = params.size() > 0 ? params[0].ToInt(pRuntime) : 0;
   CPDF_Document* pDocument = m_pDocument->GetPDFDocument();
   if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) {
     sError = JSGetStringFromID(pContext, IDS_STRING_JSVALUEERROR);
@@ -1372,8 +1345,8 @@
                                  CFX_WideString& sError) {
   CJS_Context* pContext = (CJS_Context*)cc;
   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
-  v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj(
-      pRuntime->GetIsolate(), pRuntime, CJS_PrintParamsObj::g_nObjDefnID);
+  v8::Local<v8::Object> pRetObj =
+      pRuntime->NewFxDynamicObj(CJS_PrintParamsObj::g_nObjDefnID);
 
   // Not implemented yet.
 
@@ -1526,8 +1499,8 @@
     return FALSE;
   }
 
-  CJS_Runtime* runtime = context->GetJSRuntime();
-  CFX_WideString wideName = params[0].ToCFXWideString(runtime->GetIsolate());
+  CJS_Runtime* pRuntime = context->GetJSRuntime();
+  CFX_WideString wideName = params[0].ToCFXWideString(pRuntime);
   CFX_ByteString utf8Name = wideName.UTF8Encode();
 
   CPDF_Document* pDocument = m_pDocument->GetPDFDocument();
@@ -1553,11 +1526,11 @@
     scrollPositionArraySize = j;
   }
 
-  runtime->BeginBlock();
+  pRuntime->BeginBlock();
   CPDFDoc_Environment* pApp = m_pDocument->GetEnv();
   pApp->FFI_DoGoToAction(dest.GetPageIndex(pDocument), dest.GetZoomMode(),
                          scrollPositionArray.get(), scrollPositionArraySize);
-  runtime->EndBlock();
+  pRuntime->EndBlock();
 
   return TRUE;
 }
diff --git a/fpdfsdk/javascript/Document.h b/fpdfsdk/javascript/Document.h
index 873f70e..1c20ac4 100644
--- a/fpdfsdk/javascript/Document.h
+++ b/fpdfsdk/javascript/Document.h
@@ -269,7 +269,6 @@
   CPDFSDK_Document* GetReaderDoc();
   void AddDelayData(CJS_DelayData* pData);
   void DoFieldDelay(const CFX_WideString& sFieldName, int nControlIndex);
-  void SetIsolate(v8::Isolate* isolate) { m_isolate = isolate; }
   CJS_Document* GetCJSDoc() const;
 
  private:
@@ -282,12 +281,11 @@
                               const CFX_ByteString& propName,
                               CFX_WideString& sError);
 
-  v8::Isolate* m_isolate;
-  std::list<std::unique_ptr<IconElement>> m_IconList;
   CPDFSDK_Document* m_pDocument;
   CFX_WideString m_cwBaseURL;
-  bool m_bDelay;
   std::list<std::unique_ptr<CJS_DelayData>> m_DelayData;
+  std::list<std::unique_ptr<IconElement>> m_IconList;
+  bool m_bDelay;
 };
 
 class CJS_Document : public CJS_Object {
diff --git a/fpdfsdk/javascript/Field.cpp b/fpdfsdk/javascript/Field.cpp
index 20c41c6..1f4a183 100644
--- a/fpdfsdk/javascript/Field.cpp
+++ b/fpdfsdk/javascript/Field.cpp
@@ -123,9 +123,6 @@
 CJS_DelayData::~CJS_DelayData() {}
 
 void CJS_Field::InitInstance(IJS_Runtime* pIRuntime) {
-  CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(pIRuntime);
-  Field* pField = static_cast<Field*>(GetEmbedObject());
-  pField->SetIsolate(pRuntime->GetIsolate());
 }
 
 Field::Field(CJS_Object* pJSObject)
@@ -134,8 +131,7 @@
       m_pDocument(nullptr),
       m_nFormControlIndex(-1),
       m_bCanSet(FALSE),
-      m_bDelay(FALSE),
-      m_isolate(nullptr) {}
+      m_bDelay(FALSE) {}
 
 Field::~Field() {}
 
@@ -967,9 +963,9 @@
       CJS_Value SelValue(pRuntime);
       int iSelecting;
       vp >> SelArray;
-      for (int i = 0, sz = SelArray.GetLength(); i < sz; i++) {
-        SelArray.GetElement(pRuntime->GetIsolate(), i, SelValue);
-        iSelecting = SelValue.ToInt(pRuntime->GetIsolate());
+      for (int i = 0, sz = SelArray.GetLength(pRuntime); i < sz; i++) {
+        SelArray.GetElement(pRuntime, i, SelValue);
+        iSelecting = SelValue.ToInt(pRuntime);
         array.push_back(iSelecting);
       }
     }
@@ -997,8 +993,7 @@
       CJS_Array SelArray;
       for (int i = 0, sz = pFormField->CountSelectedItems(); i < sz; i++) {
         SelArray.SetElement(
-            pRuntime->GetIsolate(), i,
-            CJS_Value(pRuntime, pFormField->GetSelectedIndex(i)));
+            pRuntime, i, CJS_Value(pRuntime, pFormField->GetSelectedIndex(i)));
       }
       vp << SelArray;
     } else {
@@ -1389,7 +1384,7 @@
       for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) {
         CPDF_FormControl* pFormControl = pFormField->GetControl(i);
         ExportValusArray.SetElement(
-            pRuntime->GetIsolate(), i,
+            pRuntime, i,
             CJS_Value(pRuntime, pFormControl->GetExportValue().c_str()));
       }
     } else {
@@ -1402,7 +1397,7 @@
         return FALSE;
 
       ExportValusArray.SetElement(
-          pRuntime->GetIsolate(), 0,
+          pRuntime, 0,
           CJS_Value(pRuntime, pFormControl->GetExportValue().c_str()));
     }
     vp << ExportValusArray;
@@ -1904,8 +1899,7 @@
       return FALSE;
 
     PageArray.SetElement(
-        pRuntime->GetIsolate(), i,
-        CJS_Value(pRuntime, (int32_t)pPageView->GetPageIndex()));
+        pRuntime, i, CJS_Value(pRuntime, (int32_t)pPageView->GetPageIndex()));
   }
 
   vp << PageArray;
@@ -2099,20 +2093,16 @@
 
     CJS_Array rcArray;
     vp >> rcArray;
-    rcArray.GetElement(pRuntime->GetIsolate(), 0, Upper_Leftx);
-    rcArray.GetElement(pRuntime->GetIsolate(), 1, Upper_Lefty);
-    rcArray.GetElement(pRuntime->GetIsolate(), 2, Lower_Rightx);
-    rcArray.GetElement(pRuntime->GetIsolate(), 3, Lower_Righty);
+    rcArray.GetElement(pRuntime, 0, Upper_Leftx);
+    rcArray.GetElement(pRuntime, 1, Upper_Lefty);
+    rcArray.GetElement(pRuntime, 2, Lower_Rightx);
+    rcArray.GetElement(pRuntime, 3, Lower_Righty);
 
     FX_FLOAT pArray[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-    pArray[0] =
-        static_cast<FX_FLOAT>(Upper_Leftx.ToInt(pRuntime->GetIsolate()));
-    pArray[1] =
-        static_cast<FX_FLOAT>(Lower_Righty.ToInt(pRuntime->GetIsolate()));
-    pArray[2] =
-        static_cast<FX_FLOAT>(Lower_Rightx.ToInt(pRuntime->GetIsolate()));
-    pArray[3] =
-        static_cast<FX_FLOAT>(Upper_Lefty.ToInt(pRuntime->GetIsolate()));
+    pArray[0] = static_cast<FX_FLOAT>(Upper_Leftx.ToInt(pRuntime));
+    pArray[1] = static_cast<FX_FLOAT>(Lower_Righty.ToInt(pRuntime));
+    pArray[2] = static_cast<FX_FLOAT>(Lower_Rightx.ToInt(pRuntime));
+    pArray[3] = static_cast<FX_FLOAT>(Upper_Lefty.ToInt(pRuntime));
 
     CFX_FloatRect crRect(pArray);
     if (m_bDelay) {
@@ -2139,10 +2129,10 @@
     Lower_Righty = CJS_Value(pRuntime, static_cast<int32_t>(crRect.bottom));
 
     CJS_Array rcArray;
-    rcArray.SetElement(pRuntime->GetIsolate(), 0, Upper_Leftx);
-    rcArray.SetElement(pRuntime->GetIsolate(), 1, Upper_Lefty);
-    rcArray.SetElement(pRuntime->GetIsolate(), 2, Lower_Rightx);
-    rcArray.SetElement(pRuntime->GetIsolate(), 3, Lower_Righty);
+    rcArray.SetElement(pRuntime, 0, Upper_Leftx);
+    rcArray.SetElement(pRuntime, 1, Upper_Lefty);
+    rcArray.SetElement(pRuntime, 2, Lower_Rightx);
+    rcArray.SetElement(pRuntime, 3, Lower_Righty);
     vp << rcArray;
   }
   return TRUE;
@@ -2716,12 +2706,11 @@
     std::vector<CFX_WideString> strArray;
     if (vp.GetJSValue()->IsArrayObject()) {
       CJS_Array ValueArray;
-      vp.GetJSValue()->ConvertToArray(pRuntime->GetIsolate(), ValueArray);
-      for (int i = 0, sz = ValueArray.GetLength(); i < sz; i++) {
+      vp.GetJSValue()->ConvertToArray(pRuntime, ValueArray);
+      for (int i = 0, sz = ValueArray.GetLength(pRuntime); i < sz; i++) {
         CJS_Value ElementValue(pRuntime);
-        ValueArray.GetElement(pRuntime->GetIsolate(), i, ElementValue);
-        strArray.push_back(
-            ElementValue.ToCFXWideString(pRuntime->GetIsolate()));
+        ValueArray.GetElement(pRuntime, i, ElementValue);
+        strArray.push_back(ElementValue.ToCFXWideString(pRuntime));
       }
     } else {
       CFX_WideString swValue;
@@ -2756,13 +2745,12 @@
             iIndex = pFormField->GetSelectedIndex(i);
             ElementValue =
                 CJS_Value(pRuntime, pFormField->GetOptionValue(iIndex).c_str());
-            if (FXSYS_wcslen(
-                    ElementValue.ToCFXWideString(pRuntime->GetIsolate())
-                        .c_str()) == 0) {
+            if (FXSYS_wcslen(ElementValue.ToCFXWideString(pRuntime).c_str()) ==
+                0) {
               ElementValue = CJS_Value(
                   pRuntime, pFormField->GetOptionLabel(iIndex).c_str());
             }
-            ValueArray.SetElement(pRuntime->GetIsolate(), i, ElementValue);
+            ValueArray.SetElement(pRuntime, i, ElementValue);
           }
           vp << ValueArray;
         } else {
@@ -2787,7 +2775,7 @@
         break;
     }
   }
-  vp.GetJSValue()->MaybeCoerceToNumber(m_isolate);
+  vp.GetJSValue()->MaybeCoerceToNumber(pRuntime);
   return TRUE;
 }
 
@@ -2918,7 +2906,7 @@
   int nface = 0;
   int iSize = params.size();
   if (iSize >= 1)
-    nface = params[0].ToInt(pRuntime->GetIsolate());
+    nface = params[0].ToInt(pRuntime);
 
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
   if (FieldArray.empty())
@@ -2954,7 +2942,7 @@
   int nface = 0;
   int iSize = params.size();
   if (iSize >= 1)
-    nface = params[0].ToInt(pRuntime->GetIsolate());
+    nface = params[0].ToInt(pRuntime);
 
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
   if (FieldArray.empty())
@@ -2968,11 +2956,11 @@
   if (!pFormControl)
     return FALSE;
 
-  v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj(
-      pRuntime->GetIsolate(), pRuntime, CJS_Icon::g_nObjDefnID);
+  v8::Local<v8::Object> pObj =
+      pRuntime->NewFxDynamicObj(CJS_Icon::g_nObjDefnID);
   ASSERT(pObj.IsEmpty() == FALSE);
 
-  CJS_Icon* pJS_Icon = (CJS_Icon*)FXJS_GetPrivate(pRuntime->GetIsolate(), pObj);
+  CJS_Icon* pJS_Icon = static_cast<CJS_Icon*>(pRuntime->GetObjectPrivate(pObj));
   Icon* pIcon = (Icon*)pJS_Icon->GetEmbedObject();
 
   CPDF_Stream* pIconStream = nullptr;
@@ -3023,11 +3011,11 @@
     return FALSE;
 
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  int nWidget = params[0].ToInt(pRuntime->GetIsolate());
+  int nWidget = params[0].ToInt(pRuntime);
 
   bool bCheckit = true;
   if (iSize >= 2)
-    bCheckit = params[1].ToBool(pRuntime->GetIsolate());
+    bCheckit = params[1].ToBool(pRuntime);
 
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
   if (FieldArray.empty())
@@ -3069,7 +3057,7 @@
     return FALSE;
 
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  int nWidget = params[0].ToInt(pRuntime->GetIsolate());
+  int nWidget = params[0].ToInt(pRuntime);
 
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
   if (FieldArray.empty())
@@ -3118,16 +3106,15 @@
 
   int j = 0;
   for (const auto& pStr : swSort) {
-    v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj(
-        pRuntime->GetIsolate(), pRuntime, CJS_Field::g_nObjDefnID);
+    v8::Local<v8::Object> pObj =
+        pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
     ASSERT(!pObj.IsEmpty());
 
     CJS_Field* pJSField =
-        static_cast<CJS_Field*>(FXJS_GetPrivate(pRuntime->GetIsolate(), pObj));
+        static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pObj));
     Field* pField = static_cast<Field*>(pJSField->GetEmbedObject());
     pField->AttachField(m_pJSDoc, *pStr);
-    FormFieldArray.SetElement(pRuntime->GetIsolate(), j++,
-                              CJS_Value(pRuntime, pJSField));
+    FormFieldArray.SetElement(pRuntime, j++, CJS_Value(pRuntime, pJSField));
   }
 
   vRet = CJS_Value(pRuntime, FormFieldArray);
@@ -3143,11 +3130,11 @@
   int iSize = params.size();
   int nIdx = -1;
   if (iSize >= 1)
-    nIdx = params[0].ToInt(pRuntime->GetIsolate());
+    nIdx = params[0].ToInt(pRuntime);
 
   FX_BOOL bExport = TRUE;
   if (iSize >= 2)
-    bExport = params[1].ToBool(pRuntime->GetIsolate());
+    bExport = params[1].ToBool(pRuntime);
 
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
   if (FieldArray.empty())
@@ -3196,7 +3183,7 @@
 
   int nIndex = -1;
   if (params.size() >= 1)
-    nIndex = params[0].ToInt(pRuntime->GetIsolate());
+    nIndex = params[0].ToInt(pRuntime);
 
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
   if (FieldArray.empty())
@@ -3222,7 +3209,7 @@
 
   int nIndex = -1;
   if (params.size() >= 1)
-    nIndex = params[0].ToInt(pRuntime->GetIsolate());
+    nIndex = params[0].ToInt(pRuntime);
 
   std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName);
   if (FieldArray.empty())
diff --git a/fpdfsdk/javascript/Field.h b/fpdfsdk/javascript/Field.h
index 3d1b0ff..0ffdbd4 100644
--- a/fpdfsdk/javascript/Field.h
+++ b/fpdfsdk/javascript/Field.h
@@ -435,7 +435,6 @@
 
   FX_BOOL AttachField(Document* pDocument, const CFX_WideString& csFieldName);
   void SetDelay(FX_BOOL bDelay);
-  void SetIsolate(v8::Isolate* isolate) { m_isolate = isolate; }
 
  protected:
   void ParseFieldName(const std::wstring& strFieldNameParsed,
@@ -464,9 +463,7 @@
   CFX_WideString m_FieldName;
   int m_nFormControlIndex;
   FX_BOOL m_bCanSet;
-
   FX_BOOL m_bDelay;
-  v8::Isolate* m_isolate;
 };
 
 class CJS_Field : public CJS_Object {
diff --git a/fpdfsdk/javascript/JS_Define.h b/fpdfsdk/javascript/JS_Define.h
index b9ae140..770f9f5 100644
--- a/fpdfsdk/javascript/JS_Define.h
+++ b/fpdfsdk/javascript/JS_Define.h
@@ -76,23 +76,22 @@
                   const char* class_name_string,
                   v8::Local<v8::String> property,
                   const v8::PropertyCallbackInfo<v8::Value>& info) {
-  v8::Isolate* isolate = info.GetIsolate();
   CJS_Runtime* pRuntime =
-      static_cast<CJS_Runtime*>(FXJS_GetCurrentEngineFromIsolate(isolate));
+      CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
   if (!pRuntime)
     return;
-  IJS_Context* pContext = pRuntime->GetCurrentContext();
-  CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder());
+  CJS_Object* pJSObj =
+      static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
   C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject());
   CFX_WideString sError;
   CJS_PropValue value(pRuntime);
   value.StartGetting();
-  if (!(pObj->*M)(pContext, value, sError)) {
-    FXJS_Error(isolate, JSFormatErrorString(class_name_string, prop_name_string,
-                                            sError));
+  if (!(pObj->*M)(pRuntime->GetCurrentContext(), value, sError)) {
+    pRuntime->Error(
+        JSFormatErrorString(class_name_string, prop_name_string, sError));
     return;
   }
-  info.GetReturnValue().Set(value.GetJSValue()->ToV8Value(isolate));
+  info.GetReturnValue().Set(value.GetJSValue()->ToV8Value(pRuntime));
 }
 
 template <class C,
@@ -102,20 +101,19 @@
                   v8::Local<v8::String> property,
                   v8::Local<v8::Value> value,
                   const v8::PropertyCallbackInfo<void>& info) {
-  v8::Isolate* isolate = info.GetIsolate();
   CJS_Runtime* pRuntime =
-      static_cast<CJS_Runtime*>(FXJS_GetCurrentEngineFromIsolate(isolate));
+      CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
   if (!pRuntime)
     return;
-  IJS_Context* pContext = pRuntime->GetCurrentContext();
-  CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder());
+  CJS_Object* pJSObj =
+      static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
   C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject());
   CFX_WideString sError;
   CJS_PropValue propValue(pRuntime, CJS_Value(pRuntime, value));
   propValue.StartSetting();
-  if (!(pObj->*M)(pContext, propValue, sError)) {
-    FXJS_Error(isolate, JSFormatErrorString(class_name_string, prop_name_string,
-                                            sError));
+  if (!(pObj->*M)(pRuntime->GetCurrentContext(), propValue, sError)) {
+    pRuntime->Error(
+        JSFormatErrorString(class_name_string, prop_name_string, sError));
   }
 }
 
@@ -141,26 +139,26 @@
 void JSMethod(const char* method_name_string,
               const char* class_name_string,
               const v8::FunctionCallbackInfo<v8::Value>& info) {
-  v8::Isolate* isolate = info.GetIsolate();
   CJS_Runtime* pRuntime =
-      static_cast<CJS_Runtime*>(FXJS_GetCurrentEngineFromIsolate(isolate));
+      CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
   if (!pRuntime)
     return;
-  IJS_Context* pContext = pRuntime->GetCurrentContext();
   std::vector<CJS_Value> parameters;
   for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) {
     parameters.push_back(CJS_Value(pRuntime, info[i]));
   }
-  CJS_Value valueRes(pRuntime);
-  CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder());
+  CJS_Object* pJSObj =
+      static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
   C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject());
   CFX_WideString sError;
-  if (!(pObj->*M)(pContext, parameters, valueRes, sError)) {
-    FXJS_Error(isolate, JSFormatErrorString(class_name_string,
-                                            method_name_string, sError));
+  CJS_Value valueRes(pRuntime);
+  if (!(pObj->*M)(pRuntime->GetCurrentContext(), parameters, valueRes,
+                  sError)) {
+    pRuntime->Error(
+        JSFormatErrorString(class_name_string, method_name_string, sError));
     return;
   }
-  info.GetReturnValue().Set(valueRes.ToV8Value(isolate));
+  info.GetReturnValue().Set(valueRes.ToV8Value(pRuntime));
 }
 
 #define JS_STATIC_METHOD(method_name, class_name)                             \
@@ -183,7 +181,7 @@
 #define DECLARE_JS_CLASS_BASE_PART()  \
   static const wchar_t* g_pClassName; \
   static int g_nObjDefnID;            \
-  static void DefineJSObjects(v8::Isolate* pIsolate, FXJSOBJTYPE eObjType);
+  static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
 
 #define IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)           \
   const wchar_t* js_class_name::g_pClassName = JS_WIDESTRING(class_name); \
@@ -194,28 +192,28 @@
   DECLARE_JS_CLASS_BASE_PART()   \
   DECLARE_JS_CLASS_CONST_PART()
 
-#define IMPLEMENT_JS_CLASS_CONST(js_class_name, class_name)              \
-  IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                \
-  IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)               \
-  void js_class_name::DefineJSObjects(v8::Isolate* pIsolate,             \
-                                      FXJSOBJTYPE eObjType) {            \
-    g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName, \
-                                  eObjType, nullptr, nullptr);           \
-    DefineConsts(pIsolate);                                              \
+#define IMPLEMENT_JS_CLASS_CONST(js_class_name, class_name)                  \
+  IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                    \
+  IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                   \
+  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine,                 \
+                                      FXJSOBJTYPE eObjType) {                \
+    g_nObjDefnID = pEngine->DefineObj(js_class_name::g_pClassName, eObjType, \
+                                      nullptr, nullptr);                     \
+    DefineConsts(pEngine);                                                   \
   }
 
 #define DECLARE_JS_CLASS_CONST_PART()   \
   static JSConstSpec JS_Class_Consts[]; \
-  static void DefineConsts(v8::Isolate* pIsolate);
+  static void DefineConsts(CFXJS_Engine* pEngine);
 
 #define IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)     \
-  void js_class_name::DefineConsts(v8::Isolate* pIsolate) {          \
+  void js_class_name::DefineConsts(CFXJS_Engine* pEngine) {          \
     for (size_t i = 0; i < FX_ArraySize(JS_Class_Consts) - 1; ++i) { \
-      FXJS_DefineObjConst(                                           \
-          pIsolate, g_nObjDefnID, JS_Class_Consts[i].pName,          \
+      pEngine->DefineObjConst(                                       \
+          g_nObjDefnID, JS_Class_Consts[i].pName,                    \
           JS_Class_Consts[i].t == 0                                  \
-              ? FXJS_NewNumber(pIsolate, JS_Class_Consts[i].number)  \
-              : FXJS_NewString(pIsolate, JS_Class_Consts[i].str));   \
+              ? pEngine->NewNumber(JS_Class_Consts[i].number)        \
+              : pEngine->NewString(JS_Class_Consts[i].str));         \
     }                                                                \
   }
 
@@ -231,53 +229,55 @@
   DECLARE_JS_CLASS_CONST_PART() \
   DECLARE_JS_CLASS_RICH_PART()
 
-#define IMPLEMENT_JS_CLASS_RICH(js_class_name, class_alternate, class_name) \
-  IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                   \
-  IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                  \
-  IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, class_name)  \
-  void js_class_name::DefineJSObjects(v8::Isolate* pIsolate,                \
-                                      FXJSOBJTYPE eObjType) {               \
-    g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName,    \
-                                  eObjType, JSConstructor, JSDestructor);   \
-    DefineConsts(pIsolate);                                                 \
-    DefineProps(pIsolate);                                                  \
-    DefineMethods(pIsolate);                                                \
+#define IMPLEMENT_JS_CLASS_RICH(js_class_name, class_alternate, class_name)  \
+  IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name)                    \
+  IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                   \
+  IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, class_name)   \
+  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine,                 \
+                                      FXJSOBJTYPE eObjType) {                \
+    g_nObjDefnID = pEngine->DefineObj(js_class_name::g_pClassName, eObjType, \
+                                      JSConstructor, JSDestructor);          \
+    DefineConsts(pEngine);                                                   \
+    DefineProps(pEngine);                                                    \
+    DefineMethods(pEngine);                                                  \
   }
 
 #define DECLARE_JS_CLASS_RICH_PART()                                           \
   static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj); \
-  static void JSDestructor(v8::Local<v8::Object> obj);                         \
-  static void DefineProps(v8::Isolate* pIsoalte);                              \
-  static void DefineMethods(v8::Isolate* pIsoalte);                            \
+  static void JSDestructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);  \
+  static void DefineProps(CFXJS_Engine* pEngine);                              \
+  static void DefineMethods(CFXJS_Engine* pEngine);                            \
   static JSPropertySpec JS_Class_Properties[];                                 \
   static JSMethodSpec JS_Class_Methods[];
 
-#define IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate,          \
-                                     class_name)                              \
-  void js_class_name::JSConstructor(CFXJS_Engine* pEngine,                    \
-                                    v8::Local<v8::Object> obj) {              \
-    CJS_Object* pObj = new js_class_name(obj);                                \
-    pObj->SetEmbedObject(new class_alternate(pObj));                          \
-    FXJS_SetPrivate(nullptr, obj, (void*)pObj);                               \
-    pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));                   \
-  }                                                                           \
-  void js_class_name::JSDestructor(v8::Local<v8::Object> obj) {               \
-    js_class_name* pObj = (js_class_name*)FXJS_GetPrivate(nullptr, obj);      \
-    pObj->ExitInstance();                                                     \
-    delete pObj;                                                              \
-  }                                                                           \
-  void js_class_name::DefineProps(v8::Isolate* pIsolate) {                    \
-    for (size_t i = 0; i < FX_ArraySize(JS_Class_Properties) - 1; ++i) {      \
-      FXJS_DefineObjProperty(                                                 \
-          pIsolate, g_nObjDefnID, JS_Class_Properties[i].pName,               \
-          JS_Class_Properties[i].pPropGet, JS_Class_Properties[i].pPropPut);  \
-    }                                                                         \
-  }                                                                           \
-  void js_class_name::DefineMethods(v8::Isolate* pIsolate) {                  \
-    for (size_t i = 0; i < FX_ArraySize(JS_Class_Methods) - 1; ++i) {         \
-      FXJS_DefineObjMethod(pIsolate, g_nObjDefnID, JS_Class_Methods[i].pName, \
-                           JS_Class_Methods[i].pMethodCall);                  \
-    }                                                                         \
+#define IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate,         \
+                                     class_name)                             \
+  void js_class_name::JSConstructor(CFXJS_Engine* pEngine,                   \
+                                    v8::Local<v8::Object> obj) {             \
+    CJS_Object* pObj = new js_class_name(obj);                               \
+    pObj->SetEmbedObject(new class_alternate(pObj));                         \
+    pEngine->SetObjectPrivate(obj, (void*)pObj);                             \
+    pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));                  \
+  }                                                                          \
+  void js_class_name::JSDestructor(CFXJS_Engine* pEngine,                    \
+                                   v8::Local<v8::Object> obj) {              \
+    js_class_name* pObj =                                                    \
+        static_cast<js_class_name*>(pEngine->GetObjectPrivate(obj));         \
+    pObj->ExitInstance();                                                    \
+    delete pObj;                                                             \
+  }                                                                          \
+  void js_class_name::DefineProps(CFXJS_Engine* pEngine) {                   \
+    for (size_t i = 0; i < FX_ArraySize(JS_Class_Properties) - 1; ++i) {     \
+      pEngine->DefineObjProperty(g_nObjDefnID, JS_Class_Properties[i].pName, \
+                                 JS_Class_Properties[i].pPropGet,            \
+                                 JS_Class_Properties[i].pPropPut);           \
+    }                                                                        \
+  }                                                                          \
+  void js_class_name::DefineMethods(CFXJS_Engine* pEngine) {                 \
+    for (size_t i = 0; i < FX_ArraySize(JS_Class_Methods) - 1; ++i) {        \
+      pEngine->DefineObjMethod(g_nObjDefnID, JS_Class_Methods[i].pName,      \
+                               JS_Class_Methods[i].pMethodCall);             \
+    }                                                                        \
   }
 
 // Special JS classes implement methods, props, and queries, but not consts.
@@ -292,14 +292,14 @@
   IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name)                     \
   IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, class_name)     \
   IMPLEMENT_SPECIAL_JS_CLASS_PART(js_class_name, class_alternate, class_name)  \
-  void js_class_name::DefineJSObjects(v8::Isolate* pIsolate,                   \
+  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine,                   \
                                       FXJSOBJTYPE eObjType) {                  \
-    g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName,       \
-                                  eObjType, JSConstructor, JSDestructor);      \
-    DefineConsts(pIsolate);                                                    \
-    DefineProps(pIsolate);                                                     \
-    DefineMethods(pIsolate);                                                   \
-    DefineAllProperties(pIsolate);                                             \
+    g_nObjDefnID = pEngine->DefineObj(js_class_name::g_pClassName, eObjType,   \
+                                      JSConstructor, JSDestructor);            \
+    DefineConsts(pEngine);                                                     \
+    DefineProps(pEngine);                                                      \
+    DefineMethods(pEngine);                                                    \
+    DefineAllProperties(pEngine);                                              \
   }
 
 #define DECLARE_SPECIAL_JS_CLASS_PART()                                        \
@@ -314,7 +314,7 @@
   static void delprop_static(                                                  \
       v8::Local<v8::String> property,                                          \
       const v8::PropertyCallbackInfo<v8::Boolean>& info);                      \
-  static void DefineAllProperties(v8::Isolate* pIsolate);
+  static void DefineAllProperties(CFXJS_Engine* pEngine);
 
 #define IMPLEMENT_SPECIAL_JS_CLASS_PART(js_class_name, class_alternate,    \
                                         class_name)                        \
@@ -338,9 +338,9 @@
       const v8::PropertyCallbackInfo<v8::Boolean>& info) {                 \
     JSSpecialPropDel<class_alternate>(#class_name, property, info);        \
   }                                                                        \
-  void js_class_name::DefineAllProperties(v8::Isolate* pIsolate) {         \
-    FXJS_DefineObjAllProperties(                                           \
-        pIsolate, g_nObjDefnID, js_class_name::queryprop_static,           \
+  void js_class_name::DefineAllProperties(CFXJS_Engine* pEngine) {         \
+    pEngine->DefineObjAllProperties(                                       \
+        g_nObjDefnID, js_class_name::queryprop_static,                     \
         js_class_name::getprop_static, js_class_name::putprop_static,      \
         js_class_name::delprop_static);                                    \
   }
@@ -349,12 +349,13 @@
 void JSSpecialPropQuery(const char*,
                         v8::Local<v8::String> property,
                         const v8::PropertyCallbackInfo<v8::Integer>& info) {
-  v8::Isolate* isolate = info.GetIsolate();
+  CJS_Runtime* pRuntime =
+      CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
   v8::String::Utf8Value utf8_value(property);
   CFX_WideString propname = CFX_WideString::FromUTF8(
       CFX_ByteStringC(*utf8_value, utf8_value.length()));
   CJS_Object* pJSObj =
-      reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder()));
+      static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
   FX_BOOL bRet = pObj->QueryProperty(propname.c_str());
   info.GetReturnValue().Set(bRet ? 4 : 0);
@@ -364,14 +365,12 @@
 void JSSpecialPropGet(const char* class_name,
                       v8::Local<v8::String> property,
                       const v8::PropertyCallbackInfo<v8::Value>& info) {
-  v8::Isolate* isolate = info.GetIsolate();
   CJS_Runtime* pRuntime =
-      static_cast<CJS_Runtime*>(FXJS_GetCurrentEngineFromIsolate(isolate));
+      CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
   if (!pRuntime)
     return;
-  IJS_Context* pContext = pRuntime->GetCurrentContext();
   CJS_Object* pJSObj =
-      reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder()));
+      static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
   v8::String::Utf8Value utf8_value(property);
   CFX_WideString propname = CFX_WideString::FromUTF8(
@@ -379,11 +378,12 @@
   CFX_WideString sError;
   CJS_PropValue value(pRuntime);
   value.StartGetting();
-  if (!pObj->DoProperty(pContext, propname.c_str(), value, sError)) {
-    FXJS_Error(isolate, JSFormatErrorString(class_name, "GetProperty", sError));
+  if (!pObj->DoProperty(pRuntime->GetCurrentContext(), propname.c_str(), value,
+                        sError)) {
+    pRuntime->Error(JSFormatErrorString(class_name, "GetProperty", sError));
     return;
   }
-  info.GetReturnValue().Set(value.GetJSValue()->ToV8Value(isolate));
+  info.GetReturnValue().Set(value.GetJSValue()->ToV8Value(pRuntime));
 }
 
 template <class Alt>
@@ -391,14 +391,12 @@
                       v8::Local<v8::String> property,
                       v8::Local<v8::Value> value,
                       const v8::PropertyCallbackInfo<v8::Value>& info) {
-  v8::Isolate* isolate = info.GetIsolate();
   CJS_Runtime* pRuntime =
-      static_cast<CJS_Runtime*>(FXJS_GetCurrentEngineFromIsolate(isolate));
+      CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
   if (!pRuntime)
     return;
-  IJS_Context* pContext = pRuntime->GetCurrentContext();
   CJS_Object* pJSObj =
-      reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder()));
+      static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
   v8::String::Utf8Value utf8_value(property);
   CFX_WideString propname = CFX_WideString::FromUTF8(
@@ -406,8 +404,9 @@
   CFX_WideString sError;
   CJS_PropValue PropValue(pRuntime, CJS_Value(pRuntime, value));
   PropValue.StartSetting();
-  if (!pObj->DoProperty(pContext, propname.c_str(), PropValue, sError)) {
-    FXJS_Error(isolate, JSFormatErrorString(class_name, "PutProperty", sError));
+  if (!pObj->DoProperty(pRuntime->GetCurrentContext(), propname.c_str(),
+                        PropValue, sError)) {
+    pRuntime->Error(JSFormatErrorString(class_name, "PutProperty", sError));
   }
 }
 
@@ -415,20 +414,19 @@
 void JSSpecialPropDel(const char* class_name,
                       v8::Local<v8::String> property,
                       const v8::PropertyCallbackInfo<v8::Boolean>& info) {
-  v8::Isolate* isolate = info.GetIsolate();
   CJS_Runtime* pRuntime =
-      static_cast<CJS_Runtime*>(FXJS_GetCurrentEngineFromIsolate(isolate));
+      CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
   if (!pRuntime)
     return;
-  IJS_Context* pContext = pRuntime->GetCurrentContext();
   CJS_Object* pJSObj =
-      reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder()));
+      static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
   v8::String::Utf8Value utf8_value(property);
   CFX_WideString propname = CFX_WideString::FromUTF8(
       CFX_ByteStringC(*utf8_value, utf8_value.length()));
   CFX_WideString sError;
-  if (!pObj->DelProperty(pContext, propname.c_str(), sError)) {
+  if (!pObj->DelProperty(pRuntime->GetCurrentContext(), propname.c_str(),
+                         sError)) {
     CFX_ByteString cbName;
     cbName.Format("%s.%s", class_name, "DelProperty");
     // Probably a missing call to JSFX_Error().
@@ -441,23 +439,21 @@
                        CFX_WideString&)>
 void JSGlobalFunc(const char* func_name_string,
                   const v8::FunctionCallbackInfo<v8::Value>& info) {
-  CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(
-      FXJS_GetCurrentEngineFromIsolate(info.GetIsolate()));
+  CJS_Runtime* pRuntime =
+      CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
   if (!pRuntime)
     return;
-  IJS_Context* pContext = pRuntime->GetCurrentContext();
   std::vector<CJS_Value> parameters;
   for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) {
     parameters.push_back(CJS_Value(pRuntime, info[i]));
   }
   CJS_Value valueRes(pRuntime);
   CFX_WideString sError;
-  if (!(*F)(pContext, parameters, valueRes, sError)) {
-    FXJS_Error(pRuntime->GetIsolate(),
-               JSFormatErrorString(func_name_string, nullptr, sError));
+  if (!(*F)(pRuntime->GetCurrentContext(), parameters, valueRes, sError)) {
+    pRuntime->Error(JSFormatErrorString(func_name_string, nullptr, sError));
     return;
   }
-  info.GetReturnValue().Set(valueRes.ToV8Value(pRuntime->GetIsolate()));
+  info.GetReturnValue().Set(valueRes.ToV8Value(pRuntime));
 }
 
 #define JS_STATIC_GLOBAL_FUN(fun_name)                   \
@@ -468,7 +464,7 @@
 
 #define JS_STATIC_DECLARE_GLOBAL_FUN()  \
   static JSMethodSpec global_methods[]; \
-  static void DefineJSObjects(v8::Isolate* pIsolate)
+  static void DefineJSObjects(CFXJS_Engine* pEngine)
 
 #define BEGIN_JS_STATIC_GLOBAL_FUN(js_class_name) \
   JSMethodSpec js_class_name::global_methods[] = {
@@ -477,13 +473,13 @@
 
 #define END_JS_STATIC_GLOBAL_FUN() END_JS_STATIC_METHOD()
 
-#define IMPLEMENT_JS_STATIC_GLOBAL_FUN(js_class_name)                        \
-  void js_class_name::DefineJSObjects(v8::Isolate* pIsolate) {               \
-    for (size_t i = 0; i < FX_ArraySize(global_methods) - 1; ++i) {          \
-      FXJS_DefineGlobalMethod(pIsolate,                                      \
-                              js_class_name::global_methods[i].pName,        \
-                              js_class_name::global_methods[i].pMethodCall); \
-    }                                                                        \
+#define IMPLEMENT_JS_STATIC_GLOBAL_FUN(js_class_name)               \
+  void js_class_name::DefineJSObjects(CFXJS_Engine* pEngine) {      \
+    for (size_t i = 0; i < FX_ArraySize(global_methods) - 1; ++i) { \
+      pEngine->DefineGlobalMethod(                                  \
+          js_class_name::global_methods[i].pName,                   \
+          js_class_name::global_methods[i].pMethodCall);            \
+    }                                                               \
   }
 
 #endif  // FPDFSDK_JAVASCRIPT_JS_DEFINE_H_
diff --git a/fpdfsdk/javascript/JS_EventHandler.cpp b/fpdfsdk/javascript/JS_EventHandler.cpp
index 8dc1b82..fe9a909 100644
--- a/fpdfsdk/javascript/JS_EventHandler.cpp
+++ b/fpdfsdk/javascript/JS_EventHandler.cpp
@@ -595,22 +595,22 @@
 
 Field* CJS_EventHandler::Source() {
   CJS_Runtime* pRuntime = m_pJSContext->GetJSRuntime();
-  v8::Local<v8::Object> pDocObj = FXJS_NewFxDynamicObj(
-      pRuntime->GetIsolate(), pRuntime, CJS_Document::g_nObjDefnID);
+  v8::Local<v8::Object> pDocObj =
+      pRuntime->NewFxDynamicObj(CJS_Document::g_nObjDefnID);
   ASSERT(!pDocObj.IsEmpty());
 
-  v8::Local<v8::Object> pFieldObj = FXJS_NewFxDynamicObj(
-      pRuntime->GetIsolate(), pRuntime, CJS_Field::g_nObjDefnID);
+  v8::Local<v8::Object> pFieldObj =
+      pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
   ASSERT(!pFieldObj.IsEmpty());
 
   CJS_Document* pJSDocument =
-      (CJS_Document*)FXJS_GetPrivate(pRuntime->GetIsolate(), pDocObj);
+      static_cast<CJS_Document*>(pRuntime->GetObjectPrivate(pDocObj));
   Document* pDocument = (Document*)pJSDocument->GetEmbedObject();
   pDocument->AttachDoc(m_pTargetDoc ? m_pTargetDoc
                                     : m_pJSContext->GetReaderDocument());
 
   CJS_Field* pJSField =
-      (CJS_Field*)FXJS_GetPrivate(pRuntime->GetIsolate(), pFieldObj);
+      static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pFieldObj));
   Field* pField = (Field*)pJSField->GetEmbedObject();
   pField->AttachField(pDocument, m_strSourceName);
   return pField;
@@ -618,22 +618,22 @@
 
 Field* CJS_EventHandler::Target_Field() {
   CJS_Runtime* pRuntime = m_pJSContext->GetJSRuntime();
-  v8::Local<v8::Object> pDocObj = FXJS_NewFxDynamicObj(
-      pRuntime->GetIsolate(), pRuntime, CJS_Document::g_nObjDefnID);
+  v8::Local<v8::Object> pDocObj =
+      pRuntime->NewFxDynamicObj(CJS_Document::g_nObjDefnID);
   ASSERT(!pDocObj.IsEmpty());
 
-  v8::Local<v8::Object> pFieldObj = FXJS_NewFxDynamicObj(
-      pRuntime->GetIsolate(), pRuntime, CJS_Field::g_nObjDefnID);
+  v8::Local<v8::Object> pFieldObj =
+      pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
   ASSERT(!pFieldObj.IsEmpty());
 
   CJS_Document* pJSDocument =
-      (CJS_Document*)FXJS_GetPrivate(pRuntime->GetIsolate(), pDocObj);
+      static_cast<CJS_Document*>(pRuntime->GetObjectPrivate(pDocObj));
   Document* pDocument = (Document*)pJSDocument->GetEmbedObject();
   pDocument->AttachDoc(m_pTargetDoc ? m_pTargetDoc
                                     : m_pJSContext->GetReaderDocument());
 
   CJS_Field* pJSField =
-      (CJS_Field*)FXJS_GetPrivate(pRuntime->GetIsolate(), pFieldObj);
+      static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pFieldObj));
   Field* pField = (Field*)pJSField->GetEmbedObject();
   pField->AttachField(pDocument, m_strTargetName);
   return pField;
diff --git a/fpdfsdk/javascript/JS_Object.cpp b/fpdfsdk/javascript/JS_Object.cpp
index d67ceeb..3de0ece 100644
--- a/fpdfsdk/javascript/JS_Object.cpp
+++ b/fpdfsdk/javascript/JS_Object.cpp
@@ -19,7 +19,7 @@
   CJS_Object* pJSObj = data.GetParameter();
   pJSObj->ExitInstance();
   delete pJSObj;
-  FXJS_FreePrivate(data.GetInternalField(0));
+  CFXJS_Engine::FreeObjectPrivate(data.GetInternalField(0));
 }
 
 void DisposeObject(const v8::WeakCallbackInfo<CJS_Object>& data) {
diff --git a/fpdfsdk/javascript/JS_Runtime_Stub.cpp b/fpdfsdk/javascript/JS_Runtime_Stub.cpp
index 109be0a..98c641f 100644
--- a/fpdfsdk/javascript/JS_Runtime_Stub.cpp
+++ b/fpdfsdk/javascript/JS_Runtime_Stub.cpp
@@ -147,7 +147,8 @@
   }
 #endif  // PDF_ENABLE_XFA
 
-  int Execute(const CFX_WideString& script, CFX_WideString* info) override {
+  int ExecuteScript(const CFX_WideString& script,
+                    CFX_WideString* info) override {
     return 0;
   }
 
diff --git a/fpdfsdk/javascript/JS_Value.cpp b/fpdfsdk/javascript/JS_Value.cpp
index b719835..c99affb 100644
--- a/fpdfsdk/javascript/JS_Value.cpp
+++ b/fpdfsdk/javascript/JS_Value.cpp
@@ -39,16 +39,16 @@
     : m_pValue(pValue) {}
 
 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const int& iValue)
-    : m_pValue(FXJS_NewNumber(pRuntime->GetIsolate(), iValue)) {}
+    : m_pValue(pRuntime->NewNumber(iValue)) {}
 
 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const bool& bValue)
-    : m_pValue(FXJS_NewBoolean(pRuntime->GetIsolate(), bValue)) {}
+    : m_pValue(pRuntime->NewBoolean(bValue)) {}
 
 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const float& fValue)
-    : m_pValue(FXJS_NewNumber(pRuntime->GetIsolate(), fValue)) {}
+    : m_pValue(pRuntime->NewNumber(fValue)) {}
 
 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const double& dValue)
-    : m_pValue(FXJS_NewNumber(pRuntime->GetIsolate(), dValue)) {}
+    : m_pValue(pRuntime->NewNumber(dValue)) {}
 
 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, CJS_Object* pObj) {
   if (pObj)
@@ -56,17 +56,16 @@
 }
 
 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const FX_WCHAR* pWstr)
-    : m_pValue(FXJS_NewString(pRuntime->GetIsolate(), (wchar_t*)pWstr)) {}
+    : m_pValue(pRuntime->NewString(pWstr)) {}
 
 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const FX_CHAR* pStr)
-    : m_pValue(FXJS_NewString(pRuntime->GetIsolate(),
-                              CFX_WideString::FromLocal(pStr).c_str())) {}
+    : m_pValue(pRuntime->NewString(CFX_WideString::FromLocal(pStr).c_str())) {}
 
 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const CJS_Array& array)
-    : m_pValue(array.ToV8Array(pRuntime->GetIsolate())) {}
+    : m_pValue(array.ToV8Array(pRuntime)) {}
 
 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const CJS_Date& date)
-    : m_pValue(date.ToV8Date(pRuntime->GetIsolate())) {}
+    : m_pValue(date.ToV8Date(pRuntime)) {}
 
 CJS_Value::~CJS_Value() {}
 
@@ -80,62 +79,63 @@
   m_pValue = v8::Local<v8::Value>();
 }
 
-int CJS_Value::ToInt(v8::Isolate* pIsolate) const {
-  return FXJS_ToInt32(pIsolate, m_pValue);
+int CJS_Value::ToInt(CJS_Runtime* pRuntime) const {
+  return pRuntime->ToInt32(m_pValue);
 }
 
-bool CJS_Value::ToBool(v8::Isolate* pIsolate) const {
-  return FXJS_ToBoolean(pIsolate, m_pValue);
+bool CJS_Value::ToBool(CJS_Runtime* pRuntime) const {
+  return pRuntime->ToBoolean(m_pValue);
 }
 
-double CJS_Value::ToDouble(v8::Isolate* pIsolate) const {
-  return FXJS_ToNumber(pIsolate, m_pValue);
+double CJS_Value::ToDouble(CJS_Runtime* pRuntime) const {
+  return pRuntime->ToNumber(m_pValue);
 }
 
-float CJS_Value::ToFloat(v8::Isolate* pIsolate) const {
-  return (float)ToDouble(pIsolate);
+float CJS_Value::ToFloat(CJS_Runtime* pRuntime) const {
+  return (float)ToDouble(pRuntime);
 }
 
-CJS_Object* CJS_Value::ToCJSObject(v8::Isolate* pIsolate) const {
-  v8::Local<v8::Object> pObj = FXJS_ToObject(pIsolate, m_pValue);
-  return (CJS_Object*)FXJS_GetPrivate(pIsolate, pObj);
+CJS_Object* CJS_Value::ToCJSObject(CJS_Runtime* pRuntime) const {
+  v8::Local<v8::Object> pObj = pRuntime->ToObject(m_pValue);
+  return static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(pObj));
 }
 
-v8::Local<v8::Object> CJS_Value::ToV8Object(v8::Isolate* pIsolate) const {
-  return FXJS_ToObject(pIsolate, m_pValue);
+v8::Local<v8::Object> CJS_Value::ToV8Object(CJS_Runtime* pRuntime) const {
+  return pRuntime->ToObject(m_pValue);
 }
 
-CFX_WideString CJS_Value::ToCFXWideString(v8::Isolate* pIsolate) const {
-  return FXJS_ToString(pIsolate, m_pValue);
+CFX_WideString CJS_Value::ToCFXWideString(CJS_Runtime* pRuntime) const {
+  return pRuntime->ToString(m_pValue);
 }
 
-CFX_ByteString CJS_Value::ToCFXByteString(v8::Isolate* pIsolate) const {
-  return CFX_ByteString::FromUnicode(ToCFXWideString(pIsolate));
+CFX_ByteString CJS_Value::ToCFXByteString(CJS_Runtime* pRuntime) const {
+  return CFX_ByteString::FromUnicode(ToCFXWideString(pRuntime));
 }
 
-v8::Local<v8::Value> CJS_Value::ToV8Value(v8::Isolate* pIsolate) const {
+v8::Local<v8::Value> CJS_Value::ToV8Value(CJS_Runtime* pRuntime) const {
   return m_pValue;
 }
 
-v8::Local<v8::Array> CJS_Value::ToV8Array(v8::Isolate* pIsolate) const {
+v8::Local<v8::Array> CJS_Value::ToV8Array(CJS_Runtime* pRuntime) const {
   if (IsArrayObject())
-    return v8::Local<v8::Array>::Cast(FXJS_ToObject(pIsolate, m_pValue));
+    return v8::Local<v8::Array>::Cast(pRuntime->ToObject(m_pValue));
   return v8::Local<v8::Array>();
 }
 
 void CJS_Value::SetNull(CJS_Runtime* pRuntime) {
-  m_pValue = FXJS_NewNull(pRuntime->GetIsolate());
+  m_pValue = pRuntime->NewNull();
 }
 
-void CJS_Value::MaybeCoerceToNumber(v8::Isolate* pIsolate) {
+void CJS_Value::MaybeCoerceToNumber(CJS_Runtime* pRuntime) {
   bool bAllowNaN = false;
   if (GetType() == VT_string) {
-    CFX_ByteString bstr = ToCFXByteString(pIsolate);
+    CFX_ByteString bstr = ToCFXByteString(pRuntime);
     if (bstr.GetLength() == 0)
       return;
     if (bstr == "NaN")
       bAllowNaN = true;
   }
+  v8::Isolate* pIsolate = pRuntime->GetIsolate();
   v8::TryCatch try_catch(pIsolate);
   v8::MaybeLocal<v8::Number> maybeNum =
       m_pValue->ToNumber(pIsolate->GetCurrentContext());
@@ -176,14 +176,14 @@
   return !m_pValue.IsEmpty() && m_pValue->IsDate();
 }
 
-bool CJS_Value::ConvertToArray(v8::Isolate* pIsolate, CJS_Array& array) const {
+bool CJS_Value::ConvertToArray(CJS_Runtime* pRuntime, CJS_Array& array) const {
   if (!IsArrayObject())
     return false;
-  array.Attach(FXJS_ToArray(pIsolate, m_pValue));
+  array.Attach(pRuntime->ToArray(m_pValue));
   return true;
 }
 
-bool CJS_Value::ConvertToDate(v8::Isolate* pIsolate, CJS_Date& date) const {
+bool CJS_Value::ConvertToDate(CJS_Runtime* pRuntime, CJS_Date& date) const {
   if (!IsDateObject())
     return false;
   v8::Local<v8::Value> mutable_value = m_pValue;
@@ -206,7 +206,7 @@
 
 void CJS_PropValue::operator>>(int& iValue) const {
   ASSERT(m_bIsSetting);
-  iValue = m_Value.ToInt(m_pJSRuntime->GetIsolate());
+  iValue = m_Value.ToInt(m_pJSRuntime);
 }
 
 void CJS_PropValue::operator<<(bool bValue) {
@@ -216,7 +216,7 @@
 
 void CJS_PropValue::operator>>(bool& bValue) const {
   ASSERT(m_bIsSetting);
-  bValue = m_Value.ToBool(m_pJSRuntime->GetIsolate());
+  bValue = m_Value.ToBool(m_pJSRuntime);
 }
 
 void CJS_PropValue::operator<<(double dValue) {
@@ -226,7 +226,7 @@
 
 void CJS_PropValue::operator>>(double& dValue) const {
   ASSERT(m_bIsSetting);
-  dValue = m_Value.ToDouble(m_pJSRuntime->GetIsolate());
+  dValue = m_Value.ToDouble(m_pJSRuntime);
 }
 
 void CJS_PropValue::operator<<(CJS_Object* pObj) {
@@ -236,7 +236,7 @@
 
 void CJS_PropValue::operator>>(CJS_Object*& ppObj) const {
   ASSERT(m_bIsSetting);
-  ppObj = m_Value.ToCJSObject(m_pJSRuntime->GetIsolate());
+  ppObj = m_Value.ToCJSObject(m_pJSRuntime);
 }
 
 void CJS_PropValue::operator<<(CJS_Document* pJsDoc) {
@@ -246,8 +246,7 @@
 
 void CJS_PropValue::operator>>(CJS_Document*& ppJsDoc) const {
   ASSERT(m_bIsSetting);
-  ppJsDoc = static_cast<CJS_Document*>(
-      m_Value.ToCJSObject(m_pJSRuntime->GetIsolate()));
+  ppJsDoc = static_cast<CJS_Document*>(m_Value.ToCJSObject(m_pJSRuntime));
 }
 
 void CJS_PropValue::operator<<(v8::Local<v8::Object> pObj) {
@@ -257,7 +256,7 @@
 
 void CJS_PropValue::operator>>(v8::Local<v8::Object>& ppObj) const {
   ASSERT(m_bIsSetting);
-  ppObj = m_Value.ToV8Object(m_pJSRuntime->GetIsolate());
+  ppObj = m_Value.ToV8Object(m_pJSRuntime);
 }
 
 void CJS_PropValue::operator<<(CFX_ByteString str) {
@@ -267,7 +266,7 @@
 
 void CJS_PropValue::operator>>(CFX_ByteString& str) const {
   ASSERT(m_bIsSetting);
-  str = m_Value.ToCFXByteString(m_pJSRuntime->GetIsolate());
+  str = m_Value.ToCFXByteString(m_pJSRuntime);
 }
 
 void CJS_PropValue::operator<<(const FX_WCHAR* str) {
@@ -277,7 +276,7 @@
 
 void CJS_PropValue::operator>>(CFX_WideString& wide_string) const {
   ASSERT(m_bIsSetting);
-  wide_string = m_Value.ToCFXWideString(m_pJSRuntime->GetIsolate());
+  wide_string = m_Value.ToCFXWideString(m_pJSRuntime);
 }
 
 void CJS_PropValue::operator<<(CFX_WideString wide_string) {
@@ -287,18 +286,17 @@
 
 void CJS_PropValue::operator>>(CJS_Array& array) const {
   ASSERT(m_bIsSetting);
-  m_Value.ConvertToArray(m_pJSRuntime->GetIsolate(), array);
+  m_Value.ConvertToArray(m_pJSRuntime, array);
 }
 
 void CJS_PropValue::operator<<(CJS_Array& array) {
   ASSERT(!m_bIsSetting);
-  m_Value =
-      CJS_Value(m_pJSRuntime, array.ToV8Array(m_pJSRuntime->GetIsolate()));
+  m_Value = CJS_Value(m_pJSRuntime, array.ToV8Array(m_pJSRuntime));
 }
 
 void CJS_PropValue::operator>>(CJS_Date& date) const {
   ASSERT(m_bIsSetting);
-  m_Value.ConvertToDate(m_pJSRuntime->GetIsolate(), date);
+  m_Value.ConvertToDate(m_pJSRuntime, date);
 }
 
 void CJS_PropValue::operator<<(CJS_Date& date) {
@@ -316,154 +314,146 @@
   m_pArray = pArray;
 }
 
-void CJS_Array::GetElement(v8::Isolate* pIsolate,
+void CJS_Array::GetElement(CJS_Runtime* pRuntime,
                            unsigned index,
                            CJS_Value& value) const {
   if (!m_pArray.IsEmpty())
-    value.Attach(FXJS_GetArrayElement(pIsolate, m_pArray, index));
+    value.Attach(pRuntime->GetArrayElement(m_pArray, index));
 }
 
-void CJS_Array::SetElement(v8::Isolate* pIsolate,
+void CJS_Array::SetElement(CJS_Runtime* pRuntime,
                            unsigned index,
                            const CJS_Value& value) {
   if (m_pArray.IsEmpty())
-    m_pArray = FXJS_NewArray(pIsolate);
+    m_pArray = pRuntime->NewArray();
 
-  FXJS_PutArrayElement(pIsolate, m_pArray, index, value.ToV8Value(pIsolate));
+  pRuntime->PutArrayElement(m_pArray, index, value.ToV8Value(pRuntime));
 }
 
-int CJS_Array::GetLength() const {
+int CJS_Array::GetLength(CJS_Runtime* pRuntime) const {
   if (m_pArray.IsEmpty())
     return 0;
-  return FXJS_GetArrayLength(m_pArray);
+  return pRuntime->GetArrayLength(m_pArray);
 }
 
-v8::Local<v8::Array> CJS_Array::ToV8Array(v8::Isolate* pIsolate) const {
+v8::Local<v8::Array> CJS_Array::ToV8Array(CJS_Runtime* pRuntime) const {
   if (m_pArray.IsEmpty())
-    m_pArray = FXJS_NewArray(pIsolate);
+    m_pArray = pRuntime->NewArray();
 
   return m_pArray;
 }
 
 CJS_Date::CJS_Date() {}
 
-CJS_Date::CJS_Date(v8::Isolate* pIsolate, double dMsecTime)
-    : m_pDate(FXJS_NewDate(pIsolate, dMsecTime)) {}
+CJS_Date::CJS_Date(CJS_Runtime* pRuntime, double dMsecTime)
+    : m_pDate(pRuntime->NewDate(dMsecTime)) {}
 
-CJS_Date::CJS_Date(v8::Isolate* pIsolate,
+CJS_Date::CJS_Date(CJS_Runtime* pRuntime,
                    int year,
                    int mon,
                    int day,
                    int hour,
                    int min,
                    int sec)
-    : m_pDate(FXJS_NewDate(pIsolate,
-                           MakeDate(year, mon, day, hour, min, sec, 0))) {}
+    : m_pDate(pRuntime->NewDate(MakeDate(year, mon, day, hour, min, sec, 0))) {}
 
 CJS_Date::~CJS_Date() {}
 
-bool CJS_Date::IsValidDate(v8::Isolate* pIsolate) const {
-  return !m_pDate.IsEmpty() && !JS_PortIsNan(FXJS_ToNumber(pIsolate, m_pDate));
+bool CJS_Date::IsValidDate(CJS_Runtime* pRuntime) const {
+  return !m_pDate.IsEmpty() && !JS_PortIsNan(pRuntime->ToNumber(m_pDate));
 }
 
 void CJS_Date::Attach(v8::Local<v8::Date> pDate) {
   m_pDate = pDate;
 }
 
-int CJS_Date::GetYear(v8::Isolate* pIsolate) const {
-  if (!IsValidDate(pIsolate))
+int CJS_Date::GetYear(CJS_Runtime* pRuntime) const {
+  if (!IsValidDate(pRuntime))
     return 0;
 
-  return JS_GetYearFromTime(JS_LocalTime(FXJS_ToNumber(pIsolate, m_pDate)));
+  return JS_GetYearFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate)));
 }
 
-void CJS_Date::SetYear(v8::Isolate* pIsolate, int iYear) {
-  m_pDate = FXJS_NewDate(
-      pIsolate,
-      MakeDate(iYear, GetMonth(pIsolate), GetDay(pIsolate), GetHours(pIsolate),
-               GetMinutes(pIsolate), GetSeconds(pIsolate), 0));
+void CJS_Date::SetYear(CJS_Runtime* pRuntime, int iYear) {
+  m_pDate = pRuntime->NewDate(
+      MakeDate(iYear, GetMonth(pRuntime), GetDay(pRuntime), GetHours(pRuntime),
+               GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
 }
 
-int CJS_Date::GetMonth(v8::Isolate* pIsolate) const {
-  if (!IsValidDate(pIsolate))
+int CJS_Date::GetMonth(CJS_Runtime* pRuntime) const {
+  if (!IsValidDate(pRuntime))
     return 0;
 
-  return JS_GetMonthFromTime(JS_LocalTime(FXJS_ToNumber(pIsolate, m_pDate)));
+  return JS_GetMonthFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate)));
 }
 
-void CJS_Date::SetMonth(v8::Isolate* pIsolate, int iMonth) {
-  m_pDate = FXJS_NewDate(
-      pIsolate,
-      MakeDate(GetYear(pIsolate), iMonth, GetDay(pIsolate), GetHours(pIsolate),
-               GetMinutes(pIsolate), GetSeconds(pIsolate), 0));
+void CJS_Date::SetMonth(CJS_Runtime* pRuntime, int iMonth) {
+  m_pDate = pRuntime->NewDate(
+      MakeDate(GetYear(pRuntime), iMonth, GetDay(pRuntime), GetHours(pRuntime),
+               GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
 }
 
-int CJS_Date::GetDay(v8::Isolate* pIsolate) const {
-  if (!IsValidDate(pIsolate))
+int CJS_Date::GetDay(CJS_Runtime* pRuntime) const {
+  if (!IsValidDate(pRuntime))
     return 0;
 
-  return JS_GetDayFromTime(JS_LocalTime(FXJS_ToNumber(pIsolate, m_pDate)));
+  return JS_GetDayFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate)));
 }
 
-void CJS_Date::SetDay(v8::Isolate* pIsolate, int iDay) {
-  m_pDate = FXJS_NewDate(
-      pIsolate,
-      MakeDate(GetYear(pIsolate), GetMonth(pIsolate), iDay, GetHours(pIsolate),
-               GetMinutes(pIsolate), GetSeconds(pIsolate), 0));
+void CJS_Date::SetDay(CJS_Runtime* pRuntime, int iDay) {
+  m_pDate = pRuntime->NewDate(
+      MakeDate(GetYear(pRuntime), GetMonth(pRuntime), iDay, GetHours(pRuntime),
+               GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
 }
 
-int CJS_Date::GetHours(v8::Isolate* pIsolate) const {
-  if (!IsValidDate(pIsolate))
+int CJS_Date::GetHours(CJS_Runtime* pRuntime) const {
+  if (!IsValidDate(pRuntime))
     return 0;
 
-  return JS_GetHourFromTime(JS_LocalTime(FXJS_ToNumber(pIsolate, m_pDate)));
+  return JS_GetHourFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate)));
 }
 
-void CJS_Date::SetHours(v8::Isolate* pIsolate, int iHours) {
-  m_pDate = FXJS_NewDate(
-      pIsolate,
-      MakeDate(GetYear(pIsolate), GetMonth(pIsolate), GetDay(pIsolate), iHours,
-               GetMinutes(pIsolate), GetSeconds(pIsolate), 0));
+void CJS_Date::SetHours(CJS_Runtime* pRuntime, int iHours) {
+  m_pDate = pRuntime->NewDate(
+      MakeDate(GetYear(pRuntime), GetMonth(pRuntime), GetDay(pRuntime), iHours,
+               GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
 }
 
-int CJS_Date::GetMinutes(v8::Isolate* pIsolate) const {
-  if (!IsValidDate(pIsolate))
+int CJS_Date::GetMinutes(CJS_Runtime* pRuntime) const {
+  if (!IsValidDate(pRuntime))
     return 0;
 
-  return JS_GetMinFromTime(JS_LocalTime(FXJS_ToNumber(pIsolate, m_pDate)));
+  return JS_GetMinFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate)));
 }
 
-void CJS_Date::SetMinutes(v8::Isolate* pIsolate, int minutes) {
-  m_pDate =
-      FXJS_NewDate(pIsolate, MakeDate(GetYear(pIsolate), GetMonth(pIsolate),
-                                      GetDay(pIsolate), GetHours(pIsolate),
-                                      minutes, GetSeconds(pIsolate), 0));
+void CJS_Date::SetMinutes(CJS_Runtime* pRuntime, int minutes) {
+  m_pDate = pRuntime->NewDate(MakeDate(GetYear(pRuntime), GetMonth(pRuntime),
+                                       GetDay(pRuntime), GetHours(pRuntime),
+                                       minutes, GetSeconds(pRuntime), 0));
 }
 
-int CJS_Date::GetSeconds(v8::Isolate* pIsolate) const {
-  if (!IsValidDate(pIsolate))
+int CJS_Date::GetSeconds(CJS_Runtime* pRuntime) const {
+  if (!IsValidDate(pRuntime))
     return 0;
 
-  return JS_GetSecFromTime(JS_LocalTime(FXJS_ToNumber(pIsolate, m_pDate)));
+  return JS_GetSecFromTime(JS_LocalTime(pRuntime->ToNumber(m_pDate)));
 }
 
-void CJS_Date::SetSeconds(v8::Isolate* pIsolate, int seconds) {
-  m_pDate =
-      FXJS_NewDate(pIsolate, MakeDate(GetYear(pIsolate), GetMonth(pIsolate),
-                                      GetDay(pIsolate), GetHours(pIsolate),
-                                      GetMinutes(pIsolate), seconds, 0));
+void CJS_Date::SetSeconds(CJS_Runtime* pRuntime, int seconds) {
+  m_pDate = pRuntime->NewDate(MakeDate(GetYear(pRuntime), GetMonth(pRuntime),
+                                       GetDay(pRuntime), GetHours(pRuntime),
+                                       GetMinutes(pRuntime), seconds, 0));
 }
 
-double CJS_Date::ToDouble(v8::Isolate* pIsolate) const {
-  return !m_pDate.IsEmpty() ? FXJS_ToNumber(pIsolate, m_pDate) : 0.0;
+double CJS_Date::ToDouble(CJS_Runtime* pRuntime) const {
+  return !m_pDate.IsEmpty() ? pRuntime->ToNumber(m_pDate) : 0.0;
 }
 
-CFX_WideString CJS_Date::ToString(v8::Isolate* pIsolate) const {
-  return !m_pDate.IsEmpty() ? FXJS_ToString(pIsolate, m_pDate)
-                            : CFX_WideString();
+CFX_WideString CJS_Date::ToString(CJS_Runtime* pRuntime) const {
+  return !m_pDate.IsEmpty() ? pRuntime->ToString(m_pDate) : CFX_WideString();
 }
 
-v8::Local<v8::Date> CJS_Date::ToV8Date(v8::Isolate* pIsolate) const {
+v8::Local<v8::Date> CJS_Date::ToV8Date(CJS_Runtime* pRuntime) const {
   return m_pDate;
 }
 
@@ -688,7 +678,8 @@
     if (v->IsFunction()) {
       v8::Local<v8::Function> funC = v8::Local<v8::Function>::Cast(v);
       const int argc = 1;
-      v8::Local<v8::String> timeStr = FXJS_WSToJSString(pIsolate, str);
+      v8::Local<v8::String> timeStr =
+          CJS_Runtime::CurrentRuntimeFromIsolate(pIsolate)->WSToJSString(str);
       v8::Local<v8::Value> argv[argc] = {timeStr};
       v = funC->Call(context, context->Global(), argc, argv).ToLocalChecked();
       if (v->IsNumber()) {
@@ -763,15 +754,14 @@
       originals[0].IsArrayObject()) {
     return result;
   }
-  v8::Local<v8::Object> pObj = originals[0].ToV8Object(pRuntime->GetIsolate());
+  v8::Local<v8::Object> pObj = originals[0].ToV8Object(pRuntime);
   result[0] = CJS_Value(pRuntime);  // Make unknown.
 
   va_list ap;
   va_start(ap, nKeywords);
   for (size_t i = 0; i < nKeywords; ++i) {
     const wchar_t* property = va_arg(ap, const wchar_t*);
-    v8::Local<v8::Value> v8Value =
-        FXJS_GetObjectProperty(pRuntime->GetIsolate(), pObj, property);
+    v8::Local<v8::Value> v8Value = pRuntime->GetObjectProperty(pObj, property);
     if (!v8Value->IsUndefined())
       result[i] = CJS_Value(pRuntime, v8Value);
   }
diff --git a/fpdfsdk/javascript/JS_Value.h b/fpdfsdk/javascript/JS_Value.h
index 5587ed0..c567a7c 100644
--- a/fpdfsdk/javascript/JS_Value.h
+++ b/fpdfsdk/javascript/JS_Value.h
@@ -55,25 +55,25 @@
   static Type GetValueType(v8::Local<v8::Value> value);
   Type GetType() const { return GetValueType(m_pValue); }
 
-  int ToInt(v8::Isolate* pIsolate) const;
-  bool ToBool(v8::Isolate* pIsolate) const;
-  double ToDouble(v8::Isolate* pIsolate) const;
-  float ToFloat(v8::Isolate* pIsolate) const;
-  CJS_Object* ToCJSObject(v8::Isolate* pIsolate) const;
-  CFX_WideString ToCFXWideString(v8::Isolate* pIsolate) const;
-  CFX_ByteString ToCFXByteString(v8::Isolate* pIsolate) const;
-  v8::Local<v8::Object> ToV8Object(v8::Isolate* pIsolate) const;
-  v8::Local<v8::Array> ToV8Array(v8::Isolate* pIsolate) const;
-  v8::Local<v8::Value> ToV8Value(v8::Isolate* pIsolate) const;
+  int ToInt(CJS_Runtime* pRuntime) const;
+  bool ToBool(CJS_Runtime* pRuntime) const;
+  double ToDouble(CJS_Runtime* pRuntime) const;
+  float ToFloat(CJS_Runtime* pRuntime) const;
+  CJS_Object* ToCJSObject(CJS_Runtime* pRuntime) const;
+  CFX_WideString ToCFXWideString(CJS_Runtime* pRuntime) const;
+  CFX_ByteString ToCFXByteString(CJS_Runtime* pRuntime) const;
+  v8::Local<v8::Object> ToV8Object(CJS_Runtime* pRuntime) const;
+  v8::Local<v8::Array> ToV8Array(CJS_Runtime* pRuntime) const;
+  v8::Local<v8::Value> ToV8Value(CJS_Runtime* pRuntime) const;
 
   // Replace the current |m_pValue| with a v8::Number if possible
   // to make one from the current |m_pValue|.
-  void MaybeCoerceToNumber(v8::Isolate* pIsolate);
+  void MaybeCoerceToNumber(CJS_Runtime* pRuntime);
 
   bool IsArrayObject() const;
   bool IsDateObject() const;
-  bool ConvertToArray(v8::Isolate* pIsolate, CJS_Array&) const;
-  bool ConvertToDate(v8::Isolate* pIsolate, CJS_Date&) const;
+  bool ConvertToArray(CJS_Runtime* pRuntime, CJS_Array&) const;
+  bool ConvertToDate(CJS_Runtime* pRuntime, CJS_Date&) const;
 
  protected:
   v8::Local<v8::Value> m_pValue;
@@ -127,15 +127,15 @@
   virtual ~CJS_Array();
 
   void Attach(v8::Local<v8::Array> pArray);
-  void GetElement(v8::Isolate* pIsolate,
+  void GetElement(CJS_Runtime* pRuntime,
                   unsigned index,
                   CJS_Value& value) const;
-  void SetElement(v8::Isolate* pIsolate,
+  void SetElement(CJS_Runtime* pRuntime,
                   unsigned index,
                   const CJS_Value& value);
-  int GetLength() const;
+  int GetLength(CJS_Runtime* pRuntime) const;
 
-  v8::Local<v8::Array> ToV8Array(v8::Isolate* pIsolate) const;
+  v8::Local<v8::Array> ToV8Array(CJS_Runtime* pRuntime) const;
 
  private:
   mutable v8::Local<v8::Array> m_pArray;
@@ -144,8 +144,8 @@
 class CJS_Date {
  public:
   CJS_Date();
-  CJS_Date(v8::Isolate* pIsolate, double dMsec_time);
-  CJS_Date(v8::Isolate* pIsolate,
+  CJS_Date(CJS_Runtime* pRuntime, double dMsec_time);
+  CJS_Date(CJS_Runtime* pRuntime,
            int year,
            int mon,
            int day,
@@ -155,29 +155,29 @@
   virtual ~CJS_Date();
 
   void Attach(v8::Local<v8::Date> pDate);
-  bool IsValidDate(v8::Isolate* pIsolate) const;
+  bool IsValidDate(CJS_Runtime* pRuntime) const;
 
-  int GetYear(v8::Isolate* pIsolate) const;
-  void SetYear(v8::Isolate* pIsolate, int iYear);
+  int GetYear(CJS_Runtime* pRuntime) const;
+  void SetYear(CJS_Runtime* pRuntime, int iYear);
 
-  int GetMonth(v8::Isolate* pIsolate) const;
-  void SetMonth(v8::Isolate* pIsolate, int iMonth);
+  int GetMonth(CJS_Runtime* pRuntime) const;
+  void SetMonth(CJS_Runtime* pRuntime, int iMonth);
 
-  int GetDay(v8::Isolate* pIsolate) const;
-  void SetDay(v8::Isolate* pIsolate, int iDay);
+  int GetDay(CJS_Runtime* pRuntime) const;
+  void SetDay(CJS_Runtime* pRuntime, int iDay);
 
-  int GetHours(v8::Isolate* pIsolate) const;
-  void SetHours(v8::Isolate* pIsolate, int iHours);
+  int GetHours(CJS_Runtime* pRuntime) const;
+  void SetHours(CJS_Runtime* pRuntime, int iHours);
 
-  int GetMinutes(v8::Isolate* pIsolate) const;
-  void SetMinutes(v8::Isolate* pIsolate, int minutes);
+  int GetMinutes(CJS_Runtime* pRuntime) const;
+  void SetMinutes(CJS_Runtime* pRuntime, int minutes);
 
-  int GetSeconds(v8::Isolate* pIsolate) const;
-  void SetSeconds(v8::Isolate* pIsolate, int seconds);
+  int GetSeconds(CJS_Runtime* pRuntime) const;
+  void SetSeconds(CJS_Runtime* pRuntime, int seconds);
 
-  v8::Local<v8::Date> ToV8Date(v8::Isolate* pIsolate) const;
-  double ToDouble(v8::Isolate* pIsolate) const;
-  CFX_WideString ToString(v8::Isolate* pIsolate) const;
+  v8::Local<v8::Date> ToV8Date(CJS_Runtime* pRuntime) const;
+  double ToDouble(CJS_Runtime* pRuntime) const;
+  CFX_WideString ToString(CJS_Runtime* pRuntime) const;
 
  protected:
   v8::Local<v8::Date> m_pDate;
diff --git a/fpdfsdk/javascript/PublicMethods.cpp b/fpdfsdk/javascript/PublicMethods.cpp
index f1e23db..01bcfac 100644
--- a/fpdfsdk/javascript/PublicMethods.cpp
+++ b/fpdfsdk/javascript/PublicMethods.cpp
@@ -163,10 +163,10 @@
                                                   CJS_Value val) {
   CJS_Array StrArray;
   if (val.IsArrayObject()) {
-    val.ConvertToArray(pRuntime->GetIsolate(), StrArray);
+    val.ConvertToArray(pRuntime, StrArray);
     return StrArray;
   }
-  CFX_WideString wsStr = val.ToCFXWideString(pRuntime->GetIsolate());
+  CFX_WideString wsStr = val.ToCFXWideString(pRuntime);
   CFX_ByteString t = CFX_ByteString::FromUnicode(wsStr);
   const char* p = t.c_str();
 
@@ -177,7 +177,7 @@
     const char* pTemp = strchr(p, ch);
     if (!pTemp) {
       StrArray.SetElement(
-          pRuntime->GetIsolate(), nIndex,
+          pRuntime, nIndex,
           CJS_Value(pRuntime, StrTrim(CFX_ByteString(p)).c_str()));
       break;
     }
@@ -187,7 +187,7 @@
     *(pSub + (pTemp - p)) = '\0';
 
     StrArray.SetElement(
-        pRuntime->GetIsolate(), nIndex,
+        pRuntime, nIndex,
         CJS_Value(pRuntime, StrTrim(CFX_ByteString(pSub)).c_str()));
     delete[] pSub;
 
@@ -743,13 +743,12 @@
   if (strValue.IsEmpty())
     return TRUE;
 
-  int iDec = params[0].ToInt(pRuntime->GetIsolate());
-  int iSepStyle = params[1].ToInt(pRuntime->GetIsolate());
-  int iNegStyle = params[2].ToInt(pRuntime->GetIsolate());
+  int iDec = params[0].ToInt(pRuntime);
+  int iSepStyle = params[1].ToInt(pRuntime);
+  int iNegStyle = params[2].ToInt(pRuntime);
   // params[3] is iCurrStyle, it's not used.
-  CFX_WideString wstrCurrency =
-      params[4].ToCFXWideString(pRuntime->GetIsolate());
-  FX_BOOL bCurrencyPrepend = params[5].ToBool(pRuntime->GetIsolate());
+  CFX_WideString wstrCurrency = params[4].ToCFXWideString(pRuntime);
+  FX_BOOL bCurrencyPrepend = params[5].ToBool(pRuntime);
 
   if (iDec < 0)
     iDec = -iDec;
@@ -839,12 +838,12 @@
         CJS_Array arColor;
         CJS_Value vColElm(pRuntime);
         vColElm = CJS_Value(pRuntime, L"RGB");
-        arColor.SetElement(pRuntime->GetIsolate(), 0, vColElm);
+        arColor.SetElement(pRuntime, 0, vColElm);
         vColElm = CJS_Value(pRuntime, 1);
-        arColor.SetElement(pRuntime->GetIsolate(), 1, vColElm);
+        arColor.SetElement(pRuntime, 1, vColElm);
         vColElm = CJS_Value(pRuntime, 0);
-        arColor.SetElement(pRuntime->GetIsolate(), 2, vColElm);
-        arColor.SetElement(pRuntime->GetIsolate(), 3, vColElm);
+        arColor.SetElement(pRuntime, 2, vColElm);
+        arColor.SetElement(pRuntime, 3, vColElm);
 
         CJS_PropValue vProp(pRuntime);
         vProp.StartGetting();
@@ -859,18 +858,18 @@
         CJS_Array arColor;
         CJS_Value vColElm(pRuntime);
         vColElm = CJS_Value(pRuntime, L"RGB");
-        arColor.SetElement(pRuntime->GetIsolate(), 0, vColElm);
+        arColor.SetElement(pRuntime, 0, vColElm);
         vColElm = CJS_Value(pRuntime, 0);
-        arColor.SetElement(pRuntime->GetIsolate(), 1, vColElm);
-        arColor.SetElement(pRuntime->GetIsolate(), 2, vColElm);
-        arColor.SetElement(pRuntime->GetIsolate(), 3, vColElm);
+        arColor.SetElement(pRuntime, 1, vColElm);
+        arColor.SetElement(pRuntime, 2, vColElm);
+        arColor.SetElement(pRuntime, 3, vColElm);
 
         CJS_PropValue vProp(pRuntime);
         vProp.StartGetting();
         fTarget->textColor(cc, vProp, sError);
 
         CJS_Array aProp;
-        vProp.GetJSValue()->ConvertToArray(pRuntime->GetIsolate(), aProp);
+        vProp.GetJSValue()->ConvertToArray(pRuntime, aProp);
 
         CPWL_Color crProp;
         CPWL_Color crColor;
@@ -942,7 +941,7 @@
   }
 
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  int iSepStyle = params[1].ToInt(pRuntime->GetIsolate());
+  int iSepStyle = params[1].ToInt(pRuntime);
   if (iSepStyle < 0 || iSepStyle > 3)
     iSepStyle = 0;
   const FX_WCHAR cSep = iSepStyle < 2 ? L'.' : L',';
@@ -1017,11 +1016,11 @@
   if (strValue.IsEmpty())
     return TRUE;
 
-  int iDec = params[0].ToInt(pRuntime->GetIsolate());
+  int iDec = params[0].ToInt(pRuntime);
   if (iDec < 0)
     iDec = -iDec;
 
-  int iSepStyle = params[1].ToInt(pRuntime->GetIsolate());
+  int iSepStyle = params[1].ToInt(pRuntime);
   if (iSepStyle < 0 || iSepStyle > 3)
     iSepStyle = 0;
 
@@ -1117,7 +1116,7 @@
   if (strValue.IsEmpty())
     return TRUE;
 
-  CFX_WideString sFormat = params[0].ToCFXWideString(pRuntime->GetIsolate());
+  CFX_WideString sFormat = params[0].ToCFXWideString(pRuntime);
   double dDate = 0.0f;
 
   if (strValue.Find(L"GMT") != -1) {
@@ -1218,7 +1217,7 @@
     if (strValue.IsEmpty())
       return TRUE;
 
-    CFX_WideString sFormat = params[0].ToCFXWideString(pRuntime->GetIsolate());
+    CFX_WideString sFormat = params[0].ToCFXWideString(pRuntime);
     bool bWrongFormat = FALSE;
     double dRet = MakeRegularDate(strValue, sFormat, &bWrongFormat);
     if (bWrongFormat || JS_PortIsNan(dRet)) {
@@ -1244,7 +1243,7 @@
   }
 
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  int iIndex = params[0].ToInt(pRuntime->GetIsolate());
+  int iIndex = params[0].ToInt(pRuntime);
   const FX_WCHAR* cFormats[] = {L"m/d",
                                 L"m/d/yy",
                                 L"mm/dd/yy",
@@ -1282,7 +1281,7 @@
   }
 
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  int iIndex = params[0].ToInt(pRuntime->GetIsolate());
+  int iIndex = params[0].ToInt(pRuntime);
   const FX_WCHAR* cFormats[] = {L"m/d",
                                 L"m/d/yy",
                                 L"mm/dd/yy",
@@ -1319,7 +1318,7 @@
   }
 
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  int iIndex = params[0].ToInt(pRuntime->GetIsolate());
+  int iIndex = params[0].ToInt(pRuntime);
   const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
                                 L"h:MM:ss tt"};
 
@@ -1344,7 +1343,7 @@
   }
 
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  int iIndex = params[0].ToInt(pRuntime->GetIsolate());
+  int iIndex = params[0].ToInt(pRuntime);
   const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
                                 L"h:MM:ss tt"};
 
@@ -1391,7 +1390,7 @@
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CFX_WideString wsSource = pEvent->Value();
   CFX_WideString wsFormat;
-  switch (params[0].ToInt(pRuntime->GetIsolate())) {
+  switch (params[0].ToInt(pRuntime)) {
     case 0:
       wsFormat = L"99999";
       break;
@@ -1432,7 +1431,7 @@
     return FALSE;
   CFX_WideString& valEvent = pEvent->Value();
 
-  CFX_WideString wstrMask = params[0].ToCFXWideString(pRuntime->GetIsolate());
+  CFX_WideString wstrMask = params[0].ToCFXWideString(pRuntime);
   if (wstrMask.IsEmpty())
     return TRUE;
 
@@ -1520,7 +1519,7 @@
 
   const char* cFormat = "";
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  switch (params[0].ToInt(pRuntime->GetIsolate())) {
+  switch (params[0].ToInt(pRuntime)) {
     case 0:
       cFormat = "99999";
       break;
@@ -1596,8 +1595,8 @@
     return FALSE;
   }
 
-  CFX_WideString sValue = params[0].ToCFXWideString(pRuntime->GetIsolate());
-  CFX_WideString sFormat = params[1].ToCFXWideString(pRuntime->GetIsolate());
+  CFX_WideString sValue = params[0].ToCFXWideString(pRuntime);
+  CFX_WideString sFormat = params[1].ToCFXWideString(pRuntime);
 
   double dDate = MakeRegularDate(sValue, sFormat, nullptr);
 
@@ -1625,11 +1624,10 @@
     return FALSE;
   }
 
-  vRet = CJS_Value(
-      pRuntime, static_cast<double>(AF_Simple(
-                    params[0].ToCFXWideString(pRuntime->GetIsolate()).c_str(),
-                    params[1].ToDouble(pRuntime->GetIsolate()),
-                    params[2].ToDouble(pRuntime->GetIsolate()))));
+  vRet = CJS_Value(pRuntime, static_cast<double>(AF_Simple(
+                                 params[0].ToCFXWideString(pRuntime).c_str(),
+                                 params[1].ToDouble(pRuntime),
+                                 params[2].ToDouble(pRuntime))));
 
   return TRUE;
 }
@@ -1646,10 +1644,10 @@
     return FALSE;
   }
 
-  CFX_WideString ws = params[0].ToCFXWideString(pRuntime->GetIsolate());
+  CFX_WideString ws = params[0].ToCFXWideString(pRuntime);
   ws.Replace(L",", L".");
   vRet = CJS_Value(pRuntime, ws.c_str());
-  vRet.MaybeCoerceToNumber(pRuntime->GetIsolate());
+  vRet.MaybeCoerceToNumber(pRuntime);
   if (vRet.GetType() != CJS_Value::VT_number)
     vRet = CJS_Value(pRuntime, 0);
   return TRUE;
@@ -1678,17 +1676,16 @@
   CPDFSDK_InterForm* pReaderInterForm = pReaderDoc->GetInterForm();
   CPDF_InterForm* pInterForm = pReaderInterForm->GetInterForm();
 
-  CFX_WideString sFunction = params[0].ToCFXWideString(pRuntime->GetIsolate());
+  CFX_WideString sFunction = params[0].ToCFXWideString(pRuntime);
   double dValue = wcscmp(sFunction.c_str(), L"PRD") == 0 ? 1.0 : 0.0;
 
   CJS_Array FieldNameArray = AF_MakeArrayFromList(pRuntime, params1);
   int nFieldsCount = 0;
 
-  for (int i = 0, isz = FieldNameArray.GetLength(); i < isz; i++) {
+  for (int i = 0, isz = FieldNameArray.GetLength(pRuntime); i < isz; i++) {
     CJS_Value jsValue(pRuntime);
-    FieldNameArray.GetElement(pRuntime->GetIsolate(), i, jsValue);
-    CFX_WideString wsFieldName =
-        jsValue.ToCFXWideString(pRuntime->GetIsolate());
+    FieldNameArray.GetElement(pRuntime, i, jsValue);
+    CFX_WideString wsFieldName = jsValue.ToCFXWideString(pRuntime);
 
     for (int j = 0, jsz = pInterForm->CountFields(wsFieldName); j < jsz; j++) {
       if (CPDF_FormField* pFormField = pInterForm->GetField(j, wsFieldName)) {
@@ -1749,8 +1746,7 @@
            FXSYS_pow((double)10, (double)6);
   CJS_Value jsValue(pRuntime, dValue);
   if (pContext->GetEventHandler()->m_pValue)
-    pContext->GetEventHandler()->Value() =
-        jsValue.ToCFXWideString(pRuntime->GetIsolate());
+    pContext->GetEventHandler()->Value() = jsValue.ToCFXWideString(pRuntime);
 
   return TRUE;
 }
@@ -1778,25 +1774,25 @@
     return TRUE;
   double dEentValue =
       atof(CFX_ByteString::FromUnicode(pEvent->Value()).c_str());
-  FX_BOOL bGreaterThan = params[0].ToBool(pRuntime->GetIsolate());
-  double dGreaterThan = params[1].ToDouble(pRuntime->GetIsolate());
-  FX_BOOL bLessThan = params[2].ToBool(pRuntime->GetIsolate());
-  double dLessThan = params[3].ToDouble(pRuntime->GetIsolate());
+  FX_BOOL bGreaterThan = params[0].ToBool(pRuntime);
+  double dGreaterThan = params[1].ToDouble(pRuntime);
+  FX_BOOL bLessThan = params[2].ToBool(pRuntime);
+  double dLessThan = params[3].ToDouble(pRuntime);
   CFX_WideString swMsg;
 
   if (bGreaterThan && bLessThan) {
     if (dEentValue < dGreaterThan || dEentValue > dLessThan)
       swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE1).c_str(),
-                   params[1].ToCFXWideString(pRuntime->GetIsolate()).c_str(),
-                   params[3].ToCFXWideString(pRuntime->GetIsolate()).c_str());
+                   params[1].ToCFXWideString(pRuntime).c_str(),
+                   params[3].ToCFXWideString(pRuntime).c_str());
   } else if (bGreaterThan) {
     if (dEentValue < dGreaterThan)
       swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE2).c_str(),
-                   params[1].ToCFXWideString(pRuntime->GetIsolate()).c_str());
+                   params[1].ToCFXWideString(pRuntime).c_str());
   } else if (bLessThan) {
     if (dEentValue > dLessThan)
       swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE3).c_str(),
-                   params[3].ToCFXWideString(pRuntime->GetIsolate()).c_str());
+                   params[3].ToCFXWideString(pRuntime).c_str());
   }
 
   if (!swMsg.IsEmpty()) {
@@ -1819,7 +1815,7 @@
   }
 
   CJS_Array nums;
-  CFX_WideString str = params[0].ToCFXWideString(pRuntime->GetIsolate());
+  CFX_WideString str = params[0].ToCFXWideString(pRuntime);
   CFX_WideString sPart;
 
   if (str.GetAt(0) == L'.' || str.GetAt(0) == L',')
@@ -1832,8 +1828,7 @@
       sPart += wc;
     } else {
       if (sPart.GetLength() > 0) {
-        nums.SetElement(pRuntime->GetIsolate(), nIndex,
-                        CJS_Value(pRuntime, sPart.c_str()));
+        nums.SetElement(pRuntime, nIndex, CJS_Value(pRuntime, sPart.c_str()));
         sPart = L"";
         nIndex++;
       }
@@ -1841,11 +1836,10 @@
   }
 
   if (sPart.GetLength() > 0) {
-    nums.SetElement(pRuntime->GetIsolate(), nIndex,
-                    CJS_Value(pRuntime, sPart.c_str()));
+    nums.SetElement(pRuntime, nIndex, CJS_Value(pRuntime, sPart.c_str()));
   }
 
-  if (nums.GetLength() > 0)
+  if (nums.GetLength(pRuntime) > 0)
     vRet = CJS_Value(pRuntime, nums);
   else
     vRet.SetNull(pRuntime);
diff --git a/fpdfsdk/javascript/app.cpp b/fpdfsdk/javascript/app.cpp
index 8d7420b..18415dc 100644
--- a/fpdfsdk/javascript/app.cpp
+++ b/fpdfsdk/javascript/app.cpp
@@ -235,21 +235,21 @@
   if (CPDFSDK_Document* pDoc = pApp->GetSDKDocument()) {
     CJS_Document* pJSDocument = nullptr;
     if (pDoc == pCurDoc) {
-      v8::Local<v8::Object> pObj = FXJS_GetThisObj(pRuntime->GetIsolate());
-      if (FXJS_GetObjDefnID(pObj) == CJS_Document::g_nObjDefnID)
+      v8::Local<v8::Object> pObj = pRuntime->GetThisObj();
+      if (CFXJS_Engine::GetObjDefnID(pObj) == CJS_Document::g_nObjDefnID) {
         pJSDocument =
-            (CJS_Document*)FXJS_GetPrivate(pRuntime->GetIsolate(), pObj);
+            static_cast<CJS_Document*>(pRuntime->GetObjectPrivate(pObj));
+      }
     } else {
-      v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj(
-          pRuntime->GetIsolate(), pRuntime, CJS_Document::g_nObjDefnID);
+      v8::Local<v8::Object> pObj =
+          pRuntime->NewFxDynamicObj(CJS_Document::g_nObjDefnID);
       pJSDocument =
-          (CJS_Document*)FXJS_GetPrivate(pRuntime->GetIsolate(), pObj);
+          static_cast<CJS_Document*>(pRuntime->GetObjectPrivate(pObj));
       ASSERT(pJSDocument);
     }
-    aDocs.SetElement(pRuntime->GetIsolate(), 0,
-                     CJS_Value(pRuntime, pJSDocument));
+    aDocs.SetElement(pRuntime, 0, CJS_Value(pRuntime, pJSDocument));
   }
-  if (aDocs.GetLength() > 0)
+  if (aDocs.GetLength(pRuntime) > 0)
     vp << aDocs;
   else
     vp.GetJSValue()->SetNull(pRuntime);
@@ -412,34 +412,34 @@
   CFX_WideString swMsg;
   if (newParams[0].GetType() == CJS_Value::VT_object) {
     CJS_Array carray;
-    if (newParams[0].ConvertToArray(pRuntime->GetIsolate(), carray)) {
+    if (newParams[0].ConvertToArray(pRuntime, carray)) {
       swMsg = L"[";
       CJS_Value element(pRuntime);
-      for (int i = 0; i < carray.GetLength(); ++i) {
+      for (int i = 0; i < carray.GetLength(pRuntime); ++i) {
         if (i)
           swMsg += L", ";
-        carray.GetElement(pRuntime->GetIsolate(), i, element);
-        swMsg += element.ToCFXWideString(pRuntime->GetIsolate());
+        carray.GetElement(pRuntime, i, element);
+        swMsg += element.ToCFXWideString(pRuntime);
       }
       swMsg += L"]";
     } else {
-      swMsg = newParams[0].ToCFXWideString(pRuntime->GetIsolate());
+      swMsg = newParams[0].ToCFXWideString(pRuntime);
     }
   } else {
-    swMsg = newParams[0].ToCFXWideString(pRuntime->GetIsolate());
+    swMsg = newParams[0].ToCFXWideString(pRuntime);
   }
 
   int iIcon = 0;
   if (newParams[1].GetType() != CJS_Value::VT_unknown)
-    iIcon = newParams[1].ToInt(pRuntime->GetIsolate());
+    iIcon = newParams[1].ToInt(pRuntime);
 
   int iType = 0;
   if (newParams[2].GetType() != CJS_Value::VT_unknown)
-    iType = newParams[2].ToInt(pRuntime->GetIsolate());
+    iType = newParams[2].ToInt(pRuntime);
 
   CFX_WideString swTitle;
   if (newParams[3].GetType() != CJS_Value::VT_unknown)
-    swTitle = newParams[3].ToCFXWideString(pRuntime->GetIsolate());
+    swTitle = newParams[3].ToCFXWideString(pRuntime);
   else
     swTitle = JSGetStringFromID(pContext, IDS_STRING_JSALERT);
 
@@ -461,7 +461,7 @@
     CJS_Context* pContext = (CJS_Context*)cc;
     CJS_Runtime* pRuntime = pContext->GetJSRuntime();
     CPDFDoc_Environment* pEnv = pRuntime->GetReaderApp();
-    pEnv->JS_appBeep(params[0].ToInt(pRuntime->GetIsolate()));
+    pEnv->JS_appBeep(params[0].ToInt(pRuntime));
     return TRUE;
   }
 
@@ -500,23 +500,21 @@
   }
 
   CFX_WideString script =
-      params.size() > 0 ? params[0].ToCFXWideString(pRuntime->GetIsolate())
-                        : L"";
+      params.size() > 0 ? params[0].ToCFXWideString(pRuntime) : L"";
   if (script.IsEmpty()) {
     sError = JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE);
     return TRUE;
   }
 
-  uint32_t dwInterval =
-      params.size() > 1 ? params[1].ToInt(pRuntime->GetIsolate()) : 1000;
+  uint32_t dwInterval = params.size() > 1 ? params[1].ToInt(pRuntime) : 1000;
   CPDFDoc_Environment* pApp = pRuntime->GetReaderApp();
   m_Timers.push_back(std::unique_ptr<GlobalTimer>(
       new GlobalTimer(this, pApp, pRuntime, 0, script, dwInterval, 0)));
 
-  v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj(
-      pRuntime->GetIsolate(), pRuntime, CJS_TimerObj::g_nObjDefnID);
-  CJS_TimerObj* pJS_TimerObj = static_cast<CJS_TimerObj*>(
-      FXJS_GetPrivate(pRuntime->GetIsolate(), pRetObj));
+  v8::Local<v8::Object> pRetObj =
+      pRuntime->NewFxDynamicObj(CJS_TimerObj::g_nObjDefnID);
+  CJS_TimerObj* pJS_TimerObj =
+      static_cast<CJS_TimerObj*>(pRuntime->GetObjectPrivate(pRetObj));
   TimerObj* pTimerObj = static_cast<TimerObj*>(pJS_TimerObj->GetEmbedObject());
   pTimerObj->SetTimer(m_Timers.back().get());
 
@@ -536,23 +534,22 @@
     return FALSE;
   }
 
-  CFX_WideString script = params[0].ToCFXWideString(pRuntime->GetIsolate());
+  CFX_WideString script = params[0].ToCFXWideString(pRuntime);
   if (script.IsEmpty()) {
     sError = JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE);
     return TRUE;
   }
 
-  uint32_t dwTimeOut =
-      params.size() > 1 ? params[1].ToInt(pRuntime->GetIsolate()) : 1000;
+  uint32_t dwTimeOut = params.size() > 1 ? params[1].ToInt(pRuntime) : 1000;
   CPDFDoc_Environment* pApp = pRuntime->GetReaderApp();
   m_Timers.push_back(std::unique_ptr<GlobalTimer>(
       new GlobalTimer(this, pApp, pRuntime, 1, script, dwTimeOut, dwTimeOut)));
 
-  v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj(
-      pRuntime->GetIsolate(), pRuntime, CJS_TimerObj::g_nObjDefnID);
+  v8::Local<v8::Object> pRetObj =
+      pRuntime->NewFxDynamicObj(CJS_TimerObj::g_nObjDefnID);
 
-  CJS_TimerObj* pJS_TimerObj = static_cast<CJS_TimerObj*>(
-      FXJS_GetPrivate(pRuntime->GetIsolate(), pRetObj));
+  CJS_TimerObj* pJS_TimerObj =
+      static_cast<CJS_TimerObj*>(pRuntime->GetObjectPrivate(pRetObj));
 
   TimerObj* pTimerObj = static_cast<TimerObj*>(pJS_TimerObj->GetEmbedObject());
   pTimerObj->SetTimer(m_Timers.back().get());
@@ -571,7 +568,7 @@
     return FALSE;
   }
 
-  app::ClearTimerCommon(params[0]);
+  app::ClearTimerCommon(pContext->GetJSRuntime(), params[0]);
   return TRUE;
 }
 
@@ -585,19 +582,19 @@
     return FALSE;
   }
 
-  app::ClearTimerCommon(params[0]);
+  app::ClearTimerCommon(pContext->GetJSRuntime(), params[0]);
   return TRUE;
 }
 
-void app::ClearTimerCommon(const CJS_Value& param) {
+void app::ClearTimerCommon(CJS_Runtime* pRuntime, const CJS_Value& param) {
   if (param.GetType() != CJS_Value::VT_object)
     return;
 
-  v8::Local<v8::Object> pObj = param.ToV8Object(GetJSObject()->GetIsolate());
-  if (FXJS_GetObjDefnID(pObj) != CJS_TimerObj::g_nObjDefnID)
+  v8::Local<v8::Object> pObj = param.ToV8Object(pRuntime);
+  if (CFXJS_Engine::GetObjDefnID(pObj) != CJS_TimerObj::g_nObjDefnID)
     return;
 
-  CJS_Object* pJSObj = param.ToCJSObject(GetJSObject()->GetIsolate());
+  CJS_Object* pJSObj = param.ToCJSObject(pRuntime);
   if (!pJSObj)
     return;
 
@@ -671,11 +668,11 @@
     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
     return FALSE;
   }
-  bool bUI = newParams[0].ToBool(pRuntime->GetIsolate());
+  bool bUI = newParams[0].ToBool(pRuntime);
 
   CFX_WideString cTo;
   if (newParams[1].GetType() != CJS_Value::VT_unknown) {
-    cTo = newParams[1].ToCFXWideString(pRuntime->GetIsolate());
+    cTo = newParams[1].ToCFXWideString(pRuntime);
   } else {
     if (!bUI) {
       // cTo parameter required when UI not invoked.
@@ -686,19 +683,19 @@
 
   CFX_WideString cCc;
   if (newParams[2].GetType() != CJS_Value::VT_unknown)
-    cCc = newParams[2].ToCFXWideString(pRuntime->GetIsolate());
+    cCc = newParams[2].ToCFXWideString(pRuntime);
 
   CFX_WideString cBcc;
   if (newParams[3].GetType() != CJS_Value::VT_unknown)
-    cBcc = newParams[3].ToCFXWideString(pRuntime->GetIsolate());
+    cBcc = newParams[3].ToCFXWideString(pRuntime);
 
   CFX_WideString cSubject;
   if (newParams[4].GetType() != CJS_Value::VT_unknown)
-    cSubject = newParams[4].ToCFXWideString(pRuntime->GetIsolate());
+    cSubject = newParams[4].ToCFXWideString(pRuntime);
 
   CFX_WideString cMsg;
   if (newParams[5].GetType() != CJS_Value::VT_unknown)
-    cMsg = newParams[5].ToCFXWideString(pRuntime->GetIsolate());
+    cMsg = newParams[5].ToCFXWideString(pRuntime);
 
   pRuntime->BeginBlock();
   pContext->GetReaderApp()->JS_docmailForm(nullptr, 0, bUI, cTo.c_str(),
@@ -794,24 +791,23 @@
     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
     return FALSE;
   }
-  CFX_WideString swQuestion =
-      newParams[0].ToCFXWideString(pRuntime->GetIsolate());
+  CFX_WideString swQuestion = newParams[0].ToCFXWideString(pRuntime);
 
   CFX_WideString swTitle = L"PDF";
   if (newParams[1].GetType() != CJS_Value::VT_unknown)
-    swTitle = newParams[1].ToCFXWideString(pRuntime->GetIsolate());
+    swTitle = newParams[1].ToCFXWideString(pRuntime);
 
   CFX_WideString swDefault;
   if (newParams[2].GetType() != CJS_Value::VT_unknown)
-    swDefault = newParams[2].ToCFXWideString(pRuntime->GetIsolate());
+    swDefault = newParams[2].ToCFXWideString(pRuntime);
 
   bool bPassword = false;
   if (newParams[3].GetType() != CJS_Value::VT_unknown)
-    bPassword = newParams[3].ToBool(pRuntime->GetIsolate());
+    bPassword = newParams[3].ToBool(pRuntime);
 
   CFX_WideString swLabel;
   if (newParams[4].GetType() != CJS_Value::VT_unknown)
-    swLabel = newParams[4].ToCFXWideString(pRuntime->GetIsolate());
+    swLabel = newParams[4].ToCFXWideString(pRuntime);
 
   const int MAX_INPUT_BYTES = 2048;
   std::unique_ptr<char[]> pBuff(new char[MAX_INPUT_BYTES + 2]);
diff --git a/fpdfsdk/javascript/app.h b/fpdfsdk/javascript/app.h
index 52dfd2f..97db59e 100644
--- a/fpdfsdk/javascript/app.h
+++ b/fpdfsdk/javascript/app.h
@@ -161,7 +161,7 @@
   // CJS_EmbedObj
   void RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript);
 
-  void ClearTimerCommon(const CJS_Value& param);
+  void ClearTimerCommon(CJS_Runtime* pRuntime, const CJS_Value& param);
 
   bool m_bCalculate;
   bool m_bRuntimeHighLight;
diff --git a/fpdfsdk/javascript/cjs_context.cpp b/fpdfsdk/javascript/cjs_context.cpp
index 06abf7f..c37fdab 100644
--- a/fpdfsdk/javascript/cjs_context.cpp
+++ b/fpdfsdk/javascript/cjs_context.cpp
@@ -29,7 +29,7 @@
                                CFX_WideString* info) {
   v8::Isolate::Scope isolate_scope(m_pRuntime->GetIsolate());
   v8::HandleScope handle_scope(m_pRuntime->GetIsolate());
-  v8::Local<v8::Context> context = m_pRuntime->NewJSContext();
+  v8::Local<v8::Context> context = m_pRuntime->NewLocalContext();
   v8::Context::Scope context_scope(context);
 
   if (m_bBusy) {
@@ -49,7 +49,7 @@
   CFX_WideString sErrorMessage;
   int nRet = 0;
   if (script.GetLength() > 0) {
-    nRet = m_pRuntime->Execute(script.c_str(), &sErrorMessage);
+    nRet = m_pRuntime->ExecuteScript(script.c_str(), &sErrorMessage);
   }
 
   if (nRet < 0) {
diff --git a/fpdfsdk/javascript/cjs_runtime.cpp b/fpdfsdk/javascript/cjs_runtime.cpp
index 36d888a..7ea9b15 100644
--- a/fpdfsdk/javascript/cjs_runtime.cpp
+++ b/fpdfsdk/javascript/cjs_runtime.cpp
@@ -55,11 +55,18 @@
   return pContext->GetJSRuntime();
 }
 
+// static
+CJS_Runtime* CJS_Runtime::CurrentRuntimeFromIsolate(v8::Isolate* pIsolate) {
+  return static_cast<CJS_Runtime*>(
+      CFXJS_Engine::CurrentEngineFromIsolate(pIsolate));
+}
+
 CJS_Runtime::CJS_Runtime(CPDFDoc_Environment* pApp)
     : m_pApp(pApp),
       m_pDocument(nullptr),
       m_bBlocking(false),
       m_isolateManaged(false) {
+  v8::Isolate* pIsolate = nullptr;
 #ifndef PDF_ENABLE_XFA
   IPDF_JSPLATFORM* pPlatform = m_pApp->GetFormFillInfo()->m_pJsPlatform;
   if (pPlatform->version <= 2) {
@@ -71,11 +78,13 @@
     }
     FXJS_Initialize(embedderDataSlot, pExternalIsolate);
   }
-  m_isolateManaged = FXJS_GetIsolate(&m_isolate);
+  m_isolateManaged = FXJS_GetIsolate(&pIsolate);
+  SetIsolate(pIsolate);
 #else
   if (CPDFXFA_App::GetInstance()->GetJSERuntime()) {
     // TODO(tsepez): CPDFXFA_App should also use the embedder provided isolate.
-    m_isolate = (v8::Isolate*)CPDFXFA_App::GetInstance()->GetJSERuntime();
+    pIsolate = CPDFXFA_App::GetInstance()->GetJSERuntime();
+    SetIsolate(pIsolate);
   } else {
     IPDF_JSPLATFORM* pPlatform = m_pApp->GetFormFillInfo()->m_pJsPlatform;
     if (pPlatform->version <= 2) {
@@ -87,15 +96,15 @@
       }
       FXJS_Initialize(embedderDataSlot, pExternalIsolate);
     }
-    m_isolateManaged = FXJS_GetIsolate(&m_isolate);
+    m_isolateManaged = FXJS_GetIsolate(&pIsolate);
+    SetIsolate(pIsolate);
   }
 
-  v8::Isolate* isolate = m_isolate;
-  v8::Isolate::Scope isolate_scope(isolate);
-  v8::HandleScope handle_scope(isolate);
+  v8::Isolate::Scope isolate_scope(pIsolate);
+  v8::HandleScope handle_scope(pIsolate);
   if (CPDFXFA_App::GetInstance()->IsJavaScriptInitialized()) {
     CJS_Context* pContext = (CJS_Context*)NewContext();
-    FXJS_InitializeEngine(GetIsolate(), this, &m_context, &m_StaticObjects);
+    InitializeEngine();
     ReleaseContext(pContext);
     return;
   }
@@ -109,7 +118,7 @@
 #endif
 
   CJS_Context* pContext = (CJS_Context*)NewContext();
-  FXJS_InitializeEngine(GetIsolate(), this, &m_context, &m_StaticObjects);
+  InitializeEngine();
   ReleaseContext(pContext);
 }
 
@@ -117,12 +126,11 @@
   for (auto* obs : m_observers)
     obs->OnDestroyed();
 
-  m_ContextArray.clear();
-  m_ConstArrays.clear();
-  FXJS_ReleaseEngine(GetIsolate(), &m_context, &m_StaticObjects);
-  m_context.Reset();
-  if (m_isolateManaged)
-    m_isolate->Dispose();
+  ReleaseEngine();
+  if (m_isolateManaged) {
+    GetIsolate()->Dispose();
+    SetIsolate(nullptr);
+  }
 }
 
 void CJS_Runtime::DefineJSObjects() {
@@ -133,43 +141,43 @@
 
   // The call order determines the "ObjDefID" assigned to each class.
   // ObjDefIDs 0 - 2
-  CJS_Border::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
-  CJS_Display::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
-  CJS_Font::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
+  CJS_Border::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
+  CJS_Display::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
+  CJS_Font::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
 
   // ObjDefIDs 3 - 5
-  CJS_Highlight::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
-  CJS_Position::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
-  CJS_ScaleHow::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
+  CJS_Highlight::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
+  CJS_Position::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
+  CJS_ScaleHow::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
 
   // ObjDefIDs 6 - 8
-  CJS_ScaleWhen::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
-  CJS_Style::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
-  CJS_Zoomtype::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
+  CJS_ScaleWhen::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
+  CJS_Style::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
+  CJS_Zoomtype::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
 
   // ObjDefIDs 9 - 11
-  CJS_App::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
-  CJS_Color::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
-  CJS_Console::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
+  CJS_App::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
+  CJS_Color::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
+  CJS_Console::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
 
   // ObjDefIDs 12 - 14
-  CJS_Document::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_GLOBAL);
-  CJS_Event::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
-  CJS_Field::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC);
+  CJS_Document::DefineJSObjects(this, FXJSOBJTYPE_GLOBAL);
+  CJS_Event::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
+  CJS_Field::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
 
   // ObjDefIDs 15 - 17
-  CJS_Global::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
-  CJS_Icon::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC);
-  CJS_Util::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
+  CJS_Global::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
+  CJS_Icon::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
+  CJS_Util::DefineJSObjects(this, FXJSOBJTYPE_STATIC);
 
   // ObjDefIDs 18 - 20 (these can't fail, return void).
-  CJS_PublicMethods::DefineJSObjects(GetIsolate());
+  CJS_PublicMethods::DefineJSObjects(this);
   CJS_GlobalConsts::DefineJSObjects(this);
   CJS_GlobalArrays::DefineJSObjects(this);
 
   // ObjDefIDs 21 - 22.
-  CJS_TimerObj::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC);
-  CJS_PrintParamsObj::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC);
+  CJS_TimerObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
+  CJS_PrintParamsObj::DefineJSObjects(this, FXJSOBJTYPE_DYNAMIC);
 }
 
 IJS_Context* CJS_Runtime::NewContext() {
@@ -191,36 +199,45 @@
 }
 
 void CJS_Runtime::SetReaderDocument(CPDFSDK_Document* pReaderDoc) {
-  if (m_pDocument != pReaderDoc) {
-    v8::Isolate::Scope isolate_scope(m_isolate);
-    v8::HandleScope handle_scope(m_isolate);
-    v8::Local<v8::Context> context =
-        v8::Local<v8::Context>::New(m_isolate, m_context);
-    v8::Context::Scope context_scope(context);
+  if (m_pDocument == pReaderDoc)
+    return;
 
-    m_pDocument = pReaderDoc;
-    if (pReaderDoc) {
-      v8::Local<v8::Object> pThis = FXJS_GetThisObj(GetIsolate());
-      if (!pThis.IsEmpty()) {
-        if (FXJS_GetObjDefnID(pThis) == CJS_Document::g_nObjDefnID) {
-          if (CJS_Document* pJSDocument =
-                  (CJS_Document*)FXJS_GetPrivate(GetIsolate(), pThis)) {
-            if (Document* pDocument = (Document*)pJSDocument->GetEmbedObject())
-              pDocument->AttachDoc(pReaderDoc);
-          }
-        }
-      }
-    }
-  }
+  v8::Isolate::Scope isolate_scope(GetIsolate());
+  v8::HandleScope handle_scope(GetIsolate());
+  v8::Local<v8::Context> context = NewLocalContext();
+  v8::Context::Scope context_scope(context);
+
+  m_pDocument = pReaderDoc;
+  if (!pReaderDoc)
+    return;
+
+  v8::Local<v8::Object> pThis = GetThisObj();
+  if (pThis.IsEmpty())
+    return;
+
+  if (CFXJS_Engine::GetObjDefnID(pThis) != CJS_Document::g_nObjDefnID)
+    return;
+
+  CJS_Document* pJSDocument =
+      static_cast<CJS_Document*>(GetObjectPrivate(pThis));
+  if (!pJSDocument)
+    return;
+
+  Document* pDocument = static_cast<Document*>(pJSDocument->GetEmbedObject());
+  if (!pDocument)
+    return;
+
+  pDocument->AttachDoc(pReaderDoc);
 }
 
 CPDFSDK_Document* CJS_Runtime::GetReaderDocument() {
   return m_pDocument;
 }
 
-int CJS_Runtime::Execute(const CFX_WideString& script, CFX_WideString* info) {
+int CJS_Runtime::ExecuteScript(const CFX_WideString& script,
+                               CFX_WideString* info) {
   FXJSErr error = {};
-  int nRet = FXJS_Execute(m_isolate, script, &error);
+  int nRet = Execute(script, &error);
   if (nRet < 0) {
     info->Format(L"[ Line: %05d { %s } ] : %s", error.linnum - 1, error.srcline,
                  error.message);
@@ -236,19 +253,6 @@
   m_FieldEventSet.erase(event);
 }
 
-v8::Local<v8::Context> CJS_Runtime::NewJSContext() {
-  return v8::Local<v8::Context>::New(m_isolate, m_context);
-}
-
-void CJS_Runtime::SetConstArray(const CFX_WideString& name,
-                                v8::Local<v8::Array> array) {
-  m_ConstArrays[name] = v8::Global<v8::Array>(m_isolate, array);
-}
-
-v8::Local<v8::Array> CJS_Runtime::GetConstArray(const CFX_WideString& name) {
-  return v8::Local<v8::Array>::New(m_isolate, m_ConstArrays[name]);
-}
-
 void CJS_Runtime::AddObserver(Observer* observer) {
   ASSERT(!pdfium::ContainsKey(m_observers, observer));
   m_observers.insert(observer);
@@ -272,8 +276,7 @@
   v8::Isolate::Scope isolate_scope(GetIsolate());
   v8::HandleScope handle_scope(GetIsolate());
   v8::Local<v8::Context> old_context = GetIsolate()->GetCurrentContext();
-  v8::Local<v8::Context> context =
-      v8::Local<v8::Context>::New(GetIsolate(), m_context);
+  v8::Local<v8::Context> context = NewLocalContext();
   v8::Context::Scope context_scope(context);
 
   // Caution: We're about to hand to XFA an object that in order to invoke
@@ -283,7 +286,7 @@
   // Do so now.
   // TODO(tsepez): redesign PDF-side objects to not rely on v8::Context's
   // embedder data slots, and/or to always use the right context.
-  FXJS_SetEngineForV8Context(old_context, this);
+  CFXJS_Engine::SetForV8Context(old_context, this);
 
   v8::Local<v8::Value> propvalue =
       context->Global()->Get(v8::String::NewFromUtf8(
@@ -304,8 +307,7 @@
   v8::Isolate* pIsolate = GetIsolate();
   v8::Isolate::Scope isolate_scope(pIsolate);
   v8::HandleScope handle_scope(pIsolate);
-  v8::Local<v8::Context> context =
-      v8::Local<v8::Context>::New(pIsolate, m_context);
+  v8::Local<v8::Context> context = NewLocalContext();
   v8::Context::Scope context_scope(context);
 
   // v8::Local<v8::Context> tmpCotext =
diff --git a/fpdfsdk/javascript/cjs_runtime.h b/fpdfsdk/javascript/cjs_runtime.h
index 16432d5..33d2956 100644
--- a/fpdfsdk/javascript/cjs_runtime.h
+++ b/fpdfsdk/javascript/cjs_runtime.h
@@ -33,6 +33,7 @@
   using FieldEvent = std::pair<CFX_WideString, JS_EVENT_T>;
 
   static CJS_Runtime* FromContext(const IJS_Context* cc);
+  static CJS_Runtime* CurrentRuntimeFromIsolate(v8::Isolate* pIsolate);
 
   explicit CJS_Runtime(CPDFDoc_Environment* pApp);
   ~CJS_Runtime() override;
@@ -43,7 +44,8 @@
   IJS_Context* GetCurrentContext() override;
   void SetReaderDocument(CPDFSDK_Document* pReaderDoc) override;
   CPDFSDK_Document* GetReaderDocument() override;
-  int Execute(const CFX_WideString& script, CFX_WideString* info) override;
+  int ExecuteScript(const CFX_WideString& script,
+                    CFX_WideString* info) override;
 
   CPDFDoc_Environment* GetReaderApp() const { return m_pApp; }
 
@@ -55,12 +57,6 @@
   void EndBlock() { m_bBlocking = FALSE; }
   FX_BOOL IsBlocking() const { return m_bBlocking; }
 
-  v8::Isolate* GetIsolate() const { return m_isolate; }
-  v8::Local<v8::Context> NewJSContext();
-
-  void SetConstArray(const CFX_WideString& name, v8::Local<v8::Array> array);
-  v8::Local<v8::Array> GetConstArray(const CFX_WideString& name);
-
 #ifdef PDF_ENABLE_XFA
   FX_BOOL GetValueByName(const CFX_ByteStringC& utf8Name,
                          CFXJSE_Value* pValue) override;
diff --git a/fpdfsdk/javascript/color.cpp b/fpdfsdk/javascript/color.cpp
index 949c429..f77d548 100644
--- a/fpdfsdk/javascript/color.cpp
+++ b/fpdfsdk/javascript/color.cpp
@@ -62,32 +62,24 @@
                                    CJS_Array* array) {
   switch (color.nColorType) {
     case COLORTYPE_TRANSPARENT:
-      array->SetElement(pRuntime->GetIsolate(), 0, CJS_Value(pRuntime, "T"));
+      array->SetElement(pRuntime, 0, CJS_Value(pRuntime, "T"));
       break;
     case COLORTYPE_GRAY:
-      array->SetElement(pRuntime->GetIsolate(), 0, CJS_Value(pRuntime, "G"));
-      array->SetElement(pRuntime->GetIsolate(), 1,
-                        CJS_Value(pRuntime, color.fColor1));
+      array->SetElement(pRuntime, 0, CJS_Value(pRuntime, "G"));
+      array->SetElement(pRuntime, 1, CJS_Value(pRuntime, color.fColor1));
       break;
     case COLORTYPE_RGB:
-      array->SetElement(pRuntime->GetIsolate(), 0, CJS_Value(pRuntime, "RGB"));
-      array->SetElement(pRuntime->GetIsolate(), 1,
-                        CJS_Value(pRuntime, color.fColor1));
-      array->SetElement(pRuntime->GetIsolate(), 2,
-                        CJS_Value(pRuntime, color.fColor2));
-      array->SetElement(pRuntime->GetIsolate(), 3,
-                        CJS_Value(pRuntime, color.fColor3));
+      array->SetElement(pRuntime, 0, CJS_Value(pRuntime, "RGB"));
+      array->SetElement(pRuntime, 1, CJS_Value(pRuntime, color.fColor1));
+      array->SetElement(pRuntime, 2, CJS_Value(pRuntime, color.fColor2));
+      array->SetElement(pRuntime, 3, CJS_Value(pRuntime, color.fColor3));
       break;
     case COLORTYPE_CMYK:
-      array->SetElement(pRuntime->GetIsolate(), 0, CJS_Value(pRuntime, "CMYK"));
-      array->SetElement(pRuntime->GetIsolate(), 1,
-                        CJS_Value(pRuntime, color.fColor1));
-      array->SetElement(pRuntime->GetIsolate(), 2,
-                        CJS_Value(pRuntime, color.fColor2));
-      array->SetElement(pRuntime->GetIsolate(), 3,
-                        CJS_Value(pRuntime, color.fColor3));
-      array->SetElement(pRuntime->GetIsolate(), 4,
-                        CJS_Value(pRuntime, color.fColor4));
+      array->SetElement(pRuntime, 0, CJS_Value(pRuntime, "CMYK"));
+      array->SetElement(pRuntime, 1, CJS_Value(pRuntime, color.fColor1));
+      array->SetElement(pRuntime, 2, CJS_Value(pRuntime, color.fColor2));
+      array->SetElement(pRuntime, 3, CJS_Value(pRuntime, color.fColor3));
+      array->SetElement(pRuntime, 4, CJS_Value(pRuntime, color.fColor4));
       break;
   }
 }
@@ -95,13 +87,13 @@
 void color::ConvertArrayToPWLColor(CJS_Runtime* pRuntime,
                                    const CJS_Array& array,
                                    CPWL_Color* color) {
-  int nArrayLen = array.GetLength();
+  int nArrayLen = array.GetLength(pRuntime);
   if (nArrayLen < 1)
     return;
 
   CJS_Value value(pRuntime);
-  array.GetElement(pRuntime->GetIsolate(), 0, value);
-  CFX_ByteString sSpace = value.ToCFXByteString(pRuntime->GetIsolate());
+  array.GetElement(pRuntime, 0, value);
+  CFX_ByteString sSpace = value.ToCFXByteString(pRuntime);
 
   double d1 = 0;
   double d2 = 0;
@@ -109,23 +101,23 @@
   double d4 = 0;
 
   if (nArrayLen > 1) {
-    array.GetElement(pRuntime->GetIsolate(), 1, value);
-    d1 = value.ToDouble(pRuntime->GetIsolate());
+    array.GetElement(pRuntime, 1, value);
+    d1 = value.ToDouble(pRuntime);
   }
 
   if (nArrayLen > 2) {
-    array.GetElement(pRuntime->GetIsolate(), 2, value);
-    d2 = value.ToDouble(pRuntime->GetIsolate());
+    array.GetElement(pRuntime, 2, value);
+    d2 = value.ToDouble(pRuntime);
   }
 
   if (nArrayLen > 3) {
-    array.GetElement(pRuntime->GetIsolate(), 3, value);
-    d3 = value.ToDouble(pRuntime->GetIsolate());
+    array.GetElement(pRuntime, 3, value);
+    d3 = value.ToDouble(pRuntime);
   }
 
   if (nArrayLen > 4) {
-    array.GetElement(pRuntime->GetIsolate(), 4, value);
-    d4 = value.ToDouble(pRuntime->GetIsolate());
+    array.GetElement(pRuntime, 4, value);
+    d4 = value.ToDouble(pRuntime);
   }
 
   if (sSpace == "T") {
@@ -141,20 +133,20 @@
   }
 }
 
-#define JS_IMPLEMENT_COLORPROP(prop, var)                                  \
-  FX_BOOL color::prop(IJS_Context* cc, CJS_PropValue& vp,                  \
-                      CFX_WideString& sError) {                            \
-    CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);                  \
-    CJS_Array array;                                                       \
-    if (vp.IsGetting()) {                                                  \
-      ConvertPWLColorToArray(pRuntime, var, &array);                       \
-      vp << array;                                                         \
-    } else {                                                               \
-      if (!vp.GetJSValue()->ConvertToArray(pRuntime->GetIsolate(), array)) \
-        return FALSE;                                                      \
-      ConvertArrayToPWLColor(pRuntime, array, &var);                       \
-    }                                                                      \
-    return TRUE;                                                           \
+#define JS_IMPLEMENT_COLORPROP(prop, var)                    \
+  FX_BOOL color::prop(IJS_Context* cc, CJS_PropValue& vp,    \
+                      CFX_WideString& sError) {              \
+    CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);    \
+    CJS_Array array;                                         \
+    if (vp.IsGetting()) {                                    \
+      ConvertPWLColorToArray(pRuntime, var, &array);         \
+      vp << array;                                           \
+    } else {                                                 \
+      if (!vp.GetJSValue()->ConvertToArray(pRuntime, array)) \
+        return FALSE;                                        \
+      ConvertArrayToPWLColor(pRuntime, array, &var);         \
+    }                                                        \
+    return TRUE;                                             \
   }
 
 JS_IMPLEMENT_COLORPROP(transparent, m_crTransparent)
@@ -180,13 +172,13 @@
 
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CJS_Array aSource;
-  if (!params[0].ConvertToArray(pRuntime->GetIsolate(), aSource))
+  if (!params[0].ConvertToArray(pRuntime, aSource))
     return FALSE;
 
   CPWL_Color crSource;
   ConvertArrayToPWLColor(pRuntime, aSource, &crSource);
 
-  CFX_ByteString sDestSpace = params[1].ToCFXByteString(pRuntime->GetIsolate());
+  CFX_ByteString sDestSpace = params[1].ToCFXByteString(pRuntime);
   int nColorType = COLORTYPE_TRANSPARENT;
 
   if (sDestSpace == "T") {
@@ -218,9 +210,9 @@
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
   CJS_Array array1;
   CJS_Array array2;
-  if (!params[0].ConvertToArray(pRuntime->GetIsolate(), array1))
+  if (!params[0].ConvertToArray(pRuntime, array1))
     return FALSE;
-  if (!params[1].ConvertToArray(pRuntime->GetIsolate(), array2))
+  if (!params[1].ConvertToArray(pRuntime, array2))
     return FALSE;
 
   CPWL_Color color1;
diff --git a/fpdfsdk/javascript/global.cpp b/fpdfsdk/javascript/global.cpp
index 5ffc559..27c156e 100644
--- a/fpdfsdk/javascript/global.cpp
+++ b/fpdfsdk/javascript/global.cpp
@@ -168,11 +168,11 @@
     return FALSE;
   }
 
-  auto it = m_mapGlobal.find(params[0].ToCFXByteString(pRuntime->GetIsolate()));
+  auto it = m_mapGlobal.find(params[0].ToCFXByteString(pRuntime));
   if (it != m_mapGlobal.end()) {
     JSGlobalData* pData = it->second;
     if (!pData->bDeleted) {
-      pData->bPersistent = params[1].ToBool(pRuntime->GetIsolate());
+      pData->bPersistent = params[1].ToBool(pRuntime);
       return TRUE;
     }
   }
@@ -182,6 +182,10 @@
 }
 
 void JSGlobalAlternate::UpdateGlobalPersistentVariables() {
+  CJS_Runtime* pRuntime =
+      static_cast<CJS_Runtime*>(CFXJS_Engine::CurrentEngineFromIsolate(
+          m_pJSObject->ToV8Object()->GetIsolate()));
+
   for (int i = 0, sz = m_pGlobalData->GetSize(); i < sz; i++) {
     CJS_GlobalData_Element* pData = m_pGlobalData->GetAt(i);
     switch (pData->data.nType) {
@@ -189,43 +193,41 @@
         SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::NUMBER,
                            pData->data.dData, false, "",
                            v8::Local<v8::Object>(), pData->bPersistent == 1);
-        FXJS_PutObjectNumber(nullptr, m_pJSObject->ToV8Object(),
-                             pData->data.sKey.UTF8Decode(), pData->data.dData);
+        pRuntime->PutObjectNumber(m_pJSObject->ToV8Object(),
+                                  pData->data.sKey.UTF8Decode(),
+                                  pData->data.dData);
         break;
       case JS_GlobalDataType::BOOLEAN:
         SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::BOOLEAN, 0,
                            (bool)(pData->data.bData == 1), "",
                            v8::Local<v8::Object>(), pData->bPersistent == 1);
-        FXJS_PutObjectBoolean(nullptr, m_pJSObject->ToV8Object(),
-                              pData->data.sKey.UTF8Decode(),
-                              (bool)(pData->data.bData == 1));
+        pRuntime->PutObjectBoolean(m_pJSObject->ToV8Object(),
+                                   pData->data.sKey.UTF8Decode(),
+                                   (bool)(pData->data.bData == 1));
         break;
       case JS_GlobalDataType::STRING:
         SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::STRING, 0,
                            false, pData->data.sData, v8::Local<v8::Object>(),
                            pData->bPersistent == 1);
-        FXJS_PutObjectString(nullptr, m_pJSObject->ToV8Object(),
-                             pData->data.sKey.UTF8Decode(),
-                             pData->data.sData.UTF8Decode());
+        pRuntime->PutObjectString(m_pJSObject->ToV8Object(),
+                                  pData->data.sKey.UTF8Decode(),
+                                  pData->data.sData.UTF8Decode());
         break;
       case JS_GlobalDataType::OBJECT: {
-        v8::Isolate* pRuntime = m_pJSObject->ToV8Object()->GetIsolate();
-        v8::Local<v8::Object> pObj =
-            FXJS_NewFxDynamicObj(pRuntime, nullptr, -1);
+        v8::Local<v8::Object> pObj = pRuntime->NewFxDynamicObj(-1);
 
         PutObjectProperty(pObj, &pData->data);
-
         SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::OBJECT, 0,
                            false, "", pObj, pData->bPersistent == 1);
-        FXJS_PutObjectObject(nullptr, m_pJSObject->ToV8Object(),
-                             pData->data.sKey.UTF8Decode(), pObj);
+        pRuntime->PutObjectObject(m_pJSObject->ToV8Object(),
+                                  pData->data.sKey.UTF8Decode(), pObj);
       } break;
       case JS_GlobalDataType::NULLOBJ:
         SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::NULLOBJ, 0,
                            false, "", v8::Local<v8::Object>(),
                            pData->bPersistent == 1);
-        FXJS_PutObjectNull(nullptr, m_pJSObject->ToV8Object(),
-                           pData->data.sKey.UTF8Decode());
+        pRuntime->PutObjectNull(m_pJSObject->ToV8Object(),
+                                pData->data.sKey.UTF8Decode());
         break;
     }
   }
@@ -271,31 +273,29 @@
 void JSGlobalAlternate::ObjectToArray(IJS_Context* cc,
                                       v8::Local<v8::Object> pObj,
                                       CJS_GlobalVariableArray& array) {
-  v8::Isolate* isolate = pObj->GetIsolate();
   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
-  std::vector<CFX_WideString> pKeyList =
-      FXJS_GetObjectPropertyNames(isolate, pObj);
+  std::vector<CFX_WideString> pKeyList = pRuntime->GetObjectPropertyNames(pObj);
   for (const auto& ws : pKeyList) {
     CFX_ByteString sKey = ws.UTF8Encode();
-    v8::Local<v8::Value> v = FXJS_GetObjectProperty(isolate, pObj, ws);
+    v8::Local<v8::Value> v = pRuntime->GetObjectProperty(pObj, ws);
     switch (CJS_Value::GetValueType(v)) {
       case CJS_Value::VT_number: {
         CJS_KeyValue* pObjElement = new CJS_KeyValue;
         pObjElement->nType = JS_GlobalDataType::NUMBER;
         pObjElement->sKey = sKey;
-        pObjElement->dData = FXJS_ToNumber(isolate, v);
+        pObjElement->dData = pRuntime->ToNumber(v);
         array.Add(pObjElement);
       } break;
       case CJS_Value::VT_boolean: {
         CJS_KeyValue* pObjElement = new CJS_KeyValue;
         pObjElement->nType = JS_GlobalDataType::BOOLEAN;
         pObjElement->sKey = sKey;
-        pObjElement->dData = FXJS_ToBoolean(isolate, v);
+        pObjElement->dData = pRuntime->ToBoolean(v);
         array.Add(pObjElement);
       } break;
       case CJS_Value::VT_string: {
         CFX_ByteString sValue =
-            CJS_Value(pRuntime, v).ToCFXByteString(pRuntime->GetIsolate());
+            CJS_Value(pRuntime, v).ToCFXByteString(pRuntime);
         CJS_KeyValue* pObjElement = new CJS_KeyValue;
         pObjElement->nType = JS_GlobalDataType::STRING;
         pObjElement->sKey = sKey;
@@ -306,7 +306,7 @@
         CJS_KeyValue* pObjElement = new CJS_KeyValue;
         pObjElement->nType = JS_GlobalDataType::OBJECT;
         pObjElement->sKey = sKey;
-        ObjectToArray(cc, FXJS_ToObject(isolate, v), pObjElement->objData);
+        ObjectToArray(cc, pRuntime->ToObject(v), pObjElement->objData);
         array.Add(pObjElement);
       } break;
       case CJS_Value::VT_null: {
@@ -323,31 +323,31 @@
 
 void JSGlobalAlternate::PutObjectProperty(v8::Local<v8::Object> pObj,
                                           CJS_KeyValue* pData) {
+  CJS_Runtime* pRuntime = CJS_Runtime::CurrentRuntimeFromIsolate(
+      m_pJSObject->ToV8Object()->GetIsolate());
+
   for (int i = 0, sz = pData->objData.Count(); i < sz; i++) {
     CJS_KeyValue* pObjData = pData->objData.GetAt(i);
     switch (pObjData->nType) {
       case JS_GlobalDataType::NUMBER:
-        FXJS_PutObjectNumber(nullptr, pObj, pObjData->sKey.UTF8Decode(),
-                             pObjData->dData);
+        pRuntime->PutObjectNumber(pObj, pObjData->sKey.UTF8Decode(),
+                                  pObjData->dData);
         break;
       case JS_GlobalDataType::BOOLEAN:
-        FXJS_PutObjectBoolean(nullptr, pObj, pObjData->sKey.UTF8Decode(),
-                              pObjData->bData == 1);
+        pRuntime->PutObjectBoolean(pObj, pObjData->sKey.UTF8Decode(),
+                                   pObjData->bData == 1);
         break;
       case JS_GlobalDataType::STRING:
-        FXJS_PutObjectString(nullptr, pObj, pObjData->sKey.UTF8Decode(),
-                             pObjData->sData.UTF8Decode());
+        pRuntime->PutObjectString(pObj, pObjData->sKey.UTF8Decode(),
+                                  pObjData->sData.UTF8Decode());
         break;
       case JS_GlobalDataType::OBJECT: {
-        v8::Isolate* pRuntime = m_pJSObject->ToV8Object()->GetIsolate();
-        v8::Local<v8::Object> pNewObj =
-            FXJS_NewFxDynamicObj(pRuntime, nullptr, -1);
+        v8::Local<v8::Object> pNewObj = pRuntime->NewFxDynamicObj(-1);
         PutObjectProperty(pNewObj, pObjData);
-        FXJS_PutObjectObject(nullptr, pObj, pObjData->sKey.UTF8Decode(),
-                             pNewObj);
+        pRuntime->PutObjectObject(pObj, pObjData->sKey.UTF8Decode(), pNewObj);
       } break;
       case JS_GlobalDataType::NULLOBJ:
-        FXJS_PutObjectNull(nullptr, pObj, pObjData->sKey.UTF8Decode());
+        pRuntime->PutObjectNull(pObj, pObjData->sKey.UTF8Decode());
         break;
     }
   }
diff --git a/fpdfsdk/javascript/ijs_runtime.h b/fpdfsdk/javascript/ijs_runtime.h
index cae465a..3dcfa37 100644
--- a/fpdfsdk/javascript/ijs_runtime.h
+++ b/fpdfsdk/javascript/ijs_runtime.h
@@ -31,7 +31,8 @@
   virtual IJS_Context* GetCurrentContext() = 0;
   virtual void SetReaderDocument(CPDFSDK_Document* pReaderDoc) = 0;
   virtual CPDFSDK_Document* GetReaderDocument() = 0;
-  virtual int Execute(const CFX_WideString& script, CFX_WideString* info) = 0;
+  virtual int ExecuteScript(const CFX_WideString& script,
+                            CFX_WideString* info) = 0;
 
 #ifdef PDF_ENABLE_XFA
   virtual FX_BOOL GetValueByName(const CFX_ByteStringC& utf8Name,
diff --git a/fpdfsdk/javascript/util.cpp b/fpdfsdk/javascript/util.cpp
index a68d96c..fa53a9e 100644
--- a/fpdfsdk/javascript/util.cpp
+++ b/fpdfsdk/javascript/util.cpp
@@ -122,8 +122,7 @@
   int iSize = params.size();
   if (iSize < 1)
     return FALSE;
-  std::wstring c_ConvChar(
-      params[0].ToCFXWideString(pRuntime->GetIsolate()).c_str());
+  std::wstring c_ConvChar(params[0].ToCFXWideString(pRuntime).c_str());
   std::vector<std::wstring> c_strConvers;
   int iOffset = 0;
   int iOffend = 0;
@@ -156,17 +155,15 @@
 
     switch (ParseDataType(&c_strFormat)) {
       case UTIL_INT:
-        strSegment.Format(c_strFormat.c_str(),
-                          params[iIndex].ToInt(pRuntime->GetIsolate()));
+        strSegment.Format(c_strFormat.c_str(), params[iIndex].ToInt(pRuntime));
         break;
       case UTIL_DOUBLE:
         strSegment.Format(c_strFormat.c_str(),
-                          params[iIndex].ToDouble(pRuntime->GetIsolate()));
+                          params[iIndex].ToDouble(pRuntime));
         break;
       case UTIL_STRING:
-        strSegment.Format(
-            c_strFormat.c_str(),
-            params[iIndex].ToCFXWideString(pRuntime->GetIsolate()).c_str());
+        strSegment.Format(c_strFormat.c_str(),
+                          params[iIndex].ToCFXWideString(pRuntime).c_str());
         break;
       default:
         strSegment.Format(L"%S", c_strFormat.c_str());
@@ -192,45 +189,38 @@
   CJS_Value p1 = params[0];
   CJS_Value p2 = params[1];
   CJS_Date jsDate;
-  if (!p2.ConvertToDate(pRuntime->GetIsolate(), jsDate)) {
+  if (!p2.ConvertToDate(pRuntime, jsDate)) {
     sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPRINT1);
     return FALSE;
   }
 
-  if (!jsDate.IsValidDate(pRuntime->GetIsolate())) {
+  if (!jsDate.IsValidDate(pRuntime)) {
     sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPRINT2);
     return FALSE;
   }
 
   if (p1.GetType() == CJS_Value::VT_number) {
     CFX_WideString swResult;
-    switch (p1.ToInt(pRuntime->GetIsolate())) {
+    switch (p1.ToInt(pRuntime)) {
       case 0:
-        swResult.Format(L"D:%04d%02d%02d%02d%02d%02d",
-                        jsDate.GetYear(pRuntime->GetIsolate()),
-                        jsDate.GetMonth(pRuntime->GetIsolate()) + 1,
-                        jsDate.GetDay(pRuntime->GetIsolate()),
-                        jsDate.GetHours(pRuntime->GetIsolate()),
-                        jsDate.GetMinutes(pRuntime->GetIsolate()),
-                        jsDate.GetSeconds(pRuntime->GetIsolate()));
+        swResult.Format(L"D:%04d%02d%02d%02d%02d%02d", jsDate.GetYear(pRuntime),
+                        jsDate.GetMonth(pRuntime) + 1, jsDate.GetDay(pRuntime),
+                        jsDate.GetHours(pRuntime), jsDate.GetMinutes(pRuntime),
+                        jsDate.GetSeconds(pRuntime));
         break;
       case 1:
         swResult.Format(L"%04d.%02d.%02d %02d:%02d:%02d",
-                        jsDate.GetYear(pRuntime->GetIsolate()),
-                        jsDate.GetMonth(pRuntime->GetIsolate()) + 1,
-                        jsDate.GetDay(pRuntime->GetIsolate()),
-                        jsDate.GetHours(pRuntime->GetIsolate()),
-                        jsDate.GetMinutes(pRuntime->GetIsolate()),
-                        jsDate.GetSeconds(pRuntime->GetIsolate()));
+                        jsDate.GetYear(pRuntime), jsDate.GetMonth(pRuntime) + 1,
+                        jsDate.GetDay(pRuntime), jsDate.GetHours(pRuntime),
+                        jsDate.GetMinutes(pRuntime),
+                        jsDate.GetSeconds(pRuntime));
         break;
       case 2:
         swResult.Format(L"%04d/%02d/%02d %02d:%02d:%02d",
-                        jsDate.GetYear(pRuntime->GetIsolate()),
-                        jsDate.GetMonth(pRuntime->GetIsolate()) + 1,
-                        jsDate.GetDay(pRuntime->GetIsolate()),
-                        jsDate.GetHours(pRuntime->GetIsolate()),
-                        jsDate.GetMinutes(pRuntime->GetIsolate()),
-                        jsDate.GetSeconds(pRuntime->GetIsolate()));
+                        jsDate.GetYear(pRuntime), jsDate.GetMonth(pRuntime) + 1,
+                        jsDate.GetDay(pRuntime), jsDate.GetHours(pRuntime),
+                        jsDate.GetMinutes(pRuntime),
+                        jsDate.GetSeconds(pRuntime));
         break;
       default:
         sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSVALUEERROR);
@@ -242,15 +232,14 @@
   }
 
   if (p1.GetType() == CJS_Value::VT_string) {
-    if (iSize > 2 && params[2].ToBool(pRuntime->GetIsolate())) {
+    if (iSize > 2 && params[2].ToBool(pRuntime)) {
       sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_NOTSUPPORT);
       return FALSE;  // currently, it doesn't support XFAPicture.
     }
 
     // Convert PDF-style format specifiers to wcsftime specifiers. Remove any
     // pre-existing %-directives before inserting our own.
-    std::basic_string<wchar_t> cFormat =
-        p1.ToCFXWideString(pRuntime->GetIsolate()).c_str();
+    std::basic_string<wchar_t> cFormat = p1.ToCFXWideString(pRuntime).c_str();
     cFormat.erase(std::remove(cFormat.begin(), cFormat.end(), '%'),
                   cFormat.end());
 
@@ -265,12 +254,12 @@
       }
     }
 
-    int iYear = jsDate.GetYear(pRuntime->GetIsolate());
-    int iMonth = jsDate.GetMonth(pRuntime->GetIsolate());
-    int iDay = jsDate.GetDay(pRuntime->GetIsolate());
-    int iHour = jsDate.GetHours(pRuntime->GetIsolate());
-    int iMin = jsDate.GetMinutes(pRuntime->GetIsolate());
-    int iSec = jsDate.GetSeconds(pRuntime->GetIsolate());
+    int iYear = jsDate.GetYear(pRuntime);
+    int iMonth = jsDate.GetMonth(pRuntime);
+    int iDay = jsDate.GetDay(pRuntime);
+    int iHour = jsDate.GetHours(pRuntime);
+    int iMin = jsDate.GetMinutes(pRuntime);
+    int iSec = jsDate.GetSeconds(pRuntime);
 
     TbConvertAdditional cTableAd[] = {
         {L"m", iMonth + 1}, {L"d", iDay},
@@ -330,10 +319,9 @@
     return FALSE;
   }
 
-  vRet = CJS_Value(pRuntime,
-                   printx(params[0].ToCFXWideString(pRuntime->GetIsolate()),
-                          params[1].ToCFXWideString(pRuntime->GetIsolate()))
-                       .c_str());
+  vRet = CJS_Value(pRuntime, printx(params[0].ToCFXWideString(pRuntime),
+                                    params[1].ToCFXWideString(pRuntime))
+                                 .c_str());
 
   return TRUE;
 }
@@ -448,15 +436,15 @@
   if (iSize < 2)
     return FALSE;
 
-  CFX_WideString sFormat = params[0].ToCFXWideString(pRuntime->GetIsolate());
-  CFX_WideString sDate = params[1].ToCFXWideString(pRuntime->GetIsolate());
+  CFX_WideString sFormat = params[0].ToCFXWideString(pRuntime);
+  CFX_WideString sDate = params[1].ToCFXWideString(pRuntime);
   double dDate = JS_GetDateTime();
   if (sDate.GetLength() > 0) {
     dDate = CJS_PublicMethods::MakeRegularDate(sDate, sFormat, nullptr);
   }
 
   if (!JS_PortIsNan(dDate)) {
-    vRet = CJS_Value(pRuntime, CJS_Date(pRuntime->GetIsolate(), dDate));
+    vRet = CJS_Value(pRuntime, CJS_Date(pRuntime, dDate));
   } else {
     vRet.SetNull(pRuntime);
   }
@@ -476,7 +464,7 @@
     return FALSE;
   }
 
-  int arg = params[0].ToInt(pRuntime->GetIsolate());
+  int arg = params[0].ToInt(pRuntime);
   if (arg < 0 || arg > 255) {
     sError = JSGetStringFromID(pContext, IDS_STRING_JSVALUEERROR);
     return FALSE;
diff --git a/fxjs/fxjs_v8.cpp b/fxjs/fxjs_v8.cpp
index 42fc021..53f2527 100644
--- a/fxjs/fxjs_v8.cpp
+++ b/fxjs/fxjs_v8.cpp
@@ -44,8 +44,8 @@
   CFXJS_ObjDefinition(v8::Isolate* isolate,
                       const wchar_t* sObjName,
                       FXJSOBJTYPE eObjType,
-                      FXJS_CONSTRUCTOR pConstructor,
-                      FXJS_DESTRUCTOR pDestructor)
+                      CFXJS_Engine::Constructor pConstructor,
+                      CFXJS_Engine::Destructor pDestructor)
       : m_ObjName(sObjName),
         m_ObjType(eObjType),
         m_pConstructor(pConstructor),
@@ -88,8 +88,8 @@
 
   const wchar_t* const m_ObjName;
   const FXJSOBJTYPE m_ObjType;
-  const FXJS_CONSTRUCTOR m_pConstructor;
-  const FXJS_DESTRUCTOR m_pDestructor;
+  const CFXJS_Engine::Constructor m_pConstructor;
+  const CFXJS_Engine::Destructor m_pDestructor;
 
   v8::Isolate* m_pIsolate;
   v8::Global<v8::FunctionTemplate> m_FunctionTemplate;
@@ -135,16 +135,16 @@
   v8::Local<v8::Object> obj = value.Get(isolate);
   if (obj.IsEmpty())
     return;
-  int id = FXJS_GetObjDefnID(obj);
+  CFXJS_Engine* pEngine = CFXJS_Engine::CurrentEngineFromIsolate(isolate);
+  int id = pEngine->GetObjDefnID(obj);
   if (id == -1)
     return;
-
   CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(isolate, id);
   if (!pObjDef)
     return;
   if (pObjDef->m_pDestructor)
-    pObjDef->m_pDestructor(obj);
-  FXJS_FreePrivate(obj);
+    pObjDef->m_pDestructor(pEngine, obj);
+  CFXJS_Engine::FreeObjectPrivate(obj);
 }
 
 V8TemplateMapTraits::MapType* V8TemplateMapTraits::MapFromWeakCallbackInfo(
@@ -223,145 +223,176 @@
 #endif  // PDF_ENABLE_XFA
 
 CFXJS_Engine::CFXJS_Engine() : m_isolate(nullptr) {}
-CFXJS_Engine::~CFXJS_Engine() {}
 
-int FXJS_DefineObj(v8::Isolate* pIsolate,
-                   const wchar_t* sObjName,
-                   FXJSOBJTYPE eObjType,
-                   FXJS_CONSTRUCTOR pConstructor,
-                   FXJS_DESTRUCTOR pDestructor) {
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope handle_scope(pIsolate);
+CFXJS_Engine::~CFXJS_Engine() {
+  m_V8PersistentContext.Reset();
+}
 
-  FXJS_PerIsolateData::SetUp(pIsolate);
+// static
+CFXJS_Engine* CFXJS_Engine::CurrentEngineFromIsolate(v8::Isolate* pIsolate) {
+  return static_cast<CFXJS_Engine*>(
+      pIsolate->GetCurrentContext()->GetAlignedPointerFromEmbedderData(
+          kPerContextDataIndex));
+}
+
+#ifdef PDF_ENABLE_XFA
+// static
+void CFXJS_Engine::SetForV8Context(v8::Local<v8::Context> v8Context,
+                                   CFXJS_Engine* pEngine) {
+  v8Context->SetAlignedPointerInEmbedderData(kPerContextDataIndex, pEngine);
+}
+#endif  // PDF_ENABLE_XFA
+
+// static
+int CFXJS_Engine::GetObjDefnID(v8::Local<v8::Object> pObj) {
+  if (pObj.IsEmpty() || !pObj->InternalFieldCount())
+    return -1;
+  CFXJS_PerObjectData* pPerObjectData = static_cast<CFXJS_PerObjectData*>(
+      pObj->GetAlignedPointerFromInternalField(0));
+  if (!pPerObjectData)
+    return -1;
+  return pPerObjectData->m_ObjDefID;
+}
+
+// static
+void CFXJS_Engine::FreeObjectPrivate(void* pPerObjectData) {
+  delete static_cast<CFXJS_PerObjectData*>(pPerObjectData);
+}
+
+// static
+void CFXJS_Engine::FreeObjectPrivate(v8::Local<v8::Object> pObj) {
+  if (pObj.IsEmpty() || !pObj->InternalFieldCount())
+    return;
+  FreeObjectPrivate(pObj->GetAlignedPointerFromInternalField(0));
+  pObj->SetAlignedPointerInInternalField(0, nullptr);
+}
+
+int CFXJS_Engine::DefineObj(const wchar_t* sObjName,
+                            FXJSOBJTYPE eObjType,
+                            CFXJS_Engine::Constructor pConstructor,
+                            CFXJS_Engine::Destructor pDestructor) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
+  FXJS_PerIsolateData::SetUp(m_isolate);
   CFXJS_ObjDefinition* pObjDef = new CFXJS_ObjDefinition(
-      pIsolate, sObjName, eObjType, pConstructor, pDestructor);
+      m_isolate, sObjName, eObjType, pConstructor, pDestructor);
   return pObjDef->AssignID();
 }
 
-void FXJS_DefineObjMethod(v8::Isolate* pIsolate,
-                          int nObjDefnID,
-                          const wchar_t* sMethodName,
-                          v8::FunctionCallback pMethodCall) {
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope handle_scope(pIsolate);
+void CFXJS_Engine::DefineObjMethod(int nObjDefnID,
+                                   const wchar_t* sMethodName,
+                                   v8::FunctionCallback pMethodCall) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
   CFX_ByteString bsMethodName = CFX_WideString(sMethodName).UTF8Encode();
   CFXJS_ObjDefinition* pObjDef =
-      CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID);
+      CFXJS_ObjDefinition::ForID(m_isolate, nObjDefnID);
   v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(
-      pIsolate, pMethodCall, v8::Local<v8::Value>(), pObjDef->GetSignature());
+      m_isolate, pMethodCall, v8::Local<v8::Value>(), pObjDef->GetSignature());
   fun->RemovePrototype();
   pObjDef->GetInstanceTemplate()->Set(
-      v8::String::NewFromUtf8(pIsolate, bsMethodName.c_str(),
+      v8::String::NewFromUtf8(m_isolate, bsMethodName.c_str(),
                               v8::NewStringType::kNormal)
           .ToLocalChecked(),
       fun, v8::ReadOnly);
 }
 
-void FXJS_DefineObjProperty(v8::Isolate* pIsolate,
-                            int nObjDefnID,
-                            const wchar_t* sPropName,
-                            v8::AccessorGetterCallback pPropGet,
-                            v8::AccessorSetterCallback pPropPut) {
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope handle_scope(pIsolate);
+void CFXJS_Engine::DefineObjProperty(int nObjDefnID,
+                                     const wchar_t* sPropName,
+                                     v8::AccessorGetterCallback pPropGet,
+                                     v8::AccessorSetterCallback pPropPut) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
   CFX_ByteString bsPropertyName = CFX_WideString(sPropName).UTF8Encode();
   CFXJS_ObjDefinition* pObjDef =
-      CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID);
+      CFXJS_ObjDefinition::ForID(m_isolate, nObjDefnID);
   pObjDef->GetInstanceTemplate()->SetAccessor(
-      v8::String::NewFromUtf8(pIsolate, bsPropertyName.c_str(),
+      v8::String::NewFromUtf8(m_isolate, bsPropertyName.c_str(),
                               v8::NewStringType::kNormal)
           .ToLocalChecked(),
       pPropGet, pPropPut);
 }
 
-void FXJS_DefineObjAllProperties(v8::Isolate* pIsolate,
-                                 int nObjDefnID,
-                                 v8::NamedPropertyQueryCallback pPropQurey,
-                                 v8::NamedPropertyGetterCallback pPropGet,
-                                 v8::NamedPropertySetterCallback pPropPut,
-                                 v8::NamedPropertyDeleterCallback pPropDel) {
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope handle_scope(pIsolate);
+void CFXJS_Engine::DefineObjAllProperties(
+    int nObjDefnID,
+    v8::NamedPropertyQueryCallback pPropQurey,
+    v8::NamedPropertyGetterCallback pPropGet,
+    v8::NamedPropertySetterCallback pPropPut,
+    v8::NamedPropertyDeleterCallback pPropDel) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
   CFXJS_ObjDefinition* pObjDef =
-      CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID);
+      CFXJS_ObjDefinition::ForID(m_isolate, nObjDefnID);
   pObjDef->GetInstanceTemplate()->SetNamedPropertyHandler(pPropGet, pPropPut,
                                                           pPropQurey, pPropDel);
 }
 
-void FXJS_DefineObjConst(v8::Isolate* pIsolate,
-                         int nObjDefnID,
-                         const wchar_t* sConstName,
-                         v8::Local<v8::Value> pDefault) {
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope handle_scope(pIsolate);
+void CFXJS_Engine::DefineObjConst(int nObjDefnID,
+                                  const wchar_t* sConstName,
+                                  v8::Local<v8::Value> pDefault) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
   CFX_ByteString bsConstName = CFX_WideString(sConstName).UTF8Encode();
   CFXJS_ObjDefinition* pObjDef =
-      CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID);
-  pObjDef->GetInstanceTemplate()->Set(pIsolate, bsConstName.c_str(), pDefault);
+      CFXJS_ObjDefinition::ForID(m_isolate, nObjDefnID);
+  pObjDef->GetInstanceTemplate()->Set(m_isolate, bsConstName.c_str(), pDefault);
 }
 
-void FXJS_DefineGlobalMethod(v8::Isolate* pIsolate,
-                             const wchar_t* sMethodName,
-                             v8::FunctionCallback pMethodCall) {
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope handle_scope(pIsolate);
+void CFXJS_Engine::DefineGlobalMethod(const wchar_t* sMethodName,
+                                      v8::FunctionCallback pMethodCall) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
   CFX_ByteString bsMethodName = CFX_WideString(sMethodName).UTF8Encode();
   v8::Local<v8::FunctionTemplate> fun =
-      v8::FunctionTemplate::New(pIsolate, pMethodCall);
+      v8::FunctionTemplate::New(m_isolate, pMethodCall);
   fun->RemovePrototype();
-  GetGlobalObjectTemplate(pIsolate)->Set(
-      v8::String::NewFromUtf8(pIsolate, bsMethodName.c_str(),
+  GetGlobalObjectTemplate(m_isolate)->Set(
+      v8::String::NewFromUtf8(m_isolate, bsMethodName.c_str(),
                               v8::NewStringType::kNormal)
           .ToLocalChecked(),
       fun, v8::ReadOnly);
 }
 
-void FXJS_DefineGlobalConst(v8::Isolate* pIsolate,
-                            const wchar_t* sConstName,
-                            v8::FunctionCallback pConstGetter) {
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope handle_scope(pIsolate);
+void CFXJS_Engine::DefineGlobalConst(const wchar_t* sConstName,
+                                     v8::FunctionCallback pConstGetter) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
   CFX_ByteString bsConst = CFX_WideString(sConstName).UTF8Encode();
   v8::Local<v8::FunctionTemplate> fun =
-      v8::FunctionTemplate::New(pIsolate, pConstGetter);
+      v8::FunctionTemplate::New(m_isolate, pConstGetter);
   fun->RemovePrototype();
-  GetGlobalObjectTemplate(pIsolate)->SetAccessorProperty(
-      v8::String::NewFromUtf8(pIsolate, bsConst.c_str(),
+  GetGlobalObjectTemplate(m_isolate)->SetAccessorProperty(
+      v8::String::NewFromUtf8(m_isolate, bsConst.c_str(),
                               v8::NewStringType::kNormal)
           .ToLocalChecked(),
       fun);
 }
 
-void FXJS_InitializeEngine(
-    v8::Isolate* pIsolate,
-    CFXJS_Engine* pEngine,
-    v8::Global<v8::Context>* pV8PersistentContext,
-    std::vector<v8::Global<v8::Object>*>* pStaticObjects) {
-  if (pIsolate == g_isolate)
+void CFXJS_Engine::InitializeEngine() {
+  if (m_isolate == g_isolate)
     ++g_isolate_ref_count;
 
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope handle_scope(pIsolate);
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
 
   // This has to happen before we call GetGlobalObjectTemplate because that
-  // method gets the PerIsolateData from pIsolate.
-  FXJS_PerIsolateData::SetUp(pIsolate);
+  // method gets the PerIsolateData from m_isolate.
+  FXJS_PerIsolateData::SetUp(m_isolate);
 
   v8::Local<v8::Context> v8Context =
-      v8::Context::New(pIsolate, nullptr, GetGlobalObjectTemplate(pIsolate));
+      v8::Context::New(m_isolate, nullptr, GetGlobalObjectTemplate(m_isolate));
   v8::Context::Scope context_scope(v8Context);
 
-  FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate);
+  FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(m_isolate);
   if (!pData)
     return;
-  pData->CreateDynamicObjsMap(pIsolate);
-  v8Context->SetAlignedPointerInEmbedderData(kPerContextDataIndex, pEngine);
+  pData->CreateDynamicObjsMap(m_isolate);
+  v8Context->SetAlignedPointerInEmbedderData(kPerContextDataIndex, this);
 
-  int maxID = CFXJS_ObjDefinition::MaxID(pIsolate);
-  pStaticObjects->resize(maxID + 1);
+  int maxID = CFXJS_ObjDefinition::MaxID(m_isolate);
+  m_StaticObjects.resize(maxID + 1);
   for (int i = 0; i < maxID; ++i) {
-    CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, i);
+    CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(m_isolate, i);
     if (pObjDef->m_ObjType == FXJSOBJTYPE_GLOBAL) {
       v8Context->Global()
           ->GetPrototype()
@@ -370,93 +401,79 @@
           ->SetAlignedPointerInInternalField(0, new CFXJS_PerObjectData(i));
 
       if (pObjDef->m_pConstructor)
-        pObjDef->m_pConstructor(pEngine, v8Context->Global()
-                                             ->GetPrototype()
-                                             ->ToObject(v8Context)
-                                             .ToLocalChecked());
+        pObjDef->m_pConstructor(this, v8Context->Global()
+                                          ->GetPrototype()
+                                          ->ToObject(v8Context)
+                                          .ToLocalChecked());
     } else if (pObjDef->m_ObjType == FXJSOBJTYPE_STATIC) {
       CFX_ByteString bs = CFX_WideString(pObjDef->m_ObjName).UTF8Encode();
       v8::Local<v8::String> m_ObjName =
-          v8::String::NewFromUtf8(pIsolate, bs.c_str(),
+          v8::String::NewFromUtf8(m_isolate, bs.c_str(),
                                   v8::NewStringType::kNormal, bs.GetLength())
               .ToLocalChecked();
 
-      v8::Local<v8::Object> obj =
-          FXJS_NewFxDynamicObj(pIsolate, pEngine, i, true);
+      v8::Local<v8::Object> obj = NewFxDynamicObj(i, true);
       v8Context->Global()->Set(v8Context, m_ObjName, obj).FromJust();
-      pStaticObjects->at(i) = new v8::Global<v8::Object>(pIsolate, obj);
+      m_StaticObjects[i] = new v8::Global<v8::Object>(m_isolate, obj);
     }
   }
-  pV8PersistentContext->Reset(pIsolate, v8Context);
+  m_V8PersistentContext.Reset(m_isolate, v8Context);
 }
 
-void FXJS_ReleaseEngine(v8::Isolate* pIsolate,
-                        v8::Global<v8::Context>* pV8PersistentContext,
-                        std::vector<v8::Global<v8::Object>*>* pStaticObjects) {
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::HandleScope handle_scope(pIsolate);
+void CFXJS_Engine::ReleaseEngine() {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
   v8::Local<v8::Context> context =
-      v8::Local<v8::Context>::New(pIsolate, *pV8PersistentContext);
+      v8::Local<v8::Context>::New(m_isolate, m_V8PersistentContext);
   v8::Context::Scope context_scope(context);
 
-  FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate);
+  FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(m_isolate);
   if (!pData)
     return;
 
-  int maxID = CFXJS_ObjDefinition::MaxID(pIsolate);
+  m_ConstArrays.clear();
+
+  int maxID = CFXJS_ObjDefinition::MaxID(m_isolate);
   for (int i = 0; i < maxID; ++i) {
-    CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, i);
+    CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(m_isolate, i);
     v8::Local<v8::Object> pObj;
     if (pObjDef->m_ObjType == FXJSOBJTYPE_GLOBAL) {
       pObj =
           context->Global()->GetPrototype()->ToObject(context).ToLocalChecked();
-    } else if (pStaticObjects->at(i) && !pStaticObjects->at(i)->IsEmpty()) {
-      pObj = v8::Local<v8::Object>::New(pIsolate, *pStaticObjects->at(i));
-      delete pStaticObjects->at(i);
-      pStaticObjects->at(i) = nullptr;
+    } else if (m_StaticObjects[i] && !m_StaticObjects[i]->IsEmpty()) {
+      pObj = v8::Local<v8::Object>::New(m_isolate, *m_StaticObjects[i]);
+      delete m_StaticObjects[i];
+      m_StaticObjects[i] = nullptr;
     }
 
     if (!pObj.IsEmpty()) {
       if (pObjDef->m_pDestructor)
-        pObjDef->m_pDestructor(pObj);
-      FXJS_FreePrivate(pObj);
+        pObjDef->m_pDestructor(this, pObj);
+      FreeObjectPrivate(pObj);
     }
   }
 
-  if (pIsolate == g_isolate && --g_isolate_ref_count > 0)
+  m_V8PersistentContext.Reset();
+
+  if (m_isolate == g_isolate && --g_isolate_ref_count > 0)
     return;
 
   pData->ReleaseDynamicObjsMap();
   for (int i = 0; i < maxID; ++i)
-    delete CFXJS_ObjDefinition::ForID(pIsolate, i);
+    delete CFXJS_ObjDefinition::ForID(m_isolate, i);
 
-  pIsolate->SetData(g_embedderDataSlot, nullptr);
+  m_isolate->SetData(g_embedderDataSlot, nullptr);
   delete pData;
 }
 
-CFXJS_Engine* FXJS_GetCurrentEngineFromIsolate(v8::Isolate* pIsolate) {
-  v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
-  return static_cast<CFXJS_Engine*>(
-      context->GetAlignedPointerFromEmbedderData(kPerContextDataIndex));
-}
-
-#ifdef PDF_ENABLE_XFA
-void FXJS_SetEngineForV8Context(v8::Local<v8::Context> v8Context,
-                                CFXJS_Engine* pEngine) {
-  v8Context->SetAlignedPointerInEmbedderData(kPerContextDataIndex, pEngine);
-}
-#endif  // PDF_ENABLE_XFA
-
-int FXJS_Execute(v8::Isolate* pIsolate,
-                 const CFX_WideString& script,
-                 FXJSErr* pError) {
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::TryCatch try_catch(pIsolate);
+int CFXJS_Engine::Execute(const CFX_WideString& script, FXJSErr* pError) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::TryCatch try_catch(m_isolate);
   CFX_ByteString bsScript = script.UTF8Encode();
-  v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
+  v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
   v8::Local<v8::Script> compiled_script;
   if (!v8::Script::Compile(context,
-                           v8::String::NewFromUtf8(pIsolate, bsScript.c_str(),
+                           v8::String::NewFromUtf8(m_isolate, bsScript.c_str(),
                                                    v8::NewStringType::kNormal,
                                                    bsScript.GetLength())
                                .ToLocalChecked())
@@ -475,29 +492,27 @@
   return 0;
 }
 
-v8::Local<v8::Object> FXJS_NewFxDynamicObj(v8::Isolate* pIsolate,
-                                           CFXJS_Engine* pEngine,
-                                           int nObjDefnID,
-                                           bool bStatic) {
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
+v8::Local<v8::Object> CFXJS_Engine::NewFxDynamicObj(int nObjDefnID,
+                                                    bool bStatic) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
   if (nObjDefnID == -1) {
-    v8::Local<v8::ObjectTemplate> objTempl = v8::ObjectTemplate::New(pIsolate);
+    v8::Local<v8::ObjectTemplate> objTempl = v8::ObjectTemplate::New(m_isolate);
     v8::Local<v8::Object> obj;
     if (!objTempl->NewInstance(context).ToLocal(&obj))
       return v8::Local<v8::Object>();
     return obj;
   }
 
-  FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate);
+  FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(m_isolate);
   if (!pData)
     return v8::Local<v8::Object>();
 
-  if (nObjDefnID < 0 || nObjDefnID >= CFXJS_ObjDefinition::MaxID(pIsolate))
+  if (nObjDefnID < 0 || nObjDefnID >= CFXJS_ObjDefinition::MaxID(m_isolate))
     return v8::Local<v8::Object>();
 
   CFXJS_ObjDefinition* pObjDef =
-      CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID);
+      CFXJS_ObjDefinition::ForID(m_isolate, nObjDefnID);
   v8::Local<v8::Object> obj;
   if (!pObjDef->GetInstanceTemplate()->NewInstance(context).ToLocal(&obj))
     return v8::Local<v8::Object>();
@@ -505,49 +520,37 @@
   CFXJS_PerObjectData* pPerObjData = new CFXJS_PerObjectData(nObjDefnID);
   obj->SetAlignedPointerInInternalField(0, pPerObjData);
   if (pObjDef->m_pConstructor)
-    pObjDef->m_pConstructor(pEngine, obj);
+    pObjDef->m_pConstructor(this, obj);
 
-  if (!bStatic && FXJS_PerIsolateData::Get(pIsolate)->m_pDynamicObjsMap) {
-    FXJS_PerIsolateData::Get(pIsolate)->m_pDynamicObjsMap->set(pPerObjData,
-                                                               obj);
+  if (!bStatic && FXJS_PerIsolateData::Get(m_isolate)->m_pDynamicObjsMap) {
+    FXJS_PerIsolateData::Get(m_isolate)->m_pDynamicObjsMap->set(pPerObjData,
+                                                                obj);
   }
   return obj;
 }
 
-v8::Local<v8::Object> FXJS_GetThisObj(v8::Isolate* pIsolate) {
-  v8::Isolate::Scope isolate_scope(pIsolate);
-  if (!FXJS_PerIsolateData::Get(pIsolate))
+v8::Local<v8::Object> CFXJS_Engine::GetThisObj() {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  if (!FXJS_PerIsolateData::Get(m_isolate))
     return v8::Local<v8::Object>();
 
   // Return the global object.
-  v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
+  v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
   return context->Global()->GetPrototype()->ToObject(context).ToLocalChecked();
 }
 
-int FXJS_GetObjDefnID(v8::Local<v8::Object> pObj) {
-  if (pObj.IsEmpty() || !pObj->InternalFieldCount())
-    return -1;
-  CFXJS_PerObjectData* pPerObjectData = static_cast<CFXJS_PerObjectData*>(
-      pObj->GetAlignedPointerFromInternalField(0));
-  if (pPerObjectData)
-    return pPerObjectData->m_ObjDefID;
-  return -1;
-}
-
-void FXJS_Error(v8::Isolate* pIsolate, const CFX_WideString& message) {
+void CFXJS_Engine::Error(const CFX_WideString& message) {
   // Conversion from pdfium's wchar_t wide-strings to v8's uint16_t
   // wide-strings isn't handled by v8, so use UTF8 as a common
   // intermediate format.
   CFX_ByteString utf8_message = message.UTF8Encode();
-  pIsolate->ThrowException(v8::String::NewFromUtf8(pIsolate,
-                                                   utf8_message.c_str(),
-                                                   v8::NewStringType::kNormal)
-                               .ToLocalChecked());
+  m_isolate->ThrowException(v8::String::NewFromUtf8(m_isolate,
+                                                    utf8_message.c_str(),
+                                                    v8::NewStringType::kNormal)
+                                .ToLocalChecked());
 }
 
-void FXJS_SetPrivate(v8::Isolate* pIsolate,
-                     v8::Local<v8::Object> pObj,
-                     void* p) {
+void CFXJS_Engine::SetObjectPrivate(v8::Local<v8::Object> pObj, void* p) {
   if (pObj.IsEmpty() || !pObj->InternalFieldCount())
     return;
   CFXJS_PerObjectData* pPerObjectData = static_cast<CFXJS_PerObjectData*>(
@@ -557,7 +560,7 @@
   pPerObjectData->m_pPrivate = p;
 }
 
-void* FXJS_GetPrivate(v8::Isolate* pIsolate, v8::Local<v8::Object> pObj) {
+void* CFXJS_Engine::GetObjectPrivate(v8::Local<v8::Object> pObj) {
   if (pObj.IsEmpty())
     return nullptr;
   CFXJS_PerObjectData* pPerObjectData = nullptr;
@@ -567,7 +570,7 @@
   } else {
     // It could be a global proxy object.
     v8::Local<v8::Value> v = pObj->GetPrototype();
-    v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
+    v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
     if (v->IsObject()) {
       pPerObjectData = static_cast<CFXJS_PerObjectData*>(
           v->ToObject(context)
@@ -578,246 +581,229 @@
   return pPerObjectData ? pPerObjectData->m_pPrivate : nullptr;
 }
 
-void FXJS_FreePrivate(void* pPerObjectData) {
-  delete static_cast<CFXJS_PerObjectData*>(pPerObjectData);
-}
-
-void FXJS_FreePrivate(v8::Local<v8::Object> pObj) {
-  if (pObj.IsEmpty() || !pObj->InternalFieldCount())
-    return;
-  FXJS_FreePrivate(pObj->GetAlignedPointerFromInternalField(0));
-  pObj->SetAlignedPointerInInternalField(0, nullptr);
-}
-
-v8::Local<v8::String> FXJS_WSToJSString(v8::Isolate* pIsolate,
-                                        const CFX_WideString& wsPropertyName) {
+v8::Local<v8::String> CFXJS_Engine::WSToJSString(
+    const CFX_WideString& wsPropertyName) {
+  v8::Isolate* pIsolate = m_isolate ? m_isolate : v8::Isolate::GetCurrent();
   CFX_ByteString bs = wsPropertyName.UTF8Encode();
-  if (!pIsolate)
-    pIsolate = v8::Isolate::GetCurrent();
   return v8::String::NewFromUtf8(pIsolate, bs.c_str(),
                                  v8::NewStringType::kNormal, bs.GetLength())
       .ToLocalChecked();
 }
 
-v8::Local<v8::Value> FXJS_GetObjectProperty(
-    v8::Isolate* pIsolate,
+v8::Local<v8::Value> CFXJS_Engine::GetObjectProperty(
     v8::Local<v8::Object> pObj,
     const CFX_WideString& wsPropertyName) {
   if (pObj.IsEmpty())
     return v8::Local<v8::Value>();
   v8::Local<v8::Value> val;
-  if (!pObj->Get(pIsolate->GetCurrentContext(),
-                 FXJS_WSToJSString(pIsolate, wsPropertyName))
+  if (!pObj->Get(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName))
            .ToLocal(&val))
     return v8::Local<v8::Value>();
   return val;
 }
 
-std::vector<CFX_WideString> FXJS_GetObjectPropertyNames(
-    v8::Isolate* pIsolate,
+std::vector<CFX_WideString> CFXJS_Engine::GetObjectPropertyNames(
     v8::Local<v8::Object> pObj) {
   if (pObj.IsEmpty())
     return std::vector<CFX_WideString>();
 
   v8::Local<v8::Array> val;
-  if (!pObj->GetPropertyNames(pIsolate->GetCurrentContext()).ToLocal(&val))
+  v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
+  if (!pObj->GetPropertyNames(context).ToLocal(&val))
     return std::vector<CFX_WideString>();
 
   std::vector<CFX_WideString> result;
   for (uint32_t i = 0; i < val->Length(); ++i) {
-    result.push_back(FXJS_ToString(
-        pIsolate, val->Get(pIsolate->GetCurrentContext(), i).ToLocalChecked()));
+    result.push_back(ToString(val->Get(context, i).ToLocalChecked()));
   }
 
   return result;
 }
 
-void FXJS_PutObjectString(v8::Isolate* pIsolate,
-                          v8::Local<v8::Object> pObj,
-                          const CFX_WideString& wsPropertyName,
-                          const CFX_WideString& wsValue) {
+void CFXJS_Engine::PutObjectString(v8::Local<v8::Object> pObj,
+                                   const CFX_WideString& wsPropertyName,
+                                   const CFX_WideString& wsValue) {
   if (pObj.IsEmpty())
     return;
-  pObj->Set(pIsolate->GetCurrentContext(),
-            FXJS_WSToJSString(pIsolate, wsPropertyName),
-            FXJS_WSToJSString(pIsolate, wsValue))
+  pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName),
+            WSToJSString(wsValue))
       .FromJust();
 }
 
-void FXJS_PutObjectNumber(v8::Isolate* pIsolate,
-                          v8::Local<v8::Object> pObj,
-                          const CFX_WideString& wsPropertyName,
-                          int nValue) {
+void CFXJS_Engine::PutObjectNumber(v8::Local<v8::Object> pObj,
+                                   const CFX_WideString& wsPropertyName,
+                                   int nValue) {
   if (pObj.IsEmpty())
     return;
-  pObj->Set(pIsolate->GetCurrentContext(),
-            FXJS_WSToJSString(pIsolate, wsPropertyName),
-            v8::Int32::New(pIsolate, nValue))
+  pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName),
+            v8::Int32::New(m_isolate, nValue))
       .FromJust();
 }
 
-void FXJS_PutObjectNumber(v8::Isolate* pIsolate,
-                          v8::Local<v8::Object> pObj,
-                          const CFX_WideString& wsPropertyName,
-                          float fValue) {
+void CFXJS_Engine::PutObjectNumber(v8::Local<v8::Object> pObj,
+                                   const CFX_WideString& wsPropertyName,
+                                   float fValue) {
   if (pObj.IsEmpty())
     return;
-  pObj->Set(pIsolate->GetCurrentContext(),
-            FXJS_WSToJSString(pIsolate, wsPropertyName),
-            v8::Number::New(pIsolate, (double)fValue))
+  pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName),
+            v8::Number::New(m_isolate, (double)fValue))
       .FromJust();
 }
 
-void FXJS_PutObjectNumber(v8::Isolate* pIsolate,
-                          v8::Local<v8::Object> pObj,
-                          const CFX_WideString& wsPropertyName,
-                          double dValue) {
+void CFXJS_Engine::PutObjectNumber(v8::Local<v8::Object> pObj,
+                                   const CFX_WideString& wsPropertyName,
+                                   double dValue) {
   if (pObj.IsEmpty())
     return;
-  pObj->Set(pIsolate->GetCurrentContext(),
-            FXJS_WSToJSString(pIsolate, wsPropertyName),
-            v8::Number::New(pIsolate, (double)dValue))
+  pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName),
+            v8::Number::New(m_isolate, (double)dValue))
       .FromJust();
 }
 
-void FXJS_PutObjectBoolean(v8::Isolate* pIsolate,
-                           v8::Local<v8::Object> pObj,
-                           const CFX_WideString& wsPropertyName,
-                           bool bValue) {
+void CFXJS_Engine::PutObjectBoolean(v8::Local<v8::Object> pObj,
+                                    const CFX_WideString& wsPropertyName,
+                                    bool bValue) {
   if (pObj.IsEmpty())
     return;
-  pObj->Set(pIsolate->GetCurrentContext(),
-            FXJS_WSToJSString(pIsolate, wsPropertyName),
-            v8::Boolean::New(pIsolate, bValue))
+  pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName),
+            v8::Boolean::New(m_isolate, bValue))
       .FromJust();
 }
 
-void FXJS_PutObjectObject(v8::Isolate* pIsolate,
-                          v8::Local<v8::Object> pObj,
-                          const CFX_WideString& wsPropertyName,
-                          v8::Local<v8::Object> pPut) {
+void CFXJS_Engine::PutObjectObject(v8::Local<v8::Object> pObj,
+                                   const CFX_WideString& wsPropertyName,
+                                   v8::Local<v8::Object> pPut) {
   if (pObj.IsEmpty())
     return;
-  pObj->Set(pIsolate->GetCurrentContext(),
-            FXJS_WSToJSString(pIsolate, wsPropertyName), pPut)
+  pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName), pPut)
       .FromJust();
 }
 
-void FXJS_PutObjectNull(v8::Isolate* pIsolate,
-                        v8::Local<v8::Object> pObj,
-                        const CFX_WideString& wsPropertyName) {
+void CFXJS_Engine::PutObjectNull(v8::Local<v8::Object> pObj,
+                                 const CFX_WideString& wsPropertyName) {
   if (pObj.IsEmpty())
     return;
-  pObj->Set(pIsolate->GetCurrentContext(),
-            FXJS_WSToJSString(pIsolate, wsPropertyName),
+  pObj->Set(m_isolate->GetCurrentContext(), WSToJSString(wsPropertyName),
             v8::Local<v8::Object>())
       .FromJust();
 }
 
-v8::Local<v8::Array> FXJS_NewArray(v8::Isolate* pIsolate) {
-  return v8::Array::New(pIsolate);
+v8::Local<v8::Array> CFXJS_Engine::NewArray() {
+  return v8::Array::New(m_isolate);
 }
 
-unsigned FXJS_PutArrayElement(v8::Isolate* pIsolate,
-                              v8::Local<v8::Array> pArray,
-                              unsigned index,
-                              v8::Local<v8::Value> pValue) {
+unsigned CFXJS_Engine::PutArrayElement(v8::Local<v8::Array> pArray,
+                                       unsigned index,
+                                       v8::Local<v8::Value> pValue) {
   if (pArray.IsEmpty())
     return 0;
-  if (pArray->Set(pIsolate->GetCurrentContext(), index, pValue).IsNothing())
+  if (pArray->Set(m_isolate->GetCurrentContext(), index, pValue).IsNothing())
     return 0;
   return 1;
 }
 
-v8::Local<v8::Value> FXJS_GetArrayElement(v8::Isolate* pIsolate,
-                                          v8::Local<v8::Array> pArray,
-                                          unsigned index) {
+v8::Local<v8::Value> CFXJS_Engine::GetArrayElement(v8::Local<v8::Array> pArray,
+                                                   unsigned index) {
   if (pArray.IsEmpty())
     return v8::Local<v8::Value>();
   v8::Local<v8::Value> val;
-  if (!pArray->Get(pIsolate->GetCurrentContext(), index).ToLocal(&val))
+  if (!pArray->Get(m_isolate->GetCurrentContext(), index).ToLocal(&val))
     return v8::Local<v8::Value>();
   return val;
 }
 
-unsigned FXJS_GetArrayLength(v8::Local<v8::Array> pArray) {
+unsigned CFXJS_Engine::GetArrayLength(v8::Local<v8::Array> pArray) {
   if (pArray.IsEmpty())
     return 0;
   return pArray->Length();
 }
 
-v8::Local<v8::Value> FXJS_NewNumber(v8::Isolate* pIsolate, int number) {
-  return v8::Int32::New(pIsolate, number);
+v8::Local<v8::Context> CFXJS_Engine::NewLocalContext() {
+  return v8::Local<v8::Context>::New(m_isolate, m_V8PersistentContext);
 }
 
-v8::Local<v8::Value> FXJS_NewNumber(v8::Isolate* pIsolate, double number) {
-  return v8::Number::New(pIsolate, number);
+v8::Local<v8::Context> CFXJS_Engine::GetPersistentContext() {
+  return m_V8PersistentContext.Get(m_isolate);
 }
 
-v8::Local<v8::Value> FXJS_NewNumber(v8::Isolate* pIsolate, float number) {
-  return v8::Number::New(pIsolate, (float)number);
+v8::Local<v8::Value> CFXJS_Engine::NewNumber(int number) {
+  return v8::Int32::New(m_isolate, number);
 }
 
-v8::Local<v8::Value> FXJS_NewBoolean(v8::Isolate* pIsolate, bool b) {
-  return v8::Boolean::New(pIsolate, b);
+v8::Local<v8::Value> CFXJS_Engine::NewNumber(double number) {
+  return v8::Number::New(m_isolate, number);
 }
 
-v8::Local<v8::Value> FXJS_NewString(v8::Isolate* pIsolate, const wchar_t* str) {
-  return FXJS_WSToJSString(pIsolate, str);
+v8::Local<v8::Value> CFXJS_Engine::NewNumber(float number) {
+  return v8::Number::New(m_isolate, (float)number);
 }
 
-v8::Local<v8::Value> FXJS_NewNull(v8::Isolate* pIsolate) {
+v8::Local<v8::Value> CFXJS_Engine::NewBoolean(bool b) {
+  return v8::Boolean::New(m_isolate, b);
+}
+
+v8::Local<v8::Value> CFXJS_Engine::NewString(const wchar_t* str) {
+  return WSToJSString(str);
+}
+
+v8::Local<v8::Value> CFXJS_Engine::NewNull() {
   return v8::Local<v8::Value>();
 }
 
-v8::Local<v8::Date> FXJS_NewDate(v8::Isolate* pIsolate, double d) {
-  return v8::Date::New(pIsolate->GetCurrentContext(), d)
+v8::Local<v8::Date> CFXJS_Engine::NewDate(double d) {
+  return v8::Date::New(m_isolate->GetCurrentContext(), d)
       .ToLocalChecked()
       .As<v8::Date>();
 }
 
-int FXJS_ToInt32(v8::Isolate* pIsolate, v8::Local<v8::Value> pValue) {
+int CFXJS_Engine::ToInt32(v8::Local<v8::Value> pValue) {
   if (pValue.IsEmpty())
     return 0;
-  v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
+  v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
   return pValue->ToInt32(context).ToLocalChecked()->Value();
 }
 
-bool FXJS_ToBoolean(v8::Isolate* pIsolate, v8::Local<v8::Value> pValue) {
+bool CFXJS_Engine::ToBoolean(v8::Local<v8::Value> pValue) {
   if (pValue.IsEmpty())
     return false;
-  v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
+  v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
   return pValue->ToBoolean(context).ToLocalChecked()->Value();
 }
 
-double FXJS_ToNumber(v8::Isolate* pIsolate, v8::Local<v8::Value> pValue) {
+double CFXJS_Engine::ToNumber(v8::Local<v8::Value> pValue) {
   if (pValue.IsEmpty())
     return 0.0;
-  v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
+  v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
   return pValue->ToNumber(context).ToLocalChecked()->Value();
 }
 
-v8::Local<v8::Object> FXJS_ToObject(v8::Isolate* pIsolate,
-                                    v8::Local<v8::Value> pValue) {
+v8::Local<v8::Object> CFXJS_Engine::ToObject(v8::Local<v8::Value> pValue) {
   if (pValue.IsEmpty())
     return v8::Local<v8::Object>();
-  v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
+  v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
   return pValue->ToObject(context).ToLocalChecked();
 }
 
-CFX_WideString FXJS_ToString(v8::Isolate* pIsolate,
-                             v8::Local<v8::Value> pValue) {
+CFX_WideString CFXJS_Engine::ToString(v8::Local<v8::Value> pValue) {
   if (pValue.IsEmpty())
     return L"";
-  v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
+  v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
   v8::String::Utf8Value s(pValue->ToString(context).ToLocalChecked());
   return CFX_WideString::FromUTF8(CFX_ByteStringC(*s, s.length()));
 }
 
-v8::Local<v8::Array> FXJS_ToArray(v8::Isolate* pIsolate,
-                                  v8::Local<v8::Value> pValue) {
+v8::Local<v8::Array> CFXJS_Engine::ToArray(v8::Local<v8::Value> pValue) {
   if (pValue.IsEmpty())
     return v8::Local<v8::Array>();
-  v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
+  v8::Local<v8::Context> context = m_isolate->GetCurrentContext();
   return v8::Local<v8::Array>::Cast(pValue->ToObject(context).ToLocalChecked());
 }
+
+void CFXJS_Engine::SetConstArray(const CFX_WideString& name,
+                                 v8::Local<v8::Array> array) {
+  m_ConstArrays[name] = v8::Global<v8::Array>(GetIsolate(), array);
+}
+
+v8::Local<v8::Array> CFXJS_Engine::GetConstArray(const CFX_WideString& name) {
+  return v8::Local<v8::Array>::New(GetIsolate(), m_ConstArrays[name]);
+}
diff --git a/fxjs/fxjs_v8_embeddertest.cpp b/fxjs/fxjs_v8_embeddertest.cpp
index b573939..2da3131 100644
--- a/fxjs/fxjs_v8_embeddertest.cpp
+++ b/fxjs/fxjs_v8_embeddertest.cpp
@@ -21,17 +21,14 @@
  public:
   void ExecuteInCurrentContext(const CFX_WideString& script) {
     FXJSErr error;
-    int sts = FXJS_Execute(isolate(), script, &error);
+    int sts = engine()->Execute(script, &error);
     EXPECT_EQ(0, sts);
   }
   void CheckAssignmentInCurrentContext(double expected) {
-    v8::Local<v8::Object> This = FXJS_GetThisObj(isolate());
-    v8::Local<v8::Value> fred =
-        FXJS_GetObjectProperty(isolate(), This, L"fred");
+    v8::Local<v8::Object> This = engine()->GetThisObj();
+    v8::Local<v8::Value> fred = engine()->GetObjectProperty(This, L"fred");
     EXPECT_TRUE(fred->IsNumber());
-    EXPECT_EQ(expected, fred->ToNumber(isolate()->GetCurrentContext())
-                            .ToLocalChecked()
-                            ->Value());
+    EXPECT_EQ(expected, engine()->ToNumber(fred));
   }
 };
 
@@ -48,35 +45,34 @@
   v8::Isolate::Scope isolate_scope(isolate());
   v8::HandleScope handle_scope(isolate());
 
-  v8::Global<v8::Context> global_context1;
-  std::vector<v8::Global<v8::Object>*> static_objects1;
-  FXJS_InitializeEngine(isolate(), nullptr, &global_context1, &static_objects1);
+  CFXJS_Engine engine1;
+  engine1.SetIsolate(isolate());
+  engine1.InitializeEngine();
 
-  v8::Global<v8::Context> global_context2;
-  std::vector<v8::Global<v8::Object>*> static_objects2;
-  FXJS_InitializeEngine(isolate(), nullptr, &global_context2, &static_objects2);
+  CFXJS_Engine engine2;
+  engine2.SetIsolate(isolate());
+  engine2.InitializeEngine();
 
   v8::Context::Scope context_scope(GetV8Context());
   ExecuteInCurrentContext(CFX_WideString(kScript0));
   CheckAssignmentInCurrentContext(kExpected0);
 
   {
-    v8::Local<v8::Context> context1 =
-        v8::Local<v8::Context>::New(isolate(), global_context1);
+    v8::Local<v8::Context> context1 = engine1.NewLocalContext();
     v8::Context::Scope context_scope1(context1);
     ExecuteInCurrentContext(CFX_WideString(kScript1));
     CheckAssignmentInCurrentContext(kExpected1);
   }
-  FXJS_ReleaseEngine(isolate(), &global_context1, &static_objects1);
+
+  engine1.ReleaseEngine();
 
   {
-    v8::Local<v8::Context> context2 =
-        v8::Local<v8::Context>::New(isolate(), global_context2);
+    v8::Local<v8::Context> context2 = engine2.NewLocalContext();
     v8::Context::Scope context_scope2(context2);
     ExecuteInCurrentContext(CFX_WideString(kScript2));
     CheckAssignmentInCurrentContext(kExpected2);
   }
-  FXJS_ReleaseEngine(isolate(), &global_context2, &static_objects2);
 
+  engine2.ReleaseEngine();
   CheckAssignmentInCurrentContext(kExpected0);
 }
diff --git a/fxjs/include/fxjs_v8.h b/fxjs/include/fxjs_v8.h
index 52afc49..7c4a907 100644
--- a/fxjs/include/fxjs_v8.h
+++ b/fxjs/include/fxjs_v8.h
@@ -125,25 +125,9 @@
   void Free(void* data, size_t length) override;
 };
 
-using FXJS_CONSTRUCTOR = void (*)(CFXJS_Engine* fxjs,
-                                  v8::Local<v8::Object> obj);
-using FXJS_DESTRUCTOR = void (*)(v8::Local<v8::Object> obj);
-
 void FXJS_Initialize(unsigned int embedderDataSlot, v8::Isolate* pIsolate);
 void FXJS_Release();
 
-class CFXJS_Engine {
- public:
-  CFXJS_Engine();
-  ~CFXJS_Engine();
-
- protected:
-  v8::Isolate* m_isolate;
-  v8::Global<v8::Context> m_context;
-  std::vector<v8::Global<v8::Object>*> m_StaticObjects;
-  std::map<CFX_WideString, v8::Global<v8::Array>> m_ConstArrays;
-};
-
 // Gets the global isolate set by FXJS_Initialize(), or makes a new one each
 // time if there is no such isolate. Returns true if a new isolate had to be
 // created.
@@ -152,140 +136,133 @@
 // Get the global isolate's ref count.
 size_t FXJS_GlobalIsolateRefCount();
 
-// Always returns a valid, newly-created objDefnID.
-int FXJS_DefineObj(v8::Isolate* pIsolate,
-                   const wchar_t* sObjName,
-                   FXJSOBJTYPE eObjType,
-                   FXJS_CONSTRUCTOR pConstructor,
-                   FXJS_DESTRUCTOR pDestructor);
+class CFXJS_Engine {
+ public:
+  CFXJS_Engine();
+  ~CFXJS_Engine();
 
-void FXJS_DefineObjMethod(v8::Isolate* pIsolate,
-                          int nObjDefnID,
-                          const wchar_t* sMethodName,
-                          v8::FunctionCallback pMethodCall);
-void FXJS_DefineObjProperty(v8::Isolate* pIsolate,
-                            int nObjDefnID,
-                            const wchar_t* sPropName,
-                            v8::AccessorGetterCallback pPropGet,
-                            v8::AccessorSetterCallback pPropPut);
-void FXJS_DefineObjAllProperties(v8::Isolate* pIsolate,
-                                 int nObjDefnID,
-                                 v8::NamedPropertyQueryCallback pPropQurey,
-                                 v8::NamedPropertyGetterCallback pPropGet,
-                                 v8::NamedPropertySetterCallback pPropPut,
-                                 v8::NamedPropertyDeleterCallback pPropDel);
-void FXJS_DefineObjConst(v8::Isolate* pIsolate,
-                         int nObjDefnID,
-                         const wchar_t* sConstName,
-                         v8::Local<v8::Value> pDefault);
-void FXJS_DefineGlobalMethod(v8::Isolate* pIsolate,
-                             const wchar_t* sMethodName,
-                             v8::FunctionCallback pMethodCall);
-void FXJS_DefineGlobalConst(v8::Isolate* pIsolate,
-                            const wchar_t* sConstName,
-                            v8::FunctionCallback pConstGetter);
+  using Constructor = void (*)(CFXJS_Engine* pEngine,
+                               v8::Local<v8::Object> obj);
+  using Destructor = void (*)(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj);
 
-// Called after FXJS_Define* calls made.
-void FXJS_InitializeEngine(
-    v8::Isolate* pIsolate,
-    CFXJS_Engine* pEngine,
-    v8::Global<v8::Context>* pV8PersistentContext,
-    std::vector<v8::Global<v8::Object>*>* pStaticObjects);
-void FXJS_ReleaseEngine(v8::Isolate* pIsolate,
-                        v8::Global<v8::Context>* pV8PersistentContext,
-                        std::vector<v8::Global<v8::Object>*>* pStaticObjects);
-CFXJS_Engine* FXJS_GetCurrentEngineFromIsolate(v8::Isolate* pIsolate);
+  static CFXJS_Engine* CurrentEngineFromIsolate(v8::Isolate* pIsolate);
+  static int GetObjDefnID(v8::Local<v8::Object> pObj);
 
 #ifdef PDF_ENABLE_XFA
-// Called as part of FXJS_InitializeEngine, exposed so PDF can make its
-// own contexts compatible with XFA or vice versa.
-void FXJS_SetEngineForV8Context(v8::Local<v8::Context> v8Context,
-                                CFXJS_Engine* pEngine);
+  // Called as part of FXJS_InitializeEngine, exposed so PDF can make its
+  // own contexts compatible with XFA or vice versa.
+  static void SetForV8Context(v8::Local<v8::Context> v8Context,
+                              CFXJS_Engine* pEngine);
 #endif  // PDF_ENABLE_XFA
 
-// Called after FXJS_InitializeEngine call made.
-int FXJS_Execute(v8::Isolate* pIsolate,
-                 const CFX_WideString& script,
-                 FXJSErr* perror);
+  // TODO(tsepez): to constructor.
+  void SetIsolate(v8::Isolate* pIsolate) { m_isolate = pIsolate; }
+  v8::Isolate* GetIsolate() const { return m_isolate; }
 
-v8::Local<v8::Object> FXJS_NewFxDynamicObj(v8::Isolate* pIsolate,
-                                           CFXJS_Engine* pEngine,
-                                           int nObjDefnID,
-                                           bool bStatic = false);
-v8::Local<v8::Object> FXJS_GetThisObj(v8::Isolate* pIsolate);
-int FXJS_GetObjDefnID(v8::Local<v8::Object> pObj);
+  // Always returns a valid, newly-created objDefnID.
+  int DefineObj(const wchar_t* sObjName,
+                FXJSOBJTYPE eObjType,
+                Constructor pConstructor,
+                Destructor pDestructor);
 
-void FXJS_SetPrivate(v8::Isolate* pIsolate,
-                     v8::Local<v8::Object> pObj,
-                     void* p);
-void* FXJS_GetPrivate(v8::Isolate* pIsolate, v8::Local<v8::Object> pObj);
-void FXJS_FreePrivate(void* p);
-void FXJS_FreePrivate(v8::Local<v8::Object> pObj);
-void FXJS_Error(v8::Isolate* isolate, const CFX_WideString& message);
+  void DefineObjMethod(int nObjDefnID,
+                       const wchar_t* sMethodName,
+                       v8::FunctionCallback pMethodCall);
+  void DefineObjProperty(int nObjDefnID,
+                         const wchar_t* sPropName,
+                         v8::AccessorGetterCallback pPropGet,
+                         v8::AccessorSetterCallback pPropPut);
+  void DefineObjAllProperties(int nObjDefnID,
+                              v8::NamedPropertyQueryCallback pPropQurey,
+                              v8::NamedPropertyGetterCallback pPropGet,
+                              v8::NamedPropertySetterCallback pPropPut,
+                              v8::NamedPropertyDeleterCallback pPropDel);
+  void DefineObjConst(int nObjDefnID,
+                      const wchar_t* sConstName,
+                      v8::Local<v8::Value> pDefault);
+  void DefineGlobalMethod(const wchar_t* sMethodName,
+                          v8::FunctionCallback pMethodCall);
+  void DefineGlobalConst(const wchar_t* sConstName,
+                         v8::FunctionCallback pConstGetter);
 
-v8::Local<v8::String> FXJS_WSToJSString(v8::Isolate* pIsolate,
-                                        const CFX_WideString& wsPropertyName);
+  // Called after FXJS_Define* calls made.
+  void InitializeEngine();
+  void ReleaseEngine();
 
-std::vector<CFX_WideString> FXJS_GetObjectPropertyNames(
-    v8::Isolate* pIsolate,
-    v8::Local<v8::Object> pObj);
-v8::Local<v8::Value> FXJS_GetObjectProperty(v8::Isolate* pIsolate,
-                                            v8::Local<v8::Object> pObj,
-                                            const CFX_WideString& PropertyName);
+  // Called after FXJS_InitializeEngine call made.
+  int Execute(const CFX_WideString& script, FXJSErr* perror);
 
-unsigned FXJS_GetArrayLength(v8::Local<v8::Array> pArray);
-v8::Local<v8::Value> FXJS_GetArrayElement(v8::Isolate* pIsolate,
-                                          v8::Local<v8::Array> pArray,
-                                          unsigned index);
+  v8::Local<v8::Context> NewLocalContext();
+  v8::Local<v8::Context> GetPersistentContext();
 
-void FXJS_PutObjectString(v8::Isolate* pIsolate,
-                          v8::Local<v8::Object> pObj,
-                          const CFX_WideString& wsPropertyName,
-                          const CFX_WideString& wsValue);
-void FXJS_PutObjectNumber(v8::Isolate* pIsolate,
-                          v8::Local<v8::Object> pObj,
-                          const CFX_WideString& PropertyName,
-                          int nValue);
-void FXJS_PutObjectNumber(v8::Isolate* pIsolate,
-                          v8::Local<v8::Object> pObj,
-                          const CFX_WideString& PropertyName,
-                          float fValue);
-void FXJS_PutObjectNumber(v8::Isolate* pIsolate,
-                          v8::Local<v8::Object> pObj,
-                          const CFX_WideString& PropertyName,
-                          double dValue);
-void FXJS_PutObjectBoolean(v8::Isolate* pIsolate,
-                           v8::Local<v8::Object> pObj,
-                           const CFX_WideString& PropertyName,
-                           bool bValue);
-void FXJS_PutObjectObject(v8::Isolate* pIsolate,
-                          v8::Local<v8::Object> pObj,
-                          const CFX_WideString& PropertyName,
-                          v8::Local<v8::Object> pPut);
-void FXJS_PutObjectNull(v8::Isolate* pIsolate,
-                        v8::Local<v8::Object> pObj,
-                        const CFX_WideString& PropertyName);
-unsigned FXJS_PutArrayElement(v8::Isolate* pIsolate,
-                              v8::Local<v8::Array> pArray,
-                              unsigned index,
-                              v8::Local<v8::Value> pValue);
+  v8::Local<v8::Value> NewNull();
+  v8::Local<v8::Array> NewArray();
+  v8::Local<v8::Value> NewNumber(int number);
+  v8::Local<v8::Value> NewNumber(double number);
+  v8::Local<v8::Value> NewNumber(float number);
+  v8::Local<v8::Value> NewBoolean(bool b);
+  v8::Local<v8::Value> NewString(const wchar_t* str);
+  v8::Local<v8::Date> NewDate(double d);
+  v8::Local<v8::Object> NewFxDynamicObj(int nObjDefnID, bool bStatic = false);
 
-v8::Local<v8::Value> FXJS_NewNull(v8::Isolate* pIsolate);
-v8::Local<v8::Array> FXJS_NewArray(v8::Isolate* pIsolate);
-v8::Local<v8::Value> FXJS_NewNumber(v8::Isolate* pIsolate, int number);
-v8::Local<v8::Value> FXJS_NewNumber(v8::Isolate* pIsolate, double number);
-v8::Local<v8::Value> FXJS_NewNumber(v8::Isolate* pIsolate, float number);
-v8::Local<v8::Value> FXJS_NewBoolean(v8::Isolate* pIsolate, bool b);
-v8::Local<v8::Value> FXJS_NewString(v8::Isolate* pIsolate, const wchar_t* str);
-v8::Local<v8::Date> FXJS_NewDate(v8::Isolate* pIsolate, double d);
+  v8::Local<v8::Object> GetThisObj();
+  int ToInt32(v8::Local<v8::Value> pValue);
+  bool ToBoolean(v8::Local<v8::Value> pValue);
+  double ToNumber(v8::Local<v8::Value> pValue);
+  CFX_WideString ToString(v8::Local<v8::Value> pValue);
+  v8::Local<v8::Object> ToObject(v8::Local<v8::Value> pValue);
+  v8::Local<v8::Array> ToArray(v8::Local<v8::Value> pValue);
 
-int FXJS_ToInt32(v8::Isolate* pIsolate, v8::Local<v8::Value> pValue);
-bool FXJS_ToBoolean(v8::Isolate* pIsolate, v8::Local<v8::Value> pValue);
-double FXJS_ToNumber(v8::Isolate* pIsolate, v8::Local<v8::Value> pValue);
-v8::Local<v8::Object> FXJS_ToObject(v8::Isolate* pIsolate,
-                                    v8::Local<v8::Value> pValue);
-CFX_WideString FXJS_ToString(v8::Isolate* pIsolate,
-                             v8::Local<v8::Value> pValue);
-v8::Local<v8::Array> FXJS_ToArray(v8::Isolate* pIsolate,
-                                  v8::Local<v8::Value> pValue);
+  unsigned GetArrayLength(v8::Local<v8::Array> pArray);
+  v8::Local<v8::Value> GetArrayElement(v8::Local<v8::Array> pArray,
+                                       unsigned index);
+  unsigned PutArrayElement(v8::Local<v8::Array> pArray,
+                           unsigned index,
+                           v8::Local<v8::Value> pValue);
+
+  std::vector<CFX_WideString> GetObjectPropertyNames(
+      v8::Local<v8::Object> pObj);
+  v8::Local<v8::Value> GetObjectProperty(v8::Local<v8::Object> pObj,
+                                         const CFX_WideString& PropertyName);
+
+  void PutObjectString(v8::Local<v8::Object> pObj,
+                       const CFX_WideString& wsPropertyName,
+                       const CFX_WideString& wsValue);
+  void PutObjectNumber(v8::Local<v8::Object> pObj,
+                       const CFX_WideString& PropertyName,
+                       int nValue);
+  void PutObjectNumber(v8::Local<v8::Object> pObj,
+                       const CFX_WideString& PropertyName,
+                       float fValue);
+  void PutObjectNumber(v8::Local<v8::Object> pObj,
+                       const CFX_WideString& PropertyName,
+                       double dValue);
+  void PutObjectBoolean(v8::Local<v8::Object> pObj,
+                        const CFX_WideString& PropertyName,
+                        bool bValue);
+  void PutObjectObject(v8::Local<v8::Object> pObj,
+                       const CFX_WideString& PropertyName,
+                       v8::Local<v8::Object> pPut);
+  void PutObjectNull(v8::Local<v8::Object> pObj,
+                     const CFX_WideString& PropertyName);
+
+  // Native object binding.
+  void SetObjectPrivate(v8::Local<v8::Object> pObj, void* p);
+  void* GetObjectPrivate(v8::Local<v8::Object> pObj);
+  static void FreeObjectPrivate(void* p);
+  static void FreeObjectPrivate(v8::Local<v8::Object> pObj);
+
+  void SetConstArray(const CFX_WideString& name, v8::Local<v8::Array> array);
+  v8::Local<v8::Array> GetConstArray(const CFX_WideString& name);
+
+  v8::Local<v8::String> WSToJSString(const CFX_WideString& wsPropertyName);
+  void Error(const CFX_WideString& message);
+
+ private:
+  v8::Isolate* m_isolate;
+  v8::Global<v8::Context> m_V8PersistentContext;
+  std::vector<v8::Global<v8::Object>*> m_StaticObjects;
+  std::map<CFX_WideString, v8::Global<v8::Array>> m_ConstArrays;
+};
+
 #endif  // FXJS_INCLUDE_FXJS_V8_H_
diff --git a/testing/js_embedder_test.cpp b/testing/js_embedder_test.cpp
index 1b21fe0..f7aa7e3 100644
--- a/testing/js_embedder_test.cpp
+++ b/testing/js_embedder_test.cpp
@@ -21,13 +21,14 @@
   v8::Isolate::Scope isolate_scope(m_pIsolate);
   v8::HandleScope handle_scope(m_pIsolate);
   FXJS_PerIsolateData::SetUp(m_pIsolate);
-  FXJS_InitializeEngine(m_pIsolate, nullptr, &m_pPersistentContext,
-                        &m_StaticObjects);
+  m_Engine.reset(new CFXJS_Engine);
+  m_Engine->SetIsolate(m_pIsolate);
+  m_Engine->InitializeEngine();
 }
 
 void JSEmbedderTest::TearDown() {
-  FXJS_ReleaseEngine(m_pIsolate, &m_pPersistentContext, &m_StaticObjects);
-  m_pPersistentContext.Reset();
+  m_Engine->ReleaseEngine();
+  m_Engine.reset();
   EmbedderTest::TearDown();
   m_pIsolate->Dispose();
   m_pIsolate = nullptr;
@@ -38,5 +39,5 @@
 }
 
 v8::Local<v8::Context> JSEmbedderTest::GetV8Context() {
-  return m_pPersistentContext.Get(m_pIsolate);
+  return m_Engine->GetPersistentContext();
 }
diff --git a/testing/js_embedder_test.h b/testing/js_embedder_test.h
index b2bd5a8..f0beb1e 100644
--- a/testing/js_embedder_test.h
+++ b/testing/js_embedder_test.h
@@ -21,12 +21,12 @@
 
   v8::Isolate* isolate();
   v8::Local<v8::Context> GetV8Context();
+  CFXJS_Engine* engine() { return m_Engine.get(); }
 
  private:
   std::unique_ptr<FXJS_ArrayBufferAllocator> m_pArrayBufferAllocator;
   v8::Isolate* m_pIsolate;
-  v8::Global<v8::Context> m_pPersistentContext;
-  std::vector<v8::Global<v8::Object>*> m_StaticObjects;
+  std::unique_ptr<CFXJS_Engine> m_Engine;
 };
 
 #endif  // TESTING_JS_EMBEDDER_TEST_H_