Switched to weak context/isolate bindings for V8 script objects and compiled scripts, fixing Issue #44.

This commit is contained in:
ClearScript 2014-04-24 21:25:58 -04:00
Родитель 19bc6944c3
Коммит 2b42003f6e
22 изменённых файлов: 419 добавлений и 206 удалений

Просмотреть файл

@ -231,6 +231,7 @@
<ClInclude Include="..\V8ScriptHolderImpl.h" />
<ClInclude Include="..\V8ScriptImpl.h" />
<ClInclude Include="..\V8Value.h" />
<ClInclude Include="..\V8WeakContextBinding.h" />
<ClInclude Include="..\WeakRef.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

Просмотреть файл

@ -169,5 +169,8 @@
<ClInclude Include="..\StdString.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\V8WeakContextBinding.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

Просмотреть файл

@ -232,6 +232,7 @@
<ClInclude Include="..\V8ScriptHolderImpl.h" />
<ClInclude Include="..\V8ScriptImpl.h" />
<ClInclude Include="..\V8Value.h" />
<ClInclude Include="..\V8WeakContextBinding.h" />
<ClInclude Include="..\WeakRef.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

Просмотреть файл

@ -169,5 +169,8 @@
<ClInclude Include="..\StdString.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\V8WeakContextBinding.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

Просмотреть файл

@ -84,5 +84,6 @@
#include "HostObjectHelpers.h"
#include "V8IsolateImpl.h"
#include "V8ContextImpl.h"
#include "V8WeakContextBinding.h"
#include "V8ObjectHolderImpl.h"
#include "V8ScriptHolderImpl.h"

Просмотреть файл

@ -78,11 +78,6 @@ public:
protected:
SharedPtrTarget():
m_RefCount(0)
{
}
class AddRefScope
{
PROHIBIT_COPY(AddRefScope)
@ -112,6 +107,11 @@ protected:
size_t m_RefCountValue;
};
SharedPtrTarget():
m_RefCount(0)
{
}
private:
RefCount m_RefCount;

Просмотреть файл

