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