• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
CFXJS_PerObjectData(int nObjDefID)27   explicit CFXJS_PerObjectData(int nObjDefID)
28       : m_ObjDefID(nObjDefID), m_pPrivate(nullptr) {}
29 
SetInObject(CFXJS_PerObjectData * pData,v8::Local<v8::Object> pObj)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 
GetFromObject(v8::Local<v8::Object> pObj)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:
MaxID(v8::Isolate * pIsolate)55   static int MaxID(v8::Isolate* pIsolate) {
56     return FXJS_PerIsolateData::Get(pIsolate)->m_ObjectDefnArray.size();
57   }
58 
ForID(v8::Isolate * pIsolate,int id)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 
CFXJS_ObjDefinition(v8::Isolate * isolate,const char * sObjName,FXJSOBJTYPE eObjType,CFXJS_Engine::Constructor pConstructor,CFXJS_Engine::Destructor pDestructor)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 
AssignID()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 
GetInstanceTemplate()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 
GetSignature()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 
GetGlobalObjectTemplate(v8::Isolate * pIsolate)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 
Allocate(size_t length)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 
AllocateUninitialized(size_t length)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 
Free(void * data,size_t length)162 void FXJS_ArrayBufferAllocator::Free(void* data, size_t length) {
163   pdfium::base::PartitionFreeGeneric(gArrayBufferPartitionAllocator.root(),
164                                      data);
165 }
166 
Dispose(v8::Isolate * isolate,v8::Global<v8::Object> value,void * key)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 
MapFromWeakCallbackInfo(const v8::WeakCallbackInfo<WeakCallbackDataType> & data)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 
FXJS_Initialize(unsigned int embedderDataSlot,v8::Isolate * pIsolate)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 
FXJS_Release()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 
FXJS_GetIsolate(v8::Isolate ** pResultIsolate)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 
FXJS_GlobalIsolateRefCount()227 size_t FXJS_GlobalIsolateRefCount() {
228   return g_isolate_ref_count;
229 }
230 
V8TemplateMap(v8::Isolate * isolate)231 V8TemplateMap::V8TemplateMap(v8::Isolate* isolate) : m_map(isolate) {}
232 
~V8TemplateMap()233 V8TemplateMap::~V8TemplateMap() {}
234 
set(void * key,v8::Local<v8::Object> handle)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 
~FXJS_PerIsolateData()240 FXJS_PerIsolateData::~FXJS_PerIsolateData() {}
241 
242 // static
SetUp(v8::Isolate * pIsolate)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
Get(v8::Isolate * pIsolate)249 FXJS_PerIsolateData* FXJS_PerIsolateData::Get(v8::Isolate* pIsolate) {
250   return static_cast<FXJS_PerIsolateData*>(
251       pIsolate->GetData(g_embedderDataSlot));
252 }
253 
FXJS_PerIsolateData(v8::Isolate * pIsolate)254 FXJS_PerIsolateData::FXJS_PerIsolateData(v8::Isolate* pIsolate)
255     : m_pDynamicObjsMap(new V8TemplateMap(pIsolate)) {}
256 
CFXJS_Engine()257 CFXJS_Engine::CFXJS_Engine() : CJS_V8(nullptr) {}
258 
CFXJS_Engine(v8::Isolate * pIsolate)259 CFXJS_Engine::CFXJS_Engine(v8::Isolate* pIsolate) : CJS_V8(pIsolate) {}
260 
261 CFXJS_Engine::~CFXJS_Engine() = default;
262 
263 // static
CurrentEngineFromIsolate(v8::Isolate * pIsolate)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
GetObjDefnID(v8::Local<v8::Object> pObj)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
FreeObjectPrivate(void * pPerObjectData)277 void CFXJS_Engine::FreeObjectPrivate(void* pPerObjectData) {
278   delete static_cast<CFXJS_PerObjectData*>(pPerObjectData);
279 }
280 
281 // static
FreeObjectPrivate(v8::Local<v8::Object> pObj)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 
DefineObj(const char * sObjName,FXJSOBJTYPE eObjType,CFXJS_Engine::Constructor pConstructor,CFXJS_Engine::Destructor pDestructor)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 
DefineObjMethod(int nObjDefnID,const char * sMethodName,v8::FunctionCallback pMethodCall)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 
DefineObjProperty(int nObjDefnID,const char * sPropName,v8::AccessorGetterCallback pPropGet,v8::AccessorSetterCallback pPropPut)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 
DefineObjAllProperties(int nObjDefnID,v8::NamedPropertyQueryCallback pPropQurey,v8::NamedPropertyGetterCallback pPropGet,v8::NamedPropertySetterCallback pPropPut,v8::NamedPropertyDeleterCallback pPropDel)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 
DefineObjConst(int nObjDefnID,const char * sConstName,v8::Local<v8::Value> pDefault)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 
DefineGlobalMethod(const char * sMethodName,v8::FunctionCallback pMethodCall)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 
DefineGlobalConst(const wchar_t * sConstName,v8::FunctionCallback pConstGetter)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 
InitializeEngine()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 
ReleaseEngine()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 
Execute(const WideString & script,FXJSErr * pError)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 
NewFxDynamicObj(int nObjDefnID,bool bStatic)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 
GetThisObj()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 
Error(const WideString & message)530 void CFXJS_Engine::Error(const WideString& message) {
531   GetIsolate()->ThrowException(NewString(message.AsStringView()));
532 }
533 
SetObjectPrivate(v8::Local<v8::Object> pObj,void * p)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 
GetObjectPrivate(v8::Local<v8::Object> pObj)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