@ -65,7 +65,7 @@
// V8Context
//-----------------------------------------------------------------------------
class V8Context: public SharedPtrTarget
class V8Context: public WeakRefTarget<V8Context>
{
public:

Просмотреть файл

@ -65,34 +65,6 @@
// local helper functions
//-----------------------------------------------------------------------------
static void* PtrFromObjectHandle(Persistent<Object> hObject)
{
return hObject.ToPtr();
}
//-----------------------------------------------------------------------------
static Persistent<Object> ObjectHandleFromPtr(void* pvObject)
{
return Persistent<Object>::FromPtr(pvObject);
}
//-----------------------------------------------------------------------------
static void* PtrFromScriptHandle(Persistent<Script> hScript)
{
return hScript.ToPtr();
}
//-----------------------------------------------------------------------------
static Persistent<Script> ScriptHandleFromPtr(void* pvScript)
{
return Persistent<Script>::FromPtr(pvScript);
}
//-----------------------------------------------------------------------------
static HostObjectHolder* GetHostObjectHolder(Handle<Object> hObject)
{
_ASSERTE(hObject->InternalFieldCount() > 0);
@ -331,7 +303,7 @@ V8ScriptHolder* V8ContextImpl::Compile(const StdString& documentName, const StdS
BEGIN_EXECUTION_SCOPE
auto hScript = VERIFY(Script::New(CreateString(code), CreateString(documentName)));
return new V8ScriptHolderImpl(m_spIsolateImpl, ::PtrFromScriptHandle(CreatePersistent(hScript)));
return new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromScriptHandle(CreatePersistent(hScript)));
END_EXECUTION_SCOPE
END_CONTEXT_SCOPE
@ -341,7 +313,7 @@ V8ScriptHolder* V8ContextImpl::Compile(const StdString& documentName, const StdS
bool V8ContextImpl::CanExecute(V8ScriptHolder* pHolder)
{
return m_spIsolateImpl.GetRawPtr() == pHolder->GetIsolate();
return pHolder->IsSameIsolate(m_spIsolateImpl.GetRawPtr());
}
//-----------------------------------------------------------------------------
@ -387,28 +359,6 @@ void V8ContextImpl::CollectGarbage(bool exhaustive)
//-----------------------------------------------------------------------------
void* V8ContextImpl::AddRefV8Object(void* pvObject)
{
BEGIN_ISOLATE_SCOPE
return ::PtrFromObjectHandle(CreatePersistent(::ObjectHandleFromPtr(pvObject)));
END_ISOLATE_SCOPE
}
//-----------------------------------------------------------------------------
void V8ContextImpl::ReleaseV8Object(void* pvObject)
{
BEGIN_ISOLATE_SCOPE
Dispose(::ObjectHandleFromPtr(pvObject));
END_ISOLATE_SCOPE
}
//-----------------------------------------------------------------------------
V8Value V8ContextImpl::GetV8ObjectProperty(void* pvObject, const StdString& name)
{
BEGIN_CONTEXT_SCOPE
@ -631,6 +581,18 @@ Handle<Value> V8ContextImpl::Wrap()
//-----------------------------------------------------------------------------
SharedPtr<V8WeakContextBinding> V8ContextImpl::GetWeakBinding()
{
if (m_spWeakBinding.IsEmpty())
{
m_spWeakBinding = new V8WeakContextBinding(m_spIsolateImpl, this);
}
return m_spWeakBinding;
}
//-----------------------------------------------------------------------------
void V8ContextImpl::GetV8ObjectPropertyNames(Handle<Object> hObject, std::vector<StdString>& names)
{
names.clear();
@ -1396,7 +1358,7 @@ V8Value V8ContextImpl::ExportValue(Handle<Value> hValue)
return V8Value(::GetHostObjectHolder(hObject)->Clone());
}
return V8Value(new V8ObjectHolderImpl(this, ::PtrFromObjectHandle(CreatePersistent(hObject))));
return V8Value(new V8ObjectHolderImpl(GetWeakBinding(), ::PtrFromObjectHandle(CreatePersistent(hObject))));
}
return V8Value(V8Value::Undefined);

Просмотреть файл

@ -61,6 +61,12 @@
#pragma once
//-----------------------------------------------------------------------------
// forward declarations
//-----------------------------------------------------------------------------
class V8WeakContextBinding;
//-----------------------------------------------------------------------------
// V8ContextImpl
//-----------------------------------------------------------------------------
@ -72,6 +78,7 @@ class V8ContextImpl: public V8Context
public:
V8ContextImpl(V8IsolateImpl* pIsolateImpl, const StdString& name, bool enableDebugging, bool disableGlobalMembers, int debugPort);
const StdString& GetName() const { return m_Name; }
size_t GetMaxIsolateStackUsage();
void SetMaxIsolateStackUsage(size_t value);
@ -87,9 +94,6 @@ public:
void GetIsolateHeapInfo(V8IsolateHeapInfo& heapInfo);
void CollectGarbage(bool exhaustive);
void* AddRefV8Object(void* pvObject);
void ReleaseV8Object(void* pvObject);
V8Value GetV8ObjectProperty(void* pvObject, const StdString& name);
void SetV8ObjectProperty(void* pvObject, const StdString& name, const V8Value& value);
bool DeleteV8ObjectProperty(void* pvObject, const StdString& name);
@ -104,7 +108,6 @@ public:
V8Value InvokeV8ObjectMethod(void* pvObject, const StdString& name, const std::vector<V8Value>& args);
void ProcessDebugMessages();
~V8ContextImpl();
private:
@ -255,6 +258,7 @@ private:
}
Handle<Value> Wrap();
SharedPtr<V8WeakContextBinding> GetWeakBinding();
void GetV8ObjectPropertyNames(Handle<Object> hObject, std::vector<StdString>& names);
void GetV8ObjectPropertyIndices(Handle<Object> hObject, std::vector<int>& indices);
@ -302,5 +306,6 @@ private:
Persistent<String> m_hHostObjectCookieName;
Persistent<String> m_hInnerExceptionName;
Persistent<FunctionTemplate> m_hHostObjectTemplate;
SharedPtr<V8WeakContextBinding> m_spWeakBinding;
void* m_pvV8ObjectCache;
};

Просмотреть файл

@ -76,6 +76,14 @@ public:
Type_Fatal
};
V8Exception(Type type, const StdString& engineName, StdString&& message):
m_Type(type),
m_EngineName(engineName),
m_Message(std::move(message)),
m_InnerException(V8Value::Undefined)
{
}
V8Exception(Type type, const StdString& engineName, StdString&& message, StdString&& stackTrace, V8Value&& innerException):
m_Type(type),
m_EngineName(engineName),

Просмотреть файл

