Home | History | Annotate | Download | only in fxjs
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "fxjs/fxjs_v8.h"
      8 
      9 #include <vector>
     10 
     11 #include "third_party/base/allocator/partition_allocator/partition_alloc.h"
     12 
     13 // Keep this consistent with the values defined in gin/public/context_holder.h
     14 // (without actually requiring a dependency on gin itself for the standalone
     15 // embedders of PDFIum). The value we want to use is:
     16 //   kPerContextDataStartIndex + kEmbedderPDFium, which is 3.
     17 static const unsigned int kPerContextDataIndex = 3u;
     18 static unsigned int g_embedderDataSlot = 1u;
     19 static v8::Isolate* g_isolate = nullptr;
     20 static size_t g_isolate_ref_count = 0;
     21 static FXJS_ArrayBufferAllocator* g_arrayBufferAllocator = nullptr;
     22 static v8::Global<v8::ObjectTemplate>* g_DefaultGlobalObjectTemplate = nullptr;
     23 static wchar_t kPerObjectDataTag[] = L"CFXJS_PerObjectData";
     24 
     25 class CFXJS_PerObjectData {
     26  public:
     27   explicit CFXJS_PerObjectData(int nObjDefID)
     28       : m_ObjDefID(nObjDefID), m_pPrivate(nullptr) {}
     29 
     30   static void SetInObject(CFXJS_PerObjectData* pData,
     31                           v8::Local<v8::Object> pObj) {
     32     if (pObj->InternalFieldCount() == 2) {
     33       pObj->SetAlignedPointerInInternalField(0, pData);
     34       pObj->SetAlignedPointerInInternalField(
     35           1, static_cast<void*>(kPerObjectDataTag));
     36     }
     37   }
     38 
     39   static CFXJS_PerObjectData* GetFromObject(v8::Local<v8::Object> pObj) {
     40     if (pObj.IsEmpty() || pObj->InternalFieldCount() != 2 ||
     41         pObj->GetAlignedPointerFromInternalField(1) !=
     42             static_cast<void*>(kPerObjectDataTag)) {
     43       return nullptr;
     44     }
     45     return static_cast<CFXJS_PerObjectData*>(
     46         pObj->GetAlignedPointerFromInternalField(0));
     47   }
     48 
     49   const int m_ObjDefID;
     50   void* m_pPrivate;
     51 };
     52 
     53 class CFXJS_ObjDefinition {
     54  public:
     55   static int MaxID(v8::Isolate* pIsolate) {
     56     return FXJS_PerIsolateData::Get(pIsolate)->m_ObjectDefnArray.size();
     57   }
     58 
     59   static CFXJS_ObjDefinition* ForID(v8::Isolate* pIsolate, int id) {
     60     // Note: GetAt() halts if out-of-range even in release builds.
     61     return FXJS_PerIsolateData::Get(pIsolate)->m_ObjectDefnArray[id].get();
     62   }
     63 
     64   CFXJS_ObjDefinition(v8::Isolate* isolate,
     65                       const char* sObjName,
     66                       FXJSOBJTYPE eObjType,
     67                       CFXJS_Engine::Constructor pConstructor,
     68                       CFXJS_Engine::Destructor pDestructor)
     69       : m_ObjName(sObjName),
     70         m_ObjType(eObjType),
     71         m_pConstructor(pConstructor),
     72         m_pDestructor(pDestructor),
     73         m_pIsolate(isolate) {
     74     v8::Isolate::Scope isolate_scope(isolate);
     75     v8::HandleScope handle_scope(isolate);
     76 
     77     v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
     78     fun->InstanceTemplate()->SetInternalFieldCount(2);
     79     fun->SetCallHandler([](const v8::FunctionCallbackInfo<v8::Value>& info) {
     80       v8::Local<v8::Object> holder = info.Holder();
     81       ASSERT(holder->InternalFieldCount() == 2);
     82       holder->SetAlignedPointerInInternalField(0, nullptr);
     83       holder->SetAlignedPointerInInternalField(1, nullptr);
     84     });
     85     if (eObjType == FXJSOBJTYPE_GLOBAL) {
     86       fun->InstanceTemplate()->Set(
     87           v8::Symbol::GetToStringTag(isolate),
     88           v8::String::NewFromUtf8(isolate, "global", v8::NewStringType::kNormal)
     89               .ToLocalChecked());
     90     }
     91     m_FunctionTemplate.Reset(isolate, fun);
     92 
     93     v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun);
     94     m_Signature.Reset(isolate, sig);
     95   }
     96 
     97   int AssignID() {
     98     FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(m_pIsolate);
     99     pData->m_ObjectDefnArray.emplace_back(this);
    100     return pData->m_ObjectDefnArray.size() - 1;
    101   }
    102 
    103   v8::Local<v8::ObjectTemplate> GetInstanceTemplate() {
    104     v8::EscapableHandleScope scope(m_pIsolate);
    105     v8::Local<v8::FunctionTemplate> function =
    106         m_FunctionTemplate.Get(m_pIsolate);
    107     return scope.Escape(function->InstanceTemplate());
    108   }
    109 
    110   v8::Local<v8::Signature> GetSignature() {
    111     v8::EscapableHandleScope scope(m_pIsolate);
    112     return scope.Escape(m_Signature.Get(m_pIsolate));
    113   }
    114 
    115   const char* const m_ObjName;
    116   const FXJSOBJTYPE m_ObjType;
    117   const CFXJS_Engine::Constructor m_pConstructor;
    118   const CFXJS_Engine::Destructor m_pDestructor;
    119 
    120   v8::Isolate* m_pIsolate;
    121   v8::Global<v8::FunctionTemplate> m_FunctionTemplate;
    122   v8::Global<v8::Signature> m_Signature;
    123 };
    124 
    125 static v8::Local<v8::ObjectTemplate> GetGlobalObjectTemplate(
    126     v8::Isolate* pIsolate) {
    127   int maxID = CFXJS_ObjDefinition::MaxID(pIsolate);
    128   for (int i = 0; i < maxID; ++i) {
    129     CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, i);
    130     if (pObjDef->m_ObjType == FXJSOBJTYPE_GLOBAL)
    131       return pObjDef->GetInstanceTemplate();
    132   }
    133   if (!g_DefaultGlobalObjectTemplate) {
    134     v8::Local<v8::ObjectTemplate> hGlobalTemplate =
    135         v8::ObjectTemplate::New(pIsolate);
    136     hGlobalTemplate->Set(
    137         v8::Symbol::GetToStringTag(pIsolate),
    138         v8::String::NewFromUtf8(pIsolate, "global", v8::NewStringType::kNormal)
    139             .ToLocalChecked());
    140     g_DefaultGlobalObjectTemplate =
    141         new v8::Global<v8::ObjectTemplate>(pIsolate, hGlobalTemplate);
    142   }
    143   return g_DefaultGlobalObjectTemplate->Get(pIsolate);
    144 }
    145 
    146 void* FXJS_ArrayBufferAllocator::Allocate(size_t length) {
    147   if (length > kMaxAllowedBytes)
    148     return nullptr;
    149   void* p = AllocateUninitialized(length);
    150   if (p)
    151     memset(p, 0, length);
    152   return p;
    153 }
    154 
    155 void* FXJS_ArrayBufferAllocator::AllocateUninitialized(size_t length) {
    156   if (length > kMaxAllowedBytes)
    157     return nullptr;
    158   return pdfium::base::PartitionAllocGeneric(
    159       gArrayBufferPartitionAllocator.root(), length, "FXJS_ArrayBuffer");
    160 }
    161 
    162 void FXJS_ArrayBufferAllocator::Free(void* data, size_t length) {
    163   pdfium::base::PartitionFreeGeneric(gArrayBufferPartitionAllocator.root(),
    164                                      data);
    165 }
    166 
    167 void V8TemplateMapTraits::Dispose(v8::Isolate* isolate,
    168                                   v8::Global<v8::Object> value,
    169                                   void* key) {
    170   v8::Local<v8::Object> obj = value.Get(isolate);
    171   if (obj.IsEmpty())
    172     return;
    173   int id = CFXJS_Engine::GetObjDefnID(obj);
    174   if (id == -1)
    175     return;
    176   CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(isolate, id);
    177   if (!pObjDef)
    178     return;
    179   if (pObjDef->m_pDestructor) {
    180     pObjDef->m_pDestructor(CFXJS_Engine::CurrentEngineFromIsolate(isolate),
    181                            obj);
    182   }
    183   CFXJS_Engine::FreeObjectPrivate(obj);
    184 }
    185 
    186 V8TemplateMapTraits::MapType* V8TemplateMapTraits::MapFromWeakCallbackInfo(
    187     const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
    188   V8TemplateMap* pMap =
    189       (FXJS_PerIsolateData::Get(data.GetIsolate()))->m_pDynamicObjsMap.get();
    190   return pMap ? &pMap->m_map : nullptr;
    191 }
    192 
    193 void FXJS_Initialize(unsigned int embedderDataSlot, v8::Isolate* pIsolate) {
    194   if (g_isolate) {
    195     ASSERT(g_embedderDataSlot == embedderDataSlot);
    196     ASSERT(g_isolate == pIsolate);
    197     return;
    198   }
    199   g_embedderDataSlot = embedderDataSlot;
    200   g_isolate = pIsolate;
    201 }
    202 
    203 void FXJS_Release() {
    204   ASSERT(!g_isolate || g_isolate_ref_count == 0);
    205   delete g_DefaultGlobalObjectTemplate;
    206   g_DefaultGlobalObjectTemplate = nullptr;
    207   g_isolate = nullptr;
    208 
    209   delete g_arrayBufferAllocator;
    210   g_arrayBufferAllocator = nullptr;
    211 }
    212 
    213 bool FXJS_GetIsolate(v8::Isolate** pResultIsolate) {
    214   if (g_isolate) {
    215     *pResultIsolate = g_isolate;
    216     return false;
    217   }
    218   // Provide backwards compatibility when no external isolate.
    219   if (!g_arrayBufferAllocator)
    220     g_arrayBufferAllocator = new FXJS_ArrayBufferAllocator();
    221   v8::Isolate::CreateParams params;
    222   params.array_buffer_allocator = g_arrayBufferAllocator;
    223   *pResultIsolate = v8::Isolate::New(params);
    224   return true;
    225 }
    226 
    227 size_t FXJS_GlobalIsolateRefCount() {
    228   return g_isolate_ref_count;
    229 }
    230 
    231 V8TemplateMap::V8TemplateMap(v8::Isolate* isolate) : m_map(isolate) {}
    232 
    233 V8TemplateMap::~V8TemplateMap() {}
    234 
    235 void V8TemplateMap::set(void* key, v8::Local<v8::Object> handle) {
    236   ASSERT(!m_map.Contains(key));
    237   m_map.Set(key, handle);
    238 }
    239 
    240 FXJS_PerIsolateData::~FXJS_PerIsolateData() {}
    241 
    242 // static
    243 void FXJS_PerIsolateData::SetUp(v8::Isolate* pIsolate) {
    244   if (!pIsolate->GetData(g_embedderDataSlot))
    245     pIsolate->SetData(g_embedderDataSlot, new FXJS_PerIsolateData(pIsolate));
    246 }
    247 
    248 // static
    249 FXJS_PerIsolateData* FXJS_PerIsolateData::Get(v8::Isolate* pIsolate) {
    250   return static_cast<FXJS_PerIsolateData*>(
    251       pIsolate->GetData(g_embedderDataSlot));
    252 }
    253 
    254 FXJS_PerIsolateData::FXJS_PerIsolateData(v8::Isolate* pIsolate)
    255     : m_pDynamicObjsMap(new V8TemplateMap(pIsolate)) {}
    256 
    257 CFXJS_Engine::CFXJS_Engine() : CJS_V8(nullptr) {}
    258 
    259 CFXJS_Engine::CFXJS_Engine(v8::Isolate* pIsolate) : CJS_V8(pIsolate) {}
    260 
    261 CFXJS_Engine::~CFXJS_Engine() = default;
    262 
    263 // static
    264 CFXJS_Engine* CFXJS_Engine::CurrentEngineFromIsolate(v8::Isolate* pIsolate) {
    265   return static_cast<CFXJS_Engine*>(
    266       pIsolate->GetCurrentContext()->GetAlignedPointerFromEmbedderData(
    267           kPerContextDataIndex));
    268 }
    269 
    270 // static
    271 int CFXJS_Engine::GetObjDefnID(v8::Local<v8::Object> pObj) {
    272   CFXJS_PerObjectData* pData = CFXJS_PerObjectData::GetFromObject(pObj);
    273   return pData ? pData->m_ObjDefID : -1;
    274 }
    275 
    276 // static
    277 void CFXJS_Engine::FreeObjectPrivate(void* pPerObjectData) {
    278   delete static_cast<CFXJS_PerObjectData*>(pPerObjectData);
    279 }
    280 
    281 // static
    282 void CFXJS_Engine::FreeObjectPrivate(v8::Local<v8::Object> pObj) {
    283   CFXJS_PerObjectData* pData = CFXJS_PerObjectData::GetFromObject(pObj);
    284   pObj->SetAlignedPointerInInternalField(0, nullptr);
    285   pObj->SetAlignedPointerInInternalField(1, nullptr);
    286   delete pData;
    287 }
    288 
    289 int CFXJS_Engine::DefineObj(const char* sObjName,
    290                             FXJSOBJTYPE eObjType,
    291                             CFXJS_Engine::Constructor pConstructor,
    292                             CFXJS_Engine::Destructor pDestructor) {
    293   v8::Isolate::Scope isolate_scope(GetIsolate());
    294   v8::HandleScope handle_scope(GetIsolate());
    295   FXJS_PerIsolateData::SetUp(GetIsolate());
    296   CFXJS_ObjDefinition* pObjDef = new CFXJS_ObjDefinition(
    297       GetIsolate(), sObjName, eObjType, pConstructor, pDestructor);
    298   return pObjDef->AssignID();
    299 }
    300 
    301 void CFXJS_Engine::DefineObjMethod(int nObjDefnID,
    302                                    const char* sMethodName,
    303                                    v8::FunctionCallback pMethodCall) {
    304   v8::Isolate::Scope isolate_scope(GetIsolate());
    305   v8::HandleScope handle_scope(GetIsolate());
    306   CFXJS_ObjDefinition* pObjDef =
    307       CFXJS_ObjDefinition::ForID(GetIsolate(), nObjDefnID);
    308   v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(
    309       GetIsolate(), pMethodCall, v8::Local<v8::Value>(),
    310       pObjDef->GetSignature());
    311   fun->RemovePrototype();
    312   pObjDef->GetInstanceTemplate()->Set(NewString(sMethodName), fun,
    313                                       v8::ReadOnly);
    314 }
    315 
    316 void CFXJS_Engine::DefineObjProperty(int nObjDefnID,
    317                                      const char* sPropName,
    318                                      v8::AccessorGetterCallback pPropGet,
    319                                      v8::AccessorSetterCallback pPropPut) {
    320   v8::Isolate::Scope isolate_scope(GetIsolate());
    321   v8::HandleScope handle_scope(GetIsolate());
    322   CFXJS_ObjDefinition* pObjDef =
    323       CFXJS_ObjDefinition::ForID(GetIsolate(), nObjDefnID);
    324   pObjDef->GetInstanceTemplate()->SetAccessor(NewString(sPropName), pPropGet,
    325                                               pPropPut);
    326 }
    327 
    328 void CFXJS_Engine::DefineObjAllProperties(
    329     int nObjDefnID,
    330     v8::NamedPropertyQueryCallback pPropQurey,
    331     v8::NamedPropertyGetterCallback pPropGet,
    332     v8::NamedPropertySetterCallback pPropPut,
    333     v8::NamedPropertyDeleterCallback pPropDel) {
    334   v8::Isolate::Scope isolate_scope(GetIsolate());
    335   v8::HandleScope handle_scope(GetIsolate());
    336   CFXJS_ObjDefinition* pObjDef =
    337       CFXJS_ObjDefinition::ForID(GetIsolate(), nObjDefnID);
    338   pObjDef->GetInstanceTemplate()->SetNamedPropertyHandler(pPropGet, pPropPut,
    339                                                           pPropQurey, pPropDel);
    340 }
    341 
    342 void CFXJS_Engine::DefineObjConst(int nObjDefnID,
    343                                   const char* sConstName,
    344                                   v8::Local<v8::Value> pDefault) {
    345   v8::Isolate::Scope isolate_scope(GetIsolate());
    346   v8::HandleScope handle_scope(GetIsolate());
    347   CFXJS_ObjDefinition* pObjDef =
    348       CFXJS_ObjDefinition::ForID(GetIsolate(), nObjDefnID);
    349   pObjDef->GetInstanceTemplate()->Set(GetIsolate(), sConstName, pDefault);
    350 }
    351 
    352 void CFXJS_Engine::DefineGlobalMethod(const char* sMethodName,
    353                                       v8::FunctionCallback pMethodCall) {
    354   v8::Isolate::Scope isolate_scope(GetIsolate());
    355   v8::HandleScope handle_scope(GetIsolate());
    356   v8::Local<v8::FunctionTemplate> fun =
    357       v8::FunctionTemplate::New(GetIsolate(), pMethodCall);
    358   fun->RemovePrototype();
    359   GetGlobalObjectTemplate(GetIsolate())
    360       ->Set(NewString(sMethodName), fun, v8::ReadOnly);
    361 }
    362 
    363 void CFXJS_Engine::DefineGlobalConst(const wchar_t* sConstName,
    364                                      v8::FunctionCallback pConstGetter) {
    365   v8::Isolate::Scope isolate_scope(GetIsolate());
    366   v8::HandleScope handle_scope(GetIsolate());
    367   v8::Local<v8::FunctionTemplate> fun =
    368       v8::FunctionTemplate::New(GetIsolate(), pConstGetter);
    369   fun->RemovePrototype();
    370   GetGlobalObjectTemplate(GetIsolate())
    371       ->SetAccessorProperty(NewString(sConstName), fun);
    372 }
    373 
    374 void CFXJS_Engine::InitializeEngine() {
    375   if (GetIsolate() == g_isolate)
    376     ++g_isolate_ref_count;
    377 
    378   v8::Isolate::Scope isolate_scope(GetIsolate());
    379   v8::HandleScope handle_scope(GetIsolate());
    380 
    381   // This has to happen before we call GetGlobalObjectTemplate because that
    382   // method gets the PerIsolateData from GetIsolate().
    383   FXJS_PerIsolateData::SetUp(GetIsolate());
    384 
    385   v8::Local<v8::Context> v8Context = v8::Context::New(
    386       GetIsolate(), nullptr, GetGlobalObjectTemplate(GetIsolate()));
    387   v8::Context::Scope context_scope(v8Context);
    388 
    389   v8Context->SetAlignedPointerInEmbedderData(kPerContextDataIndex, this);
    390 
    391   int maxID = CFXJS_ObjDefinition::MaxID(GetIsolate());
    392   m_StaticObjects.resize(maxID + 1);
    393   for (int i = 0; i < maxID; ++i) {
    394     CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(GetIsolate(), i);
    395     if (pObjDef->m_ObjType == FXJSOBJTYPE_GLOBAL) {
    396       CFXJS_PerObjectData::SetInObject(new CFXJS_PerObjectData(i),
    397                                        v8Context->Global()
    398                                            ->GetPrototype()
    399                                            ->ToObject(v8Context)
    400                                            .ToLocalChecked());
    401       if (pObjDef->m_pConstructor) {
    402         pObjDef->m_pConstructor(this, v8Context->Global()
    403                                           ->GetPrototype()
    404                                           ->ToObject(v8Context)
    405                                           .ToLocalChecked());
    406       }
    407     } else if (pObjDef->m_ObjType == FXJSOBJTYPE_STATIC) {
    408       v8::Local<v8::String> pObjName = NewString(pObjDef->m_ObjName);
    409       v8::Local<v8::Object> obj = NewFxDynamicObj(i, true);
    410       if (!obj.IsEmpty()) {
    411         v8Context->Global()->Set(v8Context, pObjName, obj).FromJust();
    412         m_StaticObjects[i] = new v8::Global<v8::Object>(GetIsolate(), obj);
    413       } else {
    414         m_StaticObjects[i] = nullptr;
    415       }
    416     }
    417   }
    418   ResetPersistentContext(v8Context);
    419 }
    420 
    421 void CFXJS_Engine::ReleaseEngine() {
    422   v8::Isolate::Scope isolate_scope(GetIsolate());
    423   v8::HandleScope handle_scope(GetIsolate());
    424   v8::Local<v8::Context> context = NewLocalContext();
    425   v8::Context::Scope context_scope(context);
    426   FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(GetIsolate());
    427   if (!pData)
    428     return;
    429 
    430   ClearConstArray();
    431 
    432   int maxID = CFXJS_ObjDefinition::MaxID(GetIsolate());
    433   for (int i = 0; i < maxID; ++i) {
    434     CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(GetIsolate(), i);
    435     v8::Local<v8::Object> pObj;
    436     if (pObjDef->m_ObjType == FXJSOBJTYPE_GLOBAL) {
    437       pObj =
    438           context->Global()->GetPrototype()->ToObject(context).ToLocalChecked();
    439     } else if (m_StaticObjects[i] && !m_StaticObjects[i]->IsEmpty()) {
    440       pObj = v8::Local<v8::Object>::New(GetIsolate(), *m_StaticObjects[i]);
    441       delete m_StaticObjects[i];
    442       m_StaticObjects[i] = nullptr;
    443     }
    444 
    445     if (!pObj.IsEmpty()) {
    446       if (pObjDef->m_pDestructor)
    447         pObjDef->m_pDestructor(this, pObj);
    448       FreeObjectPrivate(pObj);
    449     }
    450   }
    451 
    452   ReleasePersistentContext();
    453 
    454   if (GetIsolate() == g_isolate && --g_isolate_ref_count > 0)
    455     return;
    456 
    457   delete pData;
    458   GetIsolate()->SetData(g_embedderDataSlot, nullptr);
    459 }
    460 
    461 int CFXJS_Engine::Execute(const WideString& script, FXJSErr* pError) {
    462   v8::Isolate::Scope isolate_scope(GetIsolate());
    463   v8::TryCatch try_catch(GetIsolate());
    464   v8::Local<v8::Context> context = GetIsolate()->GetCurrentContext();
    465   v8::Local<v8::Script> compiled_script;
    466   if (!v8::Script::Compile(context, NewString(script.AsStringView()))
    467            .ToLocal(&compiled_script)) {
    468     v8::String::Utf8Value error(GetIsolate(), try_catch.Exception());
    469     // TODO(tsepez): return error via pError->message.
    470     return -1;
    471   }
    472 
    473   v8::Local<v8::Value> result;
    474   if (!compiled_script->Run(context).ToLocal(&result)) {
    475     v8::String::Utf8Value error(GetIsolate(), try_catch.Exception());
    476     // TODO(tsepez): return error via pError->message.
    477     return -1;
    478   }
    479   return 0;
    480 }
    481 
    482 v8::Local<v8::Object> CFXJS_Engine::NewFxDynamicObj(int nObjDefnID,
    483                                                     bool bStatic) {
    484   v8::Isolate::Scope isolate_scope(GetIsolate());
    485   v8::Local<v8::Context> context = GetIsolate()->GetCurrentContext();
    486   if (nObjDefnID == -1) {
    487     v8::Local<v8::ObjectTemplate> objTempl =
    488         v8::ObjectTemplate::New(GetIsolate());
    489     v8::Local<v8::Object> obj;
    490     if (!objTempl->NewInstance(context).ToLocal(&obj))
    491       return v8::Local<v8::Object>();
    492     return obj;
    493   }
    494 
    495   FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(GetIsolate());
    496   if (!pData)
    497     return v8::Local<v8::Object>();
    498 
    499   if (nObjDefnID < 0 || nObjDefnID >= CFXJS_ObjDefinition::MaxID(GetIsolate()))
    500     return v8::Local<v8::Object>();
    501 
    502   CFXJS_ObjDefinition* pObjDef =
    503       CFXJS_ObjDefinition::ForID(GetIsolate(), nObjDefnID);
    504   v8::Local<v8::Object> obj;
    505   if (!pObjDef->GetInstanceTemplate()->NewInstance(context).ToLocal(&obj))
    506     return v8::Local<v8::Object>();
    507 
    508   CFXJS_PerObjectData* pObjData = new CFXJS_PerObjectData(nObjDefnID);
    509   CFXJS_PerObjectData::SetInObject(pObjData, obj);
    510   if (pObjDef->m_pConstructor)
    511     pObjDef->m_pConstructor(this, obj);
    512 
    513   if (!bStatic && FXJS_PerIsolateData::Get(GetIsolate())->m_pDynamicObjsMap)
    514     FXJS_PerIsolateData::Get(GetIsolate())
    515         ->m_pDynamicObjsMap->set(pObjData, obj);
    516 
    517   return obj;
    518 }
    519 
    520 v8::Local<v8::Object> CFXJS_Engine::GetThisObj() {
    521   v8::Isolate::Scope isolate_scope(GetIsolate());
    522   if (!FXJS_PerIsolateData::Get(GetIsolate()))
    523     return v8::Local<v8::Object>();
    524 
    525   // Return the global object.
    526   v8::Local<v8::Context> context = GetIsolate()->GetCurrentContext();
    527   return context->Global()->GetPrototype()->ToObject(context).ToLocalChecked();
    528 }
    529 
    530 void CFXJS_Engine::Error(const WideString& message) {
    531   GetIsolate()->ThrowException(NewString(message.AsStringView()));
    532 }
    533 
    534 void CFXJS_Engine::SetObjectPrivate(v8::Local<v8::Object> pObj, void* p) {
    535   CFXJS_PerObjectData* pPerObjectData =
    536       CFXJS_PerObjectData::GetFromObject(pObj);
    537   if (!pPerObjectData)
    538     return;
    539   pPerObjectData->m_pPrivate = p;
    540 }
    541 
    542 void* CFXJS_Engine::GetObjectPrivate(v8::Local<v8::Object> pObj) {
    543   CFXJS_PerObjectData* pData = CFXJS_PerObjectData::GetFromObject(pObj);
    544   if (!pData && !pObj.IsEmpty()) {
    545     // It could be a global proxy object.
    546     v8::Local<v8::Value> v = pObj->GetPrototype();
    547     v8::Local<v8::Context> context = GetIsolate()->GetCurrentContext();
    548     if (v->IsObject()) {
    549       pData = CFXJS_PerObjectData::GetFromObject(
    550           v->ToObject(context).ToLocalChecked());
    551     }
    552   }
    553   return pData ? pData->m_pPrivate : nullptr;
    554 }
    555