Make CJS_Objects track CJS_Runtime (and hence the document itself)

Precursor to removing some more v8::Context slot dependency.

There's a cost to maintaining the set of observers, but since these
objects are tied to V8 lifetimes, not C++ lifetimes, we want to be
very wary of the document going away unexpectedly.

Change-Id: I579f58a460aa50b88cb861227c9aca9a8a83ce12
Reviewed-on: https://pdfium-review.googlesource.com/33471
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: dsinclair <dsinclair@chromium.org>
diff --git a/fxjs/JS_Define.h b/fxjs/JS_Define.h
index d9ab139..325642d 100644
--- a/fxjs/JS_Define.h
+++ b/fxjs/JS_Define.h
@@ -50,8 +50,8 @@
 
 template <class T>
 static void JSConstructor(CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
-  auto pObj = pdfium::MakeUnique<T>(obj);
-  pObj->InitInstance(static_cast<CJS_Runtime*>(pEngine));
+  auto pObj = pdfium::MakeUnique<T>(obj, static_cast<CJS_Runtime*>(pEngine));
+  pObj->InitInstance();
   pEngine->SetObjectPrivate(obj, std::move(pObj));
 }
 
diff --git a/fxjs/cfxjs_engine_unittest.cpp b/fxjs/cfxjs_engine_unittest.cpp
index 5b93072..64cd3a3 100644
--- a/fxjs/cfxjs_engine_unittest.cpp
+++ b/fxjs/cfxjs_engine_unittest.cpp
@@ -43,7 +43,7 @@
   engine()->DefineObj("perm", FXJSOBJTYPE_DYNAMIC,
                       [](CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
                         pEngine->SetObjectPrivate(
-                            obj, pdfium::MakeUnique<CJS_Object>(obj));
+                            obj, pdfium::MakeUnique<CJS_Object>(obj, nullptr));
                         perm_created = true;
                       },
                       [](v8::Local<v8::Object> obj) {
@@ -55,7 +55,7 @@
   engine()->DefineObj("temp", FXJSOBJTYPE_DYNAMIC,
                       [](CFXJS_Engine* pEngine, v8::Local<v8::Object> obj) {
                         pEngine->SetObjectPrivate(
-                            obj, pdfium::MakeUnique<CJS_Object>(obj));
+                            obj, pdfium::MakeUnique<CJS_Object>(obj, nullptr));
                         temp_created = true;
                       },
                       [](v8::Local<v8::Object> obj) {
diff --git a/fxjs/cjs_annot.cpp b/fxjs/cjs_annot.cpp
index fc38e11..4cb126d 100644
--- a/fxjs/cjs_annot.cpp
+++ b/fxjs/cjs_annot.cpp
@@ -40,7 +40,8 @@
   DefineProps(pEngine, ObjDefnID, PropertySpecs, FX_ArraySize(PropertySpecs));
 }
 
-CJS_Annot::CJS_Annot(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
+CJS_Annot::CJS_Annot(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_Annot::~CJS_Annot() = default;
 
diff --git a/fxjs/cjs_annot.h b/fxjs/cjs_annot.h
index bbcf4ac..cdb884f 100644
--- a/fxjs/cjs_annot.h
+++ b/fxjs/cjs_annot.h
@@ -15,7 +15,7 @@
   static int GetObjDefnID();
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Annot(v8::Local<v8::Object> pObject);
+  CJS_Annot(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_Annot() override;
 
   void SetSDKAnnot(CPDFSDK_BAAnnot* annot) { m_pAnnot.Reset(annot); }
diff --git a/fxjs/cjs_app.cpp b/fxjs/cjs_app.cpp
index 6c04c03..9ce8dc3 100644
--- a/fxjs/cjs_app.cpp
+++ b/fxjs/cjs_app.cpp
@@ -91,8 +91,8 @@
   DefineMethods(pEngine, ObjDefnID, MethodSpecs, FX_ArraySize(MethodSpecs));
 }
 
-CJS_App::CJS_App(v8::Local<v8::Object> pObject)
-    : CJS_Object(pObject), m_bCalculate(true), m_bRuntimeHighLight(false) {}
+CJS_App::CJS_App(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_App::~CJS_App() = default;
 
diff --git a/fxjs/cjs_app.h b/fxjs/cjs_app.h
index e195c6d..3c3a129 100644
--- a/fxjs/cjs_app.h
+++ b/fxjs/cjs_app.h
@@ -20,7 +20,7 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_App(v8::Local<v8::Object> pObject);
+  CJS_App(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_App() override;
 
   void TimerProc(GlobalTimer* pTimer);
@@ -153,8 +153,8 @@
   void RunJsScript(CJS_Runtime* pRuntime, const WideString& wsScript);
   void ClearTimerCommon(CJS_Runtime* pRuntime, v8::Local<v8::Value> param);
 
-  bool m_bCalculate;
-  bool m_bRuntimeHighLight;
+  bool m_bCalculate = true;
+  bool m_bRuntimeHighLight = false;
   std::set<std::unique_ptr<GlobalTimer>> m_Timers;
 };
 
diff --git a/fxjs/cjs_border.cpp b/fxjs/cjs_border.cpp
index 95693f4..77d527d 100644
--- a/fxjs/cjs_border.cpp
+++ b/fxjs/cjs_border.cpp
@@ -21,3 +21,8 @@
       pEngine->DefineObj("border", FXJSOBJTYPE_STATIC, nullptr, nullptr);
   DefineConsts(pEngine, ObjDefnID, ConstSpecs, FX_ArraySize(ConstSpecs));
 }
+
+CJS_Border::CJS_Border(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
+
+CJS_Border::~CJS_Border() = default;
diff --git a/fxjs/cjs_border.h b/fxjs/cjs_border.h
index b3fcef7..49e9325 100644
--- a/fxjs/cjs_border.h
+++ b/fxjs/cjs_border.h
@@ -13,8 +13,8 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Border(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Border() override {}
+  CJS_Border(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
+  ~CJS_Border() override;
 
  private:
   static int ObjDefnID;
diff --git a/fxjs/cjs_color.cpp b/fxjs/cjs_color.cpp
index a0cb02a..66cb972 100644
--- a/fxjs/cjs_color.cpp
+++ b/fxjs/cjs_color.cpp
@@ -121,8 +121,8 @@
   return CFX_Color();
 }
 
-CJS_Color::CJS_Color(v8::Local<v8::Object> pObject)
-    : CJS_Object(pObject),
+CJS_Color::CJS_Color(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime),
       m_crTransparent(CFX_Color::kTransparent),
       m_crBlack(CFX_Color::kGray, 0),
       m_crWhite(CFX_Color::kGray, 1),
diff --git a/fxjs/cjs_color.h b/fxjs/cjs_color.h
index 667a13c..00b9546 100644
--- a/fxjs/cjs_color.h
+++ b/fxjs/cjs_color.h
@@ -20,7 +20,7 @@
   static CFX_Color ConvertArrayToPWLColor(CJS_Runtime* pRuntime,
                                           v8::Local<v8::Array> array);
 
-  explicit CJS_Color(v8::Local<v8::Object> pObject);
+  CJS_Color(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_Color() override;
 
   JS_STATIC_PROP(black, black, CJS_Color);
diff --git a/fxjs/cjs_console.cpp b/fxjs/cjs_console.cpp
index 2b7c84a..8ed3472 100644
--- a/fxjs/cjs_console.cpp
+++ b/fxjs/cjs_console.cpp
@@ -28,7 +28,8 @@
   DefineMethods(pEngine, ObjDefnID, MethodSpecs, FX_ArraySize(MethodSpecs));
 }
 
-CJS_Console::CJS_Console(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
+CJS_Console::CJS_Console(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_Console::~CJS_Console() = default;
 
diff --git a/fxjs/cjs_console.h b/fxjs/cjs_console.h
index 56243cf..c25bc4b 100644
--- a/fxjs/cjs_console.h
+++ b/fxjs/cjs_console.h
@@ -15,7 +15,7 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Console(v8::Local<v8::Object> pObject);
+  CJS_Console(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_Console() override;
 
   JS_STATIC_METHOD(clear, CJS_Console);
diff --git a/fxjs/cjs_display.cpp b/fxjs/cjs_display.cpp
index 6970bfc..82f2f82 100644
--- a/fxjs/cjs_display.cpp
+++ b/fxjs/cjs_display.cpp
@@ -20,3 +20,8 @@
       pEngine->DefineObj("display", FXJSOBJTYPE_STATIC, nullptr, nullptr);
   DefineConsts(pEngine, ObjDefnID, ConstSpecs, FX_ArraySize(ConstSpecs));
 }
+
+CJS_Display::CJS_Display(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
+
+CJS_Display::~CJS_Display() = default;
diff --git a/fxjs/cjs_display.h b/fxjs/cjs_display.h
index 7b13c38..e5806b0 100644
--- a/fxjs/cjs_display.h
+++ b/fxjs/cjs_display.h
@@ -13,8 +13,8 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Display(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Display() override {}
+  CJS_Display(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
+  ~CJS_Display() override;
 
  private:
   static int ObjDefnID;
diff --git a/fxjs/cjs_document.cpp b/fxjs/cjs_document.cpp
index 533decf..3022519 100644
--- a/fxjs/cjs_document.cpp
+++ b/fxjs/cjs_document.cpp
@@ -123,16 +123,13 @@
   DefineMethods(pEngine, ObjDefnID, MethodSpecs, FX_ArraySize(MethodSpecs));
 }
 
-CJS_Document::CJS_Document(v8::Local<v8::Object> pObject)
-    : CJS_Object(pObject),
-      m_pFormFillEnv(nullptr),
-      m_cwBaseURL(L""),
-      m_bDelay(false) {}
+CJS_Document::CJS_Document(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_Document::~CJS_Document() = default;
 
-void CJS_Document::InitInstance(IJS_Runtime* pIRuntime) {
-  SetFormFillEnv(pIRuntime->GetFormFillEnv());
+void CJS_Document::InitInstance() {
+  SetFormFillEnv(GetRuntime()->GetFormFillEnv());
 }
 
 // The total number of fields in document.
diff --git a/fxjs/cjs_document.h b/fxjs/cjs_document.h
index 179b8ef..5172df0 100644
--- a/fxjs/cjs_document.h
+++ b/fxjs/cjs_document.h
@@ -23,11 +23,11 @@
   static int GetObjDefnID();
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Document(v8::Local<v8::Object> pObject);
+  CJS_Document(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_Document() override;
 
-  // CJS_Object
-  void InitInstance(IJS_Runtime* pIRuntime) override;
+  // CJS_Object:
+  void InitInstance() override;
 
   void SetFormFillEnv(CPDFSDK_FormFillEnvironment* pFormFillEnv);
   CPDFSDK_FormFillEnvironment* GetFormFillEnv() const {
@@ -312,12 +312,12 @@
                                  v8::Local<v8::Value> vp,
                                  const ByteString& propName);
 
-  CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
   WideString m_cwBaseURL;
+  CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
   std::list<std::unique_ptr<CJS_DelayData>> m_DelayData;
   // Needs to be a std::list for iterator stability.
   std::list<WideString> m_IconNames;
-  bool m_bDelay;
+  bool m_bDelay = false;
 };
 
 #endif  // FXJS_CJS_DOCUMENT_H_
diff --git a/fxjs/cjs_event.cpp b/fxjs/cjs_event.cpp
index 341bcc4..d2537b9 100644
--- a/fxjs/cjs_event.cpp
+++ b/fxjs/cjs_event.cpp
@@ -44,7 +44,8 @@
   DefineProps(pEngine, ObjDefnID, PropertySpecs, FX_ArraySize(PropertySpecs));
 }
 
-CJS_Event::CJS_Event(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
+CJS_Event::CJS_Event(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_Event::~CJS_Event() = default;
 
diff --git a/fxjs/cjs_event.h b/fxjs/cjs_event.h
index 291b6eb..434f259 100644
--- a/fxjs/cjs_event.h
+++ b/fxjs/cjs_event.h
@@ -13,7 +13,7 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Event(v8::Local<v8::Object> pObject);
+  CJS_Event(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_Event() override;
 
   JS_STATIC_PROP(change, change, CJS_Event);
diff --git a/fxjs/cjs_field.cpp b/fxjs/cjs_field.cpp
index 1e9e389..b9bc8cb 100644
--- a/fxjs/cjs_field.cpp
+++ b/fxjs/cjs_field.cpp
@@ -171,18 +171,11 @@
   DefineMethods(pEngine, ObjDefnID, MethodSpecs, FX_ArraySize(MethodSpecs));
 }
 
-CJS_Field::CJS_Field(v8::Local<v8::Object> pObject)
-    : CJS_Object(pObject),
-      m_pJSDoc(nullptr),
-      m_pFormFillEnv(nullptr),
-      m_nFormControlIndex(-1),
-      m_bCanSet(false),
-      m_bDelay(false) {}
+CJS_Field::CJS_Field(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_Field::~CJS_Field() = default;
 
-void CJS_Field::InitInstance(IJS_Runtime* pIRuntime) {}
-
 // note: iControlNo = -1, means not a widget.
 void CJS_Field::ParseFieldName(const std::wstring& strFieldNameParsed,
                                std::wstring& strFieldName,
diff --git a/fxjs/cjs_field.h b/fxjs/cjs_field.h
index 51cc530..ba47613 100644
--- a/fxjs/cjs_field.h
+++ b/fxjs/cjs_field.h
@@ -34,12 +34,9 @@
   static void DoDelay(CPDFSDK_FormFillEnvironment* pFormFillEnv,
                       CJS_DelayData* pData);
 
-  explicit CJS_Field(v8::Local<v8::Object> pObject);
+  CJS_Field(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_Field() override;
 
-  // CJS_Object
-  void InitInstance(IJS_Runtime* pIRuntime) override;
-
   bool AttachField(CJS_Document* pDocument, const WideString& csFieldName);
 
   JS_STATIC_PROP(alignment, alignment, CJS_Field);
@@ -421,12 +418,12 @@
 
   void DoDelay();
 
-  CJS_Document* m_pJSDoc;
+  CJS_Document* m_pJSDoc = nullptr;
   CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
   WideString m_FieldName;
-  int m_nFormControlIndex;
-  bool m_bCanSet;
-  bool m_bDelay;
+  int m_nFormControlIndex = -1;
+  bool m_bCanSet = false;
+  bool m_bDelay = false;
 };
 
 #endif  // FXJS_CJS_FIELD_H_
diff --git a/fxjs/cjs_font.cpp b/fxjs/cjs_font.cpp
index 54b392f..4d18eea 100644
--- a/fxjs/cjs_font.cpp
+++ b/fxjs/cjs_font.cpp
@@ -29,3 +29,8 @@
   ObjDefnID = pEngine->DefineObj("font", FXJSOBJTYPE_STATIC, nullptr, nullptr);
   DefineConsts(pEngine, ObjDefnID, ConstSpecs, FX_ArraySize(ConstSpecs));
 }
+
+CJS_Font::CJS_Font(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
+
+CJS_Font::~CJS_Font() = default;
diff --git a/fxjs/cjs_font.h b/fxjs/cjs_font.h
index 31edf06..8e52778 100644
--- a/fxjs/cjs_font.h
+++ b/fxjs/cjs_font.h
@@ -13,8 +13,8 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Font(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Font() override {}
+  CJS_Font(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
+  ~CJS_Font() override;
 
  private:
   static int ObjDefnID;
diff --git a/fxjs/cjs_global.cpp b/fxjs/cjs_global.cpp
index 282b262..2a91bdd 100644
--- a/fxjs/cjs_global.cpp
+++ b/fxjs/cjs_global.cpp
@@ -205,16 +205,16 @@
   DefineAllProperties(pEngine);
 }
 
-CJS_Global::CJS_Global(v8::Local<v8::Object> pObject)
-    : CJS_Object(pObject), m_pFormFillEnv(nullptr) {}
+CJS_Global::CJS_Global(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_Global::~CJS_Global() {
   DestroyGlobalPersisitentVariables();
   m_pGlobalData->Release();
 }
 
-void CJS_Global::InitInstance(IJS_Runtime* pIRuntime) {
-  Initial(pIRuntime->GetFormFillEnv());
+void CJS_Global::InitInstance() {
+  Initial(GetRuntime()->GetFormFillEnv());
 }
 
 void CJS_Global::Initial(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
diff --git a/fxjs/cjs_global.h b/fxjs/cjs_global.h
index 15ef603..8a2fdab 100644
--- a/fxjs/cjs_global.h
+++ b/fxjs/cjs_global.h
@@ -35,11 +35,11 @@
   static void setPersistent_static(
       const v8::FunctionCallbackInfo<v8::Value>& info);
 
-  explicit CJS_Global(v8::Local<v8::Object> pObject);
+  CJS_Global(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_Global() override;
 
-  // CJS_Object
-  void InitInstance(IJS_Runtime* pIRuntime) override;
+  // CJS_Object:
+  void InitInstance() override;
 
   CJS_Return DelProperty(CJS_Runtime* pRuntime, const wchar_t* propname);
   void Initial(CPDFSDK_FormFillEnvironment* pFormFillEnv);
diff --git a/fxjs/cjs_highlight.cpp b/fxjs/cjs_highlight.cpp
index e60a5a8..c77a80d 100644
--- a/fxjs/cjs_highlight.cpp
+++ b/fxjs/cjs_highlight.cpp
@@ -20,3 +20,9 @@
       pEngine->DefineObj("highlight", FXJSOBJTYPE_STATIC, nullptr, nullptr);
   DefineConsts(pEngine, ObjDefnID, ConstSpecs, FX_ArraySize(ConstSpecs));
 }
+
+CJS_Highlight::CJS_Highlight(v8::Local<v8::Object> pObject,
+                             CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
+
+CJS_Highlight::~CJS_Highlight() = default;
diff --git a/fxjs/cjs_highlight.h b/fxjs/cjs_highlight.h
index 74091d3..2815c88 100644
--- a/fxjs/cjs_highlight.h
+++ b/fxjs/cjs_highlight.h
@@ -13,8 +13,8 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Highlight(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Highlight() override {}
+  CJS_Highlight(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
+  ~CJS_Highlight() override;
 
  private:
   static int ObjDefnID;
diff --git a/fxjs/cjs_icon.cpp b/fxjs/cjs_icon.cpp
index 40a2936..786d19c 100644
--- a/fxjs/cjs_icon.cpp
+++ b/fxjs/cjs_icon.cpp
@@ -24,8 +24,8 @@
   DefineProps(pEngine, ObjDefnID, PropertySpecs, FX_ArraySize(PropertySpecs));
 }
 
-CJS_Icon::CJS_Icon(v8::Local<v8::Object> pObject)
-    : CJS_Object(pObject), m_swIconName(L"") {}
+CJS_Icon::CJS_Icon(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_Icon::~CJS_Icon() = default;
 
diff --git a/fxjs/cjs_icon.h b/fxjs/cjs_icon.h
index a346d69..2f3ee3f 100644
--- a/fxjs/cjs_icon.h
+++ b/fxjs/cjs_icon.h
@@ -14,7 +14,7 @@
   static int GetObjDefnID();
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Icon(v8::Local<v8::Object> pObject);
+  CJS_Icon(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_Icon() override;
 
   WideString GetIconName() const { return m_swIconName; }
diff --git a/fxjs/cjs_object.cpp b/fxjs/cjs_object.cpp
index a1e5ce1..62fa421 100644
--- a/fxjs/cjs_object.cpp
+++ b/fxjs/cjs_object.cpp
@@ -40,11 +40,11 @@
     pEngine->DefineObjMethod(objId, methods[i].pName, methods[i].pMethodCall);
 }
 
-CJS_Object::CJS_Object(v8::Local<v8::Object> pObject) {
-  m_pIsolate = pObject->GetIsolate();
-  m_pV8Object.Reset(m_pIsolate, pObject);
-}
+CJS_Object::CJS_Object(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : m_pIsolate(pObject->GetIsolate()),
+      m_pV8Object(GetIsolate(), pObject),
+      m_pRuntime(pRuntime) {}
 
 CJS_Object::~CJS_Object() {}
 
-void CJS_Object::InitInstance(IJS_Runtime* pIRuntime) {}
+void CJS_Object::InitInstance() {}
diff --git a/fxjs/cjs_object.h b/fxjs/cjs_object.h
index 8254af9..c33fd77 100644
--- a/fxjs/cjs_object.h
+++ b/fxjs/cjs_object.h
@@ -10,6 +10,7 @@
 #include <memory>
 #include <utility>
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "fpdfsdk/cpdfsdk_helpers.h"
 #include "fxjs/cfxjs_engine.h"
 #include "fxjs/cjs_runtime.h"
@@ -49,17 +50,19 @@
                             const JSMethodSpec methods[],
                             size_t count);
 
-  explicit CJS_Object(v8::Local<v8::Object> pObject);
+  CJS_Object(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   virtual ~CJS_Object();
 
-  virtual void InitInstance(IJS_Runtime* pIRuntime);
+  virtual void InitInstance();
 
-  v8::Local<v8::Object> ToV8Object() { return m_pV8Object.Get(m_pIsolate); }
-  v8::Isolate* GetIsolate() const { return m_pIsolate; }
+  v8::Local<v8::Object> ToV8Object() { return m_pV8Object.Get(GetIsolate()); }
+  v8::Isolate* GetIsolate() const { return m_pIsolate.Get(); }
+  CJS_Runtime* GetRuntime() const { return m_pRuntime.Get(); }
 
- protected:
+ private:
+  UnownedPtr<v8::Isolate> m_pIsolate;
   v8::Global<v8::Object> m_pV8Object;
-  v8::Isolate* m_pIsolate;
+  CJS_Runtime::ObservedPtr m_pRuntime;
 };
 
 #endif  // FXJS_CJS_OBJECT_H_
diff --git a/fxjs/cjs_position.cpp b/fxjs/cjs_position.cpp
index 16e4ab0..0e1fa66 100644
--- a/fxjs/cjs_position.cpp
+++ b/fxjs/cjs_position.cpp
@@ -23,3 +23,8 @@
       pEngine->DefineObj("position", FXJSOBJTYPE_STATIC, nullptr, nullptr);
   DefineConsts(pEngine, ObjDefnID, ConstSpecs, FX_ArraySize(ConstSpecs));
 }
+
+CJS_Position::CJS_Position(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
+
+CJS_Position::~CJS_Position() = default;
diff --git a/fxjs/cjs_position.h b/fxjs/cjs_position.h
index 7557f01..0f54c2b 100644
--- a/fxjs/cjs_position.h
+++ b/fxjs/cjs_position.h
@@ -13,8 +13,8 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Position(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Position() override {}
+  CJS_Position(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
+  ~CJS_Position() override;
 
  private:
   static int ObjDefnID;
diff --git a/fxjs/cjs_printparamsobj.cpp b/fxjs/cjs_printparamsobj.cpp
index b85925d..7cb32de 100644
--- a/fxjs/cjs_printparamsobj.cpp
+++ b/fxjs/cjs_printparamsobj.cpp
@@ -20,7 +20,8 @@
                          JSConstructor<CJS_PrintParamsObj>, JSDestructor);
 }
 
-CJS_PrintParamsObj::CJS_PrintParamsObj(v8::Local<v8::Object> pObject)
-    : CJS_Object(pObject) {}
+CJS_PrintParamsObj::CJS_PrintParamsObj(v8::Local<v8::Object> pObject,
+                                       CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_PrintParamsObj::~CJS_PrintParamsObj() = default;
diff --git a/fxjs/cjs_printparamsobj.h b/fxjs/cjs_printparamsobj.h
index 97028dd..90bc9b8 100644
--- a/fxjs/cjs_printparamsobj.h
+++ b/fxjs/cjs_printparamsobj.h
@@ -14,7 +14,7 @@
   static int GetObjDefnID();
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_PrintParamsObj(v8::Local<v8::Object> pObject);
+  CJS_PrintParamsObj(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_PrintParamsObj() override;
 
   bool GetUI() const { return bUI; }
diff --git a/fxjs/cjs_publicmethods.cpp b/fxjs/cjs_publicmethods.cpp
index 6f49940..b8d62b1 100644
--- a/fxjs/cjs_publicmethods.cpp
+++ b/fxjs/cjs_publicmethods.cpp
@@ -205,10 +205,11 @@
 
 }  // namespace
 
-CJS_PublicMethods::CJS_PublicMethods(v8::Local<v8::Object> pObject)
-    : CJS_Object(pObject) {}
+CJS_PublicMethods::CJS_PublicMethods(v8::Local<v8::Object> pObject,
+                                     CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
-CJS_PublicMethods::~CJS_PublicMethods() {}
+CJS_PublicMethods::~CJS_PublicMethods() = default;
 
 // static
 void CJS_PublicMethods::DefineJSObjects(CFXJS_Engine* pEngine) {
diff --git a/fxjs/cjs_publicmethods.h b/fxjs/cjs_publicmethods.h
index 8726996..df23eb1 100644
--- a/fxjs/cjs_publicmethods.h
+++ b/fxjs/cjs_publicmethods.h
@@ -14,7 +14,7 @@
 
 class CJS_PublicMethods : public CJS_Object {
  public:
-  explicit CJS_PublicMethods(v8::Local<v8::Object> pObject);
+  CJS_PublicMethods(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_PublicMethods() override;
 
   static void DefineJSObjects(CFXJS_Engine* pEngine);
diff --git a/fxjs/cjs_report.cpp b/fxjs/cjs_report.cpp
index 2f5490c..89737e6 100644
--- a/fxjs/cjs_report.cpp
+++ b/fxjs/cjs_report.cpp
@@ -25,7 +25,8 @@
   DefineMethods(pEngine, ObjDefnID, MethodSpecs, FX_ArraySize(MethodSpecs));
 }
 
-CJS_Report::CJS_Report(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
+CJS_Report::CJS_Report(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_Report::~CJS_Report() = default;
 
diff --git a/fxjs/cjs_report.h b/fxjs/cjs_report.h
index 2a59206..8de0991 100644
--- a/fxjs/cjs_report.h
+++ b/fxjs/cjs_report.h
@@ -15,7 +15,7 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine, FXJSOBJTYPE eObjType);
 
-  explicit CJS_Report(v8::Local<v8::Object> pObject);
+  CJS_Report(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_Report() override;
 
   JS_STATIC_METHOD(save, CJS_Report);
diff --git a/fxjs/cjs_scalehow.cpp b/fxjs/cjs_scalehow.cpp
index 762863b..a29aa38 100644
--- a/fxjs/cjs_scalehow.cpp
+++ b/fxjs/cjs_scalehow.cpp
@@ -18,3 +18,8 @@
       pEngine->DefineObj("scaleHow", FXJSOBJTYPE_STATIC, nullptr, nullptr);
   DefineConsts(pEngine, ObjDefnID, ConstSpecs, FX_ArraySize(ConstSpecs));
 }
+
+CJS_ScaleHow::CJS_ScaleHow(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
+
+CJS_ScaleHow::~CJS_ScaleHow() = default;
diff --git a/fxjs/cjs_scalehow.h b/fxjs/cjs_scalehow.h
index 8177a3e..bbff20a 100644
--- a/fxjs/cjs_scalehow.h
+++ b/fxjs/cjs_scalehow.h
@@ -13,8 +13,8 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_ScaleHow(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_ScaleHow() override {}
+  CJS_ScaleHow(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
+  ~CJS_ScaleHow() override;
 
  private:
   static int ObjDefnID;
diff --git a/fxjs/cjs_scalewhen.cpp b/fxjs/cjs_scalewhen.cpp
index 59f0487..33f13cb 100644
--- a/fxjs/cjs_scalewhen.cpp
+++ b/fxjs/cjs_scalewhen.cpp
@@ -20,3 +20,9 @@
       pEngine->DefineObj("scaleWhen", FXJSOBJTYPE_STATIC, nullptr, nullptr);
   DefineConsts(pEngine, ObjDefnID, ConstSpecs, FX_ArraySize(ConstSpecs));
 }
+
+CJS_ScaleWhen::CJS_ScaleWhen(v8::Local<v8::Object> pObject,
+                             CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
+
+CJS_ScaleWhen::~CJS_ScaleWhen() = default;
diff --git a/fxjs/cjs_scalewhen.h b/fxjs/cjs_scalewhen.h
index e97a285..d068a38 100644
--- a/fxjs/cjs_scalewhen.h
+++ b/fxjs/cjs_scalewhen.h
@@ -13,8 +13,8 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_ScaleWhen(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_ScaleWhen() override {}
+  CJS_ScaleWhen(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
+  ~CJS_ScaleWhen() override;
 
  private:
   static int ObjDefnID;
diff --git a/fxjs/cjs_style.cpp b/fxjs/cjs_style.cpp
index be95e9a..2a172c9 100644
--- a/fxjs/cjs_style.cpp
+++ b/fxjs/cjs_style.cpp
@@ -21,3 +21,8 @@
   ObjDefnID = pEngine->DefineObj("style", FXJSOBJTYPE_STATIC, nullptr, nullptr);
   DefineConsts(pEngine, ObjDefnID, ConstSpecs, FX_ArraySize(ConstSpecs));
 }
+
+CJS_Style::CJS_Style(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
+
+CJS_Style::~CJS_Style() = default;
diff --git a/fxjs/cjs_style.h b/fxjs/cjs_style.h
index 46ab66b..ba7eefa 100644
--- a/fxjs/cjs_style.h
+++ b/fxjs/cjs_style.h
@@ -13,8 +13,8 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Style(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Style() override {}
+  CJS_Style(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
+  ~CJS_Style() override;
 
  private:
   static int ObjDefnID;
diff --git a/fxjs/cjs_timerobj.cpp b/fxjs/cjs_timerobj.cpp
index 59d3842..f11d3fd 100644
--- a/fxjs/cjs_timerobj.cpp
+++ b/fxjs/cjs_timerobj.cpp
@@ -21,8 +21,8 @@
                                  JSConstructor<CJS_TimerObj>, JSDestructor);
 }
 
-CJS_TimerObj::CJS_TimerObj(v8::Local<v8::Object> pObject)
-    : CJS_Object(pObject), m_nTimerID(0) {}
+CJS_TimerObj::CJS_TimerObj(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_TimerObj::~CJS_TimerObj() = default;
 
diff --git a/fxjs/cjs_timerobj.h b/fxjs/cjs_timerobj.h
index edc3def..810b1b3 100644
--- a/fxjs/cjs_timerobj.h
+++ b/fxjs/cjs_timerobj.h
@@ -16,7 +16,7 @@
   static int GetObjDefnID();
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_TimerObj(v8::Local<v8::Object> pObject);
+  CJS_TimerObj(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_TimerObj() override;
 
   void SetTimer(GlobalTimer* pTimer);
@@ -25,7 +25,7 @@
  private:
   static int ObjDefnID;
 
-  int m_nTimerID;  // Weak reference to GlobalTimer through global map.
+  int m_nTimerID = 0;  // Weak reference to GlobalTimer through global map.
 };
 
 #endif  // FXJS_CJS_TIMEROBJ_H_
diff --git a/fxjs/cjs_util.cpp b/fxjs/cjs_util.cpp
index 883d022..ee96395 100644
--- a/fxjs/cjs_util.cpp
+++ b/fxjs/cjs_util.cpp
@@ -74,7 +74,8 @@
   DefineMethods(pEngine, ObjDefnID, MethodSpecs, FX_ArraySize(MethodSpecs));
 }
 
-CJS_Util::CJS_Util(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
+CJS_Util::CJS_Util(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
 
 CJS_Util::~CJS_Util() = default;
 
diff --git a/fxjs/cjs_util.h b/fxjs/cjs_util.h
index 0ad0fa1..03e1b08 100644
--- a/fxjs/cjs_util.h
+++ b/fxjs/cjs_util.h
@@ -21,7 +21,7 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Util(v8::Local<v8::Object> pObject);
+  CJS_Util(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
   ~CJS_Util() override;
 
   static WideString printx(const WideString& cFormat,
diff --git a/fxjs/cjs_zoomtype.cpp b/fxjs/cjs_zoomtype.cpp
index 528bba0..af56732 100644
--- a/fxjs/cjs_zoomtype.cpp
+++ b/fxjs/cjs_zoomtype.cpp
@@ -23,3 +23,8 @@
       pEngine->DefineObj("zoomtype", FXJSOBJTYPE_STATIC, nullptr, nullptr);
   DefineConsts(pEngine, ObjDefnID, ConstSpecs, FX_ArraySize(ConstSpecs));
 }
+
+CJS_Zoomtype::CJS_Zoomtype(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
+    : CJS_Object(pObject, pRuntime) {}
+
+CJS_Zoomtype::~CJS_Zoomtype() = default;
diff --git a/fxjs/cjs_zoomtype.h b/fxjs/cjs_zoomtype.h
index 14db0a4..a5f6fda 100644
--- a/fxjs/cjs_zoomtype.h
+++ b/fxjs/cjs_zoomtype.h
@@ -13,8 +13,8 @@
  public:
   static void DefineJSObjects(CFXJS_Engine* pEngine);
 
-  explicit CJS_Zoomtype(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {}
-  ~CJS_Zoomtype() override {}
+  CJS_Zoomtype(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime);
+  ~CJS_Zoomtype() override;
 
  private:
   static int ObjDefnID;