@ -61,22 +61,6 @@
#include "ClearScriptV8Native.h"
//-----------------------------------------------------------------------------
// local helper functions
//-----------------------------------------------------------------------------
static void* PtrFromScriptHandle(Persistent<Script> hScript)
{
return hScript.ToPtr();
}
//-----------------------------------------------------------------------------
static Persistent<Script> ScriptHandleFromPtr(void* pvScript)
{
return Persistent<Script>::FromPtr(pvScript);
}
//-----------------------------------------------------------------------------
// V8IsolateImpl implementation
//-----------------------------------------------------------------------------
@ -300,6 +284,28 @@ void V8IsolateImpl::CollectGarbage(bool exhaustive)
//-----------------------------------------------------------------------------
void* V8IsolateImpl::AddRefV8Object(void* pvObject)
{
BEGIN_ISOLATE_SCOPE
return ::PtrFromObjectHandle(CreatePersistent(::ObjectHandleFromPtr(pvObject)));
END_ISOLATE_SCOPE
}
//-----------------------------------------------------------------------------
void V8IsolateImpl::ReleaseV8Object(void* pvObject)
{
BEGIN_ISOLATE_SCOPE
Dispose(::ObjectHandleFromPtr(pvObject));
END_ISOLATE_SCOPE
}
//-----------------------------------------------------------------------------
void* V8IsolateImpl::AddRefV8Script(void* pvScript)
{
BEGIN_ISOLATE_SCOPE
@ -325,7 +331,7 @@ void V8IsolateImpl::ReleaseV8Script(void* pvScript)
void DECLSPEC_NORETURN V8IsolateImpl::ThrowOutOfMemoryException()
{
m_IsOutOfMemory = true;
throw V8Exception(V8Exception::Type_Fatal, m_Name, StdString(L"The V8 runtime has exceeded its memory limit"), StdString(), V8Value(V8Value::Undefined));
throw V8Exception(V8Exception::Type_Fatal, m_Name, StdString(L"The V8 runtime has exceeded its memory limit"));
}
//-----------------------------------------------------------------------------
@ -409,7 +415,7 @@ void V8IsolateImpl::EnterExecutionScope(size_t* pStackMarker)
else if ((m_pStackLimit != nullptr) && (pStackMarker < m_pStackLimit))
{
// stack usage limit exceeded (host-side detection)
throw V8Exception(V8Exception::Type_General, m_Name, StdString(L"The V8 runtime has exceeded its stack usage limit"), StdString(), V8Value(V8Value::Undefined));
throw V8Exception(V8Exception::Type_General, m_Name, StdString(L"The V8 runtime has exceeded its stack usage limit"));
}
m_ExecutionLevel++;

Просмотреть файл

@ -122,6 +122,7 @@ public:
};
V8IsolateImpl(const StdString& name, const V8IsolateConstraints* pConstraints, bool enableDebugging, int debugPort);
const StdString& GetName() const { return m_Name; }
Local<Context> CreateContext(ExtensionConfiguration* pExtensionConfiguation = nullptr, Handle<ObjectTemplate> hGlobalTemplate = Handle<ObjectTemplate>(), Handle<Value> hGlobalObject = Handle<Value>())
{
@ -252,6 +253,9 @@ public:
void GetHeapInfo(V8IsolateHeapInfo& heapInfo);
void CollectGarbage(bool exhaustive);
void* AddRefV8Object(void* pvObject);
void ReleaseV8Object(void* pvObject);
void* AddRefV8Script(void* pvScript);
void ReleaseV8Script(void* pvScript);

Просмотреть файл

@ -65,16 +65,8 @@
// V8ObjectHolderImpl implementation
//-----------------------------------------------------------------------------
V8ObjectHolderImpl::V8ObjectHolderImpl(V8ContextImpl* pContextImpl, void* pvObject):
m_spContextImpl(pContextImpl),
m_pvObject(pvObject)
{
}
//-----------------------------------------------------------------------------
V8ObjectHolderImpl::V8ObjectHolderImpl(const SharedPtr<V8ContextImpl>& spContextImpl, void* pvObject):
m_spContextImpl(spContextImpl),
V8ObjectHolderImpl::V8ObjectHolderImpl(V8WeakContextBinding* pBinding, void* pvObject):
m_spBinding(pBinding),
m_pvObject(pvObject)
{
}
@ -83,7 +75,7 @@ V8ObjectHolderImpl::V8ObjectHolderImpl(const SharedPtr<V8ContextImpl>& spContext
V8ObjectHolderImpl* V8ObjectHolderImpl::Clone() const
{
return new V8ObjectHolderImpl(m_spContextImpl, m_spContextImpl->AddRefV8Object(m_pvObject));
return new V8ObjectHolderImpl(m_spBinding, m_spBinding->GetIsolateImpl()->AddRefV8Object(m_pvObject));
}
//-----------------------------------------------------------------------------
@ -97,75 +89,79 @@ void* V8ObjectHolderImpl::GetObject() const
V8Value V8ObjectHolderImpl::GetProperty(const StdString& name) const
{
return m_spContextImpl->GetV8ObjectProperty(m_pvObject, name);
return m_spBinding->GetContextImpl()->GetV8ObjectProperty(m_pvObject, name);
}
//-----------------------------------------------------------------------------
void V8ObjectHolderImpl::SetProperty(const StdString& name, const V8Value& value) const
{
m_spContextImpl->SetV8ObjectProperty(m_pvObject, name, value);
m_spBinding->GetContextImpl()->SetV8ObjectProperty(m_pvObject, name, value);
}
//-----------------------------------------------------------------------------
bool V8ObjectHolderImpl::DeleteProperty(const StdString& name) const
{
return m_spContextImpl->DeleteV8ObjectProperty(m_pvObject, name);
return m_spBinding->GetContextImpl()->DeleteV8ObjectProperty(m_pvObject, name);
}
//-----------------------------------------------------------------------------
void V8ObjectHolderImpl::GetPropertyNames(std::vector<StdString>& names) const
{
m_spContextImpl->GetV8ObjectPropertyNames(m_pvObject, names);
m_spBinding->GetContextImpl()->GetV8ObjectPropertyNames(m_pvObject, names);
}
//-----------------------------------------------------------------------------
V8Value V8ObjectHolderImpl::GetProperty(int index) const
{
return m_spContextImpl->GetV8ObjectProperty(m_pvObject, index);
return m_spBinding->GetContextImpl()->GetV8ObjectProperty(m_pvObject, index);
}
//-----------------------------------------------------------------------------
void V8ObjectHolderImpl::SetProperty(int index, const V8Value& value) const
{
m_spContextImpl->SetV8ObjectProperty(m_pvObject, index, value);
m_spBinding->GetContextImpl()->SetV8ObjectProperty(m_pvObject, index, value);
}
//-----------------------------------------------------------------------------
bool V8ObjectHolderImpl::DeleteProperty(int index) const
{
return m_spContextImpl->DeleteV8ObjectProperty(m_pvObject, index);
return m_spBinding->GetContextImpl()->DeleteV8ObjectProperty(m_pvObject, index);
}
//-----------------------------------------------------------------------------
void V8ObjectHolderImpl::GetPropertyIndices(std::vector<int>& indices) const
{
m_spContextImpl->GetV8ObjectPropertyIndices(m_pvObject, indices);
m_spBinding->GetContextImpl()->GetV8ObjectPropertyIndices(m_pvObject, indices);
}
//-----------------------------------------------------------------------------
V8Value V8ObjectHolderImpl::Invoke(const std::vector<V8Value>& args, bool asConstructor) const
{
return m_spContextImpl->InvokeV8Object(m_pvObject, args, asConstructor);
return m_spBinding->GetContextImpl()->InvokeV8Object(m_pvObject, args, asConstructor);
}
//-----------------------------------------------------------------------------
V8Value V8ObjectHolderImpl::InvokeMethod(const StdString& name, const std::vector<V8Value>& args) const
{
return m_spContextImpl->InvokeV8ObjectMethod(m_pvObject, name, args);
return m_spBinding->GetContextImpl()->InvokeV8ObjectMethod(m_pvObject, name, args);
}
//-----------------------------------------------------------------------------
V8ObjectHolderImpl::~V8ObjectHolderImpl()
{
m_spContextImpl->ReleaseV8Object(m_pvObject);
SharedPtr<V8IsolateImpl> spIsolateImpl;
if (m_spBinding->TryGetIsolateImpl(spIsolateImpl))
{
spIsolateImpl->ReleaseV8Object(m_pvObject);
}
}

Просмотреть файл

@ -71,8 +71,7 @@ class V8ObjectHolderImpl: public V8ObjectHolder
public:
V8ObjectHolderImpl(V8ContextImpl* pContextImpl, void* pvObject);
V8ObjectHolderImpl(const SharedPtr<V8ContextImpl>& spContextImpl, void* pvObject);
V8ObjectHolderImpl(V8WeakContextBinding* pBinding, void* pvObject);
V8ObjectHolderImpl* Clone() const;
void* GetObject() const;
@ -94,6 +93,6 @@ public:
private:
SharedPtr<V8ContextImpl> m_spContextImpl;
SharedPtr<V8WeakContextBinding> m_spBinding;
void* m_pvObject;
};

Просмотреть файл

@ -373,3 +373,33 @@ const Persistent<T> V8SafePersistent<T>::ms_EmptyImpl;
//-----------------------------------------------------------------------------
#define Persistent V8FastPersistent
//-----------------------------------------------------------------------------
// helper functions
//-----------------------------------------------------------------------------
inline void* PtrFromObjectHandle(Persistent<Object> hObject)
{
return hObject.ToPtr();
}
//-----------------------------------------------------------------------------
inline Persistent<Object> ObjectHandleFromPtr(void* pvObject)
{
return Persistent<Object>::FromPtr(pvObject);
}
//-----------------------------------------------------------------------------
inline void* PtrFromScriptHandle(Persistent<Script> hScript)
{
return hScript.ToPtr();
}
//-----------------------------------------------------------------------------
inline Persistent<Script> ScriptHandleFromPtr(void* pvScript)
{
return Persistent<Script>::FromPtr(pvScript);
}

Просмотреть файл

@ -70,7 +70,7 @@ class V8ScriptHolder
public:
virtual V8ScriptHolder* Clone() const = 0;
virtual void* GetIsolate() const = 0;
virtual bool IsSameIsolate(void* pvIsolate) const = 0;
virtual void* GetScript() const = 0;
virtual ~V8ScriptHolder() {}

Просмотреть файл

@ -65,16 +65,8 @@
// V8ScriptHolderImpl implementation
//-----------------------------------------------------------------------------
V8ScriptHolderImpl::V8ScriptHolderImpl(V8IsolateImpl* pIsolateImpl, void* pvScript):
m_spIsolateImpl(pIsolateImpl),
m_pvScript(pvScript)
{
}
//-----------------------------------------------------------------------------
V8ScriptHolderImpl::V8ScriptHolderImpl(const SharedPtr<V8IsolateImpl>& spIsolateImpl, void* pvScript):
m_spIsolateImpl(spIsolateImpl),
V8ScriptHolderImpl::V8ScriptHolderImpl(V8WeakContextBinding* pBinding, void* pvScript):
m_spBinding(pBinding),
m_pvScript(pvScript)
{
}
@ -83,14 +75,20 @@ V8ScriptHolderImpl::V8ScriptHolderImpl(const SharedPtr<V8IsolateImpl>& spIsolate
V8ScriptHolderImpl* V8ScriptHolderImpl::Clone() const
{
return new V8ScriptHolderImpl(m_spIsolateImpl, m_spIsolateImpl->AddRefV8Script(m_pvScript));
return new V8ScriptHolderImpl(m_spBinding, m_spBinding->GetIsolateImpl()->AddRefV8Script(m_pvScript));
}
//-----------------------------------------------------------------------------
void* V8ScriptHolderImpl::GetIsolate() const
bool V8ScriptHolderImpl::IsSameIsolate(void* pvIsolate) const
{
return m_spIsolateImpl.GetRawPtr();
SharedPtr<V8IsolateImpl> spIsolateImpl;
if (m_spBinding->TryGetIsolateImpl(spIsolateImpl))
{
return spIsolateImpl.GetRawPtr() == pvIsolate;
}
return false;
}
//-----------------------------------------------------------------------------
@ -104,5 +102,9 @@ void* V8ScriptHolderImpl::GetScript() const
V8ScriptHolderImpl::~V8ScriptHolderImpl()
{
m_spIsolateImpl->ReleaseV8Script(m_pvScript);
SharedPtr<V8IsolateImpl> spIsolateImpl;
if (m_spBinding->TryGetIsolateImpl(spIsolateImpl))
{
spIsolateImpl->ReleaseV8Script(m_pvScript);
}
}

Просмотреть файл

@ -71,17 +71,16 @@ class V8ScriptHolderImpl: public V8ScriptHolder
public:
V8ScriptHolderImpl(V8IsolateImpl* pIsolateImpl, void* pvScript);
V8ScriptHolderImpl(const SharedPtr<V8IsolateImpl>& spIsolateImpl, void* pvScript);
V8ScriptHolderImpl(V8WeakContextBinding* pBinding, void* pvScript);
V8ScriptHolderImpl* Clone() const;
void* GetIsolate() const;
bool IsSameIsolate(void* pvIsolate) const;
void* GetScript() const;
~V8ScriptHolderImpl();
private:
SharedPtr<V8IsolateImpl> m_spIsolateImpl;
SharedPtr<V8WeakContextBinding> m_spBinding;
void* m_pvScript;
};

Просмотреть файл

@ -0,0 +1,133 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Microsoft Public License (MS-PL)
//
// This license governs use of the accompanying software. If you use the
// software, you accept this license. If you do not accept the license, do not
// use the software.
//
// 1. Definitions
//
// The terms "reproduce," "reproduction," "derivative works," and
// "distribution" have the same meaning here as under U.S. copyright law. A
// "contribution" is the original software, or any additions or changes to
// the software. A "contributor" is any person that distributes its
// contribution under this license. "Licensed patents" are a contributor's
// patent claims that read directly on its contribution.
//
// 2. Grant of Rights
//
// (A) Copyright Grant- Subject to the terms of this license, including the
// license conditions and limitations in section 3, each contributor
// grants you a non-exclusive, worldwide, royalty-free copyright license
// to reproduce its contribution, prepare derivative works of its
// contribution, and distribute its contribution or any derivative works
// that you create.
//
// (B) Patent Grant- Subject to the terms of this license, including the
// license conditions and limitations in section 3, each contributor
// grants you a non-exclusive, worldwide, royalty-free license under its
// licensed patents to make, have made, use, sell, offer for sale,
// import, and/or otherwise dispose of its contribution in the software
// or derivative works of the contribution in the software.
//
// 3. Conditions and Limitations
//
// (A) No Trademark License- This license does not grant you rights to use
// any contributors' name, logo, or trademarks.
//
// (B) If you bring a patent claim against any contributor over patents that
// you claim are infringed by the software, your patent license from such
// contributor to the software ends automatically.
//
// (C) If you distribute any portion of the software, you must retain all
// copyright, patent, trademark, and attribution notices that are present
// in the software.
//
// (D) If you distribute any portion of the software in source code form, you
// may do so only under this license by including a complete copy of this
// license with your distribution. If you distribute any portion of the
// software in compiled or object code form, you may only do so under a
// license that complies with this license.
//
// (E) The software is licensed "as-is." You bear the risk of using it. The
// contributors give no express warranties, guarantees or conditions. You
// may have additional consumer rights under your local laws which this
// license cannot change. To the extent permitted under your local laws,
// the contributors exclude the implied warranties of merchantability,
// fitness for a particular purpose and non-infringement.
//
#pragma once
//-----------------------------------------------------------------------------
// V8WeakContextBinding
//-----------------------------------------------------------------------------
class V8WeakContextBinding: public SharedPtrTarget
{
public:
V8WeakContextBinding(V8IsolateImpl* pIsolateImpl, V8ContextImpl* pContextImpl):
m_wrIsolate(pIsolateImpl->CreateWeakRef()),
m_IsolateName(pIsolateImpl->GetName()),
m_wrContext(pContextImpl->CreateWeakRef()),
m_ContextName(pContextImpl->GetName())
{
}
SharedPtr<V8IsolateImpl> GetIsolateImpl() const
{
SharedPtr<V8IsolateImpl> spIsolateImpl;
if (TryGetIsolateImpl(spIsolateImpl))
{
return spIsolateImpl;
}
throw V8Exception(V8Exception::Type_General, m_IsolateName, StdString(L"The V8 runtime has been destroyed"));
}
bool TryGetIsolateImpl(SharedPtr<V8IsolateImpl>& spIsolateImpl) const
{
auto spIsolate = m_wrIsolate.GetTarget();
if (!spIsolate.IsEmpty())
{
spIsolateImpl = static_cast<V8IsolateImpl*>(spIsolate.GetRawPtr());
return true;
}
return false;
}
SharedPtr<V8ContextImpl> GetContextImpl() const
{
SharedPtr<V8ContextImpl> spContextImpl;
if (TryGetContextImpl(spContextImpl))
{
return spContextImpl;
}
throw V8Exception(V8Exception::Type_General, m_ContextName, StdString(L"The V8 script engine has been destroyed"));
}
bool TryGetContextImpl(SharedPtr<V8ContextImpl>& spContextImpl) const
{
auto spContext = m_wrContext.GetTarget();
if (!spContext.IsEmpty())
{
spContextImpl = static_cast<V8ContextImpl*>(spContext.GetRawPtr());
return true;
}
return false;
}
private:
WeakRef<V8Isolate> m_wrIsolate;
StdString m_IsolateName;
WeakRef<V8Context> m_wrContext;
StdString m_ContextName;
};

Просмотреть файл

@ -82,6 +82,28 @@ class WeakRef
public:
WeakRef<T>(const WeakRef<T>& that):
m_spImpl(that.m_spImpl)
{
}
WeakRef<T>(WeakRef<T>&& that):
m_spImpl(std::move(that.m_spImpl))
{
}
const WeakRef<T>& operator=(const WeakRef<T>& that)
{
m_spImpl = that.m_spImpl;
return *this;
}
const WeakRef<T>& operator=(WeakRef<T>&& that)
{
m_spImpl = std::move(that.m_spImpl);
return *this;
}
SharedPtr<T> GetTarget() const
{
return m_spImpl->GetTarget();
@ -97,39 +119,6 @@ private:
SharedPtr<WeakRefImpl<T>> m_spImpl;
};
//-----------------------------------------------------------------------------
// WeakRefUtil
//-----------------------------------------------------------------------------
template <typename T>
class WeakRefUtil
{
PROHIBIT_CONSTRUCT(WeakRefUtil)
friend class WeakRefTarget<T>;
friend class WeakRefImpl<T>;
private:
template <typename TResult>
static TResult CallWithLock(const std::function<TResult()>& callback)
{
BEGIN_MUTEX_SCOPE(*ms_pMutex)
return callback();
END_MUTEX_SCOPE
}
// Put the mutex on the heap. At process shutdown, static cleanup races against GC,
// so using non-POD static data in conjunction with managed objects is problematic.
static SimpleMutex* ms_pMutex;
};
template <typename T>
SimpleMutex* WeakRefUtil<T>::ms_pMutex = new SimpleMutex;
//-----------------------------------------------------------------------------
// WeakRefTarget
//-----------------------------------------------------------------------------
@ -139,27 +128,21 @@ class WeakRefTarget: public SharedPtrTarget
{
public:
WeakRefTarget<T>():
m_spWeakRefImpl(new WeakRefImpl<T>(static_cast<T*>(this)))
{
}
WeakRef<T> CreateWeakRef()
{
return WeakRefUtil<T>::CallWithLock<WeakRef<T>>([this]
{
if (m_spWeakRefImpl.IsEmpty())
{
m_spWeakRefImpl = new WeakRefImpl<T>(static_cast<T*>(this));
}
return WeakRef<T>(m_spWeakRefImpl);
});
return WeakRef<T>(m_spWeakRefImpl);
}
protected:
~WeakRefTarget()
{
if (!m_spWeakRefImpl.IsEmpty())
{
m_spWeakRefImpl->OnTargetDeleted();
}
m_spWeakRefImpl->OnTargetDeleted();
}
private:
@ -184,11 +167,11 @@ private:
{
}
SharedPtr<T> GetTarget() const
SharedPtr<T> GetTarget()
{
return WeakRefUtil<T>::CallWithLock<SharedPtr<T>>([this]
{
SharedPtr<T> spTarget;
SharedPtr<T> spTarget;
BEGIN_MUTEX_SCOPE(m_Mutex)
if (m_pTarget != nullptr)
{
@ -199,17 +182,20 @@ private:
}
}
return spTarget;
});
END_MUTEX_SCOPE
return spTarget;
}
void OnTargetDeleted()
{
WeakRefUtil<T>::CallWithLock<void>([this]
{
BEGIN_MUTEX_SCOPE(m_Mutex)
m_pTarget = nullptr;
});
END_MUTEX_SCOPE
}
SimpleMutex m_Mutex;
T* m_pTarget;
};

