Version 5.4.8: Added support for V8 parser and code caching; added ScriptObject to ease script object identification; fixed argument validation for interop interface parameters; fixed V8 crash when exceptions are thrown during script interruption (Issue #112); fixed V8 crash when code that consumes iterable host objects is optimized; fixed intermittent deadlocks during V8 runtime teardown; added a 64-bit OS check in V8Update.cmd; added tests for bug fixes and new APIs. Tested with V8 5.4.500.40.

This commit is contained in:
ClearScript 2016-11-02 08:07:05 -04:00
Родитель 26ec250ac3
Коммит 5ebc1dda8f
47 изменённых файлов: 1306 добавлений и 154 удалений

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

@ -88,6 +88,7 @@
<Compile Include="ScriptMemberFlags.cs" />
<Compile Include="ScriptMethod.cs" />
<Compile Include="ScriptMemberAttribute.cs" />
<Compile Include="ScriptObject.cs" />
<Compile Include="ScriptUsageAttribute.cs" />
<Compile Include="Util\AssemblyHelpers.cs" />
<Compile Include="Util\Collateral.cs" />
@ -111,6 +112,7 @@
<Compile Include="V8\IV8DebugListener.cs" />
<Compile Include="V8\V8ArrayBufferOrViewInfo.cs" />
<Compile Include="V8\V8ArrayBufferOrViewKind.cs" />
<Compile Include="V8\V8CacheKind.cs" />
<Compile Include="V8\V8DebugAgent.cs" />
<Compile Include="V8\V8RuntimeHeapInfo.cs" />
<Compile Include="V8\V8Script.cs" />

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

@ -63,5 +63,5 @@
#pragma once
#define CLEARSCRIPT_VERSION_STRING "5.4.7.0"
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 5,4,7,0
#define CLEARSCRIPT_VERSION_STRING "5.4.8.0"
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 5,4,8,0

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

@ -464,7 +464,7 @@ namespace Microsoft.ClearScript
/// <returns>The <see cref="System.Type"/> for the specified host type.</returns>
/// <remarks>
/// <para>
/// This function is similar to the C#
/// This function is similar to C#'s
/// <c><see href="http://msdn.microsoft.com/en-us/library/58918ffs(VS.71).aspx">typeof</see></c>
/// operator. It is overloaded with <see cref="typeOf(object)"/> and selected at runtime if
/// <typeparamref name="T"/> can be used as a type argument.
@ -499,7 +499,7 @@ namespace Microsoft.ClearScript
/// <returns>The <see cref="System.Type"/> for the specified host type.</returns>
/// <remarks>
/// <para>
/// This function is similar to the C#
/// This function is similar to C#'s
/// <c><see href="http://msdn.microsoft.com/en-us/library/58918ffs(VS.71).aspx">typeof</see></c>
/// operator. It is overloaded with <see cref="typeOf{T}"/> and selected at runtime if
/// <paramref name="value"/> cannot be used as a type argument. Note that this applies to
@ -534,7 +534,7 @@ namespace Microsoft.ClearScript
/// <param name="value">The object to test for compatibility with the specified host type.</param>
/// <returns><c>True</c> if <paramref name="value"/> is compatible with the specified type, <c>false</c> otherwise.</returns>
/// <remarks>
/// This function is similar to the C#
/// This function is similar to C#'s
/// <c><see href="http://msdn.microsoft.com/en-us/library/scekt9xw(VS.71).aspx">is</see></c>
/// operator.
/// </remarks>
@ -565,7 +565,7 @@ namespace Microsoft.ClearScript
/// <param name="value">The object to cast to the specified host type.</param>
/// <returns>The result of the cast if successful, <c>null</c> otherwise.</returns>
/// <remarks>
/// This function is similar to the C#
/// This function is similar to C#'s
/// <c><see href="http://msdn.microsoft.com/en-us/library/cscsdfbt(VS.71).aspx">as</see></c>
/// operator.
/// </remarks>

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

@ -75,5 +75,5 @@ using System.Runtime.InteropServices;
[assembly: InternalsVisibleTo("ClearScriptTest")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("5.4.7.0")]
[assembly: AssemblyFileVersion("5.4.7.0")]
[assembly: AssemblyVersion("5.4.8.0")]
[assembly: AssemblyFileVersion("5.4.8.0")]

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

@ -1131,7 +1131,7 @@ namespace Microsoft.ClearScript
/// </item>
/// <item>
/// <term><b>Script&#xA0;Object</b></term>
/// <term><see href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx">System.Dynamic.DynamicObject</see></term>
/// <term><see cref="ScriptObject"/></term>
/// <description>
/// This includes all native script objects that have no .NET representation. C#'s
/// <see href="http://msdn.microsoft.com/en-us/library/dd264741.aspx">dynamic</see>

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

@ -72,7 +72,7 @@ using Microsoft.ClearScript.Util;
namespace Microsoft.ClearScript
{
internal abstract class ScriptItem : DynamicObject, IExpando, IDynamic, IScriptMarshalWrapper
internal abstract class ScriptItem : ScriptObject, IExpando, IDynamic, IScriptMarshalWrapper
{
private static readonly MethodInfo throwLastScriptErrorMethod = typeof(ScriptItem).GetMethod("ThrowLastScriptError");
private static readonly MethodInfo clearLastScriptErrorMethod = typeof(ScriptItem).GetMethod("ClearLastScriptError");
@ -419,8 +419,6 @@ namespace Microsoft.ClearScript
#region IScriptMarshalWrapper implementation (abstract)
public abstract ScriptEngine Engine { get; }
public abstract object Unwrap();
#endregion

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

@ -0,0 +1,25 @@
using System.Dynamic;
namespace Microsoft.ClearScript
{
/// <summary>
/// Represents a script object.
/// </summary>
/// <remarks>
/// Use this class in conjunction with C#'s
/// <c><see href="http://msdn.microsoft.com/en-us/library/scekt9xw(VS.71).aspx">is</see></c>
/// operator to identify script objects.
/// </remarks>
/// <seealso cref="ScriptEngine.Evaluate(string, bool, string)"/>
public abstract class ScriptObject : DynamicObject
{
internal ScriptObject()
{
}
/// <summary>
/// Gets the script engine that owns the object.
/// </summary>
public abstract ScriptEngine Engine { get; }
}
}

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

@ -66,6 +66,7 @@ using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Microsoft.ClearScript.Util
{
@ -204,7 +205,32 @@ namespace Microsoft.ClearScript.Util
if (!type.IsValueType)
{
return type.IsAssignableFrom(valueType);
if (type.IsAssignableFrom(valueType))
{
return true;
}
if (type.IsInterface && type.IsImport && valueType.IsCOMObject)
{
var result = false;
var pUnknown = Marshal.GetIUnknownForObject(value);
var iid = type.GUID;
if (iid != Guid.Empty)
{
IntPtr pInterface;
if (RawCOMHelpers.HResult.Succeeded(Marshal.QueryInterface(pUnknown, ref iid, out pInterface)))
{
Marshal.Release(pInterface);
result = true;
}
}
Marshal.Release(pUnknown);
return result;
}
return false;
}
if (!valueType.IsValueType)

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

@ -226,6 +226,7 @@
<ClInclude Include="..\SharedPtr.h" />
<ClInclude Include="..\StdString.h" />
<ClInclude Include="..\Timer.h" />
<ClInclude Include="..\V8CacheType.h" />
<ClInclude Include="..\V8Context.h" />
<ClInclude Include="..\V8ContextImpl.h" />
<ClInclude Include="..\V8ContextProxyImpl.h" />

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

@ -199,5 +199,8 @@
<ClInclude Include="..\NativeCallbackImpl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\V8CacheType.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

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

@ -225,8 +225,9 @@
<ClInclude Include="..\NativePlatform.h" />
<ClInclude Include="..\RefCount.h" />
<ClInclude Include="..\SharedPtr.h" />
<ClInclude Include="..\Timer.h" />
<ClInclude Include="..\StdString.h" />
<ClInclude Include="..\Timer.h" />
<ClInclude Include="..\V8CacheType.h" />
<ClInclude Include="..\V8Context.h" />
<ClInclude Include="..\V8ContextImpl.h" />
<ClInclude Include="..\V8ContextProxyImpl.h" />

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

@ -199,5 +199,8 @@
<ClInclude Include="..\NativeCallbackImpl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\V8CacheType.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

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

@ -75,6 +75,7 @@
#include "V8Exception.h"
#include "V8IsolateConstraints.h"
#include "V8IsolateHeapInfo.h"
#include "V8CacheType.h"
#include "V8Isolate.h"
#include "V8Context.h"
#include "HostObjectHolderImpl.h"

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

@ -77,6 +77,7 @@
#include "V8Exception.h"
#include "V8IsolateConstraints.h"
#include "V8IsolateHeapInfo.h"
#include "V8CacheType.h"
#include "V8Isolate.h"
#include "V8Context.h"
#include "HostObjectHolderImpl.h"

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

@ -131,7 +131,7 @@
// PulseValueScope
//-----------------------------------------------------------------------------
template<typename T>
template <typename T>
class PulseValueScope
{
PROHIBIT_COPY(PulseValueScope)

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

@ -66,14 +66,14 @@
// HighResolutionClock implementation
//-----------------------------------------------------------------------------
static std::once_flag s_InitializationFlag;
static OnceFlag s_InitializationFlag;
static LARGE_INTEGER s_TicksPerSecond;
//-----------------------------------------------------------------------------
double HighResolutionClock::GetRelativeSeconds()
{
std::call_once(s_InitializationFlag, []
s_InitializationFlag.CallOnce([]
{
ASSERT_EVAL(::QueryPerformanceFrequency(&s_TicksPerSecond));
});

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

@ -202,3 +202,62 @@ RecursiveMutex::~RecursiveMutex()
{
delete m_pImpl;
}
//-----------------------------------------------------------------------------
// OnceFlagImpl
//-----------------------------------------------------------------------------
class OnceFlagImpl
{
PROHIBIT_COPY(OnceFlagImpl)
public:
OnceFlagImpl()
{
}
void CallOnce(std::function<void()>&& func)
{
if (!m_Called)
{
BEGIN_MUTEX_SCOPE(m_Mutex)
if (!m_Called)
{
func();
m_Called = true;
}
END_MUTEX_SCOPE
}
}
private:
std::atomic<bool> m_Called;
SimpleMutex m_Mutex;
};
//-----------------------------------------------------------------------------
// OnceFlag implementation
//-----------------------------------------------------------------------------
OnceFlag::OnceFlag():
m_pImpl(new OnceFlagImpl)
{
}
//-----------------------------------------------------------------------------
void OnceFlag::CallOnce(std::function<void()>&& func)
{
m_pImpl->CallOnce(std::move(func));
}
//-----------------------------------------------------------------------------
OnceFlag::~OnceFlag()
{
delete m_pImpl;
}

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

@ -111,7 +111,7 @@ private:
// NullMutex
//-----------------------------------------------------------------------------
struct NullMutex
class NullMutex
{
PROHIBIT_COPY(NullMutex)
@ -171,3 +171,24 @@ private:
#define END_MUTEX_SCOPE \
IGNORE_UNUSED(t_MutexLock); \
}
//-----------------------------------------------------------------------------
// OnceFlag
//-----------------------------------------------------------------------------
class OnceFlag
{
PROHIBIT_COPY(OnceFlag)
public:
OnceFlag();
void CallOnce(std::function<void()>&& func);
~OnceFlag();
private:
class OnceFlagImpl* m_pImpl;
};

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

@ -0,0 +1,73 @@
//
// 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
//-----------------------------------------------------------------------------
// V8CacheType
//-----------------------------------------------------------------------------
enum class V8CacheType
{
None,
Parser,
Code
};

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

@ -88,6 +88,8 @@ public:
virtual V8Value Execute(const StdString& documentName, const StdString& code, bool evaluate, bool discard) = 0;
virtual V8ScriptHolder* Compile(const StdString& documentName, const StdString& code) = 0;
virtual V8ScriptHolder* Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, std::vector<std::uint8_t>& cacheBytes) = 0;
virtual V8ScriptHolder* Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, const std::vector<std::uint8_t>& cacheBytes, bool& cacheAccepted) = 0;
virtual bool CanExecute(V8ScriptHolder* pHolder) = 0;
virtual V8Value Execute(V8ScriptHolder* pHolder, bool evaluate) = 0;

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

@ -89,7 +89,7 @@ static void* GetHostObject(v8::Local<v8::Object> hObject)
//-----------------------------------------------------------------------------
template<typename T>
template <typename T>
static V8ContextImpl* UnwrapContextImplFromHolder(const v8::PropertyCallbackInfo<T>& info)
{
auto hGlobal = info.Holder();
@ -400,6 +400,69 @@ V8ScriptHolder* V8ContextImpl::Compile(const StdString& documentName, const StdS
//-----------------------------------------------------------------------------
V8ScriptHolder* V8ContextImpl::Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, std::vector<std::uint8_t>& cacheBytes)
{
if (cacheType == V8CacheType::None)
{
cacheBytes.clear();
return Compile(documentName, code);
}
BEGIN_CONTEXT_SCOPE
BEGIN_EXECUTION_SCOPE
v8::ScriptCompiler::Source source(CreateString(code), v8::ScriptOrigin(CreateString(documentName)));
auto hScript = VERIFY(CreateUnboundScript(&source, (cacheType == V8CacheType::Parser) ? v8::ScriptCompiler::kProduceParserCache : v8::ScriptCompiler::kProduceCodeCache));
cacheBytes.clear();
auto pCachedData = source.GetCachedData();
if (pCachedData != nullptr)
{
if ((pCachedData->length > 0) && (pCachedData->data != nullptr))
{
cacheBytes.resize(pCachedData->length);
memcpy_s(&cacheBytes[0], cacheBytes.size(), pCachedData->data, pCachedData->length);
}
// Delete cached data explicitly via a custom exported method. Doing so avoids Debug-
// Release heap mismatches caused by V8's inlining of v8::ScriptCompiler::~Source.
source.DeleteCachedData();
}
return new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromScriptHandle(CreatePersistent(hScript)));
END_EXECUTION_SCOPE
END_CONTEXT_SCOPE
}
//-----------------------------------------------------------------------------
V8ScriptHolder* V8ContextImpl::Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, const std::vector<std::uint8_t>& cacheBytes, bool& cacheAccepted)
{
if ((cacheType == V8CacheType::None) || (cacheBytes.size() < 1))
{
cacheAccepted = false;
return Compile(documentName, code);
}
BEGIN_CONTEXT_SCOPE
BEGIN_EXECUTION_SCOPE
auto pCachedData = new v8::ScriptCompiler::CachedData(&cacheBytes[0], static_cast<int>(cacheBytes.size()), v8::ScriptCompiler::CachedData::BufferNotOwned);
v8::ScriptCompiler::Source source(CreateString(code), v8::ScriptOrigin(CreateString(documentName)), pCachedData);
auto hScript = VERIFY(CreateUnboundScript(&source, (cacheType == V8CacheType::Parser) ? v8::ScriptCompiler::kConsumeParserCache : v8::ScriptCompiler::kConsumeCodeCache));
cacheAccepted = !m_spIsolateImpl->IsDebuggingEnabled() && !pCachedData->rejected;
return new V8ScriptHolderImpl(GetWeakBinding(), ::PtrFromScriptHandle(CreatePersistent(hScript)));
END_EXECUTION_SCOPE
END_CONTEXT_SCOPE
}
//-----------------------------------------------------------------------------
bool V8ContextImpl::CanExecute(V8ScriptHolder* pHolder)
{
return pHolder->IsSameIsolate(m_spIsolateImpl.GetRawPtr());
@ -717,7 +780,7 @@ void V8ContextImpl::ProcessDebugMessages()
{
BEGIN_CONTEXT_SCOPE
v8::Debug::ProcessDebugMessages();
m_spIsolateImpl->ProcessDebugMessages();
END_CONTEXT_SCOPE
}
@ -896,6 +959,12 @@ void V8ContextImpl::GetV8ObjectPropertyIndices(v8::Local<v8::Object> hObject, st
void V8ContextImpl::GetGlobalProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Value>& info)
{
if (!hKey->IsString())
{
// apparently V8 ignores v8::PropertyHandlerFlags::kOnlyInterceptStrings in some cases
return;
}
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
{
@ -921,6 +990,12 @@ void V8ContextImpl::GetGlobalProperty(v8::Local<v8::Name> hKey, const v8::Proper
void V8ContextImpl::SetGlobalProperty(v8::Local<v8::Name> hKey, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info)
{
if (!hKey->IsString())
{
// apparently V8 ignores v8::PropertyHandlerFlags::kOnlyInterceptStrings in some cases
return;
}
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
{
@ -947,6 +1022,12 @@ void V8ContextImpl::SetGlobalProperty(v8::Local<v8::Name> hKey, v8::Local<v8::Va
void V8ContextImpl::QueryGlobalProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Integer>& info)
{
if (!hKey->IsString())
{
// apparently V8 ignores v8::PropertyHandlerFlags::kOnlyInterceptStrings in some cases
return;
}
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
{
@ -972,6 +1053,12 @@ void V8ContextImpl::QueryGlobalProperty(v8::Local<v8::Name> hKey, const v8::Prop
void V8ContextImpl::DeleteGlobalProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Boolean>& info)
{
if (!hKey->IsString())
{
// apparently V8 ignores v8::PropertyHandlerFlags::kOnlyInterceptStrings in some cases
return;
}
auto pContextImpl = ::UnwrapContextImplFromHolder(info);
if (CheckContextImplForGlobalObjectCallback(pContextImpl))
{
@ -1312,6 +1399,12 @@ void V8ContextImpl::InvokeHostDelegate(const v8::FunctionCallbackInfo<v8::Value>
void V8ContextImpl::GetHostObjectProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Value>& info)
{
if (!hKey->IsString())
{
// apparently V8 ignores v8::PropertyHandlerFlags::kOnlyInterceptStrings in some cases
return;
}
auto pContextImpl = ::UnwrapContextImplFromData(info);
if (CheckContextImplForHostObjectCallback(pContextImpl))
{
@ -1393,6 +1486,12 @@ void V8ContextImpl::GetHostObjectProperty(v8::Local<v8::Name> hKey, const v8::Pr
void V8ContextImpl::SetHostObjectProperty(v8::Local<v8::Name> hKey, v8::Local<v8::Value> hValue, const v8::PropertyCallbackInfo<v8::Value>& info)
{
if (!hKey->IsString())
{
// apparently V8 ignores v8::PropertyHandlerFlags::kOnlyInterceptStrings in some cases
return;
}
auto pContextImpl = ::UnwrapContextImplFromData(info);
if (CheckContextImplForHostObjectCallback(pContextImpl))
{
@ -1413,6 +1512,12 @@ void V8ContextImpl::SetHostObjectProperty(v8::Local<v8::Name> hKey, v8::Local<v8
void V8ContextImpl::QueryHostObjectProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Integer>& info)
{
if (!hKey->IsString())
{
// apparently V8 ignores v8::PropertyHandlerFlags::kOnlyInterceptStrings in some cases
return;
}
auto pContextImpl = ::UnwrapContextImplFromData(info);
if (CheckContextImplForHostObjectCallback(pContextImpl))
{
@ -1447,6 +1552,12 @@ void V8ContextImpl::QueryHostObjectProperty(v8::Local<v8::Name> hKey, const v8::
void V8ContextImpl::DeleteHostObjectProperty(v8::Local<v8::Name> hKey, const v8::PropertyCallbackInfo<v8::Boolean>& info)
{
if (!hKey->IsString())
{
// apparently V8 ignores v8::PropertyHandlerFlags::kOnlyInterceptStrings in some cases
return;
}
auto pContextImpl = ::UnwrapContextImplFromData(info);
if (CheckContextImplForHostObjectCallback(pContextImpl))
{
@ -2064,13 +2175,21 @@ void V8ContextImpl::VerifyNotOutOfMemory()
void V8ContextImpl::ThrowScriptException(const HostException& exception)
{
auto hException = v8::Exception::Error(CreateString(exception.GetMessage()))->ToObject();
// WARNING: Error instantiation may fail during script interruption. Check Exception::Error()
// result to avoid access violations. Extra defense is warranted here.
auto hHostException = ImportValue(exception.GetException());
if (!hHostException.IsEmpty() && hHostException->IsObject())
if (!IsExecutionTerminating())
{
hException->Set(m_hHostExceptionName, hHostException);
}
auto hException = v8::Exception::Error(CreateString(exception.GetMessage()))->ToObject();
if (!hException.IsEmpty() && hException->IsObject())
{
auto hHostException = ImportValue(exception.GetException());
if (!hHostException.IsEmpty() && hHostException->IsObject())
{
hException->Set(m_hHostExceptionName, hHostException);
}
ThrowException(hException);
ThrowException(hException);
}
}
}

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

@ -97,6 +97,8 @@ public:
V8Value Execute(const StdString& documentName, const StdString& code, bool evaluate, bool discard);
V8ScriptHolder* Compile(const StdString& documentName, const StdString& code);
V8ScriptHolder* Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, std::vector<std::uint8_t>& cacheBytes);
V8ScriptHolder* Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, const std::vector<std::uint8_t>& cacheBytes, bool& cacheAccepted);
bool CanExecute(V8ScriptHolder* pHolder);
V8Value Execute(V8ScriptHolder* pHolder, bool evaluate);
@ -286,7 +288,7 @@ private:
return m_spIsolateImpl->MakeWeak(hTarget, pArg1, pArg2, pCallback);
}
template<typename T>
template <typename T>
void ClearWeak(Persistent<T> hTarget)
{
return m_spIsolateImpl->ClearWeak(hTarget);

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

@ -206,6 +206,70 @@ namespace V8 {
//-------------------------------------------------------------------------
V8Script^ V8ContextProxyImpl::Compile(String^ gcDocumentName, String^ gcCode, V8CacheKind cacheKind, [Out] array<Byte>^% gcCacheBytes)
{
if (cacheKind == V8CacheKind::None)
{
gcCacheBytes = nullptr;
return Compile(gcDocumentName, gcCode);
}
try
{
std::vector<std::uint8_t> cacheBytes;
auto cacheType = (cacheKind == V8CacheKind::Parser) ? V8CacheType::Parser : V8CacheType::Code;
auto gcScript = gcnew V8ScriptImpl(gcDocumentName, GetContext()->Compile(StdString(gcDocumentName), StdString(gcCode), cacheType, cacheBytes));
auto length = static_cast<int>(cacheBytes.size());
if (length < 1)
{
gcCacheBytes = nullptr;
}
else
{
gcCacheBytes = gcnew array<Byte>(length);
Marshal::Copy((IntPtr)&cacheBytes[0], gcCacheBytes, 0, length);
}
return gcScript;
}
catch (const V8Exception& exception)
{
exception.ThrowScriptEngineException();
}
}
//-------------------------------------------------------------------------
V8Script^ V8ContextProxyImpl::Compile(String^ gcDocumentName, String^ gcCode, V8CacheKind cacheKind, array<Byte>^ gcCacheBytes, [Out] Boolean% cacheAccepted)
{
if ((cacheKind == V8CacheKind::None) || (gcCacheBytes == nullptr) || (gcCacheBytes->Length < 1))
{
cacheAccepted = false;
return Compile(gcDocumentName, gcCode);
}
try
{
auto length = gcCacheBytes->Length;
std::vector<std::uint8_t> cacheBytes(length);
Marshal::Copy(gcCacheBytes, 0, (IntPtr)&cacheBytes[0], length);
bool tempCacheAccepted;
auto cacheType = (cacheKind == V8CacheKind::Parser) ? V8CacheType::Parser : V8CacheType::Code;
auto gcScript = gcnew V8ScriptImpl(gcDocumentName, GetContext()->Compile(StdString(gcDocumentName), StdString(gcCode), cacheType, cacheBytes, tempCacheAccepted));
cacheAccepted = tempCacheAccepted;
return gcScript;
}
catch (const V8Exception& exception)
{
exception.ThrowScriptEngineException();
}
}
//-------------------------------------------------------------------------
Object^ V8ContextProxyImpl::Execute(V8Script^ gcScript, Boolean evaluate)
{
try

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

@ -98,6 +98,8 @@ namespace V8 {
virtual void AddGlobalItem(String^ gcName, Object^ gcItem, Boolean globalMembers) override;
virtual Object^ Execute(String^ gcDocumentName, String^ gcCode, Boolean evaluate, Boolean discard) override;
virtual V8Script^ Compile(String^ gcDocumentName, String^ gcCode) override;
virtual V8Script^ Compile(String^ gcDocumentName, String^ gcCode, V8CacheKind cacheKind, [Out] array<Byte>^% gcCacheBytes) override;
virtual V8Script^ Compile(String^ gcDocumentName, String^ gcCode, V8CacheKind cacheKind, array<Byte>^ gcCacheBytes, [Out] Boolean% cacheAccepted) override;
virtual Object^ Execute(V8Script^ gcScript, Boolean evaluate) override;
virtual void Interrupt() override;
virtual V8RuntimeHeapInfo^ GetRuntimeHeapInfo() override;

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

@ -81,6 +81,8 @@ public:
virtual void SetMaxStackUsage(size_t value) = 0;
virtual V8ScriptHolder* Compile(const StdString& documentName, const StdString& code) = 0;
virtual V8ScriptHolder* Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, std::vector<std::uint8_t>& cacheBytes) = 0;
virtual V8ScriptHolder* Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, const std::vector<std::uint8_t>& cacheBytes, bool& cacheAccepted) = 0;
virtual void GetHeapInfo(V8IsolateHeapInfo& heapInfo) = 0;
virtual void CollectGarbage(bool exhaustive) = 0;

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

@ -84,14 +84,14 @@ private:
V8Platform();
static V8Platform ms_Instance;
static std::once_flag ms_InstallationFlag;
static OnceFlag ms_InstallationFlag;
};
//-----------------------------------------------------------------------------
void V8Platform::EnsureInstalled()
{
std::call_once(ms_InstallationFlag, []
ms_InstallationFlag.CallOnce([]
{
v8::V8::InitializePlatform(&ms_Instance);
ASSERT_EVAL(v8::V8::Initialize());
@ -109,54 +109,25 @@ size_t V8Platform::NumberOfAvailableBackgroundThreads()
void V8Platform::CallOnBackgroundThread(v8::Task* pTask, ExpectedRuntime /*runtime*/)
{
#if 1
// Unlike earlier versions, V8 5.3 tracks outstanding background tasks and awaits their
// completion within v8::Isolate::Dispose(). In addition, it actually schedules at least one
// background task during disposition, and since the corresponding callback fails to acquire a
// strong reference to the isolate wrapper (whose shutdown is in progress), it drops the task,
// causing V8's wait to deadlock. Because V8's precise behavior is undocumented and could
// always be reverted, we'll keep the older code here to ease A/B testing in the future.
SharedPtr<v8::Task> spTask(pTask);
HostObjectHelpers::QueueNativeCallback([spTask]
{
spTask->Run();
});
#else
auto pIsolate = v8::Isolate::GetCurrent();
if (pIsolate)
{
static_cast<V8IsolateImpl*>(pIsolate->GetData(0))->RunBackgroundTask(pTask);
}
else
{
SharedPtr<v8::Task> spTask(pTask);
HostObjectHelpers::QueueNativeCallback([spTask]
{
spTask->Run();
});
}
#endif
}
//-----------------------------------------------------------------------------
void V8Platform::CallOnForegroundThread(v8::Isolate* pIsolate, v8::Task* pTask)
{
static_cast<V8IsolateImpl*>(pIsolate->GetData(0))->RunTaskWithLock(pTask);
static_cast<V8IsolateImpl*>(pIsolate->GetData(0))->RunTaskWithLockAsync(pTask);
}
//-----------------------------------------------------------------------------
void V8Platform::CallDelayedOnForegroundThread(v8::Isolate* pIsolate, v8::Task* pTask, double delayInSeconds)
{
static_cast<V8IsolateImpl*>(pIsolate->GetData(0))->RunDelayedTaskWithLock(pTask, delayInSeconds);
static_cast<V8IsolateImpl*>(pIsolate->GetData(0))->RunTaskWithLockDelayed(pTask, delayInSeconds);
}
//-----------------------------------------------------------------------------
@ -190,7 +161,7 @@ V8Platform::V8Platform()
//-----------------------------------------------------------------------------
V8Platform V8Platform::ms_Instance;
std::once_flag V8Platform::ms_InstallationFlag;
OnceFlag V8Platform::ms_InstallationFlag;
//-----------------------------------------------------------------------------
// V8ArrayBufferAllocator
@ -211,7 +182,6 @@ private:
V8ArrayBufferAllocator();
static V8ArrayBufferAllocator ms_Instance;
static std::once_flag ms_InstallationFlag;
};
//-----------------------------------------------------------------------------
@ -251,7 +221,6 @@ V8ArrayBufferAllocator::V8ArrayBufferAllocator()
//-----------------------------------------------------------------------------
V8ArrayBufferAllocator V8ArrayBufferAllocator::ms_Instance;
std::once_flag V8ArrayBufferAllocator::ms_InstallationFlag;
//-----------------------------------------------------------------------------
// V8IsolateImpl implementation
@ -397,7 +366,7 @@ void V8IsolateImpl::EnableDebugging(int debugPort)
}
});
v8::Debug::SetMessageHandler(OnDebugMessageShared);
v8::Debug::SetMessageHandler(m_pIsolate, OnDebugMessageShared);
m_DebuggingEnabled = true;
m_DebugPort = debugPort;
@ -411,7 +380,7 @@ void V8IsolateImpl::DisableDebugging()
_ASSERTE(IsCurrent() && IsLocked());
if (m_DebuggingEnabled)
{
v8::Debug::SetMessageHandler(nullptr);
v8::Debug::SetMessageHandler(m_pIsolate, nullptr);
HostObjectHelpers::DestroyDebugAgent(m_pvDebugAgent);
m_DebuggingEnabled = false;
@ -476,6 +445,30 @@ V8ScriptHolder* V8IsolateImpl::Compile(const StdString& documentName, const StdS
//-----------------------------------------------------------------------------
V8ScriptHolder* V8IsolateImpl::Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, std::vector<std::uint8_t>& cacheBytes)
{
BEGIN_ISOLATE_SCOPE
SharedPtr<V8ContextImpl> spContextImpl((m_ContextPtrs.size() > 0) ? m_ContextPtrs.front() : new V8ContextImpl(this, StdString(), false, true, 0));
return spContextImpl->Compile(documentName, code, cacheType, cacheBytes);
END_ISOLATE_SCOPE
}
//-----------------------------------------------------------------------------
V8ScriptHolder* V8IsolateImpl::Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, const std::vector<std::uint8_t>& cacheBytes, bool& cacheAccepted)
{
BEGIN_ISOLATE_SCOPE
SharedPtr<V8ContextImpl> spContextImpl((m_ContextPtrs.size() > 0) ? m_ContextPtrs.front() : new V8ContextImpl(this, StdString(), false, true, 0));
return spContextImpl->Compile(documentName, code, cacheType, cacheBytes, cacheAccepted);
END_ISOLATE_SCOPE
}
//-----------------------------------------------------------------------------
void V8IsolateImpl::GetHeapInfo(V8IsolateHeapInfo& heapInfo)
{
BEGIN_ISOLATE_SCOPE
@ -556,66 +549,61 @@ void V8IsolateImpl::ReleaseV8Script(void* pvScript)
//-----------------------------------------------------------------------------
void V8IsolateImpl::RunBackgroundTask(v8::Task* pTask)
void V8IsolateImpl::RunTaskWithLockAsync(v8::Task* pTask)
{
SharedPtr<v8::Task> spTask(pTask);
auto wrIsolate = CreateWeakRef();
HostObjectHelpers::QueueNativeCallback([wrIsolate, spTask]
CallWithLockAsync([spTask] (V8IsolateImpl* /*pIsolateImpl*/)
{
auto spIsolate = wrIsolate.GetTarget();
if (!spIsolate.IsEmpty())
{
spTask->Run();
throw std::bad_exception();
}
spTask->Run();
});
}
//-----------------------------------------------------------------------------
void V8IsolateImpl::RunTaskWithLock(v8::Task* pTask)
void V8IsolateImpl::RunTaskWithLockDelayed(v8::Task* pTask, double delayInSeconds)
{
SharedPtr<v8::Task> spTask(pTask);
auto wrIsolate = CreateWeakRef();
HostObjectHelpers::QueueNativeCallback([this, wrIsolate, spTask]
SharedPtr<Timer> spTimer(new Timer(static_cast<int>(delayInSeconds * 1000), -1, [this, wrIsolate, spTask] (Timer* pTimer) mutable
{
auto spIsolate = wrIsolate.GetTarget();
if (!spIsolate.IsEmpty())
if (!spTask.IsEmpty())
{
CallWithLockNoWait([spTask] (V8IsolateImpl* /*pIsolateImpl*/)
auto spIsolate = wrIsolate.GetTarget();
if (!spIsolate.IsEmpty())
{
spTask->Run();
});
}
});
}
CallWithLockNoWait([spTask] (V8IsolateImpl* /*pIsolateImpl*/)
{
spTask->Run();
});
//-----------------------------------------------------------------------------
// Release the timer's strong task reference. Doing so avoids a deadlock when
// spIsolate's implicit destruction below triggers immediate isolate teardown.
void V8IsolateImpl::RunDelayedTaskWithLock(v8::Task* pTask, double delayInSeconds)
{
SharedPtr<v8::Task> spTask(pTask);
auto wrIsolate = CreateWeakRef();
SharedPtr<Timer> spTimer(new Timer(static_cast<int>(delayInSeconds * 1000), -1, [this, wrIsolate, spTask] (Timer* pTimer)
{
auto spIsolate = wrIsolate.GetTarget();
if (!spIsolate.IsEmpty())
{
CallWithLockNoWait([spTask] (V8IsolateImpl* /*pIsolateImpl*/)
{
spTask->Run();
});
spTask.Empty();
BEGIN_MUTEX_SCOPE(m_DataMutex)
m_TaskTimers.erase(std::remove(m_TaskTimers.begin(), m_TaskTimers.end(), pTimer), m_TaskTimers.end());
END_MUTEX_SCOPE
// the timer has fired; discard it
BEGIN_MUTEX_SCOPE(m_DataMutex)
m_TaskTimers.erase(std::remove(m_TaskTimers.begin(), m_TaskTimers.end(), pTimer), m_TaskTimers.end());
END_MUTEX_SCOPE
}
}
}));
// hold on to the timer to ensure callback execution
BEGIN_MUTEX_SCOPE(m_DataMutex)
m_TaskTimers.push_back(spTimer);
END_MUTEX_SCOPE
// Release the local task reference explicitly. Doing so avoids a deadlock if the callback is
// executed synchronously. That shouldn't happen given the current timer implementation.
spTask.Empty();
// now it's safe to start the timer
spTimer->Start();
}
@ -635,11 +623,7 @@ void V8IsolateImpl::CallWithLockNoWait(std::function<void(V8IsolateImpl*)>&& cal
}
else
{
std::function<void(V8IsolateImpl*)> userCallback(std::move(callback));
CallWithLockAsync([userCallback] (V8IsolateImpl* pIsolateImpl)
{
userCallback(pIsolateImpl);
});
CallWithLockAsync(std::move(callback));
}
}
@ -661,6 +645,13 @@ V8IsolateImpl::~V8IsolateImpl()
DisableDebugging();
END_ISOLATE_SCOPE
{
std::vector<SharedPtr<Timer>> taskTimers;
BEGIN_MUTEX_SCOPE(m_DataMutex)
std::swap(taskTimers, m_TaskTimers);
END_MUTEX_SCOPE
}
m_pIsolate->RemoveBeforeCallEnteredCallback(OnBeforeCallEntered);
m_pIsolate->Dispose();
}
@ -739,27 +730,20 @@ void V8IsolateImpl::DispatchDebugMessages()
{
if (++m_DebugMessageDispatchCount == 1)
{
ProcessDebugMessages();
BEGIN_ISOLATE_SCOPE
m_DebugMessageDispatchCount = 0;
if (m_ContextPtrs.size() > 0)
{
m_ContextPtrs.front()->ProcessDebugMessages();
}
END_ISOLATE_SCOPE
}
}
//-----------------------------------------------------------------------------
void V8IsolateImpl::ProcessDebugMessages()
{
BEGIN_ISOLATE_SCOPE
m_DebugMessageDispatchCount = 0;
if (m_ContextPtrs.size() > 0)
{
m_ContextPtrs.front()->ProcessDebugMessages();
}
END_ISOLATE_SCOPE
}
//-----------------------------------------------------------------------------
V8IsolateImpl::ExecutionScope* V8IsolateImpl::EnterExecutionScope(ExecutionScope* pExecutionScope, size_t* pStackMarker)
{
_ASSERTE(IsCurrent() && IsLocked());

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

@ -291,7 +291,7 @@ public:
return hTarget.MakeWeak(m_pIsolate, pArg1, pArg2, pCallback);
}
template<typename T>
template <typename T>
void ClearWeak(Persistent<T> hTarget)
{
return hTarget.ClearWeak();
@ -308,6 +308,11 @@ public:
return m_pIsolate->ThrowException(hException);
}
bool IsDebuggingEnabled()
{
return m_DebuggingEnabled;
}
void TerminateExecution()
{
m_pIsolate->TerminateExecution();
@ -345,6 +350,11 @@ public:
m_pIsolate->RequestInterrupt(callback, pvData);
}
void ProcessDebugMessages()
{
v8::Debug::ProcessDebugMessages(m_pIsolate);
}
bool IsCurrent() const
{
return m_pIsolate == v8::Isolate::GetCurrent();
@ -375,6 +385,8 @@ public:
void SetMaxStackUsage(size_t value);
V8ScriptHolder* Compile(const StdString& documentName, const StdString& code);
V8ScriptHolder* Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, std::vector<std::uint8_t>& cacheBytes);
V8ScriptHolder* Compile(const StdString& documentName, const StdString& code, V8CacheType cacheType, const std::vector<std::uint8_t>& cacheBytes, bool& cacheAccepted);
void GetHeapInfo(V8IsolateHeapInfo& heapInfo);
void CollectGarbage(bool exhaustive);
@ -384,9 +396,8 @@ public:
void* AddRefV8Script(void* pvScript);
void ReleaseV8Script(void* pvScript);
void RunBackgroundTask(v8::Task* pTask);
void RunTaskWithLock(v8::Task* pTask);
void RunDelayedTaskWithLock(v8::Task* pTask, double delayInSeconds);
void RunTaskWithLockAsync(v8::Task* pTask);
void RunTaskWithLockDelayed(v8::Task* pTask, double delayInSeconds);
void CallWithLockNoWait(std::function<void(V8IsolateImpl*)>&& callback);
void DECLSPEC_NORETURN ThrowOutOfMemoryException();
@ -403,7 +414,6 @@ private:
static void OnDebugMessageShared(const v8::Debug::Message& message);
void OnDebugMessage(const v8::Debug::Message& message);
void DispatchDebugMessages();
void ProcessDebugMessages();
ExecutionScope* EnterExecutionScope(ExecutionScope* pExecutionScope, size_t* pStackMarker);
void ExitExecutionScope(ExecutionScope* pPreviousExecutionScope);

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

@ -149,6 +149,70 @@ namespace V8 {
//-------------------------------------------------------------------------
V8Script^ V8IsolateProxyImpl::Compile(String^ gcDocumentName, String^ gcCode, V8CacheKind cacheKind, [Out] array<Byte>^% gcCacheBytes)
{
if (cacheKind == V8CacheKind::None)
{
gcCacheBytes = nullptr;
return Compile(gcDocumentName, gcCode);
}
try
{
std::vector<std::uint8_t> cacheBytes;
auto cacheType = (cacheKind == V8CacheKind::Parser) ? V8CacheType::Parser : V8CacheType::Code;
auto gcScript = gcnew V8ScriptImpl(gcDocumentName, GetIsolate()->Compile(StdString(gcDocumentName), StdString(gcCode), cacheType, cacheBytes));
auto length = static_cast<int>(cacheBytes.size());
if (length < 1)
{
gcCacheBytes = nullptr;
}
else
{
gcCacheBytes = gcnew array<Byte>(length);
Marshal::Copy((IntPtr)&cacheBytes[0], gcCacheBytes, 0, length);
}
return gcScript;
}
catch (const V8Exception& exception)
{
exception.ThrowScriptEngineException();
}
}
//-------------------------------------------------------------------------
V8Script^ V8IsolateProxyImpl::Compile(String^ gcDocumentName, String^ gcCode, V8CacheKind cacheKind, array<Byte>^ gcCacheBytes, [Out] Boolean% cacheAccepted)
{
if ((cacheKind == V8CacheKind::None) || (gcCacheBytes == nullptr) || (gcCacheBytes->Length < 1))
{
cacheAccepted = false;
return Compile(gcDocumentName, gcCode);
}
try
{
auto length = gcCacheBytes->Length;
std::vector<std::uint8_t> cacheBytes(length);
Marshal::Copy(gcCacheBytes, 0, (IntPtr)&cacheBytes[0], length);
bool tempCacheAccepted;
auto cacheType = (cacheKind == V8CacheKind::Parser) ? V8CacheType::Parser : V8CacheType::Code;
auto gcScript = gcnew V8ScriptImpl(gcDocumentName, GetIsolate()->Compile(StdString(gcDocumentName), StdString(gcCode), cacheType, cacheBytes, tempCacheAccepted));
cacheAccepted = tempCacheAccepted;
return gcScript;
}
catch (const V8Exception& exception)
{
exception.ThrowScriptEngineException();
}
}
//-------------------------------------------------------------------------
V8RuntimeHeapInfo^ V8IsolateProxyImpl::GetHeapInfo()
{
V8IsolateHeapInfo heapInfo;

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

@ -94,6 +94,8 @@ namespace V8 {
}
virtual V8Script^ Compile(String^ gcDocumentName, String^ gcCode) override;
virtual V8Script^ Compile(String^ gcDocumentName, String^ gcCode, V8CacheKind cacheKind, [Out] array<Byte>^% gcCacheBytes) override;
virtual V8Script^ Compile(String^ gcDocumentName, String^ gcCode, V8CacheKind cacheKind, array<Byte>^ gcCacheBytes, [Out] Boolean% cacheAccepted) override;
virtual V8RuntimeHeapInfo^ GetHeapInfo() override;
virtual void CollectGarbage(bool exhaustive) override;

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

@ -1,8 +1,8 @@
diff --git a/gypfiles/standalone.gypi b/gypfiles/standalone.gypi
index c6c26fb..130a000 100644
index 6599bb8..285fbb6 100644
--- a/gypfiles/standalone.gypi
+++ b/gypfiles/standalone.gypi
@@ -918,7 +918,7 @@
@@ -949,7 +949,7 @@
'EnableFunctionLevelLinking': 'true',
'RuntimeTypeInfo': 'false',
'WarningLevel': '3',
@ -11,8 +11,38 @@ index c6c26fb..130a000 100644
'DebugInformationFormat': '3',
'Detect64BitPortabilityProblems': 'false',
'conditions': [
diff --git a/include/v8.h b/include/v8.h
index d7e39ad..4701f29 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1170,6 +1170,7 @@ class V8_EXPORT ScriptCompiler {
// caller. The CachedData object is alive as long as the Source object is
// alive.
V8_INLINE const CachedData* GetCachedData() const;
+ V8_EXPORT void DeleteCachedData();
private:
friend class ScriptCompiler;
diff --git a/src/api.cc b/src/api.cc
index 6858a32..63f45a5 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1713,6 +1713,13 @@ void ObjectTemplate::SetImmutableProto() {
// --- S c r i p t s ---
+void ScriptCompiler::Source::DeleteCachedData()
+{
+ delete cached_data;
+ cached_data = nullptr;
+}
+
+
// Internally, UnboundScript is a SharedFunctionInfo, and Script is a
// JSFunction.
diff --git a/src/v8.cc b/src/v8.cc
index d660b58..76f5aa3 100644
index 08796f3..c7fd6d2 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -91,7 +91,6 @@ void V8::InitializeOncePerProcess() {
@ -24,10 +54,10 @@ index d660b58..76f5aa3 100644
platform_ = platform;
}
diff --git a/src/v8.gyp b/src/v8.gyp
index 84c361e..26fc971 100644
index 1adb2fe..e2552fc 100644
--- a/src/v8.gyp
+++ b/src/v8.gyp
@@ -40,6 +40,7 @@
@@ -41,6 +41,7 @@
'targets': [
{
'target_name': 'v8',

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

@ -0,0 +1,88 @@
//
// 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.
//
namespace Microsoft.ClearScript.V8
{
/// <summary>
/// Defines caching options for V8 script compilation.
/// </summary>
public enum V8CacheKind
{
/// <summary>
/// Specifies that no cache data is to be generated or consumed during V8 script
/// compilation. This option results in the most efficient script compilation when no cache
/// data is available.
/// </summary>
None,
/// <summary>
/// Selects parser caching. Parser cache data is smaller and less expensive to generate
/// than code cache data, but it is less effective at accelerating recompilation.
/// </summary>
Parser,
/// <summary>
/// Selects code caching. Code cache data is larger and more expensive to generate than
/// parser cache data, but it is more effective at accelerating recompilation.
/// </summary>
Code
}
}

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

@ -86,6 +86,10 @@ namespace Microsoft.ClearScript.V8
public abstract V8Script Compile(string documentName, string code);
public abstract V8Script Compile(string documentName, string code, V8CacheKind cacheKind, out byte[] cacheBytes);
public abstract V8Script Compile(string documentName, string code, V8CacheKind cacheKind, byte[] cacheBytes, out bool cacheAccepted);
public abstract object Execute(V8Script script, bool evaluate);
public abstract void Interrupt();

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

@ -78,6 +78,10 @@ namespace Microsoft.ClearScript.V8
public abstract V8Script Compile(string documentName, string code);
public abstract V8Script Compile(string documentName, string code, V8CacheKind cacheKind, out byte[] cacheBytes);
public abstract V8Script Compile(string documentName, string code, V8CacheKind cacheKind, byte[] cacheBytes, out bool cacheAccepted);
public abstract V8RuntimeHeapInfo GetHeapInfo();
public abstract void CollectGarbage(bool exhaustive);

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

@ -455,6 +455,84 @@ namespace Microsoft.ClearScript.V8
return proxy.Compile(uniqueName, FormatCode ? MiscHelpers.FormatCode(code) : code);
}
/// <summary>
/// Creates a compiled script, generating cache data for accelerated recompilation.
/// </summary>
/// <param name="code">The script code to compile.</param>
/// <param name="cacheKind">The kind of cache data to be generated.</param>
/// <param name="cacheBytes">Cache data for accelerated recompilation.</param>
/// <returns>A compiled script that can be executed by multiple V8 script engine instances.</returns>
/// <remarks>
/// The generated cache data can be stored externally and is usable in other V8 runtimes
/// and application processes. V8 runtimes with debugging enabled cannot generate cache
/// data.
/// </remarks>
/// <seealso cref="Compile(string, V8CacheKind, byte[], out bool)"/>
public V8Script Compile(string code, V8CacheKind cacheKind, out byte[] cacheBytes)
{
return Compile(null, code, cacheKind, out cacheBytes);
}
/// <summary>
/// Creates a compiled script with an associated document name, generating cache data for accelerated recompilation.
/// </summary>
/// <param name="documentName">A document name for the compiled script. Currently this name is used only as a label in presentation contexts such as debugger user interfaces.</param>
/// <param name="code">The script code to compile.</param>
/// <param name="cacheKind">The kind of cache data to be generated.</param>
/// <param name="cacheBytes">Cache data for accelerated recompilation.</param>
/// <returns>A compiled script that can be executed by multiple V8 script engine instances.</returns>
/// <remarks>
/// The generated cache data can be stored externally and is usable in other V8 runtimes
/// and application processes. V8 runtimes with debugging enabled cannot generate cache
/// data.
/// </remarks>
/// <seealso cref="Compile(string, string, V8CacheKind, byte[], out bool)"/>
public V8Script Compile(string documentName, string code, V8CacheKind cacheKind, out byte[] cacheBytes)
{
VerifyNotDisposed();
var uniqueName = name + ":" + documentNameManager.GetUniqueName(documentName, "Script Document");
return proxy.Compile(uniqueName, FormatCode ? MiscHelpers.FormatCode(code) : code, cacheKind, out cacheBytes);
}
/// <summary>
/// Creates a compiled script, consuming previously generated cache data.
/// </summary>
/// <param name="code">The script code to compile.</param>
/// <param name="cacheKind">The kind of cache data to be consumed.</param>
/// <param name="cacheBytes">Cache data for accelerated compilation.</param>
/// <param name="cacheAccepted"><c>True</c> if <paramref name="cacheBytes"/> was accepted, <c>false</c> otherwise.</param>
/// <returns>A compiled script that can be executed by multiple V8 script engine instances.</returns>
/// <remarks>
/// To be accepted, the cache data must have been generated for identical script code by
/// the same V8 build. V8 runtimes with debugging enabled cannot consume cache data.
/// </remarks>
/// <seealso cref="Compile(string, V8CacheKind, out byte[])"/>
public V8Script Compile(string code, V8CacheKind cacheKind, byte[] cacheBytes, out bool cacheAccepted)
{
return Compile(null, code, cacheKind, cacheBytes, out cacheAccepted);
}
/// <summary>
/// Creates a compiled script with an associated document name, consuming previously generated cache data.
/// </summary>
/// <param name="documentName">A document name for the compiled script. Currently this name is used only as a label in presentation contexts such as debugger user interfaces.</param>
/// <param name="code">The script code to compile.</param>
/// <param name="cacheKind">The kind of cache data to be consumed.</param>
/// <param name="cacheBytes">Cache data for accelerated compilation.</param>
/// <param name="cacheAccepted"><c>True</c> if <paramref name="cacheBytes"/> was accepted, <c>false</c> otherwise.</param>
/// <returns>A compiled script that can be executed by multiple V8 script engine instances.</returns>
/// <remarks>
/// To be accepted, the cache data must have been generated for identical script code by
/// the same V8 build. V8 runtimes with debugging enabled cannot consume cache data.
/// </remarks>
/// <seealso cref="Compile(string, string, V8CacheKind, out byte[])"/>
public V8Script Compile(string documentName, string code, V8CacheKind cacheKind, byte[] cacheBytes, out bool cacheAccepted)
{
VerifyNotDisposed();
var uniqueName = name + ":" + documentNameManager.GetUniqueName(documentName, "Script Document");
return proxy.Compile(uniqueName, FormatCode ? MiscHelpers.FormatCode(code) : code, cacheKind, cacheBytes, out cacheAccepted);
}
/// <summary>
/// Returns memory usage information.
/// </summary>

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

@ -471,6 +471,102 @@ namespace Microsoft.ClearScript.V8
});
}
/// <summary>
/// Creates a compiled script, generating cache data for accelerated recompilation.
/// </summary>
/// <param name="code">The script code to compile.</param>
/// <param name="cacheKind">The kind of cache data to be generated.</param>
/// <param name="cacheBytes">Cache data for accelerated recompilation.</param>
/// <returns>A compiled script that can be executed multiple times without recompilation.</returns>
/// <remarks>
/// The generated cache data can be stored externally and is usable in other V8 script
/// engines and application processes. V8 script engines with debugging enabled cannot
/// generate cache data.
/// </remarks>
/// <seealso cref="Compile(string, V8CacheKind, byte[], out bool)"/>
public V8Script Compile(string code, V8CacheKind cacheKind, out byte[] cacheBytes)
{
return Compile(null, code, cacheKind, out cacheBytes);
}
/// <summary>
/// Creates a compiled script with an associated document name, generating cache data for accelerated recompilation.
/// </summary>
/// <param name="documentName">A document name for the compiled script. Currently this name is used only as a label in presentation contexts such as debugger user interfaces.</param>
/// <param name="code">The script code to compile.</param>
/// <param name="cacheKind">The kind of cache data to be generated.</param>
/// <param name="cacheBytes">Cache data for accelerated recompilation.</param>
/// <returns>A compiled script that can be executed multiple times without recompilation.</returns>
/// <remarks>
/// The generated cache data can be stored externally and is usable in other V8 script
/// engines and application processes. V8 script engines with debugging enabled cannot
/// generate cache data.
/// </remarks>
/// <seealso cref="Compile(string, string, V8CacheKind, byte[], out bool)"/>
public V8Script Compile(string documentName, string code, V8CacheKind cacheKind, out byte[] cacheBytes)
{
VerifyNotDisposed();
V8Script tempScript = null;
cacheBytes = ScriptInvoke(() =>
{
byte[] tempCacheBytes;
var uniqueName = documentNameManager.GetUniqueName(documentName, "Script Document");
tempScript = proxy.Compile(uniqueName, FormatCode ? MiscHelpers.FormatCode(code) : code, cacheKind, out tempCacheBytes);
return tempCacheBytes;
});
return tempScript;
}
/// <summary>
/// Creates a compiled script, consuming previously generated cache data.
/// </summary>
/// <param name="code">The script code to compile.</param>
/// <param name="cacheKind">The kind of cache data to be consumed.</param>
/// <param name="cacheBytes">Cache data for accelerated compilation.</param>
/// <param name="cacheAccepted"><c>True</c> if <paramref name="cacheBytes"/> was accepted, <c>false</c> otherwise.</param>
/// <returns>A compiled script that can be executed multiple times without recompilation.</returns>
/// <remarks>
/// To be accepted, the cache data must have been generated for identical script code by
/// the same V8 build. V8 script engines with debugging enabled cannot consume cache data.
/// </remarks>
/// <seealso cref="Compile(string, V8CacheKind, out byte[])"/>
public V8Script Compile(string code, V8CacheKind cacheKind, byte[] cacheBytes, out bool cacheAccepted)
{
return Compile(null, code, cacheKind, cacheBytes, out cacheAccepted);
}
/// <summary>
/// Creates a compiled script with an associated document name, consuming previously generated cache data.
/// </summary>
/// <param name="documentName">A document name for the compiled script. Currently this name is used only as a label in presentation contexts such as debugger user interfaces.</param>
/// <param name="code">The script code to compile.</param>
/// <param name="cacheKind">The kind of cache data to be consumed.</param>
/// <param name="cacheBytes">Cache data for accelerated compilation.</param>
/// <param name="cacheAccepted"><c>True</c> if <paramref name="cacheBytes"/> was accepted, <c>false</c> otherwise.</param>
/// <returns>A compiled script that can be executed multiple times without recompilation.</returns>
/// <remarks>
/// To be accepted, the cache data must have been generated for identical script code by
/// the same V8 build. V8 script engines with debugging enabled cannot consume cache data.
/// </remarks>
/// <seealso cref="Compile(string, string, V8CacheKind, out byte[])"/>
public V8Script Compile(string documentName, string code, V8CacheKind cacheKind, byte[] cacheBytes, out bool cacheAccepted)
{
VerifyNotDisposed();
V8Script tempScript = null;
cacheAccepted = ScriptInvoke(() =>
{
bool tempCacheAccepted;
var uniqueName = documentNameManager.GetUniqueName(documentName, "Script Document");
tempScript = proxy.Compile(uniqueName, FormatCode ? MiscHelpers.FormatCode(code) : code, cacheKind, cacheBytes, out tempCacheAccepted);
return tempCacheAccepted;
});
return tempScript;
}
// ReSharper disable ParameterHidesMember
/// <summary>

Двоичные данные
ClearScript/doc/Reference.chm

Двоичный файл не отображается.

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

@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("5.4.7.0")]
[assembly: AssemblyFileVersion("5.4.7.0")]
[assembly: AssemblyVersion("5.4.8.0")]
[assembly: AssemblyFileVersion("5.4.8.0")]

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

@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("5.4.7.0")]
[assembly: AssemblyFileVersion("5.4.7.0")]
[assembly: AssemblyVersion("5.4.8.0")]
[assembly: AssemblyFileVersion("5.4.8.0")]

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

@ -75,6 +75,7 @@ using Microsoft.ClearScript.Util;
using Microsoft.ClearScript.Windows;
using Microsoft.CSharp.RuntimeBinder;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using UIAutomationClient;
namespace Microsoft.ClearScript.Test
{
@ -469,7 +470,6 @@ namespace Microsoft.ClearScript.Test
using (item2 as IDisposable)
{
Assert.AreEqual(456, item2());
}
}
@ -808,7 +808,7 @@ namespace Microsoft.ClearScript.Test
{
// this test is for a crash that occurred only on debug V8 builds
engine.AddHostObject("bag", HostItemFlags.GlobalMembers, new PropertyBag());
engine.AddHostObject("test", HostItemFlags.GlobalMembers, new ReadOnlyCollection<int>(new [] { 5, 4, 3, 2, 1 }));
engine.AddHostObject("test", HostItemFlags.GlobalMembers, new ReadOnlyCollection<int>(new[] { 5, 4, 3, 2, 1 }));
TestUtil.AssertException<ScriptEngineException>(() => engine.Execute("this[2] = 123"));
}
@ -2147,6 +2147,79 @@ namespace Microsoft.ClearScript.Test
}
}
[TestMethod, TestCategory("BugFix")]
public void BugFix_V8ExceptionWhileInterrupting()
{
var context = new PropertyBag();
engine.Script.context = context;
var startEvent = new ManualResetEventSlim();
var waitEvent = new ManualResetEventSlim();
var tokenSource = new CancellationTokenSource();
context["count"] = 0;
context["startEvent"] = startEvent;
context["waitForCancel"] = new Action(() => waitEvent.Wait(tokenSource.Token));
var thread = new Thread(() =>
{
try
{
engine.Execute(@"
context.count = 1;
context.startEvent.Set();
context.waitForCancel();
context.count = 2;
");
}
catch (ScriptEngineException)
{
}
catch (ScriptInterruptedException)
{
}
});
thread.Start();
startEvent.Wait(Timeout.Infinite);
tokenSource.Cancel();
engine.Interrupt();
thread.Join();
Assert.AreEqual(1, context["count"]);
}
[TestMethod, TestCategory("BugFix")]
public void BugFix_InteropMethodCallWithInteropArg()
{
engine.AddHostObject("host", new HostFunctions());
engine.AddHostType("Automation", typeof(CUIAutomationClass));
engine.AddHostType(typeof(UIA_PropertyIds));
engine.AddHostType(typeof(UIA_ControlTypeIds));
engine.AddHostType(typeof(IUIAutomationCondition));
engine.Execute(@"
automation = new Automation();
condition1 = automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_CustomControlTypeId);
condition2 = automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_CustomControlTypeId);
condition3 = automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_CustomControlTypeId);
conditions = host.newArr(IUIAutomationCondition, 3);
conditions[0] = condition1;
conditions[1] = condition2;
conditions[2] = condition3;
andCondition = automation.CreateAndCondition(condition1, condition2);
andAndCondition = automation.CreateAndConditionFromArray(conditions);
");
}
[TestMethod, TestCategory("BugFix")]
public void BugFix_InteropMethodCallWithInteropArg_JScript()
{
engine.Dispose();
engine = new JScriptEngine();
BugFix_InteropMethodCallWithInteropArg();
}
// ReSharper restore InconsistentNaming
#endregion

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

@ -121,6 +121,15 @@
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
<COMReference Include="UIAutomationClient">
<Guid>{944DE083-8FB8-45CF-BCB7-C477ACB2F897}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

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

@ -2137,6 +2137,14 @@ namespace Microsoft.ClearScript.Test
TestUtil.AssertException<ScriptEngineException>(() => engine.Script.sum(DayOfWeek.Monday));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_ScriptObject()
{
var obj = engine.Evaluate("({})") as ScriptObject;
Assert.IsNotNull(obj);
Assert.AreSame(engine, obj.Engine);
}
// ReSharper restore InconsistentNaming
#endregion

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

@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("5.4.7.0")]
[assembly: AssemblyFileVersion("5.4.7.0")]
[assembly: AssemblyVersion("5.4.8.0")]
[assembly: AssemblyFileVersion("5.4.8.0")]

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

@ -893,6 +893,250 @@ namespace Microsoft.ClearScript.Test
}
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_General_ParserCache()
{
engine.Dispose();
engine = new V8ScriptEngine(); // default engine enables debugging, which disables caching
byte[] cacheBytes;
using (var tempEngine = new V8ScriptEngine())
{
using (tempEngine.Compile(generalScript, V8CacheKind.Parser, out cacheBytes))
{
}
}
Assert.IsNotNull(cacheBytes);
Assert.IsTrue((cacheBytes.Length > 50) && (cacheBytes.Length < 2000)); // typical size is ~100
bool cacheAccepted;
using (var script = engine.Compile(generalScript, V8CacheKind.Parser, cacheBytes, out cacheAccepted))
{
Assert.IsTrue(cacheAccepted);
using (var console = new StringWriter())
{
var clr = new HostTypeCollection(type => type != typeof(Console), "mscorlib", "System", "System.Core");
clr.GetNamespaceNode("System").SetPropertyNoCheck("Console", console);
engine.AddHostObject("host", new ExtendedHostFunctions());
engine.AddHostObject("clr", clr);
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
console.GetStringBuilder().Clear();
Assert.AreEqual(string.Empty, console.ToString());
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
}
}
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_General_ParserCache_BadData()
{
engine.Dispose();
engine = new V8ScriptEngine(); // default engine enables debugging, which disables caching
byte[] cacheBytes;
using (var tempEngine = new V8ScriptEngine())
{
using (tempEngine.Compile(generalScript, V8CacheKind.Parser, out cacheBytes))
{
}
}
Assert.IsNotNull(cacheBytes);
Assert.IsTrue((cacheBytes.Length > 50) && (cacheBytes.Length < 2000)); // typical size is ~100
cacheBytes = cacheBytes.Take(cacheBytes.Length - 1).ToArray();
bool cacheAccepted;
using (var script = engine.Compile(generalScript, V8CacheKind.Parser, cacheBytes, out cacheAccepted))
{
Assert.IsFalse(cacheAccepted);
using (var console = new StringWriter())
{
var clr = new HostTypeCollection(type => type != typeof(Console), "mscorlib", "System", "System.Core");
clr.GetNamespaceNode("System").SetPropertyNoCheck("Console", console);
engine.AddHostObject("host", new ExtendedHostFunctions());
engine.AddHostObject("clr", clr);
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
console.GetStringBuilder().Clear();
Assert.AreEqual(string.Empty, console.ToString());
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
}
}
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_General_ParserCache_DebuggingEnabled()
{
byte[] cacheBytes;
using (var tempEngine = new V8ScriptEngine())
{
using (tempEngine.Compile(generalScript, V8CacheKind.Parser, out cacheBytes))
{
}
}
Assert.IsNotNull(cacheBytes);
Assert.IsTrue((cacheBytes.Length > 50) && (cacheBytes.Length < 2000)); // typical size is ~100
bool cacheAccepted;
using (var script = engine.Compile(generalScript, V8CacheKind.Parser, cacheBytes, out cacheAccepted))
{
Assert.IsFalse(cacheAccepted);
using (var console = new StringWriter())
{
var clr = new HostTypeCollection(type => type != typeof(Console), "mscorlib", "System", "System.Core");
clr.GetNamespaceNode("System").SetPropertyNoCheck("Console", console);
engine.AddHostObject("host", new ExtendedHostFunctions());
engine.AddHostObject("clr", clr);
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
console.GetStringBuilder().Clear();
Assert.AreEqual(string.Empty, console.ToString());
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
}
}
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_General_CodeCache()
{
engine.Dispose();
engine = new V8ScriptEngine(); // default engine enables debugging, which disables caching
byte[] cacheBytes;
using (var tempEngine = new V8ScriptEngine())
{
using (tempEngine.Compile(generalScript, V8CacheKind.Code, out cacheBytes))
{
}
}
Assert.IsNotNull(cacheBytes);
Assert.IsTrue(cacheBytes.Length > 4000); // typical size is ~8K
bool cacheAccepted;
using (var script = engine.Compile(generalScript, V8CacheKind.Code, cacheBytes, out cacheAccepted))
{
Assert.IsTrue(cacheAccepted);
using (var console = new StringWriter())
{
var clr = new HostTypeCollection(type => type != typeof(Console), "mscorlib", "System", "System.Core");
clr.GetNamespaceNode("System").SetPropertyNoCheck("Console", console);
engine.AddHostObject("host", new ExtendedHostFunctions());
engine.AddHostObject("clr", clr);
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
console.GetStringBuilder().Clear();
Assert.AreEqual(string.Empty, console.ToString());
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
}
}
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_General_CodeCache_BadData()
{
engine.Dispose();
engine = new V8ScriptEngine(); // default engine enables debugging, which disables caching
byte[] cacheBytes;
using (var tempEngine = new V8ScriptEngine())
{
using (tempEngine.Compile(generalScript, V8CacheKind.Code, out cacheBytes))
{
}
}
Assert.IsNotNull(cacheBytes);
Assert.IsTrue(cacheBytes.Length > 4000); // typical size is ~8K
cacheBytes = cacheBytes.Take(cacheBytes.Length - 1).ToArray();
bool cacheAccepted;
using (var script = engine.Compile(generalScript, V8CacheKind.Code, cacheBytes, out cacheAccepted))
{
Assert.IsFalse(cacheAccepted);
using (var console = new StringWriter())
{
var clr = new HostTypeCollection(type => type != typeof(Console), "mscorlib", "System", "System.Core");
clr.GetNamespaceNode("System").SetPropertyNoCheck("Console", console);
engine.AddHostObject("host", new ExtendedHostFunctions());
engine.AddHostObject("clr", clr);
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
console.GetStringBuilder().Clear();
Assert.AreEqual(string.Empty, console.ToString());
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
}
}
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_General_CodeCache_DebuggingEnabled()
{
byte[] cacheBytes;
using (var tempEngine = new V8ScriptEngine())
{
using (tempEngine.Compile(generalScript, V8CacheKind.Code, out cacheBytes))
{
}
}
Assert.IsNotNull(cacheBytes);
Assert.IsTrue(cacheBytes.Length > 4000); // typical size is ~8K
bool cacheAccepted;
using (var script = engine.Compile(generalScript, V8CacheKind.Code, cacheBytes, out cacheAccepted))
{
Assert.IsFalse(cacheAccepted);
using (var console = new StringWriter())
{
var clr = new HostTypeCollection(type => type != typeof(Console), "mscorlib", "System", "System.Core");
clr.GetNamespaceNode("System").SetPropertyNoCheck("Console", console);
engine.AddHostObject("host", new ExtendedHostFunctions());
engine.AddHostObject("clr", clr);
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
console.GetStringBuilder().Clear();
Assert.AreEqual(string.Empty, console.ToString());
engine.Evaluate(script);
Assert.AreEqual(MiscHelpers.FormatCode(generalScriptOutput), console.ToString().Replace("\r\n", "\n"));
}
}
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_ErrorHandling_SyntaxError()
{
@ -2275,7 +2519,12 @@ namespace Microsoft.ClearScript.Test
return result;
}
");
Assert.AreEqual(array.Aggregate((current, next) => current + next), engine.Script.sum(array));
// run test several times to verify workaround for V8 optimizer bug
for (var i = 0; i < 64; i++)
{
Assert.AreEqual(array.Aggregate((current, next) => current + next), engine.Script.sum(array));
}
}
[TestMethod, TestCategory("V8ScriptEngine")]
@ -2292,7 +2541,12 @@ namespace Microsoft.ClearScript.Test
return result;
}
");
Assert.AreEqual(array.Aggregate((current, next) => Convert.ToInt32(current) + Convert.ToInt32(next)), engine.Script.sum(array));
// run test several times to verify workaround for V8 optimizer bug
for (var i = 0; i < 64; i++)
{
Assert.AreEqual(array.Aggregate((current, next) => Convert.ToInt32(current) + Convert.ToInt32(next)), engine.Script.sum(array));
}
}
[TestMethod, TestCategory("V8ScriptEngine")]
@ -2308,7 +2562,12 @@ namespace Microsoft.ClearScript.Test
return result;
}
");
Assert.AreEqual(array.Aggregate((current, next) => current + next), engine.Script.sum(HostObject.Wrap(array, typeof(IEnumerable))));
// run test several times to verify workaround for V8 optimizer bug
for (var i = 0; i < 64; i++)
{
Assert.AreEqual(array.Aggregate((current, next) => current + next), engine.Script.sum(HostObject.Wrap(array, typeof(IEnumerable))));
}
}
[TestMethod, TestCategory("V8ScriptEngine")]
@ -2323,7 +2582,12 @@ namespace Microsoft.ClearScript.Test
return result;
}
");
TestUtil.AssertException<NotSupportedException>(() => engine.Script.sum(DayOfWeek.Monday));
// run test several times to verify workaround for V8 optimizer bug
for (var i = 0; i < 64; i++)
{
TestUtil.AssertException<NotSupportedException>(() => engine.Script.sum(DayOfWeek.Monday));
}
}
[TestMethod, TestCategory("V8ScriptEngine")]
@ -2346,6 +2610,14 @@ namespace Microsoft.ClearScript.Test
Assert.AreEqual(25, engine.Evaluate("foo.Count()"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_ScriptObject()
{
var obj = engine.Evaluate("({})") as ScriptObject;
Assert.IsNotNull(obj);
Assert.AreSame(engine, obj.Engine);
}
// ReSharper restore InconsistentNaming
#endregion

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

@ -2299,6 +2299,20 @@ namespace Microsoft.ClearScript.Test
TestUtil.AssertException<NotSupportedException>(() => engine.Script.sum(DayOfWeek.Monday));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_ScriptObject()
{
engine.Execute(@"
class VBTestObject
end class
set testObject = new VBTestObject
");
var obj = engine.Evaluate("testObject") as ScriptObject;
Assert.IsNotNull(obj);
Assert.AreSame(engine, obj.Engine);
}
// ReSharper restore InconsistentNaming
#endregion

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

@ -38,21 +38,25 @@ build, and import V8:
with any third-party software required to download and build V8. Rights to
V8 and its prerequisites are provided by their rights holders.
2. Install Git (http://www.git-scm.com/download/win). Ensure that Git is added
2. IMPORTANT: Because of changes in V8 5.4, this procedure and the V8Update
script now require a 64-bit operating system. Once built, ClearScript can
still be deployed in a 32-bit environment.
3. Install Git (http://www.git-scm.com/download/win). Ensure that Git is added
to your executable path by selecting the option "Use Git from the Windows
Command Prompt".
3. Install the latest Python 2.x (http://www.python.org/downloads/) and add it
4. Install the latest Python 2.x (http://www.python.org/downloads/) and add it
to your executable path. V8's build process requires at least Python 2.7 and
does not support Python 3.x.
4. Unzip or clone the ClearScript source code into a convenient directory.
5. Unzip or clone the ClearScript source code into a convenient directory.
IMPORTANT: Ensure that the path to your ClearScript root directory does not
contain any non-ASCII characters.
5. Ensure that your Visual Studio installation includes C++ support.
6. Ensure that your Visual Studio installation includes C++ support.
6. Open a Visual Studio developer command prompt and run the V8Update script
7. Open a Visual Studio developer command prompt and run the V8Update script
from your ClearScript root directory:
C:\ClearScript> V8Update [/N] [Debug|Release] [Latest|Tested|<Revision>]

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

@ -5,12 +5,12 @@ setlocal
:: process arguments
::-----------------------------------------------------------------------------
set v8testedrev=5.3.332.45
set v8testedrev=5.4.500.40
set gyprev=35eafcd939515d51d19556c543f9cf97faf75ee6
set gyprev=702ac58e477214c635d9b541932e75a95d349352
set cygwinrev=c89e446b273697fadf3a10ff1007a97c0b7de6df
set clangrev=2ad431ac7823581e1f39c5b770704e1e1ca6cb32
set traceeventcommonrev=54b8455be9505c2cb0cf5c26bb86739c236471aa
set clangrev=3afb04a8153e40ff00f9eaa14337851c3ab4a368
set traceeventcommonrev=315bf1e2d45be7d53346c31cfcc37424a32c30c8
set gtestrev=6f8a66431cb592dad629028a50b3dd418a408c87
set gmockrev=0421b6f358139f02e102c9c332ce19a33faf75be
@ -66,6 +66,13 @@ goto ProcessArg
:: check environment
::-----------------------------------------------------------------------------
:CheckOS
if /i "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto CheckOSDone
if defined PROCESSOR_ARCHITEW6432 goto CheckOSDone
echo Error: This script requires a 64-bit operating system.
goto Exit
:CheckOSDone
:CheckMSVS
if "%VisualStudioVersion%"=="12.0" goto UseMSVS2013
if "%VisualStudioVersion%"=="14.0" goto UseMSVS2015

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

@ -1 +1 @@
<# var version = new Version(5, 4, 7, 0); #>
<# var version = new Version(5, 4, 8, 0); #>