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