Просмотреть файл

@ -413,6 +413,80 @@ namespace Microsoft.ClearScript.Test
Assert.AreEqual(value2, obj[value]);
}
[TestMethod, TestCategory("BugFix")]
public void BugFix_V8ScriptItemWeakBinding()
{
// This test verifies that V8 script items no longer prevent their isolates from being
// destroyed. Previously it exhausted address space and crashed in 32-bit mode.
for (var i = 0; i < 128; i++)
{
using (var tempEngine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging))
{
tempEngine.Evaluate("(function () {}).valueOf()");
}
}
}
[TestMethod, TestCategory("BugFix")]
public void BugFix_V8ScriptItemDispose()
{
dynamic item1;
using (var tempEngine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging))
{
item1 = tempEngine.Evaluate("(function () { return 123; }).valueOf()");
Assert.AreEqual(123, item1());
dynamic item2 = tempEngine.Evaluate("(function () { return 456; }).valueOf()");
using (item2 as IDisposable)
{
Assert.AreEqual(456, item2());
}
}
using (item1 as IDisposable)
{
}
}
[TestMethod, TestCategory("BugFix")]
public void BugFix_V8CompiledScriptWeakBinding()
{
// This test verifies that V8 compiled scripts no longer prevent their isolates from
// being destroyed. Previously it exhausted address space and crashed in 32-bit mode.
for (var i = 0; i < 128; i++)
{
using (var tempEngine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging))
{
tempEngine.Compile("(function () {}).valueOf()");
}
}
}
[TestMethod, TestCategory("BugFix")]
public void BugFix_V8CompiledScriptDispose()
{
V8Script script1;
using (var tempEngine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging))
{
script1 = tempEngine.Compile("(function () { return 123; })()");
Assert.AreEqual(123, tempEngine.Evaluate(script1));
V8Script script2 = tempEngine.Compile("(function () { return 456; })()");
using (script2)
{
Assert.AreEqual(456, tempEngine.Evaluate(script2));
}
}
using (script1)
{
}
}
// ReSharper restore InconsistentNaming
#endregion

