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:
Родитель
26ec250ac3
Коммит
5ebc1dda8f
|
@ -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 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
Двоичные данные
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
|
||||
|
|
14
ReadMe.txt
14
ReadMe.txt
|
@ -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>]
|
||||
|
|
15
V8Update.cmd
15
V8Update.cmd
|
@ -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); #>
|
||||
|
|
Загрузка…
Ссылка в новой задаче