Просмотреть файл

@ -409,24 +409,24 @@ namespace Microsoft.ClearScript.Test
public class BaseObject
{
[NoScriptAccess] public event EventHandler BlockedBaseEvent { add { } remove { } }
[NoScriptAccess] public virtual event EventHandler BlockedOverriddenEvent { add { } remove { } }
[NoScriptAccess] public event EventHandler BlockedBaseEvent { add {} remove {} }
[NoScriptAccess] public virtual event EventHandler BlockedOverriddenEvent { add {} remove {} }
[NoScriptAccess] public int BlockedBaseField = 1;
[NoScriptAccess] public Guid BlockedBaseProperty { get { return guids[0]; } set { } }
[NoScriptAccess] public virtual Guid BlockedOverriddenProperty { get { return guids[1]; } set { } }
[NoScriptAccess] public Guid BlockedBaseProperty { get { return guids[0]; } set {} }
[NoScriptAccess] public virtual Guid BlockedOverriddenProperty { get { return guids[1]; } set {} }
[NoScriptAccess] public double BlockedBaseMethod(object arg) { return TestUtil.CalcTestValue(new Guid("9bf4c32d-1394-4546-a150-eb162b3bbb5f"), "BlockedBaseMethod", arg); }
[NoScriptAccess] public virtual double BlockedOverriddenMethod(object arg) { return TestUtil.CalcTestValue(new Guid("83aa905a-e17d-47fe-bd0f-d2350cfb92d6"), "BlockedOverriddenMethod", arg); }
[ScriptMember("renamedBaseEvent")] public event EventHandler RenamedBaseEvent { add { } remove { } }
[ScriptMember("renamedOverriddenEvent")] public virtual event EventHandler RenamedOverriddenEvent { add { } remove { } }
[ScriptMember("renamedBaseEvent")] public event EventHandler RenamedBaseEvent { add {} remove {} }
[ScriptMember("renamedOverriddenEvent")] public virtual event EventHandler RenamedOverriddenEvent { add {} remove {} }
[ScriptMember("renamedBaseField")] public int RenamedBaseField = 2;
[ScriptMember("renamedBaseProperty")] public Guid RenamedBaseProperty { get { return guids[2]; } set { } }
[ScriptMember("renamedOverriddenProperty")] public virtual Guid RenamedOverriddenProperty { get { return guids[3]; } set { } }
[ScriptMember("renamedBaseProperty")] public Guid RenamedBaseProperty { get { return guids[2]; } set {} }
[ScriptMember("renamedOverriddenProperty")] public virtual Guid RenamedOverriddenProperty { get { return guids[3]; } set {} }
[ScriptMember("renamedBaseMethod")] public double RenamedBaseMethod(object arg) { return TestUtil.CalcTestValue(new Guid("460c0b65-56e6-4174-9331-905d417df885"), "RenamedBaseMethod", arg); }
[ScriptMember("renamedOverriddenMethod")] public virtual double RenamedOverriddenMethod(object arg) { return TestUtil.CalcTestValue(new Guid("051b3239-df62-4a14-967c-0291e02ad48f"), "RenamedOverriddenMethod", arg); }
@ -455,19 +455,19 @@ namespace Microsoft.ClearScript.Test
public sealed class TestObject : BaseObject, ITestInterface
{
[NoScriptAccess] public event EventHandler BlockedEvent { add { } remove { } }
public override event EventHandler BlockedOverriddenEvent { add { } remove { } }
public event EventHandler BlockedInterfaceEvent { add { } remove { } }
event EventHandler ITestInterface.BlockedExplicitInterfaceEvent { add { } remove { } }
[NoScriptAccess] public event EventHandler BlockedEvent { add {} remove {} }
public override event EventHandler BlockedOverriddenEvent { add {} remove {} }
public event EventHandler BlockedInterfaceEvent { add {} remove {} }
event EventHandler ITestInterface.BlockedExplicitInterfaceEvent { add {} remove {} }
[NoScriptAccess] public int BlockedField = 3;
[ScriptMember(ScriptAccess.ReadOnly)] public int ReadOnlyField = 4;
[NoScriptAccess] public Guid BlockedProperty { get { return guids[4]; } set { } }
public override Guid BlockedOverriddenProperty { get { return guids[5]; } set { } }
public Guid BlockedInterfaceProperty { get { return guids[6]; } set { } }
Guid ITestInterface.BlockedExplicitInterfaceProperty { get { return guids[7]; } set { } }
[ScriptMember(ScriptAccess.ReadOnly)] public Guid ReadOnlyProperty { get { return guids[8]; } set { } }
[NoScriptAccess] public Guid BlockedProperty { get { return guids[4]; } set {} }
public override Guid BlockedOverriddenProperty { get { return guids[5]; } set {} }
public Guid BlockedInterfaceProperty { get { return guids[6]; } set {} }
Guid ITestInterface.BlockedExplicitInterfaceProperty { get { return guids[7]; } set {} }
[ScriptMember(ScriptAccess.ReadOnly)] public Guid ReadOnlyProperty { get { return guids[8]; } set {} }
[NoScriptAccess] public double BlockedMethod(object arg) { return TestUtil.CalcTestValue(new Guid("9e890478-709c-4e42-be5f-c4e291572a17"), "BlockedMethod", arg); }
public override double BlockedOverriddenMethod(object arg) { return TestUtil.CalcTestValue(new Guid("7ff033f5-f6f2-46cf-aba5-5adec6e210fd"), "BlockedOverriddenMethod", arg); }
@ -476,19 +476,19 @@ namespace Microsoft.ClearScript.Test
public double BlockedOverloadedMethod(object arg) { return TestUtil.CalcTestValue(new Guid("47a9e14b-65f6-4202-9e6c-528f05d2fd08"), "BlockedOverloadedMethod 1", arg); }
[NoScriptAccess] public double BlockedOverloadedMethod<T>(T arg) { return TestUtil.CalcTestValue(new Guid("60e54acc-0b47-4d0a-a29e-b6f420079095"), "BlockedOverloadedMethod 2", arg); }
[ScriptMember("renamedEvent")] public event EventHandler RenamedEvent { add { } remove { } }
public override event EventHandler RenamedOverriddenEvent { add { } remove { } }
public event EventHandler RenamedInterfaceEvent { add { } remove { } }
event EventHandler ITestInterface.RenamedExplicitInterfaceEvent { add { } remove { } }
[ScriptMember("renamedEvent")] public event EventHandler RenamedEvent { add {} remove {} }
public override event EventHandler RenamedOverriddenEvent { add {} remove {} }
public event EventHandler RenamedInterfaceEvent { add {} remove {} }
event EventHandler ITestInterface.RenamedExplicitInterfaceEvent { add {} remove {} }
[ScriptMember("renamedField")] public int RenamedField = 5;
[ScriptMember("renamedReadOnlyField", ScriptAccess.ReadOnly)] public int RenamedReadOnlyField = 6;
[ScriptMember("renamedProperty")] public Guid RenamedProperty { get { return guids[9]; } set { } }
public override Guid RenamedOverriddenProperty { get { return guids[10]; } set { } }
public Guid RenamedInterfaceProperty { get { return guids[11]; } set { } }
Guid ITestInterface.RenamedExplicitInterfaceProperty { get { return guids[12]; } set { } }
[ScriptMember("renamedReadOnlyProperty", ScriptAccess.ReadOnly)] public Guid RenamedReadOnlyProperty { get { return guids[13]; } set { } }
[ScriptMember("renamedProperty")] public Guid RenamedProperty { get { return guids[9]; } set {} }
public override Guid RenamedOverriddenProperty { get { return guids[10]; } set {} }
public Guid RenamedInterfaceProperty { get { return guids[11]; } set {} }
Guid ITestInterface.RenamedExplicitInterfaceProperty { get { return guids[12]; } set {} }
[ScriptMember("renamedReadOnlyProperty", ScriptAccess.ReadOnly)] public Guid RenamedReadOnlyProperty { get { return guids[13]; } set {} }
[ScriptMember("renamedMethod")] public double RenamedMethod(object arg) { return TestUtil.CalcTestValue(new Guid("d6c05624-6357-4ef1-b54a-d7a03864a034"), "RenamedMethod", arg); }
public override double RenamedOverriddenMethod(object arg) { return TestUtil.CalcTestValue(new Guid("77382ed3-feec-4d49-bd6e-d1d590827c35"), "RenamedOverriddenMethod", arg); }